11 #include "gameglobals.h"
15 ////////////////////////////////////////////////////////////////////////////////
16 #define MAP_WIDTH (44)
17 #define MAP_HEIGHT (41)
18 #define VIS_WIDTH (15)
19 #define VIS_HEIGHT (17)
24 ////////////////////////////////////////////////////////////////////////////////
25 static const char *itemNames
[] = {
57 int type
; // 0: inactive
59 int frame
; // animation frame
60 int fframe
, lframe
; // first and last anim frame
66 ////////////////////////////////////////////////////////////////////////////////
68 static char levelname
[257];
70 static Uint8 levelback
;
71 static Uint8 bmap
[MAP_HEIGHT
][MAP_WIDTH
];
72 static Uint8 fmap
[MAP_HEIGHT
][MAP_WIDTH
];
73 static Uint8 xflags
[MAP_WIDTH
];
74 static Item items
[256];
76 static int scrX
, scrY
;
77 static int profX
, profY
;
78 //static Item profItem;
83 ////////////////////////////////////////////////////////////////////////////////
84 static void frmGameKey (SDL_KeyboardEvent
*key
) {
85 if (key
->type
== SDL_KEYDOWN
) {
86 switch (key
->keysym
.sym
) {
91 vmGVars
[GVAR_KEY_MINIMAP
] = 0;
95 vmGVars
[GVAR_KEY_QUIT
] = 1;
98 vmGVars
[GVAR_KEY_MINIMAP
] = 1;
104 switch (key
->keysym
.sym
) {
105 case SDLK_LEFT
: case SDLK_KP4
: vmGVars
[GVAR_KEY_LEFT
] = (key
->type
== SDL_KEYDOWN
); break;
106 case SDLK_RIGHT
: case SDLK_KP6
: vmGVars
[GVAR_KEY_RIGHT
] = (key
->type
== SDL_KEYDOWN
); break;
107 case SDLK_UP
: case SDLK_KP8
: vmGVars
[GVAR_KEY_UP
] = (key
->type
== SDL_KEYDOWN
); break;
108 case SDLK_DOWN
: case SDLK_KP2
: vmGVars
[GVAR_KEY_DOWN
] = (key
->type
== SDL_KEYDOWN
); break;
109 case SDLK_SPACE
: case SDLK_KP0
: vmGVars
[GVAR_KEY_TAKE
] = (key
->type
== SDL_KEYDOWN
); break;
110 case SDLK_RETURN
: case SDLK_KP_PERIOD
: vmGVars
[GVAR_KEY_USE
] = (key
->type
== SDL_KEYDOWN
); break;
112 case SDLK_f
: vmGVars
[GVAR_KEY_FALL_CHEAT
] = (key
->type
== SDL_KEYDOWN
); break;
113 case SDLK_w
: vmGVars
[GVAR_KEY_WALK_CHEAT
] = (key
->type
== SDL_KEYDOWN
); break;
114 case SDLK_KP_MINUS
: vmGVars
[GVAR_KEY_PLEV_CHEAT
] = (key
->type
== SDL_KEYDOWN
); break;
115 case SDLK_KP_PLUS
: vmGVars
[GVAR_KEY_NLEV_CHEAT
] = (key
->type
== SDL_KEYDOWN
); break;
117 case SDLK_F1
: fkeys
[1] = (key
->type
== SDL_KEYDOWN
); break;
118 case SDLK_F2
: fkeys
[2] = (key
->type
== SDL_KEYDOWN
); break;
119 case SDLK_F3
: fkeys
[3] = (key
->type
== SDL_KEYDOWN
); break;
120 case SDLK_F4
: fkeys
[4] = (key
->type
== SDL_KEYDOWN
); break;
121 case SDLK_F5
: fkeys
[5] = (key
->type
== SDL_KEYDOWN
); break;
122 case SDLK_F6
: fkeys
[6] = (key
->type
== SDL_KEYDOWN
); break;
123 case SDLK_F7
: fkeys
[7] = (key
->type
== SDL_KEYDOWN
); break;
124 case SDLK_F8
: fkeys
[8] = (key
->type
== SDL_KEYDOWN
); break;
125 case SDLK_F9
: fkeys
[9] = (key
->type
== SDL_KEYDOWN
); break;
131 ////////////////////////////////////////////////////////////////////////////////
132 static int loadLevelInternal (ResFile
*resfile
, int lidx
) {
134 int sz
, res
= -1, pos
;
136 vmGVars
[GVAR_MAP_WIDTH
] = MAP_WIDTH
;
137 vmGVars
[GVAR_MAP_HEIGHT
] = MAP_HEIGHT
;
138 vmGVars
[GVAR_VIS_WIDTH
] = VIS_WIDTH
;
139 vmGVars
[GVAR_VIS_HEIGHT
] = VIS_HEIGHT
;
141 if ((lvl
= loadResFile(resfile
, lidx
+9, &sz
)) == NULL
) return -1;
142 if (sz
< 3700) goto quit
;
143 if (lvl
[0] > 25) goto quit
;
144 memset(levelname
, 0, sizeof(levelname
));
145 if (lvl
[0] > 0) memcpy(levelname
, lvl
+1, lvl
[0]);
146 lnamex
= (320-strlen(levelname
)*8)/2;
148 if (levelback
< 1 || levelback
> 7) levelback
= 1;
149 profX
= lvl
[27]; //if (profX > 0) --profX;
151 vmSetTVar(0, TVAR_POS_X
, profX
);
152 vmSetTVar(0, TVAR_POS_Y
, profY
);
153 scrX
= lvl
[29]; //if (scrX > 0) --scrX;
154 scrY
= lvl
[30]; if (scrY
> 0) --scrY
;
155 vmGVars
[GVAR_SCR_X
] = scrX
;
156 vmGVars
[GVAR_SCR_Y
] = scrY
;
158 memset(bmap
, 0, sizeof(bmap
));
159 memset(fmap
, 0, sizeof(fmap
));
160 memset(xflags
, 0, sizeof(xflags
));
161 for (int x
= 1; x
< MAP_WIDTH
; ++x
) {
162 for (int y
= 0; y
< MAP_HEIGHT
; ++y
) {
163 bmap
[y
][x
] = lvl
[pos
++];
166 for (int x
= 1; x
< MAP_WIDTH
; ++x
) {
167 for (int y
= 0; y
< MAP_HEIGHT
; ++y
) {
168 fmap
[y
][x
] = lvl
[pos
++];
170 pos
+= 3; // skip unknown bytes
173 //fprintf(stderr, "pos: 0x%08x\n", pos);
174 itemCount
= lvl
[pos
++]+1; // at least one item is always here
175 vmGVars
[GVAR_ITEM_COUNT
] = itemCount
;
176 //fprintf(stderr, "ic=%d\n", itemCount);
177 //fprintf(stderr, "LEVEL #%d\n", lidx+1);
178 for (int f
= 0; f
< itemCount
; ++f
) {
181 items
[f
].x
= lvl
[pos
++]; //--items[f].x;
182 items
[f
].y
= lvl
[pos
++]; //--items[f].y;
183 items
[f
].fframe
= lvl
[pos
++];
184 items
[f
].lframe
= lvl
[pos
++];
185 items
[f
].frame
= lvl
[pos
++];
186 items
[f
].animated
= lvl
[pos
++];
187 //if (items[f].animated > 1) fprintf(stderr, "item #%d: animated=%d\n", f, items[f].animated);
188 if (!items
[f
].animated
) items
[f
].frame
= items
[f
].fframe
;
189 //if (lvl[pos] != 0xff) fprintf(stderr, "item #%d: NOT FF!\n", f);
192 #define DIE(msg,ofs) { fprintf(stderr, "LEVEL #%d, item #%d (%s): %s (%d)\n", lidx+1, f, itemNames[lvl[pos+4]], msg, lvl[pos+ofs]); abort(); }
193 if (lvl[pos-1] != 0xff) DIE("FF", 0);
194 if (lvl[pos+4] == 6) {
195 if (lidx == 18 && lvl[pos+0] == 3) goto skip;
196 if (f == 3 && lidx == 20 && lvl[pos+0] == 7) goto skip;
197 if (f == 4 && lidx == 20 && lvl[pos+0] == 3) goto skip;
198 if (lidx == 23 && lvl[pos+0] == 6) goto skip;
199 if (lidx == 24 && lvl[pos+0] == 1) goto skip;
200 if (lidx == 26 && lvl[pos+0] == 0) goto skip;
201 if (lidx == 32 && lvl[pos+0] == 6) goto skip;
202 if (f == 2 && lidx == 37 && lvl[pos+0] == 2) goto skip;
203 if (f == 3 && lidx == 37 && lvl[pos+0] == 4) goto skip;
204 if (f == 4 && lidx == 37 && lvl[pos+0] == 6) goto skip;
205 if (f == 6 && lidx == 37 && lvl[pos+0] == 7) goto skip;
206 if (f == 8 && lidx == 37 && lvl[pos+0] == 3) goto skip;
207 if (f == 10 && lidx == 37 && lvl[pos+0] == 0) goto skip;
208 if (f == 12 && lidx == 37 && lvl[pos+0] == 0) goto skip;
209 if (f == 16 && lidx == 37 && lvl[pos+0] == 4) goto skip;
210 if (f == 17 && lidx == 37 && lvl[pos+0] == 0) goto skip;
211 if (f == 18 && lidx == 37 && lvl[pos+0] == 0) goto skip;
212 if (f == 19 && lidx == 37 && lvl[pos+0] == 0) goto skip;
213 if (lidx == 43 && lvl[pos+0] == 0) goto skip;
214 if (lidx == 48 && lvl[pos+0] == 6) goto skip;
215 if (lidx == 55 && lvl[pos+0] == 4) goto skip;
216 if (lidx == 59 && lvl[pos+0] == 8) goto skip;
217 if (lidx == 60 && lvl[pos+0] == 7) goto skip;
218 if (lidx == 63 && lvl[pos+0] == 1) goto skip;
219 if (lidx == 65 && lvl[pos+0] == 2) goto skip;
220 if (lidx == 66 && lvl[pos+0] == 3) goto skip;
221 if (f == 9 && lidx == 67 && lvl[pos+0] == 0) goto skip;
222 if (f == 10 && lidx == 67 && lvl[pos+0] == 7) goto skip;
223 if (lidx == 69 && lvl[pos+0] == 2) goto skip;
224 if (lvl[pos+0] != 9) DIE("MONSTER+0 is not 9", 0);
226 if (lidx == 12 && lvl[pos+4] == 2 && lvl[pos+0] == 1) goto skip;
227 if (lidx == 23 && lvl[pos+4] == 2 && lvl[pos+0] == 1) goto skip;
228 if (lidx == 25 && lvl[pos+4] == 2 && lvl[pos+0] == 1) goto skip;
229 if (lidx == 26 && lvl[pos+4] == 2 && lvl[pos+0] == 1) goto skip;
230 if (lidx == 27 && lvl[pos+4] == 2 && lvl[pos+0] == 1) goto skip;
231 if (lidx == 48 && lvl[pos+4] == 2 && lvl[pos+0] == 1) goto skip;
232 if (lidx == 55 && lvl[pos+4] == 2 && lvl[pos+0] == 1) goto skip;
233 if (lidx == 60 && lvl[pos+4] == 2 && lvl[pos+0] == 1) goto skip;
234 if (lvl[pos+0] != 0) DIE("non-MONSTER+0 is not 0", 0);
237 switch (lvl[pos+4]) {
238 case 1: case 4: case 5: case 8: case 10:
239 if (lvl[pos+1] != 0) DIE("00", 1);
242 if (lvl[pos+1] != 2) DIE("01", 1);
245 if (lvl[pos+1] != 6) DIE("02", 1);
248 if (lvl[pos+1] != 10) DIE("03", 1);
251 if (lvl[pos+1] != 2) DIE("04", 1);
254 if (lvl[pos+1] != 10) DIE("05", 1);
258 if (lvl[pos+2] != 0) DIE("06", 2);
259 if (lvl[pos+3] != 0) DIE("07", 3);
260 if (lvl[pos+5] != 0) DIE("08", 5);
263 items
[f
].type
= lvl
[pos
++];
267 if (items[f].type == 6) { if (lvl[pos-6] != 9) lvl[pos-6] = 255; else lvl[pos-6] = 0; }
268 if (lvl[pos-6] == 0 || lvl[pos-4] == 0 || lvl[pos-3] == 0 || lvl[pos-1] == 0) {
269 //if (items[f].type == 1 && lvl[pos-5] == 0) goto skip;
270 if (items[f].type == 2 && lvl[pos-5] == 2) goto skip;
271 if (items[f].type == 3 && lvl[pos-5] == 6) goto skip;
272 //if (items[f].type == 4 && lvl[pos-5] == 0) goto skip;
273 //if (items[f].type == 5 && lvl[pos-5] == 0) goto skip;
274 if (items[f].type == 6 && lvl[pos-5] == 10) goto skip;
275 if (items[f].type == 7 && lvl[pos-5] == 2) goto skip;
276 //if (items[f].type == 8 && lvl[pos-5] == 0) goto skip;
277 if (items[f].type == 9 && lvl[pos-5] == 10) goto skip;
278 //if (items[f].type == 10 && lvl[pos-5] == 0) goto skip;
280 fprintf(stderr, "item #%d: %s (%d)", f, itemNames[items[f].type], items[f].type);
281 for (int c = -6; c < 0; ++c) fprintf(stderr, " %d", lvl[pos+c]);
282 fprintf(stderr, "\n");
286 //fprintf(stderr, "%d: x=%d; y=%d; type=%d\n", f, items[f].x, items[f].y, items[f].type);
288 tid
= vmNewThread(CODE_ENTRY_ITEM
);
289 if (tid
< 0) goto quit
;
290 vmSetTVar(tid
, TVAR_ITEM_ID
, items
[f
].type
);
291 vmSetTVar(tid
, TVAR_ANIMATED
, items
[f
].animated
);
292 vmSetTVar(tid
, TVAR_AFIRST_FRAME
, items
[f
].fframe
);
293 vmSetTVar(tid
, TVAR_ALAST_FRAME
, items
[f
].lframe
);
294 vmSetTVar(tid
, TVAR_AFRAME
, items
[f
].frame
);
295 if (items
[f
].type
== 6) vmSetTVar(tid
, TVAR_AFRAME
, lvl
[pos
-6]);
296 vmSetTVar(tid
, TVAR_POS_X
, items
[f
].x
);
297 vmSetTVar(tid
, TVAR_POS_Y
, items
[f
].y
);
298 vmSetTVar(tid
, TVAR_POS_TX
, 0);
299 vmSetTVar(tid
, TVAR_POS_TY
, 0);
300 vmSetTVar(tid
, TVAR_SPR_BANK
, CONST_BANK_ITEMS
);
301 vmSetTVar(tid
, TVAR_SPR_NUM
, items
[f
].frame
);
302 vmSetTVar(tid
, TVAR_SPR_DIR
, 0);
312 ////////////////////////////////////////////////////////////////////////////////
313 static inline Uint8
fgTile (int x
, int y
) {
314 return (x
>= 0 && y
>= 0 && x
< MAP_WIDTH
&& y
< MAP_HEIGHT
) ? fmap
[y
][x
]&0x0f : 0;
318 static inline Uint8
bgTile (int x
, int y
) {
319 if (y
== -666) return (x
>= 0 && x
< MAP_WIDTH
) ? xflags
[x
] : 0;
320 return (x
>= 0 && y
>= 0 && x
< MAP_WIDTH
&& y
< MAP_HEIGHT
) ? bmap
[y
][x
]&0x0f : 0;
324 static int mapGet (int tid
, int fg
, int x
, int y
) {
325 return fg
? fgTile(x
, y
) : bgTile(x
, y
);
329 static inline void setFGTile (int x
, int y
, Uint8 tile
) {
330 if (x
>= 0 && y
>= 0 && x
< MAP_WIDTH
&& y
< MAP_HEIGHT
) fmap
[y
][x
] = (fmap
[y
][x
]&0xf0)|(tile
&0x0f);
334 static inline void setBGTile (int x
, int y
, Uint8 tile
) {
335 if (y
== -666 && x
>= 0 && x
< MAP_WIDTH
) xflags
[x
] = tile
;
336 if (x
>= 0 && y
>= 0 && x
< MAP_WIDTH
&& y
< MAP_HEIGHT
) bmap
[y
][x
] = (bmap
[y
][x
]&0xf0)|(tile
&0x0f);
340 static void mapSet (int tid
, int fg
, int x
, int y
, int tile
) {
341 if (fg
) setFGTile(x
, y
, tile
); else setBGTile(x
, y
, tile
);
345 ////////////////////////////////////////////////////////////////////////////////
346 // cliprect should be set
347 static void levelDrawMap (SDL_Surface
*frame
) {
349 int scrX
= vmGVars
[GVAR_SCR_X
], scrY
= vmGVars
[GVAR_SCR_Y
];
351 for (int dy
= 0; dy
< VIS_HEIGHT
; ++dy
) {
352 for (int dx
= 0; dx
< VIS_WIDTH
; ++dx
) {
353 int x
= scrX
+dx
, y
= scrY
+dy
;
354 Uint8 b
= bgTile(x
, y
), f
= fgTile(x
, y
);
356 if (b
) blitSurface2x(frame
, VIS_X
+dx
*20, VIS_Y
+dy
*10, banks
[CONST_BANK_BG_TILES
].spr
[b
-1][0]);
357 if (f
) blitSurface2x(frame
, VIS_X
+dx
*20, VIS_Y
+dy
*10, banks
[CONST_BANK_FG_TILES
].spr
[f
-1][0]);
361 for (int dy
= 0; dy
< MAP_HEIGHT
; ++dy
) {
362 for (int dx
= 1; dx
< MAP_WIDTH
; ++dx
) {
363 Uint8 b
= bgTile(dx
, dy
), f
= fgTile(dx
, dy
), t
= 8;
366 if (b
>= 1 && b
<= 8) t
= b
-1; else t
= 8;
370 if (banks
[CONST_BANK_MAP_TILES
].spr
[t
][0]) {
371 blitSurface2x(frame
, VIS_X
+dx
*6, VIS_Y
+dy
*4, banks
[CONST_BANK_MAP_TILES
].spr
[t
][0]);
379 static void levelDrawSprites (SDL_Surface
*frame
) {
381 int scrX
= vmGVars
[GVAR_SCR_X
], scrY
= vmGVars
[GVAR_SCR_Y
];
383 for (int cc
= 0; cc
<= 1; ++cc
) {
384 for (int f
= cc
; f
<= vmLastThread(); ++f
) {
385 if (vmIsThreadAlive(f
) && !vmIsSuspendedThread(f
)) {
386 int b
= vmGetTVar(f
, TVAR_SPR_BANK
);
387 int s
= vmGetTVar(f
, TVAR_SPR_NUM
);
388 int d
= vmGetTVar(f
, TVAR_SPR_DIR
);
390 if (cc
== 0 && b
== CONST_BANK_ITEMS
) continue;
391 if (cc
== 1 && b
!= CONST_BANK_ITEMS
) continue;
392 if (d
>= 0 && d
<= 1 && s
>= 0 && b
>= 0 && b
<= 255 && s
< banks
[b
].count
&& banks
[b
].spr
[s
][d
]) {
393 SDL_Surface
*sf
= banks
[b
].spr
[s
][d
];
394 int x
= vmGetTVar(f
, TVAR_POS_X
)-scrX
;
395 int y
= vmGetTVar(f
, TVAR_POS_Y
)-scrY
;
396 int tx
= vmGetTVar(f
, TVAR_POS_TX
);
397 int ty
= vmGetTVar(f
, TVAR_POS_TY
);
398 int si
= vmGetTVar(f
, TVAR_SPR_ITEM
);
400 if (b
== CONST_BANK_IM_PROF
|| b
== CONST_BANK_PROF
) tx
-= 5;
401 blitSurface2x(frame
, VIS_X
+x
*20+tx
, VIS_Y
+y
*10+ty
-sf
->h
/2, sf
);
402 if (si
> 0 && si
< banks
[CONST_BANK_ITEMS
].count
) {
403 sf
= banks
[CONST_BANK_ITEMS
].spr
[si
][0];
404 blitSurface2x(frame
, VIS_X
+x
*20+tx
, VIS_Y
+y
*10+ty
-sf
->h
/2-24, sf
);
411 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]);
412 for (int f
= 1; f
< VM_MAX_THREADS
; ++f
) {
413 if (vmIsThreadAlive(f
) && !vmIsSuspendedThread(f
)) {
414 int i
= vmGetTVar(f
, TVAR_ITEM_ID
);
415 if (i
> 0 && i
< ITEM_MAX
) {
416 SDL_Surface
*sf
= banks
[CONST_BANK_MAP_ITEMS
].spr
[i
][0];
417 int x
= vmGetTVar(f
, TVAR_POS_X
);
418 int y
= vmGetTVar(f
, TVAR_POS_Y
);
420 blitSurface2x(frame
, VIS_X
+(x
+0)*6, VIS_Y
+(y
-2)*4, sf
);
428 static void drawSpriteBank (SDL_Surface
*frame
, SpriteBank
*bank
) {
430 int x
= 0, y
= 0, maxh
= 0;
432 SDL_SetClipRect(frame
, NULL
);
437 SDL_FillRect(frame
, &dst
, palette
[3]);
439 for (int num
= 0; num
< bank
->count
; ++num
) {
440 SDL_Surface
*s
= bank
->spr
[num
][0];
446 sprintf(buf
, "%d", num
);
447 if (w
< strlen(buf
)*8+2) w
= strlen(buf
)*8+2;
453 if (maxh
< s
->h
/2+1) maxh
= s
->h
/2+1;
454 blitSurface2x(frame
, x
, y
, s
);
455 drawString(frame
, buf
, x
, y
, 1);
462 static void frmGameDraw (SDL_Surface
*frame
) {
467 SDL_SetClipRect(frame
, NULL
);
469 blitSurface(frame
, 0, 0, backs
[levelback
]);
471 blitSurface(frame
, 0, 0, backs
[1]);
473 drawString(frame
, levelname
, lnamex
, 0, 0x76);
475 pi
= vmGVars
[GVAR_PROF_ITEM
];
476 if (vmIsThreadAlive(pi
) && vmIsSuspendedThread(pi
)) {
477 pi
= vmGetTVar(pi
, TVAR_ITEM_ID
);
478 if (pi
> 0 && pi
< 11) {
479 //blitSurface2x(frame, 0, 0, itemSpr[profItem.frame]);
480 drawString(frame
, itemNames
[pi
], 0, 0, 1);
484 sprintf(buf
, "%d", curLevel
+1);
485 drawString(frame
, buf
, 320-strlen(buf
)*8, 0, 1);
489 rc
.w
= VIS_WIDTH
*20*2;
490 rc
.h
= VIS_HEIGHT
*10*2;
491 SDL_SetClipRect(frame
, &rc
);
494 levelDrawSprites(frame
);
496 for (int f
= 84; f
<= 90; ++f
) if (fkeys
[f
-83]) drawSpriteBank(frame
, &banks
[f
]);
500 ////////////////////////////////////////////////////////////////////////////////
501 int loadLevel (int lidx
) {
502 if (lidx
< 0 || lidx
> 73) return -1;
503 return loadLevelInternal(&resfile
, lidx
);
507 void activateMinimap (void) {
513 ////////////////////////////////////////////////////////////////////////////////
514 void setMainLoopGame (void) {
515 frameCB
= frmGameDraw
;
523 memset(fkeys
, 0, sizeof(fkeys
));