scummvm/engines/glk/agt/token.cpp
2022-10-23 22:46:19 +02:00

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