ref: a6fe5b8c177c72c40efd76c6bf255897854bb76f
parent: eb9bc6ef4f8fd2595ec79e6469a1efd7b317fb28
author: qwx <>
date: Sat Jul 22 21:11:04 EDT 2017
add save/load game - hub: fix blinking prompts and cursor initial state - gm: use WPnone constant to indicate hiding weapon - gm: remove crmmap - map: reset boss die states' dt whenever loading map - wl3d(6): misc fixes and document save format - savegame format is incompatible; in particular, at the expense of a 16-32kB file size, it contains the current state of the map, including both map planes; this allows us to just load everything once instead of loading map from disk, spawning everything, then nuking most of the state and retrieving that from the save
--- a/dat.h
+++ b/dat.h
@@ -1199,6 +1199,7 @@
enum{
Mapdxy = 64,
Mapa = Mapdxy * Mapdxy,
+
MTgoup = 21,
MTarrows = 90,
MTpush = 98,
@@ -1206,6 +1207,11 @@
MTambush = 106,
MTsetec = 107,
MTfloor = MTsetec,
+
+ Nobj = 150,
+ Ndoor = 64,
+ Nstc = 400,
+ Narea = 37
};
struct Tile{
u16int p0;
@@ -1231,6 +1237,7 @@
WPpistol,
WPmg,
WPgatling,
+ WPnone,
GMup = 0,
GMsetec,
@@ -1280,10 +1287,10 @@
int com;
int demo;
int record;
- int load;
};
extern Game gm;
extern int allrecv, god, noclip, slomo;
+extern int loaded;
struct Score{
char name[58];
--- a/drw.c
+++ b/drw.c
@@ -422,6 +422,16 @@
}
void
+disking(void)
+{
+ static int n;
+
+ pic(104, 85, pict[Pread1] + n);
+ out();
+ n ^= 1;
+}
+
+void
viewbox(void)
{
int x, y;
--- a/fns.h
+++ b/fns.h
@@ -2,6 +2,8 @@
void grab(int);
void toss(void);
void flush(void);
+int wrsav(int);
+int ldsav(int);
char* demof(char*);
u16int* readmap(int);
void dat(char*);
@@ -30,6 +32,7 @@
void sdstripe(int);
void outbox(int, int, int, int, int, int);
void box(int, int, int, int, int, int, int);
+void disking(void);
void viewbox(void);
void hudf(void);
void hudh(void);
@@ -59,6 +62,8 @@
Obj* ospawn(Tile*, State*);
void uworld(void);
void mapmus(void);
+uchar* wrmap(uchar*);
+int ldmap(uchar*, uchar**);
void initmap(void);
void sodmap(void);
void dieturn(void);
@@ -74,6 +79,8 @@
void nextmap(void);
void game(void);
void spshunt(void);
+uchar* wrgm(uchar*);
+uchar* ldgm(uchar*);
void greset(void);
void ginit(uchar*, int, int);
uchar* opl2out(uchar*, int);
@@ -87,3 +94,10 @@
void stopmus(void);
void mus(int);
void initsnd(void);
+
+#define GET8(p) ((p)[0]);(p)++
+#define GET16(p) ((p)[0]|((p)[1]<<8));(p)+=2
+#define GET32(p) ((p)[0]|((p)[1]<<8)|((p)[2]<<16)|((p)[3]<<24));(p)+=4
+#define PUT8(p,v) (p)[0]=(v);(p)++
+#define PUT16(p,v) (p)[0]=(v);(p)[1]=(v)>>8;(p)+=2
+#define PUT32(p,v) (p)[0]=(v);(p)[1]=(v)>>8;(p)[2]=(v)>>16;(p)[3]=(v)>>24;(p)+=4
--- a/fs.c
+++ b/fs.c
@@ -444,7 +444,15 @@
enum{
Nplane = 2,
Planesz = Mapa * Nplane,
- Mapsz = Planesz * Nplane
+ Mapsz = Planesz * Nplane,
+ Svgmsz = 2+2+4+4+4+17*2+4+4+4+2+2+2+4+4+1+1,
+ Svmapsz = Mapa * (2+2+1+1) + Narea + Narea * Narea,
+ Svobjsz = 2+2+2+2+1+4+4+4+2+2+1+2+2+4+2+2+4+2+2,
+ Svstsz = 2+2+1+1,
+ Svdrsz = 2+1+1+2+2+2,
+ Svpshsz = 2+2+2+2,
+ Svsz = sizeof(savs[0]) + Svgmsz + Svmapsz + Svobjsz + 2 + 2 + 2 + Svpshsz,
+ Svmax = Svsz + Nobj * Svobjsz + (Nstc-1) * Svstsz + (Ndoor-1) * Svdrsz
};
static Dat *pcms;
static int alofs, npcm;
@@ -462,11 +470,22 @@
snprint(s, sizeof s, "%s%s", f, ext);
bf = Bopen(s, m);
if(bf == nil)
- sysfatal("bopen: %r");
+ return nil;
Blethal(bf, nil);
return bf;
}
+static Biobuf *
+eopen(char *f, int m)
+{
+ Biobuf *bf;
+
+ bf = bopen(f, m);
+ if(bf == nil)
+ sysfatal("bopen: %r");
+ return bf;
+}
+
static long
eread(Biobuf *bf, void *u, long n)
{
@@ -737,7 +756,7 @@
u16int *szs, *szp;
Biobuf *bf;
- bf = bopen("vswap.", OREAD);
+ bf = eopen("vswap.", OREAD);
n = get16(bf);
so = get16(bf);
po = get16(bf);
@@ -764,7 +783,7 @@
u32int v, *d;
Biobuf *hed;
- hed = bopen("maphead.", OREAD);
+ hed = eopen("maphead.", OREAD);
n = ver==WL6 ? 60 : ver==WL1 ? 10 : ver==SDM ? 2 : 21;
rlewtag = get16(hed);
d = mapofs = emalloc(n * sizeof *mapofs);
@@ -779,6 +798,24 @@
}
static void
+savnames(void)
+{
+ int n;
+ char u[sizeof savs[0]], (*t)[sizeof savs[0]], s[10] = "savegam?.";
+ Biobuf *bf;
+
+ for(n='0', t=savs; n<='9'; n++, t++){
+ s[7] = n;
+ bf = bopen(s, OREAD);
+ if(bf == nil)
+ continue;
+ if(Bread(bf, u, sizeof(u)-1) == sizeof(u)-1)
+ memcpy(t, u, sizeof(u)-1);
+ Bterm(bf);
+ }
+}
+
+static void
swap(Sfx *a, Sfx *b)
{
Sfx c;
@@ -864,8 +901,8 @@
int n;
Biobuf *hed, *dat;
- hed = bopen("audiohed.", OREAD);
- dat = bopen("audiot.", OREAD);
+ hed = eopen("audiohed.", OREAD);
+ dat = eopen("audiot.", OREAD);
n = ver < SDM ? Send : Ssend;
Bseek(hed, n*4, 0);
al(dat, hed, n);
@@ -982,13 +1019,13 @@
u16int hf[512], *h;
Biobuf *dat, *aux;
- aux = bopen("vgadict.", OREAD);
+ aux = eopen("vgadict.", OREAD);
for(h=hf; h<hf+nelem(hf); h++)
*h = get16(aux);
Bterm(aux);
- aux = bopen("vgahead.", OREAD);
- dat = bopen("vgagraph.", OREAD);
+ aux = eopen("vgahead.", OREAD);
+ dat = eopen("vgagraph.", OREAD);
n = piched(dat, aux, hf);
getfnts(dat, aux, hf);
getpics(dat, aux, hf, n);
@@ -1004,7 +1041,7 @@
Biobuf *bf;
ext = ver < SDM ? "wl6" : "sod";
- bf = bopen("intro.", OREAD);
+ bf = eopen("intro.", OREAD);
eread(bf, pxb, Va);
out();
Bterm(bf);
@@ -1034,6 +1071,55 @@
}
}
+int
+wrsav(int i)
+{
+ int r;
+ vlong n;
+ uchar *u, *p;
+ char s[10] = "savegam?.";
+ Biobuf *bf;
+
+ s[7] = '0' + i;
+ bf = eopen(s, OWRITE);
+ u = emalloc(Svmax);
+ memcpy(u, savs[i], sizeof savs[0]);
+ p = wrgm(u + sizeof savs[0]);
+ p = wrmap(p);
+ assert(p <= u + Svmax);
+ n = p - u;
+ r = Bwrite(bf, u, n) != n ? -1 : 0;
+ Bterm(bf);
+ free(u);
+ return r;
+}
+
+int
+ldsav(int i)
+{
+ int r;
+ vlong n;
+ uchar *u, *p;
+ char s[10] = "savegam?.";
+ Biobuf *bf;
+
+ s[7] = '0' + i;
+ bf = eopen(s, OREAD);
+ n = bsize(bf);
+ if(n < Svsz){
+ werrstr("ldsav: short map");
+ return -1;
+ }
+ u = emalloc(n);
+ eread(bf, u, n);
+ Bterm(bf);
+ p = ldgm(u + sizeof savs[0]);
+ r = ldmap(p, &p);
+ assert(p <= u + n);
+ free(u);
+ return r;
+}
+
u16int *
readmap(int n)
{
@@ -1044,7 +1130,7 @@
m = mapofs + n;
if(m >= mape)
sysfatal("readmap: invalid map number %d", n);
- dat = bopen("gamemaps.", OREAD);
+ dat = eopen("gamemaps.", OREAD);
Bseek(dat, *m, 0);
u = emalloc(Mapsz);
p0 = get32(dat);
@@ -1061,18 +1147,18 @@
char *
demof(char *f)
{
- char *p;
+ char *p, *e;
vlong n;
Biobuf *bf;
- bf = Bopen(f, OREAD);
- if(bf == nil)
- sysfatal("demof: %r");
- Blethal(bf, nil);
+ e = ext;
+ ext = "";
+ bf = eopen(f, OREAD);
n = bsize(bf);
p = emalloc(n);
eread(bf, p, n);
Bterm(bf);
+ ext = e;
return p;
}
@@ -1089,6 +1175,7 @@
ext = e;
vswap();
gamemaps();
+ savnames();
if(ver == SOD)
ext = "sod";
audiot();
--- a/gm.c
+++ b/gm.c
@@ -28,6 +28,7 @@
Game gm;
int msense;
int allrecv, god, noclip, slomo;
+int loaded;
typedef struct Crm Crm;
enum{
@@ -2259,10 +2260,6 @@
crmchop();
}
static void
-crmmap(void)
-{
-}
-static void
crmgod(void)
{
god ^= 1;
@@ -2331,7 +2328,7 @@
int θ, lrot, rrot;
double fθ;
- gm.w = -1;
+ gm.w = WPnone;
gm.lives--;
stopmus();
sfx(Sdie);
@@ -2521,7 +2518,6 @@
{"opeopn", crmkey},
{"opephz", crmwep},
{"opemli", crmmli},
- {"opepda", crmmap},
{"opedqd", crmgod},
{"opeclp", crmclp},
{"opeslo", crmslo},
@@ -2641,10 +2637,12 @@
void
game(void)
{
- initmap();
- killx = oplr->x;
- killy = oplr->y;
- mapmus();
+ if(!loaded){
+ initmap();
+ killx = oplr->x;
+ killy = oplr->y;
+ mapmus();
+ }
pal = pals[C0];
dofizz++;
step = gstep;
@@ -2666,10 +2664,86 @@
oplr->areaid = oplr->tl->p0 - MTfloor;
}
+uchar *
+wrgm(uchar *p)
+{
+ disking();
+ PUT16(p, gm.difc);
+ PUT16(p, gm.map);
+ PUT32(p, gm.oldpt);
+ PUT32(p, gm.pt);
+ PUT32(p, gm.to1up);
+ PUT16(p, gm.lives);
+ PUT16(p, gm.hp);
+ PUT16(p, gm.ammo);
+ PUT16(p, gm.keys);
+ PUT16(p, gm.bestw);
+ PUT16(p, gm.w);
+ PUT16(p, gm.lastw);
+ PUT16(p, gm.facefrm);
+ PUT16(p, atkfrm);
+ PUT16(p, atktc);
+ PUT16(p, gm.wfrm);
+ PUT16(p, gm.sp);
+ PUT16(p, gm.tp);
+ PUT16(p, gm.kp);
+ PUT16(p, gm.stot);
+ PUT16(p, gm.ttot);
+ PUT16(p, gm.ktot);
+ PUT32(p, gm.tc);
+ PUT32(p, killx);
+ PUT32(p, killy);
+ PUT16(p, gm.epk);
+ PUT16(p, gm.eps);
+ PUT16(p, gm.ept);
+ PUT32(p, gm.eptm);
+ PUT8(p, dirty);
+ PUT8(p, firing);
+ return p;
+}
+
+uchar *
+ldgm(uchar *p)
+{
+ disking();
+ gm.difc = GET16(p);
+ gm.map = GET16(p);
+ gm.oldpt = GET32(p);
+ gm.pt = GET32(p);
+ gm.to1up = GET32(p);
+ gm.lives = GET16(p);
+ gm.hp = GET16(p);
+ gm.ammo = GET16(p);
+ gm.keys = GET16(p);
+ gm.bestw = GET16(p);
+ gm.w = GET16(p);
+ gm.lastw = GET16(p);
+ gm.facefrm = GET16(p);
+ atkfrm = GET16(p);
+ atktc = (s16int)GET16(p);
+ gm.wfrm = GET16(p);
+ gm.sp = GET16(p);
+ gm.tp = GET16(p);
+ gm.kp = GET16(p);
+ gm.stot = GET16(p);
+ gm.ttot = GET16(p);
+ gm.ktot = GET16(p);
+ gm.tc = GET32(p);
+ killx = GET32(p);
+ killy = GET32(p);
+ gm.epk = GET16(p);
+ gm.eps = GET16(p);
+ gm.ept = GET16(p);
+ gm.eptm = GET32(p);
+ dirty = GET8(p);
+ firing = GET8(p);
+ return p;
+}
+
void
greset(void)
{
- if(gm.w == -1){
+ if(gm.w == WPnone){
gm.hp = 100;
gm.ammo = 8;
gm.w = gm.lastw = gm.bestw = WPpistol;
@@ -2693,6 +2767,7 @@
slomo = noclip = god = 0;
if(ver == SOD && gm.map == 20)
givek(0);
+ loaded = 0;
}
void
--- a/hub.c
+++ b/hub.c
@@ -1,5 +1,6 @@
#include <u.h>
#include <libc.h>
+#include <ctype.h>
#include <thread.h>
#include <keyboard.h>
#include "dat.h"
@@ -17,7 +18,7 @@
{"John Romero", 10000, 1},
{"Jay Wilbur", 10000, 1},
};
-char savs[10][32];
+char savs[11][32];
typedef struct Fade Fade;
typedef struct Sp Sp;
@@ -107,14 +108,22 @@
Lfsav,
Lmsav,
Lsvctl,
+ Lsvname,
+ Lwrsav,
Lflod,
Lmlod,
Lldctl,
+ Lldsav,
+ Lldsav2,
+ Lldsav3,
+ Lldsav4,
+ Lldsav5,
Lfvw,
Lmvw,
Lvwctl,
Lfmscore,
Lmscore,
+ Lovrsav,
Lend,
Lcurgame,
Lquit,
@@ -305,12 +314,21 @@
static void
pblink(void)
{
- if(mp->n == 0)
+ if(mp->n ^= 1)
+ put(mp->x, mp->y, fnt->w['_'], fnt->h, DIreg);
+ else
txt(mp->x, mp->y, "_", 0);
+ out();
+}
+
+static void
+iblink(void)
+{
+ if(mp->n ^= 1)
+ txt(111 + irb - 1, mp->y + 3, "\x80", DIrhi);
else
- put(mp->x, mp->y, fnt->w['_'], fnt->h, DIreg);
+ put(111 + irb - 1, mp->y + 3, fnt->w[0x80]-1, fnt->h, mcol[DMbg]);
out();
- mp->n ^= 1;
}
static void
@@ -318,8 +336,8 @@
{
put(mp->x, mp->y, 24, 16, mcol[DMbg]);
pic(mp->x, mp->y, pict[Pcur1] + mp->n);
- out();
mp->n ^= 1;
+ out();
}
static void
@@ -368,6 +386,7 @@
m = ml+LMctl;
i = m->s;
+ i[3].c = DIreg;
i[4].c = mcol[DMoff];
i[6].s = "View Scores";
i[6].q = ql+Lfmscore;
@@ -467,6 +486,15 @@
}
static void
+ovrsav(void)
+{
+ msg("There's already a game\n"
+ "saved at this position.\n Overwrite?", 0);
+ mp->p->q = ql+Lsvname;
+ qesc = ql+Lsvctl;
+}
+
+static void
denied(void)
{
msg("Please select \"Read This!\"\nfrom the Options menu to\n"
@@ -624,15 +652,61 @@
}
static void
-savitem(int i, int c)
+disk(void)
{
- outbox(109, 55 + i * 13, 136, 11, c, c);
- fnt = fnts;
- txt(111, 56 + i * 13, savs[i][0] == 0 ? " - empty -" : savs[i], c);
+ int n;
+
+ box(96, 80, 130, 42, DIreg, 0, DIrhi);
+ pic(104, 85, pict[Pread1]);
fnt = fnts+1;
+ txt(142, 93, qsp == ql+Lwrsav ? "Saving..." : "Loading...", 0);
+ out();
+ n = mp->p - mp->s;
+ if(qsp == ql+Lwrsav){
+ qsp->q = ql+Lftoctl;
+ if(wrsav(n) < 0)
+ goto err;
+ }else{
+ qsp->q = ql+Lldsav2;
+ ginit(nil, -1, 0);
+ greset();
+ if(ldsav(n) < 0)
+ goto err;
+ ingctl();
+ loaded++;
+ }
+ sfx(Sshoot);
+ return;
+err:
+ memset(savs[n], 0, sizeof savs[0]);
+ qsp->q = ql+Lftoctl;
+ sfx(Snoway);
}
static void
+savtxt(Item *i, char *s)
+{
+ int n;
+
+ n = 56 + (i - mp->s) * 13;
+ put(110, n, 135, fnt->h, mcol[DMbg]);
+ txt(111, n, s, i->c);
+}
+
+static void
+savitem(Item *i, int n)
+{
+ outbox(109, 55 + n * 13, 136, 11, i->c, i->c);
+ if(savs[n][0] != 0){
+ savtxt(i, savs[n]);
+ i->q = qsp->q == ql+Lsvctl ? ql+Lovrsav : ql+Lldsav;
+ }else{
+ savtxt(i, " - empty -");
+ i->q = qsp->q == ql+Lsvctl ? ql+Lsvname : nil;
+ }
+}
+
+static void
sav(void)
{
Menu *m;
@@ -642,13 +716,14 @@
pic(112, 184, pict[Pmouselback]);
mbox(75, 50, 175, 140);
stripe(10);
- pic(56, 0, pict[qsp->q == ql+Lsvctl ? Psave : Pload]);
+ pic(56, 0, pict[qsp->q == ql+Lldctl ? Pload : Psave]);
m = ml+LMsav;
mp = m;
i = m->s;
e = m->e;
+ fnt = fnts;
do
- savitem(i - m->s, i->c);
+ savitem(i, i - m->s);
while(++i < e);
qesc = ql+Lftoctl;
m->n = 0;
@@ -656,6 +731,17 @@
}
static void
+savname(void)
+{
+ sav();
+ memcpy(savs[10], savs[mp->p - mp->s], sizeof savs[10]);
+ savtxt(mp->p, savs[10]);
+ iri = strlen(savs[10]);
+ irb = txtw(savs[10]);
+ mp->n = 0;
+}
+
+static void
mvw(void)
{
int dx, dy;
@@ -825,6 +911,69 @@
}
static void
+prompt(void)
+{
+ int n, m;
+ char *s;
+ Rune r;
+
+ if(nbrecv(csc, &r) <= 0)
+ return;
+ s = savs[10];
+ n = strlen(s);
+ switch(r){
+ redraw:
+ savtxt(mp->p, savs[10]);
+ mp->n = 0;
+ iblink();
+ qtc = 0;
+ break;
+ default:
+ if(runelen(r) > 1 || !isprint(r))
+ break;
+ m = fnt->w[r];
+ if(txtw(s) + m > 134 || n == sizeof(savs[10]) - 1)
+ break;
+ while(n-- > iri)
+ s[n+1] = s[n];
+ s[iri++] = r;
+ irb += m;
+ goto redraw;
+ case Kleft:
+ if(iri == 0)
+ break;
+ irb -= fnt->w[s[--iri]];
+ goto redraw;
+ case Kright:
+ if(iri == n)
+ break;
+ irb += fnt->w[s[iri++]];
+ goto redraw;
+ case Kdel:
+ case Kbs:
+ if(iri == 0)
+ break;
+ irb -= fnt->w[s[--iri]];
+ for(m=iri+1; m<=n; m++)
+ s[m-1] = s[m];
+ s[m] = 0;
+ goto redraw;
+ abort:
+ case Kesc:
+ sfx(Sesc);
+ reset(ql+Lsvctl);
+ break;
+ case '\n':
+ if(n == 0)
+ goto abort;
+ strcpy(savs[mp->p - mp->s], savs[10]);
+ sfx(Sshoot);
+ reset(ql+Lwrsav);
+ break;
+ }
+}
+
+static void
ask(void)
{
Rune r;
@@ -948,7 +1097,6 @@
a[3] = 0;
txt(241, 72, a, DIshi);
}
- fnt = fnts+1;
mus(ver < SDM ? Mwon : Msdwon);
grab(0);
}
@@ -1246,7 +1394,8 @@
static void
ingam(void)
{
- greset();
+ if(qsp != ql+Lldsav4)
+ greset();
view();
}
@@ -1434,6 +1583,8 @@
slq[] = {{1, slider}},
curq[] = {{8, nil}, {0, cursfx}},
togq[] = {{1, toggle}},
+ promptq[] = {{0, iblink}, {Tb / 2, prompt}},
+ diskq[] = {{1, disk}, {1, nil}}, /* buffer extra tics */
mscoreq[] = {{10, fadein}, {1, bwait}, {10, fadeout}},
quitq[] = {{0, pblink}, {10, ask}},
ackq[] = {{1, bwait}},
@@ -1509,9 +1660,15 @@
[Lfsav] {nil, escq, escq+nelem(escq), ql+Lmsav, &fctl},
[Lmsav] {sav, toctlq, toctlq+nelem(toctlq), ql+Lsvctl, &fctl},
[Lsvctl] {sav, ctlq, ctlq+nelem(ctlq), ql+Lsvctl},
+ [Lsvname] {savname, promptq, promptq+nelem(promptq), ql+Lsvname},
+ [Lwrsav] {nil, diskq, diskq+nelem(diskq), nil},
[Lflod] {nil, escq, escq+nelem(escq), ql+Lmlod, &fctl},
[Lmlod] {sav, toctlq, toctlq+nelem(toctlq), ql+Lldctl, &fctl},
[Lldctl] {sav, ctlq, ctlq+nelem(ctlq), ql+Lldctl},
+ [Lldsav] {nil, diskq, diskq+nelem(diskq), nil},
+ [Lldsav2] {nil, escq, escq+nelem(escq), ql+Lldsav3, &fctl},
+ [Lldsav3] {nil, loadq, loadq+nelem(loadq), ql+Lldsav4, &fblk},
+ [Lldsav4] {psych, psychq, psychq+nelem(psychq), ql+Lgame, &fblk},
[Lfsens] {nil, escq, escq+nelem(escq), ql+Lmsens, &fctl},
[Lmsens] {sens, toctlq, toctlq+nelem(toctlq), ql+Lsectl, &fctl},
[Lsectl] {sens, slq, slq+nelem(slq), ql+Lsectl},
@@ -1520,6 +1677,7 @@
[Lvwctl] {mvw, slq, slq+nelem(slq), ql+Lvwctl},
[Lfmscore] {nil, escq, escq+nelem(escq), ql+Lmscore, &fctl},
[Lmscore] {score, mscoreq, mscoreq+nelem(mscoreq), ql+Lmtoctl, &fctl},
+ [Lovrsav] {ovrsav, quitq, quitq+nelem(quitq), ql+Lovrsav},
[Lend] {mend, quitq, quitq+nelem(quitq), ql+Lend},
[Lcurgame] {curgame, quitq, quitq+nelem(quitq), ql+Lcurgame},
[Lquit] {quit, quitq, quitq+nelem(quitq), ql+Lquit},
--- a/main.c
+++ b/main.c
@@ -122,237 +122,6 @@
}
}
-void DiskFlopAnim(s16int x,s16int y)
-{
- static char which=0;
- if (!x && !y)
- return;
- VWB_DrawPic(x,y,Pread1+which);
- VW_UpdateScreen();
- which^=1;
-}
-
-
-s32int DoChecksum(u8int far *source,u16int size,s32int checksum)
-{
- u16int i;
-
- for (i=0;i<size-1;i++)
- checksum += source[i]^source[i+1];
-
- return checksum;
-}
-
-int SaveTheGame(s16int file,s16int x,s16int y)
-{
- struct diskfree_t dfree;
- s32int avail,size,checksum;
- objtype *ob,nullobj;
-
-
- if (_dos_getdiskfree(0,&dfree))
- Quit("Error in _dos_getdiskfree call");
-
- avail = (s32int)dfree.avail_clusters *
- dfree.bytes_per_sector *
- dfree.sectors_per_cluster;
-
- size = 0;
- for (ob = player; ob ; ob=ob->next)
- size += sizeof(*ob);
- size += sizeof(nullobj);
-
- size += sizeof(gamestate) +
- sizeof(LRstruct)*8 +
- sizeof(tilemap) +
- sizeof(actorat) +
- sizeof(laststatobj) +
- sizeof(statobjlist) +
- sizeof(doorposition) +
- sizeof(pwallstate) +
- sizeof(pwallx) +
- sizeof(pwally) +
- sizeof(pwalldir) +
- sizeof(pwallpos);
-
- if (avail < size)
- {
- Message("There is not enough space\n"
- "on your disk to Save Game!");
- return false;
- }
-
- checksum = 0;
-
-
- DiskFlopAnim(x,y);
- CA_FarWrite (file,(void far *)&gamestate,sizeof(gamestate));
- checksum = DoChecksum((u8int far *)&gamestate,sizeof(gamestate),checksum);
-
- DiskFlopAnim(x,y);
-#ifdef SPEAR
- CA_FarWrite (file,(void far *)&LevelRatios[0],sizeof(LRstruct)*20);
- checksum = DoChecksum((u8int far *)&LevelRatios[0],sizeof(LRstruct)*20,checksum);
-#else
- CA_FarWrite (file,(void far *)&LevelRatios[0],sizeof(LRstruct)*8);
- checksum = DoChecksum((u8int far *)&LevelRatios[0],sizeof(LRstruct)*8,checksum);
-#endif
-
- DiskFlopAnim(x,y);
- CA_FarWrite (file,(void far *)tilemap,sizeof(tilemap));
- checksum = DoChecksum((u8int far *)tilemap,sizeof(tilemap),checksum);
- DiskFlopAnim(x,y);
- CA_FarWrite (file,(void far *)actorat,sizeof(actorat));
- checksum = DoChecksum((u8int far *)actorat,sizeof(actorat),checksum);
-
- CA_FarWrite (file,(void far *)conarea,sizeof(conarea));
- CA_FarWrite (file,(void far *)plrarea,sizeof(plrarea));
-
- for (ob = player ; ob ; ob=ob->next)
- {
- DiskFlopAnim(x,y);
- CA_FarWrite (file,(void far *)ob,sizeof(*ob));
- }
- nullobj.active = ac_badobject; // end of file marker
- DiskFlopAnim(x,y);
- CA_FarWrite (file,(void far *)&nullobj,sizeof(nullobj));
-
-
-
- DiskFlopAnim(x,y);
- CA_FarWrite (file,(void far *)&laststatobj,sizeof(laststatobj));
- checksum = DoChecksum((u8int far *)&laststatobj,sizeof(laststatobj),checksum);
- DiskFlopAnim(x,y);
- CA_FarWrite (file,(void far *)statobjlist,sizeof(statobjlist));
- checksum = DoChecksum((u8int far *)statobjlist,sizeof(statobjlist),checksum);
-
- DiskFlopAnim(x,y);
- CA_FarWrite (file,(void far *)doorposition,sizeof(doorposition));
- checksum = DoChecksum((u8int far *)doorposition,sizeof(doorposition),checksum);
- DiskFlopAnim(x,y);
- CA_FarWrite (file,(void far *)doorobjlist,sizeof(doorobjlist));
- checksum = DoChecksum((u8int far *)doorobjlist,sizeof(doorobjlist),checksum);
-
- DiskFlopAnim(x,y);
- CA_FarWrite (file,(void far *)&pwallstate,sizeof(pwallstate));
- checksum = DoChecksum((u8int far *)&pwallstate,sizeof(pwallstate),checksum);
- CA_FarWrite (file,(void far *)&pwallx,sizeof(pwallx));
- checksum = DoChecksum((u8int far *)&pwallx,sizeof(pwallx),checksum);
- CA_FarWrite (file,(void far *)&pwally,sizeof(pwally));
- checksum = DoChecksum((u8int far *)&pwally,sizeof(pwally),checksum);
- CA_FarWrite (file,(void far *)&pwalldir,sizeof(pwalldir));
- checksum = DoChecksum((u8int far *)&pwalldir,sizeof(pwalldir),checksum);
- CA_FarWrite (file,(void far *)&pwallpos,sizeof(pwallpos));
- checksum = DoChecksum((u8int far *)&pwallpos,sizeof(pwallpos),checksum);
-
- //
- // WRITE OUT CHECKSUM
- //
- CA_FarWrite (file,(void far *)&checksum,sizeof(checksum));
-
- return(true);
-}
-
-int LoadTheGame(s16int file,s16int x,s16int y)
-{
- s32int checksum,oldchecksum;
- objtype *ob,nullobj;
-
-
- checksum = 0;
-
- DiskFlopAnim(x,y);
- CA_FarRead (file,(void far *)&gamestate,sizeof(gamestate));
- checksum = DoChecksum((u8int far *)&gamestate,sizeof(gamestate),checksum);
-
- DiskFlopAnim(x,y);
-#ifdef SPEAR
- CA_FarRead (file,(void far *)&LevelRatios[0],sizeof(LRstruct)*20);
- checksum = DoChecksum((u8int far *)&LevelRatios[0],sizeof(LRstruct)*20,checksum);
-#else
- CA_FarRead (file,(void far *)&LevelRatios[0],sizeof(LRstruct)*8);
- checksum = DoChecksum((u8int far *)&LevelRatios[0],sizeof(LRstruct)*8,checksum);
-#endif
-
- DiskFlopAnim(x,y);
- initmap ();
-
- DiskFlopAnim(x,y);
- CA_FarRead (file,(void far *)tilemap,sizeof(tilemap));
- checksum = DoChecksum((u8int far *)tilemap,sizeof(tilemap),checksum);
- DiskFlopAnim(x,y);
- CA_FarRead (file,(void far *)actorat,sizeof(actorat));
- checksum = DoChecksum((u8int far *)actorat,sizeof(actorat),checksum);
-
- CA_FarRead (file,(void far *)conarea,sizeof(conarea));
- CA_FarRead (file,(void far *)plrarea,sizeof(plrarea));
-
-
-
- oinit ();
- DiskFlopAnim(x,y);
- CA_FarRead (file,(void far *)player,sizeof(*player));
-
- while (1)
- {
- DiskFlopAnim(x,y);
- CA_FarRead (file,(void far *)&nullobj,sizeof(nullobj));
- if (nullobj.active == ac_badobject)
- break;
- onew ();
- // don't copy over the links
- memcpy (new,&nullobj,sizeof(nullobj)-4);
- }
-
-
-
- DiskFlopAnim(x,y);
- CA_FarRead (file,(void far *)&laststatobj,sizeof(laststatobj));
- checksum = DoChecksum((u8int far *)&laststatobj,sizeof(laststatobj),checksum);
- DiskFlopAnim(x,y);
- CA_FarRead (file,(void far *)statobjlist,sizeof(statobjlist));
- checksum = DoChecksum((u8int far *)statobjlist,sizeof(statobjlist),checksum);
-
- DiskFlopAnim(x,y);
- CA_FarRead (file,(void far *)doorposition,sizeof(doorposition));
- checksum = DoChecksum((u8int far *)doorposition,sizeof(doorposition),checksum);
- DiskFlopAnim(x,y);
- CA_FarRead (file,(void far *)doorobjlist,sizeof(doorobjlist));
- checksum = DoChecksum((u8int far *)doorobjlist,sizeof(doorobjlist),checksum);
-
- DiskFlopAnim(x,y);
- CA_FarRead (file,(void far *)&pwallstate,sizeof(pwallstate));
- checksum = DoChecksum((u8int far *)&pwallstate,sizeof(pwallstate),checksum);
- CA_FarRead (file,(void far *)&pwallx,sizeof(pwallx));
- checksum = DoChecksum((u8int far *)&pwallx,sizeof(pwallx),checksum);
- CA_FarRead (file,(void far *)&pwally,sizeof(pwally));
- checksum = DoChecksum((u8int far *)&pwally,sizeof(pwally),checksum);
- CA_FarRead (file,(void far *)&pwalldir,sizeof(pwalldir));
- checksum = DoChecksum((u8int far *)&pwalldir,sizeof(pwalldir),checksum);
- CA_FarRead (file,(void far *)&pwallpos,sizeof(pwallpos));
- checksum = DoChecksum((u8int far *)&pwallpos,sizeof(pwallpos),checksum);
-
- CA_FarRead (file,(void far *)&oldchecksum,sizeof(oldchecksum));
-
- if (oldchecksum != checksum)
- {
- Message("Your Save Game file is,\n"
- "shall we say, \"corrupted\".\n"
- "But I'll let you go on and\n"
- "play anyway....");
-
- IN_ClearKeysDown();
- IN_Ack();
-
- gm.score = 0;
- gm.lives = 1;
- gm.w = gm.bestw = gm.lastw = WPpistol;
- gm.ammo = 8;
- }
-
- return true;
-}
-
void DemoLoop (void)
{
while (1)
--- a/man/1/wl3d
+++ b/man/1/wl3d
@@ -31,7 +31,8 @@
.RE
.PP
The command line options are:
-.TP \w'\fLw\ \ \fI"map\ 0-3"'u
+.TF "-w map 0-3"
+.TP
.B -2
Set game version to Spear of Destiny Mission 2: Return to Danger.
.TP
@@ -84,9 +85,9 @@
flags (see
.IR bind (2)).
Data files can thus be contained in a system directory while the config and save files' location, which are user-specific, can be left at the user's discretion.
-If these user-specific files exist and
+If the configuration file exists and
.I wl3d
-fails to parse them, they are not overwritten.
+fails to parse it, it is not overwritten.
The
.B -m
parameter is used to change
--- a/man/6/wl3d
+++ b/man/6/wl3d
@@ -48,7 +48,9 @@
In the notation for file and lump formats below, the number of bytes in a field is given in brackets after the field name.
The notation
.IR a [ s ]
-denotes an unterminated array of
+denotes an unterminated array
+.I a
+of
.I s
.SM ASCII
characters.
@@ -244,7 +246,7 @@
pair with a
.IR delay ,
expressed in multiples of 1/700 seconds.
-A zero delay means to execute the next command immediately.
+A zero delay means to write the next command immediately.
.I Tag
is a variable length field suffixed by Muse, and is ignored.
.SH MAPS
@@ -283,10 +285,12 @@
.PD
.PP
Missing maps have an offset of zero.
-As zero offsets are not handled specially, references of these maps will point to the first map.
+As zero offsets are not handled specially,
+the references to these maps will point to the first map.
.PP
An offset of 0xffffffff marks the map lump as sparse.
-In this case, the engine will not initialize the map's reference, resulting in a crash if it should be accessed.
+In this case, the engine will not initialize the map's reference,
+resulting in a crash should it be accessed.
.IR wl3d (1)
exits if it reads such an offset.
.SS Gamemaps
@@ -320,8 +324,17 @@
.I Planes
stores contiguously each plane's data.
.PP
+Each map plane is first compressed using
+.SM RLEW,
+then further using what is eponymously referred to as
+.SM Carmack compression.
+.SS RLEW Compression
+[words]
+.SS Carmack Compression
+[words]
+.SS Plane 0
The first plane is an array of [words].
-.PP
+.SS Plane 1
The second plane is an array of [other words].
.PP
There are static limits for objects on the map:
@@ -335,15 +348,6 @@
.TP
.B static objects
399
-.SS RLEW Compression
-Each map plane is first compressed using
-.SM RLEW,
-then further using what is eponymously refered to as
-.SM Carmack compression.
-.PP
-[words]
-.SS Carmack Compression
-[words]
.SH GRAPHICS
Graphics are either static data loaded in the executable, or huffman-compressed lumps contained in
.BR vgagraph .
@@ -372,6 +376,8 @@
.PP
This file contains a dictionary used for decompression of Huffman-encoded lumps in
.IR vgagraph .
+.SS Huffman Compression
+[words]
.SS Vgagraph
.RS
.IR pt [ np ][]
@@ -694,7 +700,241 @@
.SH "CONFIGURATION FILE AND HIGHSCORES"
[words]
.SH "SAVED GAMES"
-[words]
+.RS
+.IR name [32]
+.IR game []
+.IR map []
+.IR chksum [4]
+.br
+.PP
+.BR game :
+.IR gm1 []
+.IR score []
+.IR plr []
+.IR gm2 []
+.IR stat []
+.IR misc []
+.IR epstat []
+.br
+.BR gm1 :
+.IR difc [2]
+.IR map [2]
+.br
+.BR score :
+.IR oldpt [4]
+.IR pt [4]
+.IR to1up [4]
+.br
+.BR plr :
+.IR lives [2]
+.IR hp [2]
+.IR ammo [2]
+.IR keys [2]
+.IR bestw [2]
+.IR wep [2]
+.IR lastw [2]
+.br
+.BR gm2 :
+.IR facefrm [2]
+.IR atkfrm [2]
+.IR wfrm [2]
+.IR ep [2]
+.br
+.BR stat :
+.IR sp [2]
+.IR tp [2]
+.IR kp [2]
+.IR stot [2]
+.IR ttot [2]
+.IR ktot [2]
+.IR tc [4]
+.br
+.BR misc :
+.IR killx [4]
+.IR killy [4]
+.IR won [2]
+.br
+.BR epstat :
+{
+.IR k [2]
+.IR s [2]
+.IR t [2]
+.IR tm [4]
+.RI }[ nmap ]
+.br
+.PP
+.BR map :
+.IR tilemap []
+.IR obj []
+.IR stats []
+.IR doors []
+.IR pwall []
+.br
+.BR tilemap :
+.IR tl [64*64]
+.IR tlo [64*64][2]
+.br
+.BR obj :
+{
+.IR on [2]
+.IR tc [2]
+.IR type [2]
+.IR stt [2]
+.IR f [1]
+.IR Δr [4]
+.IR dir [2]
+.IR x [4]
+.IR y [4]
+.IR tx [2]
+.IR ty [2]
+.IR aid [1]
+.IR vwx [2]
+.IR vwh [2]
+.IR trx [4]
+.IR try [4]
+.IR θ [2]
+.IR hp [2]
+.IR v [4]
+.IR tmp [3][2]
+.IR node [2][2]
+.RI }[ nobj+1 ]
+.br
+.BR stats :
+.IR statse [2]
+{
+.IR tx [1]
+.IR ty [1]
+.IR vis [2]
+.IR spr [2]
+.IR f [1]
+.IR itm [1]
+}[400]
+.br
+.BR doors :
+.IR dopen [64][2]
+{
+.IR tx [1]
+.IR ty [1]
+.IR vert [2]
+.IR lck [1]
+.IR φ [2]
+.IR tc [2]
+}[64]
+.br
+.BR pwall :
+.IR φ [2]
+.IR x [2]
+.IR y [2]
+.IR dir [2]
+.IR dopen [2]
+.RE
+.PP
+Savegame files contain game and map state used to regenerate a live game.
+It can be split into lumps containing variable-size fields.
+.PP
+A checksum of each written byte is calculated and appended.
+It is tested upon subsequent loading to guard against tampering.
+Its formula is:
+.RS
+.BR chksum \ = \ ∑\ n[i]\ XOR\ n[i+1]
+.RE
+.PP
+A save file does not contain the entire state necessary to restore a game.
+The map must first be loaded and initialized,
+then the information from the save file is used
+to overwrite some of the resulting state.
+.IR Wl3d (1)
+uses a different save game format, containing a complete state.
+Converting between the two formats is possible.
+.PP
+.I Name
+contains a nul-terminated ascii string, which may be empty.
+It is the savegame's name displayed ingame using the second game font,
+and may be truncated depending on its total on screen width.
+.SS Game state
+.PP
+The first two fields are the game difficulty (0-3, from easiest to hardest),
+and a zero-indexed map number (0-59).
+.PP
+Then follow three scoring fields:
+the points at the start of the level,
+current points, and the points needed for another 1-up reward.
+.PP
+Next are seven player state fields:
+number of lives (0-9),
+hit points (1-100), ammo points (0-99),
+collected keys bitfield,
+best available weapon (1-3),
+currently equipped weapon,
+and last switched from weapon.
+.PP
+The subsequent four fields store frame counters for face and firing animations,
+and an episode index (0-5 or 0 for
+.IR sod/sdm ),
+derived from the map index.
+.PP
+Seven map statistics fields follow:
+current secrets, treasure and kills counts,
+then their respective maximums,
+and a level time in 70 Hz tics.
+.PP
+The ensuing three fields are used when a victory condition is triggered,
+and contain the coordinates of a reference object and a victory flag.
+.PP
+The last lump is an array of scoring information for each of the current
+episode's maps:
+percentage of kills, secrets found and treasure collected,
+and level time in 70 Hz tics.
+.I Nmap
+is 8 for
+.I wl1/wl6
+and 20 for
+.IR sdm/sod .
+.SS Map state
+The
+.I tilemap
+is an array of byte-sized tile numbers,
+followed by an array of object pointers.
+Values lower than 256 in
+.I tlo
+denote item numbers.
+.PP
+The subsequent lump is a variable-size array of objects,
+defined by the following fields:
+active flag, state timer, object type, state pointer, object flags,
+displacement counter, direction, global and tile coordinates, area number,
+rendering dimensions,
+angle (used for player and projectiles),
+hit points, speed,
+three temporary variables used for timing and drawing,
+and next and previous node pointers.
+The
+.I obj
+lump is terminated by a trailing object definition with
+.LR 0xffff
+in its
+.I on
+field.
+.PP
+Afterwards is stored a fixed-size array of static objects,
+preceded by an end pointer, referencing past the last element.
+Each element is defined by tile coordinates,
+a pointer to an array of visible elements,
+a sprite number,
+a flags field,
+and an item number.
+.PP
+Next is stored a fixed-size array of doors,
+prepended by an array of door positions (0-0xffff, from closed to open).
+Each is ascribed tile coordinates,
+a vertical map position flag,
+a lock bitfield,
+an open/close phase,
+and a timer.
+.PP
+The last lump describes an active pushwall:
+opening phase, global map coordinates, direction,
+and fine position.
.SH "SEE ALSO"
.IR opl2 (1) ,
.IR pcmconv (1) ,
--- a/map.c
+++ b/map.c
@@ -3,12 +3,6 @@
#include "dat.h"
#include "fns.h"
-enum{
- Nobj = 150,
- Ndoor = 64,
- Nstc = 400,
- Narea = 37
-};
Tile tiles[Mapa];
Obj *objs, *ofree, *oplr;
Door doors[Ndoor], *doore, pusher;
@@ -49,8 +43,7 @@
case Rbible:
case Rcrown:
case R1up:
- if(!gm.load)
- gm.ttot++;
+ gm.ttot++;
/* wet floor */
default:
stce->f = OFbonus;
@@ -62,7 +55,7 @@
stce->spr = sprs + n;
if(stce->spr == nil)
sysfatal("spawnstc: missing static sprite %d\n", n);
- if(++stce == stcs+Nstc)
+ if(++stce == stcs + nelem(stcs))
sysfatal("static object overflow");
}
@@ -73,7 +66,7 @@
a = conarea + id * Narea;
p = plrarea;
- while(p < plrarea+nelem(plrarea)){
+ while(p < plrarea + nelem(plrarea)){
if(*a && !*p){
(*p)++;
rconair(p-plrarea);
@@ -293,7 +286,7 @@
}
static void
-oinit(int all)
+oinit(void)
{
Obj *o, *p;
@@ -313,15 +306,6 @@
}
ofree->p = p;
p->n = ofree;
-
- if(all){
- memset(plrarea, 0, sizeof plrarea);
- memset(conarea, 0, sizeof conarea);
- memset(doors, 0, sizeof doors);
- memset(stcs, 0, sizeof stcs);
- doore = doors;
- stce = stcs;
- }
}
static void
@@ -426,8 +410,7 @@
o->v = 1500;
o->θ = θE;
o->f |= OFambush;
- if(!gm.load)
- gm.ktot++;
+ gm.ktot++;
}
static void
@@ -461,7 +444,6 @@
θ = θS;
goto wlonly;
case Oschb:
- stt[GSschbdie2].dt = pcmon ? 140 : 5;
s = stt+GSschb;
hp = gm.difc<GDeasy ? 850 : gm.difc<GDmed ? 950
: gm.difc<GDhard ? 1550 : 2400;
@@ -473,26 +455,21 @@
θ = θN;
goto wlonly;
case Ootto:
- stt[GSottodie2].dt = pcmon ? 140 : 5;
s = stt+GSotto;
hp = gm.difc<GDhard ? 850 + gm.difc * 100 : 1200;
θ = θN;
goto wlonly;
case Ofett:
- stt[GSfettdie2].dt = pcmon ? 140 : 5;
s = stt+GSfett;
hp = gm.difc<GDhard ? 850 + gm.difc * 100 : 1200;
θ = θS;
goto wlonly;
case Ofake:
- /* bug? */
- stt[GShitlerdie2].dt = pcmon ? 140 : 5;
s = stt+GSfake;
hp = 200 + 100 * gm.difc;
θ = θN;
goto wlonly;
case Omech:
- stt[GShitlerdie2].dt = pcmon ? 140 : 5;
s = stt+GSmech;
hp = gm.difc<GDeasy ? 800 : gm.difc<GDmed ? 950
: gm.difc<GDhard ? 1050 : 1200;
@@ -499,26 +476,18 @@
θ = θS;
goto wlonly;
case Otrans:
- if(pcmon)
- stt[GStransdie2].dt = 105;
s = stt+GStrans;
hp = gm.difc<GDhard ? 850 + gm.difc * 100 : 1200;
goto sdonly;
case Owilh:
- if(pcmon)
- stt[GSwilhdie2].dt = 70;
s = stt+GSwilh;
hp = gm.difc<GDhard ? 950 + gm.difc * 100 : 1300;
goto sdonly;
case Ouber:
- if(pcmon)
- stt[GSuberdie2].dt = 70;
s = stt+GSuber;
hp = gm.difc<GDhard ? 1050 + gm.difc * 100 : 1400;
goto sdonly;
case Oknight:
- if(pcmon)
- stt[GSknightdie2].dt = 105;
s = stt+GSknight;
hp = gm.difc<GDhard ? 1250 + 100 * gm.difc : 1600;
goto sdonly;
@@ -527,8 +496,6 @@
hp = gm.difc<GDhard ? 5 * (1 + gm.difc) : 25;
goto sdonly;
case Oangel:
- if(pcmon)
- stt[GSangeldie2].dt = 105;
s = stt+GSangel;
hp = gm.difc<GDhard ? 1450 + 100 * gm.difc : 2000;
goto sdonly;
@@ -538,8 +505,7 @@
o->hp = hp;
o->θ = θ;
o->f |= OFshootable | OFambush;
- if(!gm.load)
- gm.ktot++;
+ gm.ktot++;
}
static void
@@ -605,8 +571,7 @@
o->v = type == Odog ? 1500 : 512;
o->θ = dir * 90;
- if(!gm.load)
- gm.ktot++;
+ gm.ktot++;
if(patrol){
o->Δr = Dtlglobal;
o->on++;
@@ -638,8 +603,7 @@
spawnstc(tl, n-23);
break;
case 98:
- if(!gm.load)
- gm.stot++;
+ gm.stot++;
break;
case 180: case 181: case 182: case 183: difc++; n-=36; /* wet floor */
case 144: case 145: case 146: case 147: difc+=2; n-=36; /* wet floor */
@@ -730,7 +694,7 @@
for(sti=stctype; sti<stctype+nelem(stctype); sti++)
if(*sti == n)
break;
- if(sti >= stctype+nelem(stctype))
+ if(sti >= stctype + nelem(stctype))
sysfatal("drop: unknown item type");
for(s=stcs; s<stcs+nelem(stcs); s++)
if(s->tl == nil){
@@ -738,7 +702,7 @@
stce++;
break;
}
- if(s >= stcs+nelem(stcs))
+ if(s >= stcs + nelem(stcs))
return;
s->tl = tl;
sn = n == Rclip2 ? 28 : 2+(sti-stctype);
@@ -855,6 +819,201 @@
mus(ver < SDM ? wlmus[gm.map] : sdmus[gm.map]);
}
+uchar *
+wrmap(uchar *p)
+{
+ Tile *tl;
+ Obj *o;
+ Static *s;
+ Door *d;
+
+ disking();
+ for(tl=tiles; tl<tiles+nelem(tiles); tl++){
+ PUT16(p, tl->p0);
+ PUT16(p, tl->p1);
+ PUT8(p, tl->tl);
+ PUT8(p, tl->to);
+ }
+ memcpy(p, conarea, sizeof conarea); p+=sizeof conarea;
+ memcpy(p, plrarea, sizeof plrarea); p+=sizeof plrarea;
+ for(o=oplr; o!=objs; o=o->n){
+ disking();
+ PUT16(p, o->on);
+ PUT16(p, o->tc);
+ PUT16(p, o->type);
+ PUT16(p, o->s - stt);
+ PUT8(p, o->f);
+ PUT32(p, o->Δr);
+ PUT32(p, o->x);
+ PUT32(p, o->y);
+ PUT16(p, o->tx);
+ PUT16(p, o->ty);
+ PUT8(p, o->areaid);
+ PUT16(p, o->vwx);
+ PUT16(p, o->vwdy);
+ PUT32(p, o->vwdx);
+ PUT16(p, o->θ);
+ PUT16(p, o->hp);
+ PUT32(p, o->v);
+ PUT16(p, o->atkdt);
+ PUT16(p, o->sdt);
+ }
+ PUT16(p, 0xffff);
+ disking();
+ PUT16(p, stce - stcs);
+ for(s=stcs; s<stce; s++){
+ PUT16(p, s->tl - tiles);
+ PUT16(p, s->spr - sprs);
+ PUT8(p, s->f);
+ PUT8(p, s->item);
+ }
+ disking();
+ PUT16(p, doore - doors);
+ for(d=doors; d<doore; d++){
+ PUT16(p, d->tl - tiles);
+ PUT8(p, d->isvert);
+ PUT8(p, d->lock);
+ PUT16(p, d->φ);
+ PUT16(p, d->tc);
+ PUT16(p, d->dopen);
+ }
+ disking();
+ PUT16(p, pusher.φ);
+ PUT16(p, pusher.tl - tiles);
+ PUT16(p, pusher.isvert);
+ PUT16(p, pusher.dopen);
+ return p;
+}
+
+static void
+sttdtinit(void)
+{
+ /* bug: die state durations are set on spawn and persist regardless of
+ * changes in sound settings, until map load; sod: durations persist
+ * across maps */
+ if(pcmon){
+ stt[GSschbdie2].dt = 140;
+ stt[GSottodie2].dt = 140;
+ stt[GSfettdie2].dt = 140;
+ /* bug?: set for Ofake as well */
+ stt[GShitlerdie2].dt = 140;
+ stt[GStransdie2].dt = 105;
+ stt[GSuberdie2].dt = 70;
+ stt[GSknightdie2].dt = 105;
+ stt[GSangeldie2].dt = 105;
+ }else{
+ stt[GSschbdie2].dt = 5;
+ stt[GSottodie2].dt = 5;
+ stt[GSfettdie2].dt = 5;
+ stt[GShitlerdie2].dt = 5;
+ stt[GStransdie2].dt = 1;
+ stt[GSuberdie2].dt = 1;
+ stt[GSknightdie2].dt = 10;
+ stt[GSangeldie2].dt = 1;
+ }
+}
+
+static void
+nukemap(void)
+{
+ memset(tiles, 0, sizeof tiles);
+ memset(plrarea, 0, sizeof plrarea);
+ memset(conarea, 0, sizeof conarea);
+ memset(doors, 0, sizeof doors);
+ memset(stcs, 0, sizeof stcs);
+ doore = doors;
+ stce = stcs;
+ oinit();
+ sttdtinit();
+}
+
+int
+ldmap(uchar *p, uchar **ep)
+{
+ int n;
+ Tile *tl;
+ Obj *o;
+ Static *s;
+ Door *d;
+
+ disking();
+ nukemap();
+ disking();
+ for(tl=tiles; tl<tiles+nelem(tiles); tl++){
+ tl->p0 = GET16(p);
+ tl->p1 = GET16(p);
+ tl->tl = GET8(p);
+ tl->to = GET8(p);
+ }
+ disking();
+ memcpy(conarea, p, sizeof conarea); p+=sizeof conarea;
+ memcpy(plrarea, p, sizeof plrarea); p+=sizeof plrarea;
+ for(o=nil;;){
+ n = GET16(p);
+ if(n == 0xffff)
+ break;
+ o = o == nil ? oplr : onew();
+ o->on = n;
+ o->tc = (s16int)GET16(p);
+ o->type = GET16(p);
+ o->s = stt + GET16(p);
+ o->f = GET8(p);
+ o->Δr = (s32int)GET32(p);
+ o->x = GET32(p);
+ o->y = GET32(p);
+ o->tx = GET16(p);
+ o->ty = GET16(p);
+ o->tl = tiles + o->ty * Mapdxy + o->tx;
+ o->areaid = GET8(p);
+ o->vwx = GET16(p);
+ o->vwdy = GET16(p);
+ o->vwdx = GET32(p);
+ o->θ = (s16int)GET16(p);
+ o->hp = GET16(p);
+ o->v = GET32(p);
+ o->atkdt = (s16int)GET16(p);
+ o->sdt = GET16(p);
+ if(o != oplr && ((o->f & OFnevermark) == 0
+ || (o->f & OFnomark) == 0 || o->tl->o == nil)){
+ o->tl->o = o;
+ o->tl->to = 0;
+ }
+ }
+ disking();
+ stce = stcs + GET16(p);
+ if(stce > stcs + nelem(stcs)){
+ werrstr("ldmap: static object overflow");
+ return -1;
+ }
+ for(s=stcs; s<stce; s++){
+ s->tl = tiles + GET16(p);
+ s->spr = sprs + GET16(p);
+ s->f = GET8(p);
+ s->item = GET8(p);
+ }
+ disking();
+ doore = doors + GET16(p);
+ if(doore > doors + nelem(doors)){
+ werrstr("ldmap: door overflow");
+ return -1;
+ }
+ for(d=doors; d<doore; d++){
+ d->tl = tiles + GET16(p);
+ d->isvert = GET8(p);
+ d->lock = GET8(p);
+ d->φ = GET16(p);
+ d->tc = GET16(p);
+ d->dopen = GET16(p);
+ }
+ disking();
+ pusher.φ = GET16(p);
+ pusher.tl = tiles + GET16(p);
+ pusher.isvert = GET16(p);
+ pusher.dopen = GET16(p);
+ *ep = p;
+ return 0;
+}
+
void
initmap(void)
{
@@ -861,8 +1020,7 @@
u16int *p0, *p1, *s;
Tile *tl;
- oinit(1);
- memset(tiles, 0, sizeof tiles);
+ nukemap();
p0 = s = readmap(gm.map);
p1 = p0 + Mapa;
for(tl=tiles; tl<tiles+nelem(tiles); tl++){
--- a/menu.c
+++ b/menu.c
@@ -1,44 +1,3 @@
-s16int SaveGamesAvail[10],StartGame,SoundStatus=1,pickquick;
-char SaveGameNames[10][32],SaveName[13]="SAVEGAM?.";
-
-void US_ControlPanel(u8int scancode)
-{
- if (ingame)
- if (CP_CheckQuick(scancode))
- return;
- switch(scancode)
- {
- case sc_F1:
- #ifndef SPEAR
- HelpScreens();
- #endif
- goto finishup;
-
- case sc_F2:
- CP_SaveGame(0);
- goto finishup;
-
- case sc_F3:
- CP_LoadGame(0);
- goto finishup;
-
- case sc_F4:
- CP_Sound();
- goto finishup;
-
- case sc_F5:
- CP_ChangeView();
- goto finishup;
-
- case sc_F6:
- CP_Control();
- goto finishup;
-
- finishup:
- return;
- }
-}
-
void CP_ReadThis(void)
{
StartCPMusic(0);
@@ -160,402 +119,4 @@
}
return 0;
-}
-
-void CP_NewGame(void)
-{
- s16int which,episode;
-
-#ifndef SPEAR
-firstpart:
-
- DrawNewEpisode();
- do
- {
- which=HandleMenu(&NewEitems,&NewEmenu[0],NULL);
- switch(which)
- {
- case -1:
- MenuFadeOut();
- return;
-
- default:
- if (!EpisodeSelect[which/2])
- {
- sfx (Snoway);
- Message("Please select \"Read This!\"\n"
- "from the Options menu to\n"
- "find out how to order this\n"
- "episode from Apogee.");
- IN_ClearKeysDown();
- IN_Ack();
- DrawNewEpisode();
- which = 0;
- }
- else
- {
- episode = which/2;
- which = 1;
- }
- break;
- }
-
- } while (!which);
-
- ShootSnd();
-
- //
- // ALREADY IN A GAME?
- //
- if (ingame)
- if (!Confirm(CURGAME))
- {
- MenuFadeOut();
- return;
- }
-
- MenuFadeOut();
-
-#else
- episode = 0;
-
- //
- // ALREADY IN A GAME?
- //
- DrawNewGame();
- if (ingame)
- if (!Confirm(CURGAME))
- {
- MenuFadeOut();
- return;
- }
-
-#endif
-
- DrawNewGame();
- which=HandleMenu(&NewItems,&NewMenu[0],DrawNewGameDiff);
- if (which<0)
- {
- MenuFadeOut();
- #ifndef SPEAR
- goto firstpart;
- #else
- return;
- #endif
- }
-
- ShootSnd();
- NewGame(which,episode);
- StartGame=1;
- MenuFadeOut();
-
- //
- // CHANGE "READ THIS!" TO NORMAL COLOR
- //
- #ifndef SPEAR
- MainMenu[readthis].active=1;
- #endif
-
- pickquick = 0;
-}
-
-void DrawLSAction(s16int which)
-{
- #define LSA_X 96
- #define LSA_Y 80
- #define LSA_W 130
- #define LSA_H 42
-
- DrawWindow(LSA_X,LSA_Y,LSA_W,LSA_H,TEXTCOLOR);
- DrawOutline(LSA_X,LSA_Y,LSA_W,LSA_H,0,HIGHLIGHT);
- VWB_DrawPic(LSA_X+8,LSA_Y+5,Pread1);
-
- fontnumber=1;
- SETFONTCOLOR(0,TEXTCOLOR);
- PrintX=LSA_X+46;
- PrintY=LSA_Y+13;
-
- if (!which)
- US_Print("Loading...");
- else
- US_Print("Saving...");
-
- VW_UpdateScreen();
-}
-
-s16int CP_LoadGame(s16int quick)
-{
- s16int handle,which,exit=0;
- char name[13];
-
-
- strcpy(name,SaveName);
-
- //
- // QUICKLOAD?
- //
- if (quick)
- {
- which=LSItems.curpos;
-
- if (SaveGamesAvail[which])
- {
- name[7]=which+'0';
- handle=open(name,O_BINARY);
- lseek(handle,32,SEEK_SET);
- gm.load=true;
- LoadTheGame(handle,0,0);
- gm.load=false;
- close(handle);
-
- hudf ();
- hudh ();
- hudl ();
- hudm ();
- huda ();
- hudk ();
- hudw ();
- hudp ();
- return 1;
- }
- }
-
- DrawLoadSaveScreen(0);
-
- do
- {
- which=HandleMenu(&LSItems,&LSMenu[0],TrackWhichGame);
- if (which>=0 && SaveGamesAvail[which])
- {
- ShootSnd();
- name[7]=which+'0';
-
- handle=open(name,O_BINARY);
- lseek(handle,32,SEEK_SET);
-
- DrawLSAction(0);
- gm.load=true;
-
- LoadTheGame(handle,LSA_X+8,LSA_Y+5);
- close(handle);
-
- StartGame=1;
- ShootSnd();
- //
- // CHANGE "READ THIS!" TO NORMAL COLOR
- //
- #ifndef SPEAR
- MainMenu[readthis].active=1;
- #endif
-
- exit=1;
- break;
- }
-
- } while(which>=0);
-
- MenuFadeOut();
-
- return exit;
-}
-
-void TrackWhichGame(s16int w)
-{
- static s16int lastgameon=0;
-
- PrintLSEntry(lastgameon,TEXTCOLOR);
- PrintLSEntry(w,HIGHLIGHT);
-
- lastgameon=w;
-}
-
-void DrawLoadSaveScreen(s16int loadsave)
-{
- s16int i;
-
- ClearMScreen();
- fontnumber=1;
- VWB_DrawPic(112,184,Pmouselback);
- DrawWindow(LSM_X-10,LSM_Y-5,LSM_W,LSM_H,BKGDCOLOR);
- DrawStripes(10);
-
- if (!loadsave)
- VWB_DrawPic(60,0,Pload);
- else
- VWB_DrawPic(60,0,Psave);
-
- for (i=0;i<10;i++)
- PrintLSEntry(i,TEXTCOLOR);
-
- DrawMenu(&LSItems,&LSMenu[0]);
- VW_UpdateScreen();
- MenuFadeIn();
- WaitKeyUp();
-}
-
-void PrintLSEntry(s16int w,s16int color)
-{
- SETFONTCOLOR(color,BKGDCOLOR);
- DrawOutline(LSM_X+LSItems.indent,LSM_Y+w*13,LSM_W-LSItems.indent-15,11,color,color);
- PrintX=LSM_X+LSItems.indent+2;
- PrintY=LSM_Y+w*13+1;
- fontnumber=0;
-
- if (SaveGamesAvail[w])
- US_Print(SaveGameNames[w]);
- else
- US_Print(" - empty -");
-
- fontnumber=1;
-}
-
-s16int CP_SaveGame(s16int quick)
-{
- s16int handle,which,exit=0;
- u16int nwritten;
- char name[13],input[32];
-
-
- strcpy(name,SaveName);
-
- //
- // QUICKSAVE?
- //
- if (quick)
- {
- which=LSItems.curpos;
-
- if (SaveGamesAvail[which])
- {
- name[7]=which+'0';
- unlink(name);
- handle=creat(name,S_IREAD|S_IWRITE);
-
- strcpy(input,&SaveGameNames[which][0]);
-
- _dos_write(handle,(void far *)input,32,&nwritten);
- lseek(handle,32,SEEK_SET);
- SaveTheGame(handle,0,0);
- close(handle);
-
- return 1;
- }
- }
-
- DrawLoadSaveScreen(1);
-
- do
- {
- which=HandleMenu(&LSItems,&LSMenu[0],TrackWhichGame);
- if (which>=0)
- {
- //
- // OVERWRITE EXISTING SAVEGAME?
- //
- if (SaveGamesAvail[which])
- if (!Confirm("There's already a game\nsaved at this position.\n Overwrite?"))
- {
- DrawLoadSaveScreen(1);
- continue;
- }
- else
- {
- DrawLoadSaveScreen(1);
- PrintLSEntry(which,HIGHLIGHT);
- VW_UpdateScreen();
- }
-
- ShootSnd();
-
- strcpy(input,&SaveGameNames[which][0]);
- name[7]=which+'0';
-
- fontnumber=0;
- if (!SaveGamesAvail[which])
- VWB_Bar(LSM_X+LSItems.indent+1,LSM_Y+which*13+1,LSM_W-LSItems.indent-16,10,BKGDCOLOR);
- VW_UpdateScreen();
-
- if (US_LineInput(LSM_X+LSItems.indent+2,LSM_Y+which*13+1,input,input,true,31,LSM_W-LSItems.indent-30))
- {
- SaveGamesAvail[which]=1;
- strcpy(&SaveGameNames[which][0],input);
-
- unlink(name);
- handle=creat(name,S_IREAD|S_IWRITE);
- _dos_write(handle,(void far *)input,32,&nwritten);
- lseek(handle,32,SEEK_SET);
-
- DrawLSAction(1);
- SaveTheGame(handle,LSA_X+8,LSA_Y+5);
-
- close(handle);
-
- ShootSnd();
- exit=1;
- }
- else
- {
- VWB_Bar(LSM_X+LSItems.indent+1,LSM_Y+which*13+1,LSM_W-LSItems.indent-16,10,BKGDCOLOR);
- PrintLSEntry(which,HIGHLIGHT);
- VW_UpdateScreen();
- sfx(Sesc);
- continue;
- }
-
- fontnumber=1;
- break;
- }
-
- } while(which>=0);
-
- MenuFadeOut();
-
- return exit;
-}
-
-void SetupControlPanel(void)
-{
- //
- // SEE WHICH SAVE GAME FILES ARE AVAILABLE & READ STRING IN
- //
- strcpy(name,SaveName);
- if (!findfirst(name,&f,0))
- do
- {
- which=f.ff_name[7]-'0';
- if (which<10)
- {
- s16int handle;
- char temp[32];
-
- SaveGamesAvail[which]=1;
- handle=open(f.ff_name,O_BINARY);
- read(handle,temp,32);
- close(handle);
- strcpy(&SaveGameNames[which][0],temp);
- }
- } while(!findnext(&f));
-}
-
-void StartCPMusic(s16int song)
-{
- SD_MusicOff();
- SD_mapmus((MusicGroup far *)audiosegs[STARTMUSIC + song]);
-}
-
-void CheckPause(void)
-{
- if (Paused)
- {
- switch(SoundStatus)
- {
- case 0: SD_MusicOn(); break;
- case 1: SD_MusicOff(); break;
- }
-
- SoundStatus^=1;
- VW_WaitVBL(3);
- IN_ClearKeysDown();
- Paused=false;
- }
}
--- a/rend.c
+++ b/rend.c
@@ -182,7 +182,7 @@
scalspr(SPcam, vw.dx/2, vw.dy+1);
return;
}
- if(gm.w != -1)
+ if(gm.w != WPnone)
scalspr(wspr[gm.w] + gm.wfrm, vw.dx/2, vw.dy+1);
if(gm.record || gm.demo)
scalspr(SPdemo, vw.dx/2, vw.dy+1);
--- a/us.h
+++ /dev/null
@@ -1,12 +1,0 @@
-#define MaxHighName 57
-#define MaxScores 7
-typedef struct
- {
- char name[MaxHighName + 1];
- s32int score;
- u16int completed,episode;
- } HighScore;
-
-#define MaxString 128 // Maximum input string size
-
-extern HighScore Scores[];
--- a/us1.c
+++ /dev/null
@@ -1,224 +1,0 @@
-///////////////////////////////////////////////////////////////////////////
-//
-// USL_XORICursor() - XORs the I-bar text cursor. Used by US_LineInput()
-//
-///////////////////////////////////////////////////////////////////////////
-static void
-USL_XORICursor(s16int x,s16int y,char *s,u16int cursor)
-{
- static int status; // VGA doesn't XOR...
- char buf[MaxString];
- s16int temp;
- u16int w,h;
-
- strcpy(buf,s);
- buf[cursor] = '\0';
- USL_MeasureString(buf,&w,&h);
-
- px = x + w - 1;
- py = y;
- if (status^=1)
- USL_DrawString("\x80");
- else
- {
- temp = fontcolor;
- fontcolor = backcolor;
- USL_DrawString("\x80");
- fontcolor = temp;
- }
-
-}
-
-///////////////////////////////////////////////////////////////////////////
-//
-// US_LineInput() - Gets a line of user input at (x,y), the string defaults
-// to whatever is pointed at by def. Input is restricted to maxchars
-// chars or maxwidth pixels wide. If the user hits escape (and escok is
-// true), nothing is copied into buf, and false is returned. If the
-// user hits return, the current string is copied into buf, and true is
-// returned
-//
-///////////////////////////////////////////////////////////////////////////
-int
-US_LineInput(s16int x,s16int y,char *buf,char *def,int escok,
- s16int maxchars,s16int maxwidth)
-{
- int redraw,
- cursorvis,cursormoved,
- done,result;
- u8int sc;
- char c,
- s[MaxString],olds[MaxString];
- u16int i,
- cursor,
- w,h,
- len,temp;
- u32int lasttime;
-
- if (def)
- strcpy(s,def);
- else
- *s = '\0';
- *olds = '\0';
- cursor = strlen(s);
- cursormoved = redraw = true;
-
- cursorvis = done = false;
- lasttime = TimeCount;
- LastASCII = key_None;
- LastScan = sc_None;
-
- while (!done)
- {
- if (cursorvis)
- USL_XORICursor(x,y,s,cursor);
-
- asm pushf
- asm cli
-
- sc = LastScan;
- LastScan = sc_None;
- c = LastASCII;
- LastASCII = key_None;
-
- asm popf
-
- switch (sc)
- {
- case sc_LeftArrow:
- if (cursor)
- cursor--;
- c = key_None;
- cursormoved = true;
- break;
- case sc_RightArrow:
- if (s[cursor])
- cursor++;
- c = key_None;
- cursormoved = true;
- break;
- case sc_Home:
- cursor = 0;
- c = key_None;
- cursormoved = true;
- break;
- case sc_End:
- cursor = strlen(s);
- c = key_None;
- cursormoved = true;
- break;
-
- case sc_Return:
- strcpy(buf,s);
- done = true;
- result = true;
- c = key_None;
- break;
- case sc_Escape:
- if (escok)
- {
- done = true;
- result = false;
- }
- c = key_None;
- break;
-
- case sc_BackSpace:
- if (cursor)
- {
- strcpy(s + cursor - 1,s + cursor);
- cursor--;
- redraw = true;
- }
- c = key_None;
- cursormoved = true;
- break;
- case sc_Delete:
- if (s[cursor])
- {
- strcpy(s + cursor,s + cursor + 1);
- redraw = true;
- }
- c = key_None;
- cursormoved = true;
- break;
-
- case 0x4c: // Keypad 5
- case sc_UpArrow:
- case sc_DownArrow:
- case sc_PgUp:
- case sc_PgDn:
- case sc_Insert:
- c = key_None;
- break;
- }
-
- if (c)
- {
- len = strlen(s);
- USL_MeasureString(s,&w,&h);
-
- if
- (
- isprint(c)
- && (len < MaxString - 1)
- && ((!maxchars) || (len < maxchars))
- && ((!maxwidth) || (w < maxwidth))
- )
- {
- for (i = len + 1;i > cursor;i--)
- s[i] = s[i - 1];
- s[cursor++] = c;
- redraw = true;
- }
- }
-
- if (redraw)
- {
- px = x;
- py = y;
- temp = fontcolor;
- fontcolor = backcolor;
- USL_DrawString(olds);
- fontcolor = temp;
- strcpy(olds,s);
-
- px = x;
- py = y;
- USL_DrawString(s);
-
- redraw = false;
- }
-
- if (cursormoved)
- {
- cursorvis = false;
- lasttime = TimeCount - TickBase;
-
- cursormoved = false;
- }
- if (TimeCount - lasttime > TickBase / 2)
- {
- lasttime = TimeCount;
-
- cursorvis ^= true;
- }
- if (cursorvis)
- USL_XORICursor(x,y,s,cursor);
-
- VW_UpdateScreen();
- }
-
- if (cursorvis)
- USL_XORICursor(x,y,s,cursor);
- if (!result)
- {
- px = x;
- py = y;
- USL_DrawString(olds);
- }
- VW_UpdateScreen();
-
- IN_ClearKeysDown();
- return(result);
-}