1 /*
2 
3 This is not the AGS Parallax plugin by Scorpiorus
4 but a workalike plugin created by JJS for the AGS engine ports.
5 
6 */
7 
8 #ifdef WIN32
9 #define WINDOWS_VERSION
10 #define WIN32_LEAN_AND_MEAN
11 #include <windows.h>
12 #pragma warning(disable : 4244)
13 #endif
14 
15 #if !defined(BUILTIN_PLUGINS)
16 #define THIS_IS_THE_PLUGIN
17 #endif
18 
19 #include <stdlib.h>
20 #include <stdio.h>
21 #include <string.h>
22 #include <math.h>
23 
24 #include "plugin/agsplugin.h"
25 
26 #if defined(BUILTIN_PLUGINS)
27 namespace ags_parallax {
28 #endif
29 
30 //#define DEBUG
31 
32 const unsigned int Magic = 0xCAFE0000;
33 const unsigned int Version = 2;
34 const unsigned int SaveMagic = Magic + Version;
35 
36 int screen_width = 320;
37 int screen_height = 200;
38 int screen_color_depth = 32;
39 
40 IAGSEngine* engine;
41 
42 bool enabled = false;
43 
44 
45 typedef struct
46 {
47   int x;
48   int y;
49   int slot;
50   int speed;
51 } sprite_t;
52 
53 #define MAX_SPEED 1000
54 #define MAX_SPRITES 100
55 sprite_t sprites[MAX_SPRITES];
56 
57 // workaround to fix this error:
58 //   psp-fixup-imports ags_parallax.elf
59 //   Error, no .lib.stub section found
dummy()60 void dummy()
61 {
62   void *tmp = new int;
63 }
64 
engineFileRead(void * ptr,size_t size,size_t count,long fileHandle)65 static size_t engineFileRead(void * ptr, size_t size, size_t count, long fileHandle) {
66   int totalBytes = engine->FRead(ptr, size*count, fileHandle);
67   return totalBytes/size;
68 }
69 
engineFileWrite(const void * ptr,size_t size,size_t count,long fileHandle)70 static size_t engineFileWrite(const void *ptr, size_t size, size_t count, long fileHandle) {
71   int totalBytes = engine->FWrite(const_cast<void *>(ptr), size*count, fileHandle);
72   return totalBytes/size;
73 }
74 
RestoreGame(long fileHandle)75 void RestoreGame(long fileHandle)
76 {
77   unsigned int SaveVersion = 0;
78   engineFileRead(&SaveVersion, sizeof(SaveVersion), 1, fileHandle);
79 
80   if (SaveVersion != SaveMagic) {
81     engine->AbortGame("ags_parallax: bad save.");
82   }
83 
84   engineFileRead(sprites, sizeof(sprite_t), MAX_SPRITES, fileHandle);
85   engineFileRead(&enabled, sizeof(bool), 1, fileHandle);
86 }
87 
SaveGame(long file)88 void SaveGame(long file)
89 {
90   engineFileWrite(&SaveMagic, sizeof(SaveMagic), 1, file);
91   engineFileWrite(sprites, sizeof(sprite_t), MAX_SPRITES, file);
92   engineFileWrite(&enabled, sizeof(bool), 1, file);
93 }
94 
95 
Initialize()96 void Initialize()
97 {
98   memset(sprites, 0, sizeof(sprite_t) * MAX_SPRITES);
99 
100   int i;
101   for (i = 0; i < MAX_SPRITES; i++)
102     sprites[i].slot = -1;
103 
104   enabled = false;
105 }
106 
107 
Draw(bool foreground)108 void Draw(bool foreground)
109 {
110   if (!enabled)
111     return;
112 
113   BITMAP *bmp;
114   int i;
115 
116   int offsetX = 0;
117   int offsetY = 0;
118   engine->ViewportToRoom(&offsetX, &offsetY);
119 
120   for (i = 0; i < MAX_SPRITES; i++)
121   {
122     if (sprites[i].slot > -1)
123     {
124       if (foreground)
125       {
126         if (sprites[i].speed > 0)
127         {
128           bmp = engine->GetSpriteGraphic(sprites[i].slot);
129           if (bmp)
130             engine->BlitBitmap(sprites[i].x - offsetX - (sprites[i].speed * offsetX / 100), sprites[i].y, bmp, 1);
131         }
132       }
133       else
134       {
135         if (sprites[i].speed <= 0)
136         {
137           bmp = engine->GetSpriteGraphic(sprites[i].slot);
138           if (bmp)
139             engine->BlitBitmap(sprites[i].x - offsetX - (sprites[i].speed * offsetX / 1000), sprites[i].y, bmp, 1);
140         }
141       }
142     }
143   }
144 }
145 
146 
147 
148 
149 
150 // ********************************************
151 // ************  AGS Interface  ***************
152 // ********************************************
153 
pxDrawSprite(int id,int x,int y,int slot,int speed)154 void pxDrawSprite(int id, int x, int y, int slot, int speed)
155 {
156 #ifdef DEBUG
157   char buffer[200];
158   sprintf(buffer, "%s %d %d %d %d %d\n", "pxDrawSprite", id, x, y, slot, speed);
159   engine->PrintDebugConsole(buffer);
160 #endif
161 
162   if ((id < 0) || (id >= MAX_SPRITES))
163     return;
164 
165   if ((speed < -MAX_SPEED) || (speed > MAX_SPEED))
166     speed = 0;
167 
168   sprites[id].x = x;
169   sprites[id].y = y;
170   sprites[id].slot = slot;
171   sprites[id].speed = speed;
172 
173   engine->RoomToViewport(&sprites[id].x, &sprites[id].y);
174 
175   enabled = true;
176 }
177 
178 
pxDeleteSprite(int id)179 void pxDeleteSprite(int id)
180 {
181 #ifdef DEBUG
182   char buffer[200];
183   sprintf(buffer, "%s %d\n", "pxDeleteSprite", id);
184   engine->PrintDebugConsole(buffer);
185 #endif
186 
187   if ((id < 0) || (id >= MAX_SPRITES))
188     return;
189 
190   sprites[id].slot = -1;
191 }
192 
AGS_EngineStartup(IAGSEngine * lpEngine)193 void AGS_EngineStartup(IAGSEngine *lpEngine)
194 {
195   engine = lpEngine;
196 
197   if (engine->version < 13)
198     engine->AbortGame("Engine interface is too old, need newer version of AGS.");
199 
200   engine->RegisterScriptFunction("pxDrawSprite", (void*)&pxDrawSprite);
201   engine->RegisterScriptFunction("pxDeleteSprite", (void*)&pxDeleteSprite);
202 
203   engine->RequestEventHook(AGSE_PREGUIDRAW);
204   engine->RequestEventHook(AGSE_PRESCREENDRAW);
205   engine->RequestEventHook(AGSE_ENTERROOM);
206   engine->RequestEventHook(AGSE_SAVEGAME);
207   engine->RequestEventHook(AGSE_RESTOREGAME);
208 
209   Initialize();
210 }
211 
AGS_EngineShutdown()212 void AGS_EngineShutdown()
213 {
214 }
215 
AGS_EngineOnEvent(int event,int data)216 int AGS_EngineOnEvent(int event, int data)
217 {
218   if (event == AGSE_PREGUIDRAW)
219   {
220     Draw(true);
221   }
222   else if (event == AGSE_PRESCREENDRAW)
223   {
224     Draw(false);
225   }
226   else if (event == AGSE_ENTERROOM)
227   {
228     // Reset all sprites
229     Initialize();
230   }
231   else if (event == AGSE_PRESCREENDRAW)
232   {
233     // Get screen size once here
234     engine->GetScreenDimensions(&screen_width, &screen_height, &screen_color_depth);
235     engine->UnrequestEventHook(AGSE_PRESCREENDRAW);
236   }
237   else if (event == AGSE_RESTOREGAME)
238   {
239     RestoreGame(data);
240   }
241   else if (event == AGSE_SAVEGAME)
242   {
243     SaveGame(data);
244   }
245 
246   return 0;
247 }
248 
AGS_EngineDebugHook(const char * scriptName,int lineNum,int reserved)249 int AGS_EngineDebugHook(const char *scriptName, int lineNum, int reserved)
250 {
251   return 0;
252 }
253 
AGS_EngineInitGfx(const char * driverID,void * data)254 void AGS_EngineInitGfx(const char *driverID, void *data)
255 {
256 }
257 
258 
259 
260 #if defined(WINDOWS_VERSION) && !defined(BUILTIN_PLUGINS)
261 
262 // ********************************************
263 // ***********  Editor Interface  *************
264 // ********************************************
265 
266 const char* scriptHeader =
267   "import void pxDrawSprite(int ID, int X, int Y, int SlotNum, int Speed);\r\n"
268   "import void pxDeleteSprite(int ID);\r\n";
269 
270 IAGSEditor* editor;
271 
272 
AGS_GetPluginName(void)273 LPCSTR AGS_GetPluginName(void)
274 {
275   // Return the plugin description
276   return "Parallax plugin recreation";
277 }
278 
AGS_EditorStartup(IAGSEditor * lpEditor)279 int  AGS_EditorStartup(IAGSEditor* lpEditor)
280 {
281   // User has checked the plugin to use it in their game
282 
283   // If it's an earlier version than what we need, abort.
284   if (lpEditor->version < 1)
285     return -1;
286 
287   editor = lpEditor;
288   editor->RegisterScriptHeader(scriptHeader);
289 
290   // Return 0 to indicate success
291   return 0;
292 }
293 
AGS_EditorShutdown()294 void AGS_EditorShutdown()
295 {
296   // User has un-checked the plugin from their game
297   editor->UnregisterScriptHeader(scriptHeader);
298 }
299 
AGS_EditorProperties(HWND parent)300 void AGS_EditorProperties(HWND parent)
301 {
302   // User has chosen to view the Properties of the plugin
303   // We could load up an options dialog or something here instead
304   MessageBoxA(parent, "Parallax plugin recreation by JJS", "About", MB_OK | MB_ICONINFORMATION);
305 }
306 
AGS_EditorSaveGame(char * buffer,int bufsize)307 int AGS_EditorSaveGame(char* buffer, int bufsize)
308 {
309   // We don't want to save any persistent data
310   return 0;
311 }
312 
AGS_EditorLoadGame(char * buffer,int bufsize)313 void AGS_EditorLoadGame(char* buffer, int bufsize)
314 {
315   // Nothing to load for this plugin
316 }
317 
318 #endif
319 
320 
321 #if defined(BUILTIN_PLUGINS)
322 } // namespace ags_parallax
323 #endif
324