alot of things changed in code file format; preparing for room local scripts
[awish.git] / src / awish.c
blob5f8deaa44200cfd93207903c6fbfd663f5d4ae3e
1 /*
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/>.
15 #include <ctype.h>
16 #include <stdio.h>
17 #include <stdlib.h>
18 #include <unistd.h>
20 #include "SDL.h"
21 #include "SDL_endian.h"
23 #ifdef WIN32
24 # include <windows.h>
25 #endif
27 #include "resfile.h"
28 #include "video.h"
29 #include "mainloop.h"
30 #include "vm.h"
31 #include "gameglobals.h"
32 #include "game.h"
33 #include "title.h"
36 int goobers = 0;
37 int datfirst = 0;
40 ////////////////////////////////////////////////////////////////////////////////
41 static SDL_Surface *loadCFScreen (const char *fname, SDL_Surface *old, int w, int h, int chained) {
42 SDL_Surface *new;
43 static Uint8 pal[256][3];
44 static Uint32 opal[256];
45 static Uint8 scr[64000];
46 int rsz;
47 uint8_t *diskdata = tryDiskFile(fname, &rsz);
49 if (diskdata == NULL) return old;
50 if (rsz < w*h+(chained >= 0 ? 768 : 0)) { free(diskdata); return old; }
52 new = createSurface(320*2, 200*2);
53 if (!new) { free(diskdata); return old; }
55 for (int dy = 0; dy < 200; ++dy) {
56 for (int dx = 0; dx < 320; ++dx) {
57 putPixel2x(new, dx, dy, 0);
61 memcpy(scr, diskdata, w*h);
62 if (chained >= 0) memcpy(pal, diskdata+w*h, 768);
63 free(diskdata);
65 if (chained >= 0) {
66 memcpy(opal, palette, 256*4);
67 for (int f = 0; f < 256; ++f) {
68 pal[f][0] <<= 2;
69 if (pal[f][0] != 0) pal[f][0] |= 3;
70 pal[f][1] <<= 2;
71 if (pal[f][1] != 0) pal[f][1] |= 3;
72 pal[f][2] <<= 2;
73 if (pal[f][2] != 0) pal[f][2] |= 3;
74 palette[f] = SDL_MapRGB(screen->format, pal[f][0], pal[f][1], pal[f][2]);
78 if (chained > 0) {
79 for (int dy = 0; dy < h; ++dy) {
80 for (int dx = 0; dx < w/4; ++dx) {
81 for (int c = 0; c < 4; ++c) {
82 putPixel2x(new, dx*4+c, dy, scr[dy*(w/4)+(w*h)/4*c+dx]);
86 } else {
87 for (int dy = 0; dy < h; ++dy) {
88 for (int dx = 0; dx < w; ++dx) {
89 putPixel2x(new, dx, dy, scr[dy*w+dx]);
94 memcpy(palette, opal, 256*4);
95 SDL_FreeSurface(old);
96 return new;
100 ////////////////////////////////////////////////////////////////////////////////
101 static int loadFont (void) {
102 int sz;
103 uint8_t *buf = loadResFile(&resfile, 92, &sz);
105 if (buf == NULL) return -1;
106 if (sz != 256*8) { free(buf); return -1; }
107 memcpy(font, buf, 256*8);
108 free(buf);
109 return 0;
113 static int loadPalette (void) {
114 int sz;
115 uint8_t *buf = loadResFile(&resfile, 83, &sz);
117 if (buf == NULL) return -1;
118 if (sz != 768) { free(buf); return -1; }
119 for (int f = 0; f < 768; ++f) {
120 buf[f] <<= 2;
121 if (buf[f] != 0) buf[f] |= 3;
123 for (int f = 0; f < 256; ++f) palette[f] = SDL_MapRGB(screen->format, buf[f*3+0], buf[f*3+1], buf[f*3+2]);
124 free(buf);
125 return 0;
129 static SDL_Surface *loadImage (ResFile *resfile, int idx) {
130 int sz;
131 static Uint8 *img;
132 SDL_Surface *res;
134 img = loadResFile(resfile, idx, &sz);
135 if (img == NULL) return NULL;
136 if (sz < 320*200) { free(img); return NULL; }
137 res = createSurface(320*2, 200*2);
138 if (res == NULL) { free(img); return NULL; }
139 SDL_SetColorKey(res, 0, 0); // clear colorkey info (it's the fullscreen image after all!)
140 for (int f = 0; f < 320*200; ++f) putPixel2x(res, f%320, f/320, img[f]);
141 free(img);
142 return res;
146 // return # of sprites loaded or <0 on error
147 static int loadSpriteBank (SpriteBank *bank, ResFile *resfile, int idx) {
148 Uint8 *buf;
149 int sz, pos, cnt;
151 if ((buf = loadResFile(resfile, idx, &sz)) == NULL) return -1;
152 if (sz < 3) { free(buf); return -1; }
153 pos = 0;
154 cnt = 0;
155 bank->count = 0;
156 while (pos+4 <= sz) {
157 int h = ((Uint32)buf[pos+0])+256*((Uint32)buf[pos+1]);
158 int w = ((Uint32)buf[pos+2])+256*((Uint32)buf[pos+3]);
160 pos += 4;
161 if (h > 0 && w > 0) {
162 SDL_Surface *s0 = createSurface(w*2, h*2);
163 SDL_Surface *s1 = createSurface(w*2, h*2);
165 if (!s0 || !s1) { free(buf); return -1; }
167 for (int y = 0; y < h; ++y) {
168 for (int x = 0; x < w; ++x) {
169 if (pos < sz) {
170 putPixel2x(s0, x, y, buf[pos]);
171 putPixel2x(s1, w-x-1, y, buf[pos]);
172 ++pos;
176 bank->spr[bank->count][0] = s0;
177 bank->spr[bank->count][1] = s1;
178 ++(bank->count);
181 free(buf);
182 return cnt;
187 static void freeSpriteBank (SpriteBank *bank) {
188 for (int f = bank->count-1; f >= 0; --f) {
189 SDL_FreeSurface(bank->spr[f][1]);
190 SDL_FreeSurface(bank->spr[f][0]);
196 ////////////////////////////////////////////////////////////////////////////////
197 static void quitCleanupRes (void) {
198 freeLabels();
199 deinitResFile(&resfile);
200 //for (int f = 0; f < sizeof(banks)/sizeof(SpriteBank); ++f) freeSpriteBank(&banks[f]);
204 ////////////////////////////////////////////////////////////////////////////////
205 static int awishRST (int tid, int opcode, int argc, int argv[], int *argp[]) {
206 vmGVars[GVAR_RST_RESULT] = 0;
208 if (argv[0] == CONST_FRST_ML_TITLE) {
209 setMainLoopTitle();
210 } else if (argv[0] == CONST_FRST_ML_GAME) {
211 setMainLoopGame();
212 } else if (argv[0] == CONST_FRST_MINIMAP) {
213 activateMinimap();
214 } else if (argv[0] == CONST_FRST_LOAD_LEVEL) {
215 // levelnum
216 if (vmLoadArgs(tid, 2, argv, argp, argc, argv, argp) != 0) fatal("out of args");
217 vmGVars[GVAR_RST_RESULT] = loadLevel(argv[1]);
218 } else if (argv[0] == CONST_FRST_DEBUG_PRINT_STR) {
219 int pos = 0, len = 0;
221 switch (argc) {
222 case 1:
223 pos = vmPop(tid);
224 goto dolen;
225 case 2:
226 pos = argv[1];
227 dolen: if (pos >= 0) {
228 while (pos < vmCodeSize && vmCode[pos+len]) ++len;
230 break;
231 case 3:
232 pos = argv[1];
233 len = argv[2];
234 break;
236 if (goobers) {
237 for (; len > 0; --len, ++pos) if (pos >= 0 && pos < vmCodeSize) fputc(vmCode[pos], stderr);
239 } else if (argv[0] == CONST_FRST_DEBUG_PRINT_NUM) {
240 switch (argc) {
241 case 1: argv[1] = vmPop(tid); // fallthru
242 case 2: if (goobers) fprintf(stderr, "%d", argv[1]); break;
243 case 3: if (goobers) fprintf(stderr, "%d,%d", argv[1], argv[2]); break;
245 } else {
246 fatal("invalid RST: %d", argv[0]);
248 return 0;
252 ////////////////////////////////////////////////////////////////////////////////
253 static int checkLevelCode (const char *t) {
254 int ctrd;
256 if (!t || !t[0]) return -1;
257 ctrd = vmNewThread(0);
258 for (int level = 0; level < vmGVars[GVAR_MAX_LEVEL]; ++level) {
259 //fprintf(stderr, "%d/%d\n", level+1, vmGVars[GVAR_MAX_LEVEL]);
260 vmPush(ctrd, level);
261 if (vmExecuteBSR(ctrd, CODE_ENTRY_GET_LEVEL_CODE, 0) == 0) {
262 int pos = vmGVars[GVAR_LEVEL_CODE_OFS], len = vmGVars[GVAR_LEVEL_CODE_LEN], ok = 1;
264 if (strlen(t) == len && pos >= 0 && len > 0 && pos+len <= vmCodeSize) {
265 //fwrite(vmCode+pos, len, 1, stderr);
266 //fprintf(stderr, " [%s]\n", t);
267 for (int f = 0; f < len; ++f) {
268 //fprintf(stderr, "%c %c\n", tolower(t[f]), tolower(vmCode[pos+f]));
269 if (tolower(t[f]) != tolower(vmCode[pos+f])) { ok = 0; break; }
271 if (ok) {
272 if (goobers) fprintf(stderr, "found code for level #%02d\n", level+1);
273 return level;
276 } else {
277 if (goobers) fprintf(stderr, "sorry!\n");
278 break;
281 vmKillThread(ctrd);
282 return -1;
286 ////////////////////////////////////////////////////////////////////////////////
287 #ifdef _WIN32
288 # include "cmdline.c"
289 #endif
292 ////////////////////////////////////////////////////////////////////////////////
293 int main (int argc, char *argv[]) {
294 int csz;
296 #ifdef _WIN32
297 cmdLineParse();
298 argc = k8argc;
299 argv = k8argv;
300 #endif
302 for (int f = 1; f < argc; ++f) {
303 if (strcmp(argv[f], "-goobers") == 0) goobers = 1;
304 else if (strcmp(argv[f], "-dat") == 0) datfirst = 1;
305 else continue;
306 for (int c = f+1; c < argc; ++c) argv[c-1] = argv[c];
307 argv[--argc] = NULL;
308 --f;
311 initResFile(&resfile, "RESOURCE.DAT");
312 atexit(quitCleanupRes);
314 if (loadFont() != 0) {
315 fprintf(stderr, "FATAL: can't load font!\n");
316 exit(1);
319 sdlInit();
320 initVideo();
322 if (loadPalette() != 0) {
323 fprintf(stderr, "FATAL: can't load palette!\n");
324 exit(1);
328 SurfaceLock lock;
330 lockSurface(&lock, screen);
331 drawString(screen, "loading...", 2, 200-9, 1);
332 unlockSurface(&lock);
333 SDL_Flip(screen);
336 for (int f = 0; f < 8; ++f) {
337 if ((backs[(f+1)%8] = loadImage(&resfile, f)) == NULL) {
338 fprintf(stderr, "FATAL: can't load image #%d!\n", f);
339 exit(1);
343 backs[0] = loadCFScreen("CFTITLE.DAT", backs[0], 320, 200, 1);
344 backs[0] = loadCFScreen("cftitle.dat", backs[0], 320, 200, 1);
346 memset(banks, 0, sizeof(banks));
347 for (int f = 84; f <= 90; ++f) {
348 if (loadSpriteBank(&banks[f], &resfile, f)) {
349 fprintf(stderr, "FATAL: can't load sprint bank #%d!\n", f);
350 exit(1);
354 if (vmInitialize() != 0) fatal("can't init VM");
356 memset(vmGVars, 0, sizeof(vmGVars));
357 vmRSTCB = awishRST;
359 addLabel("flag_skip_title", LB_GVAR, 120, 1); // 1: public
360 vmGVars[120] = 0;
362 vmCodeSize = 100;
363 if ((csz = loadVMCode(&resfile, vmCodeSize)) < 1) {
364 fprintf(stderr, "FATAL: can't load VM code!\n");
365 exit(1);
367 vmCodeSize += csz;
368 initLabels();
370 //vmGVars[GVAR_KEY_QUIT] = 0;
371 //vmGVars[GVAR_KEY_START] = 0;
372 vmGVars[GVAR_GOOBERS] = goobers;
374 vmSetPC(0, CODE_ENTRY_TITLE);
375 if (vmExecuteBSR(0, CODE_ENTRY_MAIN_INIT, 0) != 0) fatal("can't initialize game");
376 if (goobers) fprintf(stderr, "MAX LEVEL: %d\n", vmGVars[GVAR_MAX_LEVEL]);
378 if (argc > 1) {
379 // check level code
380 for (int f = 1; f < argc; ++f) {
381 int lvl = checkLevelCode(argv[f]);
383 if (lvl >= 0) {
384 vmGVars[GVAR_START_LEVEL] = lvl;
385 break;
390 mainLoop();
392 return 0;
396 #ifdef WIN32
397 int CALLBACK WinMain (HINSTANCE hInstance, HINSTANCE unused__, LPSTR lpszCmdLine, int nCmdShow) {
398 char *shit[] = { (char *)"shit", NULL };
399 return SDL_main(1, shit);
401 #endif