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/>.
26 #include "gameglobals.h"
34 ////////////////////////////////////////////////////////////////////////////////
35 #define MAP_WIDTH (44)
36 #define MAP_HEIGHT (41)
37 #define VIS_WIDTH (15)
38 #define VIS_HEIGHT (17)
43 ////////////////////////////////////////////////////////////////////////////////
44 static const char *itemNames
[] = {
76 int type
; // 0: inactive
78 int frame
; // animation frame
79 int fframe
, lframe
; // first and last anim frame
85 ////////////////////////////////////////////////////////////////////////////////
87 static char levelname
[257];
90 static Uint8 bmap
[MAP_HEIGHT
][MAP_WIDTH
];
91 static Uint8 fmap
[MAP_HEIGHT
][MAP_WIDTH
];
92 static Uint8 xflags
[MAP_WIDTH
];
96 static int doSave
= 0;
99 ////////////////////////////////////////////////////////////////////////////////
100 static void frmGameKey (SDL_KeyboardEvent
*key
) {
101 if (key
->type
== SDL_KEYDOWN
) {
102 switch (key
->keysym
.sym
) {
108 vmGVars
[GVAR_KEY_MINIMAP
] = 0;
112 vmGVars
[GVAR_KEY_QUIT
] = 1;
115 vmGVars
[GVAR_KEY_MINIMAP
] = 1;
118 if ((key
->keysym
.mod
&(KMOD_CTRL
)) != 0) vmGVars
[GVAR_KEY_RESTART
] = 1;
121 if (goobers
&& (key
->keysym
.mod
&(KMOD_CTRL
)) != 0) { doSave
= 1; vmPaused
= 1; }
124 if (goobers
&& (key
->keysym
.mod
&(KMOD_CTRL
)) != 0) { doSave
= -1; vmPaused
= 1; }
130 switch (key
->keysym
.sym
) {
131 case SDLK_LEFT
: case SDLK_KP4
: vmGVars
[GVAR_KEY_LEFT
] = (key
->type
== SDL_KEYDOWN
); break;
132 case SDLK_RIGHT
: case SDLK_KP6
: vmGVars
[GVAR_KEY_RIGHT
] = (key
->type
== SDL_KEYDOWN
); break;
133 case SDLK_UP
: case SDLK_KP8
: vmGVars
[GVAR_KEY_UP
] = (key
->type
== SDL_KEYDOWN
); break;
134 case SDLK_DOWN
: case SDLK_KP2
: vmGVars
[GVAR_KEY_DOWN
] = (key
->type
== SDL_KEYDOWN
); break;
135 case SDLK_SPACE
: case SDLK_KP0
: vmGVars
[GVAR_KEY_TAKE
] = (key
->type
== SDL_KEYDOWN
); break;
136 case SDLK_RETURN
: case SDLK_KP_PERIOD
: vmGVars
[GVAR_KEY_USE
] = (key
->type
== SDL_KEYDOWN
); break;
141 switch (key
->keysym
.sym
) {
142 case SDLK_f
: vmGVars
[GVAR_KEY_FALL_CHEAT
] = (key
->type
== SDL_KEYDOWN
); break;
143 case SDLK_w
: vmGVars
[GVAR_KEY_WALK_CHEAT
] = (key
->type
== SDL_KEYDOWN
); break;
144 case SDLK_KP_MINUS
: vmGVars
[GVAR_KEY_PLEV_CHEAT
] = (key
->type
== SDL_KEYDOWN
); break;
145 case SDLK_KP_PLUS
: vmGVars
[GVAR_KEY_NLEV_CHEAT
] = (key
->type
== SDL_KEYDOWN
); break;
147 case SDLK_F1
: fkeys
[1] = (key
->type
== SDL_KEYDOWN
); break;
148 case SDLK_F2
: fkeys
[2] = (key
->type
== SDL_KEYDOWN
); break;
149 case SDLK_F3
: fkeys
[3] = (key
->type
== SDL_KEYDOWN
); break;
150 case SDLK_F4
: fkeys
[4] = (key
->type
== SDL_KEYDOWN
); break;
151 case SDLK_F5
: fkeys
[5] = (key
->type
== SDL_KEYDOWN
); break;
152 case SDLK_F6
: fkeys
[6] = (key
->type
== SDL_KEYDOWN
); break;
153 case SDLK_F7
: fkeys
[7] = (key
->type
== SDL_KEYDOWN
); break;
154 case SDLK_F8
: fkeys
[8] = (key
->type
== SDL_KEYDOWN
); break;
155 case SDLK_F9
: fkeys
[9] = (key
->type
== SDL_KEYDOWN
); break;
162 ////////////////////////////////////////////////////////////////////////////////
163 static int loadLevelInternal (ResFile
*resfile
, int lidx
) {
165 int sz
, res
= -1, pos
;
166 static Item items
[256];
167 static int itemCount
;
168 static int scrX
, scrY
;
169 static int profX
, profY
;
172 vmGVars
[GVAR_MAP_WIDTH
] = MAP_WIDTH
;
173 vmGVars
[GVAR_MAP_HEIGHT
] = MAP_HEIGHT
;
174 vmGVars
[GVAR_VIS_WIDTH
] = VIS_WIDTH
;
175 vmGVars
[GVAR_VIS_HEIGHT
] = VIS_HEIGHT
;
177 if ((lvl
= loadResFile(resfile
, lidx
+9, &sz
)) == NULL
) return -1;
178 if (sz
< 3700) goto quit
;
179 if (lvl
[0] > 25) goto quit
;
180 memset(levelname
, 0, sizeof(levelname
));
181 if (lvl
[0] > 0) memcpy(levelname
, lvl
+1, lvl
[0]);
182 lnamex
= (320-strlen(levelname
)*8)/2;
183 sprintf(buf
, "%d", lidx
+1);
184 while (lnamex
+strlen(levelname
)*8+strlen(buf
)*8+6*8 > 320) lnamex
-= 8;
186 if (levelback
< 1 || levelback
> 7) levelback
= 1;
189 vmSetTVar(0, TVAR_POS_X
, profX
);
190 vmSetTVar(0, TVAR_POS_Y
, profY
);
192 scrY
= lvl
[30]; if (scrY
> 0) --scrY
;
193 vmGVars
[GVAR_SCR_X
] = scrX
;
194 vmGVars
[GVAR_SCR_Y
] = scrY
;
196 memset(bmap
, 0, sizeof(bmap
));
197 memset(fmap
, 0, sizeof(fmap
));
198 memset(xflags
, 0, sizeof(xflags
));
199 for (int x
= 1; x
< MAP_WIDTH
; ++x
) {
200 for (int y
= 0; y
< MAP_HEIGHT
; ++y
) {
201 bmap
[y
][x
] = lvl
[pos
++];
204 for (int x
= 1; x
< MAP_WIDTH
; ++x
) {
205 for (int y
= 0; y
< MAP_HEIGHT
; ++y
) {
206 fmap
[y
][x
] = lvl
[pos
++];
208 pos
+= 3; // skip unknown bytes
211 itemCount
= lvl
[pos
++]+1; // at least one item is always here
212 for (int f
= 0; f
< itemCount
; ++f
) {
215 items
[f
].x
= lvl
[pos
++];
216 items
[f
].y
= lvl
[pos
++];
217 items
[f
].fframe
= lvl
[pos
++];
218 items
[f
].lframe
= lvl
[pos
++];
219 items
[f
].frame
= lvl
[pos
++];
220 items
[f
].animated
= lvl
[pos
++];
221 if (!items
[f
].animated
) items
[f
].frame
= items
[f
].fframe
;
224 items
[f
].type
= lvl
[pos
++];
227 tid
= vmNewThread(CODE_ENTRY_ITEM
);
228 if (tid
< 0) goto quit
;
229 vmSetTVar(tid
, TVAR_ITEM_ID
, items
[f
].type
);
230 vmSetTVar(tid
, TVAR_ANIMATED
, items
[f
].animated
);
231 vmSetTVar(tid
, TVAR_AFIRST_FRAME
, items
[f
].fframe
);
232 vmSetTVar(tid
, TVAR_ALAST_FRAME
, items
[f
].lframe
);
233 vmSetTVar(tid
, TVAR_AFRAME
, items
[f
].frame
);
234 if (items
[f
].type
== 6) vmSetTVar(tid
, TVAR_AFRAME
, lvl
[pos
-6]);
235 vmSetTVar(tid
, TVAR_POS_X
, items
[f
].x
);
236 vmSetTVar(tid
, TVAR_POS_Y
, items
[f
].y
);
237 vmSetTVar(tid
, TVAR_POS_TX
, 0);
238 vmSetTVar(tid
, TVAR_POS_TY
, 0);
239 vmSetTVar(tid
, TVAR_SPR_BANK
, CONST_BANK_ITEMS
);
240 vmSetTVar(tid
, TVAR_SPR_NUM
, items
[f
].frame
);
241 vmSetTVar(tid
, TVAR_SPR_DIR
, 0);
253 ////////////////////////////////////////////////////////////////////////////////
254 static inline Uint8
fgTile (int x
, int y
) {
255 return (x
>= 0 && y
>= 0 && x
< MAP_WIDTH
&& y
< MAP_HEIGHT
) ? fmap
[y
][x
]&0x0f : 0;
259 static inline Uint8
bgTile (int x
, int y
) {
260 if (y
== -666) return (x
>= 0 && x
< MAP_WIDTH
) ? xflags
[x
] : 0;
261 return (x
>= 0 && y
>= 0 && x
< MAP_WIDTH
&& y
< MAP_HEIGHT
) ? bmap
[y
][x
]&0x0f : 0;
265 static int mapGet (int tid
, int fg
, int x
, int y
) {
266 return fg
? fgTile(x
, y
) : bgTile(x
, y
);
270 static inline void setFGTile (int x
, int y
, Uint8 tile
) {
271 if (x
>= 0 && y
>= 0 && x
< MAP_WIDTH
&& y
< MAP_HEIGHT
) fmap
[y
][x
] = (fmap
[y
][x
]&0xf0)|(tile
&0x0f);
275 static inline void setBGTile (int x
, int y
, Uint8 tile
) {
276 if (y
== -666 && x
>= 0 && x
< MAP_WIDTH
) xflags
[x
] = tile
;
277 if (x
>= 0 && y
>= 0 && x
< MAP_WIDTH
&& y
< MAP_HEIGHT
) bmap
[y
][x
] = (bmap
[y
][x
]&0xf0)|(tile
&0x0f);
281 static void mapSet (int tid
, int fg
, int x
, int y
, int tile
) {
282 if (fg
) setFGTile(x
, y
, tile
); else setBGTile(x
, y
, tile
);
286 ////////////////////////////////////////////////////////////////////////////////
287 // cliprect should be set
288 static void levelDrawMap (SDL_Surface
*frame
) {
290 int scrX
= vmGVars
[GVAR_SCR_X
], scrY
= vmGVars
[GVAR_SCR_Y
];
292 for (int dy
= 0; dy
< VIS_HEIGHT
; ++dy
) {
293 for (int dx
= 0; dx
< VIS_WIDTH
; ++dx
) {
294 int x
= scrX
+dx
, y
= scrY
+dy
;
295 Uint8 b
= bgTile(x
, y
), f
= fgTile(x
, y
);
297 if (b
) blitSurface2x(frame
, VIS_X
+dx
*20, VIS_Y
+dy
*10, banks
[CONST_BANK_BG_TILES
].spr
[b
-1][0]);
298 if (f
) blitSurface2x(frame
, VIS_X
+dx
*20, VIS_Y
+dy
*10, banks
[CONST_BANK_FG_TILES
].spr
[f
-1][0]);
302 for (int dy
= 0; dy
< MAP_HEIGHT
; ++dy
) {
303 for (int dx
= 1; dx
< MAP_WIDTH
; ++dx
) {
304 Uint8 b
= bgTile(dx
, dy
), f
= fgTile(dx
, dy
), t
= 8;
307 if (b
>= 1 && b
<= 8) t
= b
-1; else t
= 8;
311 if (banks
[CONST_BANK_MAP_TILES
].spr
[t
][0]) {
312 blitSurface2x(frame
, VIS_X
+dx
*6, VIS_Y
+dy
*4, banks
[CONST_BANK_MAP_TILES
].spr
[t
][0]);
320 static void levelDrawSprites (SDL_Surface
*frame
) {
322 int scrX
= vmGVars
[GVAR_SCR_X
], scrY
= vmGVars
[GVAR_SCR_Y
];
323 int py
= vmGetTVar(0, TVAR_POS_Y
)-scrY
;
325 for (int cc
= 0; cc
<= 2; ++cc
) {
326 for (int f
= cc
==1?1:0; f
<= vmLastThread(); ++f
) {
327 if (vmIsThreadAlive(f
) && !vmIsSuspendedThread(f
)) {
328 int b
= vmGetTVar(f
, TVAR_SPR_BANK
);
329 int s
= vmGetTVar(f
, TVAR_SPR_NUM
);
330 int d
= vmGetTVar(f
, TVAR_SPR_DIR
);
332 if (d
>= 0 && d
<= 1 && s
>= 0 && b
>= 0 && b
<= 255 && s
< banks
[b
].count
&& banks
[b
].spr
[s
][d
]) {
333 SDL_Surface
*sf
= banks
[b
].spr
[s
][d
];
334 int x
= vmGetTVar(f
, TVAR_POS_X
)-scrX
;
335 int y
= vmGetTVar(f
, TVAR_POS_Y
)-scrY
;
336 int tx
= vmGetTVar(f
, TVAR_POS_TX
);
337 int ty
= vmGetTVar(f
, TVAR_POS_TY
);
338 int si
= vmGetTVar(f
, TVAR_SPR_ITEM
);
340 if (cc
== 0 && b
== CONST_BANK_ITEMS
) continue;
341 if (cc
== 1 && b
!= CONST_BANK_ITEMS
) continue;
343 if (b
!= CONST_BANK_PROF
) {
344 if (b
!= CONST_BANK_ITEMS
) continue;
345 if (y
< py
) continue;
348 if (b
== CONST_BANK_IM_PROF
|| b
== CONST_BANK_PROF
) tx
-= 5;
349 blitSurface2x(frame
, VIS_X
+x
*20+tx
, VIS_Y
+y
*10+ty
-sf
->h
/2, sf
);
350 if (si
> 0 && si
< banks
[CONST_BANK_ITEMS
].count
) {
351 sf
= banks
[CONST_BANK_ITEMS
].spr
[si
][0];
352 blitSurface2x(frame
, VIS_X
+x
*20+tx
, VIS_Y
+y
*10+ty
-sf
->h
/2-24, sf
);
359 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]);
360 for (int f
= 1; f
< VM_MAX_THREADS
; ++f
) {
361 if (vmIsThreadAlive(f
) && !vmIsSuspendedThread(f
)) {
362 int i
= vmGetTVar(f
, TVAR_ITEM_ID
);
363 if (i
> 0 && i
< ITEM_MAX
) {
364 SDL_Surface
*sf
= banks
[CONST_BANK_MAP_ITEMS
].spr
[i
][0];
365 int x
= vmGetTVar(f
, TVAR_POS_X
);
366 int y
= vmGetTVar(f
, TVAR_POS_Y
);
368 blitSurface2x(frame
, VIS_X
+(x
+0)*6, VIS_Y
+(y
-2)*4, sf
);
376 static void levelDrawCode (SDL_Surface
*frame
) {
377 int pos
= vmGVars
[GVAR_LEVEL_CODE_OFS
], len
= vmGVars
[GVAR_LEVEL_CODE_LEN
], x
;
380 if (pos
< 0 || len
< 1 || pos
+len
> vmCodeSize
) return;
382 sprintf(buf
, "%d", curLevel
);
384 for (; len
> 0; x
+= 8, ++pos
, --len
) drawChar(frame
, vmCode
[pos
], x
, 0, 3);
388 static void drawSpriteBank (SDL_Surface
*frame
, SpriteBank
*bank
) {
390 int x
= 0, y
= 0, maxh
= 0;
392 SDL_SetClipRect(frame
, NULL
);
397 SDL_FillRect(frame
, &dst
, palette
[3]);
399 for (int num
= 0; num
< bank
->count
; ++num
) {
400 SDL_Surface
*s
= bank
->spr
[num
][0];
406 sprintf(buf
, "%d", num
);
407 if (w
< strlen(buf
)*8+2) w
= strlen(buf
)*8+2;
413 if (maxh
< s
->h
/2+1) maxh
= s
->h
/2+1;
414 blitSurface2x(frame
, x
, y
, s
);
415 drawString(frame
, buf
, x
, y
, 1);
422 static int readBuf (FILE *fl
, void *buf
, int len
) {
423 unsigned char *c
= (unsigned char *)buf
;
428 if (fread(&b
, 1, 1, fl
) != 1) return -1;
436 static int writeBuf (FILE *fl
, const void *buf
, int len
) {
437 const unsigned char *c
= (const unsigned char *)buf
;
440 unsigned char b
= *c
++;
443 if (fwrite(&b
, 1, 1, fl
) != 1) return -1;
449 static int readDW (FILE *fl
, int *v
) {
452 for (int f
= 0; f
< 4; ++f
) {
455 if (fread(&b
, 1, 1, fl
) != 1) return -1;
461 for (int f
= 0; f
< 4; ++f
) *v
|= t
[f
]<<(8*f
);
467 static int writeDW (FILE *fl
, int v
) {
468 for (int f
= 0; f
< 4; ++f
) {
473 if (fwrite(&b
, 1, 1, fl
) != 1) return -1;
480 static void frmGameDraw (SDL_Surface
*frame
) {
485 if (vmPaused
&& doSave
) {
490 fl
= fopen("awish.sav", "rb");
494 if (vmLoadState(fl
) == 0) {
495 if (readDW(fl
, &inMinimap
) != 0) goto stop_loading
;
496 if (readDW(fl
, &curLevel
) != 0) goto stop_loading
;
497 if (readBuf(fl
, levelname
, sizeof(levelname
)) != 0) goto stop_loading
;
498 if (readDW(fl
, &lnamex
) != 0) goto stop_loading
;
499 if (readDW(fl
, &levelback
) != 0) goto stop_loading
;
500 if (readBuf(fl
, bmap
, sizeof(bmap
)) != 0) goto stop_loading
;
501 if (readBuf(fl
, fmap
, sizeof(fmap
)) != 0) goto stop_loading
;
502 if (readBuf(fl
, xflags
, sizeof(xflags
)) != 0) goto stop_loading
;
509 if (vmInitialize() != 0) fatal("can't init VM");
510 vmSetPC(0, CODE_ENTRY_TITLE
);
511 if (vmExecuteBSR(0, CODE_ENTRY_MAIN_INIT
, 0) != 0) fatal("can't initialize game");
520 fl
= fopen("awish.sav", "wb");
524 if (vmSaveState(fl
) == 0) {
525 if (writeDW(fl
, inMinimap
) != 0) goto stop_saving
;
526 if (writeDW(fl
, curLevel
) != 0) goto stop_saving
;
527 if (writeBuf(fl
, levelname
, sizeof(levelname
)) != 0) goto stop_saving
;
528 if (writeDW(fl
, lnamex
) != 0) goto stop_saving
;
529 if (writeDW(fl
, levelback
) != 0) goto stop_saving
;
530 if (writeBuf(fl
, bmap
, sizeof(bmap
)) != 0) goto stop_saving
;
531 if (writeBuf(fl
, fmap
, sizeof(fmap
)) != 0) goto stop_saving
;
532 if (writeBuf(fl
, xflags
, sizeof(xflags
)) != 0) goto stop_saving
;
537 if (!ok
) unlink("awish.sav");
541 vmPaused
= inMinimap
;
544 SDL_SetClipRect(frame
, NULL
);
547 blitSurface(frame
, 0, 0, backs
[levelback
]);
549 blitSurface(frame
, 0, 0, backs
[1]);
551 drawString(frame
, levelname
, lnamex
, 0, 0x76);
552 levelDrawCode(frame
);
554 pi
= vmGVars
[GVAR_PROF_ITEM
];
555 if (vmIsThreadAlive(pi
) && vmIsSuspendedThread(pi
)) {
556 pi
= vmGetTVar(pi
, TVAR_ITEM_ID
);
557 if (pi
> 0 && pi
< 11) {
558 drawString(frame
, itemNames
[pi
], 0, 0, 1);
562 sprintf(buf
, "%d", curLevel
+1);
563 drawString(frame
, buf
, 320-strlen(buf
)*8, 0, 1);
567 rc
.w
= VIS_WIDTH
*20*2;
568 rc
.h
= VIS_HEIGHT
*10*2;
569 SDL_SetClipRect(frame
, &rc
);
572 levelDrawSprites(frame
);
575 for (int f
= 84; f
<= 90; ++f
) if (fkeys
[f
-83]) drawSpriteBank(frame
, &banks
[f
]);
580 ////////////////////////////////////////////////////////////////////////////////
581 int loadLevel (int lidx
) {
582 if (lidx
< 0 || lidx
> 73) return -1;
583 return loadLevelInternal(&resfile
, lidx
);
587 void activateMinimap (void) {
594 ////////////////////////////////////////////////////////////////////////////////
595 void setMainLoopGame (void) {
596 frameCB
= frmGameDraw
;
605 memset(fkeys
, 0, sizeof(fkeys
));