1 // BlinkenSisters - Hunt for the Lost Pixels
2 //     Bringing back the fun of the 80s
3 //
4 // (C) 2005-07 Rene Schickbauer, Wolfgang Dautermann
5 //
6 // See License.txt for licensing information
7 //
8 
9 
10 #include <stdio.h>
11 #include "globals.h"
12 #include "fgobjects.h"
13 #include "errorhandler.h"
14 #include "gameengine.h"
15 #include "colission.h"
16 #include "engine.h"
17 #include "bl_lua.h"
18 #include "sound.h"
19 #include "playersprite.h"
20 #include "convert.h"
21 #include "levelhandler.h"
22 
23 #include <string.h>
24 
25 Uint32 fgobjcnt = 0;
26 Uint32 fgobjgfxcnt = 0;
27 Uint32 fgobjanimcnt = 0;
28 
29 FGOBJS *fgObjs[MAX_FGOBJECTS];
30 FGGFX *fgGFX[MAX_FGOBJECTGFX];
31 FGANIMS *fgAnims[MAX_FGOBJECTGFX];
32 FGOVERLAP fgOverlap;
33 
initFGObjs()34 void initFGObjs() {
35 	fgobjcnt = 0;
36 	fgobjgfxcnt = 0;
37 	fgobjanimcnt = 0;
38 
39 	Uint32 i;
40 	for(i = 0; i < MAX_FGOBJECTS; i++) {
41         fgObjs[i] = 0;
42     }
43 
44 	for(i = 0; i < MAX_FGOBJECTGFX; i++) {
45         fgGFX[i] = 0;
46     }
47 
48 	for(i = 0; i < MAX_FGOBJECTGFX; i++) {
49         fgAnims[i] = 0;
50     }
51 }
52 
deInitFGObjs()53 void deInitFGObjs() {
54     Uint32 i;
55 
56 	for(i = 0; i < MAX_FGOBJECTS; i++) {
57         free(fgObjs[i]);
58         fgObjs[i] = 0;
59     }
60 
61     for(i = 0; i < MAX_FGOBJECTGFX; i++) {
62         if(fgGFX[i]) {
63             if(fgGFX[i]->surface) {
64                 SDL_FreeSurface(fgGFX[i]->surface);
65             }
66             free(fgGFX[i]);
67             fgGFX[i] = 0;
68         }
69     }
70 
71     for(i = 0; i < MAX_FGOBJECTGFX; i++) {
72         if(fgAnims[i]) {
73             free(fgAnims[i]);
74             fgAnims[i] = 0;
75         }
76     }
77 
78 	fgobjgfxcnt = 0;
79 	fgobjcnt = 0;
80 }
81 
getFGSurface(const Uint32 gfxid)82 SDL_Surface* getFGSurface(const Uint32 gfxid) {
83     if(gfxid < MAX_FGOBJECTGFX) {
84         if(!fgGFX[gfxid]) {
85     		DIE(ERROR_INDEX_INVALID, "gfxobj");
86 	   }
87 	   return fgGFX[gfxid]->surface;
88     } else {
89         Uint32 tmpnum = gfxid - MAX_FGOBJECTGFX;
90         return fgGFX[fgAnims[tmpnum]->frames[fgAnims[tmpnum]->currentFrame].gfxobj]->surface;
91     }
92 
93     return 0;
94 }
95 
96 
addFGObjGFX(const char * fname,bool ignoreLoadError)97 Uint32 addFGObjGFX(const char *fname, bool ignoreLoadError) {
98 	if(fgobjgfxcnt == MAX_FGOBJECTGFX) {
99 		DIE(ERROR_BOUNDARY, "MAX_FGOBJECTGFX");
100 	}
101 
102 	char fullfname[MAX_FNAME_LENGTH];
103 	sprintf(fullfname, "%s", configGetPath(fname));
104 	SDL_Surface* temp = IMG_Load(fullfname);
105 	if(!temp) {
106 		if(!ignoreLoadError) {
107 			DIE(ERROR_IMAGE_READ, fullfname);
108 		} else {
109 			printf("Warning: Can't load FgObjGFX '%s' - ignored!\n", fname);
110 			return PSEUDO_FGOBJECTGFXNUM;
111 		}
112 	}
113 
114     Uint32 nextfree = 0;
115 	for(Uint32 i = 0; i < MAX_FGOBJECTGFX; i++) {
116         if(!fgGFX[i]) {
117             nextfree = i;
118             break;
119         }
120     }
121 
122     FGGFX *tmp = (FGGFX *)malloc(sizeof(FGGFX));
123     if(!tmp) {
124         DIE(ERROR_MALLOC, "addFGObjGFX()");
125     }
126     memset(tmp, 0, sizeof(FGGFX));
127     fgGFX[nextfree] = tmp;
128 
129 	fgGFX[nextfree]->surface = convertToBSSurface(temp);
130 	sprintf(fgGFX[nextfree]->filename, "%s", fname);
131 	SDL_FreeSurface(temp);
132 	fgobjgfxcnt++;
133 	return nextfree;
134 }
135 
addFGObjAnim(const char * templfname,const Uint32 startnum,const Uint32 endnum,const double fps,const Uint32 looptype)136 Uint32 addFGObjAnim(const char *templfname, const Uint32 startnum, const Uint32 endnum, const double fps, const Uint32 looptype) {
137 	if(fgobjanimcnt == MAX_FGOBJECTGFX) {
138 		DIE(ERROR_BOUNDARY, "MAX_FGOBJECTGFX");
139 	}
140 
141     Uint32 nextfree = 0;
142 	for(Uint32 i = 0; i < MAX_FGOBJECTGFX; i++) {
143         if(!fgAnims[i]) {
144             nextfree = i;
145             break;
146         }
147     }
148 
149     FGANIMS *tmp = (FGANIMS *)malloc(sizeof(FGANIMS));
150     if(!tmp) {
151         DIE(ERROR_MALLOC, "addFGObjAnim()");
152     }
153     memset(tmp, 0, sizeof(FGANIMS));
154     fgAnims[nextfree] = tmp;
155 	fgobjanimcnt++;
156 
157 	// Fill the anim with basic data
158 	sprintf(fgAnims[nextfree]->filetemplate, "%s", templfname);
159 	fgAnims[nextfree]->filestartnum = startnum;
160 	fgAnims[nextfree]->fileendnum = endnum;
161 	fgAnims[nextfree]->fps = fps;
162 	fgAnims[nextfree]->looptype = looptype;
163 	if(fps != 0) {
164 	   fgAnims[nextfree]->tickIncrement = 1000.0 / fps;
165     } else {
166         fgAnims[nextfree]->tickIncrement = 0.0;
167     }
168 
169 	// Now, prepare to load the graphics
170 	char tmpname[MAX_FNAME_LENGTH];
171 	sprintf(tmpname, "%s", templfname);
172 	char *tmppos = strchr(tmpname, '%');
173 	if(!tmppos) {
174         DIE(ERROR_FILETEMPLATE, "addFGObjAnim()");
175     }
176     char *tmpcnt = tmppos;
177     Uint32 tmplen = 1;
178 	tmpcnt++;
179 	while(*tmpcnt == '%') {
180         tmplen++;
181         tmpcnt++;
182     }
183 
184     // Now we know the first and last char of the "%" placeholder and the minimum length...
185     // break the string into 2 parts
186     *tmppos = 0;
187 
188     // ok, we got the minimum length of the number in tmplen, the first part of the name in tmpname and the
189     // second in tmpcnt
190     // Generate all filenames
191     fgAnims[nextfree]->frameCount = 0;
192     char tmpNumber[MAX_FNAME_LENGTH];
193     char shortName[MAX_FNAME_LENGTH];
194     for(Uint32 i = startnum; i <= endnum; i++) {
195         sprintf(tmpNumber, "%d", i);
196         // Padding if required
197         while(strlen(tmpNumber) < tmplen) {
198             sprintf(shortName, "0%s", tmpNumber);
199             sprintf(tmpNumber, "%s", shortName);
200         }
201         sprintf(shortName, "%s%s%s", tmpname, tmpNumber, tmpcnt);
202         printf("Shortname: %s\n", shortName);
203         fgAnims[nextfree]->frames[fgAnims[nextfree]->frameCount].gfxobj = addFGObjGFX(shortName);
204         fgAnims[nextfree]->frameCount++;
205     }
206 
207     // Add the final settings
208     if(fgAnims[nextfree]->looptype == ANIMLOOPTYPE_REVERSELOOP) {
209         if(fgAnims[nextfree]->frameCount > 1) {
210             fgAnims[nextfree]->currentFrame = fgAnims[nextfree]->frameCount - 1;
211             fgAnims[nextfree]->loopDirection = -1;
212         } else {
213             fgAnims[nextfree]->currentFrame = 0;
214             fgAnims[nextfree]->loopDirection = 0; // Single frame - no animation
215         }
216     } else {
217         fgAnims[nextfree]->currentFrame = 0;
218         if(fgAnims[nextfree]->frameCount > 1) {
219             fgAnims[nextfree]->loopDirection = 1;
220         } else {
221             fgAnims[nextfree]->loopDirection = 0; // Single frame - no animation
222         }
223     }
224     fgAnims[nextfree]->lastTick = (double)BS_GetTicks() + fgAnims[nextfree]->tickIncrement;
225 
226 	return nextfree + MAX_FGOBJECTGFX; // Anims have a offset of MAX_FGOBJECTGFX as pseudo-GFX :-)
227 }
228 
duplicateFGObjAnim(const Uint32 obj)229 Uint32 duplicateFGObjAnim(const Uint32 obj) {
230 	Uint32 objid = obj - MAX_FGOBJECTGFX; // reverse pseudo-GFX offset
231 
232 	if(fgobjanimcnt == MAX_FGOBJECTGFX) {
233 		DIE(ERROR_BOUNDARY, "MAX_FGOBJECTGFX");
234 	}
235 
236     Uint32 nextfree = 0;
237 	for(Uint32 i = 0; i < MAX_FGOBJECTGFX; i++) {
238         if(!fgAnims[i]) {
239             nextfree = i;
240             break;
241         }
242     }
243 
244     FGANIMS *tmp = (FGANIMS *)malloc(sizeof(FGANIMS));
245     if(!tmp) {
246         DIE(ERROR_MALLOC, "addFGObjAnim()");
247     }
248     memset(tmp, 0, sizeof(FGANIMS));
249     fgAnims[nextfree] = tmp;
250 	fgobjanimcnt++;
251 
252 	// Fill the anim with basic data
253 	sprintf(fgAnims[nextfree]->filetemplate, "%s", fgAnims[objid]->filetemplate);
254 	fgAnims[nextfree]->filestartnum = fgAnims[objid]->filestartnum;
255 	fgAnims[nextfree]->fileendnum = fgAnims[objid]->fileendnum;
256 	fgAnims[nextfree]->fps = fgAnims[objid]->fps;
257 	fgAnims[nextfree]->looptype = fgAnims[objid]->looptype;
258 	fgAnims[nextfree]->tickIncrement = fgAnims[objid]->tickIncrement;
259 	fgAnims[nextfree]->currentFrame = fgAnims[objid]->currentFrame;
260 	fgAnims[nextfree]->frameCount = fgAnims[objid]->frameCount;
261 	fgAnims[nextfree]->loopDirection = fgAnims[objid]->loopDirection;
262 	fgAnims[nextfree]->lastTick = fgAnims[objid]->lastTick;
263 
264     for(Uint32 i = 0; i < fgAnims[nextfree]->frameCount; i++) {
265         fgAnims[nextfree]->frames[i].gfxobj = fgAnims[objid]->frames[i].gfxobj;
266     }
267 
268 	return nextfree + MAX_FGOBJECTGFX; // Anims have a offset of MAX_FGOBJECTGFX as pseudo-GFX :-)
269 }
270 
271 
advanceFGObjAnim()272 void advanceFGObjAnim() {
273     double curTicks = (double)BS_GetTicks();
274 
275  	for(Uint32 i = 0; i < MAX_FGOBJECTGFX; i++) {
276         if(fgAnims[i]) {
277             if(fgAnims[i]->frameCount > 1 && fgAnims[i]->fps > 0) {
278                 while(fgAnims[i]->lastTick < curTicks) {
279                     if(fgAnims[i]->looptype == ANIMLOOPTYPE_FORWARDLOOP) {
280                         fgAnims[i]->currentFrame++;
281                         if((Uint32)fgAnims[i]->currentFrame == fgAnims[i]->frameCount) {
282                             fgAnims[i]->currentFrame = 0;
283                         }
284                     } else if(fgAnims[i]->looptype == ANIMLOOPTYPE_REVERSELOOP) {
285                         fgAnims[i]->currentFrame--;
286                         if(fgAnims[i]->currentFrame < 0) {
287                             fgAnims[i]->currentFrame = fgAnims[i]->frameCount - 1;
288                         }
289                     } else if(fgAnims[i]->looptype == ANIMLOOPTYPE_PINGPONG) {
290                         fgAnims[i]->currentFrame += fgAnims[i]->loopDirection;
291                         if(fgAnims[i]->currentFrame < 0 || (Uint32)fgAnims[i]->currentFrame == fgAnims[i]->frameCount) {
292                             // Reverse direction...
293                             fgAnims[i]->loopDirection *= -1;
294                             // and add a "double" correction" for smooth animation
295                             fgAnims[i]->currentFrame += fgAnims[i]->loopDirection * 2;
296                         }
297                     }
298                     // Advance time
299                     if(!turboMode) {
300                         fgAnims[i]->lastTick += fgAnims[i]->tickIncrement;
301                     } else {
302                         fgAnims[i]->lastTick += (fgAnims[i]->tickIncrement / 4);
303                     }
304                 }
305             }
306         }
307     }
308 }
309 
setFGObjAnimLoopType(const Uint32 obj,const Uint32 looptype)310 bool setFGObjAnimLoopType(const Uint32 obj, const Uint32 looptype) {
311     Uint32 objid = obj - MAX_FGOBJECTGFX; // reverse pseudo-GFX offset
312 
313     if(!fgAnims[objid]) {
314 		DIE(ERROR_INDEX_INVALID, "setFGObjAnimLoopType");
315 	}
316 
317 	fgAnims[objid]->looptype = looptype;
318     if(fgAnims[objid]->looptype == ANIMLOOPTYPE_REVERSELOOP) {
319         if(fgAnims[objid]->frameCount > 1) {
320             fgAnims[objid]->currentFrame = fgAnims[objid]->frameCount - 1;
321             fgAnims[objid]->loopDirection = -1;
322         } else {
323             fgAnims[objid]->currentFrame = 0;
324             fgAnims[objid]->loopDirection = 0; // Single frame - no animation
325         }
326     } else {
327         fgAnims[objid]->currentFrame = 0;
328         if(fgAnims[objid]->frameCount > 1) {
329             fgAnims[objid]->loopDirection = 1;
330         } else {
331             fgAnims[objid]->loopDirection = 0; // Single frame - no animation
332         }
333     }
334     return true;
335 }
336 
setFGObjAnimCurrentFrame(const Uint32 obj,const Uint32 frameNum)337 bool setFGObjAnimCurrentFrame(const Uint32 obj, const Uint32 frameNum) {
338     Uint32 objid = obj - MAX_FGOBJECTGFX; // reverse pseudo-GFX offset
339 
340     if(!fgAnims[objid]) {
341 		DIE(ERROR_INDEX_INVALID, "setFGObjAnimLoopType");
342 	}
343 
344     if(frameNum >= fgAnims[objid]->frameCount) {
345         return false;
346     } else {
347         fgAnims[objid]->currentFrame = frameNum;
348         // Advance time
349         fgAnims[objid]->lastTick = (double)BS_GetTicks();
350     }
351     return true;
352 }
353 
setFGObjAnimCurrentDirection(const Uint32 obj,const Sint32 loopDirection)354 bool setFGObjAnimCurrentDirection(const Uint32 obj, const Sint32 loopDirection) {
355     Uint32 objid = obj - MAX_FGOBJECTGFX; // reverse pseudo-GFX offset
356 
357     if(!fgAnims[objid]) {
358 		DIE(ERROR_INDEX_INVALID, "setFGObjAnimLoopType");
359 	}
360 
361 	if(fgAnims[objid]->looptype != ANIMLOOPTYPE_REVERSELOOP) {
362         return false;
363     } else if(fgAnims[objid]->frameCount == 1) {
364         return false;
365     } else {
366         fgAnims[objid]->loopDirection = loopDirection;
367     }
368     return true;
369 }
370 
setFGObjAnimFrameRate(const Uint32 obj,const double fps)371 bool setFGObjAnimFrameRate(const Uint32 obj, const double fps) {
372     Uint32 objid = obj - MAX_FGOBJECTGFX; // reverse pseudo-GFX offset
373 
374     if(!fgAnims[objid]) {
375 		DIE(ERROR_INDEX_INVALID, "setFGObjAnimLoopType");
376 	}
377 
378     fgAnims[objid]->fps = fps;
379     if(fps != 0) {
380 	   fgAnims[objid]->tickIncrement = 1000.0 / fps;
381     } else {
382         fgAnims[objid]->tickIncrement = 0;
383     }
384     // Advance time
385     fgAnims[objid]->lastTick = (double)BS_GetTicks();
386     return true;
387 }
388 
getFGObjAnimLoopType(const Uint32 obj)389 Uint32 getFGObjAnimLoopType(const Uint32 obj) {
390     Uint32 objid = obj - MAX_FGOBJECTGFX; // reverse pseudo-GFX offset
391 
392     if(!fgAnims[objid]) {
393 		DIE(ERROR_INDEX_INVALID, "setFGObjAnimLoopType");
394 	}
395 	return fgAnims[objid]->looptype;
396 }
397 
getFGObjAnimCurrentFrame(const Uint32 obj)398 Uint32 getFGObjAnimCurrentFrame(const Uint32 obj) {
399     Uint32 objid = obj - MAX_FGOBJECTGFX; // reverse pseudo-GFX offset
400 
401     if(!fgAnims[objid]) {
402 		DIE(ERROR_INDEX_INVALID, "setFGObjAnimLoopType");
403 	}
404 
405 	return fgAnims[objid]->currentFrame;
406 }
407 
getFGObjAnimCurrentDirection(const Uint32 obj)408 Sint32 getFGObjAnimCurrentDirection(const Uint32 obj) {
409     Uint32 objid = obj - MAX_FGOBJECTGFX; // reverse pseudo-GFX offset
410 
411     if(!fgAnims[objid]) {
412 		DIE(ERROR_INDEX_INVALID, "setFGObjAnimLoopType");
413 	}
414 	return fgAnims[objid]->loopDirection;
415 }
416 
getFGObjAnimFrameRate(const Uint32 obj)417 double getFGObjAnimFrameRate(const Uint32 obj) {
418     Uint32 objid = obj - MAX_FGOBJECTGFX; // reverse pseudo-GFX offset
419 
420     if(!fgAnims[objid]) {
421 		DIE(ERROR_INDEX_INVALID, "setFGObjAnimLoopType");
422 	}
423     return fgAnims[objid]->fps;
424 }
425 
426 
addFGObj(const Uint32 gfxobj,const Sint32 x,const Sint32 y,const bool isBlocking,const bool isVisible,const bool isOnTop,const bool isKilling)427 Uint32 addFGObj(const Uint32 gfxobj, const Sint32 x, const Sint32 y, const bool isBlocking, const bool isVisible, const bool isOnTop, const bool isKilling) {
428 	if(fgobjcnt == MAX_FGOBJECTS) {
429 		DIE(ERROR_BOUNDARY, "MAX_FGOBJECT");
430 	}
431 
432 	Uint32 nextfree = 0;
433 	for(Uint32 i = 0; i < MAX_FGOBJECTS; i++) {
434         if(!fgObjs[i]) {
435             nextfree = i;
436             break;
437         }
438     }
439 
440     FGOBJS *tmp = (FGOBJS *)malloc(sizeof(FGOBJS));
441     if(!tmp) {
442         DIE(ERROR_MALLOC, "addFGObj()");
443     }
444     memset(tmp, 0, sizeof(FGOBJS));
445     fgObjs[nextfree] = tmp;
446 
447 	fgObjs[nextfree]->gfxobj = gfxobj;
448 	fgObjs[nextfree]->x = x;
449 	fgObjs[nextfree]->y = y;
450 	fgObjs[nextfree]->isBlocking = isBlocking;
451 	fgObjs[nextfree]->isVisible = isVisible;
452 	fgObjs[nextfree]->isOnTop = isOnTop;
453 	fgObjs[nextfree]->isKilling = isKilling;
454 	fgObjs[nextfree]->isPixel = false;
455 	fgObjs[nextfree]->isElevator = false;
456 
457 	fgobjcnt++;
458 	return nextfree;
459 }
460 
deleteFGObj(const Uint32 objid)461 bool deleteFGObj(const Uint32 objid) {
462 	if(objid >= MAX_FGOBJECTS) {
463 		DIE(ERROR_BOUNDARY, "MAX_FGOBJECT");
464 	}
465 	if(fgObjs[objid]) {
466         free(fgObjs[objid]);
467         fgObjs[objid] = 0;
468         fgobjcnt--;
469         return true;
470     }
471     return false;
472 }
473 
setFGObjSetVisible(const Uint32 obj,const bool visible)474 void setFGObjSetVisible(const Uint32 obj, const bool visible) {
475 	if(!fgObjs[obj]) {
476 		DIE(ERROR_INDEX_INVALID, "fgobj");
477 	}
478 	fgObjs[obj]->isVisible = visible;
479 }
480 
setFGObjSetBlocking(const Uint32 obj,const bool blocking)481 void setFGObjSetBlocking(const Uint32 obj, const bool blocking) {
482 	if(!fgObjs[obj]) {
483 		DIE(ERROR_INDEX_INVALID, "fgobj");
484 	}
485 	fgObjs[obj]->isBlocking = blocking;
486 }
487 
setFGObjSetKilling(const Uint32 obj,const bool killing)488 void setFGObjSetKilling(const Uint32 obj, const bool killing) {
489 	if(!fgObjs[obj]) {
490 		DIE(ERROR_INDEX_INVALID, "fgobj");
491 	}
492 	fgObjs[obj]->isKilling = killing;
493 }
494 
setFGObjSetPixel(const Uint32 obj,const bool pixel)495 void setFGObjSetPixel(const Uint32 obj, const bool pixel) {
496 	if(!fgObjs[obj]) {
497 		DIE(ERROR_INDEX_INVALID, "fgobj");
498 	}
499 	fgObjs[obj]->isPixel = pixel;
500 }
501 
setFGObjSetOnTop(const Uint32 obj,const bool ontop)502 void setFGObjSetOnTop(const Uint32 obj, const bool ontop) {
503 	if(!fgObjs[obj]) {
504 		DIE(ERROR_INDEX_INVALID, "fgobj");
505 	}
506 	fgObjs[obj]->isOnTop = ontop;
507 }
508 
setFGObjSetElevator(const Uint32 obj,const bool elevator)509 void setFGObjSetElevator(const Uint32 obj, const bool elevator) {
510 	if(!fgObjs[obj]) {
511 		DIE(ERROR_INDEX_INVALID, "fgobj");
512 	}
513 	fgObjs[obj]->isElevator = elevator;
514 }
515 
getFGObjSetVisible(const Uint32 obj)516 bool getFGObjSetVisible(const Uint32 obj) {
517     if(!fgObjs[obj]) {
518 		DIE(ERROR_INDEX_INVALID, "fgobj");
519 	}
520 	return fgObjs[obj]->isVisible;
521 }
522 
getFGObjSetBlocking(const Uint32 obj)523 bool getFGObjSetBlocking(const Uint32 obj) {
524     if(!fgObjs[obj]) {
525 		DIE(ERROR_INDEX_INVALID, "fgobj");
526 	}
527 
528 	return fgObjs[obj]->isBlocking;
529 }
530 
getFGObjSetOnTop(const Uint32 obj)531 bool getFGObjSetOnTop(const Uint32 obj) {
532     if(!fgObjs[obj]) {
533 		DIE(ERROR_INDEX_INVALID, "fgobj");
534 	}
535 	return fgObjs[obj]->isOnTop;
536 }
537 
getFGObjSetElevator(const Uint32 obj)538 bool getFGObjSetElevator(const Uint32 obj) {
539     if(!fgObjs[obj]) {
540 		DIE(ERROR_INDEX_INVALID, "fgobj");
541 	}
542 	return fgObjs[obj]->isElevator;
543 }
544 
getFGObjSetKilling(const Uint32 obj)545 bool getFGObjSetKilling(const Uint32 obj) {
546     if(!fgObjs[obj]) {
547 		DIE(ERROR_INDEX_INVALID, "fgobj");
548 	}
549 	return fgObjs[obj]->isKilling;
550 }
551 
getFGObjSetPixel(const Uint32 obj)552 bool getFGObjSetPixel(const Uint32 obj) {
553     if(!fgObjs[obj]) {
554 		DIE(ERROR_INDEX_INVALID, "fgobj");
555 	}
556 	return fgObjs[obj]->isPixel;
557 }
558 
559 
setFGObjSetPos(const Uint32 obj,const Sint32 x,const Sint32 y)560 void setFGObjSetPos(const Uint32 obj, const Sint32 x, const Sint32 y) {
561 	if(!fgObjs[obj]) {
562 		DIE(ERROR_INDEX_INVALID, "fgobj");
563 	}
564 
565 	if(fgObjs[obj]->hasPlayerElevatorCollission && spritevy >= 0) {
566 	    spritey += (double)abs((int)(fgObjs[obj]->y - y)) + 1.0;
567 	}
568 
569 	fgObjs[obj]->x = x;
570 	fgObjs[obj]->y = y;
571 }
572 
setFGObjSetPosX(const Uint32 obj,const Sint32 x)573 void setFGObjSetPosX(const Uint32 obj, const Sint32 x) {
574 	if(!fgObjs[obj]) {
575 		DIE(ERROR_INDEX_INVALID, "fgobj");
576 	}
577 
578 	fgObjs[obj]->x = x;
579 }
580 
setFGObjSetPosY(const Uint32 obj,const Sint32 y)581 void setFGObjSetPosY(const Uint32 obj, const Sint32 y) {
582 	if(!fgObjs[obj]) {
583 		DIE(ERROR_INDEX_INVALID, "fgobj");
584 	}
585 
586 	if(fgObjs[obj]->hasPlayerElevatorCollission && spritevy >= 0) {
587 	    spritey += (double)abs((int)(fgObjs[obj]->y - y)) + 1.0;
588 	}
589 
590 	fgObjs[obj]->y = y;
591 }
592 
getFGObjSetPosX(const Uint32 obj)593 Sint32 getFGObjSetPosX(const Uint32 obj) {
594 	if(!fgObjs[obj]) {
595 		DIE(ERROR_INDEX_INVALID, "fgobj");
596 	}
597 
598 	return fgObjs[obj]->x;
599 }
600 
getFGObjSetPosY(const Uint32 obj)601 Sint32 getFGObjSetPosY(const Uint32 obj) {
602 	if(!fgObjs[obj]) {
603 		DIE(ERROR_INDEX_INVALID, "fgobj");
604 	}
605 
606 	return fgObjs[obj]->y;
607 }
608 
setFGObjSetGFX(const Uint32 obj,const Uint32 gfx)609 void setFGObjSetGFX(const Uint32 obj, const Uint32 gfx) {
610 	if(!fgObjs[obj]) {
611 		DIE(ERROR_INDEX_INVALID, "fgobj");
612 	}
613 
614 	fgObjs[obj]->gfxobj = gfx;
615 }
616 
getFGObjSetGFX(const Uint32 obj)617 Uint32 getFGObjSetGFX(const Uint32 obj) {
618 	if(!fgObjs[obj]) {
619 		DIE(ERROR_INDEX_INVALID, "fgobj");
620 	}
621 
622 	return fgObjs[obj]->gfxobj;
623 }
624 
paintSingleFGObj(SDL_Surface * gfx,const Sint32 x,const Sint32 y)625 void paintSingleFGObj(SDL_Surface *gfx, const Sint32 x, const Sint32 y) {
626 
627 	SDL_Rect src;
628 	SDL_Rect dest;
629 	Sint32 tmpoffs;
630 	if(x >= 0) {
631 		src.x = 0;
632 		src.w = gfx->w;
633 		dest.x = x;
634 		dest.w = gfx->w;
635 	} else if((Sint32)gfx->w + x > 0) {
636 		tmpoffs = -x;
637 		src.x = tmpoffs;
638 		src.w = gfx->w - tmpoffs;
639 		dest.x = 0;
640 		dest.w = gfx->w - tmpoffs;
641 	} else {
642 		// Nothing to paint
643 		return;
644 	}
645 
646 	if(y >= 0) {
647 		src.y = 0;
648 		src.h = gfx->h;
649 		dest.y = y;
650 		dest.h = gfx->h;
651 	} else if((Sint32)gfx->h + y > 0) {
652 		tmpoffs = -y;
653 		src.y = tmpoffs;
654 		src.h = gfx->h - tmpoffs;
655 		dest.y = 0;
656 		dest.h = gfx->h - tmpoffs;
657 	} else {
658 		// Nothing to paint
659 		return;
660 	}
661 
662 	SDL_BlitSurface(gfx, &src, gScreen, &dest);
663 
664 
665 	return;
666 }
667 
paintFGObjs(const Uint32 xoffs,const Uint32 yoffs,const bool topObjects)668 void paintFGObjs(const Uint32 xoffs, const Uint32 yoffs, const bool topObjects) {
669 	Sint32 xpos;
670 	Sint32 ypos;
671 
672 	for(Uint32 i = 0; i < MAX_FGOBJECTS; i++) {
673         if(!fgObjs[i]) {
674             continue;
675         }
676 		xpos =  fgObjs[i]->x - (Sint32)xoffs;
677 		ypos =  fgObjs[i]->y - (Sint32)yoffs;
678 		SDL_Surface *tempsurface = getFGSurface(fgObjs[i]->gfxobj);
679 		if(fgObjs[i]->isVisible && fgObjs[i]->isOnTop == topObjects && xpos + tempsurface->w >= 0 && ypos + tempsurface->h >= 0 && xpos < SCR_WIDTH && ypos < SCR_HEIGHT) {
680 			paintSingleFGObj(tempsurface, xpos, ypos);
681 		}
682 	}
683 }
684 
doFGPlayerAction(const Uint32 playerx,const Uint32 playery)685 void doFGPlayerAction(const Uint32 playerx, const Uint32 playery) {
686 	Uint32 playerxmax = playerx + TILESIZE;
687 	Uint32 playerymax = playery + TILESIZE;
688 	for(Uint32 i = 0; i < MAX_FGOBJECTS; i++) {
689 		if(!fgObjs[i] || !fgObjs[i]->isVisible) {
690 			continue;
691 		}
692 
693 		SDL_Surface *tempsurface = getFGSurface(fgObjs[i]->gfxobj);
694 		Uint32 xpos =  fgObjs[i]->x;
695 		Uint32 ypos =  fgObjs[i]->y;
696 		Uint32 xmax = tempsurface->w + xpos;
697 		Uint32 ymax = tempsurface->h + ypos;
698 
699 		if(playerxmax > xpos && playerx < xmax && playerymax > ypos && playery < ymax) {
700 			if(lhandle.hasScript) {
701 				blLuaCall(lhandle.blLuaState, "handleAction", "i", i);
702 			}
703 			if(lhandle.hasOOScript && strlen(fgObjs[i]->luaCB[OBJECT_CB_PLAYERACTION].cbName) > 0) {
704 				blLuaCall(lhandle.blOOLuaState, fgObjs[i]->luaCB[OBJECT_CB_PLAYERACTION].cbName, "F", i);
705 			}
706 		}
707 	}
708 }
709 
handlePlayerFGColission()710 void handlePlayerFGColission() {
711 	handlePlayerFGPixelCollission();
712 	handlePlayerFGTrueCollission();
713 }
714 
handlePlayerFGTrueCollission()715 void handlePlayerFGTrueCollission() {
716     Sint32 playerx = (Sint32)spritex;
717 	Sint32 playery = (Sint32)spritey;
718 
719 	for(Uint32 i = 0; i < MAX_FGOBJECTS; i++) {
720         if(!fgObjs[i]) {
721             continue;
722         }
723         fgObjs[i]->hasPlayerElevatorCollission = false;
724 		if(fgObjs[i]->isKilling || !fgObjs[i]->isVisible || !fgObjs[i]->isBlocking) {
725 			continue;
726 		}
727 		// Check if player CAN touch the object
728 		SDL_Surface *tempsurface = getFGSurface(fgObjs[i]->gfxobj);
729 		if((playerx + TILESIZE) <= fgObjs[i]->x || (playery + TILESIZE) <= fgObjs[i]->y ||
730 		      (fgObjs[i]->x + tempsurface->w) <= playerx ||
731 		      (fgObjs[i]->y + tempsurface->h) <= playery) {
732             // not overlapping
733             continue;
734         }
735         if(i == 5) {
736             printf("TEST\n");
737         }
738         if(checkPlayerFGTrueCollission(i)) {
739             // Check bottom
740             if(spritevy > 0.0 && fgOverlap.bottom) {
741                 spritevy = 0;
742                 spritey -= fgOverlap.bottom;
743                 isJumping = false;
744                 checkPlayerFGTrueCollission(i);
745                 if(fgObjs[i]->isElevator) {
746                     fgObjs[i]->hasPlayerElevatorCollission = true;
747                 }
748             }
749             // Check left
750             if(spritevx < 0.0 && fgOverlap.left) {
751                 spritevx = 0;
752                 spritex += fgOverlap.left;
753                 checkPlayerFGTrueCollission(i);
754             }
755             // Check right
756             if(spritevx > 0.0 && fgOverlap.right > 0) {
757                 spritevx = 0;
758                 spritex -= fgOverlap.right;
759                 checkPlayerFGTrueCollission(i);
760             }
761             // Check top
762             if(spritevy < 0.0 && fgOverlap.top) {
763                 spritevy = 0;
764                 spritey += fgOverlap.top;
765                 //checkPlayerFGTrueCollission(i);
766             }
767 
768         }
769     }
770 
771 }
772 
773 
getPlayerFGKillColission()774 bool getPlayerFGKillColission() {
775 	Sint32 playerx = (Sint32)spritex;
776 	Sint32 playery = (Sint32)spritey;
777 
778 	for(Uint32 i = 0; i < MAX_FGOBJECTS; i++) {
779 		if(!fgObjs[i] || !fgObjs[i]->isKilling || !fgObjs[i]->isVisible) {
780 			continue;
781 		}
782 
783 		SDL_Surface *tempsurface = getFGSurface(fgObjs[i]->gfxobj);
784 		if((playerx + TILESIZE) > fgObjs[i]->x && playerx < (fgObjs[i]->x + tempsurface->w) &&
785 		   (playery + TILESIZE) > fgObjs[i]->y && playery < (fgObjs[i]->y + tempsurface->h) &&
786            checkPlayerFGTrueCollission(i)) {
787 			return true;
788 		}
789 	}
790 	return false;
791 }
792 
handlePlayerFGPixelCollission()793 void handlePlayerFGPixelCollission() {
794 	Sint32 playerx = (Sint32)spritex;
795 	Sint32 playery = (Sint32)spritey;
796 
797 	for(Uint32 i = 0; i < MAX_FGOBJECTS; i++) {
798 		if(!fgObjs[i] || !fgObjs[i]->isPixel || !fgObjs[i]->isVisible) {
799 			continue;
800 		}
801 
802 		SDL_Surface *tempsurface = getFGSurface(fgObjs[i]->gfxobj);
803 		if((playerx + TILESIZE) > fgObjs[i]->x && playerx < (fgObjs[i]->x + tempsurface->w) &&
804 		   (playery + TILESIZE) > fgObjs[i]->y && playery < (fgObjs[i]->y + tempsurface->h) &&
805            checkPlayerFGTrueCollission(i)) {
806 			foundPixels++;
807 			gamedata.player->score += PIXEL_SCORE;
808 			soundPlayFX(FX_COLLECT_PIXEL);
809 			fgObjs[i]->isVisible = false;
810 		}
811 	}
812 }
813 
handlePlayerFGObjCallbacks()814 void handlePlayerFGObjCallbacks() {
815 	Sint32 playerx = (Sint32)spritex;
816 	Sint32 playery = (Sint32)spritey;
817 	Uint32 topColission;
818 
819 	for(Uint32 i = 0; i < MAX_FGOBJECTS; i++) {
820 		if(!fgObjs[i] || fgObjs[i]->luaCB[OBJECT_CB_PLAYERCOLLISION].cbName[0] == 0) {
821 			continue;
822 		}
823 
824 		SDL_Surface *tempsurface = getFGSurface(fgObjs[i]->gfxobj);
825 		if((playerx + TILESIZE) > fgObjs[i]->x && playerx < (fgObjs[i]->x + tempsurface->w) &&
826 		   (playery + TILESIZE) > fgObjs[i]->y && playery < (fgObjs[i]->y + tempsurface->h) &&
827            checkPlayerFGTrueCollission(i)) {
828 			topColission = 0;
829 			blLuaCall(lhandle.blOOLuaState, fgObjs[i]->luaCB[OBJECT_CB_PLAYERCOLLISION].cbName, "FC", i);
830 		}
831 	}
832 }
833 
checkPlayerFGTrueCollission(const Uint32 objid)834 bool checkPlayerFGTrueCollission(const Uint32 objid) {
835 
836 	bool overlap = false;
837 	fgOverlap.top = 0;
838 	fgOverlap.bottom = 0;
839 	fgOverlap.left = 0;
840 	fgOverlap.right = 0;
841 
842 
843 
844 	SDL_Surface* obj = getFGSurface(fgObjs[objid]->gfxobj);
845 
846 	if (SDL_MUSTLOCK(playersprite))
847 		if (SDL_LockSurface(playersprite) < 0)
848 			return false;
849 	if (SDL_MUSTLOCK(obj))
850 		if (SDL_LockSurface(obj) < 0)
851 			return false;
852 
853 	Uint32 pitch_sprite = playersprite->pitch / 4;
854 	Uint32 pitch_obj = obj->pitch / 4;
855 	Sint32 i, j, k, l;
856 	Uint32 pixel;
857 
858 	Sint32 playerscreenx, playerscreeny;
859 	Sint32 objx, objy;
860 	Sint32 minx = -1;
861 	Sint32 miny = -1;
862 	Sint32 maxx = TILESIZE;
863 	Sint32 maxy = TILESIZE;
864 
865 	// Check for colission
866 	for(i=0; i < TILESIZE; i++) {
867 		for(j=0; j < TILESIZE; j++) {
868 			pixel = ((Uint32 *)playersprite->pixels)[(j + playersprite_srcoffset) * pitch_sprite + i];
869 
870 			if(pixel != 0x00000000) {
871 				playerscreenx = (Uint32)spritex + i;
872 				playerscreeny = (Uint32)spritey + j;
873 				// Check, if this point CAN touch the playersprite...
874 				if(playerscreenx >= fgObjs[objid]->x && playerscreeny >= fgObjs[objid]->y &&
875 				   playerscreenx < (fgObjs[objid]->x + obj->w) &&
876 				   playerscreeny < (fgObjs[objid]->y + obj->h)) {
877 
878 					// OK, pixel overlaps, calculate in-object position and check for transparency
879 					objx = playerscreenx - fgObjs[objid]->x;
880 					objy = playerscreeny - fgObjs[objid]->y;
881 
882 					pixel = ((Uint32 *)obj->pixels)[objy * pitch_obj + objx];
883 					if((pixel & 0xff000000) > 0x80000000) {
884 						overlap = true;
885 						// Search to left
886 						if(i < TILESIZE/2) {
887 						     minx = TILESIZE;
888 						     for(k = i; k >= 0; k--) {
889                                  if(((Uint32 *)playersprite->pixels)[(j + playersprite_srcoffset) * pitch_sprite + k] != 0x00000000) {
890                                     minx = k;
891                                 }
892                             }
893                             minx = i - minx + 1;
894                             if(minx > fgOverlap.left) {
895                                 fgOverlap.left = minx;
896                             }
897                         }
898 
899                         // Search to right
900 						if(i >= TILESIZE/2) {
901 						     maxx = 0;
902 						     for(k = i; k < TILESIZE; k++) {
903                                  if(((Uint32 *)playersprite->pixels)[(j + playersprite_srcoffset) * pitch_sprite + k] != 0x00000000) {
904                                     maxx = k;
905                                 }
906                             }
907                             maxx = maxx - i + 1;
908                             if(maxx > fgOverlap.right) {
909                                 fgOverlap.right = maxx;
910                             }
911                         }
912 
913                         // Search to top
914 						if(j < TILESIZE/2) {
915 						     miny = TILESIZE;
916 						     for(l = j; l >= 0; l--) {
917                                  if(((Uint32 *)playersprite->pixels)[(l + playersprite_srcoffset) * pitch_sprite + i] != 0x00000000) {
918                                     miny = l;
919                                 }
920                             }
921                             miny = j - miny + 1;
922                             if(miny > fgOverlap.top) {
923                                 fgOverlap.top = miny;
924                             }
925                         }
926 
927                         // Search to bottom
928 						if(j >= TILESIZE/2) {
929 						     maxy = 0;
930 						     for(l = j; l < TILESIZE; l++) {
931                                  if(((Uint32 *)playersprite->pixels)[(l + playersprite_srcoffset) * pitch_sprite + i] != 0x00000000) {
932                                     maxy = l;
933                                 }
934                             }
935                             maxy = maxy - j + 1;
936                             if(maxy > fgOverlap.bottom) {
937                                 fgOverlap.bottom = maxy;
938                             }
939                         }
940 					}
941 				}
942 				//((Uint32 *)gScreen->pixels)[(j + y) * pitch_bg + i + x] = pixel;
943 			}
944 
945 		}
946 	}
947 
948 	// More than a half-overlap shouldn't be possible; but check anyway...
949 	if(fgOverlap.left > TILESIZE/2) {
950 		fgOverlap.left = 0;
951 	}
952 	if(fgOverlap.top > TILESIZE/2) {
953 		fgOverlap.top = 0;
954 	}
955 	if(fgOverlap.right > TILESIZE/2) {
956 		fgOverlap.right = 0;
957 	}
958 	if(fgOverlap.bottom > TILESIZE/2) {
959 		fgOverlap.bottom = 0;
960 	}
961 	if(!fgOverlap.left && !fgOverlap.right && !fgOverlap.top && !fgOverlap.bottom) {
962         // Someone set up us the bomb????
963         overlap = false;
964     }
965 
966 	if(overlap) {
967 		//printf("L: %d R: %d T: %d B: %d\n", fgOverlap.left, fgOverlap.right, fgOverlap.top, fgOverlap.bottom);
968 
969 	}
970 		// Unlock Surfaces if needed
971 		if (SDL_MUSTLOCK(playersprite))
972 			SDL_UnlockSurface(playersprite);
973 		if (SDL_MUSTLOCK(obj))
974 			SDL_UnlockSurface(obj);
975 
976 	return overlap;
977 }
978