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