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 "ac/gui.h"
17 #include "ac/common.h"
18 #include "ac/draw.h"
19 #include "ac/event.h"
20 #include "ac/gamesetup.h"
21 #include "ac/gamesetupstruct.h"
22 #include "ac/global_character.h"
23 #include "ac/global_game.h"
24 #include "ac/global_gui.h"
25 #include "ac/global_inventoryitem.h"
26 #include "ac/global_screen.h"
27 #include "ac/guicontrol.h"
28 #include "ac/interfacebutton.h"
29 #include "ac/invwindow.h"
30 #include "ac/mouse.h"
31 #include "ac/roomstruct.h"
32 #include "ac/runtime_defines.h"
33 #include "ac/system.h"
34 #include "ac/dynobj/cc_guiobject.h"
35 #include "ac/dynobj/scriptgui.h"
36 #include "script/cc_instance.h"
37 #include "debug/debug_log.h"
38 #include "device/mousew32.h"
39 #include "gfx/gfxfilter.h"
40 #include "gui/guibutton.h"
41 #include "gui/guimain.h"
42 #include "script/script.h"
43 #include "script/script_runtime.h"
44 #include "gfx/graphicsdriver.h"
45 #include "gfx/bitmap.h"
46 #include "ac/dynobj/cc_gui.h"
47 #include "ac/dynobj/cc_guiobject.h"
48 #include "script/runtimescriptvalue.h"
49 
50 using namespace AGS::Common;
51 using namespace AGS::Engine;
52 
53 
54 extern GameSetup usetup;
55 extern roomstruct thisroom;
56 extern int cur_mode,cur_cursor;
57 extern ccInstance *gameinst;
58 extern ScriptGUI *scrGui;
59 extern GameSetupStruct game;
60 extern CCGUIObject ccDynamicGUIObject;
61 extern Bitmap **guibg;
62 extern IDriverDependantBitmap **guibgbmp;
63 extern IGraphicsDriver *gfxDriver;
64 
65 extern CCGUI ccDynamicGUI;
66 extern CCGUIObject ccDynamicGUIObject;
67 
68 
69 int ifacepopped=-1;  // currently displayed pop-up GUI (-1 if none)
70 int mouse_on_iface=-1;   // mouse cursor is over this interface
71 int mouse_on_iface_button=-1;
72 int mouse_pushed_iface=-1;  // this BUTTON on interface MOUSE_ON_IFACE is pushed
73 int mouse_ifacebut_xoffs=-1,mouse_ifacebut_yoffs=-1;
74 
75 int eip_guinum, eip_guiobj;
76 
77 
GUI_SetVisible(ScriptGUI * tehgui,int isvisible)78 void GUI_SetVisible(ScriptGUI *tehgui, int isvisible) {
79   if (isvisible)
80     InterfaceOn(tehgui->id);
81   else
82     InterfaceOff(tehgui->id);
83 }
84 
GUI_GetVisible(ScriptGUI * tehgui)85 int GUI_GetVisible(ScriptGUI *tehgui) {
86   // GUI_GetVisible is slightly different from IsGUIOn, because
87   // with a mouse ypos gui it returns 1 if the GUI is enabled,
88   // whereas IsGUIOn actually checks if it is displayed
89   if (!guis[tehgui->id].IsOff())
90     return 1;
91   return 0;
92 }
93 
GUI_GetX(ScriptGUI * tehgui)94 int GUI_GetX(ScriptGUI *tehgui) {
95   return divide_down_coordinate(guis[tehgui->id].X);
96 }
97 
GUI_SetX(ScriptGUI * tehgui,int xx)98 void GUI_SetX(ScriptGUI *tehgui, int xx) {
99   guis[tehgui->id].X = multiply_up_coordinate(xx);
100 }
101 
GUI_GetY(ScriptGUI * tehgui)102 int GUI_GetY(ScriptGUI *tehgui) {
103   return divide_down_coordinate(guis[tehgui->id].Y);
104 }
105 
GUI_SetY(ScriptGUI * tehgui,int yy)106 void GUI_SetY(ScriptGUI *tehgui, int yy) {
107   guis[tehgui->id].Y = multiply_up_coordinate(yy);
108 }
109 
GUI_SetPosition(ScriptGUI * tehgui,int xx,int yy)110 void GUI_SetPosition(ScriptGUI *tehgui, int xx, int yy) {
111   GUI_SetX(tehgui, xx);
112   GUI_SetY(tehgui, yy);
113 }
114 
GUI_SetSize(ScriptGUI * sgui,int widd,int hitt)115 void GUI_SetSize(ScriptGUI *sgui, int widd, int hitt) {
116   if ((widd < 1) || (hitt < 1))
117     quitprintf("!SetGUISize: invalid dimensions (tried to set to %d x %d)", widd, hitt);
118 
119   GUIMain *tehgui = &guis[sgui->id];
120   multiply_up_coordinates(&widd, &hitt);
121 
122   if ((tehgui->Width == widd) && (tehgui->Height == hitt))
123     return;
124 
125   tehgui->Width = widd;
126   tehgui->Height = hitt;
127 
128   recreate_guibg_image(tehgui);
129 
130   guis_need_update = 1;
131 }
132 
GUI_GetWidth(ScriptGUI * sgui)133 int GUI_GetWidth(ScriptGUI *sgui) {
134   return divide_down_coordinate(guis[sgui->id].Width);
135 }
136 
GUI_GetHeight(ScriptGUI * sgui)137 int GUI_GetHeight(ScriptGUI *sgui) {
138   return divide_down_coordinate(guis[sgui->id].Height);
139 }
140 
GUI_SetWidth(ScriptGUI * sgui,int newwid)141 void GUI_SetWidth(ScriptGUI *sgui, int newwid) {
142   GUI_SetSize(sgui, newwid, GUI_GetHeight(sgui));
143 }
144 
GUI_SetHeight(ScriptGUI * sgui,int newhit)145 void GUI_SetHeight(ScriptGUI *sgui, int newhit) {
146   GUI_SetSize(sgui, GUI_GetWidth(sgui), newhit);
147 }
148 
GUI_SetZOrder(ScriptGUI * tehgui,int z)149 void GUI_SetZOrder(ScriptGUI *tehgui, int z) {
150   guis[tehgui->id].ZOrder = z;
151   update_gui_zorder();
152 }
153 
GUI_GetZOrder(ScriptGUI * tehgui)154 int GUI_GetZOrder(ScriptGUI *tehgui) {
155   return guis[tehgui->id].ZOrder;
156 }
157 
GUI_SetClickable(ScriptGUI * tehgui,int clickable)158 void GUI_SetClickable(ScriptGUI *tehgui, int clickable) {
159   guis[tehgui->id].Flags &= ~kGUIMain_NoClick;
160   if (clickable == 0)
161     guis[tehgui->id].Flags |= kGUIMain_NoClick;
162 }
163 
GUI_GetClickable(ScriptGUI * tehgui)164 int GUI_GetClickable(ScriptGUI *tehgui) {
165   if (guis[tehgui->id].Flags & kGUIMain_NoClick)
166     return 0;
167   return 1;
168 }
169 
GUI_GetID(ScriptGUI * tehgui)170 int GUI_GetID(ScriptGUI *tehgui) {
171   return tehgui->id;
172 }
173 
GUI_GetiControls(ScriptGUI * tehgui,int idx)174 GUIObject* GUI_GetiControls(ScriptGUI *tehgui, int idx) {
175   if ((idx < 0) || (idx >= guis[tehgui->id].ControlCount))
176     return NULL;
177   return guis[tehgui->id].Controls[idx];
178 }
179 
GUI_GetControlCount(ScriptGUI * tehgui)180 int GUI_GetControlCount(ScriptGUI *tehgui) {
181   return guis[tehgui->id].ControlCount;
182 }
183 
GUI_SetTransparency(ScriptGUI * tehgui,int trans)184 void GUI_SetTransparency(ScriptGUI *tehgui, int trans) {
185   if ((trans < 0) | (trans > 100))
186     quit("!SetGUITransparency: transparency value must be between 0 and 100");
187 
188   guis[tehgui->id].SetTransparencyAsPercentage(trans);
189 }
190 
GUI_GetTransparency(ScriptGUI * tehgui)191 int GUI_GetTransparency(ScriptGUI *tehgui) {
192   if (guis[tehgui->id].Transparency == 0)
193     return 0;
194   if (guis[tehgui->id].Transparency == 255)
195     return 100;
196 
197   return 100 - ((guis[tehgui->id].Transparency * 10) / 25);
198 }
199 
GUI_Centre(ScriptGUI * sgui)200 void GUI_Centre(ScriptGUI *sgui) {
201   GUIMain *tehgui = &guis[sgui->id];
202   tehgui->X = play.viewport.GetWidth() / 2 - tehgui->Width / 2;
203   tehgui->Y = play.viewport.GetHeight() / 2 - tehgui->Height / 2;
204 }
205 
GUI_SetBackgroundGraphic(ScriptGUI * tehgui,int slotn)206 void GUI_SetBackgroundGraphic(ScriptGUI *tehgui, int slotn) {
207   if (guis[tehgui->id].BgImage != slotn) {
208     guis[tehgui->id].BgImage = slotn;
209     guis_need_update = 1;
210   }
211 }
212 
GUI_GetBackgroundGraphic(ScriptGUI * tehgui)213 int GUI_GetBackgroundGraphic(ScriptGUI *tehgui) {
214   if (guis[tehgui->id].BgImage < 1)
215     return 0;
216   return guis[tehgui->id].BgImage;
217 }
218 
GetGUIAtLocation(int xx,int yy)219 ScriptGUI *GetGUIAtLocation(int xx, int yy) {
220     int guiid = GetGUIAt(xx, yy);
221     if (guiid < 0)
222         return NULL;
223     return &scrGui[guiid];
224 }
225 
GUI_Click(ScriptGUI * scgui,int mbut)226 void GUI_Click(ScriptGUI *scgui, int mbut)
227 {
228     process_interface_click(scgui->id, -1, mbut);
229 }
230 
GUI_ProcessClick(int x,int y,int mbut)231 void GUI_ProcessClick(int x, int y, int mbut)
232 {
233     int guiid = gui_get_interactable(x, y);
234     if (guiid >= 0)
235     {
236         const int real_mousex = mousex;
237         const int real_mousey = mousey;
238         mousex = x;
239         mousey = y;
240         guis[guiid].Poll();
241         gui_on_mouse_down(guiid, mbut);
242         gui_on_mouse_up(guiid, mbut);
243         mousex = real_mousex;
244         mousey = real_mousey;
245     }
246 }
247 
248 //=============================================================================
249 
remove_popup_interface(int ifacenum)250 void remove_popup_interface(int ifacenum) {
251     if (ifacepopped != ifacenum) return;
252     ifacepopped=-1; UnPauseGame();
253     guis[ifacenum].SetVisibility(kGUIVisibility_Off);
254     if (mousey<=guis[ifacenum].PopupAtMouseY)
255         Mouse::SetPosition(Point(mousex, guis[ifacenum].PopupAtMouseY+2));
256     if ((!IsInterfaceEnabled()) && (cur_cursor == cur_mode))
257         // Only change the mouse cursor if it hasn't been specifically changed first
258         set_mouse_cursor(CURS_WAIT);
259     else if (IsInterfaceEnabled())
260         set_default_cursor();
261 
262     if (ifacenum==mouse_on_iface) mouse_on_iface=-1;
263     guis_need_update = 1;
264 }
265 
process_interface_click(int ifce,int btn,int mbut)266 void process_interface_click(int ifce, int btn, int mbut) {
267     if (btn < 0) {
268         // click on GUI background
269         QueueScriptFunction(kScInstGame, guis[ifce].OnClickHandler, 2,
270             RuntimeScriptValue().SetDynamicObject(&scrGui[ifce], &ccDynamicGUI),
271             RuntimeScriptValue().SetInt32(mbut));
272         return;
273     }
274 
275     int btype=(guis[ifce].CtrlRefs[btn] >> 16) & 0x000ffff;
276     int rtype=0,rdata;
277     if (btype==kGUIButton) {
278         GUIButton*gbuto=(GUIButton*)guis[ifce].Controls[btn];
279         rtype=gbuto->leftclick;
280         rdata=gbuto->lclickdata;
281     }
282     else if ((btype==kGUISlider) || (btype == kGUITextBox) || (btype == kGUIListBox))
283         rtype = IBACT_SCRIPT;
284     else quit("unknown GUI object triggered process_interface");
285 
286     if (rtype==0) ;
287     else if (rtype==IBACT_SETMODE)
288         set_cursor_mode(rdata);
289     else if (rtype==IBACT_SCRIPT) {
290         GUIObject *theObj = guis[ifce].Controls[btn];
291         // if the object has a special handler script then run it;
292         // otherwise, run interface_click
293         if ((theObj->GetNumEvents() > 0) &&
294             (!theObj->eventHandlers[0].IsEmpty()) &&
295             (!gameinst->GetSymbolAddress(theObj->eventHandlers[0]).IsNull())) {
296                 // control-specific event handler
297                 if (strchr(theObj->GetEventArgs(0), ',') != NULL)
298                     QueueScriptFunction(kScInstGame, theObj->eventHandlers[0], 2,
299                         RuntimeScriptValue().SetDynamicObject(theObj, &ccDynamicGUIObject),
300                         RuntimeScriptValue().SetInt32(mbut));
301                 else
302                     QueueScriptFunction(kScInstGame, theObj->eventHandlers[0], 1,
303                         RuntimeScriptValue().SetDynamicObject(theObj, &ccDynamicGUIObject));
304         }
305         else
306             QueueScriptFunction(kScInstGame, "interface_click", 2,
307                 RuntimeScriptValue().SetInt32(ifce),
308                 RuntimeScriptValue().SetInt32(btn));
309     }
310 }
311 
312 
replace_macro_tokens(const char * statusbarformat,char * cur_stb_text)313 void replace_macro_tokens(const char*statusbarformat,char*cur_stb_text) {
314     const char*curptr=&statusbarformat[0];
315     char tmpm[3];
316     const char*endat = curptr + strlen(statusbarformat);
317     cur_stb_text[0]=0;
318     char tempo[STD_BUFFER_SIZE];
319 
320     while (1) {
321         if (curptr[0]==0) break;
322         if (curptr>=endat) break;
323         if (curptr[0]=='@') {
324             const char *curptrWasAt = curptr;
325             char macroname[21]; int idd=0; curptr++;
326             for (idd=0;idd<20;idd++) {
327                 if (curptr[0]=='@') {
328                     macroname[idd]=0;
329                     curptr++;
330                     break;
331                 }
332                 // unterminated macro (eg. "@SCORETEXT"), so abort
333                 if (curptr[0] == 0)
334                     break;
335                 macroname[idd]=curptr[0];
336                 curptr++;
337             }
338             macroname[idd]=0;
339             tempo[0]=0;
340             if (stricmp(macroname,"score")==0)
341                 sprintf(tempo,"%d",play.score);
342             else if (stricmp(macroname,"totalscore")==0)
343                 sprintf(tempo,"%d",MAXSCORE);
344             else if (stricmp(macroname,"scoretext")==0)
345                 sprintf(tempo,"%d of %d",play.score,MAXSCORE);
346             else if (stricmp(macroname,"gamename")==0)
347                 strcpy(tempo, play.game_name);
348             else if (stricmp(macroname,"overhotspot")==0) {
349                 // While game is in Wait mode, no overhotspot text
350                 if (!IsInterfaceEnabled())
351                     tempo[0] = 0;
352                 else
353                     GetLocationName(divide_down_coordinate(mousex), divide_down_coordinate(mousey), tempo);
354             }
355             else { // not a macro, there's just a @ in the message
356                 curptr = curptrWasAt + 1;
357                 strcpy(tempo, "@");
358             }
359 
360             strcat(cur_stb_text,tempo);
361         }
362         else {
363             tmpm[0]=curptr[0]; tmpm[1]=0;
364             strcat(cur_stb_text,tmpm);
365             curptr++;
366         }
367     }
368 }
369 
370 
update_gui_zorder()371 void update_gui_zorder() {
372     int numdone = 0, b;
373 
374     // for each GUI
375     for (int a = 0; a < game.numgui; a++) {
376         // find the right place in the draw order array
377         int insertAt = numdone;
378         for (b = 0; b < numdone; b++) {
379             if (guis[a].ZOrder < guis[play.gui_draw_order[b]].ZOrder) {
380                 insertAt = b;
381                 break;
382             }
383         }
384         // insert the new item
385         for (b = numdone - 1; b >= insertAt; b--)
386             play.gui_draw_order[b + 1] = play.gui_draw_order[b];
387         play.gui_draw_order[insertAt] = a;
388         numdone++;
389     }
390 
391 }
392 
393 
export_gui_controls(int ee)394 void export_gui_controls(int ee) {
395 
396     for (int ff = 0; ff < guis[ee].ControlCount; ff++) {
397         if (!guis[ee].Controls[ff]->scriptName.IsEmpty())
398             ccAddExternalDynamicObject(guis[ee].Controls[ff]->scriptName, guis[ee].Controls[ff], &ccDynamicGUIObject);
399 
400         ccRegisterManagedObject(guis[ee].Controls[ff], &ccDynamicGUIObject);
401     }
402 }
403 
unexport_gui_controls(int ee)404 void unexport_gui_controls(int ee) {
405 
406     for (int ff = 0; ff < guis[ee].ControlCount; ff++) {
407         if (!guis[ee].Controls[ff]->scriptName.IsEmpty())
408             ccRemoveExternalSymbol(guis[ee].Controls[ff]->scriptName);
409 
410         if (!ccUnRegisterManagedObject(guis[ee].Controls[ff]))
411             quit("unable to unregister guicontrol object");
412     }
413 }
414 
convert_gui_disabled_style(int oldStyle)415 int convert_gui_disabled_style(int oldStyle) {
416     int toret = GUIDIS_GREYOUT;
417 
418     // if GUIs Turn Off is selected, don't grey out buttons for
419     // any Persistent GUIs which remain
420     // set to 0x80 so that it is still non-zero, but has no effect
421     if (oldStyle == 3)
422         toret = GUIDIS_GUIOFF;
423     // GUIs Go Black
424     else if (oldStyle == 1)
425         toret = GUIDIS_BLACKOUT;
426     // GUIs unchanged
427     else if (oldStyle == 2)
428         toret = GUIDIS_UNCHANGED;
429 
430     return toret;
431 }
432 
update_gui_disabled_status()433 void update_gui_disabled_status() {
434     // update GUI display status (perhaps we've gone into
435     // an interface disabled state)
436     int all_buttons_was = all_buttons_disabled;
437     all_buttons_disabled = 0;
438 
439     if (!IsInterfaceEnabled()) {
440         all_buttons_disabled = gui_disabled_style;
441     }
442 
443     if (all_buttons_was != all_buttons_disabled) {
444         // GUIs might have been removed/added
445         for (int aa = 0; aa < game.numgui; aa++) {
446             guis[aa].OnControlPositionChanged();
447         }
448         guis_need_update = 1;
449         invalidate_screen();
450     }
451 }
452 
453 
adjust_x_for_guis(int xx,int yy)454 int adjust_x_for_guis (int xx, int yy) {
455     if ((game.options[OPT_DISABLEOFF]==3) && (all_buttons_disabled > 0))
456         return xx;
457     // If it's covered by a GUI, move it right a bit
458     for (int aa=0;aa < game.numgui; aa++) {
459         if (!guis[aa].IsVisible())
460             continue;
461         if ((guis[aa].X > xx) || (guis[aa].Y > yy) || (guis[aa].Y + guis[aa].Height < yy))
462             continue;
463         // totally transparent GUI, ignore
464         if ((guis[aa].BgColor == 0) && (guis[aa].BgImage < 1))
465             continue;
466 
467         // try to deal with full-width GUIs across the top
468         if (guis[aa].X + guis[aa].Width >= get_fixed_pixel_size(280))
469             continue;
470 
471         if (xx < guis[aa].X + guis[aa].Width)
472             xx = guis[aa].X + guis[aa].Width + 2;
473     }
474     return xx;
475 }
476 
adjust_y_for_guis(int yy)477 int adjust_y_for_guis ( int yy) {
478     if ((game.options[OPT_DISABLEOFF]==3) && (all_buttons_disabled > 0))
479         return yy;
480     // If it's covered by a GUI, move it down a bit
481     for (int aa=0;aa < game.numgui; aa++) {
482         if (!guis[aa].IsVisible())
483             continue;
484         if (guis[aa].Y > yy)
485             continue;
486         // totally transparent GUI, ignore
487         if ((guis[aa].BgColor == 0) && (guis[aa].BgImage < 1))
488             continue;
489 
490         // try to deal with full-height GUIs down the left or right
491         if (guis[aa].Height > get_fixed_pixel_size(50))
492             continue;
493 
494         if (yy < guis[aa].Y + guis[aa].Height)
495             yy = guis[aa].Y + guis[aa].Height + 2;
496     }
497     return yy;
498 }
499 
recreate_guibg_image(GUIMain * tehgui)500 void recreate_guibg_image(GUIMain *tehgui)
501 {
502   int ifn = tehgui->Id;
503   delete guibg[ifn];
504   guibg[ifn] = BitmapHelper::CreateBitmap(tehgui->Width, tehgui->Height, game.GetColorDepth());
505   if (guibg[ifn] == NULL)
506     quit("SetGUISize: internal error: unable to reallocate gui cache");
507   guibg[ifn] = ReplaceBitmapWithSupportedFormat(guibg[ifn]);
508 
509   if (guibgbmp[ifn] != NULL)
510   {
511     gfxDriver->DestroyDDB(guibgbmp[ifn]);
512     guibgbmp[ifn] = NULL;
513   }
514 }
515 
516 extern int is_complete_overlay;
517 
gui_get_interactable(int x,int y)518 int gui_get_interactable(int x,int y)
519 {
520     if ((game.options[OPT_DISABLEOFF]==3) && (all_buttons_disabled > 0))
521         return -1;
522     return GetGUIAt(x, y);
523 }
524 
gui_on_mouse_move()525 int gui_on_mouse_move()
526 {
527     int mouse_over_gui = -1;
528     // If all GUIs are off, skip the loop
529     if ((game.options[OPT_DISABLEOFF]==3) && (all_buttons_disabled > 0)) ;
530     else {
531         // Scan for mouse-y-pos GUIs, and pop one up if appropriate
532         // Also work out the mouse-over GUI while we're at it
533         int ll;
534         for (ll = 0; ll < game.numgui;ll++) {
535             const int guin = play.gui_draw_order[ll];
536             if (guis[guin].IsInteractableAt(mousex, mousey)) mouse_over_gui=guin;
537 
538             if (guis[guin].PopupStyle!=kGUIPopupMouseY) continue;
539             if (is_complete_overlay>0) break;  // interfaces disabled
540             //    if (play.disabled_user_interface>0) break;
541             if (ifacepopped==guin) continue;
542             if (guis[guin].IsConcealed()) continue;
543             // Don't allow it to be popped up while skipping cutscene
544             if (play.fast_forward) continue;
545 
546             if (mousey < guis[guin].PopupAtMouseY) {
547                 set_mouse_cursor(CURS_ARROW);
548                 guis[guin].SetVisibility(kGUIVisibility_On); guis_need_update = 1;
549                 ifacepopped=guin; PauseGame();
550                 break;
551             }
552         }
553     }
554     return mouse_over_gui;
555 }
556 
gui_on_mouse_hold(const int wasongui,const int wasbutdown)557 void gui_on_mouse_hold(const int wasongui, const int wasbutdown)
558 {
559     for (int i=0;i<guis[wasongui].ControlCount;i++) {
560         if (guis[wasongui].Controls[i]->activated<1) continue;
561         if (guis[wasongui].GetControlType(i)!=kGUISlider) continue;
562         // GUI Slider repeatedly activates while being dragged
563         guis[wasongui].Controls[i]->activated=0;
564         force_event(EV_IFACECLICK, wasongui, i, wasbutdown);
565         break;
566     }
567 }
568 
gui_on_mouse_up(const int wasongui,const int wasbutdown)569 void gui_on_mouse_up(const int wasongui, const int wasbutdown)
570 {
571     guis[wasongui].OnMouseButtonUp();
572 
573     for (int i=0;i<guis[wasongui].ControlCount;i++) {
574         if (guis[wasongui].Controls[i]->activated<1) continue;
575         guis[wasongui].Controls[i]->activated=0;
576         if (!IsInterfaceEnabled()) break;
577 
578         int cttype=guis[wasongui].GetControlType(i);
579         if ((cttype == kGUIButton) || (cttype == kGUISlider) || (cttype == kGUIListBox)) {
580             force_event(EV_IFACECLICK, wasongui, i, wasbutdown);
581         }
582         else if (cttype == kGUIInvWindow) {
583             mouse_ifacebut_xoffs=mousex-(guis[wasongui].Controls[i]->x)-guis[wasongui].X;
584             mouse_ifacebut_yoffs=mousey-(guis[wasongui].Controls[i]->y)-guis[wasongui].Y;
585             int iit=offset_over_inv((GUIInv*)guis[wasongui].Controls[i]);
586             if (iit>=0) {
587                 evblocknum=iit;
588                 play.used_inv_on = iit;
589                 if (game.options[OPT_HANDLEINVCLICKS]) {
590                     // Let the script handle the click
591                     // LEFTINV is 5, RIGHTINV is 6
592                     force_event(EV_TEXTSCRIPT,TS_MCLICK, wasbutdown + 4);
593                 }
594                 else if (wasbutdown==2)  // right-click is always Look
595                     run_event_block_inv(iit, 0);
596                 else if (cur_mode == MODE_HAND)
597                     SetActiveInventory(iit);
598                 else
599                     RunInventoryInteraction (iit, cur_mode);
600                 evblocknum=-1;
601             }
602         }
603         else quit("clicked on unknown control type");
604         if (guis[wasongui].PopupStyle==kGUIPopupMouseY)
605             remove_popup_interface(wasongui);
606         break;
607     }
608 
609     run_on_event(GE_GUI_MOUSEUP, RuntimeScriptValue().SetInt32(wasongui));
610 }
611 
gui_on_mouse_down(const int guin,const int mbut)612 void gui_on_mouse_down(const int guin, const int mbut)
613 {
614     debug_script_log("Mouse click over GUI %d", guin);
615     guis[guin].OnMouseButtonDown();
616     // run GUI click handler if not on any control
617     if ((guis[guin].MouseDownCtrl < 0) && (!guis[guin].OnClickHandler.IsEmpty()))
618         force_event(EV_IFACECLICK, guin, -1, mbut);
619 
620     run_on_event(GE_GUI_MOUSEDOWN, RuntimeScriptValue().SetInt32(guin));
621 }
622 
623 //=============================================================================
624 //
625 // Script API Functions
626 //
627 //=============================================================================
628 
629 #include "debug/out.h"
630 #include "script/script_api.h"
631 #include "script/script_runtime.h"
632 
633 // void GUI_Centre(ScriptGUI *sgui)
Sc_GUI_Centre(void * self,const RuntimeScriptValue * params,int32_t param_count)634 RuntimeScriptValue Sc_GUI_Centre(void *self, const RuntimeScriptValue *params, int32_t param_count)
635 {
636     API_OBJCALL_VOID(ScriptGUI, GUI_Centre);
637 }
638 
639 // ScriptGUI *(int xx, int yy)
Sc_GetGUIAtLocation(const RuntimeScriptValue * params,int32_t param_count)640 RuntimeScriptValue Sc_GetGUIAtLocation(const RuntimeScriptValue *params, int32_t param_count)
641 {
642     API_SCALL_OBJ_PINT2(ScriptGUI, ccDynamicGUI, GetGUIAtLocation);
643 }
644 
645 // void (ScriptGUI *tehgui, int xx, int yy)
Sc_GUI_SetPosition(void * self,const RuntimeScriptValue * params,int32_t param_count)646 RuntimeScriptValue Sc_GUI_SetPosition(void *self, const RuntimeScriptValue *params, int32_t param_count)
647 {
648     API_OBJCALL_VOID_PINT2(ScriptGUI, GUI_SetPosition);
649 }
650 
651 // void (ScriptGUI *sgui, int widd, int hitt)
Sc_GUI_SetSize(void * self,const RuntimeScriptValue * params,int32_t param_count)652 RuntimeScriptValue Sc_GUI_SetSize(void *self, const RuntimeScriptValue *params, int32_t param_count)
653 {
654     API_OBJCALL_VOID_PINT2(ScriptGUI, GUI_SetSize);
655 }
656 
657 // int (ScriptGUI *tehgui)
Sc_GUI_GetBackgroundGraphic(void * self,const RuntimeScriptValue * params,int32_t param_count)658 RuntimeScriptValue Sc_GUI_GetBackgroundGraphic(void *self, const RuntimeScriptValue *params, int32_t param_count)
659 {
660     API_OBJCALL_INT(ScriptGUI, GUI_GetBackgroundGraphic);
661 }
662 
663 // void (ScriptGUI *tehgui, int slotn)
Sc_GUI_SetBackgroundGraphic(void * self,const RuntimeScriptValue * params,int32_t param_count)664 RuntimeScriptValue Sc_GUI_SetBackgroundGraphic(void *self, const RuntimeScriptValue *params, int32_t param_count)
665 {
666     API_OBJCALL_VOID_PINT(ScriptGUI, GUI_SetBackgroundGraphic);
667 }
668 
669 // int (ScriptGUI *tehgui)
Sc_GUI_GetClickable(void * self,const RuntimeScriptValue * params,int32_t param_count)670 RuntimeScriptValue Sc_GUI_GetClickable(void *self, const RuntimeScriptValue *params, int32_t param_count)
671 {
672     API_OBJCALL_INT(ScriptGUI, GUI_GetClickable);
673 }
674 
675 // void (ScriptGUI *tehgui, int clickable)
Sc_GUI_SetClickable(void * self,const RuntimeScriptValue * params,int32_t param_count)676 RuntimeScriptValue Sc_GUI_SetClickable(void *self, const RuntimeScriptValue *params, int32_t param_count)
677 {
678     API_OBJCALL_VOID_PINT(ScriptGUI, GUI_SetClickable);
679 }
680 
681 // int (ScriptGUI *tehgui)
Sc_GUI_GetControlCount(void * self,const RuntimeScriptValue * params,int32_t param_count)682 RuntimeScriptValue Sc_GUI_GetControlCount(void *self, const RuntimeScriptValue *params, int32_t param_count)
683 {
684     API_OBJCALL_INT(ScriptGUI, GUI_GetControlCount);
685 }
686 
687 // GUIObject* (ScriptGUI *tehgui, int idx)
Sc_GUI_GetiControls(void * self,const RuntimeScriptValue * params,int32_t param_count)688 RuntimeScriptValue Sc_GUI_GetiControls(void *self, const RuntimeScriptValue *params, int32_t param_count)
689 {
690     API_OBJCALL_OBJ_PINT(ScriptGUI, GUIObject, ccDynamicGUIObject, GUI_GetiControls);
691 }
692 
693 // int (ScriptGUI *sgui)
Sc_GUI_GetHeight(void * self,const RuntimeScriptValue * params,int32_t param_count)694 RuntimeScriptValue Sc_GUI_GetHeight(void *self, const RuntimeScriptValue *params, int32_t param_count)
695 {
696     API_OBJCALL_INT(ScriptGUI, GUI_GetHeight);
697 }
698 
699 // void (ScriptGUI *sgui, int newhit)
Sc_GUI_SetHeight(void * self,const RuntimeScriptValue * params,int32_t param_count)700 RuntimeScriptValue Sc_GUI_SetHeight(void *self, const RuntimeScriptValue *params, int32_t param_count)
701 {
702     API_OBJCALL_VOID_PINT(ScriptGUI, GUI_SetHeight);
703 }
704 
705 // int (ScriptGUI *tehgui)
Sc_GUI_GetID(void * self,const RuntimeScriptValue * params,int32_t param_count)706 RuntimeScriptValue Sc_GUI_GetID(void *self, const RuntimeScriptValue *params, int32_t param_count)
707 {
708     API_OBJCALL_INT(ScriptGUI, GUI_GetID);
709 }
710 
711 // int (ScriptGUI *tehgui)
Sc_GUI_GetTransparency(void * self,const RuntimeScriptValue * params,int32_t param_count)712 RuntimeScriptValue Sc_GUI_GetTransparency(void *self, const RuntimeScriptValue *params, int32_t param_count)
713 {
714     API_OBJCALL_INT(ScriptGUI, GUI_GetTransparency);
715 }
716 
717 // void (ScriptGUI *tehgui, int trans)
Sc_GUI_SetTransparency(void * self,const RuntimeScriptValue * params,int32_t param_count)718 RuntimeScriptValue Sc_GUI_SetTransparency(void *self, const RuntimeScriptValue *params, int32_t param_count)
719 {
720     API_OBJCALL_VOID_PINT(ScriptGUI, GUI_SetTransparency);
721 }
722 
723 // int (ScriptGUI *tehgui)
Sc_GUI_GetVisible(void * self,const RuntimeScriptValue * params,int32_t param_count)724 RuntimeScriptValue Sc_GUI_GetVisible(void *self, const RuntimeScriptValue *params, int32_t param_count)
725 {
726     API_OBJCALL_INT(ScriptGUI, GUI_GetVisible);
727 }
728 
729 // void (ScriptGUI *tehgui, int isvisible)
Sc_GUI_SetVisible(void * self,const RuntimeScriptValue * params,int32_t param_count)730 RuntimeScriptValue Sc_GUI_SetVisible(void *self, const RuntimeScriptValue *params, int32_t param_count)
731 {
732     API_OBJCALL_VOID_PINT(ScriptGUI, GUI_SetVisible);
733 }
734 
735 // int (ScriptGUI *sgui)
Sc_GUI_GetWidth(void * self,const RuntimeScriptValue * params,int32_t param_count)736 RuntimeScriptValue Sc_GUI_GetWidth(void *self, const RuntimeScriptValue *params, int32_t param_count)
737 {
738     API_OBJCALL_INT(ScriptGUI, GUI_GetWidth);
739 }
740 
741 // void (ScriptGUI *sgui, int newwid)
Sc_GUI_SetWidth(void * self,const RuntimeScriptValue * params,int32_t param_count)742 RuntimeScriptValue Sc_GUI_SetWidth(void *self, const RuntimeScriptValue *params, int32_t param_count)
743 {
744     API_OBJCALL_VOID_PINT(ScriptGUI, GUI_SetWidth);
745 }
746 
747 // int (ScriptGUI *tehgui)
Sc_GUI_GetX(void * self,const RuntimeScriptValue * params,int32_t param_count)748 RuntimeScriptValue Sc_GUI_GetX(void *self, const RuntimeScriptValue *params, int32_t param_count)
749 {
750     API_OBJCALL_INT(ScriptGUI, GUI_GetX);
751 }
752 
753 // void (ScriptGUI *tehgui, int xx)
Sc_GUI_SetX(void * self,const RuntimeScriptValue * params,int32_t param_count)754 RuntimeScriptValue Sc_GUI_SetX(void *self, const RuntimeScriptValue *params, int32_t param_count)
755 {
756     API_OBJCALL_VOID_PINT(ScriptGUI, GUI_SetX);
757 }
758 
759 // int (ScriptGUI *tehgui)
Sc_GUI_GetY(void * self,const RuntimeScriptValue * params,int32_t param_count)760 RuntimeScriptValue Sc_GUI_GetY(void *self, const RuntimeScriptValue *params, int32_t param_count)
761 {
762     API_OBJCALL_INT(ScriptGUI, GUI_GetY);
763 }
764 
765 // void (ScriptGUI *tehgui, int yy)
Sc_GUI_SetY(void * self,const RuntimeScriptValue * params,int32_t param_count)766 RuntimeScriptValue Sc_GUI_SetY(void *self, const RuntimeScriptValue *params, int32_t param_count)
767 {
768     API_OBJCALL_VOID_PINT(ScriptGUI, GUI_SetY);
769 }
770 
771 // int (ScriptGUI *tehgui)
Sc_GUI_GetZOrder(void * self,const RuntimeScriptValue * params,int32_t param_count)772 RuntimeScriptValue Sc_GUI_GetZOrder(void *self, const RuntimeScriptValue *params, int32_t param_count)
773 {
774     API_OBJCALL_INT(ScriptGUI, GUI_GetZOrder);
775 }
776 
777 // void (ScriptGUI *tehgui, int z)
Sc_GUI_SetZOrder(void * self,const RuntimeScriptValue * params,int32_t param_count)778 RuntimeScriptValue Sc_GUI_SetZOrder(void *self, const RuntimeScriptValue *params, int32_t param_count)
779 {
780     API_OBJCALL_VOID_PINT(ScriptGUI, GUI_SetZOrder);
781 }
782 
Sc_GUI_Click(void * self,const RuntimeScriptValue * params,int32_t param_count)783 RuntimeScriptValue Sc_GUI_Click(void *self, const RuntimeScriptValue *params, int32_t param_count)
784 {
785     API_OBJCALL_VOID_PINT(ScriptGUI, GUI_Click);
786 }
787 
Sc_GUI_ProcessClick(const RuntimeScriptValue * params,int32_t param_count)788 RuntimeScriptValue Sc_GUI_ProcessClick(const RuntimeScriptValue *params, int32_t param_count)
789 {
790     API_SCALL_VOID_PINT3(GUI_ProcessClick);
791 }
792 
RegisterGUIAPI()793 void RegisterGUIAPI()
794 {
795     ccAddExternalObjectFunction("GUI::Centre^0",                Sc_GUI_Centre);
796     ccAddExternalObjectFunction("GUI::Click^1",                 Sc_GUI_Click);
797     ccAddExternalStaticFunction("GUI::GetAtScreenXY^2",         Sc_GetGUIAtLocation);
798     ccAddExternalStaticFunction("GUI::ProcessClick^3",          Sc_GUI_ProcessClick);
799     ccAddExternalObjectFunction("GUI::SetPosition^2",           Sc_GUI_SetPosition);
800     ccAddExternalObjectFunction("GUI::SetSize^2",               Sc_GUI_SetSize);
801     ccAddExternalObjectFunction("GUI::get_BackgroundGraphic",   Sc_GUI_GetBackgroundGraphic);
802     ccAddExternalObjectFunction("GUI::set_BackgroundGraphic",   Sc_GUI_SetBackgroundGraphic);
803     ccAddExternalObjectFunction("GUI::get_Clickable",           Sc_GUI_GetClickable);
804     ccAddExternalObjectFunction("GUI::set_Clickable",           Sc_GUI_SetClickable);
805     ccAddExternalObjectFunction("GUI::get_ControlCount",        Sc_GUI_GetControlCount);
806     ccAddExternalObjectFunction("GUI::geti_Controls",           Sc_GUI_GetiControls);
807     ccAddExternalObjectFunction("GUI::get_Height",              Sc_GUI_GetHeight);
808     ccAddExternalObjectFunction("GUI::set_Height",              Sc_GUI_SetHeight);
809     ccAddExternalObjectFunction("GUI::get_ID",                  Sc_GUI_GetID);
810     ccAddExternalObjectFunction("GUI::get_Transparency",        Sc_GUI_GetTransparency);
811     ccAddExternalObjectFunction("GUI::set_Transparency",        Sc_GUI_SetTransparency);
812     ccAddExternalObjectFunction("GUI::get_Visible",             Sc_GUI_GetVisible);
813     ccAddExternalObjectFunction("GUI::set_Visible",             Sc_GUI_SetVisible);
814     ccAddExternalObjectFunction("GUI::get_Width",               Sc_GUI_GetWidth);
815     ccAddExternalObjectFunction("GUI::set_Width",               Sc_GUI_SetWidth);
816     ccAddExternalObjectFunction("GUI::get_X",                   Sc_GUI_GetX);
817     ccAddExternalObjectFunction("GUI::set_X",                   Sc_GUI_SetX);
818     ccAddExternalObjectFunction("GUI::get_Y",                   Sc_GUI_GetY);
819     ccAddExternalObjectFunction("GUI::set_Y",                   Sc_GUI_SetY);
820     ccAddExternalObjectFunction("GUI::get_ZOrder",              Sc_GUI_GetZOrder);
821     ccAddExternalObjectFunction("GUI::set_ZOrder",              Sc_GUI_SetZOrder);
822 
823     /* ----------------------- Registering unsafe exports for plugins -----------------------*/
824 
825     ccAddExternalFunctionForPlugin("GUI::Centre^0",                (void*)GUI_Centre);
826     ccAddExternalFunctionForPlugin("GUI::GetAtScreenXY^2",         (void*)GetGUIAtLocation);
827     ccAddExternalFunctionForPlugin("GUI::SetPosition^2",           (void*)GUI_SetPosition);
828     ccAddExternalFunctionForPlugin("GUI::SetSize^2",               (void*)GUI_SetSize);
829     ccAddExternalFunctionForPlugin("GUI::get_BackgroundGraphic",   (void*)GUI_GetBackgroundGraphic);
830     ccAddExternalFunctionForPlugin("GUI::set_BackgroundGraphic",   (void*)GUI_SetBackgroundGraphic);
831     ccAddExternalFunctionForPlugin("GUI::get_Clickable",           (void*)GUI_GetClickable);
832     ccAddExternalFunctionForPlugin("GUI::set_Clickable",           (void*)GUI_SetClickable);
833     ccAddExternalFunctionForPlugin("GUI::get_ControlCount",        (void*)GUI_GetControlCount);
834     ccAddExternalFunctionForPlugin("GUI::geti_Controls",           (void*)GUI_GetiControls);
835     ccAddExternalFunctionForPlugin("GUI::get_Height",              (void*)GUI_GetHeight);
836     ccAddExternalFunctionForPlugin("GUI::set_Height",              (void*)GUI_SetHeight);
837     ccAddExternalFunctionForPlugin("GUI::get_ID",                  (void*)GUI_GetID);
838     ccAddExternalFunctionForPlugin("GUI::get_Transparency",        (void*)GUI_GetTransparency);
839     ccAddExternalFunctionForPlugin("GUI::set_Transparency",        (void*)GUI_SetTransparency);
840     ccAddExternalFunctionForPlugin("GUI::get_Visible",             (void*)GUI_GetVisible);
841     ccAddExternalFunctionForPlugin("GUI::set_Visible",             (void*)GUI_SetVisible);
842     ccAddExternalFunctionForPlugin("GUI::get_Width",               (void*)GUI_GetWidth);
843     ccAddExternalFunctionForPlugin("GUI::set_Width",               (void*)GUI_SetWidth);
844     ccAddExternalFunctionForPlugin("GUI::get_X",                   (void*)GUI_GetX);
845     ccAddExternalFunctionForPlugin("GUI::set_X",                   (void*)GUI_SetX);
846     ccAddExternalFunctionForPlugin("GUI::get_Y",                   (void*)GUI_GetY);
847     ccAddExternalFunctionForPlugin("GUI::set_Y",                   (void*)GUI_SetY);
848     ccAddExternalFunctionForPlugin("GUI::get_ZOrder",              (void*)GUI_GetZOrder);
849     ccAddExternalFunctionForPlugin("GUI::set_ZOrder",              (void*)GUI_SetZOrder);
850 }
851