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/overlay.h"
17 #include "ac/common.h"
18 #include "ac/view.h"
19 #include "ac/characterextras.h"
20 #include "ac/draw.h"
21 #include "ac/gamesetupstruct.h"
22 #include "ac/gamestate.h"
23 #include "ac/global_overlay.h"
24 #include "ac/global_translation.h"
25 #include "ac/runtime_defines.h"
26 #include "ac/screenoverlay.h"
27 #include "ac/string.h"
28 #include "gfx/graphicsdriver.h"
29 #include "gfx/bitmap.h"
30 #include "script/runtimescriptvalue.h"
31 
32 using namespace AGS::Common;
33 using namespace AGS::Engine;
34 
35 extern GameSetupStruct game;
36 extern int offsetx, offsety;
37 extern int displayed_room;
38 extern int spritewidth[MAX_SPRITES],spriteheight[MAX_SPRITES];
39 extern int face_talking;
40 extern ViewStruct*views;
41 extern CharacterExtras *charextra;
42 extern IGraphicsDriver *gfxDriver;
43 
44 
45 
46 ScreenOverlay screenover[MAX_SCREEN_OVERLAYS];
47 int numscreenover=0;
48 int is_complete_overlay=0,is_text_overlay=0;
49 int crovr_id=2;  // whether using SetTextOverlay or CreateTextOvelay
50 
Overlay_Remove(ScriptOverlay * sco)51 void Overlay_Remove(ScriptOverlay *sco) {
52     sco->Remove();
53 }
54 
Overlay_SetText(ScriptOverlay * scover,int wii,int fontid,int clr,const char * text)55 void Overlay_SetText(ScriptOverlay *scover, int wii, int fontid, int clr, const char*text) {
56     int ovri=find_overlay_of_type(scover->overlayId);
57     if (ovri<0)
58         quit("!Overlay.SetText: invalid overlay ID specified");
59     int xx = divide_down_coordinate(screenover[ovri].x) - scover->borderWidth;
60     int yy = divide_down_coordinate(screenover[ovri].y) - scover->borderHeight;
61 
62     RemoveOverlay(scover->overlayId);
63     crovr_id = scover->overlayId;
64 
65     if (CreateTextOverlay(xx,yy,wii,fontid,clr,get_translation(text)) != scover->overlayId)
66         quit("SetTextOverlay internal error: inconsistent type ids");
67 }
68 
Overlay_GetX(ScriptOverlay * scover)69 int Overlay_GetX(ScriptOverlay *scover) {
70     int ovri = find_overlay_of_type(scover->overlayId);
71     if (ovri < 0)
72         quit("!invalid overlay ID specified");
73 
74     int tdxp, tdyp;
75     get_overlay_position(ovri, &tdxp, &tdyp);
76 
77     return divide_down_coordinate(tdxp);
78 }
79 
Overlay_SetX(ScriptOverlay * scover,int newx)80 void Overlay_SetX(ScriptOverlay *scover, int newx) {
81     int ovri = find_overlay_of_type(scover->overlayId);
82     if (ovri < 0)
83         quit("!invalid overlay ID specified");
84 
85     screenover[ovri].x = multiply_up_coordinate(newx);
86 }
87 
Overlay_GetY(ScriptOverlay * scover)88 int Overlay_GetY(ScriptOverlay *scover) {
89     int ovri = find_overlay_of_type(scover->overlayId);
90     if (ovri < 0)
91         quit("!invalid overlay ID specified");
92 
93     int tdxp, tdyp;
94     get_overlay_position(ovri, &tdxp, &tdyp);
95 
96     return divide_down_coordinate(tdyp);
97 }
98 
Overlay_SetY(ScriptOverlay * scover,int newy)99 void Overlay_SetY(ScriptOverlay *scover, int newy) {
100     int ovri = find_overlay_of_type(scover->overlayId);
101     if (ovri < 0)
102         quit("!invalid overlay ID specified");
103 
104     screenover[ovri].y = multiply_up_coordinate(newy);
105 }
106 
Overlay_GetValid(ScriptOverlay * scover)107 int Overlay_GetValid(ScriptOverlay *scover) {
108     if (scover->overlayId == -1)
109         return 0;
110 
111     if (!IsOverlayValid(scover->overlayId)) {
112         scover->overlayId = -1;
113         return 0;
114     }
115 
116     return 1;
117 }
118 
Overlay_CreateGraphical(int x,int y,int slot,int transparent)119 ScriptOverlay* Overlay_CreateGraphical(int x, int y, int slot, int transparent) {
120     ScriptOverlay *sco = new ScriptOverlay();
121     sco->overlayId = CreateGraphicOverlay(x, y, slot, transparent);
122     sco->borderHeight = 0;
123     sco->borderWidth = 0;
124     sco->isBackgroundSpeech = 0;
125 
126     ccRegisterManagedObject(sco, sco);
127     return sco;
128 }
129 
Overlay_CreateTextual(int x,int y,int width,int font,int colour,const char * text)130 ScriptOverlay* Overlay_CreateTextual(int x, int y, int width, int font, int colour, const char* text) {
131     ScriptOverlay *sco = new ScriptOverlay();
132 
133     multiply_up_coordinates(&x, &y);
134     width = multiply_up_coordinate(width);
135 
136     sco->overlayId = CreateTextOverlayCore(x, y, width, font, colour, text, 0);
137 
138     int ovri = find_overlay_of_type(sco->overlayId);
139     sco->borderWidth = divide_down_coordinate(screenover[ovri].x - x);
140     sco->borderHeight = divide_down_coordinate(screenover[ovri].y - y);
141     sco->isBackgroundSpeech = 0;
142 
143     ccRegisterManagedObject(sco, sco);
144     return sco;
145 }
146 
147 //=============================================================================
148 
remove_screen_overlay_index(int cc)149 void remove_screen_overlay_index(int cc) {
150     int dd;
151     delete screenover[cc].pic;
152     screenover[cc].pic=NULL;
153 
154     if (screenover[cc].bmp != NULL)
155         gfxDriver->DestroyDDB(screenover[cc].bmp);
156     screenover[cc].bmp = NULL;
157 
158     if (screenover[cc].type==OVER_COMPLETE) is_complete_overlay--;
159     if (screenover[cc].type==OVER_TEXTMSG) is_text_overlay--;
160 
161     // if the script didn't actually use the Overlay* return
162     // value, dispose of the pointer
163     if (screenover[cc].associatedOverlayHandle)
164         ccAttemptDisposeObject(screenover[cc].associatedOverlayHandle);
165 
166     numscreenover--;
167     for (dd = cc; dd < numscreenover; dd++)
168         screenover[dd] = screenover[dd+1];
169 
170     // if an overlay before the sierra-style speech one is removed,
171     // update the index
172     if (face_talking > cc)
173         face_talking--;
174 }
175 
remove_screen_overlay(int type)176 void remove_screen_overlay(int type) {
177     int cc;
178     for (cc=0;cc<numscreenover;cc++) {
179         if (screenover[cc].type==type) ;
180         else if (type==-1) ;
181         else continue;
182         remove_screen_overlay_index(cc);
183         cc--;
184     }
185 }
186 
find_overlay_of_type(int typ)187 int find_overlay_of_type(int typ) {
188     int ww;
189     for (ww=0;ww<numscreenover;ww++) {
190         if (screenover[ww].type == typ) return ww;
191     }
192     return -1;
193 }
194 
add_screen_overlay(int x,int y,int type,Bitmap * piccy,bool alphaChannel)195 int add_screen_overlay(int x,int y,int type,Bitmap *piccy, bool alphaChannel) {
196     if (numscreenover>=MAX_SCREEN_OVERLAYS)
197         quit("too many screen overlays created");
198     if (type==OVER_COMPLETE) is_complete_overlay++;
199     if (type==OVER_TEXTMSG) is_text_overlay++;
200     if (type==OVER_CUSTOM) {
201         int uu;  // find an unused custom ID
202         for (uu=OVER_CUSTOM+1;uu<OVER_CUSTOM+100;uu++) {
203             if (find_overlay_of_type(uu) == -1) { type=uu; break; }
204         }
205     }
206     screenover[numscreenover].pic=piccy;
207     screenover[numscreenover].bmp = gfxDriver->CreateDDBFromBitmap(piccy, alphaChannel);
208     screenover[numscreenover].x=x;
209     screenover[numscreenover].y=y;
210     screenover[numscreenover].type=type;
211     screenover[numscreenover].timeout=0;
212     screenover[numscreenover].bgSpeechForChar = -1;
213     screenover[numscreenover].associatedOverlayHandle = 0;
214     screenover[numscreenover].hasAlphaChannel = alphaChannel;
215     screenover[numscreenover].positionRelativeToScreen = true;
216     numscreenover++;
217     return numscreenover-1;
218 }
219 
220 
221 
get_overlay_position(int overlayidx,int * x,int * y)222 void get_overlay_position(int overlayidx, int *x, int *y) {
223     int tdxp, tdyp;
224 
225     if (screenover[overlayidx].x == OVR_AUTOPLACE) {
226         // auto place on character
227         int charid = screenover[overlayidx].y;
228         int charpic = views[game.chars[charid].view].loops[game.chars[charid].loop].frames[0].pic;
229 
230         tdyp = multiply_up_coordinate(game.chars[charid].get_effective_y()) - offsety - 5;
231         if (charextra[charid].height<1)
232             tdyp -= spriteheight[charpic];
233         else
234             tdyp -= charextra[charid].height;
235 
236         tdyp -= screenover[overlayidx].pic->GetHeight();
237         if (tdyp < 5) tdyp=5;
238         tdxp = (multiply_up_coordinate(game.chars[charid].x) - screenover[overlayidx].pic->GetWidth()/2) - offsetx;
239         if (tdxp < 0) tdxp=0;
240 
241         if ((tdxp + screenover[overlayidx].pic->GetWidth()) >= play.viewport.GetWidth())
242             tdxp = (play.viewport.GetWidth() - screenover[overlayidx].pic->GetWidth()) - 1;
243         if (game.chars[charid].room != displayed_room) {
244             tdxp = play.viewport.GetWidth()/2 - screenover[overlayidx].pic->GetWidth()/2;
245             tdyp = play.viewport.GetHeight()/2 - screenover[overlayidx].pic->GetHeight()/2;
246         }
247     }
248     else {
249         tdxp = screenover[overlayidx].x;
250         tdyp = screenover[overlayidx].y;
251 
252         if (!screenover[overlayidx].positionRelativeToScreen)
253         {
254             tdxp -= offsetx;
255             tdyp -= offsety;
256         }
257     }
258     *x = tdxp;
259     *y = tdyp;
260 }
261 
recreate_overlay_ddbs()262 void recreate_overlay_ddbs()
263 {
264     for (int i = 0; i < numscreenover; ++i)
265     {
266         if (screenover[i].bmp)
267             gfxDriver->DestroyDDB(screenover[i].bmp);
268         if (screenover[i].pic)
269             screenover[i].bmp = gfxDriver->CreateDDBFromBitmap(screenover[i].pic, false);
270         else
271             screenover[i].bmp = NULL;
272     }
273 }
274 
275 //=============================================================================
276 //
277 // Script API Functions
278 //
279 //=============================================================================
280 
281 #include "debug/out.h"
282 #include "script/script_api.h"
283 #include "script/script_runtime.h"
284 
285 // ScriptOverlay* (int x, int y, int slot, int transparent)
Sc_Overlay_CreateGraphical(const RuntimeScriptValue * params,int32_t param_count)286 RuntimeScriptValue Sc_Overlay_CreateGraphical(const RuntimeScriptValue *params, int32_t param_count)
287 {
288     API_SCALL_OBJAUTO_PINT4(ScriptOverlay, Overlay_CreateGraphical);
289 }
290 
291 // ScriptOverlay* (int x, int y, int width, int font, int colour, const char* text, ...)
Sc_Overlay_CreateTextual(const RuntimeScriptValue * params,int32_t param_count)292 RuntimeScriptValue Sc_Overlay_CreateTextual(const RuntimeScriptValue *params, int32_t param_count)
293 {
294     API_SCALL_SCRIPT_SPRINTF(Overlay_CreateTextual, 6);
295     ScriptOverlay *overlay = Overlay_CreateTextual(params[0].IValue, params[1].IValue, params[2].IValue,
296                                                    params[3].IValue, params[4].IValue, scsf_buffer);
297     return RuntimeScriptValue().SetDynamicObject(overlay, overlay);
298 }
299 
300 // void (ScriptOverlay *scover, int wii, int fontid, int clr, char*texx, ...)
Sc_Overlay_SetText(void * self,const RuntimeScriptValue * params,int32_t param_count)301 RuntimeScriptValue Sc_Overlay_SetText(void *self, const RuntimeScriptValue *params, int32_t param_count)
302 {
303     API_OBJCALL_SCRIPT_SPRINTF(Overlay_SetText, 4);
304     Overlay_SetText((ScriptOverlay*)self, params[0].IValue, params[1].IValue, params[2].IValue, scsf_buffer);
305     return RuntimeScriptValue((int32_t)0);
306 }
307 
308 // void (ScriptOverlay *sco)
Sc_Overlay_Remove(void * self,const RuntimeScriptValue * params,int32_t param_count)309 RuntimeScriptValue Sc_Overlay_Remove(void *self, const RuntimeScriptValue *params, int32_t param_count)
310 {
311     API_OBJCALL_VOID(ScriptOverlay, Overlay_Remove);
312 }
313 
314 // int (ScriptOverlay *scover)
Sc_Overlay_GetValid(void * self,const RuntimeScriptValue * params,int32_t param_count)315 RuntimeScriptValue Sc_Overlay_GetValid(void *self, const RuntimeScriptValue *params, int32_t param_count)
316 {
317     API_OBJCALL_INT(ScriptOverlay, Overlay_GetValid);
318 }
319 
320 // int (ScriptOverlay *scover)
Sc_Overlay_GetX(void * self,const RuntimeScriptValue * params,int32_t param_count)321 RuntimeScriptValue Sc_Overlay_GetX(void *self, const RuntimeScriptValue *params, int32_t param_count)
322 {
323     API_OBJCALL_INT(ScriptOverlay, Overlay_GetX);
324 }
325 
326 // void (ScriptOverlay *scover, int newx)
Sc_Overlay_SetX(void * self,const RuntimeScriptValue * params,int32_t param_count)327 RuntimeScriptValue Sc_Overlay_SetX(void *self, const RuntimeScriptValue *params, int32_t param_count)
328 {
329     API_OBJCALL_VOID_PINT(ScriptOverlay, Overlay_SetX);
330 }
331 
332 // int (ScriptOverlay *scover)
Sc_Overlay_GetY(void * self,const RuntimeScriptValue * params,int32_t param_count)333 RuntimeScriptValue Sc_Overlay_GetY(void *self, const RuntimeScriptValue *params, int32_t param_count)
334 {
335     API_OBJCALL_INT(ScriptOverlay, Overlay_GetY);
336 }
337 
338 // void (ScriptOverlay *scover, int newy)
Sc_Overlay_SetY(void * self,const RuntimeScriptValue * params,int32_t param_count)339 RuntimeScriptValue Sc_Overlay_SetY(void *self, const RuntimeScriptValue *params, int32_t param_count)
340 {
341     API_OBJCALL_VOID_PINT(ScriptOverlay, Overlay_SetY);
342 }
343 
344 //=============================================================================
345 //
346 // Exclusive API for Plugins
347 //
348 //=============================================================================
349 
350 // ScriptOverlay* (int x, int y, int width, int font, int colour, const char* text, ...)
ScPl_Overlay_CreateTextual(int x,int y,int width,int font,int colour,const char * text,...)351 ScriptOverlay* ScPl_Overlay_CreateTextual(int x, int y, int width, int font, int colour, const char *text, ...)
352 {
353     API_PLUGIN_SCRIPT_SPRINTF(text);
354     return Overlay_CreateTextual(x, y, width, font, colour, scsf_buffer);
355 }
356 
357 // void (ScriptOverlay *scover, int wii, int fontid, int clr, char*texx, ...)
ScPl_Overlay_SetText(ScriptOverlay * scover,int wii,int fontid,int clr,char * texx,...)358 void ScPl_Overlay_SetText(ScriptOverlay *scover, int wii, int fontid, int clr, char *texx, ...)
359 {
360     API_PLUGIN_SCRIPT_SPRINTF(texx);
361     Overlay_SetText(scover, wii, fontid, clr, scsf_buffer);
362 }
363 
364 
RegisterOverlayAPI()365 void RegisterOverlayAPI()
366 {
367     ccAddExternalStaticFunction("Overlay::CreateGraphical^4",   Sc_Overlay_CreateGraphical);
368     ccAddExternalStaticFunction("Overlay::CreateTextual^106",   Sc_Overlay_CreateTextual);
369     ccAddExternalObjectFunction("Overlay::SetText^104",         Sc_Overlay_SetText);
370     ccAddExternalObjectFunction("Overlay::Remove^0",            Sc_Overlay_Remove);
371     ccAddExternalObjectFunction("Overlay::get_Valid",           Sc_Overlay_GetValid);
372     ccAddExternalObjectFunction("Overlay::get_X",               Sc_Overlay_GetX);
373     ccAddExternalObjectFunction("Overlay::set_X",               Sc_Overlay_SetX);
374     ccAddExternalObjectFunction("Overlay::get_Y",               Sc_Overlay_GetY);
375     ccAddExternalObjectFunction("Overlay::set_Y",               Sc_Overlay_SetY);
376 
377     /* ----------------------- Registering unsafe exports for plugins -----------------------*/
378 
379     ccAddExternalFunctionForPlugin("Overlay::CreateGraphical^4",   (void*)Overlay_CreateGraphical);
380     ccAddExternalFunctionForPlugin("Overlay::CreateTextual^106",   (void*)ScPl_Overlay_CreateTextual);
381     ccAddExternalFunctionForPlugin("Overlay::SetText^104",         (void*)ScPl_Overlay_SetText);
382     ccAddExternalFunctionForPlugin("Overlay::Remove^0",            (void*)Overlay_Remove);
383     ccAddExternalFunctionForPlugin("Overlay::get_Valid",           (void*)Overlay_GetValid);
384     ccAddExternalFunctionForPlugin("Overlay::get_X",               (void*)Overlay_GetX);
385     ccAddExternalFunctionForPlugin("Overlay::set_X",               (void*)Overlay_SetX);
386     ccAddExternalFunctionForPlugin("Overlay::get_Y",               (void*)Overlay_GetY);
387     ccAddExternalFunctionForPlugin("Overlay::set_Y",               (void*)Overlay_SetY);
388 }
389