mirror of
https://github.com/libretro/scummvm.git
synced 2025-02-10 21:03:31 +00:00
1178 lines
25 KiB
C++
1178 lines
25 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 3 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, see <http://www.gnu.org/licenses/>.
|
|
*
|
|
*/
|
|
|
|
#include "glk/agt/agility.h"
|
|
#include "glk/agt/interp.h"
|
|
#include "glk/agt/exec.h"
|
|
|
|
namespace Glk {
|
|
namespace AGT {
|
|
|
|
/*
|
|
|
|
This contains the code for actually executing each of the
|
|
individual metacommand tokens as well as the routines for
|
|
doing range checking to prevent a bad metacommand from crashing
|
|
the interpreter.
|
|
|
|
*/
|
|
|
|
static void it_newdesc(integer item, descr_ptr *newdesc) {
|
|
descr_ptr *desc;
|
|
|
|
if (tnoun(item)) desc = noun_ptr + (item - first_noun);
|
|
else if (tcreat(item)) desc = creat_ptr + (item - first_creat);
|
|
else if (item >= first_room && item <= maxroom)
|
|
desc = room_ptr + (item - first_room);
|
|
else {
|
|
writeln("INTERNAL ERROR: it_newdesc called with invalid object");
|
|
return;
|
|
}
|
|
desc->start = newdesc->start;
|
|
desc->size = newdesc->size;
|
|
}
|
|
|
|
static void changepict(int old_pict, int new_pict)
|
|
/* Replace old_pict by new_pict */
|
|
{
|
|
pictable[old_pict - 1] = new_pict - 1;
|
|
}
|
|
|
|
|
|
static const int antidir[12] = {1, 0, 3, 2, 7, 6, 5, 4, 9, 8, 11, 10};
|
|
|
|
static void change_passage(int start, int dir, int newend)
|
|
/* dir is 1..12 */
|
|
/* START is a room number: i.e. starting at 0. */
|
|
/* NEWEND is an object number, so starts at first_room */
|
|
{
|
|
int oldend, i;
|
|
|
|
dir--; /* Convert direction to 0..11 scale */
|
|
oldend = room[start].path[dir];
|
|
room[start].path[dir] = newend;
|
|
if (newend == 0) {
|
|
if (room[oldend - first_room].path[antidir[dir]] == start + first_room)
|
|
room[oldend - first_room].path[antidir[dir]] = 0;
|
|
else for (i = 0; i < 12; i++)
|
|
if (room[oldend - first_room].path[i] == start + first_room) {
|
|
room[oldend - first_room].path[i] = 0;
|
|
break;
|
|
}
|
|
} else
|
|
room[newend - first_room].path[antidir[dir]] = start + first_room;
|
|
}
|
|
|
|
|
|
static long ask_for_number(int n1, int n2) {
|
|
char s[50];
|
|
int n;
|
|
|
|
if (n1 != n2)
|
|
Common::sprintf_s(s, "Enter a number from %d to %d: ", n1, n2);
|
|
else
|
|
Common::sprintf_s(s, "Enter a number: ");
|
|
for (;;) {
|
|
writestr(s);
|
|
n = read_number();
|
|
if (aver < AGX00)
|
|
n = (integer) (n & 0xFFFF);
|
|
if (n1 == n2 || (n >= n1 && n <= n2)) return n;
|
|
writeln("");
|
|
}
|
|
}
|
|
|
|
/* Check if n1*n2 will fit in 32 bits and print an error message if not */
|
|
/* This errs on the side of caution */
|
|
static rbool mult_rangecheck(long n1, long n2) {
|
|
int cnt;
|
|
|
|
if (n1 == 0 || n2 == 0) return 1;
|
|
if (n1 < 0) n1 = -n1;
|
|
if (n2 < 0) n2 = -n2;
|
|
|
|
for (cnt = 0; n1 != 0; n1 >>= 1, cnt++);
|
|
for (; n2 != 0; n2 >>= 1, cnt++);
|
|
cnt--;
|
|
|
|
if (cnt <= 31) return 1; /* We're okay */
|
|
|
|
if (!PURE_ERROR)
|
|
writeln("GAME ERROR: Multiplication out of range.");
|
|
return 0;
|
|
}
|
|
|
|
static rbool is_numeric(parse_rec *objrec) {
|
|
char *s;
|
|
|
|
if (objrec->num != 0 || objrec->info == D_NUM) return 1;
|
|
if (objrec->adj != 0) return 0;
|
|
if (objrec->noun <= 0) return 0;
|
|
(void)strtol(dict[objrec->noun], &s, 10);
|
|
return (*s == 0); /* *s==0 means no error-- it parsed as a number. */
|
|
}
|
|
|
|
static void setcase(char *s, rbool up) {
|
|
for (; *s != 0; s++)
|
|
if (up) *s = toupper(*s);
|
|
else *s = tolower(*s);
|
|
}
|
|
|
|
|
|
void move_in_dir(int obj, int dir) {
|
|
int r;
|
|
|
|
r = it_room(obj);
|
|
if (!troom(r)) {
|
|
writeln("GAME ERROR: Object not in a room.");
|
|
return;
|
|
}
|
|
r = room[r - first_room].path[dir - 1];
|
|
if (!troom(r)) return; /* Can't go that way; Fail silently */
|
|
if (obj == 1)
|
|
goto_room(r);
|
|
else
|
|
it_move(obj, r);
|
|
}
|
|
|
|
|
|
/* ------------------------------------------------------------------- */
|
|
/* Stack routines: Manipulating the expression stack */
|
|
/* ------------------------------------------------------------------- */
|
|
|
|
static long *stack = nullptr;
|
|
static int sp = 0; /* Stack pointer */
|
|
static int stacksize = 0; /* Actual space allocated to the stack */
|
|
|
|
void init_stack(void) {
|
|
rfree(stack);
|
|
sp = 0;
|
|
stacksize = 0;
|
|
}
|
|
|
|
/* This resets the stack to an empty state. */
|
|
void clear_stack(void) {
|
|
sp = 0;
|
|
}
|
|
|
|
static void push_stack(long val) {
|
|
sp++;
|
|
if (sp > stacksize) {
|
|
stacksize += 10;
|
|
stack = (long *)rrealloc(stack, stacksize * sizeof(long));
|
|
}
|
|
stack[sp - 1] = val;
|
|
}
|
|
|
|
static long pop_stack(void) {
|
|
long n;
|
|
if (sp == 0) {
|
|
writeln("GAME ERROR: Stack underflow.");
|
|
return 0;
|
|
}
|
|
n = stack[--sp];
|
|
if (sp + 100 < stacksize) {
|
|
stacksize -= 50;
|
|
stack = (long *)rrealloc(stack, stacksize * sizeof(long));
|
|
}
|
|
return n;
|
|
}
|
|
|
|
long pop_expr_stack(void) {
|
|
return pop_stack();
|
|
}
|
|
|
|
|
|
/* opnum: 0=+, 1=-, 2=*, 3=/ 4=% */
|
|
static void op_stack(int opnum) {
|
|
long n1, n2;
|
|
n1 = pop_stack();
|
|
n2 = pop_stack();
|
|
switch (opnum) {
|
|
case 0:
|
|
n1 = n1 + n2;
|
|
break;
|
|
case 1:
|
|
n1 = n1 - n2;
|
|
break;
|
|
case 2:
|
|
if (mult_rangecheck(n1, n2)) n1 = n1 * n2;
|
|
break;
|
|
case 3:
|
|
if (n2 != 0) n1 = n1 / n2;
|
|
else writeln("GAME ERROR: Division by zero.");
|
|
break;
|
|
case 4:
|
|
if (n2 != 0) n1 = n1 % n2;
|
|
else writeln("GAME ERROR: Division by zero.");
|
|
break;
|
|
default:
|
|
writeln("INTERNAL ERROR: Invalid stack operation.");
|
|
}
|
|
push_stack(n1);
|
|
}
|
|
|
|
/* This is called from the disassembler */
|
|
void print_tos(void) {
|
|
if (sp > 0)
|
|
dbgprintf("TOS(%ld)", stack[sp - 1]);
|
|
else
|
|
debugout("TOS(xxx)");
|
|
}
|
|
|
|
|
|
|
|
/* ------------------------------------------------------------------- */
|
|
/* METACOMMAND ROUTINES */
|
|
/* Functions for scanning and decoding of metacommands */
|
|
/* ------------------------------------------------------------------- */
|
|
|
|
/* #define cret(b) return ((b) ? -1 : 0)*/
|
|
#define cret(b) return (b)
|
|
#define cretn(i,f) cret(tnoun(i) && noun[i-first_noun].f)
|
|
#define cretc(i,f) cret(tcreat(i) && creature[i-first_creat].f)
|
|
#define icretc(f) cret(do_disambig==1 || \
|
|
(tcreat(iobj) && creature[iobj-first_creat].f))
|
|
|
|
static int obj_cond(int op_, int obj, int arg) {
|
|
switch (op_) {
|
|
case 0:
|
|
cret(in_scope(obj)); /* Present--
|
|
Do we want to use visible here?? */
|
|
case 1:
|
|
cret(is_within(obj, 1000, 1)); /* IsWearing */
|
|
case 2:
|
|
cret(is_within(obj, 1, 1));
|
|
/* if (PURE_WEAR) return (it_loc(obj)==1); else */
|
|
case 3:
|
|
cret(it_loc(obj) == 0); /* Nowhere */
|
|
case 4:
|
|
cret(it_loc(obj) != 0);
|
|
case 5:
|
|
cret(!player_has(obj) && in_scope(obj));
|
|
case 6:
|
|
cret(it_loc(obj) == arg);
|
|
case 7:
|
|
cret(it_on(obj));
|
|
case 8:
|
|
cret(!it_on(obj));
|
|
case 9:
|
|
cret(it_open(obj));
|
|
case 10:
|
|
cret(!it_open(obj));
|
|
case 11:
|
|
cretn(obj, locked);
|
|
case 12:
|
|
cret(!tnoun(obj) || !noun[obj - first_noun].locked);
|
|
case 13:
|
|
cretn(obj, edible);
|
|
case 14:
|
|
cretn(obj, drinkable);
|
|
case 15:
|
|
cretn(obj, poisonous);
|
|
case 16:
|
|
cretn(obj, movable);
|
|
default:
|
|
writeln("INTERNAL ERROR: Bad obj_cond value.");
|
|
return 2;
|
|
}
|
|
}
|
|
|
|
|
|
static int exec_cond(int op_, int arg1, int arg2) {
|
|
int i;
|
|
|
|
switch (op_) {
|
|
/* First the conditions */
|
|
case 0:
|
|
cret(loc + first_room == arg1); /* AtLoc(Room) */
|
|
case 1:
|
|
cret(loc + first_room > arg1);
|
|
case 2:
|
|
cret(loc + first_room < arg1);
|
|
case 3:
|
|
return musiccmd(-1, -1); /* SongPlaying */
|
|
case 4:
|
|
return musiccmd(-2, -1); /* SoundIsOn */
|
|
case 5:
|
|
cret(vb <= 13 && vb > 0 &&
|
|
room[loc].path[vb - 1] >= first_room); /*DirOK*/
|
|
case 6:
|
|
cret(vb == arg1); /* DirectionIs */
|
|
case 7:
|
|
cret(loc + first_room >= arg1 &&
|
|
loc + first_room <= arg2); /* BetweenRooms ?? */
|
|
case 8:
|
|
cret(room[arg1 - first_room].seen);
|
|
case 9: /* Entered Object? i.e. is iobj valid */
|
|
cret(do_disambig == 1 || iobj > 0);
|
|
case 10:
|
|
cret(curr_time > arg1); /* TimeGT */
|
|
case 11:
|
|
cret(curr_time < arg1); /* TimeLT */
|
|
case 12:
|
|
cret(first_visit_flag);
|
|
case 13:
|
|
cret(newlife_flag);
|
|
case 14:
|
|
cret(player_contents != 0); /* CarrySome */
|
|
case 15:
|
|
cret(player_contents == 0); /* CarryNo */
|
|
case 16:
|
|
cret(player_worn != 0); /* WearSome */
|
|
case 18:
|
|
cret(player_worn == 0); /* WearNo */
|
|
case 17: /* CarryTreas */
|
|
contloop(i, 1)
|
|
if (tnoun(i) && noun[i - first_noun].points >= arg1) return 1;
|
|
contloop(i, 1000)
|
|
if (tnoun(i) && noun[i - first_noun].points >= arg1) return 1;
|
|
return 0;
|
|
case 19:
|
|
cret(totwt == arg1);
|
|
case 20:
|
|
cret(totwt > arg1);
|
|
case 21:
|
|
cret(totwt < arg1);
|
|
case 22:
|
|
case 23:
|
|
case 24:
|
|
case 25:
|
|
case 26:
|
|
case 27:
|
|
case 28:
|
|
return obj_cond(op_ - 22, arg1, arg2);
|
|
case 29:
|
|
cret(it_loc(arg1) == it_loc(arg2));
|
|
case 30:
|
|
case 31:
|
|
return obj_cond(op_ - 23, arg1, arg2);
|
|
case 32:
|
|
cret(it_group(arg1));
|
|
case 33:
|
|
case 34:
|
|
case 35:
|
|
case 36:
|
|
case 37:
|
|
case 38:
|
|
case 39:
|
|
case 40:
|
|
return obj_cond(op_ - 24, arg1, arg2);
|
|
case 41:
|
|
case 42:
|
|
case 43:
|
|
case 44:
|
|
case 45:
|
|
case 46:
|
|
case 47:
|
|
case 48:
|
|
case 49:
|
|
case 50:
|
|
case 51:
|
|
case 52:
|
|
case 53:
|
|
case 54:
|
|
case 55:
|
|
case 56:
|
|
case 57:
|
|
return obj_cond(op_ - 41, dobj, arg1);
|
|
case 58:
|
|
cretn(dobj, points == arg1);
|
|
case 59:
|
|
cretn(dobj, points > arg1);
|
|
case 60:
|
|
cretn(dobj, points < arg1);
|
|
case 61:
|
|
cretn(dobj, weight == arg1);
|
|
case 62:
|
|
cretn(dobj, weight > arg1);
|
|
case 63:
|
|
cretn(dobj, weight < arg1);
|
|
case 64:
|
|
cret(islit());
|
|
case 65:
|
|
cret(room[loc].light != 0);
|
|
case 66:
|
|
cret(flag[arg1]);
|
|
case 67:
|
|
cret(!flag[arg1]);
|
|
case 68:
|
|
cret(room[loc].flag_noun_bits & (1 << (arg1 - 1)));
|
|
case 70:
|
|
cret(!(room[loc].flag_noun_bits & (1 << (arg1 - 1))));
|
|
case 69:
|
|
cret(room[loc].PIX_bits & (1 << (arg1 - 1))); /* Room Pix here? */
|
|
case 71:
|
|
cret(tscore == arg1);
|
|
case 72:
|
|
cret(tscore > arg1);
|
|
case 73:
|
|
cret(tscore < arg1);
|
|
case 74:
|
|
cret(agt_number == arg1);
|
|
case 75:
|
|
cret(agt_number > arg1);
|
|
case 76:
|
|
cret(agt_number < arg1);
|
|
case 77:
|
|
cret(agt_answer);
|
|
case 78:
|
|
cret(!agt_answer);
|
|
case 79:
|
|
cret(turncnt == arg1);
|
|
case 80:
|
|
cret(turncnt > arg1);
|
|
case 81:
|
|
cret(turncnt < arg1);
|
|
case 82:
|
|
cret(cnt_val(agt_counter[arg1]) == arg2);
|
|
case 83:
|
|
cret(cnt_val(agt_counter[arg1]) > arg2);
|
|
case 84:
|
|
cret(cnt_val(agt_counter[arg1]) < arg2);
|
|
|
|
case 85:
|
|
cret(agt_var[arg1] == arg2);
|
|
case 86:
|
|
cret(agt_var[arg1] > arg2);
|
|
case 87:
|
|
cret(agt_var[arg1] < arg2);
|
|
case 88:
|
|
cret(agt_var[arg1] < agt_var[arg2]);
|
|
case 89:
|
|
cret(agt_var[arg1] < get_random(1, arg2));
|
|
case 90:
|
|
cret((actor != 0) && (it_loc(actor) == loc + first_room));
|
|
case 91:
|
|
cret(actor == arg1);
|
|
case 92:
|
|
cret(dobj == arg1);
|
|
case 93:
|
|
cret(do_disambig == 1 || iobj == arg1);
|
|
case 94:
|
|
cret(it_contents(arg1) != 0);
|
|
case 95:
|
|
cret(get_random(1, 100) <= arg1);
|
|
case 96:
|
|
cret(yesno("Yes or no? "));
|
|
case 97:
|
|
cret(!yesno("Yes or no? "));
|
|
case 98:
|
|
cret(vb > 0 && vb <= 13);
|
|
case 99:
|
|
cret(tcreat(dobj));
|
|
case 100:
|
|
cretc(dobj, gender == 2); /* man */
|
|
case 101:
|
|
cretc(dobj, gender == 1); /* woman */
|
|
case 102:
|
|
cretc(dobj, gender == 0); /* thing */
|
|
case 103:
|
|
cretc(iobj, gender == 2);
|
|
case 104:
|
|
cretc(iobj, gender == 1); /* woman */
|
|
case 105:
|
|
cretc(iobj, gender == 0); /* thing */
|
|
case 106:
|
|
cret(do_disambig == 1 || tcreat(iobj));
|
|
case 107:
|
|
return (do_disambig == 1 || obj_cond(0, iobj, 0));
|
|
/* OR and NOT are handled higher up. */
|
|
/* The following are all v1.8x metacommands */
|
|
case 110:
|
|
cret(beforecmd);
|
|
case 111:
|
|
cret(!beforecmd);
|
|
case 112:
|
|
cret(curr_time / 100 == arg1); /* HoursEqual */
|
|
case 113:
|
|
cret(curr_time / 100 > arg1);
|
|
case 114:
|
|
cret(curr_time / 100 < arg1);
|
|
case 115:
|
|
cret(curr_time % 100 == arg1); /* MinutesEqual */
|
|
case 116:
|
|
cret(curr_time % 100 > arg1);
|
|
case 117:
|
|
cret(curr_time % 100 < arg1);
|
|
case 118:
|
|
cret(curr_time < 1200); /* IsAM */
|
|
|
|
case 119:
|
|
cret(do_disambig); /* OnDisambig */
|
|
case 120:
|
|
cretc(arg1, hostile); /* IsHostile */
|
|
case 121: /* HostilePresent */
|
|
creatloop(i)
|
|
if (creature[i].location == loc + first_room &&
|
|
creature[i].hostile) return 1;
|
|
return 0;
|
|
/* Otherwise, we're in trouble. */
|
|
case 122:
|
|
cret(actor_in_scope); /* NameWasPresent */
|
|
case 123: /* OncePerTurn */
|
|
if (beforecmd)
|
|
cret(start_of_turn);
|
|
else
|
|
cret(end_of_turn);
|
|
case 124: /* IsClass */
|
|
cret(arg2 == 0 || matchclass(arg1, arg2));
|
|
case 125:
|
|
cret(getattr(arg1, arg2)); /* IsSet */
|
|
case 126:
|
|
cret(is_numeric(dobj_rec));
|
|
case 127:
|
|
cret(is_numeric(iobj_rec));
|
|
case 128:
|
|
cret(arg1 == arg2);
|
|
case 129:
|
|
cret(arg1 > arg2);
|
|
case 130:
|
|
cret(arg1 < arg2);
|
|
case 131:
|
|
cret(arg1 >= arg2);
|
|
case 132:
|
|
cret(arg1 <= arg2);
|
|
case 133:
|
|
cret(strcmp(userstr[arg1 - 1], userstr[arg2 - 1]) == 0);
|
|
case 134:
|
|
cret(strcmp(userstr[arg1 - 1], userstr[arg2 - 1]) < 0);
|
|
case 135:
|
|
cret(strcmp(userstr[arg1 - 1], userstr[arg2 - 1]) > 0);
|
|
case 136:
|
|
cret(strcasecmp(userstr[arg1 - 1], userstr[arg2 - 1]) == 0);
|
|
case 137:
|
|
cret(strcasecmp(userstr[arg1 - 1], userstr[arg2 - 1]) < 0);
|
|
case 138:
|
|
cret(strcasecmp(userstr[arg1 - 1], userstr[arg2 - 1]) > 0);
|
|
case 139:
|
|
cret(match_answer(rstrdup(userstr[arg1 - 1]), arg2 - 1));
|
|
/* Note that match_answer rfrees it's first argument */
|
|
case 140:
|
|
cret(it_seen(arg1));
|
|
case 141:
|
|
cret(op_objflag(2, arg1, arg2));
|
|
case 142:
|
|
cret(!op_objflag(2, arg1, arg2));
|
|
case 143:
|
|
i = it_room(arg1);
|
|
cret(troom(i) && troom(room[i - first_room].path[arg2 - 1]));
|
|
default:
|
|
writeln("INTERNAL ERROR: Condition token not supported.");
|
|
rprintf("Condition #%d", op_);
|
|
writeln("");
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
#undef cret
|
|
#undef cretn
|
|
#undef cretc
|
|
|
|
|
|
static void obj_act(int op_, int obj) {
|
|
switch (op_) {
|
|
case 0:
|
|
case 1: /* open and close */
|
|
if (tnoun(obj))
|
|
noun[obj - first_noun].open = (op_ == 0);
|
|
break;
|
|
case 2:
|
|
case 3: /* lock and unlock */
|
|
if (tnoun(obj))
|
|
noun[obj - first_noun].locked = (op_ == 2);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
static void exec_action(int op_, int arg1, int arg2) {
|
|
int i, j;
|
|
char *tmpstr;
|
|
|
|
switch (op_) {
|
|
case 1000:
|
|
goto_room(arg1 - first_room);
|
|
break;
|
|
case 1001:
|
|
goto_room(get_random(arg1, arg2) - first_room);
|
|
break;
|
|
case 1002:
|
|
agt_var[arg1] = loc + first_room;
|
|
break;
|
|
case 1003:
|
|
agt_var[arg1] = dobj;
|
|
break;
|
|
case 1004:
|
|
agt_var[arg1] = iobj;
|
|
break;
|
|
case 1005:
|
|
goto_room(agt_var[arg1] - first_room);
|
|
break;
|
|
case 1006:
|
|
it_move(arg1, agt_var[arg2]);
|
|
break;
|
|
case 1007:
|
|
get_obj(agt_var[arg1]);
|
|
break;
|
|
case 1008:
|
|
msgout(agt_var[arg1], 1);
|
|
break;
|
|
case 1009:
|
|
get_obj(arg1);
|
|
break;
|
|
case 1010:
|
|
get_obj(arg1);
|
|
it_move(arg1, 1000);
|
|
break;
|
|
case 1011:
|
|
drop_obj(arg1);
|
|
break;
|
|
case 1012:
|
|
if (it_loc(arg1) == 1000) {
|
|
if (PURE_WEAR) drop_obj(arg1);
|
|
else it_move(arg1, 1);
|
|
}
|
|
break;
|
|
case 1013:
|
|
fontcmd(0, arg1 - 1);
|
|
break; /* Load font */
|
|
case 1014:
|
|
pictcmd(1, pictable[arg1 - 1]);
|
|
break; /* Show picture */
|
|
case 1015:
|
|
changepict(arg1, arg2);
|
|
break; /* ChangePicture */
|
|
case 1016:
|
|
if (PICT_SUPPORT &&
|
|
yesno("Would you like to see the picture?"))
|
|
pictcmd(1, pictable[arg1 - 1]);
|
|
break;
|
|
case 1017:
|
|
pictcmd(2, arg1);
|
|
break; /* Show room pix */
|
|
case 1018:
|
|
if (PICT_SUPPORT &&
|
|
yesno("Would you like to see the picture?"))
|
|
pictcmd(2, arg1 - 1);
|
|
break;
|
|
case 1019:
|
|
musiccmd(1, arg1 - 1);
|
|
break;
|
|
case 1020:
|
|
musiccmd(1, get_random(arg1, arg2) - 1);
|
|
break;
|
|
case 1021:
|
|
musiccmd(2, arg1 - 1);
|
|
break;
|
|
case 1022:
|
|
musiccmd(3, -1);
|
|
break; /* Stop Repeat */
|
|
case 1023:
|
|
musiccmd(4, -1);
|
|
break; /* Stop song */
|
|
case 1024:
|
|
musiccmd(5, -1);
|
|
break; /* Suspend song */
|
|
case 1025:
|
|
musiccmd(6, -1);
|
|
break; /* Resume song */
|
|
case 1026:
|
|
if (tnoun(dobj))
|
|
noun[dobj - first_noun].movable = !noun[dobj - first_noun].movable;
|
|
break;
|
|
case 1027:
|
|
it_newdesc(arg1, &msg_ptr[arg2 - 1]);
|
|
break;
|
|
case 1028:
|
|
if (tnoun(arg1)) noun[arg1 - first_noun].points = arg2;
|
|
else if (tcreat(arg1)) creature[arg1 - first_creat].points = arg2;
|
|
else if (troom(arg1)) room[arg1 - first_room].points = arg2;
|
|
break;
|
|
case 1029:
|
|
it_destroy(iobj);
|
|
break;
|
|
case 1030:
|
|
tmpstr = agt_readline(3);
|
|
i = strlen(tmpstr) - 1;
|
|
if (i > 0 && tmpstr[i] == '\n') tmpstr[i] = 0;
|
|
strncpy(userstr[arg1 - 1], tmpstr, 80);
|
|
rfree(tmpstr);
|
|
break;
|
|
case 1031:
|
|
agt_var[arg1] = read_number();
|
|
break;
|
|
case 1032:
|
|
agt_var[arg1] = curr_time;
|
|
break;
|
|
case 1033:
|
|
curr_time = normalize_time(agt_var[arg1]);
|
|
break;
|
|
case 1034:
|
|
curr_time = normalize_time(arg1);
|
|
break;
|
|
case 1035:
|
|
add_time(arg1);
|
|
break;
|
|
case 1036:
|
|
delta_time = arg1;
|
|
break;
|
|
/* 1037 and 1038 are subroutine commands */
|
|
case 1039:
|
|
get_obj(dobj);
|
|
break;
|
|
case 1040:
|
|
it_move(dobj, 1000);
|
|
break;
|
|
case 1041:
|
|
drop_obj(dobj);
|
|
break;
|
|
case 1042:
|
|
if (it_loc(dobj) == 1000) {
|
|
if (PURE_WEAR) it_move(dobj, 1);
|
|
else drop_obj(dobj);
|
|
}
|
|
break;
|
|
case 1043: /* drop all */
|
|
safecontloop(i, j, 1) drop_obj(i);
|
|
break;
|
|
case 1044: /* remove all */
|
|
safecontloop(i, j, 1000) drop_obj(i);
|
|
break;
|
|
case 1045:
|
|
deadflag = 1;
|
|
break;
|
|
case 1046:
|
|
it_move(arg1, loc + first_room);
|
|
break;
|
|
case 1047:
|
|
it_move(arg1, arg2);
|
|
break;
|
|
case 1048:
|
|
it_reposition(arg1, arg2, 1);
|
|
break; /* RePosition */
|
|
case 1049:
|
|
it_move(dobj, loc + first_room);
|
|
break;
|
|
case 1050:
|
|
it_move(dobj, arg1);
|
|
break;
|
|
case 1051:
|
|
safecontloop(i, j, 1) it_move(i, arg1);
|
|
safecontloop(i, j, 1000) it_move(i, arg1);
|
|
break;
|
|
case 1052:
|
|
nounloop(i)
|
|
if (player_has(i + first_noun) && noun[i].points > arg2)
|
|
it_move(i + first_noun, arg1);
|
|
break;
|
|
case 1053:
|
|
safecontloop(i, j, arg1)
|
|
if (tnoun(i)) it_move(i, arg2);
|
|
break;
|
|
case 1054:
|
|
it_destroy(arg1);
|
|
break;
|
|
case 1055:
|
|
it_destroy(dobj);
|
|
break;
|
|
case 1056:
|
|
i = it_loc(arg1);
|
|
it_move(arg1, it_loc(arg2));
|
|
it_move(arg2, i);
|
|
break;
|
|
case 1057:
|
|
it_move(arg1, it_loc(arg2));
|
|
break;
|
|
case 1058:
|
|
it_move(dobj, it_loc(arg2));
|
|
break;
|
|
case 1059:
|
|
case 1060: /* Add to/remove from group */
|
|
if (tcreat(arg1))
|
|
creature[arg1 - first_creat].groupmemb = (op_ == 1059);
|
|
break;
|
|
case 1061: /* Move group */
|
|
safecontloop(i, j, loc + first_room)
|
|
if (it_group(i)) it_move(i, arg1);
|
|
break;
|
|
/* 1062 is RedirectTo */
|
|
case 1063:
|
|
msgout(get_random(arg1, arg2), 1);
|
|
break;
|
|
case 1064:
|
|
print_contents(arg1, 1);
|
|
break;
|
|
case 1065:
|
|
case 1066:
|
|
case 1067:
|
|
case 1068:
|
|
obj_act(op_ - 1065, arg1);
|
|
break;
|
|
case 1069:
|
|
case 1070:
|
|
case 1071:
|
|
case 1072:
|
|
obj_act(op_ - 1069, dobj);
|
|
break;
|
|
case 1073:
|
|
print_score();
|
|
break;
|
|
case 1074:
|
|
tscore += arg1;
|
|
break;
|
|
case 1075:
|
|
tscore -= arg1;
|
|
break;
|
|
case 1076:
|
|
v_inventory();
|
|
break;
|
|
case 1077:
|
|
wait_return();
|
|
break;
|
|
case 1078:
|
|
writeln("Time passes...");
|
|
break;
|
|
case 1079:
|
|
agt_delay(arg1);
|
|
break;
|
|
case 1080:
|
|
agt_clrscr();
|
|
break;
|
|
case 1081:
|
|
it_describe(arg1);
|
|
break;
|
|
case 1082:
|
|
look_room();
|
|
break; /* LOOK */
|
|
case 1083:
|
|
msgout(arg1, 1);
|
|
break;
|
|
case 1084:
|
|
writeln("");
|
|
break;
|
|
case 1085:
|
|
if (PURE_TONE && sound_on)
|
|
agt_tone(arg1, arg2);
|
|
break; /* Tone */
|
|
case 1086:
|
|
agt_number = ask_for_number(arg1, arg2);
|
|
break;
|
|
case 1087:
|
|
agt_answer = ask_question(arg1);
|
|
break;
|
|
case 1088:
|
|
change_passage(loc, arg1, arg2);
|
|
break;
|
|
case 1089:
|
|
flag[arg1] = 1;
|
|
break;
|
|
case 1090:
|
|
flag[arg1] = 0;
|
|
break;
|
|
case 1091:
|
|
flag[arg1] = !flag[arg1];
|
|
break;
|
|
case 1092:
|
|
room[loc].flag_noun_bits |= (1 << (arg1 - 1));
|
|
break; /* Roomflag on */
|
|
case 1093:
|
|
room[loc].flag_noun_bits &= ~(1 << (arg1 - 1));
|
|
break; /* Off */
|
|
case 1094:
|
|
room[loc].flag_noun_bits ^= (1 << (arg1 - 1));
|
|
break; /* Toggle */
|
|
case 1095: /* if (agt_counter[arg1]==-1)*/
|
|
agt_counter[arg1] = 1;
|
|
break;
|
|
case 1096:
|
|
agt_counter[arg1] = -1;
|
|
break;
|
|
case 1097:
|
|
agt_var[arg1] = arg2;
|
|
break;
|
|
case 1098:
|
|
agt_var[arg1] += arg2;
|
|
break;
|
|
case 1099:
|
|
agt_var[arg1] -= arg2;
|
|
break;
|
|
case 1100:
|
|
agt_var[arg1] += agt_var[arg2];
|
|
break;
|
|
case 1101:
|
|
agt_var[arg1] -= agt_var[arg2];
|
|
break;
|
|
case 1102:
|
|
agt_var[arg1] = get_random(0, arg2);
|
|
break;
|
|
case 1103:
|
|
agt_var[arg1] = dobj_rec->num;
|
|
break;
|
|
case 1104:
|
|
agt_var[arg1] = iobj_rec->num;
|
|
break;
|
|
|
|
/* The following are v1.8x specific */
|
|
case 1105:
|
|
quote(arg1);
|
|
break;
|
|
case 1106:
|
|
add_time(arg1);
|
|
break;
|
|
case 1107:
|
|
add_time(-arg1);
|
|
break;
|
|
case 1108:
|
|
curr_time = (curr_time % 100) + 100 * arg1;
|
|
break;
|
|
case 1109:
|
|
curr_time = (curr_time / 100) * 100 + arg1;
|
|
break;
|
|
case 1110:
|
|
add_time(agt_var[arg1]);
|
|
break;
|
|
case 1111:
|
|
add_time(-agt_var[arg1]);
|
|
break;
|
|
case 1112:
|
|
curr_time = (curr_time % 100) + 100 * agt_var[arg1];
|
|
break;
|
|
case 1113:
|
|
curr_time = (curr_time / 100) * 100 + agt_var[arg1];
|
|
break;
|
|
|
|
/* Now for the AGX additions */
|
|
case 1114:
|
|
add_time(-arg1);
|
|
break; /* ME-style SubtractFromTime */
|
|
case 1115:
|
|
disambig_score = arg1;
|
|
break; /* SetDisambigPriority */
|
|
case 1116:
|
|
agt_var[arg1] = delta_time;
|
|
break;
|
|
case 1117: /* ChangeStatus */
|
|
statusmode = arg1;
|
|
break;
|
|
case 1118:
|
|
if (!mult_rangecheck(agt_var[arg1], arg2)) break;
|
|
agt_var[arg1] *= arg2;
|
|
break;
|
|
case 1119:
|
|
if (arg2 == 0) {
|
|
if (!PURE_ERROR)
|
|
writeln("GAME ERROR: Division by zero.");
|
|
} else agt_var[arg1] /= arg2;
|
|
break;
|
|
case 1120:
|
|
if (arg2 == 0) {
|
|
if (!PURE_ERROR)
|
|
writeln("GAME ERROR: Attempt to divide by zero.");
|
|
} else agt_var[arg1] %= arg2;
|
|
break;
|
|
case 1121:
|
|
agt_waitkey();
|
|
break;
|
|
case 1122:
|
|
last_he = arg1;
|
|
break; /* SetHE */
|
|
case 1123:
|
|
last_she = arg1;
|
|
break;
|
|
case 1124:
|
|
last_it = arg1;
|
|
break;
|
|
case 1125:
|
|
last_they = arg1;
|
|
break;
|
|
case 1126:
|
|
msgout(arg1, 0);
|
|
break;
|
|
case 1127:
|
|
if (!PURE_ERROR)
|
|
sysmsg(arg1, "GAME ERROR: Standard message not defined.");
|
|
break;
|
|
case 1128:
|
|
msgout(arg1, 1);
|
|
break; /* FailMessage */
|
|
case 1129: /* StdMessage */
|
|
sysmsg(arg1, "GAME ERROR: Standard message not defined.");
|
|
break;
|
|
case 1130:
|
|
msgout(arg2, 1);
|
|
break; /* ErrMessage */
|
|
case 1131: /* StdErrMessage */
|
|
sysmsg(arg1, "GAME ERROR: Standard message not defined.");
|
|
break;
|
|
case 1132: /* AND */
|
|
break; /* These don't do anything under normal circumstances */
|
|
case 1133: /* SetClass */
|
|
if (troom(arg1)) room[arg1 - first_room].oclass = arg2;
|
|
else if (tnoun(arg1)) noun[arg1 - first_noun].oclass = arg2;
|
|
else if (tcreat(arg1)) noun[arg1 - first_creat].oclass = arg2;
|
|
break;
|
|
case 1134:
|
|
agt_var[arg1] = it_class(arg2);
|
|
break; /* SetVariableToClass */
|
|
|
|
/* Stack commands */
|
|
case 1135:
|
|
push_stack(arg1);
|
|
break;
|
|
case 1136:
|
|
agt_var[arg1] = pop_stack();
|
|
break;
|
|
case 1137:
|
|
case 1138:
|
|
case 1139:
|
|
case 1140:
|
|
case 1141:
|
|
op_stack(op_ - 1137); /* +,-,*, /,% * */
|
|
break;
|
|
case 1142: { /* DupStack */
|
|
long n;
|
|
n = pop_stack();
|
|
push_stack(n);
|
|
push_stack(n);
|
|
break;
|
|
}
|
|
case 1143:
|
|
pop_stack();
|
|
break; /* Discard TOS */
|
|
case 1144:
|
|
agt_var[arg1] = agt_number;
|
|
break; /* SetVariableToInput */
|
|
case 1145:
|
|
setattr(arg1, arg2, 1);
|
|
break; /* Set */
|
|
case 1146:
|
|
setattr(arg1, arg2, 0);
|
|
break; /* Clear */
|
|
case 1147:
|
|
push_stack(getprop(arg1, arg2));
|
|
break; /* PushProp */
|
|
case 1148:
|
|
setprop(arg1, arg2, pop_stack());
|
|
break; /* PopProp */
|
|
/* 1149, 1150 handled by run_metacommand */
|
|
/* 1151 is EndDisambig */
|
|
/* 1152 is XRedirect */
|
|
case 1153:
|
|
rstrncpy(userstr[arg1 - 1], userstr[arg2 - 1], 81);
|
|
break;
|
|
case 1154:
|
|
setcase(userstr[arg1 - 1], 1);
|
|
break;
|
|
case 1155:
|
|
setcase(userstr[arg1 - 1], 0);
|
|
break;
|
|
case 1156:
|
|
op_objflag(1, arg1, arg2);
|
|
break;
|
|
case 1157:
|
|
op_objflag(0, arg1, arg2);
|
|
break;
|
|
case 1158:
|
|
op_objflag(3, arg1, arg2);
|
|
break;
|
|
case 1159:
|
|
push_stack(op_objprop(2, arg1, arg2, 0));
|
|
break;
|
|
case 1160:
|
|
op_objprop(1, arg1, arg2, pop_stack());
|
|
break;
|
|
case 1161:
|
|
move_in_dir(arg1, arg2);
|
|
break;
|
|
default:
|
|
writeln("INTERNAL ERROR: Action token not supported.");
|
|
rprintf("Action #%d", op_);
|
|
writeln("");
|
|
}
|
|
}
|
|
|
|
int exec_instr(op_rec *oprec)
|
|
/* This routine is responsible for executing all conditions and action
|
|
tokens. Remember action tokens are numbered from 1000. */
|
|
/* Return codes:
|
|
0 to continue running commands
|
|
1 for a failed conditional token
|
|
100 Next metacommand
|
|
101 Stop running metacommands
|
|
102 End turn
|
|
103 Redirection */
|
|
{
|
|
rbool r;
|
|
|
|
if (oprec->op < 1000) {
|
|
r = exec_cond(oprec->op, oprec->arg1, oprec->arg2);
|
|
return (oprec->negate ? r : !r); /* Is it prefixed by NOT? */
|
|
}
|
|
switch (oprec->op) {
|
|
case 1151: /* EndDisambig <num> */
|
|
if (do_disambig) {
|
|
disambig_score = oprec->arg1;
|
|
return 102; /* "End turn" if disambiguating */
|
|
}
|
|
return 0; /* ... otherwise do nothing */
|
|
case 1062:
|
|
case 1152:
|
|
return 103; /* Redirect */
|
|
case WIN_ACT:
|
|
winflag = 1;
|
|
return 0; /* win game */
|
|
case (WIN_ACT+1):
|
|
endflag = 1;
|
|
return 102; /* end game */
|
|
case (WIN_ACT+2):
|
|
return 100; /* end this command */
|
|
case (WIN_ACT+3):
|
|
return 101; /* end all commands */
|
|
case (WIN_ACT+4):
|
|
return 102; /* end turn */
|
|
default:
|
|
exec_action(oprec->op, oprec->arg1, oprec->arg2);
|
|
if (oprec->failmsg) return 102;
|
|
else return 0;
|
|
}
|
|
}
|
|
|
|
static unsigned int rand_gen = 1234;
|
|
|
|
void reset_random(void) {
|
|
rand_gen = 1234;
|
|
}
|
|
|
|
int get_random(int a, int b) {
|
|
if (stable_random) {
|
|
rand_gen = rand_gen * 214013 + 2531011;
|
|
unsigned int rand_num = (rand_gen >> 16) & 0xFFFF;
|
|
return a + (rand_num % (b - a + 1));
|
|
} else
|
|
return agt_rand(a,b);
|
|
}
|
|
|
|
} // End of namespace AGT
|
|
} // End of namespace Glk
|