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/>.
27 #include "gameglobals.h"
35 ////////////////////////////////////////////////////////////////////////////////
36 VMRSTCB gameRSTCB
= NULL
;
39 ////////////////////////////////////////////////////////////////////////////////
40 #define VIS_WIDTH (15)
41 #define VIS_HEIGHT (17)
46 ////////////////////////////////////////////////////////////////////////////////
50 static char levelname
[257];
53 static Uint8
*levelData
= NULL
;
54 static int levelDataSize
= 0;
55 static Uint8
*bmap
= NULL
, *fmap
= NULL
;
56 static Uint8
*xflags
= NULL
;
60 static int doSave
= 0;
62 static int demorecmode
= 0; // 0: none; 1: recording; -1: playing
63 static int demoSize
= 0;
64 static int demoPos
= 0;
65 static Uint8
*demoData
= NULL
;
66 static Uint8 demoPrevKeyState
= 0;
67 static int demoKeyStateRepeats
= 0;
69 static char message
[256];
70 //static Uint32 msgEndTime = 0;
72 static Uint32 demo_m_w
= 0;
73 static Uint32 demo_m_z
= 0;
76 ////////////////////////////////////////////////////////////////////////////////
77 static int gamekeys
[12];
80 static void setGameKeysGVars (void) {
81 vmGVars
[GVAR_KEY_LEFT
] = gamekeys
[0] ? 1 : 0;
82 vmGVars
[GVAR_KEY_RIGHT
] = gamekeys
[1] ? 1 : 0;
83 vmGVars
[GVAR_KEY_UP
] = gamekeys
[2] ? 1 : 0;
84 vmGVars
[GVAR_KEY_DOWN
] = gamekeys
[3] ? 1 : 0;
85 vmGVars
[GVAR_KEY_TAKE
] = gamekeys
[4] ? 1 : 0;
86 vmGVars
[GVAR_KEY_USE
] = gamekeys
[5] ? 1 : 0;
88 vmGVars
[GVAR_KEY_MINIMAP
] = gamekeys
[6] ? 1 : 0;
89 vmGVars
[GVAR_KEY_RESTART
] = gamekeys
[7] ? 1 : 0;
91 vmGVars
[GVAR_KEY_FALL_CHEAT
] = gamekeys
[8] ? 1 : 0;
92 vmGVars
[GVAR_KEY_WALK_CHEAT
] = gamekeys
[9] ? 1 : 0;
93 vmGVars
[GVAR_KEY_PLEV_CHEAT
] = gamekeys
[10] ? 1 : 0;
94 vmGVars
[GVAR_KEY_NLEV_CHEAT
] = gamekeys
[11] ? 1 : 0;
98 ////////////////////////////////////////////////////////////////////////////////
103 static int readBuf (FILE *fl
, void *buf
, int len
) {
104 unsigned char *c
= (unsigned char *)buf
;
109 if (fread(&b
, 1, 1, fl
) != 1) return -1;
117 static int writeBuf (FILE *fl
, const void *buf
, int len
) {
118 const unsigned char *c
= (const unsigned char *)buf
;
121 unsigned char b
= *c
++;
124 if (fwrite(&b
, 1, 1, fl
) != 1) return -1;
130 static int readDW (FILE *fl
, int *v
) {
133 for (int f
= 0; f
< 4; ++f
) {
136 if (fread(&b
, 1, 1, fl
) != 1) return -1;
142 for (int f
= 0; f
< 4; ++f
) *v
|= t
[f
]<<(8*f
);
148 static int writeDW (FILE *fl
, int v
) {
149 for (int f
= 0; f
< 4; ++f
) {
154 if (fwrite(&b
, 1, 1, fl
) != 1) return -1;
161 static int readUDW (FILE *fl
, Uint32
*v
) {
164 for (int f
= 0; f
< 4; ++f
) {
167 if (fread(&b
, 1, 1, fl
) != 1) return -1;
173 for (int f
= 0; f
< 4; ++f
) *v
|= t
[f
]<<(8*f
);
179 static int writeUDW (FILE *fl
, Uint32 v
) {
180 for (int f
= 0; f
< 4; ++f
) {
185 if (fwrite(&b
, 1, 1, fl
) != 1) return -1;
192 ////////////////////////////////////////////////////////////////////////////////
193 static const char *SAVE_GAME_SIGNATURE
= "ASG0";
195 static int loadGame (void) {
196 FILE *fl
= fopen("awish.sav", "rb");
201 if (fread(sign
, 4, 1, fl
) != 1) goto error
;
202 if (memcmp(sign
, SAVE_GAME_SIGNATURE
, 4) != 0) goto error
;
203 if (vmLoadState(fl
) != 0) goto error
;
204 if (readUDW(fl
, &demo_m_w
) != 0) goto error
;
205 if (readUDW(fl
, &demo_m_z
) != 0) goto error
;
206 if (readDW(fl
, &inMinimap
) != 0) goto error
;
207 if (readDW(fl
, &curLevel
) != 0) goto error
;
208 if (readBuf(fl
, levelname
, sizeof(levelname
)) != 0) goto error
;
209 if (readDW(fl
, &lnamex
) != 0) goto error
;
210 if (readDW(fl
, &levelback
) != 0) goto error
;
211 if (readBuf(fl
, bmap
, sizeof(bmap
)) != 0) goto error
;
212 if (readBuf(fl
, fmap
, sizeof(fmap
)) != 0) goto error
;
213 if (readBuf(fl
, xflags
, sizeof(xflags
)) != 0) goto error
;
221 if (goobers
) fprintf(stderr
, "error loading saved game\n");
226 static int saveGame (void) {
227 FILE *fl
= fopen("awish.sav", "wb");
230 demo_m_w
= getSeedL();
231 demo_m_z
= getSeedH();
232 if (fwrite(SAVE_GAME_SIGNATURE
, 4, 1, fl
) != 1) goto error
;
233 if (vmSaveState(fl
) != 0) goto error
;
234 if (writeUDW(fl
, demo_m_w
) != 0) goto error
;
235 if (writeUDW(fl
, demo_m_z
) != 0) goto error
;
236 if (writeDW(fl
, inMinimap
) != 0) goto error
;
237 if (writeDW(fl
, curLevel
) != 0) goto error
;
238 if (writeBuf(fl
, levelname
, sizeof(levelname
)) != 0) goto error
;
239 if (writeDW(fl
, lnamex
) != 0) goto error
;
240 if (writeDW(fl
, levelback
) != 0) goto error
;
241 if (writeBuf(fl
, bmap
, sizeof(bmap
)) != 0) goto error
;
242 if (writeBuf(fl
, fmap
, sizeof(fmap
)) != 0) goto error
;
243 if (writeBuf(fl
, xflags
, sizeof(xflags
)) != 0) goto error
;
250 if (goobers
) fprintf(stderr
, "error saving game\n");
255 ////////////////////////////////////////////////////////////////////////////////
256 static void demoClear (void) {
260 demoPrevKeyState
= 0;
261 demoKeyStateRepeats
= 0;
262 if (demoData
!= NULL
) free(demoData
);
267 static void demoAddByte (Uint8 b
) {
268 if (demoPos
+1 > demoSize
&& demoSize
> 1024*1024*16) fatal("out of memory in demo recording!");
269 if (demoPos
+1 > demoSize
) {
270 int newsz
= demoSize
+1024*32;
271 Uint8
*nn
= realloc(demoData
, newsz
);
273 if (!nn
) fatal("out of memory in demo recording!");
277 demoData
[demoPos
++] = b
;
281 static Uint8
demoGetKeyState (void) {
283 ((gamekeys
[0]?1:0)<<0) |
284 ((gamekeys
[1]?1:0)<<1) |
285 ((gamekeys
[2]?1:0)<<2) |
286 ((gamekeys
[3]?1:0)<<3) |
287 ((gamekeys
[4]?1:0)<<4) |
288 ((gamekeys
[5]?1:0)<<5);
292 static void demoSetKeyState (Uint8 kstate
) {
293 gamekeys
[0] = (kstate
&(1<<0)) != 0;
294 gamekeys
[1] = (kstate
&(1<<1)) != 0;
295 gamekeys
[2] = (kstate
&(1<<2)) != 0;
296 gamekeys
[3] = (kstate
&(1<<3)) != 0;
297 gamekeys
[4] = (kstate
&(1<<4)) != 0;
298 gamekeys
[5] = (kstate
&(1<<5)) != 0;
302 static void demoAddFrameData (void) {
303 Uint8 kstate
= demoGetKeyState();
305 if (demoKeyStateRepeats
== 256) {
306 demoAddByte(demoKeyStateRepeats
-1);
307 demoAddByte(demoPrevKeyState
);
308 demoKeyStateRepeats
= 0;
311 if (kstate
!= demoPrevKeyState
) {
312 if (demoKeyStateRepeats
> 0) {
313 demoAddByte(demoKeyStateRepeats
-1);
314 demoAddByte(demoPrevKeyState
);
316 demoPrevKeyState
= kstate
;
317 demoKeyStateRepeats
= 1;
319 ++demoKeyStateRepeats
;
324 static void demoGetFrameData (void) {
325 while (demoKeyStateRepeats
< 1) {
326 if (demoPos
+2 > demoSize
) {
329 if (goobers
) fprintf(stderr
, "demo complete\n");
330 strcpy(message
, "demo stopped");
333 demoKeyStateRepeats
= demoData
[demoPos
++];
334 ++demoKeyStateRepeats
;
335 demoPrevKeyState
= demoData
[demoPos
++];
337 --demoKeyStateRepeats
;
339 demoSetKeyState(demoPrevKeyState
);
343 static int demoSave (void) {
348 if (demoKeyStateRepeats
> 0) {
349 demoAddByte(demoKeyStateRepeats
-1);
350 demoAddByte(demoPrevKeyState
);
353 sprintf(buf
, "awish%02d.dmo", curLevel
+1);
354 fl
= fopen(buf
, "wb");
356 if (goobers
) fprintf(stderr
, "can't create demo file '%s'\n", buf
);
359 strcpy(sign
, "AWD1");
360 if (fwrite(sign
, 4, 1, fl
) != 1) goto error
;
361 if (writeDW(fl
, curLevel
) != 0) goto error
;
362 if (writeUDW(fl
, demo_m_w
) != 0) goto error
;
363 if (writeUDW(fl
, demo_m_z
) != 0) goto error
;
364 if (writeDW(fl
, demoPos
) != 0) goto error
;
365 if (writeBuf(fl
, demoData
, demoPos
) != 0) goto error
;
367 if (goobers
) fprintf(stderr
, "demo saved to file '%s'\n", buf
);
372 if (goobers
) fprintf(stderr
, "can't write demo file '%s'\n", buf
);
377 static int demoLoad (void) {
384 sprintf(buf
, "awish%02d.dmo", curLevel
+1);
385 fl
= fopen(buf
, "rb");
387 if (goobers
) fprintf(stderr
, "can't open demo file '%s'\n", buf
);
391 if (fread(sign
, 4, 1, fl
) != 1) goto error
;
392 if (memcmp(sign
, "AWD1", 4) != 0) goto error
;
393 if (readDW(fl
, &level
) != 0) goto error
;
394 if (readUDW(fl
, &demo_m_w
) != 0) goto error
;
395 if (readUDW(fl
, &demo_m_z
) != 0) goto error
;
396 if (readDW(fl
, &size
) != 0) goto error
;
397 if (size
< 1 || size
> 1024*1024*16) goto error
;
398 demoData
= malloc(size
);
399 if (demoData
== NULL
) goto error
;
400 if (readBuf(fl
, demoData
, size
) != 0) goto error
;
406 if (goobers
) fprintf(stderr
, "loaded demo file '%s'\n", buf
);
411 if (goobers
) fprintf(stderr
, "can't load demo file '%s'\n", buf
);
417 static inline int isGameStopped (void) {
419 vmGVars
[GVAR_GAME_STATE
] == CONST_GAME_STATE_DEAD
||
420 vmGVars
[GVAR_GAME_STATE
] == CONST_GAME_STATE_COMPLETE
;
424 static void demoCB (void) {
425 //if (vmGVars[GVAR_GAME_STATE] == CONST_GAME_STATE_STARTED) unloadMapScript();
427 switch (demorecmode
) {
428 case -666: // prepare to load demo
429 if (demoLoad() != 0) {
435 case 666: // prepare to save demo
436 vmSetPC(0, CODE_ENTRY_GAME_RESTART_LEVEL
);
437 vmGVars
[GVAR_CUR_LEVEL
] = curLevel
;
438 vmGVars
[GVAR_GAME_STATE
] = -1; // invalid state
439 if (demorecmode
> 0) {
444 case -1: // demo replaying
445 case 1: // demo saving
446 if (isGameStopped()) {
447 // the level is over or prof is dead
448 if (demorecmode
> 0) demoSave();
452 ((demorecmode
< 0) ? demoGetFrameData
: demoAddFrameData
)();
455 case -2: // waiting for 'game started' trigger
456 case 2: // waiting for 'game started' trigger
457 if (vmGVars
[GVAR_GAME_STATE
] >= 0) {
458 if (goobers
) fprintf(stderr
, "demo %s started...\n", demorecmode
<0?"replaying":"recording");
459 if (demorecmode
< 0) {
465 demo_m_w
= getSeedL();
466 demo_m_z
= getSeedH();
468 demorecmode
= (demorecmode
< 0) ? -1 : 1;
476 ////////////////////////////////////////////////////////////////////////////////
477 static void frmGameKey (SDL_KeyboardEvent
*key
) {
478 if (key
->type
== SDL_KEYDOWN
) {
479 switch (key
->keysym
.sym
) {
483 if (vmPaused
&& inMinimap
) {
491 vmGVars
[GVAR_KEY_QUIT
] = 1;
507 if (demorecmode
!= 0) { demoClear(); demorecmode
= 0; }
508 if ((key
->keysym
.mod
&(KMOD_CTRL
)) != 0) {
514 if (vmPaused
== 0 && !demorecmode
) {
515 if (goobers
&& (key
->keysym
.mod
&(KMOD_CTRL
)) != 0) { doSave
= 1; vmPaused
= 1; }
519 if (vmPaused
== 0 && !demorecmode
) {
520 if (goobers
&& (key
->keysym
.mod
&(KMOD_CTRL
)) != 0) { doSave
= -1; vmPaused
= 1; }
525 if (goobers
&& (key
->keysym
.mod
&(KMOD_CTRL
)) != 0) {
527 demorecmode
= 666; // 'start saving'
538 if (goobers
&& (key
->keysym
.mod
&(KMOD_CTRL
)) != 0) {
540 demorecmode
= -666; // 'start playing'
553 if (demorecmode
== 0 || demorecmode
== 1) {
554 switch (key
->keysym
.sym
) {
555 case SDLK_LEFT
: case SDLK_KP4
: gamekeys
[0] = (key
->type
== SDL_KEYDOWN
); break;
556 case SDLK_RIGHT
: case SDLK_KP6
: gamekeys
[1] = (key
->type
== SDL_KEYDOWN
); break;
557 case SDLK_UP
: case SDLK_KP8
: gamekeys
[2] = (key
->type
== SDL_KEYDOWN
); break;
558 case SDLK_DOWN
: case SDLK_KP2
: gamekeys
[3] = (key
->type
== SDL_KEYDOWN
); break;
559 case SDLK_SPACE
: case SDLK_KP0
: gamekeys
[4] = (key
->type
== SDL_KEYDOWN
); break;
560 case SDLK_RETURN
: case SDLK_KP_PERIOD
: gamekeys
[5] = (key
->type
== SDL_KEYDOWN
); break;
564 if (goobers
&& !demorecmode
) {
565 switch (key
->keysym
.sym
) {
566 case SDLK_f
: gamekeys
[8] = (key
->type
== SDL_KEYDOWN
); break;
567 case SDLK_w
: gamekeys
[9] = (key
->type
== SDL_KEYDOWN
); break;
568 case SDLK_KP_MINUS
: gamekeys
[10] = (key
->type
== SDL_KEYDOWN
); break;
569 case SDLK_KP_PLUS
: gamekeys
[11] = (key
->type
== SDL_KEYDOWN
); break;
571 case SDLK_F1
: fkeys
[1] = (key
->type
== SDL_KEYDOWN
); break;
572 case SDLK_F2
: fkeys
[2] = (key
->type
== SDL_KEYDOWN
); break;
573 case SDLK_F3
: fkeys
[3] = (key
->type
== SDL_KEYDOWN
); break;
574 case SDLK_F4
: fkeys
[4] = (key
->type
== SDL_KEYDOWN
); break;
575 case SDLK_F5
: fkeys
[5] = (key
->type
== SDL_KEYDOWN
); break;
576 case SDLK_F6
: fkeys
[6] = (key
->type
== SDL_KEYDOWN
); break;
577 case SDLK_F7
: fkeys
[7] = (key
->type
== SDL_KEYDOWN
); break;
578 case SDLK_F8
: fkeys
[8] = (key
->type
== SDL_KEYDOWN
); break;
579 case SDLK_F9
: fkeys
[9] = (key
->type
== SDL_KEYDOWN
); break;
587 ////////////////////////////////////////////////////////////////////////////////
588 static inline Uint8
fgTile (int x
, int y
) {
589 return (x
>= 0 && y
>= 0 && x
< mapWidth
&& y
< mapHeight
) ? fmap
[y
*mapWidth
+x
] : 0;
593 static inline Uint8
bgTile (int x
, int y
) {
594 if (y
== -666) return (x
>= 0 && x
< mapWidth
) ? xflags
[x
] : 0;
595 return (x
>= 0 && y
>= 0 && x
< mapWidth
&& y
< mapHeight
) ? bmap
[y
*mapWidth
+x
] : 0;
599 static inline void setFGTile (int x
, int y
, Uint8 tile
) {
600 if (x
>= 0 && y
>= 0 && x
< mapWidth
&& y
< mapHeight
) fmap
[y
*mapWidth
+x
] = tile
;
604 static inline void setBGTile (int x
, int y
, Uint8 tile
) {
605 if (y
== -666 && x
>= 0 && x
< mapWidth
) xflags
[x
] = tile
;
606 if (x
>= 0 && y
>= 0 && x
< mapWidth
&& y
< mapHeight
) bmap
[y
*mapWidth
+x
] = tile
;
610 static int mapGet (int tid
, int fg
, int x
, int y
) {
611 if (fmap
!= NULL
) return fg
? fgTile(x
, y
) : bgTile(x
, y
);
616 static void mapSet (int tid
, int fg
, int x
, int y
, int tile
) {
618 if (fg
) setFGTile(x
, y
, tile
); else setBGTile(x
, y
, tile
);
623 ////////////////////////////////////////////////////////////////////////////////
624 // cliprect should be set
625 static void levelDrawMap (SDL_Surface
*frame
) {
627 int scrX
= vmGVars
[GVAR_SCR_X
], scrY
= vmGVars
[GVAR_SCR_Y
];
629 for (int dy
= 0; dy
< VIS_HEIGHT
; ++dy
) {
630 for (int dx
= 0; dx
< VIS_WIDTH
; ++dx
) {
631 int x
= scrX
+dx
, y
= scrY
+dy
;
632 Uint8 b
= bgTile(x
, y
), f
= fgTile(x
, y
);
634 if (b
) blitSurface2x(frame
, VIS_X
+dx
*20, VIS_Y
+dy
*10, banks
[CONST_BANK_BG_TILES
].spr
[b
-1][0]);
635 if (f
) blitSurface2x(frame
, VIS_X
+dx
*20, VIS_Y
+dy
*10, banks
[CONST_BANK_FG_TILES
].spr
[f
-1][0]);
639 for (int dy
= 0; dy
< mapHeight
; ++dy
) {
640 for (int dx
= 1; dx
< mapWidth
; ++dx
) {
641 Uint8 b
= bgTile(dx
, dy
), f
= fgTile(dx
, dy
), t
= 8;
644 if (b
>= 1 && b
<= 8) t
= b
-1; else t
= 8;
648 if (banks
[CONST_BANK_MAP_TILES
].spr
[t
][0]) {
649 blitSurface2x(frame
, VIS_X
+dx
*6, VIS_Y
+dy
*4, banks
[CONST_BANK_MAP_TILES
].spr
[t
][0]);
651 blitSurface2x(frame
, VIS_X
+dx
*6, VIS_Y
+dy
*4, banks
[CONST_BANK_MAP_TILES
].spr
[0][0]);
659 static void levelDrawSprites (SDL_Surface
*frame
) {
661 int scrX
= vmGVars
[GVAR_SCR_X
], scrY
= vmGVars
[GVAR_SCR_Y
];
662 int py
= vmGetTVar(0, TVAR_POS_Y
)-scrY
;
664 for (int cc
= 0; cc
<= 2; ++cc
) {
665 for (int f
= cc
==1?1:0; f
<= vmLastThread(); ++f
) {
666 if (vmIsThreadAlive(f
) && !vmIsSuspendedThread(f
)) {
667 int b
= vmGetTVar(f
, TVAR_SPR_BANK
);
668 int s
= vmGetTVar(f
, TVAR_SPR_NUM
);
669 int d
= vmGetTVar(f
, TVAR_SPR_DIR
);
671 if (d
>= 0 && d
<= 1 && s
>= 0 && b
>= 0 && b
<= 255 && s
< banks
[b
].count
&& banks
[b
].spr
[s
][d
]) {
672 SDL_Surface
*sf
= banks
[b
].spr
[s
][d
];
673 int x
= vmGetTVar(f
, TVAR_POS_X
)-scrX
;
674 int y
= vmGetTVar(f
, TVAR_POS_Y
)-scrY
;
675 int tx
= vmGetTVar(f
, TVAR_POS_TX
);
676 int ty
= vmGetTVar(f
, TVAR_POS_TY
);
677 int si
= vmGetTVar(f
, TVAR_SPR_ITEM
);
679 if (cc
== 0 && b
== CONST_BANK_ITEMS
) continue;
680 if (cc
== 1 && b
!= CONST_BANK_ITEMS
) continue;
682 if (b
!= CONST_BANK_PROF
) {
683 if (b
!= CONST_BANK_ITEMS
) continue;
684 if (y
< py
) continue;
687 if (b
== CONST_BANK_IM_PROF
|| b
== CONST_BANK_PROF
) tx
-= 5;
688 blitSurface2x(frame
, VIS_X
+x
*20+tx
, VIS_Y
+y
*10+ty
-sf
->h
/2, sf
);
689 if (si
> 0 && si
< banks
[CONST_BANK_ITEMS
].count
) {
690 sf
= banks
[CONST_BANK_ITEMS
].spr
[si
][0];
691 blitSurface2x(frame
, VIS_X
+x
*20+tx
, VIS_Y
+y
*10+ty
-sf
->h
/2-24, sf
);
698 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]);
699 for (int f
= 1; f
< VM_MAX_THREADS
; ++f
) {
700 if (vmIsThreadAlive(f
) && !vmIsSuspendedThread(f
)) {
701 int i
= vmGetTVar(f
, TVAR_ITEM_ID
);
702 if (i
> 0 && i
<= 255) {
703 SDL_Surface
*sf
= banks
[CONST_BANK_MAP_ITEMS
].spr
[i
][0];
704 int x
= vmGetTVar(f
, TVAR_POS_X
);
705 int y
= vmGetTVar(f
, TVAR_POS_Y
);
707 blitSurface2x(frame
, VIS_X
+(x
+0)*6, VIS_Y
+(y
-2)*4, sf
);
715 static void levelDrawCode (SDL_Surface
*frame
) {
716 int pos
= vmGVars
[GVAR_LEVEL_CODE_OFS
], len
= vmGVars
[GVAR_LEVEL_CODE_LEN
], x
;
719 if (len
> 255) len
= 255;
720 if (pos
< 0 || len
< 1 || pos
+len
> vmCodeSize
) return;
722 sprintf(buf
, "%d", curLevel
);
724 for (; len
> 0; x
+= 8, ++pos
, --len
) drawChar(frame
, vmCode
[pos
], x
, 0, 3);
728 static void levelDrawItemName (SDL_Surface
*frame
) {
729 int pos
= vmGVars
[GVAR_ITEM_NAME_OFS
], len
= vmGVars
[GVAR_ITEM_NAME_LEN
], x
= 0;
732 if (len
< 0 || len
> 32) len
= 32;
733 for (; len
> 0 && pos
< vmCodeSize
&& vmCode
[pos
]; x
+= 8, ++pos
, --len
) drawChar(frame
, vmCode
[pos
], x
, 0, 3);
737 static void levelDrawMisc (SDL_Surface
*frame
) {
738 if (demorecmode
< 0) {
739 if (SDL_GetTicks()%1000 < 500) drawChar(frame
, 'R', 0, 8, 3);
740 } else if (demorecmode
> 0) {
741 if (SDL_GetTicks()%1000 < 500) drawChar(frame
, 'D', 0, 8, 3);
746 static void drawSpriteBank (SDL_Surface
*frame
, SpriteBank
*bank
) {
748 int x
= 0, y
= 0, maxh
= 0;
750 SDL_SetClipRect(frame
, NULL
);
755 SDL_FillRect(frame
, &dst
, palette
[3]);
757 for (int num
= 0; num
< bank
->count
; ++num
) {
758 SDL_Surface
*s
= bank
->spr
[num
][0];
764 sprintf(buf
, "%d", num
);
765 if (w
< strlen(buf
)*8+2) w
= strlen(buf
)*8+2;
771 if (maxh
< s
->h
/2+1) maxh
= s
->h
/2+1;
772 blitSurface2x(frame
, x
, y
, s
);
773 drawString(frame
, buf
, x
, y
, 1);
780 static void frmGameDraw (SDL_Surface
*frame
) {
783 if (vmPaused
&& doSave
) {
785 if (loadGame() != 0) fatal("can't load game, VM is inconsistent, dying.");
790 vmPaused
= inMinimap
;
793 SDL_SetClipRect(frame
, NULL
);
800 int levelback
= vmGVars
[GVAR_LEVEL_BACKPIC
];
802 if (levelback
< 1 || levelback
> 7) levelback
= 1;
803 blitSurface(frame
, 0, 0, backs
[levelback
]);
805 blitSurface(frame
, 0, 0, backs
[1]);
807 drawString(frame
, levelname
, lnamex
, 0, 0x76);
808 levelDrawItemName(frame
);
809 levelDrawCode(frame
);
810 levelDrawMisc(frame
);
813 pi = vmGVars[GVAR_PROF_ITEM];
814 if (vmIsThreadAlive(pi) && vmIsSuspendedThread(pi)) {
815 pi = vmGetTVar(pi, TVAR_ITEM_ID);
816 if (pi > 0 && pi < 11) {
817 drawString(frame, itemNames[pi], 0, 0, 1);
822 sprintf(buf
, "%d", curLevel
+1);
823 drawString(frame
, buf
, 320-strlen(buf
)*8, 0, 1);
827 rc
.w
= VIS_WIDTH
*20*2;
828 rc
.h
= VIS_HEIGHT
*10*2;
829 SDL_SetClipRect(frame
, &rc
);
832 levelDrawSprites(frame
);
840 SDL_FillRect(frame
, &dst
, palette
[0]);
843 SDL_SetClipRect(frame
, NULL
);
844 levelDrawMisc(frame
);
847 for (int f
= 84; f
<= 90; ++f
) if (fkeys
[f
-83]) drawSpriteBank(frame
, &banks
[f
]);
852 ////////////////////////////////////////////////////////////////////////////////
853 #define ROOM_SCRIPTS_MARK " room script labels starts here "
856 static void loadMapScript (ResFile
*resfile
) {
860 l
= vmLabelAddMark(ROOM_SCRIPTS_MARK
);
861 l
->value
= vmCodeSize
;
862 if ((csz
= loadCodeFile(resfile
, vmCodeSize
, 94+curLevel
)) > 1) {
868 static void unloadMapScript (void) {
869 VMLabelInfo
*l
, *ucl
;
871 while ((l
= vmFindMark(ROOM_SCRIPTS_MARK
)) != NULL
) {
872 ucl
= vmFindLabel("entry_local_room_script_onunload");
873 if (ucl
!= NULL
&& ucl
->type
== LB_CODE
) vmExecuteBSR(0, ucl
->value
, 0);
874 vmCodeSize
= l
->value
;
875 vmFreeLabelsUntilMark(ROOM_SCRIPTS_MARK
);
878 ucl
= vmFindLabel("entry_room_onunload");
879 if (ucl
!= NULL
&& ucl
->type
== LB_CODE
) vmExecuteBSR(0, ucl
->value
, 0);
883 ////////////////////////////////////////////////////////////////////////////////
884 static int loadLevelInternal (ResFile
*resfile
, int lidx
) {
888 vmGVars
[GVAR_VIS_WIDTH
] = VIS_WIDTH
;
889 vmGVars
[GVAR_VIS_HEIGHT
] = VIS_HEIGHT
;
890 vmGVars
[GVAR_ITEM_NAME_OFS
] = 0;
891 vmGVars
[GVAR_ITEM_NAME_LEN
] = 0;
895 if (levelData
!= NULL
) free(levelData
); levelData
= NULL
; levelDataSize
= 0;
896 if (bmap
!= NULL
) free(bmap
); bmap
= NULL
;
897 if (fmap
!= NULL
) free(fmap
); fmap
= NULL
;
898 if (xflags
!= NULL
) free(xflags
); xflags
= NULL
;
901 if (lidx
< 0 || lidx
> 73) return -1;
902 if ((levelData
= loadResFile(resfile
, lidx
+9, &levelDataSize
)) == NULL
) return -1;
904 loadMapScript(resfile
);
905 return levelDataSize
;
909 ////////////////////////////////////////////////////////////////////////////////
910 static void activateMinimap (void) {
917 ////////////////////////////////////////////////////////////////////////////////
918 static int gameRST (int tid
, int opcode
, int argc
, int argv
[], int *argp
[]) {
919 if (argv
[0] == CONST_FRST_MINIMAP
) {
921 } else if (argv
[0] == CONST_FRST_OPEN_LEVEL_FILE
) {
923 //if (vmLoadArgs(tid, 2, argv, argp, argc, argv, argp) != 0) fatal("out of args");
924 if (argc
< 2) fatal("out of args in FRST_LOAD_LEVEL");
925 vmGVars
[GVAR_RST_RESULT
] = loadLevelInternal(&resfile
, argv
[1]);
926 if (goobers
) fprintf(stderr
, "FRST_OPEN_LEVEL_FILE(%d): %d\n", argv
[1], vmGVars
[GVAR_RST_RESULT
]);
927 } else if (argv
[0] == CONST_FRST_GET_LEVEL_DATA_SIZE
) {
928 vmGVars
[GVAR_RST_RESULT
] = levelDataSize
;
929 } else if (argv
[0] == CONST_FRST_GET_LEVEL_LOADER
) {
930 VMLabelInfo
*ucl
= vmFindLabel("entry_local_room_loader");
932 vmGVars
[GVAR_RST_RESULT
] = (ucl
!= NULL
&& ucl
->type
== LB_CODE
) ? ucl
->value
: -1;
933 } else if (argv
[0] == CONST_FRST_GET_LEVEL_INITER
) {
934 VMLabelInfo
*ucl
= vmFindLabel("entry_local_room_onload");
936 vmGVars
[GVAR_RST_RESULT
] = (ucl
!= NULL
&& ucl
->type
== LB_CODE
) ? ucl
->value
: -1;
937 } else if (argv
[0] == CONST_FRST_GET_LEVEL_FILE_BYTE
) {
938 if (argc
< 2) fatal("out of args in FRST_GET_LEVEL_FILE_BYTE");
939 if (argv
[1] < 0 || argv
[1] >= levelDataSize
) fatal("invalid offset in FRST_GET_LEVEL_FILE_BYTE: %d", argv
[1]);
940 vmGVars
[GVAR_RST_RESULT
] = levelData
[argv
[1]];
941 } else if (argv
[0] == CONST_FRST_GET_LEVEL_FILE_WORD
) {
942 if (argc
< 2) fatal("out of args in FRST_GET_LEVEL_FILE_WORD");
943 if (argv
[1] < 0 || argv
[1]+1 >= levelDataSize
) fatal("invalid offset in FRST_GET_LEVEL_FILE_WORD: %d", argv
[1]);
944 vmGVars
[GVAR_RST_RESULT
] = levelData
[argv
[1]+1];
945 vmGVars
[GVAR_RST_RESULT
] <<= 8;
946 vmGVars
[GVAR_RST_RESULT
] |= levelData
[argv
[1]];
947 if (vmGVars
[GVAR_RST_RESULT
] >= 32768) vmGVars
[GVAR_RST_RESULT
] -= 65536;
948 } else if (argv
[0] == CONST_FRST_SET_LEVEL_SIZE
) {
949 if (argc
!= 3) fatal("out of args in FRST_SET_LEVEL_SIZE");
950 if (argv
[1] < 1 || argv
[1] > 32700 || argv
[2] < 1 || argv
[2] > 32700) fatal("invalid dimensions in FRST_SET_LEVEL_SIZE: %dx%d", argv
[1], argv
[2]);
951 if (bmap
!= NULL
) free(bmap
); bmap
= NULL
;
952 if (fmap
!= NULL
) free(fmap
); fmap
= NULL
;
953 if (xflags
!= NULL
) free(xflags
); xflags
= NULL
;
954 fmap
= calloc(1, argv
[1]*argv
[2]); if (fmap
== NULL
) fatal("out of memory in FRST_SET_LEVEL_SIZE");
955 bmap
= calloc(1, argv
[1]*argv
[2]); if (bmap
== NULL
) fatal("out of memory in FRST_SET_LEVEL_SIZE");
956 xflags
= calloc(1, argv
[1]); if (xflags
== NULL
) fatal("out of memory in FRST_SET_LEVEL_SIZE");
957 vmGVars
[GVAR_MAP_WIDTH
] = argv
[1];
958 vmGVars
[GVAR_MAP_HEIGHT
] = argv
[2];
959 } else if (argv
[0] == CONST_FRST_SET_LEVEL_NAME
) {
960 int pos
= 0, len
= sizeof(levelname
)-1, lp
= 0;
964 case 1: fatal("out of args in FRST_SET_LEVEL_NAME");
965 case 2: pos
= argv
[1]; break;
966 case 3: pos
= argv
[1]; len
= argv
[2]; break;
968 memset(levelname
, 0, sizeof(levelname
));
969 if (len
> sizeof(levelname
)-1) len
= sizeof(levelname
)-1;
971 while (len
> 0 && pos
< vmCodeSize
&& vmCode
[pos
]) {
972 levelname
[lp
++] = vmCode
[pos
++];
977 while (len
> 0 && pos
< levelDataSize
&& levelData
[pos
]) {
978 levelname
[lp
++] = levelData
[pos
++];
982 lnamex
= (320-strlen(levelname
)*8)/2;
983 sprintf(buf
, "%d", curLevel
+1);
984 while (lnamex
+strlen(levelname
)*8+strlen(buf
)*8+6*8 > 320) lnamex
-= 8;
986 if (gameRSTCB
) return gameRSTCB(tid
, opcode
, argc
, argv
, argp
);
987 fatal("invalid RST: %d", argv
[0]);
989 return 0; // continue
993 ////////////////////////////////////////////////////////////////////////////////
994 void setMainLoopGame (void) {
995 frameCB
= frmGameDraw
;
1000 vmMapSetCB
= mapSet
;
1002 setSeed(time(NULL
));
1009 memset(fkeys
, 0, sizeof(fkeys
));
1010 memset(gamekeys
, 0, sizeof(gamekeys
));