polymod still broken
[awish.git] / src / game.c
blob9263cbf4b93d27f960da02d113eb2fc00872215a
1 /*
2 * This program is free software: you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License as published by
4 * the Free Software Foundation, either version 3 of the License, or
5 * (at your option) any later version.
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
12 * You should have received a copy of the GNU General Public License
13 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 #include <stdio.h>
16 #include <stdlib.h>
17 #include <string.h>
18 #include <time.h>
19 #include <unistd.h>
21 #include "game.h"
23 #include "resfile.h"
24 #include "video.h"
25 #include "mainloop.h"
26 #include "vm.h"
27 #include "gameglobals.h"
28 #include "title.h"
29 #include "polymod.h"
32 extern int goobers;
36 ////////////////////////////////////////////////////////////////////////////////
37 VMRSTCB gameRSTCB = NULL;
40 ////////////////////////////////////////////////////////////////////////////////
41 #define VIS_WIDTH (15)
42 #define VIS_HEIGHT (17)
43 #define VIS_X (10)
44 #define VIS_Y (20)
47 ////////////////////////////////////////////////////////////////////////////////
48 static int redrawLevel;
49 static int oldScrX, oldScrY;
50 static int mapWidth;
51 static int mapHeight;
52 static int curLevel;
53 static char levelname[257];
54 static char levelcode[257];
55 static char itemname[257];
56 static int lnamex;
57 static Uint8 *levelData = NULL;
58 static int levelDataSize = 0;
59 static Uint8 *bmap = NULL, *fmap = NULL;
60 static Uint8 *xflags = NULL;
61 static int inMinimap;
63 static int doSave = 0;
65 static int demorecmode = 0; // 0: none; 1: recording; -1: playing
66 static int demoSize = 0;
67 static int demoPos = 0;
68 static Uint8 *demoData = NULL;
69 static Uint8 demoPrevKeyState = 0;
70 static int demoKeyStateRepeats = 0;
72 static char message[256];
73 //static Uint32 msgEndTime = 0;
75 static Uint32 demo_m_w = 0;
76 static Uint32 demo_m_z = 0;
79 ////////////////////////////////////////////////////////////////////////////////
80 static int gamekeys[12];
81 static int fkeys[10];
84 static void setGameKeysGVars (void) {
85 vmGVars[GVAR_KEY_LEFT] = gamekeys[0] ? 1 : 0;
86 vmGVars[GVAR_KEY_RIGHT] = gamekeys[1] ? 1 : 0;
87 vmGVars[GVAR_KEY_UP] = gamekeys[2] ? 1 : 0;
88 vmGVars[GVAR_KEY_DOWN] = gamekeys[3] ? 1 : 0;
89 vmGVars[GVAR_KEY_TAKE] = gamekeys[4] ? 1 : 0;
90 vmGVars[GVAR_KEY_USE] = gamekeys[5] ? 1 : 0;
92 vmGVars[GVAR_KEY_MINIMAP] = gamekeys[6] ? 1 : 0;
93 vmGVars[GVAR_KEY_RESTART] = gamekeys[7] ? 1 : 0;
95 vmGVars[GVAR_KEY_FALL_CHEAT] = gamekeys[8] ? 1 : 0;
96 vmGVars[GVAR_KEY_WALK_CHEAT] = gamekeys[9] ? 1 : 0;
97 vmGVars[GVAR_KEY_PLEV_CHEAT] = gamekeys[10] ? 1 : 0;
98 vmGVars[GVAR_KEY_NLEV_CHEAT] = gamekeys[11] ? 1 : 0;
102 ////////////////////////////////////////////////////////////////////////////////
103 #define SECRET (42)
104 //#define SECRET (0)
107 static int readBuf (FILE *fl, void *buf, int len) {
108 unsigned char *c = (unsigned char *)buf;
110 while (len-- > 0) {
111 unsigned char b;
113 if (fread(&b, 1, 1, fl) != 1) return -1;
114 b ^= SECRET;
115 *c++ = b;
117 return 0;
121 static int writeBuf (FILE *fl, const void *buf, int len) {
122 const unsigned char *c = (const unsigned char *)buf;
124 while (len-- > 0) {
125 unsigned char b = *c++;
127 b ^= SECRET;
128 if (fwrite(&b, 1, 1, fl) != 1) return -1;
130 return 0;
134 static int readDW (FILE *fl, int *v) {
135 int t[4];
137 for (int f = 0; f < 4; ++f) {
138 unsigned char b;
140 if (fread(&b, 1, 1, fl) != 1) return -1;
141 t[f] = b^SECRET;
144 if (v) {
145 *v = 0;
146 for (int f = 0; f < 4; ++f) *v |= t[f]<<(8*f);
148 return 0;
152 static int writeDW (FILE *fl, int v) {
153 for (int f = 0; f < 4; ++f) {
154 unsigned char b;
156 b = v&0xff;
157 b ^= SECRET;
158 if (fwrite(&b, 1, 1, fl) != 1) return -1;
159 v >>= 8;
161 return 0;
165 static int readUDW (FILE *fl, Uint32 *v) {
166 int t[4];
168 for (int f = 0; f < 4; ++f) {
169 unsigned char b;
171 if (fread(&b, 1, 1, fl) != 1) return -1;
172 t[f] = b^SECRET;
175 if (v) {
176 *v = 0;
177 for (int f = 0; f < 4; ++f) *v |= t[f]<<(8*f);
179 return 0;
183 static int writeUDW (FILE *fl, Uint32 v) {
184 for (int f = 0; f < 4; ++f) {
185 unsigned char b;
187 b = v&0xff;
188 b ^= SECRET;
189 if (fwrite(&b, 1, 1, fl) != 1) return -1;
190 v >>= 8;
192 return 0;
196 ////////////////////////////////////////////////////////////////////////////////
197 static const char *SAVE_GAME_SIGNATURE = "ASG1";
200 static int saveGame (void) {
201 FILE *fl = fopen("awish.sav", "wb");
203 if (fl != NULL) {
204 demo_m_w = getSeedL();
205 demo_m_z = getSeedH();
206 if (fwrite(SAVE_GAME_SIGNATURE, 4, 1, fl) != 1) goto error;
207 if (vmSaveState(fl) != 0) goto error;
208 if (writeDW(fl, mapWidth) != 0) goto error;
209 if (writeDW(fl, mapHeight) != 0) goto error;
210 if (writeUDW(fl, demo_m_w) != 0) goto error;
211 if (writeUDW(fl, demo_m_z) != 0) goto error;
212 if (writeDW(fl, inMinimap) != 0) goto error;
213 if (writeDW(fl, curLevel) != 0) goto error;
214 if (writeBuf(fl, levelname, sizeof(levelname)) != 0) goto error;
215 if (writeDW(fl, lnamex) != 0) goto error;
216 if (writeBuf(fl, levelcode, sizeof(levelcode)) != 0) goto error;
217 if (writeBuf(fl, itemname, sizeof(itemname)) != 0) goto error;
218 if (writeBuf(fl, bmap, mapWidth*mapHeight) != 0) goto error;
219 if (writeBuf(fl, fmap, mapWidth*mapHeight) != 0) goto error;
220 if (writeBuf(fl, xflags, mapWidth) != 0) goto error;
221 fclose(fl);
222 return 0;
224 error:
225 fclose(fl);
226 unlink("awish.sav");
227 if (goobers) fprintf(stderr, "error saving game\n");
228 return -1;
232 static int loadGame (void) {
233 FILE *fl = fopen("awish.sav", "rb");
235 if (fl != NULL) {
236 char sign[4];
238 if (fread(sign, 4, 1, fl) != 1) goto error;
239 if (memcmp(sign, SAVE_GAME_SIGNATURE, 4) != 0) goto error;
240 if (vmLoadState(fl) != 0) goto error;
241 if (readDW(fl, &mapWidth) != 0) goto error;
242 if (readDW(fl, &mapHeight) != 0) goto error;
243 if (readUDW(fl, &demo_m_w) != 0) goto error;
244 if (readUDW(fl, &demo_m_z) != 0) goto error;
245 if (readDW(fl, &inMinimap) != 0) goto error;
246 if (readDW(fl, &curLevel) != 0) goto error;
247 if (readBuf(fl, levelname, sizeof(levelname)) != 0) goto error;
248 if (readDW(fl, &lnamex) != 0) goto error;
249 if (readBuf(fl, levelcode, sizeof(levelcode)) != 0) goto error;
250 if (readBuf(fl, itemname, sizeof(itemname)) != 0) goto error;
251 if (bmap != NULL) free(bmap); bmap = NULL;
252 if (fmap != NULL) free(fmap); fmap = NULL;
253 if (xflags != NULL) free(xflags); xflags = NULL;
254 fmap = calloc(mapWidth*mapHeight, 1); if (fmap == NULL) fatal("out of memory in loadGame");
255 bmap = calloc(mapWidth*mapHeight, 1); if (bmap == NULL) fatal("out of memory in loadGame");
256 xflags = calloc(mapWidth, 1); if (xflags == NULL) fatal("out of memory in loadGame");
257 if (readBuf(fl, bmap, mapWidth*mapHeight) != 0) goto error;
258 if (readBuf(fl, fmap, mapWidth*mapHeight) != 0) goto error;
259 if (readBuf(fl, xflags, mapWidth) != 0) goto error;
260 fclose(fl);
261 setSeedL(demo_m_w);
262 setSeedL(demo_m_z);
263 redrawLevel = 1;
264 oldScrX = oldScrY = -1;
265 return 0;
267 error:
268 fclose(fl);
269 if (goobers) fprintf(stderr, "error loading saved game\n");
270 return -1;
274 ////////////////////////////////////////////////////////////////////////////////
275 static void demoClear (void) {
276 //demorecmode = 0;
277 demoSize = 0;
278 demoPos = 0;
279 demoPrevKeyState = 0;
280 demoKeyStateRepeats = 0;
281 if (demoData != NULL) free(demoData);
282 demoData = NULL;
286 static void demoAddByte (Uint8 b) {
287 if (demoPos+1 > demoSize && demoSize > 1024*1024*16) fatal("out of memory in demo recording!");
288 if (demoPos+1 > demoSize) {
289 int newsz = demoSize+1024*32;
290 Uint8 *nn = realloc(demoData, newsz);
292 if (!nn) fatal("out of memory in demo recording!");
293 demoData = nn;
294 demoSize = newsz;
296 demoData[demoPos++] = b;
300 static Uint8 demoGetKeyState (void) {
301 return
302 ((gamekeys[0]?1:0)<<0) |
303 ((gamekeys[1]?1:0)<<1) |
304 ((gamekeys[2]?1:0)<<2) |
305 ((gamekeys[3]?1:0)<<3) |
306 ((gamekeys[4]?1:0)<<4) |
307 ((gamekeys[5]?1:0)<<5);
311 static void demoSetKeyState (Uint8 kstate) {
312 gamekeys[0] = (kstate&(1<<0)) != 0;
313 gamekeys[1] = (kstate&(1<<1)) != 0;
314 gamekeys[2] = (kstate&(1<<2)) != 0;
315 gamekeys[3] = (kstate&(1<<3)) != 0;
316 gamekeys[4] = (kstate&(1<<4)) != 0;
317 gamekeys[5] = (kstate&(1<<5)) != 0;
321 static void demoAddFrameData (void) {
322 Uint8 kstate = demoGetKeyState();
324 if (demoKeyStateRepeats == 256) {
325 demoAddByte(demoKeyStateRepeats-1);
326 demoAddByte(demoPrevKeyState);
327 demoKeyStateRepeats = 0;
330 if (kstate != demoPrevKeyState) {
331 if (demoKeyStateRepeats > 0) {
332 demoAddByte(demoKeyStateRepeats-1);
333 demoAddByte(demoPrevKeyState);
335 demoPrevKeyState = kstate;
336 demoKeyStateRepeats = 1;
337 } else {
338 ++demoKeyStateRepeats;
343 static void demoGetFrameData (void) {
344 while (demoKeyStateRepeats < 1) {
345 if (demoPos+2 > demoSize) {
346 demoClear();
347 demorecmode = 0;
348 if (goobers) fprintf(stderr, "demo complete\n");
349 strcpy(message, "demo stopped");
350 return;
352 demoKeyStateRepeats = demoData[demoPos++];
353 ++demoKeyStateRepeats;
354 demoPrevKeyState = demoData[demoPos++];
356 --demoKeyStateRepeats;
358 demoSetKeyState(demoPrevKeyState);
362 static int demoSave (void) {
363 FILE *fl;
364 char buf[128];
365 char sign[5];
367 if (demoKeyStateRepeats > 0) {
368 demoAddByte(demoKeyStateRepeats-1);
369 demoAddByte(demoPrevKeyState);
372 sprintf(buf, "awish%02d.dmo", curLevel+1);
373 fl = fopen(buf, "wb");
374 if (fl == NULL) {
375 if (goobers) fprintf(stderr, "can't create demo file '%s'\n", buf);
376 return -1;
378 strcpy(sign, "AWD1");
379 if (fwrite(sign, 4, 1, fl) != 1) goto error;
380 if (writeDW(fl, curLevel) != 0) goto error;
381 if (writeUDW(fl, demo_m_w) != 0) goto error;
382 if (writeUDW(fl, demo_m_z) != 0) goto error;
383 if (writeDW(fl, demoPos) != 0) goto error;
384 if (writeBuf(fl, demoData, demoPos) != 0) goto error;
385 fclose(fl);
386 if (goobers) fprintf(stderr, "demo saved to file '%s'\n", buf);
387 return 0;
388 error:
389 fclose(fl);
390 unlink(buf);
391 if (goobers) fprintf(stderr, "can't write demo file '%s'\n", buf);
392 return -1;
396 static int demoLoad (void) {
397 FILE *fl;
398 char buf[128];
399 int size, level;
400 char sign[4];
402 demoClear();
403 sprintf(buf, "awish%02d.dmo", curLevel+1);
404 fl = fopen(buf, "rb");
405 if (fl == NULL) {
406 if (goobers) fprintf(stderr, "can't open demo file '%s'\n", buf);
407 return -1;
410 if (fread(sign, 4, 1, fl) != 1) goto error;
411 if (memcmp(sign, "AWD1", 4) != 0) goto error;
412 if (readDW(fl, &level) != 0) goto error;
413 if (readUDW(fl, &demo_m_w) != 0) goto error;
414 if (readUDW(fl, &demo_m_z) != 0) goto error;
415 if (readDW(fl, &size) != 0) goto error;
416 if (size < 1 || size > 1024*1024*16) goto error;
417 demoData = malloc(size);
418 if (demoData == NULL) goto error;
419 if (readBuf(fl, demoData, size) != 0) goto error;
420 demoSize = size;
421 demoPos = 0;
422 fclose(fl);
423 setSeedL(demo_m_w);
424 setSeedL(demo_m_z);
425 if (goobers) fprintf(stderr, "loaded demo file '%s'\n", buf);
427 return 0;
428 error:
429 fclose(fl);
430 if (goobers) fprintf(stderr, "can't load demo file '%s'\n", buf);
431 demoClear();
432 return -1;
436 static inline int isGameStopped (void) {
437 return
438 vmGVars[GVAR_GAME_STATE] == CONST_GAME_STATE_DEAD ||
439 vmGVars[GVAR_GAME_STATE] == CONST_GAME_STATE_COMPLETE;
443 static void demoCB (void) {
444 //if (vmGVars[GVAR_GAME_STATE] == CONST_GAME_STATE_STARTED) unloadMapScript();
446 if (vmGVars[GVAR_SCR_X] != oldScrX || vmGVars[GVAR_SCR_Y] != oldScrY) {
447 oldScrX = vmGVars[GVAR_SCR_X];
448 oldScrY = vmGVars[GVAR_SCR_Y];
449 redrawLevel = 1;
452 switch (demorecmode) {
453 case -666: // prepare to load demo
454 if (demoLoad() != 0) {
455 demorecmode = 0;
456 break;
458 demorecmode = -2;
459 // fallthru
460 case 666: // prepare to save demo
461 vmSetPC(0, CODE_ENTRY_GAME_RESTART_LEVEL);
462 vmGVars[GVAR_CUR_LEVEL] = curLevel;
463 vmGVars[GVAR_GAME_STATE] = -1; // invalid state
464 if (demorecmode > 0) {
465 demoClear();
466 demorecmode = 2;
468 break;
469 case -1: // demo replaying
470 case 1: // demo saving
471 if (isGameStopped()) {
472 // the level is over or prof is dead
473 if (demorecmode > 0) demoSave();
474 demoClear();
475 demorecmode = 0;
476 } else {
477 ((demorecmode < 0) ? demoGetFrameData : demoAddFrameData)();
479 break;
480 case -2: // waiting for 'game started' trigger
481 case 2: // waiting for 'game started' trigger
482 if (vmGVars[GVAR_GAME_STATE] >= 0) {
483 if (goobers) fprintf(stderr, "demo %s started...\n", demorecmode<0?"replaying":"recording");
484 if (demorecmode < 0) {
485 // replay
486 setSeedL(demo_m_w);
487 setSeedL(demo_m_z);
488 } else {
489 // record
490 demo_m_w = getSeedL();
491 demo_m_z = getSeedH();
493 demorecmode = (demorecmode < 0) ? -1 : 1;
495 break;
497 setGameKeysGVars();
501 ////////////////////////////////////////////////////////////////////////////////
502 static void frmGameKey (SDL_KeyboardEvent *key) {
503 if (key->type == SDL_KEYDOWN) {
504 switch (key->keysym.sym) {
505 case SDLK_ESCAPE:
506 case SDLK_SPACE:
507 case SDLK_RETURN:
508 if (vmPaused && inMinimap) {
509 inMinimap = 0;
510 doSave = 0;
511 vmPaused = 0;
512 redrawLevel = 1;
513 gamekeys[6] = 0;
515 break;
516 case SDLK_F12:
517 vmGVars[GVAR_KEY_QUIT] = 1;
518 break;
519 case SDLK_p:
520 if (vmPaused == 0) {
521 gamekeys[6] = 1;
522 } else {
523 if (inMinimap) {
524 inMinimap = 0;
525 doSave = 0;
526 vmPaused = 0;
527 redrawLevel = 1;
528 gamekeys[6] = 1;
531 break;
532 case SDLK_r:
533 if (vmPaused == 0) {
534 if (demorecmode != 0) { demoClear(); demorecmode = 0; }
535 if ((key->keysym.mod&(KMOD_CTRL)) != 0) {
536 gamekeys[7] = 1;
539 break;
540 case SDLK_s:
541 if (vmPaused == 0 && !demorecmode) {
542 if (goobers && (key->keysym.mod&(KMOD_CTRL)) != 0) { doSave = 1; vmPaused = 1; }
544 break;
545 case SDLK_l:
546 if (vmPaused == 0 && !demorecmode) {
547 if (goobers && (key->keysym.mod&(KMOD_CTRL)) != 0) { doSave = -1; vmPaused = 1; }
549 break;
550 case SDLK_d:
551 if (vmPaused == 0) {
552 if (goobers && (key->keysym.mod&(KMOD_CTRL)) != 0) {
553 if (!demorecmode) {
554 demorecmode = 666; // 'start saving'
555 } else {
556 demoSave();
557 demoClear();
558 demorecmode = 0;
562 break;
563 case SDLK_m:
564 if (vmPaused == 0) {
565 if (goobers && (key->keysym.mod&(KMOD_CTRL)) != 0) {
566 if (!demorecmode) {
567 demorecmode = -666; // 'start playing'
568 } else {
569 demoClear();
570 demorecmode = 0;
571 demoSetKeyState(0);
575 break;
576 default: ;
580 if (demorecmode == 0 || demorecmode == 1) {
581 switch (key->keysym.sym) {
582 case SDLK_LEFT: case SDLK_KP4: gamekeys[0] = (key->type == SDL_KEYDOWN); break;
583 case SDLK_RIGHT: case SDLK_KP6: gamekeys[1] = (key->type == SDL_KEYDOWN); break;
584 case SDLK_UP: case SDLK_KP8: gamekeys[2] = (key->type == SDL_KEYDOWN); break;
585 case SDLK_DOWN: case SDLK_KP2: gamekeys[3] = (key->type == SDL_KEYDOWN); break;
586 case SDLK_SPACE: case SDLK_KP0: gamekeys[4] = (key->type == SDL_KEYDOWN); break;
587 case SDLK_RETURN: case SDLK_KP_PERIOD: gamekeys[5] = (key->type == SDL_KEYDOWN); break;
588 default: ;
591 if (goobers && !demorecmode) {
592 switch (key->keysym.sym) {
593 case SDLK_f: gamekeys[8] = (key->type == SDL_KEYDOWN); break;
594 case SDLK_w: gamekeys[9] = (key->type == SDL_KEYDOWN); break;
595 case SDLK_KP_MINUS: gamekeys[10] = (key->type == SDL_KEYDOWN); break;
596 case SDLK_KP_PLUS: gamekeys[11] = (key->type == SDL_KEYDOWN); break;
598 case SDLK_F1: fkeys[1] = (key->type == SDL_KEYDOWN); break;
599 case SDLK_F2: fkeys[2] = (key->type == SDL_KEYDOWN); break;
600 case SDLK_F3: fkeys[3] = (key->type == SDL_KEYDOWN); break;
601 case SDLK_F4: fkeys[4] = (key->type == SDL_KEYDOWN); break;
602 case SDLK_F5: fkeys[5] = (key->type == SDL_KEYDOWN); break;
603 case SDLK_F6: fkeys[6] = (key->type == SDL_KEYDOWN); break;
604 case SDLK_F7: fkeys[7] = (key->type == SDL_KEYDOWN); break;
605 case SDLK_F8: fkeys[8] = (key->type == SDL_KEYDOWN); break;
606 case SDLK_F9: fkeys[9] = (key->type == SDL_KEYDOWN); break;
607 default: ;
614 ////////////////////////////////////////////////////////////////////////////////
615 static inline Uint8 fgTile (int x, int y) {
616 return (x >= 0 && y >= 0 && x < mapWidth && y < mapHeight) ? fmap[y*mapWidth+x] : 0;
620 static inline Uint8 bgTile (int x, int y) {
621 if (y == -666) return (x >= 0 && x < mapWidth) ? xflags[x] : 0;
622 return (x >= 0 && y >= 0 && x < mapWidth && y < mapHeight) ? bmap[y*mapWidth+x] : 0;
626 static inline void setFGTile (int x, int y, Uint8 tile) {
627 if (x >= 0 && y >= 0 && x < mapWidth && y < mapHeight) {
628 if (fmap[y*mapWidth+x] != tile) {
629 redrawLevel = 1;
630 fmap[y*mapWidth+x] = tile;
636 static inline void setBGTile (int x, int y, Uint8 tile) {
637 if (y == -666 && x >= 0 && x < mapWidth) xflags[x] = tile;
638 if (x >= 0 && y >= 0 && x < mapWidth && y < mapHeight) {
639 if (bmap[y*mapWidth+x] != tile) {
640 redrawLevel = 1;
641 bmap[y*mapWidth+x] = tile;
647 static int mapGet (int tid, int fg, int x, int y) {
648 if (fmap != NULL) return fg ? fgTile(x, y) : bgTile(x, y);
649 return 0;
653 static void mapSet (int tid, int fg, int x, int y, int tile) {
654 if (fmap != NULL) {
655 if (fg) setFGTile(x, y, tile); else setBGTile(x, y, tile);
660 ////////////////////////////////////////////////////////////////////////////////
661 // cliprect should be set
662 static void levelDrawMap (SDL_Surface *frame) {
663 SDL_Rect rc;
665 rc.x = VIS_X*2;
666 rc.y = VIS_Y*2;
667 rc.w = VIS_WIDTH*20*2;
668 rc.h = VIS_HEIGHT*10*2;
670 if (!inMinimap) {
671 int levelback = vmGVars[GVAR_LEVEL_BACKPIC];
672 int scrX = vmGVars[GVAR_SCR_X], scrY = vmGVars[GVAR_SCR_Y];
674 if (levelback < 1 || levelback > 7) levelback = 1;
675 blitSurface(frame, 0, 0, backs[levelback]);
677 SDL_SetClipRect(frame, &rc);
678 for (int dy = 0; dy < VIS_HEIGHT; ++dy) {
679 for (int dx = 0; dx < VIS_WIDTH; ++dx) {
680 int x = scrX+dx, y = scrY+dy;
681 Uint8 b = bgTile(x, y), f = fgTile(x, y);
683 if (b) blitSurface2x(frame, VIS_X+dx*20, VIS_Y+dy*10, banks[CONST_BANK_BG_TILES].spr[b-1][0]);
684 if (f) blitSurface2x(frame, VIS_X+dx*20, VIS_Y+dy*10, banks[CONST_BANK_FG_TILES].spr[f-1][0]);
687 } else {
688 blitSurface(frame, 0, 0, backs[1]);
689 SDL_SetClipRect(frame, &rc);
690 for (int dy = 0; dy < mapHeight; ++dy) {
691 for (int dx = 1; dx < mapWidth; ++dx) {
692 Uint8 b = bgTile(dx, dy), f = fgTile(dx, dy), t = 8;
694 if (f == 0) {
695 if (b >= 1 && b <= 8) t = b-1; else t = 8;
696 } else {
697 t = f+8;
699 if (banks[CONST_BANK_MAP_TILES].spr[t][0]) {
700 blitSurface2x(frame, VIS_X+dx*6, VIS_Y+dy*4, banks[CONST_BANK_MAP_TILES].spr[t][0]);
701 } else {
702 blitSurface2x(frame, VIS_X+dx*6, VIS_Y+dy*4, banks[CONST_BANK_MAP_TILES].spr[0][0]);
707 SDL_SetClipRect(frame, NULL);
708 redrawLevel = 0;
712 static void levelDrawSprites (SDL_Surface *frame) {
713 if (!inMinimap) {
714 int scrX = vmGVars[GVAR_SCR_X], scrY = vmGVars[GVAR_SCR_Y];
715 int py = vmGetTVar(0, TVAR_POS_Y)-scrY;
717 for (int cc = 0; cc <= 2; ++cc) {
718 for (int f = cc==1?1:0; f <= vmLastThread(); ++f) {
719 if (vmIsThreadAlive(f) && !vmIsSuspendedThread(f)) {
720 int b = vmGetTVar(f, TVAR_SPR_BANK);
721 int s = vmGetTVar(f, TVAR_SPR_NUM);
722 int d = vmGetTVar(f, TVAR_SPR_DIR);
724 if (d >= 0 && d <= 1 && s >= 0 && b >= 0 && b <= 255 && s < banks[b].count && banks[b].spr[s][d]) {
725 SDL_Surface *sf = banks[b].spr[s][d];
726 int x = vmGetTVar(f, TVAR_POS_X)-scrX;
727 int y = vmGetTVar(f, TVAR_POS_Y)-scrY;
728 int tx = vmGetTVar(f, TVAR_POS_TX);
729 int ty = vmGetTVar(f, TVAR_POS_TY);
730 int si = vmGetTVar(f, TVAR_SPR_ITEM);
732 if (cc == 0 && b == CONST_BANK_ITEMS) continue;
733 if (cc == 1 && b != CONST_BANK_ITEMS) continue;
734 if (cc == 2) {
735 if (b != CONST_BANK_PROF) {
736 if (b != CONST_BANK_ITEMS) continue;
737 if (y < py) continue;
740 if (b == CONST_BANK_IM_PROF || b == CONST_BANK_PROF) tx -= 5;
741 blitSurface2x(frame, VIS_X+x*20+tx, VIS_Y+y*10+ty-sf->h/2, sf);
742 if (si > 0 && si < banks[CONST_BANK_ITEMS].count) {
743 sf = banks[CONST_BANK_ITEMS].spr[si][0];
744 blitSurface2x(frame, VIS_X+x*20+tx, VIS_Y+y*10+ty-sf->h/2-24, sf);
750 } else {
751 blitSurface2x(frame, VIS_X+(vmGetTVar(0, TVAR_POS_X)+0)*6, VIS_Y+(vmGetTVar(0, TVAR_POS_Y)-4)*4, banks[CONST_BANK_MAP_ITEMS].spr[0][0]);
752 for (int f = 1; f < VM_MAX_THREADS; ++f) {
753 if (vmIsThreadAlive(f) && !vmIsSuspendedThread(f)) {
754 int i = vmGetTVar(f, TVAR_ITEM_ID);
755 if (i > 0 && i <= 255) {
756 SDL_Surface *sf = banks[CONST_BANK_MAP_ITEMS].spr[i][0];
757 int x = vmGetTVar(f, TVAR_POS_X);
758 int y = vmGetTVar(f, TVAR_POS_Y);
760 blitSurface2x(frame, VIS_X+(x+0)*6, VIS_Y+(y-2)*4, sf);
768 static void levelDrawName (SDL_Surface *frame) {
769 drawString(frame, levelname, lnamex, 0, 0x76);
773 static void levelDrawNumber (SDL_Surface *frame) {
774 char buf[8];
776 sprintf(buf, "%d", curLevel+1);
777 drawString(frame, buf, 320-strlen(buf)*8, 0, 1);
781 static void levelDrawCode (SDL_Surface *frame) {
782 char buf[8];
784 sprintf(buf, "%d", curLevel+1);
785 drawString(frame, levelcode, 320-strlen(levelcode)*8-strlen(buf)*8, 0, 3);
789 static void levelDrawItemName (SDL_Surface *frame) {
790 drawString(frame, itemname, 0, 0, 1);
794 static void levelDrawMisc (SDL_Surface *frame) {
795 if (demorecmode < 0) {
796 if (SDL_GetTicks()%1000 < 500) drawChar(frame, 'R', 0, 8, 3);
797 } else if (demorecmode > 0) {
798 if (SDL_GetTicks()%1000 < 500) drawChar(frame, 'D', 0, 8, 3);
803 static void drawSpriteBank (SDL_Surface *frame, SpriteBank *bank) {
804 SDL_Rect dst;
805 int x = 0, y = 0, maxh = 0;
807 SDL_SetClipRect(frame, NULL);
808 dst.x = 0;
809 dst.y = 0;
810 dst.w = frame->w;
811 dst.h = frame->h;
812 SDL_FillRect(frame, &dst, palette[3]);
814 for (int num = 0; num < bank->count; ++num) {
815 SDL_Surface *s = bank->spr[num][0];
817 if (s != NULL) {
818 char buf[16];
819 int w = s->w/2;
821 sprintf(buf, "%d", num);
822 if (w < strlen(buf)*8+2) w = strlen(buf)*8+2;
823 if (x+w > 320) {
824 x = 0;
825 y += maxh;
826 maxh = 0;
828 if (maxh < s->h/2+1) maxh = s->h/2+1;
829 blitSurface2x(frame, x, y, s);
830 drawString(frame, buf, x, y, 1);
831 x += w+1;
837 static void frmGameDraw (SDL_Surface *frame) {
838 SDL_Rect rc;
840 if (vmPaused && doSave) {
841 if (doSave < 0) {
842 if (loadGame() != 0) fatal("can't load game, VM is inconsistent, dying.");
843 redrawLevel = 1;
844 } else {
845 saveGame();
847 doSave = 0;
848 vmPaused = inMinimap;
851 SDL_SetClipRect(frame, NULL);
853 if (curLevel >= 0) {
854 if (redrawLevel) {
855 levelDrawMap(backbuf);
856 levelDrawName(backbuf);
857 levelDrawNumber(backbuf);
858 levelDrawCode(backbuf);
859 levelDrawItemName(backbuf);
861 blitSurface(frame, 0, 0, backbuf);
862 levelDrawMisc(frame);
864 rc.x = VIS_X*2;
865 rc.y = VIS_Y*2;
866 rc.w = VIS_WIDTH*20*2;
867 rc.h = VIS_HEIGHT*10*2;
868 SDL_SetClipRect(frame, &rc);
869 levelDrawSprites(frame);
870 SDL_SetClipRect(frame, NULL);
871 } else {
872 rc.x = 0;
873 rc.y = 0;
874 rc.w = frame->w;
875 rc.h = frame->h;
876 SDL_FillRect(frame, &rc, palette[0]);
879 #if 1
880 static angle = 0;
882 if (!fkeys[9]) {
883 angle = (angle+1)%360;
884 //fprintf(stderr, "a=%d\n", angle);
886 polymodStart(320/2, 200/2, 1*POLYFIX_BASE, angle);
888 #if 0
889 polymodAddPoint(-20, -20);
890 polymodAddPoint(20, -20);
891 polymodAddPoint(20, 20);
892 polymodAddPoint(-20, 20);
893 #endif
894 #if 0
895 polymodAddPoint(-10, -10);
896 polymodAddPoint(20, -10);
897 polymodAddPoint(-10, 20);
898 polymodAddPoint(20, 20);
899 #endif
900 #if 1
901 polymodAddPoint(36, 0);
902 polymodAddPoint(46, 12);
903 polymodAddPoint(31, 17);
904 polymodAddPoint(33, 33);
905 polymodAddPoint(18, 31);
906 polymodAddPoint(12, 46);
907 polymodAddPoint(0, 36);
908 polymodAddPoint(-12, 46);
909 polymodAddPoint(-17, 31);
910 polymodAddPoint(-33, 33);
911 polymodAddPoint(-31, 17);
912 polymodAddPoint(-46, 12);
913 polymodAddPoint(-36, 0);
914 polymodAddPoint(-46, -12);
915 polymodAddPoint(-31, -18);
916 polymodAddPoint(-33, -33);
917 polymodAddPoint(-18, -31);
918 polymodAddPoint(-12, -46);
919 polymodAddPoint(0, -36);
920 polymodAddPoint(12, -46);
921 polymodAddPoint(18, -31);
922 polymodAddPoint(33, -33);
923 polymodAddPoint(31, -18);
924 polymodAddPoint(46, -12);
925 #endif
927 polymodEnd();
928 polymodFill(frame, 3, 50);
929 #endif
931 if (goobers) {
932 for (int f = 84; f <= 90; ++f) if (fkeys[f-83]) drawSpriteBank(frame, &banks[f]);
937 ////////////////////////////////////////////////////////////////////////////////
938 #define ROOM_SCRIPTS_MARK " room script labels starts here "
941 static void loadMapScript (ResFile *resfile) {
942 VMLabelInfo *l;
943 int csz;
945 l = vmLabelAddMark(ROOM_SCRIPTS_MARK);
946 l->value = vmCodeSize;
947 if ((csz = loadCodeFile(resfile, vmCodeSize, 94+curLevel)) > 1) {
948 vmCodeSize += csz;
953 static void unloadMapScript (void) {
954 VMLabelInfo *l, *ucl;
956 while ((l = vmFindMark(ROOM_SCRIPTS_MARK)) != NULL) {
957 ucl = vmFindLabel("entry_local_room_script_onunload");
958 if (ucl != NULL && ucl->type == LB_CODE) vmExecuteBSR(0, ucl->value, 0);
959 vmCodeSize = l->value;
960 vmFreeLabelsUntilMark(ROOM_SCRIPTS_MARK);
963 ucl = vmFindLabel("entry_room_onunload");
964 if (ucl != NULL && ucl->type == LB_CODE) vmExecuteBSR(0, ucl->value, 0);
968 ////////////////////////////////////////////////////////////////////////////////
969 static int loadLevelInternal (ResFile *resfile, int lidx) {
970 message[0] = 0;
971 unloadMapScript();
973 vmGVars[GVAR_VIS_WIDTH] = VIS_WIDTH;
974 vmGVars[GVAR_VIS_HEIGHT] = VIS_HEIGHT;
975 vmGVars[GVAR_ITEM_NAME_OFS] = 0;
976 vmGVars[GVAR_ITEM_NAME_LEN] = 0;
977 levelname[0] = levelcode[0] = itemname[0] = 0;
979 if (levelData != NULL) free(levelData); levelData = NULL; levelDataSize = 0;
980 if (bmap != NULL) free(bmap); bmap = NULL;
981 if (fmap != NULL) free(fmap); fmap = NULL;
982 if (xflags != NULL) free(xflags); xflags = NULL;
984 curLevel = -1;
985 if (lidx < 0 || lidx > 73) return -1;
986 if ((levelData = loadResFile(resfile, lidx+9, &levelDataSize)) == NULL) return -1;
987 curLevel = lidx;
988 loadMapScript(resfile);
989 return levelDataSize;
993 ////////////////////////////////////////////////////////////////////////////////
994 static void activateMinimap (void) {
995 inMinimap = 1;
996 vmPaused = 1;
997 doSave = 0;
998 redrawLevel = 1;
1002 ////////////////////////////////////////////////////////////////////////////////
1003 static void getVMString (char *dest, int destsize, int argc, int argv[]) {
1004 if (destsize > 1) {
1005 int pos = 0, len = destsize-1, lp = 0;
1007 switch (argc) {
1008 case 1: fatal("out of args in FRST_SET_LEVEL_NAME");
1009 case 2: pos = argv[1]; break;
1010 case 3: pos = argv[1]; len = argv[2]; break;
1012 memset(dest, 0, destsize);
1013 if (len < 0) len = destsize-1;
1014 if (len > destsize-1) len = destsize-1;
1015 if (pos >= 0) {
1016 while (len > 0 && pos < vmCodeSize && vmCode[pos]) {
1017 dest[lp++] = vmCode[pos++];
1018 --len;
1020 } else {
1021 pos = 0-(pos+1);
1022 while (len > 0 && pos < levelDataSize && levelData[pos]) {
1023 dest[lp++] = levelData[pos++];
1024 --len;
1027 } else if (destsize == 1) {
1028 dest[0] = 0;
1033 static int gameRST (int tid, int opcode, int argc, int argv[], int *argp[]) {
1034 if (argv[0] == CONST_FRST_MINIMAP) {
1035 activateMinimap();
1036 } else if (argv[0] == CONST_FRST_OPEN_LEVEL_FILE) {
1037 // levelnum
1038 //if (vmLoadArgs(tid, 2, argv, argp, argc, argv, argp) != 0) fatal("out of args");
1039 if (argc < 2) fatal("out of args in FRST_LOAD_LEVEL");
1040 vmGVars[GVAR_RST_RESULT] = loadLevelInternal(&resfile, argv[1]);
1041 //if (goobers) fprintf(stderr, "FRST_OPEN_LEVEL_FILE(%d): %d\n", argv[1], vmGVars[GVAR_RST_RESULT]);
1042 } else if (argv[0] == CONST_FRST_GET_LEVEL_DATA_SIZE) {
1043 vmGVars[GVAR_RST_RESULT] = levelDataSize;
1044 } else if (argv[0] == CONST_FRST_GET_LEVEL_LOADER) {
1045 VMLabelInfo *ucl = vmFindLabel("entry_local_room_loader");
1047 vmGVars[GVAR_RST_RESULT] = (ucl != NULL && ucl->type == LB_CODE) ? ucl->value : -1;
1048 } else if (argv[0] == CONST_FRST_GET_LEVEL_INITER) {
1049 VMLabelInfo *ucl = vmFindLabel("entry_local_room_onload");
1051 vmGVars[GVAR_RST_RESULT] = (ucl != NULL && ucl->type == LB_CODE) ? ucl->value : -1;
1052 } else if (argv[0] == CONST_FRST_GET_LEVEL_FILE_BYTE) {
1053 if (argc < 2) fatal("out of args in FRST_GET_LEVEL_FILE_BYTE");
1054 if (argv[1] < 0 || argv[1] >= levelDataSize) fatal("invalid offset in FRST_GET_LEVEL_FILE_BYTE: %d", argv[1]);
1055 vmGVars[GVAR_RST_RESULT] = levelData[argv[1]];
1056 } else if (argv[0] == CONST_FRST_GET_LEVEL_FILE_WORD) {
1057 if (argc < 2) fatal("out of args in FRST_GET_LEVEL_FILE_WORD");
1058 if (argv[1] < 0 || argv[1]+1 >= levelDataSize) fatal("invalid offset in FRST_GET_LEVEL_FILE_WORD: %d", argv[1]);
1059 vmGVars[GVAR_RST_RESULT] = levelData[argv[1]+1];
1060 vmGVars[GVAR_RST_RESULT] <<= 8;
1061 vmGVars[GVAR_RST_RESULT] |= levelData[argv[1]];
1062 if (vmGVars[GVAR_RST_RESULT] >= 32768) vmGVars[GVAR_RST_RESULT] -= 65536;
1063 } else if (argv[0] == CONST_FRST_SET_LEVEL_SIZE) {
1064 int w, h;
1066 if (argc != 3) fatal("out of args in FRST_SET_LEVEL_SIZE");
1067 w = argv[1];
1068 h = argv[2];
1069 if (w < 1 || w > 32700 || h < 1 || h > 32700) fatal("invalid dimensions in FRST_SET_LEVEL_SIZE: %dx%d", w, h);
1070 if (bmap != NULL) free(bmap); bmap = NULL;
1071 if (fmap != NULL) free(fmap); fmap = NULL;
1072 if (xflags != NULL) free(xflags); xflags = NULL;
1073 fmap = calloc(w*h, 1); if (fmap == NULL) fatal("out of memory in FRST_SET_LEVEL_SIZE");
1074 bmap = calloc(w*h, 1); if (bmap == NULL) fatal("out of memory in FRST_SET_LEVEL_SIZE");
1075 xflags = calloc(w, 1); if (xflags == NULL) fatal("out of memory in FRST_SET_LEVEL_SIZE");
1076 mapWidth = vmGVars[GVAR_MAP_WIDTH] = w;
1077 mapHeight = vmGVars[GVAR_MAP_HEIGHT] = h;
1078 oldScrX = 0;
1079 oldScrY = 0;
1080 redrawLevel = 1;
1081 } else if (argv[0] == CONST_FRST_SET_LEVEL_NAME) {
1082 char buf[32];
1084 getVMString(levelname, sizeof(levelname), argc, argv);
1085 lnamex = (320-strlen(levelname)*8)/2;
1086 sprintf(buf, "%d", curLevel+1);
1087 while (lnamex+strlen(levelname)*8+strlen(buf)*8+6*8 > 320) lnamex -= 8;
1088 redrawLevel = 1;
1089 } else if (argv[0] == CONST_FRST_SET_LEVEL_CODE) {
1090 getVMString(levelcode, sizeof(levelcode), argc, argv);
1091 redrawLevel = 1;
1092 } else if (argv[0] == CONST_FRST_SET_ITEM_NAME) {
1093 getVMString(itemname, sizeof(itemname), argc, argv);
1094 redrawLevel = 1;
1095 } else {
1096 if (gameRSTCB) return gameRSTCB(tid, opcode, argc, argv, argp);
1097 fatal("invalid RST: %d", argv[0]);
1099 return 0; // continue
1103 ////////////////////////////////////////////////////////////////////////////////
1104 void setMainLoopGame (void) {
1105 frameCB = frmGameDraw;
1106 keyCB = frmGameKey;
1107 gameRSTCB = gameRST;
1108 beforeVMCB = demoCB;
1109 vmMapGetCB = mapGet;
1110 vmMapSetCB = mapSet;
1112 setSeed(time(NULL));
1113 vmPaused = 0;
1114 inMinimap = 0;
1115 doSave = 0;
1116 redrawLevel = 1;
1117 levelname[0] = levelcode[0] = itemname[0] = 0;
1118 //curLevel = -1;
1119 //demorecmode = 0;
1120 message[0] = 0;
1121 memset(fkeys, 0, sizeof(fkeys));
1122 memset(gamekeys, 0, sizeof(gamekeys));