mnemonics changed a little; added prev/next level cheats
[awish.git] / src / game.c
blob332bd7939a75098d809607a6f67ff618e2f68b57
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
5 #include "game.h"
7 #include "resfile.h"
8 #include "video.h"
9 #include "mainloop.h"
10 #include "vm.h"
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)
20 #define VIS_X (10)
21 #define VIS_Y (20)
24 ////////////////////////////////////////////////////////////////////////////////
25 static const char *itemNames[] = {
26 "",
27 "key",
28 "fan",
29 "dynamite",
30 "drill",
31 "umbrella",
32 "monster",
33 "rocket",
34 "apple",
35 "vial",
36 "gloves"
40 enum {
41 ITEM_NOTHING,
42 ITEM_KEY,
43 ITEM_FAN,
44 ITEM_DYNAMITE,
45 ITEM_DRILL,
46 ITEM_UMBRELLA,
47 ITEM_MONSTER,
48 ITEM_ROCKET,
49 ITEM_APPLE,
50 ITEM_VIAL,
51 ITEM_GLOVES,
52 ITEM_MAX
56 typedef struct {
57 int type; // 0: inactive
58 int x, y; // in map
59 int frame; // animation frame
60 int fframe, lframe; // first and last anim frame
61 int animated;
62 int tid;
63 } Item;
66 ////////////////////////////////////////////////////////////////////////////////
67 static int curLevel;
68 static char levelname[257];
69 static int lnamex;
70 static Uint8 levelback;
71 static Uint8 bmap[MAP_HEIGHT][MAP_WIDTH];
72 static Uint8 fmap[MAP_HEIGHT][MAP_WIDTH];
73 static Item items[256];
74 static int itemCount;
75 static int scrX, scrY;
76 static int profX, profY;
77 //static Item profItem;
78 static int fkeys[10];
79 static int inMinimap;
82 ////////////////////////////////////////////////////////////////////////////////
83 static void frmGameKey (SDL_KeyboardEvent *key) {
84 if (key->type == SDL_KEYDOWN) {
85 switch (key->keysym.sym) {
86 case SDLK_ESCAPE:
87 if (inMinimap) {
88 inMinimap = 0;
89 vmPaused = 0;
90 vmGVars[GVAR_KEY_MINIMAP] = 0;
92 break;
93 case SDLK_F12:
94 vmGVars[GVAR_KEY_QUIT] = 1;
95 break;
96 case SDLK_p:
97 vmGVars[GVAR_KEY_MINIMAP] = 1;
98 break;
99 default: ;
103 switch (key->keysym.sym) {
104 case SDLK_LEFT: case SDLK_KP4: vmGVars[GVAR_KEY_LEFT] = (key->type == SDL_KEYDOWN); break;
105 case SDLK_RIGHT: case SDLK_KP6: vmGVars[GVAR_KEY_RIGHT] = (key->type == SDL_KEYDOWN); break;
106 case SDLK_UP: case SDLK_KP8: vmGVars[GVAR_KEY_UP] = (key->type == SDL_KEYDOWN); break;
107 case SDLK_DOWN: case SDLK_KP2: vmGVars[GVAR_KEY_DOWN] = (key->type == SDL_KEYDOWN); break;
108 case SDLK_SPACE: case SDLK_KP0: vmGVars[GVAR_KEY_TAKE] = (key->type == SDL_KEYDOWN); break;
109 case SDLK_RETURN: case SDLK_KP_PERIOD: vmGVars[GVAR_KEY_USE] = (key->type == SDL_KEYDOWN); break;
111 case SDLK_f: vmGVars[GVAR_KEY_FALL_CHEAT] = (key->type == SDL_KEYDOWN); break;
112 case SDLK_w: vmGVars[GVAR_KEY_WALK_CHEAT] = (key->type == SDL_KEYDOWN); break;
113 case SDLK_KP_MINUS: vmGVars[GVAR_KEY_PLEV_CHEAT] = (key->type == SDL_KEYDOWN); break;
114 case SDLK_KP_PLUS: vmGVars[GVAR_KEY_NLEV_CHEAT] = (key->type == SDL_KEYDOWN); break;
116 case SDLK_F1: fkeys[1] = (key->type == SDL_KEYDOWN); break;
117 case SDLK_F2: fkeys[2] = (key->type == SDL_KEYDOWN); break;
118 case SDLK_F3: fkeys[3] = (key->type == SDL_KEYDOWN); break;
119 case SDLK_F4: fkeys[4] = (key->type == SDL_KEYDOWN); break;
120 case SDLK_F5: fkeys[5] = (key->type == SDL_KEYDOWN); break;
121 case SDLK_F6: fkeys[6] = (key->type == SDL_KEYDOWN); break;
122 case SDLK_F7: fkeys[7] = (key->type == SDL_KEYDOWN); break;
123 case SDLK_F8: fkeys[8] = (key->type == SDL_KEYDOWN); break;
124 case SDLK_F9: fkeys[9] = (key->type == SDL_KEYDOWN); break;
125 default: ;
130 ////////////////////////////////////////////////////////////////////////////////
131 static int loadLevelInternal (ResFile *resfile, int lidx) {
132 Uint8 *lvl;
133 int sz, res = -1, pos;
135 vmGVars[GVAR_MAP_WIDTH] = MAP_WIDTH;
136 vmGVars[GVAR_MAP_HEIGHT] = MAP_HEIGHT;
137 vmGVars[GVAR_VIS_WIDTH] = VIS_WIDTH;
138 vmGVars[GVAR_VIS_HEIGHT] = VIS_HEIGHT;
140 if ((lvl = loadResFile(resfile, lidx+9, &sz)) == NULL) return -1;
141 if (sz < 3700) goto quit;
142 if (lvl[0] > 25) goto quit;
143 memset(levelname, 0, sizeof(levelname));
144 if (lvl[0] > 0) memcpy(levelname, lvl+1, lvl[0]);
145 lnamex = (320-strlen(levelname)*8)/2;
146 levelback = lvl[26];
147 if (levelback < 1 || levelback > 7) levelback = 1;
148 profX = lvl[27]; //if (profX > 0) --profX;
149 profY = lvl[28];
150 vmSetTVar(0, TVAR_POS_X, profX);
151 vmSetTVar(0, TVAR_POS_Y, profY);
152 scrX = lvl[29]; //if (scrX > 0) --scrX;
153 scrY = lvl[30]; if (scrY > 0) --scrY;
154 vmGVars[GVAR_SCR_X] = scrX;
155 vmGVars[GVAR_SCR_Y] = scrY;
156 pos = 31;
157 memset(bmap, 0, sizeof(bmap));
158 memset(fmap, 0, sizeof(fmap));
159 for (int x = 1; x < MAP_WIDTH; ++x) {
160 for (int y = 0; y < MAP_HEIGHT; ++y) {
161 bmap[y][x] = lvl[pos++];
164 for (int x = 1; x < MAP_WIDTH; ++x) {
165 for (int y = 0; y < MAP_HEIGHT; ++y) {
166 fmap[y][x] = lvl[pos++];
168 pos += 3; // skip unknown bytes
171 //fprintf(stderr, "pos: 0x%08x\n", pos);
172 itemCount = lvl[pos++]+1; // at least one item is always here
173 vmGVars[GVAR_ITEM_COUNT] = itemCount;
174 //fprintf(stderr, "ic=%d\n", itemCount);
175 for (int f = 0; f < itemCount; ++f) {
176 int tid;
178 items[f].x = lvl[pos++]; //--items[f].x;
179 items[f].y = lvl[pos++]; //--items[f].y;
180 items[f].fframe = lvl[pos++];
181 items[f].lframe = lvl[pos++];
182 items[f].frame = lvl[pos++];
183 items[f].animated = lvl[pos++];
184 if (!items[f].animated) items[f].frame = items[f].fframe;
185 ++pos; // 0xff
186 pos += 4; // dunno
187 items[f].type = lvl[pos++];
188 ++pos; // dunno
189 //fprintf(stderr, "%d: x=%d; y=%d; type=%d\n", f, items[f].x, items[f].y, items[f].type);
190 // spawn thread
191 tid = vmNewThread(CODE_ENTRY_ITEM);
192 if (tid < 0) goto quit;
193 vmSetTVar(tid, TVAR_ITEM_ID, items[f].type);
194 vmSetTVar(tid, TVAR_ANIMATED, items[f].animated);
195 vmSetTVar(tid, TVAR_AFIRST_FRAME, items[f].fframe);
196 vmSetTVar(tid, TVAR_ALAST_FRAME, items[f].lframe);
197 vmSetTVar(tid, TVAR_AFRAME, items[f].frame);
198 vmSetTVar(tid, TVAR_POS_X, items[f].x);
199 vmSetTVar(tid, TVAR_POS_Y, items[f].y);
200 vmSetTVar(tid, TVAR_POS_TX, 0);
201 vmSetTVar(tid, TVAR_POS_TY, 0);
202 vmSetTVar(tid, TVAR_SPR_BANK, CONST_BANK_ITEMS);
203 vmSetTVar(tid, TVAR_SPR_NUM, items[f].frame);
204 vmSetTVar(tid, TVAR_SPR_DIR, 0);
206 curLevel = lidx;
207 res = 0;
208 quit:
209 free(lvl);
210 return res;
214 ////////////////////////////////////////////////////////////////////////////////
216 static int itemAt (int x, int y) {
217 for (int f = 0; f < itemCount; ++f) {
218 if (items[f].type > ITEM_NOTHING && items[f].tx == 0 && items[f].ty == 0 && items[f].x == x && items[f].y == y) return f;
220 return -1;
225 static inline Uint8 fgTile (int x, int y) {
226 return (x >= 0 && y >= 0 && x < MAP_WIDTH && y < MAP_HEIGHT) ? fmap[y][x]&0x0f : 0;
230 static inline Uint8 bgTile (int x, int y) {
231 return (x >= 0 && y >= 0 && x < MAP_WIDTH && y < MAP_HEIGHT) ? bmap[y][x]&0x0f : 0;
235 static int mapGet (int tid, int fg, int x, int y) {
236 return fg ? fgTile(x, y) : bgTile(x, y);
240 static inline void setFGTile (int x, int y, Uint8 tile) {
241 if (x >= 0 && y >= 0 && x < MAP_WIDTH && y < MAP_HEIGHT) fmap[y][x] = (fmap[y][x]&0xf0)|(tile&0x0f);
245 static inline void setBGTile (int x, int y, Uint8 tile) {
246 if (x >= 0 && y >= 0 && x < MAP_WIDTH && y < MAP_HEIGHT) bmap[y][x] = (bmap[y][x]&0xf0)|(tile&0x0f);
250 static void mapSet (int tid, int fg, int x, int y, int tile) {
251 if (fg) setFGTile(x, y, tile); else setBGTile(x, y, tile);
255 ////////////////////////////////////////////////////////////////////////////////
256 // cliprect should be set
257 static void levelDrawMap (SDL_Surface *frame) {
258 if (!inMinimap) {
259 int scrX = vmGVars[GVAR_SCR_X], scrY = vmGVars[GVAR_SCR_Y];
261 for (int dy = 0; dy < VIS_HEIGHT; ++dy) {
262 for (int dx = 0; dx < VIS_WIDTH; ++dx) {
263 int x = scrX+dx, y = scrY+dy;
264 Uint8 b = bgTile(x, y), f = fgTile(x, y);
266 if (b) blitSurface2x(frame, VIS_X+dx*20, VIS_Y+dy*10, banks[CONST_BANK_BG_TILES].spr[b-1][0]);
267 if (f) blitSurface2x(frame, VIS_X+dx*20, VIS_Y+dy*10, banks[CONST_BANK_FG_TILES].spr[f-1][0]);
270 } else {
271 for (int dy = 0; dy < MAP_HEIGHT; ++dy) {
272 for (int dx = 1; dx < MAP_WIDTH; ++dx) {
273 Uint8 b = bgTile(dx, dy), f = fgTile(dx, dy), t = 8;
275 if (f == 0) {
276 if (b >= 1 && b <= 8) t = b-1; else t = 8;
277 } else {
278 t = f+8;
280 if (banks[CONST_BANK_MAP_TILES].spr[t][0]) {
281 blitSurface2x(frame, VIS_X+dx*6, VIS_Y+dy*4, banks[CONST_BANK_MAP_TILES].spr[t][0]);
289 static void levelDrawSprites (SDL_Surface *frame) {
290 if (!inMinimap) {
291 int scrX = vmGVars[GVAR_SCR_X], scrY = vmGVars[GVAR_SCR_Y];
293 for (int f = 0; f < VM_MAX_THREADS; ++f) {
294 if (vmIsThreadAlive(f) && !vmIsSuspendedThread(f)) {
295 int b = vmGetTVar(f, TVAR_SPR_BANK);
296 int s = vmGetTVar(f, TVAR_SPR_NUM);
297 int d = vmGetTVar(f, TVAR_SPR_DIR);
299 if (d >= 0 && d <= 1 && s >= 0 && b >= 0 && b <= 255 && s < banks[b].count && banks[b].spr[s][d]) {
300 SDL_Surface *sf = banks[b].spr[s][d];
301 int x = vmGetTVar(f, TVAR_POS_X)-scrX;
302 int y = vmGetTVar(f, TVAR_POS_Y)-scrY;
303 int tx = vmGetTVar(f, TVAR_POS_TX);
304 int ty = vmGetTVar(f, TVAR_POS_TY);
306 if (b == CONST_BANK_IM_PROF || b == CONST_BANK_PROF) tx -= 6;
307 blitSurface2x(frame, VIS_X+x*20+tx, VIS_Y+y*10+ty-sf->h/2, sf);
311 } else {
312 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]);
313 for (int f = 1; f < VM_MAX_THREADS; ++f) {
314 if (vmIsThreadAlive(f) && !vmIsSuspendedThread(f)) {
315 int i = vmGetTVar(f, TVAR_ITEM_ID);
316 if (i > 0 && i < ITEM_MAX) {
317 SDL_Surface *sf = banks[CONST_BANK_MAP_ITEMS].spr[i][0];
318 int x = vmGetTVar(f, TVAR_POS_X);
319 int y = vmGetTVar(f, TVAR_POS_Y);
321 blitSurface2x(frame, VIS_X+(x+0)*6, VIS_Y+(y-2)*4, sf);
329 static void drawSpriteBank (SDL_Surface *frame, SpriteBank *bank) {
330 SDL_Rect dst;
331 int x = 0, y = 0, maxh = 0;
333 SDL_SetClipRect(frame, NULL);
334 dst.x = 0;
335 dst.y = 0;
336 dst.w = frame->w;
337 dst.h = frame->h;
338 SDL_FillRect(frame, &dst, palette[0]);
340 for (int num = 0; num < bank->count; ++num) {
341 SDL_Surface *s = bank->spr[num][0];
343 if (s != NULL) {
344 char buf[16];
345 int w = s->w/2;
347 sprintf(buf, "%d", num);
348 if (w < strlen(buf)*8+2) w = strlen(buf)*8+2;
349 if (x+w > 320) {
350 x = 0;
351 y += maxh;
352 maxh = 0;
354 if (maxh < s->h/2+1) maxh = s->h/2+1;
355 blitSurface2x(frame, x, y, s);
356 drawString(frame, buf, x, y, 1);
357 x += w+1;
363 static void frmGameDraw (SDL_Surface *frame) {
364 SDL_Rect rc;
365 char buf[8];
366 int pi;
368 SDL_SetClipRect(frame, NULL);
369 if (!inMinimap) {
370 blitSurface(frame, 0, 0, backs[levelback]);
371 } else {
372 blitSurface(frame, 0, 0, backs[1]);
374 drawString(frame, levelname, lnamex, 0, 0x76);
376 pi = vmGVars[GVAR_PROF_ITEM];
377 if (vmIsThreadAlive(pi) && vmIsSuspendedThread(pi)) {
378 pi = vmGetTVar(pi, TVAR_ITEM_ID);
379 if (pi > 0 && pi < 11) {
380 //blitSurface2x(frame, 0, 0, itemSpr[profItem.frame]);
381 drawString(frame, itemNames[pi], 0, 0, 1);
385 sprintf(buf, "%d", curLevel+1);
386 drawString(frame, buf, 320-strlen(buf)*8, 0, 1);
388 rc.x = VIS_X*2;
389 rc.y = VIS_Y*2;
390 rc.w = VIS_WIDTH*20*2;
391 rc.h = VIS_HEIGHT*10*2;
392 SDL_SetClipRect(frame, &rc);
394 levelDrawMap(frame);
395 levelDrawSprites(frame);
397 levelDrawProf(frame);
398 levelDrawItems(frame);
399 levelDrawProfDeath(frame);
403 SDL_SetClipRect(frame, NULL);
404 //ebfDrawText(frame, xen, "TESTING:09!", 1, 1);
405 if (keyF1) drawSpriteList(frame, profSpr[0], PROF_CNT);
407 for (int f = 84; f <= 90; ++f) if (fkeys[f-83]) drawSpriteBank(frame, &banks[f]);
411 ////////////////////////////////////////////////////////////////////////////////
412 int loadLevel (int lidx) {
413 if (lidx < 0 || lidx > 73) return -1;
414 return loadLevelInternal(&resfile, lidx);
418 void activateMinimap (void) {
419 inMinimap = 1;
420 vmPaused = 1;
424 ////////////////////////////////////////////////////////////////////////////////
425 void setMainLoopGame (void) {
426 frameCB = frmGameDraw;
427 keyCB = frmGameKey;
428 vmMapGetCB = mapGet;
429 vmMapSetCB = mapSet;
431 vmPaused = 0;
432 inMinimap = 0;
433 curLevel = -1;
434 memset(fkeys, 0, sizeof(fkeys));
436 for (int f = 0; f < VM_MAX_THREADS; ++f) {
437 vmSetTVar(f, TVAR_ITEM_ID, -1);
438 vmSetTVar(f, TVAR_SPR_BANK, 0);
439 vmSetTVar(f, TVAR_SPR_NUM, 0);
440 vmSetTVar(f, TVAR_POS_X, 0);
441 vmSetTVar(f, TVAR_POS_Y, 0);
442 vmSetTVar(f, TVAR_POS_TX, 0);
443 vmSetTVar(f, TVAR_POS_TY, 0);