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"
36 ////////////////////////////////////////////////////////////////////////////////
37 VMRSTCB gameRSTCB
= NULL
;
40 ////////////////////////////////////////////////////////////////////////////////
41 #define VIS_WIDTH (15)
42 #define VIS_HEIGHT (17)
47 ////////////////////////////////////////////////////////////////////////////////
48 static int redrawLevel
;
49 static int oldScrX
, oldScrY
;
53 static char levelname
[257];
55 static Uint8
*levelData
= NULL
;
56 static int levelDataSize
= 0;
57 static Uint8
*bmap
= NULL
, *fmap
= NULL
;
58 static Uint8
*xflags
= NULL
;
61 static int doSave
= 0;
63 static int demorecmode
= 0; // 0: none; 1: recording; -1: playing
64 static int demoSize
= 0;
65 static int demoPos
= 0;
66 static Uint8
*demoData
= NULL
;
67 static Uint8 demoPrevKeyState
= 0;
68 static int demoKeyStateRepeats
= 0;
70 static char message
[256];
71 //static Uint32 msgEndTime = 0;
73 static Uint32 demo_m_w
= 0;
74 static Uint32 demo_m_z
= 0;
77 ////////////////////////////////////////////////////////////////////////////////
78 static int gamekeys
[12];
82 static void setGameKeysGVars (void) {
83 vmGVars
[GVAR_KEY_LEFT
] = gamekeys
[0] ? 1 : 0;
84 vmGVars
[GVAR_KEY_RIGHT
] = gamekeys
[1] ? 1 : 0;
85 vmGVars
[GVAR_KEY_UP
] = gamekeys
[2] ? 1 : 0;
86 vmGVars
[GVAR_KEY_DOWN
] = gamekeys
[3] ? 1 : 0;
87 vmGVars
[GVAR_KEY_TAKE
] = gamekeys
[4] ? 1 : 0;
88 vmGVars
[GVAR_KEY_USE
] = gamekeys
[5] ? 1 : 0;
90 vmGVars
[GVAR_KEY_MINIMAP
] = gamekeys
[6] ? 1 : 0;
91 vmGVars
[GVAR_KEY_RESTART
] = gamekeys
[7] ? 1 : 0;
93 vmGVars
[GVAR_KEY_FALL_CHEAT
] = gamekeys
[8] ? 1 : 0;
94 vmGVars
[GVAR_KEY_WALK_CHEAT
] = gamekeys
[9] ? 1 : 0;
95 vmGVars
[GVAR_KEY_PLEV_CHEAT
] = gamekeys
[10] ? 1 : 0;
96 vmGVars
[GVAR_KEY_NLEV_CHEAT
] = gamekeys
[11] ? 1 : 0;
100 ////////////////////////////////////////////////////////////////////////////////
105 static int readBuf (FILE *fl
, void *buf
, int len
) {
106 unsigned char *c
= (unsigned char *)buf
;
111 if (fread(&b
, 1, 1, fl
) != 1) return -1;
119 static int writeBuf (FILE *fl
, const void *buf
, int len
) {
120 const unsigned char *c
= (const unsigned char *)buf
;
123 unsigned char b
= *c
++;
126 if (fwrite(&b
, 1, 1, fl
) != 1) return -1;
132 static int readDW (FILE *fl
, int *v
) {
135 for (int f
= 0; f
< 4; ++f
) {
138 if (fread(&b
, 1, 1, fl
) != 1) return -1;
144 for (int f
= 0; f
< 4; ++f
) *v
|= t
[f
]<<(8*f
);
150 static int writeDW (FILE *fl
, int v
) {
151 for (int f
= 0; f
< 4; ++f
) {
156 if (fwrite(&b
, 1, 1, fl
) != 1) return -1;
163 static int readUDW (FILE *fl
, Uint32
*v
) {
166 for (int f
= 0; f
< 4; ++f
) {
169 if (fread(&b
, 1, 1, fl
) != 1) return -1;
175 for (int f
= 0; f
< 4; ++f
) *v
|= t
[f
]<<(8*f
);
181 static int writeUDW (FILE *fl
, Uint32 v
) {
182 for (int f
= 0; f
< 4; ++f
) {
187 if (fwrite(&b
, 1, 1, fl
) != 1) return -1;
194 ////////////////////////////////////////////////////////////////////////////////
195 static const char *SAVE_GAME_SIGNATURE
= "ASG1";
198 static int saveGame (void) {
199 FILE *fl
= fopen("awish.sav", "wb");
202 demo_m_w
= getSeedL();
203 demo_m_z
= getSeedH();
204 if (fwrite(SAVE_GAME_SIGNATURE
, 4, 1, fl
) != 1) goto error
;
205 if (vmSaveState(fl
) != 0) goto error
;
206 if (writeDW(fl
, mapWidth
) != 0) goto error
;
207 if (writeDW(fl
, mapHeight
) != 0) goto error
;
208 if (writeUDW(fl
, demo_m_w
) != 0) goto error
;
209 if (writeUDW(fl
, demo_m_z
) != 0) goto error
;
210 if (writeDW(fl
, inMinimap
) != 0) goto error
;
211 if (writeDW(fl
, curLevel
) != 0) goto error
;
212 if (writeBuf(fl
, levelname
, sizeof(levelname
)) != 0) goto error
;
213 if (writeDW(fl
, lnamex
) != 0) goto error
;
214 if (writeBuf(fl
, bmap
, mapWidth
*mapHeight
) != 0) goto error
;
215 if (writeBuf(fl
, fmap
, mapWidth
*mapHeight
) != 0) goto error
;
216 if (writeBuf(fl
, xflags
, mapWidth
) != 0) goto error
;
223 if (goobers
) fprintf(stderr
, "error saving game\n");
228 static int loadGame (void) {
229 FILE *fl
= fopen("awish.sav", "rb");
234 if (fread(sign
, 4, 1, fl
) != 1) goto error
;
235 if (memcmp(sign
, SAVE_GAME_SIGNATURE
, 4) != 0) goto error
;
236 if (vmLoadState(fl
) != 0) goto error
;
237 if (readDW(fl
, &mapWidth
) != 0) goto error
;
238 if (readDW(fl
, &mapHeight
) != 0) goto error
;
239 if (readUDW(fl
, &demo_m_w
) != 0) goto error
;
240 if (readUDW(fl
, &demo_m_z
) != 0) goto error
;
241 if (readDW(fl
, &inMinimap
) != 0) goto error
;
242 if (readDW(fl
, &curLevel
) != 0) goto error
;
243 if (readBuf(fl
, levelname
, sizeof(levelname
)) != 0) goto error
;
244 if (readDW(fl
, &lnamex
) != 0) goto error
;
245 if (bmap
!= NULL
) free(bmap
); bmap
= NULL
;
246 if (fmap
!= NULL
) free(fmap
); fmap
= NULL
;
247 if (xflags
!= NULL
) free(xflags
); xflags
= NULL
;
248 fmap
= calloc(mapWidth
*mapHeight
, 1); if (fmap
== NULL
) fatal("out of memory in loadGame");
249 bmap
= calloc(mapWidth
*mapHeight
, 1); if (bmap
== NULL
) fatal("out of memory in loadGame");
250 xflags
= calloc(mapWidth
, 1); if (xflags
== NULL
) fatal("out of memory in loadGame");
251 if (readBuf(fl
, bmap
, mapWidth
*mapHeight
) != 0) goto error
;
252 if (readBuf(fl
, fmap
, mapWidth
*mapHeight
) != 0) goto error
;
253 if (readBuf(fl
, xflags
, mapWidth
) != 0) goto error
;
258 oldScrX
= oldScrY
= -1;
263 if (goobers
) fprintf(stderr
, "error loading saved game\n");
268 ////////////////////////////////////////////////////////////////////////////////
269 static void demoClear (void) {
273 demoPrevKeyState
= 0;
274 demoKeyStateRepeats
= 0;
275 if (demoData
!= NULL
) free(demoData
);
280 static void demoAddByte (Uint8 b
) {
281 if (demoPos
+1 > demoSize
&& demoSize
> 1024*1024*16) fatal("out of memory in demo recording!");
282 if (demoPos
+1 > demoSize
) {
283 int newsz
= demoSize
+1024*32;
284 Uint8
*nn
= realloc(demoData
, newsz
);
286 if (!nn
) fatal("out of memory in demo recording!");
290 demoData
[demoPos
++] = b
;
294 static Uint8
demoGetKeyState (void) {
296 ((gamekeys
[0]?1:0)<<0) |
297 ((gamekeys
[1]?1:0)<<1) |
298 ((gamekeys
[2]?1:0)<<2) |
299 ((gamekeys
[3]?1:0)<<3) |
300 ((gamekeys
[4]?1:0)<<4) |
301 ((gamekeys
[5]?1:0)<<5);
305 static void demoSetKeyState (Uint8 kstate
) {
306 gamekeys
[0] = (kstate
&(1<<0)) != 0;
307 gamekeys
[1] = (kstate
&(1<<1)) != 0;
308 gamekeys
[2] = (kstate
&(1<<2)) != 0;
309 gamekeys
[3] = (kstate
&(1<<3)) != 0;
310 gamekeys
[4] = (kstate
&(1<<4)) != 0;
311 gamekeys
[5] = (kstate
&(1<<5)) != 0;
315 static void demoAddFrameData (void) {
316 Uint8 kstate
= demoGetKeyState();
318 if (demoKeyStateRepeats
== 256) {
319 demoAddByte(demoKeyStateRepeats
-1);
320 demoAddByte(demoPrevKeyState
);
321 demoKeyStateRepeats
= 0;
324 if (kstate
!= demoPrevKeyState
) {
325 if (demoKeyStateRepeats
> 0) {
326 demoAddByte(demoKeyStateRepeats
-1);
327 demoAddByte(demoPrevKeyState
);
329 demoPrevKeyState
= kstate
;
330 demoKeyStateRepeats
= 1;
332 ++demoKeyStateRepeats
;
337 static void demoGetFrameData (void) {
338 while (demoKeyStateRepeats
< 1) {
339 if (demoPos
+2 > demoSize
) {
342 if (goobers
) fprintf(stderr
, "demo complete\n");
343 strcpy(message
, "demo stopped");
346 demoKeyStateRepeats
= demoData
[demoPos
++];
347 ++demoKeyStateRepeats
;
348 demoPrevKeyState
= demoData
[demoPos
++];
350 --demoKeyStateRepeats
;
352 demoSetKeyState(demoPrevKeyState
);
356 static int demoSave (void) {
361 if (demoKeyStateRepeats
> 0) {
362 demoAddByte(demoKeyStateRepeats
-1);
363 demoAddByte(demoPrevKeyState
);
366 sprintf(buf
, "awish%02d.dmo", curLevel
+1);
367 fl
= fopen(buf
, "wb");
369 if (goobers
) fprintf(stderr
, "can't create demo file '%s'\n", buf
);
372 strcpy(sign
, "AWD1");
373 if (fwrite(sign
, 4, 1, fl
) != 1) goto error
;
374 if (writeDW(fl
, curLevel
) != 0) goto error
;
375 if (writeUDW(fl
, demo_m_w
) != 0) goto error
;
376 if (writeUDW(fl
, demo_m_z
) != 0) goto error
;
377 if (writeDW(fl
, demoPos
) != 0) goto error
;
378 if (writeBuf(fl
, demoData
, demoPos
) != 0) goto error
;
380 if (goobers
) fprintf(stderr
, "demo saved to file '%s'\n", buf
);
385 if (goobers
) fprintf(stderr
, "can't write demo file '%s'\n", buf
);
390 static int demoLoad (void) {
397 sprintf(buf
, "awish%02d.dmo", curLevel
+1);
398 fl
= fopen(buf
, "rb");
400 if (goobers
) fprintf(stderr
, "can't open demo file '%s'\n", buf
);
404 if (fread(sign
, 4, 1, fl
) != 1) goto error
;
405 if (memcmp(sign
, "AWD1", 4) != 0) goto error
;
406 if (readDW(fl
, &level
) != 0) goto error
;
407 if (readUDW(fl
, &demo_m_w
) != 0) goto error
;
408 if (readUDW(fl
, &demo_m_z
) != 0) goto error
;
409 if (readDW(fl
, &size
) != 0) goto error
;
410 if (size
< 1 || size
> 1024*1024*16) goto error
;
411 demoData
= malloc(size
);
412 if (demoData
== NULL
) goto error
;
413 if (readBuf(fl
, demoData
, size
) != 0) goto error
;
419 if (goobers
) fprintf(stderr
, "loaded demo file '%s'\n", buf
);
424 if (goobers
) fprintf(stderr
, "can't load demo file '%s'\n", buf
);
430 static inline int isGameStopped (void) {
432 vmGVars
[GVAR_GAME_STATE
] == CONST_GAME_STATE_DEAD
||
433 vmGVars
[GVAR_GAME_STATE
] == CONST_GAME_STATE_COMPLETE
;
437 static void demoCB (void) {
438 //if (vmGVars[GVAR_GAME_STATE] == CONST_GAME_STATE_STARTED) unloadMapScript();
440 if (vmGVars
[GVAR_SCR_X
] != oldScrX
|| vmGVars
[GVAR_SCR_Y
] != oldScrY
) {
441 oldScrX
= vmGVars
[GVAR_SCR_X
];
442 oldScrY
= vmGVars
[GVAR_SCR_Y
];
446 switch (demorecmode
) {
447 case -666: // prepare to load demo
448 if (demoLoad() != 0) {
454 case 666: // prepare to save demo
455 vmSetPC(0, CODE_ENTRY_GAME_RESTART_LEVEL
);
456 vmGVars
[GVAR_CUR_LEVEL
] = curLevel
;
457 vmGVars
[GVAR_GAME_STATE
] = -1; // invalid state
458 if (demorecmode
> 0) {
463 case -1: // demo replaying
464 case 1: // demo saving
465 if (isGameStopped()) {
466 // the level is over or prof is dead
467 if (demorecmode
> 0) demoSave();
471 ((demorecmode
< 0) ? demoGetFrameData
: demoAddFrameData
)();
474 case -2: // waiting for 'game started' trigger
475 case 2: // waiting for 'game started' trigger
476 if (vmGVars
[GVAR_GAME_STATE
] >= 0) {
477 if (goobers
) fprintf(stderr
, "demo %s started...\n", demorecmode
<0?"replaying":"recording");
478 if (demorecmode
< 0) {
484 demo_m_w
= getSeedL();
485 demo_m_z
= getSeedH();
487 demorecmode
= (demorecmode
< 0) ? -1 : 1;
495 ////////////////////////////////////////////////////////////////////////////////
496 static void frmGameKey (SDL_KeyboardEvent
*key
) {
497 if (key
->type
== SDL_KEYDOWN
) {
498 switch (key
->keysym
.sym
) {
502 if (vmPaused
&& inMinimap
) {
511 vmGVars
[GVAR_KEY_QUIT
] = 1;
528 if (demorecmode
!= 0) { demoClear(); demorecmode
= 0; }
529 if ((key
->keysym
.mod
&(KMOD_CTRL
)) != 0) {
535 if (vmPaused
== 0 && !demorecmode
) {
536 if (goobers
&& (key
->keysym
.mod
&(KMOD_CTRL
)) != 0) { doSave
= 1; vmPaused
= 1; }
540 if (vmPaused
== 0 && !demorecmode
) {
541 if (goobers
&& (key
->keysym
.mod
&(KMOD_CTRL
)) != 0) { doSave
= -1; vmPaused
= 1; }
546 if (goobers
&& (key
->keysym
.mod
&(KMOD_CTRL
)) != 0) {
548 demorecmode
= 666; // 'start saving'
559 if (goobers
&& (key
->keysym
.mod
&(KMOD_CTRL
)) != 0) {
561 demorecmode
= -666; // 'start playing'
574 if (demorecmode
== 0 || demorecmode
== 1) {
575 switch (key
->keysym
.sym
) {
576 case SDLK_LEFT
: case SDLK_KP4
: gamekeys
[0] = (key
->type
== SDL_KEYDOWN
); break;
577 case SDLK_RIGHT
: case SDLK_KP6
: gamekeys
[1] = (key
->type
== SDL_KEYDOWN
); break;
578 case SDLK_UP
: case SDLK_KP8
: gamekeys
[2] = (key
->type
== SDL_KEYDOWN
); break;
579 case SDLK_DOWN
: case SDLK_KP2
: gamekeys
[3] = (key
->type
== SDL_KEYDOWN
); break;
580 case SDLK_SPACE
: case SDLK_KP0
: gamekeys
[4] = (key
->type
== SDL_KEYDOWN
); break;
581 case SDLK_RETURN
: case SDLK_KP_PERIOD
: gamekeys
[5] = (key
->type
== SDL_KEYDOWN
); break;
585 if (goobers
&& !demorecmode
) {
586 switch (key
->keysym
.sym
) {
587 case SDLK_f
: gamekeys
[8] = (key
->type
== SDL_KEYDOWN
); break;
588 case SDLK_w
: gamekeys
[9] = (key
->type
== SDL_KEYDOWN
); break;
589 case SDLK_KP_MINUS
: gamekeys
[10] = (key
->type
== SDL_KEYDOWN
); break;
590 case SDLK_KP_PLUS
: gamekeys
[11] = (key
->type
== SDL_KEYDOWN
); break;
592 case SDLK_F1
: fkeys
[1] = (key
->type
== SDL_KEYDOWN
); break;
593 case SDLK_F2
: fkeys
[2] = (key
->type
== SDL_KEYDOWN
); break;
594 case SDLK_F3
: fkeys
[3] = (key
->type
== SDL_KEYDOWN
); break;
595 case SDLK_F4
: fkeys
[4] = (key
->type
== SDL_KEYDOWN
); break;
596 case SDLK_F5
: fkeys
[5] = (key
->type
== SDL_KEYDOWN
); break;
597 case SDLK_F6
: fkeys
[6] = (key
->type
== SDL_KEYDOWN
); break;
598 case SDLK_F7
: fkeys
[7] = (key
->type
== SDL_KEYDOWN
); break;
599 case SDLK_F8
: fkeys
[8] = (key
->type
== SDL_KEYDOWN
); break;
600 case SDLK_F9
: fkeys
[9] = (key
->type
== SDL_KEYDOWN
); break;
608 ////////////////////////////////////////////////////////////////////////////////
609 static inline Uint8
fgTile (int x
, int y
) {
610 return (x
>= 0 && y
>= 0 && x
< mapWidth
&& y
< mapHeight
) ? fmap
[y
*mapWidth
+x
] : 0;
614 static inline Uint8
bgTile (int x
, int y
) {
615 if (y
== -666) return (x
>= 0 && x
< mapWidth
) ? xflags
[x
] : 0;
616 return (x
>= 0 && y
>= 0 && x
< mapWidth
&& y
< mapHeight
) ? bmap
[y
*mapWidth
+x
] : 0;
620 static inline void setFGTile (int x
, int y
, Uint8 tile
) {
621 if (x
>= 0 && y
>= 0 && x
< mapWidth
&& y
< mapHeight
) {
622 if (fmap
[y
*mapWidth
+x
] != tile
) {
624 fmap
[y
*mapWidth
+x
] = tile
;
630 static inline void setBGTile (int x
, int y
, Uint8 tile
) {
631 if (y
== -666 && x
>= 0 && x
< mapWidth
) xflags
[x
] = tile
;
632 if (x
>= 0 && y
>= 0 && x
< mapWidth
&& y
< mapHeight
) {
633 if (bmap
[y
*mapWidth
+x
] != tile
) {
635 bmap
[y
*mapWidth
+x
] = tile
;
641 static int mapGet (int tid
, int fg
, int x
, int y
) {
642 if (fmap
!= NULL
) return fg
? fgTile(x
, y
) : bgTile(x
, y
);
647 static void mapSet (int tid
, int fg
, int x
, int y
, int tile
) {
649 if (fg
) setFGTile(x
, y
, tile
); else setBGTile(x
, y
, tile
);
654 ////////////////////////////////////////////////////////////////////////////////
655 // cliprect should be set
656 static void levelDrawMap (SDL_Surface
*frame
) {
661 rc
.w
= VIS_WIDTH
*20*2;
662 rc
.h
= VIS_HEIGHT
*10*2;
665 int levelback
= vmGVars
[GVAR_LEVEL_BACKPIC
];
666 int scrX
= vmGVars
[GVAR_SCR_X
], scrY
= vmGVars
[GVAR_SCR_Y
];
668 if (levelback
< 1 || levelback
> 7) levelback
= 1;
669 blitSurface(frame
, 0, 0, backs
[levelback
]);
671 SDL_SetClipRect(frame
, &rc
);
672 for (int dy
= 0; dy
< VIS_HEIGHT
; ++dy
) {
673 for (int dx
= 0; dx
< VIS_WIDTH
; ++dx
) {
674 int x
= scrX
+dx
, y
= scrY
+dy
;
675 Uint8 b
= bgTile(x
, y
), f
= fgTile(x
, y
);
677 if (b
) blitSurface2x(frame
, VIS_X
+dx
*20, VIS_Y
+dy
*10, banks
[CONST_BANK_BG_TILES
].spr
[b
-1][0]);
678 if (f
) blitSurface2x(frame
, VIS_X
+dx
*20, VIS_Y
+dy
*10, banks
[CONST_BANK_FG_TILES
].spr
[f
-1][0]);
682 blitSurface(frame
, 0, 0, backs
[1]);
683 SDL_SetClipRect(frame
, &rc
);
684 for (int dy
= 0; dy
< mapHeight
; ++dy
) {
685 for (int dx
= 1; dx
< mapWidth
; ++dx
) {
686 Uint8 b
= bgTile(dx
, dy
), f
= fgTile(dx
, dy
), t
= 8;
689 if (b
>= 1 && b
<= 8) t
= b
-1; else t
= 8;
693 if (banks
[CONST_BANK_MAP_TILES
].spr
[t
][0]) {
694 blitSurface2x(frame
, VIS_X
+dx
*6, VIS_Y
+dy
*4, banks
[CONST_BANK_MAP_TILES
].spr
[t
][0]);
696 blitSurface2x(frame
, VIS_X
+dx
*6, VIS_Y
+dy
*4, banks
[CONST_BANK_MAP_TILES
].spr
[0][0]);
701 SDL_SetClipRect(frame
, NULL
);
706 static void levelDrawSprites (SDL_Surface
*frame
) {
708 int scrX
= vmGVars
[GVAR_SCR_X
], scrY
= vmGVars
[GVAR_SCR_Y
];
709 int py
= vmGetTVar(0, TVAR_POS_Y
)-scrY
;
711 for (int cc
= 0; cc
<= 2; ++cc
) {
712 for (int f
= cc
==1?1:0; f
<= vmLastThread(); ++f
) {
713 if (vmIsThreadAlive(f
) && !vmIsSuspendedThread(f
)) {
714 int b
= vmGetTVar(f
, TVAR_SPR_BANK
);
715 int s
= vmGetTVar(f
, TVAR_SPR_NUM
);
716 int d
= vmGetTVar(f
, TVAR_SPR_DIR
);
718 if (d
>= 0 && d
<= 1 && s
>= 0 && b
>= 0 && b
<= 255 && s
< banks
[b
].count
&& banks
[b
].spr
[s
][d
]) {
719 SDL_Surface
*sf
= banks
[b
].spr
[s
][d
];
720 int x
= vmGetTVar(f
, TVAR_POS_X
)-scrX
;
721 int y
= vmGetTVar(f
, TVAR_POS_Y
)-scrY
;
722 int tx
= vmGetTVar(f
, TVAR_POS_TX
);
723 int ty
= vmGetTVar(f
, TVAR_POS_TY
);
724 int si
= vmGetTVar(f
, TVAR_SPR_ITEM
);
726 if (cc
== 0 && b
== CONST_BANK_ITEMS
) continue;
727 if (cc
== 1 && b
!= CONST_BANK_ITEMS
) continue;
729 if (b
!= CONST_BANK_PROF
) {
730 if (b
!= CONST_BANK_ITEMS
) continue;
731 if (y
< py
) continue;
734 if (b
== CONST_BANK_IM_PROF
|| b
== CONST_BANK_PROF
) tx
-= 5;
735 blitSurface2x(frame
, VIS_X
+x
*20+tx
, VIS_Y
+y
*10+ty
-sf
->h
/2, sf
);
736 if (si
> 0 && si
< banks
[CONST_BANK_ITEMS
].count
) {
737 sf
= banks
[CONST_BANK_ITEMS
].spr
[si
][0];
738 blitSurface2x(frame
, VIS_X
+x
*20+tx
, VIS_Y
+y
*10+ty
-sf
->h
/2-24, sf
);
745 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]);
746 for (int f
= 1; f
< VM_MAX_THREADS
; ++f
) {
747 if (vmIsThreadAlive(f
) && !vmIsSuspendedThread(f
)) {
748 int i
= vmGetTVar(f
, TVAR_ITEM_ID
);
749 if (i
> 0 && i
<= 255) {
750 SDL_Surface
*sf
= banks
[CONST_BANK_MAP_ITEMS
].spr
[i
][0];
751 int x
= vmGetTVar(f
, TVAR_POS_X
);
752 int y
= vmGetTVar(f
, TVAR_POS_Y
);
754 blitSurface2x(frame
, VIS_X
+(x
+0)*6, VIS_Y
+(y
-2)*4, sf
);
762 static void levelDrawCode (SDL_Surface
*frame
) {
763 int pos
= vmGVars
[GVAR_LEVEL_CODE_OFS
], len
= vmGVars
[GVAR_LEVEL_CODE_LEN
], x
;
767 if (len
> 255) len
= 255;
768 if (pos
< 0 || pos
+len
> vmCodeSize
) return;
770 sprintf(buf
, "%d", curLevel
);
772 for (; len
> 0; x
+= 8, ++pos
, --len
) drawChar(frame
, vmCode
[pos
], x
, 0, 3);
776 static void levelDrawItemName (SDL_Surface
*frame
) {
777 int pos
= vmGVars
[GVAR_ITEM_NAME_OFS
], len
= vmGVars
[GVAR_ITEM_NAME_LEN
], x
= 0;
779 if (len
< 0 || len
> 32) len
= 32;
781 for (; len
> 0 && pos
< vmCodeSize
&& vmCode
[pos
]; x
+= 8, ++pos
, --len
) drawChar(frame
, vmCode
[pos
], x
, 0, 1);
784 for (; len
> 0 && pos
< levelDataSize
&& levelData
[pos
]; x
+= 8, ++pos
, --len
) drawChar(frame
, levelData
[pos
], x
, 0, 1);
789 static void levelDrawMisc (SDL_Surface
*frame
) {
790 if (demorecmode
< 0) {
791 if (SDL_GetTicks()%1000 < 500) drawChar(frame
, 'R', 0, 8, 3);
792 } else if (demorecmode
> 0) {
793 if (SDL_GetTicks()%1000 < 500) drawChar(frame
, 'D', 0, 8, 3);
798 static void drawSpriteBank (SDL_Surface
*frame
, SpriteBank
*bank
) {
800 int x
= 0, y
= 0, maxh
= 0;
802 SDL_SetClipRect(frame
, NULL
);
807 SDL_FillRect(frame
, &dst
, palette
[3]);
809 for (int num
= 0; num
< bank
->count
; ++num
) {
810 SDL_Surface
*s
= bank
->spr
[num
][0];
816 sprintf(buf
, "%d", num
);
817 if (w
< strlen(buf
)*8+2) w
= strlen(buf
)*8+2;
823 if (maxh
< s
->h
/2+1) maxh
= s
->h
/2+1;
824 blitSurface2x(frame
, x
, y
, s
);
825 drawString(frame
, buf
, x
, y
, 1);
832 static void frmGameDraw (SDL_Surface
*frame
) {
835 if (vmPaused
&& doSave
) {
837 if (loadGame() != 0) fatal("can't load game, VM is inconsistent, dying.");
843 vmPaused
= inMinimap
;
846 SDL_SetClipRect(frame
, NULL
);
851 if (redrawLevel
) levelDrawMap(backbuf
);
852 blitSurface(frame
, 0, 0, backbuf
);
854 drawString(frame
, levelname
, lnamex
, 0, 0x76);
855 levelDrawItemName(frame
);
856 levelDrawCode(frame
);
857 levelDrawMisc(frame
);
859 sprintf(buf
, "%d", curLevel
+1);
860 drawString(frame
, buf
, 320-strlen(buf
)*8, 0, 1);
864 rc
.w
= VIS_WIDTH
*20*2;
865 rc
.h
= VIS_HEIGHT
*10*2;
866 SDL_SetClipRect(frame
, &rc
);
868 levelDrawSprites(frame
);
870 SDL_SetClipRect(frame
, NULL
);
878 SDL_FillRect(frame
, &dst
, palette
[0]);
885 polymodAddPoint(10, 200-10);
886 polymodAddPoint(320-10, 200-10);
887 polymodAddPoint(10, 10);
888 polymodAddPoint(320-10, 10);
891 polymodAddPoint(10, 10);
892 polymodAddPoint(320-10, 10);
893 polymodAddPoint(10, 200-10);
895 polymodAddPoint(202, 100);
896 polymodAddPoint(200, 110);
897 polymodAddPoint(196, 120);
898 polymodAddPoint(189, 129);
899 polymodAddPoint(181, 136);
900 polymodAddPoint(170, 140);
901 polymodAddPoint(160, 142);
902 polymodAddPoint(150, 140);
903 polymodAddPoint(140, 136);
904 polymodAddPoint(131, 129);
905 polymodAddPoint(124, 120);
906 polymodAddPoint(120, 110);
907 polymodAddPoint(118, 100);
908 polymodAddPoint(120, 90);
909 polymodAddPoint(124, 79);
910 polymodAddPoint(131, 71);
911 polymodAddPoint(139, 64);
912 polymodAddPoint(150, 60);
913 polymodAddPoint(160, 58);
914 polymodAddPoint(170, 60);
915 polymodAddPoint(181, 64);
916 polymodAddPoint(189, 71);
917 polymodAddPoint(196, 79);
918 polymodAddPoint(200, 90);
921 polymodFill(frame
, 3, 50);
925 for (int f
= 84; f
<= 90; ++f
) if (fkeys
[f
-83]) drawSpriteBank(frame
, &banks
[f
]);
930 ////////////////////////////////////////////////////////////////////////////////
931 #define ROOM_SCRIPTS_MARK " room script labels starts here "
934 static void loadMapScript (ResFile
*resfile
) {
938 l
= vmLabelAddMark(ROOM_SCRIPTS_MARK
);
939 l
->value
= vmCodeSize
;
940 if ((csz
= loadCodeFile(resfile
, vmCodeSize
, 94+curLevel
)) > 1) {
946 static void unloadMapScript (void) {
947 VMLabelInfo
*l
, *ucl
;
949 while ((l
= vmFindMark(ROOM_SCRIPTS_MARK
)) != NULL
) {
950 ucl
= vmFindLabel("entry_local_room_script_onunload");
951 if (ucl
!= NULL
&& ucl
->type
== LB_CODE
) vmExecuteBSR(0, ucl
->value
, 0);
952 vmCodeSize
= l
->value
;
953 vmFreeLabelsUntilMark(ROOM_SCRIPTS_MARK
);
956 ucl
= vmFindLabel("entry_room_onunload");
957 if (ucl
!= NULL
&& ucl
->type
== LB_CODE
) vmExecuteBSR(0, ucl
->value
, 0);
961 ////////////////////////////////////////////////////////////////////////////////
962 static int loadLevelInternal (ResFile
*resfile
, int lidx
) {
966 vmGVars
[GVAR_VIS_WIDTH
] = VIS_WIDTH
;
967 vmGVars
[GVAR_VIS_HEIGHT
] = VIS_HEIGHT
;
968 vmGVars
[GVAR_ITEM_NAME_OFS
] = 0;
969 vmGVars
[GVAR_ITEM_NAME_LEN
] = 0;
972 if (levelData
!= NULL
) free(levelData
); levelData
= NULL
; levelDataSize
= 0;
973 if (bmap
!= NULL
) free(bmap
); bmap
= NULL
;
974 if (fmap
!= NULL
) free(fmap
); fmap
= NULL
;
975 if (xflags
!= NULL
) free(xflags
); xflags
= NULL
;
978 if (lidx
< 0 || lidx
> 73) return -1;
979 if ((levelData
= loadResFile(resfile
, lidx
+9, &levelDataSize
)) == NULL
) return -1;
981 loadMapScript(resfile
);
982 return levelDataSize
;
986 ////////////////////////////////////////////////////////////////////////////////
987 static void activateMinimap (void) {
995 ////////////////////////////////////////////////////////////////////////////////
996 static int gameRST (int tid
, int opcode
, int argc
, int argv
[], int *argp
[]) {
997 if (argv
[0] == CONST_FRST_MINIMAP
) {
999 } else if (argv
[0] == CONST_FRST_OPEN_LEVEL_FILE
) {
1001 //if (vmLoadArgs(tid, 2, argv, argp, argc, argv, argp) != 0) fatal("out of args");
1002 if (argc
< 2) fatal("out of args in FRST_LOAD_LEVEL");
1003 vmGVars
[GVAR_RST_RESULT
] = loadLevelInternal(&resfile
, argv
[1]);
1004 //if (goobers) fprintf(stderr, "FRST_OPEN_LEVEL_FILE(%d): %d\n", argv[1], vmGVars[GVAR_RST_RESULT]);
1005 } else if (argv
[0] == CONST_FRST_GET_LEVEL_DATA_SIZE
) {
1006 vmGVars
[GVAR_RST_RESULT
] = levelDataSize
;
1007 } else if (argv
[0] == CONST_FRST_GET_LEVEL_LOADER
) {
1008 VMLabelInfo
*ucl
= vmFindLabel("entry_local_room_loader");
1010 vmGVars
[GVAR_RST_RESULT
] = (ucl
!= NULL
&& ucl
->type
== LB_CODE
) ? ucl
->value
: -1;
1011 } else if (argv
[0] == CONST_FRST_GET_LEVEL_INITER
) {
1012 VMLabelInfo
*ucl
= vmFindLabel("entry_local_room_onload");
1014 vmGVars
[GVAR_RST_RESULT
] = (ucl
!= NULL
&& ucl
->type
== LB_CODE
) ? ucl
->value
: -1;
1015 } else if (argv
[0] == CONST_FRST_GET_LEVEL_FILE_BYTE
) {
1016 if (argc
< 2) fatal("out of args in FRST_GET_LEVEL_FILE_BYTE");
1017 if (argv
[1] < 0 || argv
[1] >= levelDataSize
) fatal("invalid offset in FRST_GET_LEVEL_FILE_BYTE: %d", argv
[1]);
1018 vmGVars
[GVAR_RST_RESULT
] = levelData
[argv
[1]];
1019 } else if (argv
[0] == CONST_FRST_GET_LEVEL_FILE_WORD
) {
1020 if (argc
< 2) fatal("out of args in FRST_GET_LEVEL_FILE_WORD");
1021 if (argv
[1] < 0 || argv
[1]+1 >= levelDataSize
) fatal("invalid offset in FRST_GET_LEVEL_FILE_WORD: %d", argv
[1]);
1022 vmGVars
[GVAR_RST_RESULT
] = levelData
[argv
[1]+1];
1023 vmGVars
[GVAR_RST_RESULT
] <<= 8;
1024 vmGVars
[GVAR_RST_RESULT
] |= levelData
[argv
[1]];
1025 if (vmGVars
[GVAR_RST_RESULT
] >= 32768) vmGVars
[GVAR_RST_RESULT
] -= 65536;
1026 } else if (argv
[0] == CONST_FRST_SET_LEVEL_SIZE
) {
1029 if (argc
!= 3) fatal("out of args in FRST_SET_LEVEL_SIZE");
1032 if (w
< 1 || w
> 32700 || h
< 1 || h
> 32700) fatal("invalid dimensions in FRST_SET_LEVEL_SIZE: %dx%d", w
, h
);
1033 if (bmap
!= NULL
) free(bmap
); bmap
= NULL
;
1034 if (fmap
!= NULL
) free(fmap
); fmap
= NULL
;
1035 if (xflags
!= NULL
) free(xflags
); xflags
= NULL
;
1036 fmap
= calloc(w
*h
, 1); if (fmap
== NULL
) fatal("out of memory in FRST_SET_LEVEL_SIZE");
1037 bmap
= calloc(w
*h
, 1); if (bmap
== NULL
) fatal("out of memory in FRST_SET_LEVEL_SIZE");
1038 xflags
= calloc(w
, 1); if (xflags
== NULL
) fatal("out of memory in FRST_SET_LEVEL_SIZE");
1039 mapWidth
= vmGVars
[GVAR_MAP_WIDTH
] = w
;
1040 mapHeight
= vmGVars
[GVAR_MAP_HEIGHT
] = h
;
1044 } else if (argv
[0] == CONST_FRST_SET_LEVEL_NAME
) {
1045 int pos
= 0, len
= sizeof(levelname
)-1, lp
= 0;
1049 case 1: fatal("out of args in FRST_SET_LEVEL_NAME");
1050 case 2: pos
= argv
[1]; break;
1051 case 3: pos
= argv
[1]; len
= argv
[2]; break;
1053 memset(levelname
, 0, sizeof(levelname
));
1054 if (len
> sizeof(levelname
)-1) len
= sizeof(levelname
)-1;
1056 while (len
> 0 && pos
< vmCodeSize
&& vmCode
[pos
]) {
1057 levelname
[lp
++] = vmCode
[pos
++];
1062 while (len
> 0 && pos
< levelDataSize
&& levelData
[pos
]) {
1063 levelname
[lp
++] = levelData
[pos
++];
1067 lnamex
= (320-strlen(levelname
)*8)/2;
1068 sprintf(buf
, "%d", curLevel
+1);
1069 while (lnamex
+strlen(levelname
)*8+strlen(buf
)*8+6*8 > 320) lnamex
-= 8;
1071 if (gameRSTCB
) return gameRSTCB(tid
, opcode
, argc
, argv
, argp
);
1072 fatal("invalid RST: %d", argv
[0]);
1074 return 0; // continue
1078 ////////////////////////////////////////////////////////////////////////////////
1079 void setMainLoopGame (void) {
1080 frameCB
= frmGameDraw
;
1082 gameRSTCB
= gameRST
;
1083 beforeVMCB
= demoCB
;
1084 vmMapGetCB
= mapGet
;
1085 vmMapSetCB
= mapSet
;
1087 setSeed(time(NULL
));
1095 memset(fkeys
, 0, sizeof(fkeys
));
1096 memset(gamekeys
, 0, sizeof(gamekeys
));