added vector font
[awish.git] / src / game.c
blobe072480c85926b2884960bf9b82298e58968bad4
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 typedef struct {
49 int x, y;
50 int bank;
51 int num;
52 int dir;
53 int inlevel;
54 } SpriteInfo;
57 typedef struct {
58 int count;
59 int size; // # of slots
60 SpriteInfo *list;
61 } SpriteLayer;
64 #define MAX_LAYER (63)
65 static SpriteLayer spLayers[MAX_LAYER];
66 static int spLayersInitialized = 0;
69 static void clearSpriteLayers (void) {
70 if (!spLayersInitialized) {
71 for (int f = 0; f <= MAX_LAYER; ++f) {
72 spLayers[f].size = 0;
73 spLayers[f].list = NULL;
75 spLayersInitialized = 1;
77 for (int f = 0; f <= MAX_LAYER; ++f) spLayers[f].count = 0;
81 static void addSpriteToLayer (int x, int y, int layer, int bank, int num, int dir, int inlevel) {
82 //fprintf(stderr, "*x=%d, y=%d, layer=%d, bank=%d, num=%d, dir=%d, inlevel=%d\n", x, y, layer, bank, num, dir, inlevel);
83 if (layer >= 0 && layer <= MAX_LAYER &&
84 bank >= 0 && bank <= 256 &&
85 num >= 0 && num < 256) {
86 if (spLayers[layer].count+1 >= spLayers[layer].size) {
87 int newsz = spLayers[layer].size+64;
88 SpriteInfo *n = realloc(spLayers[layer].list, newsz);
90 if (n == NULL) fatal("out of memory");
91 spLayers[layer].list = n;
93 spLayers[layer].list[spLayers[layer].count].x = x;
94 spLayers[layer].list[spLayers[layer].count].y = y;
95 spLayers[layer].list[spLayers[layer].count].bank = bank;
96 spLayers[layer].list[spLayers[layer].count].num = num;
97 spLayers[layer].list[spLayers[layer].count].dir = dir;
98 spLayers[layer].list[spLayers[layer].count].inlevel = inlevel;
99 ++(spLayers[layer].count);
104 ////////////////////////////////////////////////////////////////////////////////
105 static int redrawLevel;
106 static int oldScrX, oldScrY;
107 static int mapWidth;
108 static int mapHeight;
109 static int curLevel;
110 static char levelname[257];
111 static char levelcode[257];
112 static char itemname[257];
113 static int lnamex;
114 static Uint8 *levelData = NULL;
115 static int levelDataSize = 0;
116 static Uint8 *bmap = NULL, *fmap = NULL;
117 static Uint8 *xflags = NULL;
118 static int inMinimap;
120 static int doSave = 0;
122 static int demorecmode = 0; // 0: none; 1: recording; -1: playing
123 static int demoSize = 0;
124 static int demoPos = 0;
125 static Uint8 *demoData = NULL;
126 static Uint8 demoPrevKeyState = 0;
127 static int demoKeyStateRepeats = 0;
129 static char message[256];
130 //static Uint32 msgEndTime = 0;
132 static Uint32 demo_m_w = 0;
133 static Uint32 demo_m_z = 0;
136 ////////////////////////////////////////////////////////////////////////////////
137 static int gamekeys[12];
138 static int fkeys[10];
141 static void setGameKeysGVars (void) {
142 vmGVars[GVAR_KEY_LEFT] = gamekeys[0] ? 1 : 0;
143 vmGVars[GVAR_KEY_RIGHT] = gamekeys[1] ? 1 : 0;
144 vmGVars[GVAR_KEY_UP] = gamekeys[2] ? 1 : 0;
145 vmGVars[GVAR_KEY_DOWN] = gamekeys[3] ? 1 : 0;
146 vmGVars[GVAR_KEY_TAKE] = gamekeys[4] ? 1 : 0;
147 vmGVars[GVAR_KEY_USE] = gamekeys[5] ? 1 : 0;
149 vmGVars[GVAR_KEY_MINIMAP] = gamekeys[6] ? 1 : 0;
150 vmGVars[GVAR_KEY_RESTART] = gamekeys[7] ? 1 : 0;
152 vmGVars[GVAR_KEY_FALL_CHEAT] = gamekeys[8] ? 1 : 0;
153 vmGVars[GVAR_KEY_WALK_CHEAT] = gamekeys[9] ? 1 : 0;
154 vmGVars[GVAR_KEY_PLEV_CHEAT] = gamekeys[10] ? 1 : 0;
155 vmGVars[GVAR_KEY_NLEV_CHEAT] = gamekeys[11] ? 1 : 0;
159 ////////////////////////////////////////////////////////////////////////////////
160 #define SECRET (42)
161 //#define SECRET (0)
164 static int readBuf (FILE *fl, void *buf, int len) {
165 unsigned char *c = (unsigned char *)buf;
167 while (len-- > 0) {
168 unsigned char b;
170 if (fread(&b, 1, 1, fl) != 1) return -1;
171 b ^= SECRET;
172 *c++ = b;
174 return 0;
178 static int writeBuf (FILE *fl, const void *buf, int len) {
179 const unsigned char *c = (const unsigned char *)buf;
181 while (len-- > 0) {
182 unsigned char b = *c++;
184 b ^= SECRET;
185 if (fwrite(&b, 1, 1, fl) != 1) return -1;
187 return 0;
191 static int readDW (FILE *fl, int *v) {
192 int t[4];
194 for (int f = 0; f < 4; ++f) {
195 unsigned char b;
197 if (fread(&b, 1, 1, fl) != 1) return -1;
198 t[f] = b^SECRET;
201 if (v) {
202 *v = 0;
203 for (int f = 0; f < 4; ++f) *v |= t[f]<<(8*f);
205 return 0;
209 static int writeDW (FILE *fl, int v) {
210 for (int f = 0; f < 4; ++f) {
211 unsigned char b;
213 b = v&0xff;
214 b ^= SECRET;
215 if (fwrite(&b, 1, 1, fl) != 1) return -1;
216 v >>= 8;
218 return 0;
222 static int readUDW (FILE *fl, Uint32 *v) {
223 int t[4];
225 for (int f = 0; f < 4; ++f) {
226 unsigned char b;
228 if (fread(&b, 1, 1, fl) != 1) return -1;
229 t[f] = b^SECRET;
232 if (v) {
233 *v = 0;
234 for (int f = 0; f < 4; ++f) *v |= t[f]<<(8*f);
236 return 0;
240 static int writeUDW (FILE *fl, Uint32 v) {
241 for (int f = 0; f < 4; ++f) {
242 unsigned char b;
244 b = v&0xff;
245 b ^= SECRET;
246 if (fwrite(&b, 1, 1, fl) != 1) return -1;
247 v >>= 8;
249 return 0;
253 ////////////////////////////////////////////////////////////////////////////////
254 static const char *SAVE_GAME_SIGNATURE = "ASG1";
257 static int saveGame (void) {
258 FILE *fl = fopen("awish.sav", "wb");
260 if (fl != NULL) {
261 demo_m_w = getSeedL();
262 demo_m_z = getSeedH();
263 if (fwrite(SAVE_GAME_SIGNATURE, 4, 1, fl) != 1) goto error;
264 if (vmSaveState(fl) != 0) goto error;
265 if (writeDW(fl, mapWidth) != 0) goto error;
266 if (writeDW(fl, mapHeight) != 0) goto error;
267 if (writeUDW(fl, demo_m_w) != 0) goto error;
268 if (writeUDW(fl, demo_m_z) != 0) goto error;
269 if (writeDW(fl, inMinimap) != 0) goto error;
270 if (writeDW(fl, curLevel) != 0) goto error;
271 if (writeBuf(fl, levelname, sizeof(levelname)) != 0) goto error;
272 if (writeDW(fl, lnamex) != 0) goto error;
273 if (writeBuf(fl, levelcode, sizeof(levelcode)) != 0) goto error;
274 if (writeBuf(fl, itemname, sizeof(itemname)) != 0) goto error;
275 if (writeBuf(fl, bmap, mapWidth*mapHeight) != 0) goto error;
276 if (writeBuf(fl, fmap, mapWidth*mapHeight) != 0) goto error;
277 if (writeBuf(fl, xflags, mapWidth) != 0) goto error;
278 fclose(fl);
279 return 0;
281 error:
282 fclose(fl);
283 unlink("awish.sav");
284 if (goobers) fprintf(stderr, "error saving game\n");
285 return -1;
289 static int loadGame (void) {
290 FILE *fl = fopen("awish.sav", "rb");
292 if (fl != NULL) {
293 char sign[4];
295 if (fread(sign, 4, 1, fl) != 1) goto error;
296 if (memcmp(sign, SAVE_GAME_SIGNATURE, 4) != 0) goto error;
297 if (vmLoadState(fl) != 0) goto error;
298 if (readDW(fl, &mapWidth) != 0) goto error;
299 if (readDW(fl, &mapHeight) != 0) goto error;
300 if (readUDW(fl, &demo_m_w) != 0) goto error;
301 if (readUDW(fl, &demo_m_z) != 0) goto error;
302 if (readDW(fl, &inMinimap) != 0) goto error;
303 if (readDW(fl, &curLevel) != 0) goto error;
304 if (readBuf(fl, levelname, sizeof(levelname)) != 0) goto error;
305 if (readDW(fl, &lnamex) != 0) goto error;
306 if (readBuf(fl, levelcode, sizeof(levelcode)) != 0) goto error;
307 if (readBuf(fl, itemname, sizeof(itemname)) != 0) goto error;
308 if (bmap != NULL) free(bmap); bmap = NULL;
309 if (fmap != NULL) free(fmap); fmap = NULL;
310 if (xflags != NULL) free(xflags); xflags = NULL;
311 fmap = calloc(mapWidth*mapHeight, 1); if (fmap == NULL) fatal("out of memory in loadGame");
312 bmap = calloc(mapWidth*mapHeight, 1); if (bmap == NULL) fatal("out of memory in loadGame");
313 xflags = calloc(mapWidth, 1); if (xflags == NULL) fatal("out of memory in loadGame");
314 if (readBuf(fl, bmap, mapWidth*mapHeight) != 0) goto error;
315 if (readBuf(fl, fmap, mapWidth*mapHeight) != 0) goto error;
316 if (readBuf(fl, xflags, mapWidth) != 0) goto error;
317 fclose(fl);
318 setSeedL(demo_m_w);
319 setSeedL(demo_m_z);
320 redrawLevel = 1;
321 oldScrX = oldScrY = -1;
322 return 0;
324 error:
325 fclose(fl);
326 if (goobers) fprintf(stderr, "error loading saved game\n");
327 return -1;
331 ////////////////////////////////////////////////////////////////////////////////
332 static void demoClear (void) {
333 //demorecmode = 0;
334 demoSize = 0;
335 demoPos = 0;
336 demoPrevKeyState = 0;
337 demoKeyStateRepeats = 0;
338 if (demoData != NULL) free(demoData);
339 demoData = NULL;
343 static void demoAddByte (Uint8 b) {
344 if (demoPos+1 > demoSize && demoSize > 1024*1024*16) fatal("out of memory in demo recording!");
345 if (demoPos+1 > demoSize) {
346 int newsz = demoSize+1024*32;
347 Uint8 *nn = realloc(demoData, newsz);
349 if (!nn) fatal("out of memory in demo recording!");
350 demoData = nn;
351 demoSize = newsz;
353 demoData[demoPos++] = b;
357 static Uint8 demoGetKeyState (void) {
358 return
359 ((gamekeys[0]?1:0)<<0) |
360 ((gamekeys[1]?1:0)<<1) |
361 ((gamekeys[2]?1:0)<<2) |
362 ((gamekeys[3]?1:0)<<3) |
363 ((gamekeys[4]?1:0)<<4) |
364 ((gamekeys[5]?1:0)<<5);
368 static void demoSetKeyState (Uint8 kstate) {
369 gamekeys[0] = (kstate&(1<<0)) != 0;
370 gamekeys[1] = (kstate&(1<<1)) != 0;
371 gamekeys[2] = (kstate&(1<<2)) != 0;
372 gamekeys[3] = (kstate&(1<<3)) != 0;
373 gamekeys[4] = (kstate&(1<<4)) != 0;
374 gamekeys[5] = (kstate&(1<<5)) != 0;
378 static void demoAddFrameData (void) {
379 Uint8 kstate = demoGetKeyState();
381 if (demoKeyStateRepeats == 256) {
382 demoAddByte(demoKeyStateRepeats-1);
383 demoAddByte(demoPrevKeyState);
384 demoKeyStateRepeats = 0;
387 if (kstate != demoPrevKeyState) {
388 if (demoKeyStateRepeats > 0) {
389 demoAddByte(demoKeyStateRepeats-1);
390 demoAddByte(demoPrevKeyState);
392 demoPrevKeyState = kstate;
393 demoKeyStateRepeats = 1;
394 } else {
395 ++demoKeyStateRepeats;
400 static void demoGetFrameData (void) {
401 while (demoKeyStateRepeats < 1) {
402 if (demoPos+2 > demoSize) {
403 demoClear();
404 demorecmode = 0;
405 if (goobers) fprintf(stderr, "demo complete\n");
406 strcpy(message, "demo stopped");
407 return;
409 demoKeyStateRepeats = demoData[demoPos++];
410 ++demoKeyStateRepeats;
411 demoPrevKeyState = demoData[demoPos++];
413 --demoKeyStateRepeats;
415 demoSetKeyState(demoPrevKeyState);
419 static int demoSave (void) {
420 FILE *fl;
421 char buf[128];
422 char sign[5];
424 if (demoKeyStateRepeats > 0) {
425 demoAddByte(demoKeyStateRepeats-1);
426 demoAddByte(demoPrevKeyState);
429 sprintf(buf, "awish%02d.dmo", curLevel+1);
430 fl = fopen(buf, "wb");
431 if (fl == NULL) {
432 if (goobers) fprintf(stderr, "can't create demo file '%s'\n", buf);
433 return -1;
435 strcpy(sign, "AWD1");
436 if (fwrite(sign, 4, 1, fl) != 1) goto error;
437 if (writeDW(fl, curLevel) != 0) goto error;
438 if (writeUDW(fl, demo_m_w) != 0) goto error;
439 if (writeUDW(fl, demo_m_z) != 0) goto error;
440 if (writeDW(fl, demoPos) != 0) goto error;
441 if (writeBuf(fl, demoData, demoPos) != 0) goto error;
442 fclose(fl);
443 if (goobers) fprintf(stderr, "demo saved to file '%s'\n", buf);
444 return 0;
445 error:
446 fclose(fl);
447 unlink(buf);
448 if (goobers) fprintf(stderr, "can't write demo file '%s'\n", buf);
449 return -1;
453 static int demoLoad (void) {
454 FILE *fl;
455 char buf[128];
456 int size, level;
457 char sign[4];
459 demoClear();
460 sprintf(buf, "awish%02d.dmo", curLevel+1);
461 fl = fopen(buf, "rb");
462 if (fl == NULL) {
463 if (goobers) fprintf(stderr, "can't open demo file '%s'\n", buf);
464 return -1;
467 if (fread(sign, 4, 1, fl) != 1) goto error;
468 if (memcmp(sign, "AWD1", 4) != 0) goto error;
469 if (readDW(fl, &level) != 0) goto error;
470 if (readUDW(fl, &demo_m_w) != 0) goto error;
471 if (readUDW(fl, &demo_m_z) != 0) goto error;
472 if (readDW(fl, &size) != 0) goto error;
473 if (size < 1 || size > 1024*1024*16) goto error;
474 demoData = malloc(size);
475 if (demoData == NULL) goto error;
476 if (readBuf(fl, demoData, size) != 0) goto error;
477 demoSize = size;
478 demoPos = 0;
479 fclose(fl);
480 setSeedL(demo_m_w);
481 setSeedL(demo_m_z);
482 if (goobers) fprintf(stderr, "loaded demo file '%s'\n", buf);
484 return 0;
485 error:
486 fclose(fl);
487 if (goobers) fprintf(stderr, "can't load demo file '%s'\n", buf);
488 demoClear();
489 return -1;
493 static inline int isGameStopped (void) {
494 return
495 vmGVars[GVAR_GAME_STATE] == CONST_GAME_STATE_DEAD ||
496 vmGVars[GVAR_GAME_STATE] == CONST_GAME_STATE_COMPLETE;
500 static void demoCB (void) {
501 //if (vmGVars[GVAR_GAME_STATE] == CONST_GAME_STATE_STARTED) unloadMapScript();
503 if (vmGVars[GVAR_SCR_X] != oldScrX || vmGVars[GVAR_SCR_Y] != oldScrY) {
504 oldScrX = vmGVars[GVAR_SCR_X];
505 oldScrY = vmGVars[GVAR_SCR_Y];
506 redrawLevel = 1;
509 switch (demorecmode) {
510 case -666: // prepare to load demo
511 if (demoLoad() != 0) {
512 demorecmode = 0;
513 break;
515 demorecmode = -2;
516 // fallthru
517 case 666: // prepare to save demo
518 vmSetPC(0, CODE_ENTRY_GAME_RESTART_LEVEL);
519 vmGVars[GVAR_CUR_LEVEL] = curLevel;
520 vmGVars[GVAR_GAME_STATE] = -1; // invalid state
521 if (demorecmode > 0) {
522 demoClear();
523 demorecmode = 2;
525 break;
526 case -1: // demo replaying
527 case 1: // demo saving
528 if (isGameStopped()) {
529 // the level is over or prof is dead
530 if (demorecmode > 0) demoSave();
531 demoClear();
532 demorecmode = 0;
533 } else {
534 ((demorecmode < 0) ? demoGetFrameData : demoAddFrameData)();
536 break;
537 case -2: // waiting for 'game started' trigger
538 case 2: // waiting for 'game started' trigger
539 if (vmGVars[GVAR_GAME_STATE] >= 0) {
540 if (goobers) fprintf(stderr, "demo %s started...\n", demorecmode<0?"replaying":"recording");
541 if (demorecmode < 0) {
542 // replay
543 setSeedL(demo_m_w);
544 setSeedL(demo_m_z);
545 } else {
546 // record
547 demo_m_w = getSeedL();
548 demo_m_z = getSeedH();
550 demorecmode = (demorecmode < 0) ? -1 : 1;
552 break;
554 setGameKeysGVars();
558 ////////////////////////////////////////////////////////////////////////////////
559 static void frmGameKey (SDL_KeyboardEvent *key) {
560 if (key->type == SDL_KEYDOWN) {
561 switch (key->keysym.sym) {
562 case SDLK_ESCAPE:
563 case SDLK_SPACE:
564 case SDLK_RETURN:
565 if (vmPaused && inMinimap) {
566 inMinimap = 0;
567 doSave = 0;
568 vmPaused = 0;
569 redrawLevel = 1;
570 gamekeys[6] = 0;
572 break;
573 case SDLK_F12:
574 vmGVars[GVAR_KEY_QUIT] = 1;
575 break;
576 case SDLK_p:
577 if (vmPaused == 0) {
578 gamekeys[6] = 1;
579 } else {
580 if (inMinimap) {
581 inMinimap = 0;
582 doSave = 0;
583 vmPaused = 0;
584 redrawLevel = 1;
585 gamekeys[6] = 1;
588 break;
589 case SDLK_r:
590 if (vmPaused == 0) {
591 if (demorecmode != 0) { demoClear(); demorecmode = 0; }
592 if ((key->keysym.mod&(KMOD_CTRL)) != 0) {
593 gamekeys[7] = 1;
596 break;
597 case SDLK_s:
598 if (vmPaused == 0 && !demorecmode) {
599 if (goobers && (key->keysym.mod&(KMOD_CTRL)) != 0) { doSave = 1; vmPaused = 1; }
601 break;
602 case SDLK_l:
603 if (vmPaused == 0 && !demorecmode) {
604 if (goobers && (key->keysym.mod&(KMOD_CTRL)) != 0) { doSave = -1; vmPaused = 1; }
606 break;
607 case SDLK_d:
608 if (vmPaused == 0) {
609 if (goobers && (key->keysym.mod&(KMOD_CTRL)) != 0) {
610 if (!demorecmode) {
611 demorecmode = 666; // 'start saving'
612 } else {
613 demoSave();
614 demoClear();
615 demorecmode = 0;
619 break;
620 case SDLK_m:
621 if (vmPaused == 0) {
622 if (goobers && (key->keysym.mod&(KMOD_CTRL)) != 0) {
623 if (!demorecmode) {
624 demorecmode = -666; // 'start playing'
625 } else {
626 demoClear();
627 demorecmode = 0;
628 demoSetKeyState(0);
632 break;
633 default: ;
637 if (demorecmode == 0 || demorecmode == 1) {
638 switch (key->keysym.sym) {
639 case SDLK_LEFT: case SDLK_KP4: gamekeys[0] = (key->type == SDL_KEYDOWN); break;
640 case SDLK_RIGHT: case SDLK_KP6: gamekeys[1] = (key->type == SDL_KEYDOWN); break;
641 case SDLK_UP: case SDLK_KP8: gamekeys[2] = (key->type == SDL_KEYDOWN); break;
642 case SDLK_DOWN: case SDLK_KP2: gamekeys[3] = (key->type == SDL_KEYDOWN); break;
643 case SDLK_SPACE: case SDLK_KP0: gamekeys[4] = (key->type == SDL_KEYDOWN); break;
644 case SDLK_RETURN: case SDLK_KP_PERIOD: gamekeys[5] = (key->type == SDL_KEYDOWN); break;
645 default: ;
648 if (goobers && !demorecmode) {
649 switch (key->keysym.sym) {
650 case SDLK_f: gamekeys[8] = (key->type == SDL_KEYDOWN); break;
651 case SDLK_w: gamekeys[9] = (key->type == SDL_KEYDOWN); break;
652 case SDLK_KP_MINUS: gamekeys[10] = (key->type == SDL_KEYDOWN); break;
653 case SDLK_KP_PLUS: gamekeys[11] = (key->type == SDL_KEYDOWN); break;
655 case SDLK_F1: fkeys[1] = (key->type == SDL_KEYDOWN); break;
656 case SDLK_F2: fkeys[2] = (key->type == SDL_KEYDOWN); break;
657 case SDLK_F3: fkeys[3] = (key->type == SDL_KEYDOWN); break;
658 case SDLK_F4: fkeys[4] = (key->type == SDL_KEYDOWN); break;
659 case SDLK_F5: fkeys[5] = (key->type == SDL_KEYDOWN); break;
660 case SDLK_F6: fkeys[6] = (key->type == SDL_KEYDOWN); break;
661 case SDLK_F7: fkeys[7] = (key->type == SDL_KEYDOWN); break;
662 case SDLK_F8: fkeys[8] = (key->type == SDL_KEYDOWN); break;
663 case SDLK_F9: fkeys[9] = (key->type == SDL_KEYDOWN); break;
664 default: ;
671 static void frmMouse (int x, int y, int buttons) {
672 vmGVars[GVAR_MOUSE_X] = x;
673 vmGVars[GVAR_MOUSE_Y] = y;
674 vmGVars[GVAR_MOUSE_BUTTONS] = buttons;
678 ////////////////////////////////////////////////////////////////////////////////
679 static inline Uint8 fgTile (int x, int y) {
680 return (x >= 0 && y >= 0 && x < mapWidth && y < mapHeight) ? fmap[y*mapWidth+x] : 0;
684 static inline Uint8 bgTile (int x, int y) {
685 if (y == -666) return (x >= 0 && x < mapWidth) ? xflags[x] : 0;
686 return (x >= 0 && y >= 0 && x < mapWidth && y < mapHeight) ? bmap[y*mapWidth+x] : 0;
690 static inline void setFGTile (int x, int y, Uint8 tile) {
691 if (x >= 0 && y >= 0 && x < mapWidth && y < mapHeight) {
692 if (fmap[y*mapWidth+x] != tile) {
693 redrawLevel = 1;
694 fmap[y*mapWidth+x] = tile;
700 static inline void setBGTile (int x, int y, Uint8 tile) {
701 if (y == -666 && x >= 0 && x < mapWidth) xflags[x] = tile;
702 if (x >= 0 && y >= 0 && x < mapWidth && y < mapHeight) {
703 if (bmap[y*mapWidth+x] != tile) {
704 redrawLevel = 1;
705 bmap[y*mapWidth+x] = tile;
711 static int mapGet (int tid, int fg, int x, int y) {
712 if (fmap != NULL) return fg ? fgTile(x, y) : bgTile(x, y);
713 return 0;
717 static void mapSet (int tid, int fg, int x, int y, int tile) {
718 if (fmap != NULL) {
719 if (fg) setFGTile(x, y, tile); else setBGTile(x, y, tile);
724 ////////////////////////////////////////////////////////////////////////////////
725 // cliprect should be set
726 static void levelDrawMap (SDL_Surface *frame) {
727 SDL_Rect rc;
729 rc.x = VIS_X*2;
730 rc.y = VIS_Y*2;
731 rc.w = VIS_WIDTH*20*2;
732 rc.h = VIS_HEIGHT*10*2;
734 if (!inMinimap) {
735 int levelback = vmGVars[GVAR_LEVEL_BACKPIC];
736 int scrX = vmGVars[GVAR_SCR_X], scrY = vmGVars[GVAR_SCR_Y];
738 if (levelback < 1 || levelback > 7) levelback = 1;
739 blitSurface(frame, 0, 0, backs[levelback]);
741 SDL_SetClipRect(frame, &rc);
742 for (int dy = 0; dy < VIS_HEIGHT; ++dy) {
743 for (int dx = 0; dx < VIS_WIDTH; ++dx) {
744 int x = scrX+dx, y = scrY+dy;
745 Uint8 b = bgTile(x, y), f = fgTile(x, y);
747 if (b) blitSurface2x(frame, VIS_X+dx*20, VIS_Y+dy*10, banks[CONST_BANK_BG_TILES].spr[b-1][0]);
748 if (f) blitSurface2x(frame, VIS_X+dx*20, VIS_Y+dy*10, banks[CONST_BANK_FG_TILES].spr[f-1][0]);
751 } else {
752 blitSurface(frame, 0, 0, backs[1]);
753 SDL_SetClipRect(frame, &rc);
754 for (int dy = 0; dy < mapHeight; ++dy) {
755 for (int dx = 1; dx < mapWidth; ++dx) {
756 Uint8 b = bgTile(dx, dy), f = fgTile(dx, dy), t = 8;
758 if (f == 0) {
759 if (b >= 1 && b <= 8) t = b-1; else t = 8;
760 } else {
761 t = f+8;
763 if (banks[CONST_BANK_MAP_TILES].spr[t][0]) {
764 blitSurface2x(frame, VIS_X+dx*6, VIS_Y+dy*4, banks[CONST_BANK_MAP_TILES].spr[t][0]);
765 } else {
766 blitSurface2x(frame, VIS_X+dx*6, VIS_Y+dy*4, banks[CONST_BANK_MAP_TILES].spr[0][0]);
771 SDL_SetClipRect(frame, NULL);
772 redrawLevel = 0;
776 static void levelDrawSprites (SDL_Surface *frame) {
777 if (!inMinimap) {
778 int scrX = vmGVars[GVAR_SCR_X], scrY = vmGVars[GVAR_SCR_Y];
779 int py = vmGetTVar(0, TVAR_POS_Y)-scrY;
781 for (int cc = 0; cc <= 2; ++cc) {
782 for (int f = cc==1?1:0; f <= vmLastThread(); ++f) {
783 if (vmIsThreadAlive(f) && !vmIsSuspendedThread(f)) {
784 int b = vmGetTVar(f, TVAR_SPR_BANK);
785 int s = vmGetTVar(f, TVAR_SPR_NUM);
786 int d = vmGetTVar(f, TVAR_SPR_DIR);
788 if (d >= 0 && d <= 1 && s >= 0 && b >= 0 && b <= 255 && s < banks[b].count && banks[b].spr[s][d]) {
789 SDL_Surface *sf = banks[b].spr[s][d];
790 int x = vmGetTVar(f, TVAR_POS_X)-scrX;
791 int y = vmGetTVar(f, TVAR_POS_Y)-scrY;
792 int tx = vmGetTVar(f, TVAR_POS_TX);
793 int ty = vmGetTVar(f, TVAR_POS_TY);
794 int si = vmGetTVar(f, TVAR_SPR_ITEM);
796 if (cc == 0 && b == CONST_BANK_ITEMS) continue;
797 if (cc == 1 && b != CONST_BANK_ITEMS) continue;
798 if (cc == 2) {
799 if (b != CONST_BANK_PROF) {
800 if (b != CONST_BANK_ITEMS) continue;
801 if (y < py) continue;
804 if (b == CONST_BANK_IM_PROF || b == CONST_BANK_PROF) tx -= 5;
805 blitSurface2x(frame, VIS_X+x*20+tx, VIS_Y+y*10+ty-sf->h/2, sf);
806 if (si > 0 && si < banks[CONST_BANK_ITEMS].count) {
807 sf = banks[CONST_BANK_ITEMS].spr[si][0];
808 blitSurface2x(frame, VIS_X+x*20+tx, VIS_Y+y*10+ty-sf->h/2-24, sf);
814 } else {
815 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]);
816 for (int f = 1; f < VM_MAX_THREADS; ++f) {
817 if (vmIsThreadAlive(f) && !vmIsSuspendedThread(f)) {
818 int i = vmGetTVar(f, TVAR_ITEM_ID);
819 if (i > 0 && i <= 255) {
820 SDL_Surface *sf = banks[CONST_BANK_MAP_ITEMS].spr[i][0];
821 int x = vmGetTVar(f, TVAR_POS_X);
822 int y = vmGetTVar(f, TVAR_POS_Y);
824 blitSurface2x(frame, VIS_X+(x+0)*6, VIS_Y+(y-2)*4, sf);
832 static void levelDrawSpriteLayers (SDL_Surface *frame) {
833 SDL_Rect rc;
835 rc.x = VIS_X*2;
836 rc.y = VIS_Y*2;
837 rc.w = VIS_WIDTH*20*2;
838 rc.h = VIS_HEIGHT*10*2;
839 SDL_SetClipRect(frame, &rc);
840 for (int f = MAX_LAYER; f >= 0; --f) {
841 SpriteInfo *list = spLayers[f].list;
843 if (list == NULL && spLayers[f].count != 0) {
844 fatal("WTF? f=%d; count=%d", f, spLayers[f].count);
846 for (int c = spLayers[f].count; c > 0; --c, ++list) {
847 if (list->inlevel &&
848 list->dir >= 0 && list->dir <= 1 &&
849 list->bank >= 0 && list->bank <= 256 &&
850 list->num >= 0 && list->num < banks[list->bank].count &&
851 banks[list->bank].spr[list->num][list->dir]) {
852 blitSurface2x(frame, VIS_X+list->x, VIS_Y+list->y, banks[list->bank].spr[list->num][list->dir]);
857 SDL_SetClipRect(frame, NULL);
858 for (int f = MAX_LAYER; f >= 0; --f) {
859 SpriteInfo *list = spLayers[f].list;
861 if (list == NULL) continue;
862 for (int c = spLayers[f].count; c > 0; --c, ++list) {
863 //fprintf(stderr, ":x=%d, y=%d, layer=%d, bank=%d, num=%d, dir=%d, inlevel=%d\n", list->x, list->y, f, list->bank, list->num, list->dir, list->inlevel);
864 if (!list->inlevel &&
865 list->dir >= 0 && list->dir <= 1 &&
866 list->bank >= 0 && list->bank <= 256 &&
867 list->num >= 0 && list->num < banks[list->bank].count &&
868 banks[list->bank].spr[list->num][list->dir]) {
869 blitSurface2x(frame, list->x, list->y, banks[list->bank].spr[list->num][list->dir]);
876 static void levelDrawName (SDL_Surface *frame) {
877 drawString(frame, levelname, lnamex, 0, 0x76);
881 static void levelDrawNumber (SDL_Surface *frame) {
882 char buf[8];
884 sprintf(buf, "%d", curLevel+1);
885 drawString(frame, buf, 320-strlen(buf)*8, 0, 1);
889 static void levelDrawCode (SDL_Surface *frame) {
890 char buf[8];
892 sprintf(buf, "%d", curLevel+1);
893 drawString(frame, levelcode, 320-strlen(levelcode)*8-strlen(buf)*8, 0, 3);
897 static void levelDrawItemName (SDL_Surface *frame) {
898 drawString(frame, itemname, 0, 0, 1);
902 static void levelDrawMisc (SDL_Surface *frame) {
903 if (demorecmode < 0) {
904 if (SDL_GetTicks()%1000 < 500) drawChar(frame, 'R', 0, 8, 3);
905 } else if (demorecmode > 0) {
906 if (SDL_GetTicks()%1000 < 500) drawChar(frame, 'D', 0, 8, 3);
911 static void drawSpriteBank (SDL_Surface *frame, SpriteBank *bank) {
912 SDL_Rect dst;
913 int x = 0, y = 0, maxh = 0;
915 SDL_SetClipRect(frame, NULL);
916 dst.x = 0;
917 dst.y = 0;
918 dst.w = frame->w;
919 dst.h = frame->h;
920 SDL_FillRect(frame, &dst, palette[3]);
922 for (int num = 0; num < bank->count; ++num) {
923 SDL_Surface *s = bank->spr[num][0];
925 if (s != NULL) {
926 char buf[16];
927 int w = s->w/2;
929 if (gamekeys[4] || gamekeys[5]) {
930 // take or use
931 sprintf(buf, "%d", num);
932 if (w < strlen(buf)*8+2) w = strlen(buf)*8+2;
934 if (x+w > 320) {
935 x = 0;
936 y += maxh;
937 maxh = 0;
939 if (maxh < s->h/2+1) maxh = s->h/2+1;
940 blitSurface2x(frame, x, y, s);
941 if (gamekeys[4] || gamekeys[5]) drawString(frame, buf, x, y, 1);
942 x += w+1;
948 static void drawPalette (SDL_Surface *frame) {
949 SDL_Rect dst;
951 SDL_SetClipRect(frame, NULL);
952 dst.x = 0;
953 dst.y = 0;
954 dst.w = frame->w;
955 dst.h = frame->h;
956 SDL_FillRect(frame, &dst, palette[0]);
958 for (int y = 0; y < 16; ++y) {
959 for (int x = 0; x < 16; ++x) {
960 dst.x = x*20;
961 dst.y = y*20;
962 dst.w = 18;
963 dst.h = 18;
964 SDL_FillRect(frame, &dst, palette[y*16+x]);
965 if (gamekeys[4] || gamekeys[5]) {
966 char buf[16];
968 sprintf(buf, "%d", y*16+x);
969 drawString(frame, buf, x*20, y*20, 1);
976 static void frmGameDraw (SDL_Surface *frame) {
977 SDL_Rect rc;
979 if (vmPaused && doSave) {
980 if (doSave < 0) {
981 if (loadGame() != 0) fatal("can't load game, VM is inconsistent, dying.");
982 redrawLevel = 1;
983 } else {
984 saveGame();
986 doSave = 0;
987 vmPaused = inMinimap;
990 SDL_SetClipRect(frame, NULL);
992 if (curLevel >= 0) {
993 if (redrawLevel) {
994 levelDrawMap(backbuf);
995 levelDrawName(backbuf);
996 levelDrawNumber(backbuf);
997 levelDrawCode(backbuf);
998 levelDrawItemName(backbuf);
1000 blitSurface(frame, 0, 0, backbuf);
1001 levelDrawMisc(frame);
1003 rc.x = VIS_X*2;
1004 rc.y = VIS_Y*2;
1005 rc.w = VIS_WIDTH*20*2;
1006 rc.h = VIS_HEIGHT*10*2;
1007 SDL_SetClipRect(frame, &rc);
1008 levelDrawSprites(frame);
1009 levelDrawSpriteLayers(frame);
1010 SDL_SetClipRect(frame, NULL);
1011 } else {
1012 rc.x = 0;
1013 rc.y = 0;
1014 rc.w = frame->w;
1015 rc.h = frame->h;
1016 SDL_FillRect(frame, &rc, palette[0]);
1017 rc.x = VIS_X*2;
1018 rc.y = VIS_Y*2;
1019 rc.w = VIS_WIDTH*20*2;
1020 rc.h = VIS_HEIGHT*10*2;
1021 SDL_SetClipRect(frame, &rc);
1022 levelDrawSpriteLayers(frame);
1023 SDL_SetClipRect(frame, NULL);
1025 clearSpriteLayers();
1027 polymodStr(frame, "TEST", 50, 50, POLYFIX_BASE, 0, 1, 128);
1028 #if 1
1029 static int angle = 0;
1030 static int mult = 1;
1031 static int multdir = 1;
1033 if (!fkeys[9]) {
1034 angle = (angle+1)%360;
1035 mult += multdir;
1036 if (mult < 2 || mult > 50) multdir = -multdir;
1037 //fprintf(stderr, "a=%d\n", angle);
1038 } else {
1039 polyDump = fkeys[8];
1041 polymodStart(320/2, 200/2, (mult+20)*POLYFIX_BASE/50, angle);
1043 #if 0
1044 polymodAddPoint(-20, -20);
1045 polymodAddPoint(20, -20);
1046 polymodAddPoint(20, 20);
1047 polymodAddPoint(-20, 20);
1048 #endif
1049 #if 0
1050 polymodAddPoint(-10, -10);
1051 polymodAddPoint(20, -10);
1052 polymodAddPoint(-10, 20);
1053 polymodAddPoint(20, 20);
1054 #endif
1055 #if 1
1056 polymodAddPoint(36, 0);
1057 polymodAddPoint(46, 12);
1058 polymodAddPoint(31, 17);
1059 polymodAddPoint(33, 33);
1060 polymodAddPoint(18, 31);
1061 polymodAddPoint(12, 46);
1062 polymodAddPoint(0, 36);
1063 polymodAddPoint(-12, 46);
1064 polymodAddPoint(-17, 31);
1065 polymodAddPoint(-33, 33);
1066 polymodAddPoint(-31, 17);
1067 polymodAddPoint(-46, 12);
1068 polymodAddPoint(-36, 0);
1069 polymodAddPoint(-46, -12);
1070 polymodAddPoint(-31, -18);
1071 polymodAddPoint(-33, -33);
1072 polymodAddPoint(-18, -31);
1073 polymodAddPoint(-12, -46);
1074 polymodAddPoint(0, -36);
1075 polymodAddPoint(12, -46);
1076 polymodAddPoint(18, -31);
1077 polymodAddPoint(33, -33);
1078 polymodAddPoint(31, -18);
1079 polymodAddPoint(46, -12);
1080 #endif
1081 #if 0
1082 polymodAddPoint(42, 0);
1083 polymodAddPoint(40, 10);
1084 polymodAddPoint(36, 20);
1085 polymodAddPoint(29, 29);
1086 polymodAddPoint(21, 36);
1087 polymodAddPoint(10, 40);
1088 polymodAddPoint(0, 42);
1089 polymodAddPoint(-10, 40);
1090 polymodAddPoint(-20, 36);
1091 polymodAddPoint(-29, 29);
1092 polymodAddPoint(-36, 20);
1093 polymodAddPoint(-40, 10);
1094 polymodAddPoint(-42, 0);
1095 polymodAddPoint(-40, -10);
1096 polymodAddPoint(-36, -21);
1097 polymodAddPoint(-29, -29);
1098 polymodAddPoint(-21, -36);
1099 polymodAddPoint(-10, -40);
1100 polymodAddPoint(0, -42);
1101 polymodAddPoint(10, -40);
1102 polymodAddPoint(21, -36);
1103 polymodAddPoint(29, -29);
1104 polymodAddPoint(36, -21);
1105 polymodAddPoint(40, -10);
1106 #endif
1108 polymodEnd();
1109 polymodFill(frame, 3, 100);
1110 #endif
1112 if (goobers) {
1113 for (int f = 84; f <= 90; ++f) if (fkeys[f-83]) drawSpriteBank(frame, &banks[f]);
1114 if (fkeys[8]) drawPalette(frame);
1116 if (vmGVars[GVAR_MOUSE_HIDDEN] == 0) {
1117 int cur = vmGVars[GVAR_MOUSE_CURSOR];
1119 if (cur >= 0 && cur < banks[256].count) {
1120 blitSurface2x(frame, vmGVars[GVAR_MOUSE_X], vmGVars[GVAR_MOUSE_Y], banks[256].spr[cur][0]);
1126 ////////////////////////////////////////////////////////////////////////////////
1127 #define ROOM_SCRIPTS_MARK " room script labels starts here "
1130 static void loadMapScript (ResFile *resfile) {
1131 VMLabelInfo *l;
1132 int csz;
1134 l = vmLabelAddMark(ROOM_SCRIPTS_MARK);
1135 l->value = vmCodeSize;
1136 if ((csz = loadCodeFile(resfile, vmCodeSize, 94+curLevel, 1)) > 1) {
1137 vmCodeSize += csz;
1142 static void unloadMapScript (void) {
1143 VMLabelInfo *l, *ucl;
1145 while ((l = vmFindMark(ROOM_SCRIPTS_MARK)) != NULL) {
1146 ucl = vmFindLabel("entry_local_room_script_onunload");
1147 if (ucl != NULL && ucl->type == LB_CODE) vmExecuteBSR(0, ucl->value, 0);
1148 vmCodeSize = l->value;
1149 vmFreeLabelsUntilMark(ROOM_SCRIPTS_MARK);
1152 ucl = vmFindLabel("entry_goobers_room_onunload");
1153 if (ucl != NULL && ucl->type == LB_CODE) vmExecuteBSR(0, ucl->value, 0);
1155 ucl = vmFindLabel("entry_room_onunload");
1156 if (ucl != NULL && ucl->type == LB_CODE) vmExecuteBSR(0, ucl->value, 0);
1160 ////////////////////////////////////////////////////////////////////////////////
1161 static int loadLevelInternal (ResFile *resfile, int lidx) {
1162 message[0] = 0;
1163 unloadMapScript();
1165 vmGVars[GVAR_VIS_WIDTH] = VIS_WIDTH;
1166 vmGVars[GVAR_VIS_HEIGHT] = VIS_HEIGHT;
1167 levelname[0] = levelcode[0] = itemname[0] = 0;
1169 if (levelData != NULL) free(levelData); levelData = NULL; levelDataSize = 0;
1170 if (bmap != NULL) free(bmap); bmap = NULL;
1171 if (fmap != NULL) free(fmap); fmap = NULL;
1172 if (xflags != NULL) free(xflags); xflags = NULL;
1174 curLevel = -1;
1175 if (lidx < 0 || lidx > 73) return -1;
1176 if ((levelData = loadResFile(resfile, lidx+9, &levelDataSize)) == NULL) return -1;
1177 curLevel = lidx;
1178 loadMapScript(resfile);
1179 return levelDataSize;
1183 ////////////////////////////////////////////////////////////////////////////////
1184 static void activateMinimap (void) {
1185 inMinimap = 1;
1186 vmPaused = 1;
1187 doSave = 0;
1188 redrawLevel = 1;
1192 ////////////////////////////////////////////////////////////////////////////////
1193 static void getVMString (char *dest, int destsize, int argc, int argv[]) {
1194 if (destsize > 1) {
1195 int pos = 0, len = destsize-1, lp = 0;
1197 switch (argc) {
1198 case 1: fatal("out of args in FRST_SET_LEVEL_NAME");
1199 case 2: pos = argv[1]; break;
1200 case 3: pos = argv[1]; len = argv[2]; break;
1202 memset(dest, 0, destsize);
1203 if (len < 0) len = destsize-1;
1204 if (len > destsize-1) len = destsize-1;
1205 if (pos >= 0) {
1206 while (len > 0 && pos < vmCodeSize && vmCode[pos]) {
1207 dest[lp++] = vmCode[pos++];
1208 --len;
1210 } else {
1211 pos = 0-(pos+1);
1212 while (len > 0 && pos < levelDataSize && levelData[pos]) {
1213 dest[lp++] = levelData[pos++];
1214 --len;
1217 } else if (destsize == 1) {
1218 dest[0] = 0;
1223 static int gameRST (int tid, int opcode, int argc, int argv[], int *argp[]) {
1224 if (argv[0] == CONST_FRST_MINIMAP) {
1225 activateMinimap();
1226 } else if (argv[0] == CONST_FRST_OPEN_LEVEL_FILE) {
1227 // levelnum
1228 //if (vmLoadArgs(tid, 2, argv, argp, argc, argv, argp) != 0) fatal("out of args");
1229 if (argc < 2) fatal("out of args in FRST_LOAD_LEVEL");
1230 vmGVars[GVAR_RST_RESULT] = loadLevelInternal(&resfile, argv[1]);
1231 //if (goobers) fprintf(stderr, "FRST_OPEN_LEVEL_FILE(%d): %d\n", argv[1], vmGVars[GVAR_RST_RESULT]);
1232 } else if (argv[0] == CONST_FRST_GET_LEVEL_DATA_SIZE) {
1233 vmGVars[GVAR_RST_RESULT] = levelDataSize;
1234 } else if (argv[0] == CONST_FRST_GET_LEVEL_LOADER) {
1235 VMLabelInfo *ucl = vmFindLabel("entry_local_room_loader");
1237 vmGVars[GVAR_RST_RESULT] = (ucl != NULL && ucl->type == LB_CODE) ? ucl->value : -1;
1238 } else if (argv[0] == CONST_FRST_GET_LEVEL_INITER) {
1239 VMLabelInfo *ucl = vmFindLabel("entry_local_room_onload");
1241 vmGVars[GVAR_RST_RESULT] = (ucl != NULL && ucl->type == LB_CODE) ? ucl->value : -1;
1242 } else if (argv[0] == CONST_FRST_GET_GOOBERS_INITER) {
1243 VMLabelInfo *ucl = vmFindLabel("entry_goobers_game_init");
1245 vmGVars[GVAR_RST_RESULT] = (ucl != NULL && ucl->type == LB_CODE) ? ucl->value : -1;
1246 } else if (argv[0] == CONST_FRST_GET_GOOBERS_ONLOAD) {
1247 VMLabelInfo *ucl = vmFindLabel("entry_goobers_room_onload");
1249 vmGVars[GVAR_RST_RESULT] = (ucl != NULL && ucl->type == LB_CODE) ? ucl->value : -1;
1250 } else if (argv[0] == CONST_FRST_GET_LEVEL_FILE_BYTE) {
1251 if (argc < 2) fatal("out of args in FRST_GET_LEVEL_FILE_BYTE");
1252 if (argv[1] < 0 || argv[1] >= levelDataSize) fatal("invalid offset in FRST_GET_LEVEL_FILE_BYTE: %d", argv[1]);
1253 vmGVars[GVAR_RST_RESULT] = levelData[argv[1]];
1254 } else if (argv[0] == CONST_FRST_GET_LEVEL_FILE_WORD) {
1255 if (argc < 2) fatal("out of args in FRST_GET_LEVEL_FILE_WORD");
1256 if (argv[1] < 0 || argv[1]+1 >= levelDataSize) fatal("invalid offset in FRST_GET_LEVEL_FILE_WORD: %d", argv[1]);
1257 vmGVars[GVAR_RST_RESULT] = levelData[argv[1]+1];
1258 vmGVars[GVAR_RST_RESULT] <<= 8;
1259 vmGVars[GVAR_RST_RESULT] |= levelData[argv[1]];
1260 if (vmGVars[GVAR_RST_RESULT] >= 32768) vmGVars[GVAR_RST_RESULT] -= 65536;
1261 } else if (argv[0] == CONST_FRST_SET_LEVEL_SIZE) {
1262 int w, h;
1264 if (argc != 3) fatal("out of args in FRST_SET_LEVEL_SIZE");
1265 w = argv[1];
1266 h = argv[2];
1267 if (w < 1 || w > 32700 || h < 1 || h > 32700) fatal("invalid dimensions in FRST_SET_LEVEL_SIZE: %dx%d", w, h);
1268 if (bmap != NULL) free(bmap); bmap = NULL;
1269 if (fmap != NULL) free(fmap); fmap = NULL;
1270 if (xflags != NULL) free(xflags); xflags = NULL;
1271 fmap = calloc(w*h, 1); if (fmap == NULL) fatal("out of memory in FRST_SET_LEVEL_SIZE");
1272 bmap = calloc(w*h, 1); if (bmap == NULL) fatal("out of memory in FRST_SET_LEVEL_SIZE");
1273 xflags = calloc(w, 1); if (xflags == NULL) fatal("out of memory in FRST_SET_LEVEL_SIZE");
1274 mapWidth = vmGVars[GVAR_MAP_WIDTH] = w;
1275 mapHeight = vmGVars[GVAR_MAP_HEIGHT] = h;
1276 oldScrX = 0;
1277 oldScrY = 0;
1278 redrawLevel = 1;
1279 } else if (argv[0] == CONST_FRST_SET_LEVEL_NAME) {
1280 char buf[32];
1282 getVMString(levelname, sizeof(levelname), argc, argv);
1283 lnamex = (320-strlen(levelname)*8)/2;
1284 sprintf(buf, "%d", curLevel+1);
1285 while (lnamex+strlen(levelname)*8+strlen(buf)*8+6*8 > 320) lnamex -= 8;
1286 redrawLevel = 1;
1287 } else if (argv[0] == CONST_FRST_SET_LEVEL_CODE) {
1288 getVMString(levelcode, sizeof(levelcode), argc, argv);
1289 redrawLevel = 1;
1290 } else if (argv[0] == CONST_FRST_SET_ITEM_NAME) {
1291 getVMString(itemname, sizeof(itemname), argc, argv);
1292 redrawLevel = 1;
1293 } else if (argv[0] == CONST_FRST_LOAD_SPRITES) {
1294 // arg1: bank, arg2: filename (0-terminated)
1295 int fnpos;
1297 switch (argc) {
1298 case 1:
1299 argv[2] = vmPop(tid);
1300 argv[1] = vmPop(tid);
1301 break;
1302 case 2:
1303 argv[2] = vmPop(tid);
1304 break;
1307 fnpos = argv[2];
1308 vmGVars[GVAR_RST_RESULT] = -1;
1309 if (fnpos >= 0 && fnpos < vmCodeSize-1 && argv[1] >= 0 && argv[1] <= 256) {
1310 int end;
1312 for (end = fnpos; end < vmCodeSize && vmCode[end]; ++end) ;
1313 if (end < vmCodeSize) {
1314 //fprintf(stderr, "!!! %d: [%s]\n", argv[1], (const char *)(vmCode+fnpos));
1315 vmGVars[GVAR_RST_RESULT] = loadSpriteBankFromFile(&banks[argv[1]], (const char *)(vmCode+fnpos));
1318 } else if (argv[0] == CONST_FRST_ADD_LEVEL_SPRITE || argv[0] == CONST_FRST_ADD_SPRITE) {
1319 // x, y, layer, bank, num, dir (can take 1st 2 args from stack too)
1320 int inlevel = (argv[0] == CONST_FRST_ADD_LEVEL_SPRITE);
1321 int x = 0, y = 0, layer, bank, num, dir;
1323 dir = vmPop(tid);
1324 num = vmPop(tid);
1325 bank = vmPop(tid);
1326 layer = vmPop(tid);
1327 switch (argc) {
1328 case 1:
1329 y = vmPop(tid);
1330 x = vmPop(tid);
1331 break;
1332 case 2:
1333 y = vmPop(tid);
1334 x = argv[1];
1335 break;
1336 case 3:
1337 y = argv[2];
1338 x = argv[1];
1339 break;
1341 //fprintf(stderr, "x=%d, y=%d, layer=%d, bank=%d, num=%d, dir=%d, inlevel=%d\n", x, y, layer, bank, num, dir, inlevel);
1342 addSpriteToLayer(x, y, layer, bank, num, dir, inlevel);
1343 } else {
1344 if (gameRSTCB) return gameRSTCB(tid, opcode, argc, argv, argp);
1345 fatal("invalid RST: %d", argv[0]);
1347 return 0; // continue
1351 ////////////////////////////////////////////////////////////////////////////////
1352 void setMainLoopGame (void) {
1353 frameCB = frmGameDraw;
1354 keyCB = frmGameKey;
1355 mouseCB = frmMouse;
1356 gameRSTCB = gameRST;
1357 beforeVMCB = demoCB;
1358 vmMapGetCB = mapGet;
1359 vmMapSetCB = mapSet;
1361 clearSpriteLayers();
1362 setSeed(time(NULL));
1363 vmPaused = 0;
1364 inMinimap = 0;
1365 doSave = 0;
1366 redrawLevel = 1;
1367 levelname[0] = levelcode[0] = itemname[0] = 0;
1368 //curLevel = -1;
1369 //demorecmode = 0;
1370 message[0] = 0;
1371 memset(fkeys, 0, sizeof(fkeys));
1372 memset(gamekeys, 0, sizeof(gamekeys));