convert line ends
[canaan.git] / prj / cam / src / dark / drkdebrf.cpp
blob328656478cc0acd444ae53307b73d404b9019066
1 /*
2 @Copyright Looking Glass Studios, Inc.
3 1996,1997,1998,1999,2000 Unpublished Work.
4 */
6 // $Header: r:/t2repos/thief2/src/dark/drkdebrf.cpp,v 1.22 2000/03/23 21:33:06 adurant Exp $
7 #include <appagg.h>
8 #include <drkdebrf.h>
10 #include <cursors.h>
12 #include <scrnmode.h>
13 #include <scrnman.h>
15 #include <drkpanl.h>
17 #include <drkuires.h>
18 #include <imgsrc.h>
19 #include <resapi.h>
20 #include <respaths.h>
21 #include <fonrstyp.h>
23 #include <string.h>
24 #include <str.h>
26 #include <appapi.h>
28 #include <command.h>
29 #include <config.h>
30 #include <cfgdbg.h>
31 #include <ctype.h>
33 #include <simman.h>
34 #include <playrobj.h>
35 #include <buttpanl.h>
36 #include <guistyle.h>
37 #include <uigame.h>
38 #include <drkgoalr.h>
39 #include <drkgoalt.h>
40 #include <questapi.h>
41 #include <drkmiss.h>
42 #include <drkamap.h>
43 #include <drkmenu.h>
45 #include <dbfile.h>
46 #include <dbasemsg.h>
47 #include <drkmislp.h>
48 #include <tagfile.h>
49 #include <dbtagfil.h>
50 #include <quesfile.h>
51 #include <scrnman.h>
52 #include <cursors.h>
53 #include <drkdiff.h>
55 #include <gcompose.h>
57 // For status dials
58 #include <stubfile.h>
59 #include <gshelapi.h>
60 #include <gameinfo.h>
61 #include <drksave.h>
63 #include <btffact.h>
67 // Include these last!
69 #include <dbmem.h>
71 enum eFlags
73 kShowStats = 1 << 0,
74 kFictionGoals = 1 << 1,
78 class cObjectivesBase: public cDarkPanel
80 public:
81 cObjectivesBase(const sDarkPanelDesc *desc, ulong flags)
82 : cDarkPanel(desc), mFlags(flags)
86 ~cObjectivesBase() {};
89 protected:
90 BOOL DisplayFits(const Rect& r, grs_font* font);
92 void RedrawDisplay();
93 void InitUI()
95 cDarkPanel::InitUI();
96 memset(&mTextStyle,0,sizeof(mTextStyle));
97 // default to current style colors
98 AssertMsg(GetCurrentStyle(),"No current style for diff defaults");
99 memcpy(mTextStyle.colors,GetCurrentStyle()->colors,sizeof(mTextStyle.colors));
100 uiGameLoadStyle("goal_text_",&mTextStyle,mResPath);
102 memset(&mGreyStyle,0,sizeof(mGreyStyle));
103 // default to current style colors
104 AssertMsg(GetCurrentStyle(),"No current style for diff defaults");
105 memcpy(mGreyStyle.colors,GetCurrentStyle()->colors,sizeof(mGreyStyle.colors));
106 uiGameLoadStyle("grey_",&mGreyStyle,mResPath);
109 void TermUI()
111 uiGameUnloadStyle(&mTextStyle);
112 uiGameUnloadStyle(&mGreyStyle);
113 cDarkPanel::TermUI();
116 ulong mFlags;
117 guiStyle mTextStyle;
118 guiStyle mGreyStyle;
121 enum eMargins
123 kLeftGoalTextMargin = 16,
124 kStatsVertSeparator = 16,
125 kTextIconAlign = -3,
128 enum
130 kMinYSpace = 5,
133 static int compute_yspace(grs_font* font)
135 int retval = gr_font_string_height(font,"X")/4;
136 if (retval > kMinYSpace)
137 return retval;
138 return kMinYSpace;
141 enum eDrawGoalResult
143 kNoGoal,
144 kSkipGoal,
145 kDrawGoal,
149 static eDrawGoalResult should_draw_goal(IQuestData* pQuest, int i)
151 cStr var = GoalStateVarName(i);
152 // If there's no goal state, then we've passed the last goal
153 if (!pQuest->Exists(var))
154 return kNoGoal;
156 cStr visvar = GoalVisibleVarName(i);
157 // Check to see if the goal is visible
158 if (!pQuest->Get(visvar))
159 return kSkipGoal;
161 int state = pQuest->Get(var);
163 int diff = pQuest->Get(DIFF_QVAR);
165 // check against min difficulty
166 cStr minvar = GoalMinDiffVarName(i);
167 if (pQuest->Exists(minvar)
168 && diff < pQuest->Get(minvar))
169 return kSkipGoal;
172 // check against max difficulty
173 cStr maxvar = GoalMaxDiffVarName(i);
174 if (pQuest->Exists(maxvar)
175 && diff > pQuest->Get(maxvar))
176 return kSkipGoal;
178 return kDrawGoal;
181 void cObjectivesBase::RedrawDisplay()
183 // push a sub-canvas
184 Rect& area = mRects[num_butts];
185 GUIcompose c;
186 int compose_flags = ComposeFlagRead|ComposeFlagClear;
187 GUIsetup(&c,&area,(GUIcomposeFlags)compose_flags,GUI_CANV_ANY);
188 int y = 0;
189 int max = RectHeight(&area);
190 int width = RectWidth(&area);
193 // Set up font
196 guiStyleSetupFont(&mTextStyle,StyleFontNormal);
197 IRes* altfont = NULL;
200 // If the display doesn't fit, use the smaller font
202 BOOL show_stats = mFlags & kShowStats;
204 if (!show_stats && !DisplayFits(area,gr_get_font()))
207 static const char* alt_fonts[] = { "textfont", "smalfont" };
208 int nfonts = (sizeof(alt_fonts)/sizeof(alt_fonts[0]));
210 guiStyleCleanupFont(&mTextStyle,StyleFontNormal);
213 for (int i = 0; i < nfonts; i++)
215 char var[64];
216 sprintf(var,"%s_alt_font_%d",panel_name,i);
217 const char* fontname = alt_fonts[i];
219 char buf[64];
220 if (config_get_raw(var,buf,sizeof(buf)))
221 fontname = buf;
222 // Grab the tiny font and go
224 AutoAppIPtr(ResMan);
226 SafeRelease(altfont);
227 altfont = pResMan->Bind(fontname,RESTYPE_FONT,NULL,mResPath);
229 grs_font* font = (grs_font*)altfont->Lock();
231 if (DisplayFits(area,font))
233 gr_set_font(font);
234 break;
236 altfont->Unlock();
240 if (i >= nfonts)
242 Warning(("No objectives font could fit, using smallest\n"));
243 gr_set_font((grs_font*)altfont->Lock());
247 int yspace = compute_yspace(gr_get_font());
253 // Draw title
257 char buf[16];
258 sprintf(buf,"title_%d",GetMissionData()->num);
259 cStr title_str = FetchUIString("titles",buf,"strings");
260 char* title = (char*)(const char*)title_str;
261 int x = (width - gr_string_width(title))/2;
262 gr_set_fcolor(guiStyleGetColor(&mTextStyle,StyleColorText));
264 gr_string(title,x,y);
265 y += gr_string_height(title) + yspace;
269 AutoAppIPtr_(QuestData,pQuest);
270 int diff = pQuest->Get(DIFF_QVAR);
273 // Draw difficulty
277 char buf[16];
278 cStr diff_str = FetchUIString("newgame","difficulty") ;
279 sprintf(buf,"diff_%d",diff);
280 diff_str += " ";
281 diff_str += FetchUIString("newgame",buf);
282 char* diffstr = (char*)(const char*)diff_str;
284 gr_set_fcolor(guiStyleGetColor(&mTextStyle,StyleColorText));
286 gr_string(diffstr,0,y);
287 y += gr_string_height(diffstr);
292 // Draw goals
294 if (!show_stats)
296 int between = 0;
298 BOOL done = FALSE;
299 for (int i = 0; !done; i++)
301 int draw = should_draw_goal(pQuest,i);
302 if (draw == kNoGoal)
303 break;
305 if (draw == kSkipGoal)
306 continue;
308 y += between ; // first time through this is zero
309 between = yspace;
311 cStr text = (mFlags & kFictionGoals) ? GoalFiction(i) : GoalDescription(i);
313 // Perilous, we mutate a cstr in place
314 char* s = (char*)(const char*)text;
316 int x = kLeftGoalTextMargin;
317 gr_font_string_wrap(gr_get_font(), s, width - x);
319 int h = gr_string_height(s);
321 // We already did this in should_draw_goal. Oh well.
322 int state = pQuest->Get(GoalStateVarName(i));
325 if (state != 2)
327 // setup font, move "cursor" to just after icon
328 gr_set_fcolor(guiStyleGetColor(&mTextStyle,StyleColorText));
330 else
332 gr_set_fcolor(guiStyleGetColor(&mGreyStyle,StyleColorText));
335 gr_string(s,x,y);
338 // Now draw the icon
339 IImageSource* icon = GoalStatus(state);
340 grs_bitmap* bm = (grs_bitmap*)icon->Lock();
341 int icon_h = bm->h + kTextIconAlign;
342 gr_bitmap(bm,0,y+(gr_string_height("X") - icon_h)/2);
344 icon->Unlock();
345 SafeRelease(icon);
347 y += h;
354 // Draw stats
356 if (show_stats)
358 int x = 0, draw_line=TRUE;
359 // y += kStatsVertSeparator;
360 for (int i = 0, done = FALSE; !done; i++)
362 int val=0;
363 char buf[256];
364 char outbuf[256];
366 sprintf(buf,"stat_%d",i);
367 cStr var = FetchUIString(panel_name,buf);
369 if (var[0] == '\0')
370 break;
372 // if (!pQuest->Exists(var)) continue;
374 if (pQuest->Exists(var))
375 val = pQuest->Get(var);
377 sprintf(buf,"text_%d",i);
378 cStr text = FetchUIString(panel_name,buf);
380 sprintf(buf,"format_%d",i);
381 cStr format = FetchUIString(panel_name,buf);
383 // this is the fancy formatter from hell...
384 if (format == "" || format == "*missing string*")
385 format = "%d";
387 BOOL have_cr=TRUE, no_sprint=FALSE, skip=FALSE, maybe_abort=FALSE, abort=FALSE;
388 char *use_str=(char *)(const char *)format, sep[8]={0};
389 int miss_val=0;
391 while (*use_str=='@')
392 { // do we go to next line?? - strings ending in | do not
393 // do magic @ sign stuff
394 switch (use_str[1])
396 case 'x':
397 maybe_abort=TRUE;
398 break;
399 case 'n':
400 y+=gr_string_height("X");
401 x=0;
402 break;
403 case '<':
404 miss_val=((use_str[2]-'0')*10)+(use_str[3]-'0');
405 use_str+=2;
406 if (GetMissionData()->num<miss_val)
407 if (maybe_abort) abort=TRUE;
408 else skip=TRUE;
409 break;
410 case '>':
411 miss_val=((use_str[2]-'0')*10)+(use_str[3]-'0');
412 use_str+=2;
413 if (GetMissionData()->num>miss_val)
414 if (maybe_abort) abort=TRUE;
415 else skip=TRUE;
416 break;
417 case '=':
418 miss_val=((use_str[2]-'0')*10)+(use_str[3]-'0');
419 use_str+=2;
420 if (GetMissionData()->num==miss_val)
421 if (maybe_abort) abort=TRUE;
422 else skip=TRUE;
423 break;
424 case '!':
425 miss_val=((use_str[2]-'0')*10)+(use_str[3]-'0');
426 use_str+=2;
427 if (GetMissionData()->num!=miss_val)
428 if (maybe_abort) abort=TRUE;
429 else skip=TRUE;
430 break;
431 case 'c': have_cr=FALSE; break;
432 case 'b':
433 sprintf(buf,"%s",FetchUIString(panel_name,val?"true":"false"));
434 no_sprint=TRUE;
435 break;
436 case 'q':
437 sprintf(buf,"%s",FetchUIString(panel_name,val?"some":"none"));
438 no_sprint=TRUE;
439 break;
440 case 't':
442 int s=val/1000;
443 int m=s/60;
444 int h=m/60;
445 buf[0]='\0';
446 if (h)
447 sprintf(buf+strlen(buf),"%d %s ",h,FetchUIString(panel_name,h!=1?"hours":"hour"));
448 if (m)
449 sprintf(buf+strlen(buf),"%d %s ",m%60,FetchUIString(panel_name,m!=1?"minutes":"minute"));
450 if (s)
451 sprintf(buf+strlen(buf),"%d %s",s%60,FetchUIString(panel_name,s!=1?"seconds":"second"));
452 no_sprint=TRUE;
454 break;
455 case '+': skip=(val==0); break;
456 case 's': draw_line=(val!=0); have_cr=FALSE; break;
457 case ':': strcpy(sep,": "); break;
458 case '/': strcpy(sep,"/"); break;
460 use_str+=2;
463 if (abort)
464 break;
465 if (!draw_line)
467 if (have_cr) // if we arent drawing this line
468 draw_line=TRUE; // but have a carriage return
469 continue; // then we should draw the next
471 if (skip)
473 if (have_cr&&(x>0))
475 y+=gr_string_height("X");
476 x =0;
478 if (y >= max) break;
479 continue;
482 if (!no_sprint)
483 sprintf(buf,use_str,val);
484 sprintf(outbuf,"%s%s%s",(const char*)text,sep,buf);
486 gr_font_string_wrap(gr_get_font(), outbuf, width - x);
487 gr_set_fcolor(guiStyleGetColor(&mTextStyle,StyleColorText));
488 gr_string(outbuf,x,y);
490 if (have_cr)
492 y += gr_string_height(outbuf);
493 x = 0;
494 draw_line = TRUE;
496 else
497 x += gr_string_width(outbuf);
499 if (y >= max) break;
505 if (!altfont)
506 guiStyleCleanupFont(&mTextStyle,StyleFontNormal);
507 else
509 altfont->Unlock();
510 altfont->Release();
513 GUIdone(&c);
517 // Figure out if the display is going to fit
518 // @TODO: Factor this code!
521 BOOL cObjectivesBase::DisplayFits(const Rect& area, grs_font* font)
523 int y = 0;
524 int max = RectHeight(&area);
525 int width = RectWidth(&area);
528 // Set up font
531 int yspace = compute_yspace(font);
533 // Title and difficulty space
534 // @HACK: These had better be 1 line each
535 y += gr_font_string_height(font,"X")*2 + yspace;
537 AutoAppIPtr_(QuestData,pQuest);
540 // Goals
542 int between = 0;
544 BOOL done = FALSE;
545 for (int i = 0; !done; i++)
547 int draw = should_draw_goal(pQuest,i);
548 if (draw == kNoGoal)
549 break;
551 if (draw == kSkipGoal)
552 continue;
554 y += between;
555 between = yspace;
557 // setup font, move "cursor" to just after icon
558 int x = kLeftGoalTextMargin;
560 cStr text = (mFlags & kFictionGoals) ? GoalFiction(i) : GoalDescription(i);
562 // Perilous, we mutate a cstr in place
563 char* s = (char*)(const char*)text;
565 gr_font_string_wrap(font, s, width - x);
566 y += gr_font_string_height(font,s);
568 if (y >= max) return FALSE;
571 return TRUE;
576 //------------------------------------------------------------
577 // CLASS: cDebrief
580 class cDebrief : public cObjectivesBase
582 static sDarkPanelDesc vars;
584 public:
586 cDebrief()
587 : cObjectivesBase(&vars,0)
592 enum eRects
594 kMenu,
595 kContinue,
596 kStats,
597 kNumButts,
598 kText = kNumButts,
600 kNumRects
604 protected:
605 void OnButtonList(ushort action, int button);
607 void InitUI()
609 cObjectivesBase::InitUI();
610 AutoAppIPtr(QuestData);
611 if (!pQuestData->Get(MISSION_COMPLETE_VAR))
613 int i = kContinue;
614 mStrings[i] = FetchUIString(panel_name,"restart",mResPath);
615 mElems[i].draw_data = (void*)(const char*)mStrings[i];
618 mFlags &= ~kShowStats;
621 void OnEscapeKey()
623 // push to sim menu
624 SwitchToSimMenuMode(TRUE);
632 static const char* debrief_button_names[] =
634 "menu",
635 "continue",
636 "stats",
639 sDarkPanelDesc cDebrief::vars =
641 "debrief",
642 cDebrief::kNumButts,
643 cDebrief::kNumRects,
644 cDebrief::kNumButts,
645 debrief_button_names,
648 void cDebrief::OnButtonList(ushort action, int button)
650 if (action & BUTTONGADG_LCLICK)
652 switch (button)
654 case kContinue:
656 IPanelMode* pMode = GetPanelMode();
657 pMode->Exit();
658 SafeRelease(pMode);
659 break;
661 case kMenu:
662 SwitchToSimMenuMode(TRUE);
663 break;
665 case kStats:
667 int i = kStats;
668 // switch the button text
669 // toggle stat mode
670 mFlags ^= kShowStats;
671 const char* button_name = (mFlags & kShowStats) ? "goals" : "stats";
672 mStrings[i] = FetchUIString(panel_name,button_name,mResPath);
673 mElems[i].draw_data = (void*)(const char*)mStrings[i];
675 RedrawDisplay();
677 break;
688 static cDebrief* gpDebrief = NULL;
690 void SwitchToDebriefMode(BOOL push)
692 if (!gpDebrief)
693 gpDebrief = new cDebrief;
695 IPanelMode* panel = gpDebrief->GetPanelMode();
697 panel->Switch((push) ? kLoopModePush : kLoopModeSwitch);
698 SafeRelease(panel);
701 const sLoopInstantiator* DescribeDebriefMode(void)
703 if (!gpDebrief)
704 gpDebrief = new cDebrief;
706 if (gpDebrief)
708 cAutoIPtr<IPanelMode> panel = gpDebrief->GetPanelMode();
710 return panel->Instantiator();
712 return NULL;
716 //------------------------------------------------------------
717 // SUBCLASS: cObjectives
720 class cObjectives : public cObjectivesBase
722 static sDarkPanelDesc vars;
724 public:
726 cObjectives()
727 : cObjectivesBase(&vars,0)
732 enum eRects
734 kMap,
735 kQuit,
736 kNumButts,
737 kText = kNumButts,
739 kNumRects
743 protected:
744 void OnButtonList(ushort action, int button);
752 static const char* objectives_button_names[] =
754 "map",
755 "done",
756 "text",
759 sDarkPanelDesc cObjectives::vars =
761 "objctiv",
762 cObjectives::kNumButts,
763 cObjectives::kNumRects,
764 cObjectives::kNumButts,
765 objectives_button_names,
768 void cObjectives::OnButtonList(ushort action, int button)
770 if (action & BUTTONGADG_LCLICK)
772 switch (button)
774 case kMap:
775 SwitchToDarkAutomapMode(FALSE);
776 break;
777 case kQuit:
778 mpPanelMode->Exit();
779 break;
786 static cObjectives* gpObjectives = NULL;
788 void SwitchToObjectivesMode(BOOL push)
790 if (!gpObjectives)
791 gpObjectives = new cObjectives;
792 IPanelMode* panel = gpObjectives->GetPanelMode();
794 panel->Switch((push) ? kLoopModePush : kLoopModeSwitch);
795 SafeRelease(panel);
799 const sLoopInstantiator* DescribeObjectivesMode(void)
801 if (!gpObjectives)
802 gpObjectives = new cObjectives;
804 cAutoIPtr<IPanelMode> panel = gpObjectives->GetPanelMode();
806 return panel->Instantiator();
809 //------------------------------------------------------------
810 // SUBCLASS: cLoading
813 class cLoading;
814 static cLoading* gpLoading = NULL;
816 class cLoading : public cObjectivesBase
818 static sDarkPanelDesc vars;
820 public:
822 cLoading()
823 : cObjectivesBase(&vars,kFictionGoals),
824 mpMissionFile(NULL),
825 mState(kWaitForLoad),
826 mStateLocked(FALSE)
831 enum eRects
833 kDifficulty,
834 kGoOn,
835 kNumButts,
836 kText = kNumButts,
837 kCoarseDial,
838 kFineDial,
840 kNumRects,
842 kFirstDial = kCoarseDial,
845 enum
847 kNumDiffLevels = 3,
848 kNumDialImages = 20,
849 kNumDials = 2,
850 kFineDialRate = 16384, // bytes per frame
851 kFineDialFrames = 18,
854 enum eState
856 kWaitForLoad,
857 kLoad,
858 // kWaitForContinue,
859 kContinue,
860 kWaitForQuit,
861 kQuit,
865 // Add a file's size to our totals
866 void AddFile(ITagFile* file)
868 cAutoIPtr<ITagFileIter> iter = file->Iterate();
869 for (iter->Start(); !iter->Done(); iter->Next())
870 mFileTotal += file->BlockSize(iter->Tag());
873 void SetFile(ITagFile* file)
875 SafeRelease(mpMissionFile);
877 mpMissionFile = file;
878 file->AddRef();
883 void NextState(void)
885 mStateLocked=TRUE;
886 SetState(mState+1);
889 void SetState(int state)
891 mState = state;
893 static const char* button_names[] = { "continue", "loading", "loading", "continue", "continue" };
894 // change the button
895 int i = kGoOn;
896 mStrings[i] = FetchUIString(panel_name,button_names[mState],mResPath);
897 mElems[i].draw_data = (void*)(const char*)mStrings[i];
898 region_expose(LGadBoxRegion(LGadCurrentRoot()),&mRects[i]);
901 void UpdateDials(int bytes)
903 int old = mFileCur;
904 mFileCur += bytes;
906 //ConfigSpew("dial_spew",("bytes = %d delta = %d\n",mFileCur,bytes));
908 // update fine dial
910 int frame = mFileCur/mDialRate;
911 int oldframe = old/mDialRate;
912 if (frame != oldframe)
914 frame %= kNumDialImages;
915 DrawDialImage(kFineDial,frame);
920 // update coarse dial
922 int frame = mFileCur*kFineDialFrames/mFileTotal;
923 int oldframe = old*kFineDialFrames/mFileTotal;
924 if (frame != oldframe)
926 DrawDialImage(kCoarseDial,frame);
930 // pump events
931 pGameShell->PumpEvents(kPumpAll);
936 // File proxy that snoops reads and updates dials
939 class cLoadingFile: public cTagFileProxy
941 cLoading* mpUs;
942 public:
943 cLoadingFile(ITagFile* file, cLoading* us)
944 : cTagFileProxy(file), mpUs(us)
946 mpUs->AddFile(file);
949 STDMETHOD_(long,Read)(char* buf, int buflen)
951 mpUs->UpdateDials(buflen);
952 return cTagFileProxy::Read(buf,buflen);
955 STDMETHOD_(long,Move)(char* buf, int buflen)
957 mpUs->UpdateDials(buflen);
958 return cTagFileProxy::Move(buf,buflen);
966 // DB file factory that generates cLoadingFile objects wrapped
967 // around regular disk tag files.
970 class cLoadingFileFactory : public cDBFileFactory
972 cLoading* mpUs;
973 public:
974 cLoadingFileFactory(cLoading* us)
975 : mpUs(us)
979 ITagFile* Open(const char* filename, TagFileOpenMode mode)
981 char buf[256];
982 ConfigSpew("loading_open_spew",("Opening %s\n",filename));
983 // The factory is required to find the file
984 dbFind(filename,buf);
985 cAutoIPtr<ITagFile> file = BufTagFileOpen(buf,mode);
986 return new cLoadingFile(file,mpUs);
991 protected:
992 ITagFile* mpMissionFile;
993 IDataSource* mpDialImages[kNumDials][kNumDialImages];
995 int mState;
996 int mFileTotal;
997 int mFileCur;
998 int mDialRate;
999 BOOL mStateLocked; //sigh. If TRUE, kGoOn cannot use NextState.
1000 //set false on every frame. Prevents kGoOn button
1001 //from changing state while frame locked.
1003 void InitUI()
1005 cObjectivesBase::InitUI();
1007 for (int i = 0; i < kNumDials; i++)
1008 for(int j = 0; j < kNumDialImages; j++)
1010 char buf[16];
1011 sprintf(buf,"load%c_%d",'A'+i,j+1);
1012 ConfigSpew("dial_spew",("Binding %s\n",buf));
1013 mpDialImages[i][j] = FetchUIImage(buf,mResPath+"\\Dials");
1015 if (mFileTotal <= 0)
1016 mFileTotal = 1; // make sure this is not zero
1018 mDialRate = kFineDialRate;
1019 config_get_int("progress_dial_rate",&mDialRate);
1022 void TermUI()
1024 for (int i = 0; i < 2; i++)
1025 for(int j = 0; j < kNumDialImages; j++)
1027 SafeRelease(mpDialImages[i][j]);
1030 cObjectivesBase::TermUI();
1033 void DrawDialImage(int dial, int image)
1035 GUIcompose c;
1037 if (image >= kNumDialImages)
1038 image = kNumDialImages - 1;
1039 Rect& area = mRects[dial];
1040 IDataSource* img = mpDialImages[dial-kFirstDial][image];
1042 // ConfigSpew("dial_spew",("[%d %d] ",dial-kFirstDial,image));
1045 int compose_flags = ComposeFlagRead;
1046 GUIsetup(&c,&area,(GUIcomposeFlags)compose_flags,GUI_CANV_ANY);
1048 grs_bitmap* bm = (grs_bitmap*)img->Lock();
1049 gr_bitmap(bm,0,0);
1050 img->Unlock();
1052 GUIdone(&c);
1054 ScrnForceUpdateRect(&area);
1057 void OnButtonList(ushort action, int button)
1059 if (action & BUTTONGADG_LCLICK)
1061 switch (button)
1063 case kDifficulty:
1064 if (mState < kLoad)
1066 AutoAppIPtr(QuestData);
1067 int diff = pQuestData->Get(DIFF_QVAR);
1068 diff++;
1069 if (diff >= kNumDiffLevels)
1070 diff = 0;
1071 pQuestData->Set(DIFF_QVAR,diff);
1072 RedrawDisplay();
1074 break;
1076 case kGoOn:
1078 if (!mStateLocked)
1080 NextState();
1083 break;
1090 static long move_func(void* buf, size_t sz, size_t n)
1092 return gpLoading->mpMissionFile->Read((char*)buf,sz*n);
1095 void ReadMission(void)
1097 // load the objectives
1098 AutoAppIPtr(QuestData);
1099 pQuestData->DeleteAllType(kQuestDataMission);
1101 QuestDataLoadTagFile(kQuestDataMission,mpMissionFile);
1103 // load mission data
1104 LoadMissionData(mpMissionFile);
1105 LoadMapSourceInfo(mpMissionFile);
1109 virtual void DoFileLoad(ITagFile* file)
1111 dbLoadTagFile(file,kFiletypeAll);
1112 NextState();
1116 virtual void SetInitialFile(void)
1118 ITagFile* file = OpenMissionFile(GetNextMission());
1119 SetFile(file);
1120 SafeRelease(file);
1123 void OnLoopMsg(eLoopMessage msg, tLoopMessageData data)
1125 switch(msg)
1127 case kMsgEnterMode:
1129 mState = kWaitForLoad;
1130 SetInitialFile();
1132 ReadMission();
1134 break;
1136 case kMsgNormalFrame:
1137 case kMsgPauseFrame:
1139 mStateLocked = FALSE;
1140 switch (mState)
1142 case kLoad:
1144 uiHideMouse(NULL);
1145 ScrnForceUpdate();
1146 // Load the mission, then go to next state
1147 mFileCur = 1; // reset dial state
1148 mFileTotal = 1; // no dividing by zero
1150 // Set up the file factory
1151 cLoadingFileFactory fact(this);
1152 dbSetFileFactory(&fact);
1154 // load the file
1155 cLoadingFile* file = new cLoadingFile(mpMissionFile,this);
1156 DoFileLoad(file);
1157 DrawDialImage(kCoarseDial,kNumDialImages-1);
1159 uiShowMouse(NULL);
1160 dbSetFileFactory(NULL);
1161 SafeRelease(file);
1163 break;
1165 case kQuit:
1166 MissionLoopReset(kMissLoopMainMenu);
1167 // fall through
1168 case kContinue:
1169 UnwindToMissionLoop();
1170 break;
1174 break;
1176 case kMsgExitMode:
1178 SafeRelease(mpMissionFile);
1180 break;
1182 cObjectivesBase::OnLoopMsg(msg,data);
1185 void OnEscapeKey()
1187 // push to sim menu
1188 SwitchToSimMenuMode(TRUE);
1198 static const char* loading_button_names[] =
1200 "difficulty",
1201 "continue",
1204 sDarkPanelDesc cLoading::vars =
1206 "loading",
1207 cLoading::kNumButts,
1208 cLoading::kNumRects,
1209 cLoading::kNumButts,
1210 loading_button_names,
1214 void SwitchToLoadingMode(BOOL push)
1216 if (!gpLoading)
1217 gpLoading = new cLoading;
1218 if (gpLoading)
1220 IPanelMode* panel = gpLoading->GetPanelMode();
1222 panel->Switch((push) ? kLoopModePush : kLoopModeSwitch);
1223 SafeRelease(panel);
1230 const sLoopInstantiator* DescribeLoadingMode(void)
1232 if (!gpLoading)
1233 gpLoading = new cLoading;
1234 if (gpLoading)
1236 cAutoIPtr<IPanelMode> panel = gpLoading->GetPanelMode();
1238 return panel->Instantiator();
1240 return NULL;
1244 class cLoadingSaveGame: public cLoading
1247 void DoFileLoad(ITagFile* file)
1249 HRESULT retval = DarkLoadGame(file);
1250 if (FAILED(retval))
1252 // Replace the objectives with the "load failed" string
1254 // Set up the canvas & font
1255 Rect& area = mRects[num_butts];
1256 GUIcompose c;
1257 int compose_flags = ComposeFlagRead|ComposeFlagClear;
1258 GUIsetup(&c,&area,(GUIcomposeFlags)compose_flags,GUI_CANV_ANY);
1259 guiStyleSetupFont(&mTextStyle,StyleFontNormal);
1261 // Get the string
1262 cStr failed_str = FetchUIString("gamelod","failed",mResPath);
1263 char* failed = (char*)(const char*)failed_str;
1266 // Draw it
1267 short w,h;
1268 gr_string_size(failed,&w,&h);
1269 gr_set_fcolor(guiStyleGetColor(&mTextStyle,StyleColorText));
1270 gr_string(failed,(RectWidth(&area) - w)/2,(RectHeight(&area)-h)/2);
1272 guiStyleCleanupFont(&mTextStyle,StyleFontNormal);
1273 GUIdone(&c);
1275 // wait for acknowledgement
1276 SetState(kWaitForQuit);
1278 else
1279 NextState();
1282 void SetInitialFile()
1284 // we already have a file, we promise.
1285 Assert_(mpMissionFile);
1287 // Load the campaign vars out of it.
1288 // All we really need is difficulty. Oh well.
1289 AutoAppIPtr(QuestData);
1290 pQuestData->DeleteAllType(kQuestDataCampaign);
1292 QuestDataLoadTagFile(kQuestDataCampaign,mpMissionFile);
1297 void OnLoopMsg(eLoopMessage msg, tLoopMessageData data)
1299 cLoading::OnLoopMsg(msg,data);
1300 switch(msg)
1302 case kMsgEnterMode:
1304 NextState(); // start in loading state
1306 break;
1310 void InitUI()
1312 cLoading::InitUI();
1313 // erase diff button
1314 mElems[(int)kDifficulty].draw_data = "";
1315 // Do all goals have fiction strings?
1316 mFlags &= ~kFictionGoals;
1321 static cLoadingSaveGame* gpLoadingSaveGame = NULL;
1323 void PushToSaveGameLoadingMode(ITagFile* file)
1325 if (!gpLoadingSaveGame)
1326 gpLoadingSaveGame = new cLoadingSaveGame;
1328 gpLoadingSaveGame->SetFile(file);
1329 IPanelMode* panel = gpLoadingSaveGame->GetPanelMode();
1330 panel->Switch(kLoopModePush);
1331 SafeRelease(panel);
1336 //------------------------------------------------------------------
1337 // INIT/TERM
1341 void init_commands();
1343 void DebriefInit()
1345 init_commands();
1348 void DebriefTerm()
1350 delete gpObjectives;
1351 delete gpDebrief;
1352 delete gpLoading;
1353 delete gpLoadingSaveGame;
1357 //----------------------------------------
1358 // COMMANDS
1361 static void do_debrief()
1363 SwitchToDebriefMode(TRUE);
1366 static void do_objectives()
1368 SwitchToObjectivesMode(TRUE);
1372 static Command commands[] =
1374 { "debrief", FUNC_VOID, do_debrief, "Go to debrief UI.", HK_ALL },
1375 { "objectives", FUNC_VOID, do_objectives, "Go to objectives UI.", HK_ALL },
1379 static void init_commands()
1381 COMMANDS(commands,HK_ALL);