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];
54 static char levelcode
[257];
55 static char itemname
[257];
57 static Uint8
*levelData
= NULL
;
58 static int levelDataSize
= 0;
59 static Uint8
*bmap
= NULL
, *fmap
= NULL
;
60 static Uint8
*xflags
= NULL
;
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];
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 ////////////////////////////////////////////////////////////////////////////////
107 static int readBuf (FILE *fl
, void *buf
, int len
) {
108 unsigned char *c
= (unsigned char *)buf
;
113 if (fread(&b
, 1, 1, fl
) != 1) return -1;
121 static int writeBuf (FILE *fl
, const void *buf
, int len
) {
122 const unsigned char *c
= (const unsigned char *)buf
;
125 unsigned char b
= *c
++;
128 if (fwrite(&b
, 1, 1, fl
) != 1) return -1;
134 static int readDW (FILE *fl
, int *v
) {
137 for (int f
= 0; f
< 4; ++f
) {
140 if (fread(&b
, 1, 1, fl
) != 1) return -1;
146 for (int f
= 0; f
< 4; ++f
) *v
|= t
[f
]<<(8*f
);
152 static int writeDW (FILE *fl
, int v
) {
153 for (int f
= 0; f
< 4; ++f
) {
158 if (fwrite(&b
, 1, 1, fl
) != 1) return -1;
165 static int readUDW (FILE *fl
, Uint32
*v
) {
168 for (int f
= 0; f
< 4; ++f
) {
171 if (fread(&b
, 1, 1, fl
) != 1) return -1;
177 for (int f
= 0; f
< 4; ++f
) *v
|= t
[f
]<<(8*f
);
183 static int writeUDW (FILE *fl
, Uint32 v
) {
184 for (int f
= 0; f
< 4; ++f
) {
189 if (fwrite(&b
, 1, 1, fl
) != 1) return -1;
196 ////////////////////////////////////////////////////////////////////////////////
197 static const char *SAVE_GAME_SIGNATURE
= "ASG1";
200 static int saveGame (void) {
201 FILE *fl
= fopen("awish.sav", "wb");
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
;
227 if (goobers
) fprintf(stderr
, "error saving game\n");
232 static int loadGame (void) {
233 FILE *fl
= fopen("awish.sav", "rb");
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
;
264 oldScrX
= oldScrY
= -1;
269 if (goobers
) fprintf(stderr
, "error loading saved game\n");
274 ////////////////////////////////////////////////////////////////////////////////
275 static void demoClear (void) {
279 demoPrevKeyState
= 0;
280 demoKeyStateRepeats
= 0;
281 if (demoData
!= NULL
) free(demoData
);
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!");
296 demoData
[demoPos
++] = b
;
300 static Uint8
demoGetKeyState (void) {
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;
338 ++demoKeyStateRepeats
;
343 static void demoGetFrameData (void) {
344 while (demoKeyStateRepeats
< 1) {
345 if (demoPos
+2 > demoSize
) {
348 if (goobers
) fprintf(stderr
, "demo complete\n");
349 strcpy(message
, "demo stopped");
352 demoKeyStateRepeats
= demoData
[demoPos
++];
353 ++demoKeyStateRepeats
;
354 demoPrevKeyState
= demoData
[demoPos
++];
356 --demoKeyStateRepeats
;
358 demoSetKeyState(demoPrevKeyState
);
362 static int demoSave (void) {
367 if (demoKeyStateRepeats
> 0) {
368 demoAddByte(demoKeyStateRepeats
-1);
369 demoAddByte(demoPrevKeyState
);
372 sprintf(buf
, "awish%02d.dmo", curLevel
+1);
373 fl
= fopen(buf
, "wb");
375 if (goobers
) fprintf(stderr
, "can't create demo file '%s'\n", buf
);
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
;
386 if (goobers
) fprintf(stderr
, "demo saved to file '%s'\n", buf
);
391 if (goobers
) fprintf(stderr
, "can't write demo file '%s'\n", buf
);
396 static int demoLoad (void) {
403 sprintf(buf
, "awish%02d.dmo", curLevel
+1);
404 fl
= fopen(buf
, "rb");
406 if (goobers
) fprintf(stderr
, "can't open demo file '%s'\n", buf
);
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
;
425 if (goobers
) fprintf(stderr
, "loaded demo file '%s'\n", buf
);
430 if (goobers
) fprintf(stderr
, "can't load demo file '%s'\n", buf
);
436 static inline int isGameStopped (void) {
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
];
452 switch (demorecmode
) {
453 case -666: // prepare to load demo
454 if (demoLoad() != 0) {
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) {
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();
477 ((demorecmode
< 0) ? demoGetFrameData
: demoAddFrameData
)();
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) {
490 demo_m_w
= getSeedL();
491 demo_m_z
= getSeedH();
493 demorecmode
= (demorecmode
< 0) ? -1 : 1;
501 ////////////////////////////////////////////////////////////////////////////////
502 static void frmGameKey (SDL_KeyboardEvent
*key
) {
503 if (key
->type
== SDL_KEYDOWN
) {
504 switch (key
->keysym
.sym
) {
508 if (vmPaused
&& inMinimap
) {
517 vmGVars
[GVAR_KEY_QUIT
] = 1;
534 if (demorecmode
!= 0) { demoClear(); demorecmode
= 0; }
535 if ((key
->keysym
.mod
&(KMOD_CTRL
)) != 0) {
541 if (vmPaused
== 0 && !demorecmode
) {
542 if (goobers
&& (key
->keysym
.mod
&(KMOD_CTRL
)) != 0) { doSave
= 1; vmPaused
= 1; }
546 if (vmPaused
== 0 && !demorecmode
) {
547 if (goobers
&& (key
->keysym
.mod
&(KMOD_CTRL
)) != 0) { doSave
= -1; vmPaused
= 1; }
552 if (goobers
&& (key
->keysym
.mod
&(KMOD_CTRL
)) != 0) {
554 demorecmode
= 666; // 'start saving'
565 if (goobers
&& (key
->keysym
.mod
&(KMOD_CTRL
)) != 0) {
567 demorecmode
= -666; // 'start playing'
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;
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;
614 static void frmMouse (int x
, int y
, int buttons
) {
615 vmGVars
[GVAR_MOUSE_X
] = x
;
616 vmGVars
[GVAR_MOUSE_Y
] = y
;
617 vmGVars
[GVAR_MOUSE_BUTTONS
] = buttons
;
621 ////////////////////////////////////////////////////////////////////////////////
622 static inline Uint8
fgTile (int x
, int y
) {
623 return (x
>= 0 && y
>= 0 && x
< mapWidth
&& y
< mapHeight
) ? fmap
[y
*mapWidth
+x
] : 0;
627 static inline Uint8
bgTile (int x
, int y
) {
628 if (y
== -666) return (x
>= 0 && x
< mapWidth
) ? xflags
[x
] : 0;
629 return (x
>= 0 && y
>= 0 && x
< mapWidth
&& y
< mapHeight
) ? bmap
[y
*mapWidth
+x
] : 0;
633 static inline void setFGTile (int x
, int y
, Uint8 tile
) {
634 if (x
>= 0 && y
>= 0 && x
< mapWidth
&& y
< mapHeight
) {
635 if (fmap
[y
*mapWidth
+x
] != tile
) {
637 fmap
[y
*mapWidth
+x
] = tile
;
643 static inline void setBGTile (int x
, int y
, Uint8 tile
) {
644 if (y
== -666 && x
>= 0 && x
< mapWidth
) xflags
[x
] = tile
;
645 if (x
>= 0 && y
>= 0 && x
< mapWidth
&& y
< mapHeight
) {
646 if (bmap
[y
*mapWidth
+x
] != tile
) {
648 bmap
[y
*mapWidth
+x
] = tile
;
654 static int mapGet (int tid
, int fg
, int x
, int y
) {
655 if (fmap
!= NULL
) return fg
? fgTile(x
, y
) : bgTile(x
, y
);
660 static void mapSet (int tid
, int fg
, int x
, int y
, int tile
) {
662 if (fg
) setFGTile(x
, y
, tile
); else setBGTile(x
, y
, tile
);
667 ////////////////////////////////////////////////////////////////////////////////
668 // cliprect should be set
669 static void levelDrawMap (SDL_Surface
*frame
) {
674 rc
.w
= VIS_WIDTH
*20*2;
675 rc
.h
= VIS_HEIGHT
*10*2;
678 int levelback
= vmGVars
[GVAR_LEVEL_BACKPIC
];
679 int scrX
= vmGVars
[GVAR_SCR_X
], scrY
= vmGVars
[GVAR_SCR_Y
];
681 if (levelback
< 1 || levelback
> 7) levelback
= 1;
682 blitSurface(frame
, 0, 0, backs
[levelback
]);
684 SDL_SetClipRect(frame
, &rc
);
685 for (int dy
= 0; dy
< VIS_HEIGHT
; ++dy
) {
686 for (int dx
= 0; dx
< VIS_WIDTH
; ++dx
) {
687 int x
= scrX
+dx
, y
= scrY
+dy
;
688 Uint8 b
= bgTile(x
, y
), f
= fgTile(x
, y
);
690 if (b
) blitSurface2x(frame
, VIS_X
+dx
*20, VIS_Y
+dy
*10, banks
[CONST_BANK_BG_TILES
].spr
[b
-1][0]);
691 if (f
) blitSurface2x(frame
, VIS_X
+dx
*20, VIS_Y
+dy
*10, banks
[CONST_BANK_FG_TILES
].spr
[f
-1][0]);
695 blitSurface(frame
, 0, 0, backs
[1]);
696 SDL_SetClipRect(frame
, &rc
);
697 for (int dy
= 0; dy
< mapHeight
; ++dy
) {
698 for (int dx
= 1; dx
< mapWidth
; ++dx
) {
699 Uint8 b
= bgTile(dx
, dy
), f
= fgTile(dx
, dy
), t
= 8;
702 if (b
>= 1 && b
<= 8) t
= b
-1; else t
= 8;
706 if (banks
[CONST_BANK_MAP_TILES
].spr
[t
][0]) {
707 blitSurface2x(frame
, VIS_X
+dx
*6, VIS_Y
+dy
*4, banks
[CONST_BANK_MAP_TILES
].spr
[t
][0]);
709 blitSurface2x(frame
, VIS_X
+dx
*6, VIS_Y
+dy
*4, banks
[CONST_BANK_MAP_TILES
].spr
[0][0]);
714 SDL_SetClipRect(frame
, NULL
);
719 static void levelDrawSprites (SDL_Surface
*frame
) {
721 int scrX
= vmGVars
[GVAR_SCR_X
], scrY
= vmGVars
[GVAR_SCR_Y
];
722 int py
= vmGetTVar(0, TVAR_POS_Y
)-scrY
;
724 for (int cc
= 0; cc
<= 2; ++cc
) {
725 for (int f
= cc
==1?1:0; f
<= vmLastThread(); ++f
) {
726 if (vmIsThreadAlive(f
) && !vmIsSuspendedThread(f
)) {
727 int b
= vmGetTVar(f
, TVAR_SPR_BANK
);
728 int s
= vmGetTVar(f
, TVAR_SPR_NUM
);
729 int d
= vmGetTVar(f
, TVAR_SPR_DIR
);
731 if (d
>= 0 && d
<= 1 && s
>= 0 && b
>= 0 && b
<= 255 && s
< banks
[b
].count
&& banks
[b
].spr
[s
][d
]) {
732 SDL_Surface
*sf
= banks
[b
].spr
[s
][d
];
733 int x
= vmGetTVar(f
, TVAR_POS_X
)-scrX
;
734 int y
= vmGetTVar(f
, TVAR_POS_Y
)-scrY
;
735 int tx
= vmGetTVar(f
, TVAR_POS_TX
);
736 int ty
= vmGetTVar(f
, TVAR_POS_TY
);
737 int si
= vmGetTVar(f
, TVAR_SPR_ITEM
);
739 if (cc
== 0 && b
== CONST_BANK_ITEMS
) continue;
740 if (cc
== 1 && b
!= CONST_BANK_ITEMS
) continue;
742 if (b
!= CONST_BANK_PROF
) {
743 if (b
!= CONST_BANK_ITEMS
) continue;
744 if (y
< py
) continue;
747 if (b
== CONST_BANK_IM_PROF
|| b
== CONST_BANK_PROF
) tx
-= 5;
748 blitSurface2x(frame
, VIS_X
+x
*20+tx
, VIS_Y
+y
*10+ty
-sf
->h
/2, sf
);
749 if (si
> 0 && si
< banks
[CONST_BANK_ITEMS
].count
) {
750 sf
= banks
[CONST_BANK_ITEMS
].spr
[si
][0];
751 blitSurface2x(frame
, VIS_X
+x
*20+tx
, VIS_Y
+y
*10+ty
-sf
->h
/2-24, sf
);
758 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]);
759 for (int f
= 1; f
< VM_MAX_THREADS
; ++f
) {
760 if (vmIsThreadAlive(f
) && !vmIsSuspendedThread(f
)) {
761 int i
= vmGetTVar(f
, TVAR_ITEM_ID
);
762 if (i
> 0 && i
<= 255) {
763 SDL_Surface
*sf
= banks
[CONST_BANK_MAP_ITEMS
].spr
[i
][0];
764 int x
= vmGetTVar(f
, TVAR_POS_X
);
765 int y
= vmGetTVar(f
, TVAR_POS_Y
);
767 blitSurface2x(frame
, VIS_X
+(x
+0)*6, VIS_Y
+(y
-2)*4, sf
);
775 static void levelDrawName (SDL_Surface
*frame
) {
776 drawString(frame
, levelname
, lnamex
, 0, 0x76);
780 static void levelDrawNumber (SDL_Surface
*frame
) {
783 sprintf(buf
, "%d", curLevel
+1);
784 drawString(frame
, buf
, 320-strlen(buf
)*8, 0, 1);
788 static void levelDrawCode (SDL_Surface
*frame
) {
791 sprintf(buf
, "%d", curLevel
+1);
792 drawString(frame
, levelcode
, 320-strlen(levelcode
)*8-strlen(buf
)*8, 0, 3);
796 static void levelDrawItemName (SDL_Surface
*frame
) {
797 drawString(frame
, itemname
, 0, 0, 1);
801 static void levelDrawMisc (SDL_Surface
*frame
) {
802 if (demorecmode
< 0) {
803 if (SDL_GetTicks()%1000 < 500) drawChar(frame
, 'R', 0, 8, 3);
804 } else if (demorecmode
> 0) {
805 if (SDL_GetTicks()%1000 < 500) drawChar(frame
, 'D', 0, 8, 3);
810 static void drawSpriteBank (SDL_Surface
*frame
, SpriteBank
*bank
) {
812 int x
= 0, y
= 0, maxh
= 0;
814 SDL_SetClipRect(frame
, NULL
);
819 SDL_FillRect(frame
, &dst
, palette
[3]);
821 for (int num
= 0; num
< bank
->count
; ++num
) {
822 SDL_Surface
*s
= bank
->spr
[num
][0];
828 if (gamekeys
[4] || gamekeys
[5]) {
830 sprintf(buf
, "%d", num
);
831 if (w
< strlen(buf
)*8+2) w
= strlen(buf
)*8+2;
838 if (maxh
< s
->h
/2+1) maxh
= s
->h
/2+1;
839 blitSurface2x(frame
, x
, y
, s
);
840 if (gamekeys
[4] || gamekeys
[5]) drawString(frame
, buf
, x
, y
, 1);
847 static void drawPalette (SDL_Surface
*frame
) {
850 SDL_SetClipRect(frame
, NULL
);
855 SDL_FillRect(frame
, &dst
, palette
[0]);
857 for (int y
= 0; y
< 16; ++y
) {
858 for (int x
= 0; x
< 16; ++x
) {
863 SDL_FillRect(frame
, &dst
, palette
[y
*16+x
]);
864 if (gamekeys
[4] || gamekeys
[5]) {
867 sprintf(buf
, "%d", y
*16+x
);
868 drawString(frame
, buf
, x
*20, y
*20, 1);
875 static void frmGameDraw (SDL_Surface
*frame
) {
878 if (vmPaused
&& doSave
) {
880 if (loadGame() != 0) fatal("can't load game, VM is inconsistent, dying.");
886 vmPaused
= inMinimap
;
889 SDL_SetClipRect(frame
, NULL
);
893 levelDrawMap(backbuf
);
894 levelDrawName(backbuf
);
895 levelDrawNumber(backbuf
);
896 levelDrawCode(backbuf
);
897 levelDrawItemName(backbuf
);
899 blitSurface(frame
, 0, 0, backbuf
);
900 levelDrawMisc(frame
);
904 rc
.w
= VIS_WIDTH
*20*2;
905 rc
.h
= VIS_HEIGHT
*10*2;
906 SDL_SetClipRect(frame
, &rc
);
907 levelDrawSprites(frame
);
908 SDL_SetClipRect(frame
, NULL
);
914 SDL_FillRect(frame
, &rc
, palette
[0]);
918 static int angle
= 0;
920 static int multdir
= 1;
923 angle
= (angle
+1)%360;
925 if (mult
< 2 || mult
> 50) multdir
= -multdir
;
926 //fprintf(stderr, "a=%d\n", angle);
930 polymodStart(320/2, 200/2, (mult
+20)*POLYFIX_BASE
/50, angle
);
933 polymodAddPoint(-20, -20);
934 polymodAddPoint(20, -20);
935 polymodAddPoint(20, 20);
936 polymodAddPoint(-20, 20);
939 polymodAddPoint(-10, -10);
940 polymodAddPoint(20, -10);
941 polymodAddPoint(-10, 20);
942 polymodAddPoint(20, 20);
945 polymodAddPoint(36, 0);
946 polymodAddPoint(46, 12);
947 polymodAddPoint(31, 17);
948 polymodAddPoint(33, 33);
949 polymodAddPoint(18, 31);
950 polymodAddPoint(12, 46);
951 polymodAddPoint(0, 36);
952 polymodAddPoint(-12, 46);
953 polymodAddPoint(-17, 31);
954 polymodAddPoint(-33, 33);
955 polymodAddPoint(-31, 17);
956 polymodAddPoint(-46, 12);
957 polymodAddPoint(-36, 0);
958 polymodAddPoint(-46, -12);
959 polymodAddPoint(-31, -18);
960 polymodAddPoint(-33, -33);
961 polymodAddPoint(-18, -31);
962 polymodAddPoint(-12, -46);
963 polymodAddPoint(0, -36);
964 polymodAddPoint(12, -46);
965 polymodAddPoint(18, -31);
966 polymodAddPoint(33, -33);
967 polymodAddPoint(31, -18);
968 polymodAddPoint(46, -12);
971 polymodAddPoint(42, 0);
972 polymodAddPoint(40, 10);
973 polymodAddPoint(36, 20);
974 polymodAddPoint(29, 29);
975 polymodAddPoint(21, 36);
976 polymodAddPoint(10, 40);
977 polymodAddPoint(0, 42);
978 polymodAddPoint(-10, 40);
979 polymodAddPoint(-20, 36);
980 polymodAddPoint(-29, 29);
981 polymodAddPoint(-36, 20);
982 polymodAddPoint(-40, 10);
983 polymodAddPoint(-42, 0);
984 polymodAddPoint(-40, -10);
985 polymodAddPoint(-36, -21);
986 polymodAddPoint(-29, -29);
987 polymodAddPoint(-21, -36);
988 polymodAddPoint(-10, -40);
989 polymodAddPoint(0, -42);
990 polymodAddPoint(10, -40);
991 polymodAddPoint(21, -36);
992 polymodAddPoint(29, -29);
993 polymodAddPoint(36, -21);
994 polymodAddPoint(40, -10);
998 polymodFill(frame
, 3, 100);
1002 for (int f
= 84; f
<= 90; ++f
) if (fkeys
[f
-83]) drawSpriteBank(frame
, &banks
[f
]);
1003 if (fkeys
[8]) drawPalette(frame
);
1005 if (vmGVars
[GVAR_MOUSE_HIDDEN
] == 0) {
1006 int cur
= vmGVars
[GVAR_MOUSE_CURSOR
];
1008 if (cur
>= 0 && cur
< banks
[256].count
) {
1009 blitSurface2x(frame
, vmGVars
[GVAR_MOUSE_X
], vmGVars
[GVAR_MOUSE_Y
], banks
[256].spr
[cur
][0]);
1015 ////////////////////////////////////////////////////////////////////////////////
1016 #define ROOM_SCRIPTS_MARK " room script labels starts here "
1019 static void loadMapScript (ResFile
*resfile
) {
1023 l
= vmLabelAddMark(ROOM_SCRIPTS_MARK
);
1024 l
->value
= vmCodeSize
;
1025 if ((csz
= loadCodeFile(resfile
, vmCodeSize
, 94+curLevel
, 1)) > 1) {
1031 static void unloadMapScript (void) {
1032 VMLabelInfo
*l
, *ucl
;
1034 while ((l
= vmFindMark(ROOM_SCRIPTS_MARK
)) != NULL
) {
1035 ucl
= vmFindLabel("entry_local_room_script_onunload");
1036 if (ucl
!= NULL
&& ucl
->type
== LB_CODE
) vmExecuteBSR(0, ucl
->value
, 0);
1037 vmCodeSize
= l
->value
;
1038 vmFreeLabelsUntilMark(ROOM_SCRIPTS_MARK
);
1041 ucl
= vmFindLabel("entry_goobers_room_onunload");
1042 if (ucl
!= NULL
&& ucl
->type
== LB_CODE
) vmExecuteBSR(0, ucl
->value
, 0);
1044 ucl
= vmFindLabel("entry_room_onunload");
1045 if (ucl
!= NULL
&& ucl
->type
== LB_CODE
) vmExecuteBSR(0, ucl
->value
, 0);
1049 ////////////////////////////////////////////////////////////////////////////////
1050 static int loadLevelInternal (ResFile
*resfile
, int lidx
) {
1054 vmGVars
[GVAR_VIS_WIDTH
] = VIS_WIDTH
;
1055 vmGVars
[GVAR_VIS_HEIGHT
] = VIS_HEIGHT
;
1056 levelname
[0] = levelcode
[0] = itemname
[0] = 0;
1058 if (levelData
!= NULL
) free(levelData
); levelData
= NULL
; levelDataSize
= 0;
1059 if (bmap
!= NULL
) free(bmap
); bmap
= NULL
;
1060 if (fmap
!= NULL
) free(fmap
); fmap
= NULL
;
1061 if (xflags
!= NULL
) free(xflags
); xflags
= NULL
;
1064 if (lidx
< 0 || lidx
> 73) return -1;
1065 if ((levelData
= loadResFile(resfile
, lidx
+9, &levelDataSize
)) == NULL
) return -1;
1067 loadMapScript(resfile
);
1068 return levelDataSize
;
1072 ////////////////////////////////////////////////////////////////////////////////
1073 static void activateMinimap (void) {
1081 ////////////////////////////////////////////////////////////////////////////////
1082 static void getVMString (char *dest
, int destsize
, int argc
, int argv
[]) {
1084 int pos
= 0, len
= destsize
-1, lp
= 0;
1087 case 1: fatal("out of args in FRST_SET_LEVEL_NAME");
1088 case 2: pos
= argv
[1]; break;
1089 case 3: pos
= argv
[1]; len
= argv
[2]; break;
1091 memset(dest
, 0, destsize
);
1092 if (len
< 0) len
= destsize
-1;
1093 if (len
> destsize
-1) len
= destsize
-1;
1095 while (len
> 0 && pos
< vmCodeSize
&& vmCode
[pos
]) {
1096 dest
[lp
++] = vmCode
[pos
++];
1101 while (len
> 0 && pos
< levelDataSize
&& levelData
[pos
]) {
1102 dest
[lp
++] = levelData
[pos
++];
1106 } else if (destsize
== 1) {
1112 static int gameRST (int tid
, int opcode
, int argc
, int argv
[], int *argp
[]) {
1113 if (argv
[0] == CONST_FRST_MINIMAP
) {
1115 } else if (argv
[0] == CONST_FRST_OPEN_LEVEL_FILE
) {
1117 //if (vmLoadArgs(tid, 2, argv, argp, argc, argv, argp) != 0) fatal("out of args");
1118 if (argc
< 2) fatal("out of args in FRST_LOAD_LEVEL");
1119 vmGVars
[GVAR_RST_RESULT
] = loadLevelInternal(&resfile
, argv
[1]);
1120 //if (goobers) fprintf(stderr, "FRST_OPEN_LEVEL_FILE(%d): %d\n", argv[1], vmGVars[GVAR_RST_RESULT]);
1121 } else if (argv
[0] == CONST_FRST_GET_LEVEL_DATA_SIZE
) {
1122 vmGVars
[GVAR_RST_RESULT
] = levelDataSize
;
1123 } else if (argv
[0] == CONST_FRST_GET_LEVEL_LOADER
) {
1124 VMLabelInfo
*ucl
= vmFindLabel("entry_local_room_loader");
1126 vmGVars
[GVAR_RST_RESULT
] = (ucl
!= NULL
&& ucl
->type
== LB_CODE
) ? ucl
->value
: -1;
1127 } else if (argv
[0] == CONST_FRST_GET_LEVEL_INITER
) {
1128 VMLabelInfo
*ucl
= vmFindLabel("entry_local_room_onload");
1130 vmGVars
[GVAR_RST_RESULT
] = (ucl
!= NULL
&& ucl
->type
== LB_CODE
) ? ucl
->value
: -1;
1131 } else if (argv
[0] == CONST_FRST_GET_GOOBERS_INITER
) {
1132 VMLabelInfo
*ucl
= vmFindLabel("entry_goobers_game_init");
1134 vmGVars
[GVAR_RST_RESULT
] = (ucl
!= NULL
&& ucl
->type
== LB_CODE
) ? ucl
->value
: -1;
1135 } else if (argv
[0] == CONST_FRST_GET_GOOBERS_ONLOAD
) {
1136 VMLabelInfo
*ucl
= vmFindLabel("entry_goobers_room_onload");
1138 vmGVars
[GVAR_RST_RESULT
] = (ucl
!= NULL
&& ucl
->type
== LB_CODE
) ? ucl
->value
: -1;
1139 } else if (argv
[0] == CONST_FRST_GET_LEVEL_FILE_BYTE
) {
1140 if (argc
< 2) fatal("out of args in FRST_GET_LEVEL_FILE_BYTE");
1141 if (argv
[1] < 0 || argv
[1] >= levelDataSize
) fatal("invalid offset in FRST_GET_LEVEL_FILE_BYTE: %d", argv
[1]);
1142 vmGVars
[GVAR_RST_RESULT
] = levelData
[argv
[1]];
1143 } else if (argv
[0] == CONST_FRST_GET_LEVEL_FILE_WORD
) {
1144 if (argc
< 2) fatal("out of args in FRST_GET_LEVEL_FILE_WORD");
1145 if (argv
[1] < 0 || argv
[1]+1 >= levelDataSize
) fatal("invalid offset in FRST_GET_LEVEL_FILE_WORD: %d", argv
[1]);
1146 vmGVars
[GVAR_RST_RESULT
] = levelData
[argv
[1]+1];
1147 vmGVars
[GVAR_RST_RESULT
] <<= 8;
1148 vmGVars
[GVAR_RST_RESULT
] |= levelData
[argv
[1]];
1149 if (vmGVars
[GVAR_RST_RESULT
] >= 32768) vmGVars
[GVAR_RST_RESULT
] -= 65536;
1150 } else if (argv
[0] == CONST_FRST_SET_LEVEL_SIZE
) {
1153 if (argc
!= 3) fatal("out of args in FRST_SET_LEVEL_SIZE");
1156 if (w
< 1 || w
> 32700 || h
< 1 || h
> 32700) fatal("invalid dimensions in FRST_SET_LEVEL_SIZE: %dx%d", w
, h
);
1157 if (bmap
!= NULL
) free(bmap
); bmap
= NULL
;
1158 if (fmap
!= NULL
) free(fmap
); fmap
= NULL
;
1159 if (xflags
!= NULL
) free(xflags
); xflags
= NULL
;
1160 fmap
= calloc(w
*h
, 1); if (fmap
== NULL
) fatal("out of memory in FRST_SET_LEVEL_SIZE");
1161 bmap
= calloc(w
*h
, 1); if (bmap
== NULL
) fatal("out of memory in FRST_SET_LEVEL_SIZE");
1162 xflags
= calloc(w
, 1); if (xflags
== NULL
) fatal("out of memory in FRST_SET_LEVEL_SIZE");
1163 mapWidth
= vmGVars
[GVAR_MAP_WIDTH
] = w
;
1164 mapHeight
= vmGVars
[GVAR_MAP_HEIGHT
] = h
;
1168 } else if (argv
[0] == CONST_FRST_SET_LEVEL_NAME
) {
1171 getVMString(levelname
, sizeof(levelname
), argc
, argv
);
1172 lnamex
= (320-strlen(levelname
)*8)/2;
1173 sprintf(buf
, "%d", curLevel
+1);
1174 while (lnamex
+strlen(levelname
)*8+strlen(buf
)*8+6*8 > 320) lnamex
-= 8;
1176 } else if (argv
[0] == CONST_FRST_SET_LEVEL_CODE
) {
1177 getVMString(levelcode
, sizeof(levelcode
), argc
, argv
);
1179 } else if (argv
[0] == CONST_FRST_SET_ITEM_NAME
) {
1180 getVMString(itemname
, sizeof(itemname
), argc
, argv
);
1183 if (gameRSTCB
) return gameRSTCB(tid
, opcode
, argc
, argv
, argp
);
1184 fatal("invalid RST: %d", argv
[0]);
1186 return 0; // continue
1190 ////////////////////////////////////////////////////////////////////////////////
1191 void setMainLoopGame (void) {
1192 frameCB
= frmGameDraw
;
1195 gameRSTCB
= gameRST
;
1196 beforeVMCB
= demoCB
;
1197 vmMapGetCB
= mapGet
;
1198 vmMapSetCB
= mapSet
;
1200 setSeed(time(NULL
));
1205 levelname
[0] = levelcode
[0] = itemname
[0] = 0;
1209 memset(fkeys
, 0, sizeof(fkeys
));
1210 memset(gamekeys
, 0, sizeof(gamekeys
));