1 //=============================================================================
2 //
3 // Adventure Game Studio (AGS)
4 //
5 // Copyright (C) 1999-2011 Chris Jones and 2011-20xx others
6 // The full list of copyright holders can be found in the Copyright.txt
7 // file, which is part of this source code distribution.
8 //
9 // The AGS source code is provided under the Artistic License 2.0.
10 // A copy of this license can be found in the file License.txt and at
11 // http://www.opensource.org/licenses/artistic-license-2.0.php
12 //
13 //=============================================================================
14 
15 #include <stdio.h>
16 #include "gui/guidialog.h"
17 #include "ac/common.h"
18 #include "ac/draw.h"
19 #include "ac/game.h"
20 #include "ac/gamesetup.h"
21 #include "ac/gamesetupstruct.h"
22 #include "gui/cscidialog.h"
23 #include <cctype> //isdigit()
24 #include "gfx/bitmap.h"
25 #include "gfx/graphicsdriver.h"
26 
27 using namespace AGS::Common;
28 using namespace AGS::Engine;
29 
30 extern IGraphicsDriver *gfxDriver;
31 extern GameSetup usetup;
32 
33 // from ac_game
34 extern char saveGameDirectory[260];
35 
36 int windowPosX, windowPosY, windowPosWidth, windowPosHeight;
37 Bitmap *windowBuffer;
38 IDriverDependantBitmap *dialogBmp;
39 
40 #undef MAXSAVEGAMES
41 #define MAXSAVEGAMES 20
42 DisplayProperties dispp;
43 char *lpTemp, *lpTemp2;
44 char bufTemp[260], buffer2[260];
45 int numsaves = 0, toomanygames;
46 int filenumbers[MAXSAVEGAMES];
47 unsigned long filedates[MAXSAVEGAMES];
48 
49 CSCIMessage smes;
50 
51 char buff[200];
52 int myscrnwid = 320, myscrnhit = 200;
53 
54 
prepare_gui_screen(int x,int y,int width,int height,bool opaque)55 void prepare_gui_screen(int x, int y, int width, int height, bool opaque)
56 {
57     clear_gui_screen();
58     windowPosX = x;
59     windowPosY = y;
60     windowPosWidth = width;
61     windowPosHeight = height;
62     if (windowBuffer)
63     {
64         windowBuffer = recycle_bitmap(windowBuffer, windowBuffer->GetColorDepth(), windowPosWidth, windowPosHeight, !opaque);
65     }
66     else
67     {
68         windowBuffer = BitmapHelper::CreateBitmap(windowPosWidth, windowPosHeight, GetVirtualScreen()->GetColorDepth());
69         windowBuffer = ReplaceBitmapWithSupportedFormat(windowBuffer);
70     }
71     dialogBmp = recycle_ddb_bitmap(dialogBmp, windowBuffer, false, opaque);
72 }
73 
clear_gui_screen()74 void clear_gui_screen()
75 {
76     if (dialogBmp)
77         gfxDriver->DestroyDDB(dialogBmp);
78     dialogBmp = NULL;
79     delete windowBuffer;
80     windowBuffer = NULL;
81 }
82 
refresh_gui_screen()83 void refresh_gui_screen()
84 {
85     Bitmap *ds = GetVirtualScreen();
86     windowBuffer->Blit(ds, windowPosX, windowPosY, 0, 0, windowPosWidth, windowPosHeight);
87     gfxDriver->UpdateDDBFromBitmap(dialogBmp, windowBuffer, false);
88 
89     render_graphics(dialogBmp, windowPosX, windowPosY);
90 
91     // Copy it back, because the mouse will have been drawn on top
92     ds->Blit(windowBuffer, 0, 0, windowPosX, windowPosY, windowPosWidth, windowPosHeight);
93 }
94 
loadgamedialog()95 int loadgamedialog()
96 {
97   int boxleft = myscrnwid / 2 - 100;
98   int boxtop = myscrnhit / 2 - 60;
99   int buttonhit = usetup.textheight + 5;
100   Bitmap *ds = GetVirtualScreen();
101   int handl = CSCIDrawWindow(ds, boxleft, boxtop, 200, 120);
102   int ctrlok =
103     CSCICreateControl(CNT_PUSHBUTTON | CNF_DEFAULT, boxleft + 135, boxtop + 5, 60, 10, get_global_message(MSG_RESTORE));
104   int ctrlcancel =
105     CSCICreateControl(CNT_PUSHBUTTON | CNF_CANCEL, boxleft + 135, boxtop + 5 + buttonhit, 60, 10,
106                       get_global_message(MSG_CANCEL));
107   int ctrllist = CSCICreateControl(CNT_LISTBOX, boxleft + 10, boxtop + 30, 120, 80, NULL);
108   int ctrltex1 = CSCICreateControl(CNT_LABEL, boxleft + 10, boxtop + 5, 120, 0, get_global_message(MSG_SELECTLOAD));
109   CSCISendControlMessage(ctrllist, CLB_CLEAR, 0, 0);
110 
111   preparesavegamelist(ctrllist);
112   CSCIMessage mes;
113   lpTemp = NULL;
114   int toret = -1;
115   while (1) {
116     CSCIWaitMessage(ds, &mes);      //printf("mess: %d, id %d ",mes.code,mes.id);
117     if (mes.code == CM_COMMAND) {
118       if (mes.id == ctrlok) {
119         int cursel = CSCISendControlMessage(ctrllist, CLB_GETCURSEL, 0, 0);
120         if ((cursel >= numsaves) | (cursel < 0))
121           lpTemp = NULL;
122         else {
123           toret = filenumbers[cursel];
124           String path = get_save_game_path(toret);
125           strcpy(bufTemp, path);
126           lpTemp = &bufTemp[0];
127         }
128       } else if (mes.id == ctrlcancel) {
129         lpTemp = NULL;
130       }
131 
132       break;
133     }
134   }
135 
136   CSCIDeleteControl(ctrltex1);
137   CSCIDeleteControl(ctrllist);
138   CSCIDeleteControl(ctrlok);
139   CSCIDeleteControl(ctrlcancel);
140   CSCIEraseWindow(ds, handl);
141   return toret;
142 }
143 
savegamedialog()144 int savegamedialog()
145 {
146   char okbuttontext[50];
147   strcpy(okbuttontext, get_global_message(MSG_SAVEBUTTON));
148   char labeltext[200];
149   strcpy(labeltext, get_global_message(MSG_SAVEDIALOG));
150   int boxleft = myscrnwid / 2 - 100;
151   int boxtop = myscrnhit / 2 - 60;
152   int buttonhit = usetup.textheight + 5;
153   int labeltop = boxtop + 5;
154   Bitmap *ds = GetVirtualScreen();
155   int handl = CSCIDrawWindow(ds, boxleft, boxtop, 200, 120);
156   int ctrlcancel =
157     CSCICreateControl(CNT_PUSHBUTTON | CNF_CANCEL, boxleft + 135, boxtop + 5 + buttonhit, 60, 10,
158                       get_global_message(MSG_CANCEL));
159   int ctrllist = CSCICreateControl(CNT_LISTBOX, boxleft + 10, boxtop + 40, 120, 80, NULL);
160   int ctrltbox = 0;
161 
162   CSCISendControlMessage(ctrllist, CLB_CLEAR, 0, 0);    // clear the list box
163   preparesavegamelist(ctrllist);
164   if (toomanygames) {
165     strcpy(okbuttontext, get_global_message(MSG_REPLACE));
166     strcpy(labeltext, get_global_message(MSG_MUSTREPLACE));
167     labeltop = boxtop + 2;
168   } else
169     ctrltbox = CSCICreateControl(CNT_TEXTBOX, boxleft + 10, boxtop + 29, 120, 0, NULL);
170 
171   int ctrlok = CSCICreateControl(CNT_PUSHBUTTON | CNF_DEFAULT, boxleft + 135, boxtop + 5, 60, 10, okbuttontext);
172   int ctrltex1 = CSCICreateControl(CNT_LABEL, boxleft + 10, labeltop, 120, 0, labeltext);
173   CSCIMessage mes;
174 
175   lpTemp = NULL;
176   if (numsaves > 0)
177     CSCISendControlMessage(ctrllist, CLB_GETTEXT, 0, (long)&buffer2[0]);
178   else
179     buffer2[0] = 0;
180 
181   CSCISendControlMessage(ctrltbox, CTB_SETTEXT, 0, (long)&buffer2[0]);
182 
183   int toret = -1;
184   while (1) {
185     CSCIWaitMessage(ds, &mes);      //printf("mess: %d, id %d ",mes.code,mes.id);
186     if (mes.code == CM_COMMAND) {
187       if (mes.id == ctrlok) {
188         int cursell = CSCISendControlMessage(ctrllist, CLB_GETCURSEL, 0, 0);
189         CSCISendControlMessage(ctrltbox, CTB_GETTEXT, 0, (long)&buffer2[0]);
190 
191         if (numsaves > 0)
192           CSCISendControlMessage(ctrllist, CLB_GETTEXT, cursell, (long)&bufTemp[0]);
193         else
194           strcpy(bufTemp, "_NOSAVEGAMENAME");
195 
196         if (toomanygames) {
197           int nwhand = CSCIDrawWindow(ds, boxleft + 5, boxtop + 20, 190, 65);
198           int lbl1 =
199             CSCICreateControl(CNT_LABEL, boxleft + 20, boxtop + 25, 160, 0, get_global_message(MSG_REPLACEWITH1));
200           int lbl2 = CSCICreateControl(CNT_LABEL, boxleft + 30, boxtop + 34, 160, 0, bufTemp);
201           int lbl3 =
202             CSCICreateControl(CNT_LABEL, boxleft + 20, boxtop + 45, 160, 0, get_global_message(MSG_REPLACEWITH2));
203           int txt1 = CSCICreateControl(CNT_TEXTBOX, boxleft + 20, boxtop + 55, 160, 0, bufTemp);
204           int btnOk =
205             CSCICreateControl(CNT_PUSHBUTTON | CNF_DEFAULT, boxleft + 30, boxtop + 70, 60, 10,
206                               get_global_message(MSG_REPLACE));
207           int btnCancel =
208             CSCICreateControl(CNT_PUSHBUTTON | CNF_CANCEL, boxleft + 100, boxtop + 70, 60, 10,
209                               get_global_message(MSG_CANCEL));
210 
211           CSCIMessage cmes;
212           do {
213             CSCIWaitMessage(ds, &cmes);
214           } while (cmes.code != CM_COMMAND);
215 
216           CSCISendControlMessage(txt1, CTB_GETTEXT, 0, (long)&buffer2[0]);
217           CSCIDeleteControl(btnCancel);
218           CSCIDeleteControl(btnOk);
219           CSCIDeleteControl(txt1);
220           CSCIDeleteControl(lbl3);
221           CSCIDeleteControl(lbl2);
222           CSCIDeleteControl(lbl1);
223           CSCIEraseWindow(ds, nwhand);
224           bufTemp[0] = 0;
225 
226           if (cmes.id == btnCancel) {
227             lpTemp = NULL;
228             break;
229           } else
230             toret = filenumbers[cursell];
231 
232         }
233         else if (strcmp(buffer2, bufTemp) != 0) {     // create a new game (description different)
234           int highestnum = 0;
235           for (int pp = 0; pp < numsaves; pp++) {
236             if (filenumbers[pp] > highestnum)
237               highestnum = filenumbers[pp];
238           }
239 
240           if (highestnum > 90)
241             quit("Save game directory overflow");
242 
243           toret = highestnum + 1;
244           String path = get_save_game_path(toret);
245           strcpy(bufTemp, path);
246         }
247         else {
248           toret = filenumbers[cursell];
249           bufTemp[0] = 0;
250         }
251 
252         if (bufTemp[0] == 0)
253         {
254           String path = get_save_game_path(toret);
255           strcpy(bufTemp, path);
256         }
257 
258         lpTemp = &bufTemp[0];
259         lpTemp2 = &buffer2[0];
260       } else if (mes.id == ctrlcancel) {
261         lpTemp = NULL;
262       }
263       break;
264     } else if (mes.code == CM_SELCHANGE) {
265       int cursel = CSCISendControlMessage(ctrllist, CLB_GETCURSEL, 0, 0);
266       if (cursel >= 0) {
267         CSCISendControlMessage(ctrllist, CLB_GETTEXT, cursel, (long)&buffer2[0]);
268         CSCISendControlMessage(ctrltbox, CTB_SETTEXT, 0, (long)&buffer2[0]);
269       }
270     }
271   }
272 
273   CSCIDeleteControl(ctrltbox);
274   CSCIDeleteControl(ctrltex1);
275   CSCIDeleteControl(ctrllist);
276   CSCIDeleteControl(ctrlok);
277   CSCIDeleteControl(ctrlcancel);
278   CSCIEraseWindow(ds, handl);
279   return toret;
280 }
281 
preparesavegamelist(int ctrllist)282 void preparesavegamelist(int ctrllist)
283 {
284   numsaves = 0;
285   toomanygames = 0;
286   al_ffblk ffb;
287   int bufix = 0;
288   char curdir[255];
289   _getcwd(curdir, 255);
290 
291   char searchPath[260];
292   sprintf(searchPath, "%s""agssave.*%s", saveGameDirectory, saveGameSuffix.GetCStr());
293 
294   int don = al_findfirst(searchPath, &ffb, -1);
295   while (!don) {
296     bufix = 0;
297     if (numsaves >= MAXSAVEGAMES) {
298       toomanygames = 1;
299       break;
300     }
301 
302     // only list games .000 to .099 (to allow higher slots for other purposes)
303     if (strstr(ffb.name, ".0") == NULL) {
304       don = al_findnext(&ffb);
305       continue;
306     }
307 
308     const char *numberExtension = strstr(ffb.name, ".0") + 1;
309     int sgNumber = atoi(numberExtension);
310 
311     String thisGamePath = get_save_game_path(sgNumber);
312 
313     // get description
314     String description;
315     read_savedgame_description(thisGamePath, description);
316 
317     CSCISendControlMessage(ctrllist, CLB_ADDITEM, 0, (long)description.GetCStr());
318     // Select the first item
319     CSCISendControlMessage(ctrllist, CLB_SETCURSEL, 0, 0);
320     filenumbers[numsaves] = sgNumber;
321     filedates[numsaves] = (long int)ffb.time;
322     numsaves++;
323     don = al_findnext(&ffb);
324   }
325 
326   al_findclose(&ffb);
327   if (numsaves >= MAXSAVEGAMES)
328     toomanygames = 1;
329 
330   for (int nn = 0; nn < numsaves - 1; nn++) {
331     for (int kk = 0; kk < numsaves - 1; kk++) { // Date order the games
332       if (filedates[kk] < filedates[kk + 1]) {  // swap them round
333         CSCISendControlMessage(ctrllist, CLB_GETTEXT, kk, (long)&buff[0]);
334         CSCISendControlMessage(ctrllist, CLB_GETTEXT, kk + 1, (long)&buffer2[0]);
335         CSCISendControlMessage(ctrllist, CLB_SETTEXT, kk + 1, (long)&buff[0]);
336         CSCISendControlMessage(ctrllist, CLB_SETTEXT, kk, (long)&buffer2[0]);
337         int numtem = filenumbers[kk];
338         filenumbers[kk] = filenumbers[kk + 1];
339         filenumbers[kk + 1] = numtem;
340         long numted = filedates[kk];
341         filedates[kk] = filedates[kk + 1];
342         filedates[kk + 1] = numted;
343       }
344     }
345   }
346 }
347 
enterstringwindow(const char * prompttext,char * stouse)348 void enterstringwindow(const char *prompttext, char *stouse)
349 {
350   int boxleft = 60, boxtop = 80;
351   int wantCancel = 0;
352   if (prompttext[0] == '!') {
353     wantCancel = 1;
354     prompttext++;
355   }
356   Bitmap *ds = GetVirtualScreen();
357   int handl = CSCIDrawWindow(ds, boxleft, boxtop, 200, 40);
358   int ctrlok = CSCICreateControl(CNT_PUSHBUTTON | CNF_DEFAULT, boxleft + 135, boxtop + 5, 60, 10, "OK");
359   int ctrlcancel = -1;
360   if (wantCancel)
361     ctrlcancel = CSCICreateControl(CNT_PUSHBUTTON | CNF_CANCEL, boxleft + 135, boxtop + 20, 60, 10, get_global_message(MSG_CANCEL));
362   int ctrltbox = CSCICreateControl(CNT_TEXTBOX, boxleft + 10, boxtop + 29, 120, 0, NULL);
363   int ctrltex1 = CSCICreateControl(CNT_LABEL, boxleft + 10, boxtop + 5, 120, 0, prompttext);
364   CSCIMessage mes;
365 
366   while (1) {
367     CSCIWaitMessage(ds, &mes);
368     if (mes.code == CM_COMMAND) {
369       if (mes.id == ctrlcancel)
370         buffer2[0] = 0;
371       else
372         CSCISendControlMessage(ctrltbox, CTB_GETTEXT, 0, (long)&buffer2[0]);
373       break;
374     }
375   }
376 
377   CSCIDeleteControl(ctrltex1);
378   CSCIDeleteControl(ctrltbox);
379   CSCIDeleteControl(ctrlok);
380   if (wantCancel)
381     CSCIDeleteControl(ctrlcancel);
382   CSCIEraseWindow(ds, handl);
383   strcpy(stouse, buffer2);
384 }
385 
enternumberwindow(char * prompttext)386 int enternumberwindow(char *prompttext)
387 {
388   char ourbuf[200];
389   enterstringwindow(prompttext, ourbuf);
390   if (ourbuf[0] == 0)
391     return -9999;
392   return atoi(ourbuf);
393 }
394 
roomSelectorWindow(int currentRoom,int numRooms,int * roomNumbers,char ** roomNames)395 int roomSelectorWindow(int currentRoom, int numRooms, int*roomNumbers, char**roomNames)
396 {
397   char labeltext[200];
398   strcpy(labeltext, get_global_message(MSG_SAVEDIALOG));
399   int boxleft = myscrnwid / 2 - 120;
400   int boxtop = myscrnhit / 2 - 80;
401   int labeltop = boxtop + 5;
402   Bitmap *ds = GetVirtualScreen();
403   int handl = CSCIDrawWindow(ds, boxleft, boxtop, 240, 160);
404   int ctrllist = CSCICreateControl(CNT_LISTBOX, boxleft + 10, boxtop + 40, 220, 100, NULL);
405   int ctrlcancel =
406     CSCICreateControl(CNT_PUSHBUTTON | CNF_CANCEL, boxleft + 80, boxtop + 145, 60, 10, "Cancel");
407 
408   CSCISendControlMessage(ctrllist, CLB_CLEAR, 0, 0);    // clear the list box
409   for (int aa = 0; aa < numRooms; aa++)
410   {
411     sprintf(buff, "%3d %s", roomNumbers[aa], roomNames[aa]);
412     CSCISendControlMessage(ctrllist, CLB_ADDITEM, 0, (long)&buff[0]);
413     if (roomNumbers[aa] == currentRoom)
414     {
415       CSCISendControlMessage(ctrllist, CLB_SETCURSEL, aa, 0);
416     }
417   }
418 
419   int ctrlok = CSCICreateControl(CNT_PUSHBUTTON | CNF_DEFAULT, boxleft + 10, boxtop + 145, 60, 10, "OK");
420   int ctrltex1 = CSCICreateControl(CNT_LABEL, boxleft + 10, labeltop, 180, 0, "Choose which room to go to:");
421   CSCIMessage mes;
422 
423   lpTemp = NULL;
424   buffer2[0] = 0;
425 
426   int ctrltbox = CSCICreateControl(CNT_TEXTBOX, boxleft + 10, boxtop + 29, 120, 0, NULL);
427   CSCISendControlMessage(ctrltbox, CTB_SETTEXT, 0, (long)&buffer2[0]);
428 
429   int toret = -1;
430   while (1) {
431     CSCIWaitMessage(ds, &mes);      //printf("mess: %d, id %d ",mes.code,mes.id);
432     if (mes.code == CM_COMMAND)
433     {
434       if (mes.id == ctrlok)
435       {
436         CSCISendControlMessage(ctrltbox, CTB_GETTEXT, 0, (long)&buffer2[0]);
437         if (isdigit(buffer2[0]))
438         {
439           toret = atoi(buffer2);
440         }
441       }
442       else if (mes.id == ctrlcancel)
443       {
444       }
445       break;
446     }
447     else if (mes.code == CM_SELCHANGE)
448     {
449       int cursel = CSCISendControlMessage(ctrllist, CLB_GETCURSEL, 0, 0);
450       if (cursel >= 0)
451       {
452         sprintf(buffer2, "%d", roomNumbers[cursel]);
453         CSCISendControlMessage(ctrltbox, CTB_SETTEXT, 0, (long)&buffer2[0]);
454       }
455     }
456   }
457 
458   CSCIDeleteControl(ctrltbox);
459   CSCIDeleteControl(ctrltex1);
460   CSCIDeleteControl(ctrllist);
461   CSCIDeleteControl(ctrlok);
462   CSCIDeleteControl(ctrlcancel);
463   CSCIEraseWindow(ds, handl);
464   return toret;
465 }
466 
myscimessagebox(const char * lpprompt,char * btn1,char * btn2)467 int myscimessagebox(const char *lpprompt, char *btn1, char *btn2)
468 {
469     Bitmap *ds = GetVirtualScreen();
470     int windl = CSCIDrawWindow(ds, 80, 80, 240 - 80, 120 - 80);
471     int lbl1 = CSCICreateControl(CNT_LABEL, 90, 85, 150, 0, lpprompt);
472     int btflag = CNT_PUSHBUTTON;
473 
474     if (btn2 == NULL)
475         btflag |= CNF_DEFAULT | CNF_CANCEL;
476     else
477         btflag |= CNF_DEFAULT;
478 
479     int btnQuit = CSCICreateControl(btflag, 90, 105, 60, 10, btn1);
480     int btnPlay = 0;
481 
482     if (btn2 != NULL)
483         btnPlay = CSCICreateControl(CNT_PUSHBUTTON | CNF_CANCEL, 165, 105, 60, 10, btn2);
484 
485     smes.code = 0;
486 
487     do {
488         CSCIWaitMessage(ds, &smes);
489     } while (smes.code != CM_COMMAND);
490 
491     if (btnPlay)
492         CSCIDeleteControl(btnPlay);
493 
494     CSCIDeleteControl(btnQuit);
495     CSCIDeleteControl(lbl1);
496     CSCIEraseWindow(ds, windl);
497 
498     if (smes.id == btnQuit)
499         return 1;
500 
501     return 0;
502 }
503 
quitdialog()504 int quitdialog()
505 {
506     char quitbut[50], playbut[50];
507     strcpy(quitbut, get_global_message(MSG_QUITBUTTON));
508     strcpy(playbut, get_global_message(MSG_PLAYBUTTON));
509     return myscimessagebox(get_global_message(MSG_QUITDIALOG), quitbut, playbut);
510 }
511