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 #define MAP_WIDTH (44)
37 #define MAP_HEIGHT (41)
38 #define VIS_WIDTH (15)
39 #define VIS_HEIGHT (17)
44 ////////////////////////////////////////////////////////////////////////////////
45 static const char *itemNames
[] = {
77 int type
; // 0: inactive
79 int frame
; // animation frame
80 int fframe
, lframe
; // first and last anim frame
86 ////////////////////////////////////////////////////////////////////////////////
88 static char levelname
[257];
91 static Uint8 bmap
[MAP_HEIGHT
][MAP_WIDTH
];
92 static Uint8 fmap
[MAP_HEIGHT
][MAP_WIDTH
];
93 static Uint8 xflags
[MAP_WIDTH
];
97 static int doSave
= 0;
99 static int demorecmode
= 0; // 0: none; 1: recording; -1: playing
100 static int demoSize
= 0;
101 static int demoPos
= 0;
102 static Uint8
*demoData
= NULL
;
103 static Uint8 demoPrevKeyState
= 0;
104 static int demoKeyStateRepeats
= 0;
106 static char message
[256];
107 //static Uint32 msgEndTime = 0;
109 static Uint32 demo_m_w
= 0;
110 static Uint32 demo_m_z
= 0;
113 ////////////////////////////////////////////////////////////////////////////////
114 static int gamekeys
[12];
117 static void setGameKeysGVars (void) {
118 vmGVars
[GVAR_KEY_LEFT
] = gamekeys
[0] ? 1 : 0;
119 vmGVars
[GVAR_KEY_RIGHT
] = gamekeys
[1] ? 1 : 0;
120 vmGVars
[GVAR_KEY_UP
] = gamekeys
[2] ? 1 : 0;
121 vmGVars
[GVAR_KEY_DOWN
] = gamekeys
[3] ? 1 : 0;
122 vmGVars
[GVAR_KEY_TAKE
] = gamekeys
[4] ? 1 : 0;
123 vmGVars
[GVAR_KEY_USE
] = gamekeys
[5] ? 1 : 0;
125 vmGVars
[GVAR_KEY_MINIMAP
] = gamekeys
[6] ? 1 : 0;
126 vmGVars
[GVAR_KEY_RESTART
] = gamekeys
[7] ? 1 : 0;
128 vmGVars
[GVAR_KEY_FALL_CHEAT
] = gamekeys
[8] ? 1 : 0;
129 vmGVars
[GVAR_KEY_WALK_CHEAT
] = gamekeys
[9] ? 1 : 0;
130 vmGVars
[GVAR_KEY_PLEV_CHEAT
] = gamekeys
[10] ? 1 : 0;
131 vmGVars
[GVAR_KEY_NLEV_CHEAT
] = gamekeys
[11] ? 1 : 0;
135 ////////////////////////////////////////////////////////////////////////////////
136 #define ROOM_SCRIPTS_MARK " room script labels starts here "
139 static void loadMapScript (ResFile
*resfile
) {
143 vmGVars
[GVAR_ROOM_SCRIPT_TID
] = -1;
144 l
= vmLabelAddMark(ROOM_SCRIPTS_MARK
);
145 l
->value
= vmCodeSize
;
146 if ((csz
= loadCodeFile(resfile
, vmCodeSize
, 94+curLevel
)) > 1) {
147 VMLabelInfo
*l
= vmFindLabel("entry_local_room_script");
149 if (l
!= NULL
&& l
->type
== LB_CODE
) {
151 tid
= vmNewThread(l
->value
);
152 vmGVars
[GVAR_ROOM_SCRIPT_TID
] = tid
;
153 if (goobers
) fprintf(stderr
, "local room script loaded and initialized\n");
159 static void unloadMapScript (void) {
162 while ((l
= vmFindMark(ROOM_SCRIPTS_MARK
)) != NULL
) {
163 VMLabelInfo
*ucl
= vmFindLabel("entry_local_room_script_unload");
165 if (ucl
!= NULL
&& ucl
->type
== LB_CODE
) {
166 vmExecuteBSR(0, ucl
->value
, 0);
169 vmCodeSize
= l
->value
;
170 vmFreeLabelsUntilMark(ROOM_SCRIPTS_MARK
);
175 ////////////////////////////////////////////////////////////////////////////////
180 static int readBuf (FILE *fl
, void *buf
, int len
) {
181 unsigned char *c
= (unsigned char *)buf
;
186 if (fread(&b
, 1, 1, fl
) != 1) return -1;
194 static int writeBuf (FILE *fl
, const void *buf
, int len
) {
195 const unsigned char *c
= (const unsigned char *)buf
;
198 unsigned char b
= *c
++;
201 if (fwrite(&b
, 1, 1, fl
) != 1) return -1;
207 static int readDW (FILE *fl
, int *v
) {
210 for (int f
= 0; f
< 4; ++f
) {
213 if (fread(&b
, 1, 1, fl
) != 1) return -1;
219 for (int f
= 0; f
< 4; ++f
) *v
|= t
[f
]<<(8*f
);
225 static int writeDW (FILE *fl
, int v
) {
226 for (int f
= 0; f
< 4; ++f
) {
231 if (fwrite(&b
, 1, 1, fl
) != 1) return -1;
238 static int readUDW (FILE *fl
, Uint32
*v
) {
241 for (int f
= 0; f
< 4; ++f
) {
244 if (fread(&b
, 1, 1, fl
) != 1) return -1;
250 for (int f
= 0; f
< 4; ++f
) *v
|= t
[f
]<<(8*f
);
256 static int writeUDW (FILE *fl
, Uint32 v
) {
257 for (int f
= 0; f
< 4; ++f
) {
262 if (fwrite(&b
, 1, 1, fl
) != 1) return -1;
269 ////////////////////////////////////////////////////////////////////////////////
270 static const char *SAVE_GAME_SIGNATURE
= "ASG0";
272 static int loadGame (void) {
273 FILE *fl
= fopen("awish.sav", "rb");
278 if (fread(sign
, 4, 1, fl
) != 1) goto error
;
279 if (memcmp(sign
, SAVE_GAME_SIGNATURE
, 4) != 0) goto error
;
280 if (vmLoadState(fl
) != 0) goto error
;
281 if (readUDW(fl
, &demo_m_w
) != 0) goto error
;
282 if (readUDW(fl
, &demo_m_z
) != 0) goto error
;
283 if (readDW(fl
, &inMinimap
) != 0) goto error
;
284 if (readDW(fl
, &curLevel
) != 0) goto error
;
285 if (readBuf(fl
, levelname
, sizeof(levelname
)) != 0) goto error
;
286 if (readDW(fl
, &lnamex
) != 0) goto error
;
287 if (readDW(fl
, &levelback
) != 0) goto error
;
288 if (readBuf(fl
, bmap
, sizeof(bmap
)) != 0) goto error
;
289 if (readBuf(fl
, fmap
, sizeof(fmap
)) != 0) goto error
;
290 if (readBuf(fl
, xflags
, sizeof(xflags
)) != 0) goto error
;
298 if (goobers
) fprintf(stderr
, "error loading saved game\n");
303 static int saveGame (void) {
304 FILE *fl
= fopen("awish.sav", "wb");
307 demo_m_w
= getSeedL();
308 demo_m_z
= getSeedH();
309 if (fwrite(SAVE_GAME_SIGNATURE
, 4, 1, fl
) != 1) goto error
;
310 if (vmSaveState(fl
) != 0) goto error
;
311 if (writeUDW(fl
, demo_m_w
) != 0) goto error
;
312 if (writeUDW(fl
, demo_m_z
) != 0) goto error
;
313 if (writeDW(fl
, inMinimap
) != 0) goto error
;
314 if (writeDW(fl
, curLevel
) != 0) goto error
;
315 if (writeBuf(fl
, levelname
, sizeof(levelname
)) != 0) goto error
;
316 if (writeDW(fl
, lnamex
) != 0) goto error
;
317 if (writeDW(fl
, levelback
) != 0) goto error
;
318 if (writeBuf(fl
, bmap
, sizeof(bmap
)) != 0) goto error
;
319 if (writeBuf(fl
, fmap
, sizeof(fmap
)) != 0) goto error
;
320 if (writeBuf(fl
, xflags
, sizeof(xflags
)) != 0) goto error
;
327 if (goobers
) fprintf(stderr
, "error saving game\n");
332 ////////////////////////////////////////////////////////////////////////////////
333 static void demoClear (void) {
337 demoPrevKeyState
= 0;
338 demoKeyStateRepeats
= 0;
339 if (demoData
!= NULL
) free(demoData
);
344 static void demoAddByte (Uint8 b
) {
345 if (demoPos
+1 > demoSize
&& demoSize
> 1024*1024*16) fatal("out of memory in demo recording!");
346 if (demoPos
+1 > demoSize
) {
347 int newsz
= demoSize
+1024*32;
348 Uint8
*nn
= realloc(demoData
, newsz
);
350 if (!nn
) fatal("out of memory in demo recording!");
354 demoData
[demoPos
++] = b
;
358 static Uint8
demoGetKeyState (void) {
360 ((gamekeys
[0]?1:0)<<0) |
361 ((gamekeys
[1]?1:0)<<1) |
362 ((gamekeys
[2]?1:0)<<2) |
363 ((gamekeys
[3]?1:0)<<3) |
364 ((gamekeys
[4]?1:0)<<4) |
365 ((gamekeys
[5]?1:0)<<5);
369 static void demoSetKeyState (Uint8 kstate
) {
370 gamekeys
[0] = (kstate
&(1<<0)) != 0;
371 gamekeys
[1] = (kstate
&(1<<1)) != 0;
372 gamekeys
[2] = (kstate
&(1<<2)) != 0;
373 gamekeys
[3] = (kstate
&(1<<3)) != 0;
374 gamekeys
[4] = (kstate
&(1<<4)) != 0;
375 gamekeys
[5] = (kstate
&(1<<5)) != 0;
379 static void demoAddFrameData (void) {
380 Uint8 kstate
= demoGetKeyState();
382 if (demoKeyStateRepeats
== 256) {
383 demoAddByte(demoKeyStateRepeats
-1);
384 demoAddByte(demoPrevKeyState
);
385 demoKeyStateRepeats
= 0;
388 if (kstate
!= demoPrevKeyState
) {
389 if (demoKeyStateRepeats
> 0) {
390 demoAddByte(demoKeyStateRepeats
-1);
391 demoAddByte(demoPrevKeyState
);
393 demoPrevKeyState
= kstate
;
394 demoKeyStateRepeats
= 1;
396 ++demoKeyStateRepeats
;
401 static void demoGetFrameData (void) {
402 while (demoKeyStateRepeats
< 1) {
403 if (demoPos
+2 > demoSize
) {
406 if (goobers
) fprintf(stderr
, "demo complete\n");
407 strcpy(message
, "demo stopped");
410 demoKeyStateRepeats
= demoData
[demoPos
++];
411 ++demoKeyStateRepeats
;
412 demoPrevKeyState
= demoData
[demoPos
++];
414 --demoKeyStateRepeats
;
416 demoSetKeyState(demoPrevKeyState
);
420 static int demoSave (void) {
425 if (demoKeyStateRepeats
> 0) {
426 demoAddByte(demoKeyStateRepeats
-1);
427 demoAddByte(demoPrevKeyState
);
430 sprintf(buf
, "awish%02d.dmo", curLevel
+1);
431 fl
= fopen(buf
, "wb");
433 if (goobers
) fprintf(stderr
, "can't create demo file '%s'\n", buf
);
436 strcpy(sign
, "AWD1");
437 if (fwrite(sign
, 4, 1, fl
) != 1) goto error
;
438 if (writeDW(fl
, curLevel
) != 0) goto error
;
439 if (writeUDW(fl
, demo_m_w
) != 0) goto error
;
440 if (writeUDW(fl
, demo_m_z
) != 0) goto error
;
441 if (writeDW(fl
, demoPos
) != 0) goto error
;
442 if (writeBuf(fl
, demoData
, demoPos
) != 0) goto error
;
444 if (goobers
) fprintf(stderr
, "demo saved to file '%s'\n", buf
);
449 if (goobers
) fprintf(stderr
, "can't write demo file '%s'\n", buf
);
454 static int demoLoad (void) {
461 sprintf(buf
, "awish%02d.dmo", curLevel
+1);
462 fl
= fopen(buf
, "rb");
464 if (goobers
) fprintf(stderr
, "can't open demo file '%s'\n", buf
);
468 if (fread(sign
, 4, 1, fl
) != 1) goto error
;
469 if (memcmp(sign
, "AWD1", 4) != 0) goto error
;
470 if (readDW(fl
, &level
) != 0) goto error
;
471 if (readUDW(fl
, &demo_m_w
) != 0) goto error
;
472 if (readUDW(fl
, &demo_m_z
) != 0) goto error
;
473 if (readDW(fl
, &size
) != 0) goto error
;
474 if (size
< 1 || size
> 1024*1024*16) goto error
;
475 demoData
= malloc(size
);
476 if (demoData
== NULL
) goto error
;
477 if (readBuf(fl
, demoData
, size
) != 0) goto error
;
483 if (goobers
) fprintf(stderr
, "loaded demo file '%s'\n", buf
);
488 if (goobers
) fprintf(stderr
, "can't load demo file '%s'\n", buf
);
494 // CODE_GAME_RESTART_LEVEL
496 // CONST_GAME_STATE_DEAD
497 // CONST_GAME_STATE_COMPLETE
498 // CONST_GAME_STATE_STARTED
499 // CONST_GAME_STATE_PLAYING
501 static inline int isGameStopped (void) {
503 vmGVars
[GVAR_GAME_STATE
] == CONST_GAME_STATE_DEAD
||
504 vmGVars
[GVAR_GAME_STATE
] == CONST_GAME_STATE_COMPLETE
;
508 static void demoCB (void) {
509 if (vmGVars
[GVAR_GAME_STATE
] == CONST_GAME_STATE_STARTED
) unloadMapScript();
511 switch (demorecmode
) {
512 case -666: // prepare to load demo
513 if (demoLoad() != 0) {
519 case 666: // prepare to save demo
520 vmSetPC(0, CODE_GAME_RESTART_LEVEL
);
521 vmGVars
[GVAR_CUR_LEVEL
] = curLevel
;
522 vmGVars
[GVAR_GAME_STATE
] = -1; // invalid state
523 if (demorecmode
> 0) {
528 case -1: // demo replaying
529 case 1: // demo saving
530 if (isGameStopped()) {
531 // the level is over or prof is dead
532 if (demorecmode
> 0) demoSave();
536 ((demorecmode
< 0) ? demoGetFrameData
: demoAddFrameData
)();
539 case -2: // waiting for 'game started' trigger
540 case 2: // waiting for 'game started' trigger
541 if (vmGVars
[GVAR_GAME_STATE
] >= 0) {
542 if (goobers
) fprintf(stderr
, "demo %s started...\n", demorecmode
<0?"replaying":"recording");
543 if (demorecmode
< 0) {
549 demo_m_w
= getSeedL();
550 demo_m_z
= getSeedH();
552 demorecmode
= (demorecmode
< 0) ? -1 : 1;
560 ////////////////////////////////////////////////////////////////////////////////
561 static void frmGameKey (SDL_KeyboardEvent
*key
) {
562 if (key
->type
== SDL_KEYDOWN
) {
563 switch (key
->keysym
.sym
) {
567 if (vmPaused
&& inMinimap
) {
575 vmGVars
[GVAR_KEY_QUIT
] = 1;
591 if (demorecmode
!= 0) { demoClear(); demorecmode
= 0; }
592 if ((key
->keysym
.mod
&(KMOD_CTRL
)) != 0) {
598 if (vmPaused
== 0 && !demorecmode
) {
599 if (goobers
&& (key
->keysym
.mod
&(KMOD_CTRL
)) != 0) { doSave
= 1; vmPaused
= 1; }
603 if (vmPaused
== 0 && !demorecmode
) {
604 if (goobers
&& (key
->keysym
.mod
&(KMOD_CTRL
)) != 0) { doSave
= -1; vmPaused
= 1; }
609 if (goobers
&& (key
->keysym
.mod
&(KMOD_CTRL
)) != 0) {
611 demorecmode
= 666; // 'start saving'
622 if (goobers
&& (key
->keysym
.mod
&(KMOD_CTRL
)) != 0) {
624 demorecmode
= -666; // 'start playing'
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;
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;
671 ////////////////////////////////////////////////////////////////////////////////
672 static int loadLevelInternal (ResFile
*resfile
, int lidx
) {
674 int sz
, res
= -1, pos
;
675 static Item items
[256];
676 static int itemCount
;
677 static int scrX
, scrY
;
678 static int profX
, profY
;
685 vmGVars
[GVAR_MAP_WIDTH
] = MAP_WIDTH
;
686 vmGVars
[GVAR_MAP_HEIGHT
] = MAP_HEIGHT
;
687 vmGVars
[GVAR_VIS_WIDTH
] = VIS_WIDTH
;
688 vmGVars
[GVAR_VIS_HEIGHT
] = VIS_HEIGHT
;
690 if ((lvl
= loadResFile(resfile
, lidx
+9, &sz
)) == NULL
) return -1;
691 if (sz
< 3700) goto quit
;
692 if (lvl
[0] > 25) goto quit
;
693 memset(levelname
, 0, sizeof(levelname
));
694 if (lvl
[0] > 0) memcpy(levelname
, lvl
+1, lvl
[0]);
695 lnamex
= (320-strlen(levelname
)*8)/2;
696 sprintf(buf
, "%d", lidx
+1);
697 while (lnamex
+strlen(levelname
)*8+strlen(buf
)*8+6*8 > 320) lnamex
-= 8;
699 if (levelback
< 1 || levelback
> 7) levelback
= 1;
702 vmSetTVar(0, TVAR_POS_X
, profX
);
703 vmSetTVar(0, TVAR_POS_Y
, profY
);
705 scrY
= lvl
[30]; if (scrY
> 0) --scrY
;
706 vmGVars
[GVAR_SCR_X
] = scrX
;
707 vmGVars
[GVAR_SCR_Y
] = scrY
;
709 memset(bmap
, 0, sizeof(bmap
));
710 memset(fmap
, 0, sizeof(fmap
));
711 memset(xflags
, 0, sizeof(xflags
));
712 for (int x
= 1; x
< MAP_WIDTH
; ++x
) {
713 for (int y
= 0; y
< MAP_HEIGHT
; ++y
) {
714 bmap
[y
][x
] = lvl
[pos
++];
717 for (int x
= 1; x
< MAP_WIDTH
; ++x
) {
718 for (int y
= 0; y
< MAP_HEIGHT
; ++y
) {
719 fmap
[y
][x
] = lvl
[pos
++];
721 pos
+= 3; // skip unknown bytes
724 itemCount
= lvl
[pos
++]+1; // at least one item is always here
725 for (int f
= 0; f
< itemCount
; ++f
) {
728 items
[f
].x
= lvl
[pos
++];
729 items
[f
].y
= lvl
[pos
++];
730 items
[f
].fframe
= lvl
[pos
++];
731 items
[f
].lframe
= lvl
[pos
++];
732 items
[f
].frame
= lvl
[pos
++];
733 items
[f
].animated
= lvl
[pos
++];
734 if (!items
[f
].animated
) items
[f
].frame
= items
[f
].fframe
;
737 items
[f
].type
= lvl
[pos
++];
740 tid
= vmNewThread(CODE_ENTRY_ITEM
);
741 if (tid
< 0) goto quit
;
742 vmSetTVar(tid
, TVAR_ITEM_ID
, items
[f
].type
);
743 vmSetTVar(tid
, TVAR_ANIMATED
, items
[f
].animated
);
744 vmSetTVar(tid
, TVAR_AFIRST_FRAME
, items
[f
].fframe
);
745 vmSetTVar(tid
, TVAR_ALAST_FRAME
, items
[f
].lframe
);
746 vmSetTVar(tid
, TVAR_AFRAME
, items
[f
].frame
);
747 if (items
[f
].type
== 6) vmSetTVar(tid
, TVAR_AFRAME
, lvl
[pos
-6]);
748 vmSetTVar(tid
, TVAR_POS_X
, items
[f
].x
);
749 vmSetTVar(tid
, TVAR_POS_Y
, items
[f
].y
);
750 vmSetTVar(tid
, TVAR_POS_TX
, 0);
751 vmSetTVar(tid
, TVAR_POS_TY
, 0);
752 vmSetTVar(tid
, TVAR_SPR_BANK
, CONST_BANK_ITEMS
);
753 vmSetTVar(tid
, TVAR_SPR_NUM
, items
[f
].frame
);
754 vmSetTVar(tid
, TVAR_SPR_DIR
, 0);
761 loadMapScript(resfile
);
769 ////////////////////////////////////////////////////////////////////////////////
770 static inline Uint8
fgTile (int x
, int y
) {
771 return (x
>= 0 && y
>= 0 && x
< MAP_WIDTH
&& y
< MAP_HEIGHT
) ? fmap
[y
][x
]&0x0f : 0;
775 static inline Uint8
bgTile (int x
, int y
) {
776 if (y
== -666) return (x
>= 0 && x
< MAP_WIDTH
) ? xflags
[x
] : 0;
777 return (x
>= 0 && y
>= 0 && x
< MAP_WIDTH
&& y
< MAP_HEIGHT
) ? bmap
[y
][x
]&0x0f : 0;
781 static int mapGet (int tid
, int fg
, int x
, int y
) {
782 return fg
? fgTile(x
, y
) : bgTile(x
, y
);
786 static inline void setFGTile (int x
, int y
, Uint8 tile
) {
787 if (x
>= 0 && y
>= 0 && x
< MAP_WIDTH
&& y
< MAP_HEIGHT
) fmap
[y
][x
] = (fmap
[y
][x
]&0xf0)|(tile
&0x0f);
791 static inline void setBGTile (int x
, int y
, Uint8 tile
) {
792 if (y
== -666 && x
>= 0 && x
< MAP_WIDTH
) xflags
[x
] = tile
;
793 if (x
>= 0 && y
>= 0 && x
< MAP_WIDTH
&& y
< MAP_HEIGHT
) bmap
[y
][x
] = (bmap
[y
][x
]&0xf0)|(tile
&0x0f);
797 static void mapSet (int tid
, int fg
, int x
, int y
, int tile
) {
798 if (fg
) setFGTile(x
, y
, tile
); else setBGTile(x
, y
, tile
);
802 ////////////////////////////////////////////////////////////////////////////////
803 // cliprect should be set
804 static void levelDrawMap (SDL_Surface
*frame
) {
806 int scrX
= vmGVars
[GVAR_SCR_X
], scrY
= vmGVars
[GVAR_SCR_Y
];
808 for (int dy
= 0; dy
< VIS_HEIGHT
; ++dy
) {
809 for (int dx
= 0; dx
< VIS_WIDTH
; ++dx
) {
810 int x
= scrX
+dx
, y
= scrY
+dy
;
811 Uint8 b
= bgTile(x
, y
), f
= fgTile(x
, y
);
813 if (b
) blitSurface2x(frame
, VIS_X
+dx
*20, VIS_Y
+dy
*10, banks
[CONST_BANK_BG_TILES
].spr
[b
-1][0]);
814 if (f
) blitSurface2x(frame
, VIS_X
+dx
*20, VIS_Y
+dy
*10, banks
[CONST_BANK_FG_TILES
].spr
[f
-1][0]);
818 for (int dy
= 0; dy
< MAP_HEIGHT
; ++dy
) {
819 for (int dx
= 1; dx
< MAP_WIDTH
; ++dx
) {
820 Uint8 b
= bgTile(dx
, dy
), f
= fgTile(dx
, dy
), t
= 8;
823 if (b
>= 1 && b
<= 8) t
= b
-1; else t
= 8;
827 if (banks
[CONST_BANK_MAP_TILES
].spr
[t
][0]) {
828 blitSurface2x(frame
, VIS_X
+dx
*6, VIS_Y
+dy
*4, banks
[CONST_BANK_MAP_TILES
].spr
[t
][0]);
836 static void levelDrawSprites (SDL_Surface
*frame
) {
838 int scrX
= vmGVars
[GVAR_SCR_X
], scrY
= vmGVars
[GVAR_SCR_Y
];
839 int py
= vmGetTVar(0, TVAR_POS_Y
)-scrY
;
841 for (int cc
= 0; cc
<= 2; ++cc
) {
842 for (int f
= cc
==1?1:0; f
<= vmLastThread(); ++f
) {
843 if (vmIsThreadAlive(f
) && !vmIsSuspendedThread(f
)) {
844 int b
= vmGetTVar(f
, TVAR_SPR_BANK
);
845 int s
= vmGetTVar(f
, TVAR_SPR_NUM
);
846 int d
= vmGetTVar(f
, TVAR_SPR_DIR
);
848 if (d
>= 0 && d
<= 1 && s
>= 0 && b
>= 0 && b
<= 255 && s
< banks
[b
].count
&& banks
[b
].spr
[s
][d
]) {
849 SDL_Surface
*sf
= banks
[b
].spr
[s
][d
];
850 int x
= vmGetTVar(f
, TVAR_POS_X
)-scrX
;
851 int y
= vmGetTVar(f
, TVAR_POS_Y
)-scrY
;
852 int tx
= vmGetTVar(f
, TVAR_POS_TX
);
853 int ty
= vmGetTVar(f
, TVAR_POS_TY
);
854 int si
= vmGetTVar(f
, TVAR_SPR_ITEM
);
856 if (cc
== 0 && b
== CONST_BANK_ITEMS
) continue;
857 if (cc
== 1 && b
!= CONST_BANK_ITEMS
) continue;
859 if (b
!= CONST_BANK_PROF
) {
860 if (b
!= CONST_BANK_ITEMS
) continue;
861 if (y
< py
) continue;
864 if (b
== CONST_BANK_IM_PROF
|| b
== CONST_BANK_PROF
) tx
-= 5;
865 blitSurface2x(frame
, VIS_X
+x
*20+tx
, VIS_Y
+y
*10+ty
-sf
->h
/2, sf
);
866 if (si
> 0 && si
< banks
[CONST_BANK_ITEMS
].count
) {
867 sf
= banks
[CONST_BANK_ITEMS
].spr
[si
][0];
868 blitSurface2x(frame
, VIS_X
+x
*20+tx
, VIS_Y
+y
*10+ty
-sf
->h
/2-24, sf
);
875 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]);
876 for (int f
= 1; f
< VM_MAX_THREADS
; ++f
) {
877 if (vmIsThreadAlive(f
) && !vmIsSuspendedThread(f
)) {
878 int i
= vmGetTVar(f
, TVAR_ITEM_ID
);
879 if (i
> 0 && i
< ITEM_MAX
) {
880 SDL_Surface
*sf
= banks
[CONST_BANK_MAP_ITEMS
].spr
[i
][0];
881 int x
= vmGetTVar(f
, TVAR_POS_X
);
882 int y
= vmGetTVar(f
, TVAR_POS_Y
);
884 blitSurface2x(frame
, VIS_X
+(x
+0)*6, VIS_Y
+(y
-2)*4, sf
);
892 static void levelDrawCode (SDL_Surface
*frame
) {
893 int pos
= vmGVars
[GVAR_LEVEL_CODE_OFS
], len
= vmGVars
[GVAR_LEVEL_CODE_LEN
], x
;
896 if (pos
< 0 || len
< 1 || pos
+len
> vmCodeSize
) return;
898 sprintf(buf
, "%d", curLevel
);
900 for (; len
> 0; x
+= 8, ++pos
, --len
) drawChar(frame
, vmCode
[pos
], x
, 0, 3);
904 static void levelDrawMisc (SDL_Surface
*frame
) {
905 if (demorecmode
< 0) {
906 if (SDL_GetTicks()%1000 < 500) drawChar(frame
, 'R', 0, 8, 3);
907 } else if (demorecmode
> 0) {
908 if (SDL_GetTicks()%1000 < 500) drawChar(frame
, 'D', 0, 8, 3);
913 static void drawSpriteBank (SDL_Surface
*frame
, SpriteBank
*bank
) {
915 int x
= 0, y
= 0, maxh
= 0;
917 SDL_SetClipRect(frame
, NULL
);
922 SDL_FillRect(frame
, &dst
, palette
[3]);
924 for (int num
= 0; num
< bank
->count
; ++num
) {
925 SDL_Surface
*s
= bank
->spr
[num
][0];
931 sprintf(buf
, "%d", num
);
932 if (w
< strlen(buf
)*8+2) w
= strlen(buf
)*8+2;
938 if (maxh
< s
->h
/2+1) maxh
= s
->h
/2+1;
939 blitSurface2x(frame
, x
, y
, s
);
940 drawString(frame
, buf
, x
, y
, 1);
947 static void frmGameDraw (SDL_Surface
*frame
) {
952 if (vmPaused
&& doSave
) {
954 if (loadGame() != 0) fatal("can't load game, VM is inconsistent, dying.");
959 vmPaused
= inMinimap
;
962 SDL_SetClipRect(frame
, NULL
);
966 blitSurface(frame
, 0, 0, backs
[levelback
]);
968 blitSurface(frame
, 0, 0, backs
[1]);
970 drawString(frame
, levelname
, lnamex
, 0, 0x76);
971 levelDrawCode(frame
);
972 levelDrawMisc(frame
);
974 pi
= vmGVars
[GVAR_PROF_ITEM
];
975 if (vmIsThreadAlive(pi
) && vmIsSuspendedThread(pi
)) {
976 pi
= vmGetTVar(pi
, TVAR_ITEM_ID
);
977 if (pi
> 0 && pi
< 11) {
978 drawString(frame
, itemNames
[pi
], 0, 0, 1);
982 sprintf(buf
, "%d", curLevel
+1);
983 drawString(frame
, buf
, 320-strlen(buf
)*8, 0, 1);
987 rc
.w
= VIS_WIDTH
*20*2;
988 rc
.h
= VIS_HEIGHT
*10*2;
989 SDL_SetClipRect(frame
, &rc
);
992 levelDrawSprites(frame
);
1000 SDL_FillRect(frame
, &dst
, palette
[0]);
1003 SDL_SetClipRect(frame
, NULL
);
1004 levelDrawMisc(frame
);
1007 for (int f
= 84; f
<= 90; ++f
) if (fkeys
[f
-83]) drawSpriteBank(frame
, &banks
[f
]);
1012 ////////////////////////////////////////////////////////////////////////////////
1013 int loadLevel (int lidx
) {
1014 if (lidx
< 0 || lidx
> 73) return -1;
1015 return loadLevelInternal(&resfile
, lidx
);
1019 void activateMinimap (void) {
1026 ////////////////////////////////////////////////////////////////////////////////
1027 void setMainLoopGame (void) {
1028 frameCB
= frmGameDraw
;
1030 beforeVMCB
= demoCB
;
1031 vmMapGetCB
= mapGet
;
1032 vmMapSetCB
= mapSet
;
1034 setSeed(time(NULL
));
1041 memset(fkeys
, 0, sizeof(fkeys
));
1042 memset(gamekeys
, 0, sizeof(gamekeys
));