1160 lines
23 KiB
C++

/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#include "glk/alan2/alan2.h"
#include "glk/alan2/types.h"
#include "glk/alan2/exe.h"
#include "glk/alan2/glkio.h"
#include "glk/alan2/inter.h"
#include "glk/alan2/main.h"
#include "glk/alan2/parse.h"
#include "glk/alan2/stack.h"
#include "glk/alan2/decode.h"
namespace Glk {
namespace Alan2 {
#define WIDTH 80
#define N_EVTS 100
/* PUBLIC DATA */
/* The event queue */
EvtqElem eventq[N_EVTS]; /* Event queue */
int etop = 0; /* Event queue top pointer */
Boolean looking = FALSE; /* LOOKING? flag */
int dscrstkp = 0; /* Describe-stack pointer */
void dscrobjs();
void dscracts();
void print(Aword fpos, Aword len) {
char str[2 * WIDTH]; // String buffer
int outlen = 0; // Current output length
int ch = 0;
int i;
long savfp = 0; // Temporary saved text file position
static Boolean printFlag = FALSE; // Printing already?
Boolean savedPrintFlag = printFlag;
void *info = nullptr; // Saved decoding info
if (len == 0) return;
if (isHere(HERO)) { /* Check if the player will see it */
if (printFlag) { /* Already printing? */
/* Save current text file position and/or decoding info */
if (header->pack)
info = pushDecode();
else
savfp = ftell(txtfil);
}
printFlag = TRUE; /* We're printing now! */
fseek(txtfil, fpos, 0); /* Position to start of text */
if (header->pack)
startDecoding();
for (outlen = 0; outlen != (int)len; outlen = outlen + strlen(str)) {
/* Fill the buffer from the beginning */
for (i = 0; i <= WIDTH || (i > WIDTH && ch != ' '); i++) {
if (outlen + i == (int)len) /* No more characters? */
break;
if (header->pack)
ch = decodeChar();
else
ch = getc(txtfil);
if (ch == EOFChar) /* Or end of text? */
break;
str[i] = ch;
}
str[i] = '\0';
output(str);
}
/* And restore */
printFlag = savedPrintFlag;
if (printFlag) {
if (header->pack)
popDecode(info);
else
fseek(txtfil, savfp, 0);
}
}
}
void sys(Aword fpos, Aword len) {
#ifdef GLK
::error("system calls aren't supported");
#else
char *command;
getstr(fpos, len); /* Returns address to string on stack */
command = (char *)pop();
int tmp = system(command);
free(command);
#endif
}
void getstr(Aword fpos, Aword len) {
char *buf = (char *)allocate(len + 1);
push((Aptr) buf); /* Push the address to the string */
fseek(txtfil, fpos, 0); /* Position to start of text */
if (header->pack)
startDecoding();
while (len--)
if (header->pack)
*(buf++) = decodeChar();
else
*(buf++) = getc(txtfil);
*buf = '\0';
}
void score(Aword sc) {
char buf[80];
if (sc == 0) {
prmsg(M_SCORE1);
sprintf(buf, "%d", cur.score);
output(buf);
prmsg(M_SCORE2);
sprintf(buf, "%ld.", (unsigned long) header->maxscore);
output(buf);
} else {
cur.score += scores[sc - 1];
scores[sc - 1] = 0;
}
}
void visits(Aword v) {
cur.visits = v;
}
Boolean confirm(MsgKind msgno) {
char buf[80];
/* This is a bit of a hack since we really want to compare the input,
it could be affirmative, but for now any input is NOT! */
prmsg(msgno);
if (!readline(buf)) return TRUE;
col = 1;
return (buf[0] == '\0');
}
void quit(CONTEXT) {
char buf[80];
para();
while (!g_vm->shouldQuit()) {
col = 1;
statusline();
prmsg(M_QUITACTION);
if (!readline(buf)) {
CALL1(terminate, 0)
}
if (scumm_stricmp(buf, "restart") == 0) {
g_vm->setRestart(true);
LONG_JUMP
} else if (scumm_stricmp(buf, "restore") == 0) {
restore();
LONG_JUMP
} else if (scumm_stricmp(buf, "quit") == 0) {
CALL1(terminate, 0)
}
}
}
void restart() {
para();
if (confirm(M_REALLY)) {
//longjmp(restart_label, TRUE);
::error("TODO: restart");
} else
return;
syserr("Fallthrough in RESTART");
}
void cancl(Aword evt) {
int i;
for (i = etop - 1; i >= 0; i--)
if (eventq[i].event == (int)evt) {
while (i < etop - 1) {
eventq[i].event = eventq[i + 1].event;
eventq[i].time = eventq[i + 1].time;
eventq[i].where = eventq[i + 1].where;
i++;
}
etop--;
return;
}
}
void schedule(Aword evt, Aword whr, Aword aft) {
int i;
int time;
cancl(evt);
/* Check for overflow */
if (etop == N_EVTS) syserr("Out of event space.");
time = cur.tick + aft;
/* Bubble this event down */
for (i = etop; i >= 1 && eventq[i - 1].time <= time; i--) {
eventq[i].event = eventq[i - 1].event;
eventq[i].time = eventq[i - 1].time;
eventq[i].where = eventq[i - 1].where;
}
eventq[i].time = time;
eventq[i].where = whr;
eventq[i].event = evt;
etop++;
}
/*----------------------------------------------------------------------
getatr()
Get an attribute value from an attribute list
*/
static Aptr getatr(
Aaddr atradr, /* IN - ACODE address to attribute table */
Aaddr atr /* IN - The attribute to read */
) {
AtrElem *at;
at = (AtrElem *) addrTo(atradr);
return at[atr - 1].val;
}
/*----------------------------------------------------------------------
setatr()
Set a particular attribute to a value.
*/
static void setatr(
Aaddr atradr, /* IN - ACODE address to attribute table */
Aword atr, /* IN - attribute code */
Aword val /* IN - new value */
) {
AtrElem *at;
at = (AtrElem *) addrTo(atradr);
at[atr - 1].val = val;
}
/*----------------------------------------------------------------------
make()
*/
static void makloc(Aword loc, Aword atr, Aword val) {
setatr(locs[loc - LOCMIN].atrs, atr, val);
}
static void makobj(Aword obj, Aword atr, Aword val) {
setatr(objs[obj - OBJMIN].atrs, atr, val);
}
static void makact(Aword act, Aword atr, Aword val) {
setatr(acts[act - ACTMIN].atrs, atr, val);
}
void make(Aword id, Aword atr, Aword val) {
char str[80];
if (isObj(id))
makobj(id, atr, val);
else if (isLoc(id))
makloc(id, atr, val);
else if (isAct(id))
makact(id, atr, val);
else {
sprintf(str, "Can't MAKE item (%ld).", (unsigned long) id);
syserr(str);
}
}
/*----------------------------------------------------------------------------
set()
*/
static void setloc(Aword loc, Aword atr, Aword val) {
setatr(locs[loc - LOCMIN].atrs, atr, val);
locs[loc - LOCMIN].describe = 0;
}
static void setobj(Aword obj, Aword atr, Aword val) {
setatr(objs[obj - OBJMIN].atrs, atr, val);
}
static void setact(Aword act, Aword atr, Aword val) {
setatr(acts[act - ACTMIN].atrs, atr, val);
}
void set(Aword id, Aword atr, Aword val) {
char str[80];
if (isObj(id))
setobj(id, atr, val);
else if (isLoc(id))
setloc(id, atr, val);
else if (isAct(id))
setact(id, atr, val);
else {
sprintf(str, "Can't SET item (%ld).", (unsigned long) id);
syserr(str);
}
}
void setstr(Aword id, Aword atr, Aword str) {
free((char *)attribute(id, atr));
set(id, atr, str);
}
/*-----------------------------------------------------------------------------
incr/decr
*/
/*----------------------------------------------------------------------
incratr()
Increment a particular attribute by a value.
*/
static void incratr(
Aaddr atradr, /* IN - ACODE address to attribute table */
Aword atr, /* IN - attribute code */
Aword step /* IN - step to increment by */
) {
AtrElem *at;
at = (AtrElem *) addrTo(atradr);
at[atr - 1].val += step;
}
static void incrloc(Aword loc, Aword atr, Aword step) {
incratr(locs[loc - LOCMIN].atrs, atr, step);
locs[loc - LOCMIN].describe = 0;
}
static void incrobj(Aword obj, Aword atr, Aword step) {
incratr(objs[obj - OBJMIN].atrs, atr, step);
}
static void incract(Aword act, Aword atr, Aword step) {
incratr(acts[act - ACTMIN].atrs, atr, step);
}
void incr(Aword id, Aword atr, Aword step) {
char str[80];
if (isObj(id))
incrobj(id, atr, step);
else if (isLoc(id))
incrloc(id, atr, step);
else if (isAct(id))
incract(id, atr, step);
else {
sprintf(str, "Can't INCR item (%ld).", (unsigned long) id);
syserr(str);
}
}
void decr(Aword id, Aword atr, Aword step) {
char str[80];
// TODO: Original did explicit negation on an unsigned value. Make sure that the
// casts added to ignore the warnings are okay
if (isObj(id))
incrobj(id, atr, static_cast<uint>(-(int)step));
else if (isLoc(id))
incrloc(id, atr, static_cast<uint>(-(int)step));
else if (isAct(id))
incract(id, atr, static_cast<uint>(-(int)step));
else {
sprintf(str, "Can't DECR item (%ld).", (unsigned long) id);
syserr(str);
}
}
/*----------------------------------------------------------------------
attribute()
*/
static Aptr locatr(Aword loc, Aword atr) {
return getatr(locs[loc - LOCMIN].atrs, atr);
}
static Aptr objatr(Aword obj, Aword atr) {
return getatr(objs[obj - OBJMIN].atrs, atr);
}
static Aptr actatr(Aword act, Aword atr) {
return getatr(acts[act - ACTMIN].atrs, atr);
}
static Aptr litatr(Aword lit, Aword atr) {
char str[80];
if (atr == 1)
return litValues[lit - LITMIN].value;
else {
sprintf(str, "Unknown attribute for literal (%ld).", (unsigned long) atr);
syserr(str);
}
return (Aptr)EOD;
}
Aptr attribute(Aword id, Aword atr) {
char str[80];
if (isObj(id))
return objatr(id, atr);
else if (isLoc(id))
return locatr(id, atr);
else if (isAct(id))
return actatr(id, atr);
else if (isLit(id))
return litatr(id, atr);
else {
sprintf(str, "Can't ATTRIBUTE item (%ld).", (unsigned long) id);
syserr(str);
}
return (Aptr)EOD;
}
Aptr strattr(Aword id, Aword atr) {
return (Aptr) strdup((char *)attribute(id, atr));
}
/*----------------------------------------------------------------------
where()
*/
static Aword objloc(Aword obj) {
if (isCnt(objs[obj - OBJMIN].loc)) /* In something ? */
if (isObj(objs[obj - OBJMIN].loc) || isAct(objs[obj - OBJMIN].loc))
return (where(objs[obj - OBJMIN].loc));
else /* Containers not anywhere is where the hero is! */
return (where(HERO));
else
return (objs[obj - OBJMIN].loc);
}
static Aword actloc(Aword act) {
return (acts[act - ACTMIN].loc);
}
Aword where(Aword id) {
char str[80];
if (isObj(id))
return objloc(id);
else if (isAct(id))
return actloc(id);
else {
sprintf(str, "Can't WHERE item (%ld).", (unsigned long) id);
syserr(str);
}
return (Aptr)EOD;
}
/*----------------------------------------------------------------------
aggregates
*/
Aint agrmax(Aword atr, Aword whr) {
Aword i;
Aint max = 0;
for (i = OBJMIN; i <= OBJMAX; i++) {
if (isLoc(whr)) {
if (where(i) == whr && (int)attribute(i, atr) > max)
max = attribute(i, atr);
} else if (objs[i - OBJMIN].loc == whr && (int)attribute(i, atr) > max)
max = attribute(i, atr);
}
return (max);
}
Aint agrsum(Aword atr, Aword whr) {
Aword i;
Aint sum = 0;
for (i = OBJMIN; i <= OBJMAX; i++) {
if (isLoc(whr)) {
if (where(i) == whr)
sum += attribute(i, atr);
} else if (objs[i - OBJMIN].loc == whr)
sum += attribute(i, atr);
}
return (sum);
}
Aint agrcount(Aword whr) {
Aword i;
Aword count = 0;
for (i = OBJMIN; i <= OBJMAX; i++) {
if (isLoc(whr)) {
if (where(i) == whr)
count++;
} else if (objs[i - OBJMIN].loc == whr)
count++;
}
return (count);
}
/*----------------------------------------------------------------------
locate()
*/
static void locobj(Aword obj, Aword whr) {
if (isCnt(whr)) { /* Into a container */
if (whr == obj)
syserr("Locating something inside itself.");
if (checklim(whr, obj))
return;
else
objs[obj - OBJMIN].loc = whr;
} else {
objs[obj - OBJMIN].loc = whr;
/* Make sure the location is described since it's changed */
locs[whr - LOCMIN].describe = 0;
}
}
static void locact(Aword act, Aword whr) {
Aword prevact = cur.act;
Aword prevloc = cur.loc;
cur.loc = whr;
acts[act - ACTMIN].loc = whr;
if (act == HERO) {
if (locs[acts[act - ACTMIN].loc - LOCMIN].describe % (cur.visits + 1) == 0)
look();
else {
if (anyOutput)
para();
say(where(HERO));
prmsg(M_AGAIN);
newline();
dscrobjs();
dscracts();
}
locs[where(HERO) - LOCMIN].describe++;
locs[where(HERO) - LOCMIN].describe %= (cur.visits + 1);
} else
locs[whr - LOCMIN].describe = 0;
if (locs[cur.loc - LOCMIN].does != 0) {
cur.act = act;
interpret(locs[cur.loc - LOCMIN].does);
cur.act = prevact;
}
if (cur.act != (int)act)
cur.loc = prevloc;
}
void locate(Aword id, Aword whr) {
char str[80];
if (isObj(id))
locobj(id, whr);
else if (isAct(id))
locact(id, whr);
else {
sprintf(str, "Can't LOCATE item (%ld).", (unsigned long) id);
syserr(str);
}
}
/*----------------------------------------------------------------------
isHere()
*/
static Abool objhere(Aword obj) {
if (isCnt(objs[obj - OBJMIN].loc)) { /* In something? */
if (isObj(objs[obj - OBJMIN].loc) || isAct(objs[obj - OBJMIN].loc))
return (isHere(objs[obj - OBJMIN].loc));
else /* If the container wasn't anywhere, assume where HERO is! */
return ((int)where(HERO) == cur.loc);
} else {
return (int)(objs[obj - OBJMIN].loc) == cur.loc;
}
}
static Aword acthere(Aword act) {
return (int)(acts[act - ACTMIN].loc) == cur.loc;
}
Abool isHere(Aword id) {
char str[80];
if (isObj(id))
return objhere(id);
else if (isAct(id))
return acthere(id);
else {
sprintf(str, "Can't HERE item (%ld).", (unsigned long) id);
syserr(str);
}
return (Abool)EOD;
}
/*----------------------------------------------------------------------
isNear()
*/
static Aword objnear(Aword obj) {
if (isCnt(objs[obj - OBJMIN].loc)) { /* In something? */
if (isObj(objs[obj - OBJMIN].loc) || isAct(objs[obj - OBJMIN].loc))
return (isNear(objs[obj - OBJMIN].loc));
else /* If the container wasn't anywhere, assume here, so not nearby! */
return (FALSE);
} else
return (exitto(where(obj), cur.loc));
}
static Aword actnear(Aword act) {
return (exitto(where(act), cur.loc));
}
Abool isNear(Aword id) {
char str[80];
if (isObj(id))
return objnear(id);
else if (isAct(id))
return actnear(id);
else {
sprintf(str, "Can't NEAR item (%ld).", (unsigned long) id);
syserr(str);
}
return (Abool)EOD;
}
/*----------------------------------------------------------------------
in()
*/
Abool in(Aword obj, Aword cnt) {
if (!isObj(obj))
return (FALSE);
if (!isCnt(cnt))
syserr("IN in a non-container.");
return (objs[obj - OBJMIN].loc == cnt);
}
/*----------------------------------------------------------------------
say()
*/
static void sayloc(Aword loc) {
interpret(locs[loc - LOCMIN].nams);
}
static void sayobj(Aword obj) {
interpret(objs[obj - OBJMIN].dscr2);
}
static void sayact(Aword act) {
interpret(acts[act - ACTMIN].nam);
}
void sayint(Aword val) {
char buf[25];
if (isHere(HERO)) {
sprintf(buf, "%ld", (unsigned long) val);
output(buf);
}
}
void saystr(char *str) {
if (isHere(HERO))
output(str);
free(str);
}
static void saylit(Aword lit) {
char *str;
if (isNum(lit))
sayint(litValues[lit - LITMIN].value);
else {
str = (char *)strdup((char *)litValues[lit - LITMIN].value);
saystr(str);
}
}
void sayarticle(Aword id) {
if (!isObj(id))
syserr("Trying to say article of something *not* an object.");
if (objs[id - OBJMIN].art != 0)
interpret(objs[id - OBJMIN].art);
else
prmsg(M_ARTICLE);
}
void say(Aword id) {
char str[80];
if (isHere(HERO)) {
if (isObj(id))
sayobj(id);
else if (isLoc(id))
sayloc(id);
else if (isAct(id))
sayact(id);
else if (isLit(id))
saylit(id);
else {
sprintf(str, "Can't SAY item (%ld).", (unsigned long) id);
syserr(str);
}
}
}
/*----------------------------------------------------------------------
describe()
*/
static void dscrloc(Aword loc) {
if (locs[loc - LOCMIN].dscr != 0)
interpret(locs[loc - LOCMIN].dscr);
}
static void dscrobj(Aword obj) {
objs[obj - OBJMIN].describe = FALSE;
if (objs[obj - OBJMIN].dscr1 != 0)
interpret(objs[obj - OBJMIN].dscr1);
else {
prmsg(M_SEEOBJ1);
sayarticle(obj);
say(obj);
prmsg(M_SEEOBJ4);
if (objs[obj - OBJMIN].cont != 0)
list(obj);
}
}
static void dscract(Aword act) {
ScrElem *scr = NULL;
if (acts[act - ACTMIN].script != 0) {
for (scr = (ScrElem *) addrTo(acts[act - ACTMIN].scradr); !endOfTable(scr); scr++)
if (scr->code == acts[act - ACTMIN].script)
break;
if (endOfTable(scr)) scr = NULL;
}
if (scr != NULL && scr->dscr != 0)
interpret(scr->dscr);
else if (acts[act - ACTMIN].dscr != 0)
interpret(acts[act - ACTMIN].dscr);
else {
interpret(acts[act - ACTMIN].nam);
prmsg(M_SEEACT);
}
acts[act - ACTMIN].describe = FALSE;
}
static Aword dscrstk[255];
void describe(Aword id) {
int i;
char str[80];
for (i = 0; i < dscrstkp; i++)
if (dscrstk[i] == id)
syserr("Recursive DESCRIBE.");
dscrstk[dscrstkp++] = id;
if (isObj(id))
dscrobj(id);
else if (isLoc(id))
dscrloc(id);
else if (isAct(id))
dscract(id);
else {
sprintf(str, "Can't DESCRIBE item (%ld).", (unsigned long) id);
syserr(str);
}
dscrstkp--;
}
/*----------------------------------------------------------------------
use()
*/
void use(Aword act, Aword scr) {
char str[80];
if (!isAct(act)) {
sprintf(str, "Item is not an Actor (%ld).", (unsigned long) act);
syserr(str);
}
acts[act - ACTMIN].script = scr;
acts[act - ACTMIN].step = 0;
}
/*----------------------------------------------------------------------
list()
*/
void list(Aword cnt) {
uint i;
Aword props;
Aword prevobj = 0;
Boolean found = FALSE;
Boolean multiple = FALSE;
/* Find container properties */
if (isObj(cnt))
props = objs[cnt - OBJMIN].cont;
else if (isAct(cnt))
props = acts[cnt - ACTMIN].cont;
else
props = cnt;
for (i = OBJMIN; i <= OBJMAX; i++) {
if (in(i, cnt)) { /* Yes, it's in this container */
if (!found) {
found = TRUE;
if (cnts[props - CNTMIN].header != 0)
interpret(cnts[props - CNTMIN].header);
else {
prmsg(M_CONTAINS1);
if (cnts[props - CNTMIN].nam != 0) /* It has it's own name */
interpret(cnts[props - CNTMIN].nam);
else
say(cnts[props - CNTMIN].parent); /* It is actually an object or actor */
prmsg(M_CONTAINS2);
}
} else {
if (multiple) {
needsp = FALSE;
prmsg(M_CONTAINS3);
}
multiple = TRUE;
sayarticle(prevobj);
say(prevobj);
}
prevobj = i;
}
}
if (found) {
if (multiple)
prmsg(M_CONTAINS4);
sayarticle(prevobj);
say(prevobj);
prmsg(M_CONTAINS5);
} else {
if (cnts[props - CNTMIN].empty != 0)
interpret(cnts[props - CNTMIN].empty);
else {
prmsg(M_EMPTY1);
if (cnts[props - CNTMIN].nam != 0) /* It has it's own name */
interpret(cnts[props - CNTMIN].nam);
else
say(cnts[props - CNTMIN].parent); /* It is actually an actor or object */
prmsg(M_EMPTY2);
}
}
needsp = TRUE;
}
/*----------------------------------------------------------------------
empty()
*/
void empty(Aword cnt, Aword whr) {
for (uint i = OBJMIN; i <= OBJMAX; i++)
if (in(i, cnt))
locate(i, whr);
}
/*----------------------------------------------------------------------*\
Description of current location
dscrobjs()
dscracts()
look()
\*----------------------------------------------------------------------*/
void dscrobjs() {
uint i;
int prevobj = 0;
Boolean found = FALSE;
Boolean multiple = FALSE;
/* First describe everything here with its own description */
for (i = OBJMIN; i <= OBJMAX; i++)
if ((int)objs[i - OBJMIN].loc == cur.loc &&
objs[i - OBJMIN].describe &&
objs[i - OBJMIN].dscr1)
describe(i);
/* Then list everything else here */
for (i = OBJMIN; i <= OBJMAX; i++)
if ((int)objs[i - OBJMIN].loc == cur.loc && objs[i - OBJMIN].describe) {
if (!found) {
prmsg(M_SEEOBJ1);
sayarticle(i);
say(i);
found = TRUE;
} else {
if (multiple) {
needsp = FALSE;
prmsg(M_SEEOBJ2);
sayarticle(prevobj);
say(prevobj);
}
multiple = TRUE;
}
prevobj = i;
}
if (found) {
if (multiple) {
prmsg(M_SEEOBJ3);
sayarticle(prevobj);
say(prevobj);
}
prmsg(M_SEEOBJ4);
}
/* Set describe flag for all objects */
for (i = OBJMIN; i <= OBJMAX; i++)
objs[i - OBJMIN].describe = TRUE;
}
void dscracts() {
uint i;
for (i = HERO + 1; i <= ACTMAX; i++)
if ((int)acts[i - ACTMIN].loc == cur.loc && acts[i - ACTMIN].describe)
describe(i);
/* Set describe flag for all actors */
for (i = HERO; i <= ACTMAX; i++)
acts[i - ACTMIN].describe = TRUE;
}
void look() {
uint i;
if (looking)
syserr("Recursive LOOK.");
looking = TRUE;
/* Set describe flag for all objects and actors */
for (i = OBJMIN; i <= OBJMAX; i++)
objs[i - OBJMIN].describe = TRUE;
for (i = ACTMIN; i <= ACTMAX; i++)
acts[i - ACTMIN].describe = TRUE;
if (anyOutput)
para();
g_vm->glk_set_style(style_Subheader);
needsp = FALSE;
say(cur.loc);
needsp = FALSE;
output(".");
g_vm->glk_set_style(style_Normal);
newline();
needsp = FALSE;
describe(cur.loc);
dscrobjs();
dscracts();
looking = FALSE;
}
/*----------------------------------------------------------------------
save()
*/
void save() {
(void)g_vm->saveGame();
}
/*----------------------------------------------------------------------
restore()
*/
void restore() {
(void)g_vm->loadGame();
}
/*----------------------------------------------------------------------
rnd()
*/
Aword rnd(Aword from, Aword to) {
if (to == from)
return to;
else if (to > from)
return (rand() / 10) % (to - from + 1) + from;
else
return (rand() / 10) % (from - to + 1) + to;
}
/*----------------------------------------------------------------------
btw()
BETWEEN
*/
Abool btw(Aint val, Aint low, Aint high) {
if (high > low)
return low <= val && val <= high;
else
return high <= val && val <= low;
}
/*----------------------------------------------------------------------
contains()
*/
Aword contains(Aptr string, Aptr substring) {
Abool found;
strlow((char *)string);
strlow((char *)substring);
found = (strstr((char *)string, (char *)substring) != 0);
free((char *)string);
free((char *)substring);
return (found);
}
/*----------------------------------------------------------------------
streq()
Compare two strings approximately, ignore case
*/
Abool streq(char a[], char b[]) {
Boolean eq;
strlow(a);
strlow(b);
eq = (strcmp(a, b) == 0);
free(a);
free(b);
return (eq);
}
} // End of namespace Alan2
} // End of namespace Glk