mirror of
https://github.com/ganelson/inform.git
synced 2024-07-16 22:14:23 +03:00
1313 lines
34 KiB
C
Executable file
1313 lines
34 KiB
C
Executable file
! PunyInform: A small stdlib and parser for interactive fiction
|
|
! suitable for old-school computers such as the Commodore 64.
|
|
! Designed to be similar, but not identical, to the Inform 6 library.
|
|
!
|
|
! Reference documentation
|
|
! DM: http://www.inform-fiction.org/manual/html/dm4index.html
|
|
! Tech: https://www.inform-fiction.org/source/tm/TechMan.txt
|
|
! Z-machine: https://www.inform-fiction.org/zmachine/standards/z1point1
|
|
!
|
|
! Public routines (described in DM, available for a game developer)
|
|
! LIBRARY ROUTINES:
|
|
! - CommonAncestor
|
|
! - DrawStatusLine
|
|
! - IndirectlyContains
|
|
! - InScope
|
|
! - LoopOverScope
|
|
! - NextWord
|
|
! - NextWordStopped
|
|
! - NumberWord
|
|
! - ObjectIsUntouchable
|
|
! - PlayerTo
|
|
! - ParseToken
|
|
! - PlaceInScope
|
|
! - PronounNotice
|
|
! - ScopeWithin
|
|
! - SetTime
|
|
! - TestScope
|
|
! - TryNumber
|
|
! - WordAddress
|
|
! - WordLength
|
|
! - YesOrNo
|
|
! OTHERS:
|
|
! - PrintOrRun
|
|
! - RunRoutines
|
|
! PRINT UTILITIES:
|
|
! - CTheyreorThats
|
|
! - ItorThem
|
|
! - IsOrAre
|
|
! PUNYINFORM ONLY:
|
|
! - OnOff
|
|
! - ObjectIsInvisible
|
|
! - PrintMsg
|
|
! - RunTimeError
|
|
|
|
! comment/uncomment to restrict default debug messages behaviour
|
|
! (all can be overridden by adding them in the game source)
|
|
!Constant DEBUG_SCOPE;
|
|
!Constant DEBUG_CHECKNOUN;
|
|
!Constant DEBUG_GETNEXTNOUN;
|
|
!Constant DEBUG_PARSETOKEN;
|
|
!Constant DEBUG_PARSEPATTERN;
|
|
!Constant DEBUG_PARSEANDPERFORM;
|
|
|
|
System_file;
|
|
|
|
Include "messages.h";
|
|
|
|
|
|
! ######################### Include utility files
|
|
|
|
Include "scope.h";
|
|
Include "grammar.h";
|
|
|
|
! ######################### Helper routines
|
|
[ UnsignedCompare p_x p_y _u _v;
|
|
if (p_x == p_y) return 0;
|
|
if (p_x < 0 && p_y >= 0) return 1;
|
|
if (p_x >= 0 && p_y < 0) return -1;
|
|
_u = p_x&~WORD_HIGHBIT; _v = p_y&~WORD_HIGHBIT;
|
|
if (_u > _v) return 1;
|
|
return -1;
|
|
];
|
|
|
|
[ IndirectlyContains p_o1 p_o2;
|
|
! Does o1 indirectly contain o2? (Same as testing if o1 is one of the ancestors of o2.)
|
|
while (p_o2 ~= 0) {
|
|
if (p_o1 == p_o2) rtrue;
|
|
! if (p_o2 ofclass Class) rfalse;
|
|
p_o2 = parent(p_o2);
|
|
}
|
|
rfalse;
|
|
];
|
|
|
|
[ CommonAncestor p_o1 p_o2 _i _j;
|
|
! Find the nearest object indirectly containing o1 and o2,
|
|
! or return 0 if there is no common ancestor.
|
|
_i = p_o1;
|
|
while (_i) {
|
|
_j = p_o2;
|
|
while (_j) {
|
|
if (_j == _i) return _i;
|
|
_j = parent(_j);
|
|
}
|
|
_i = parent(_i);
|
|
}
|
|
return 0;
|
|
];
|
|
|
|
[ SetTime p_time p_step;
|
|
the_time = p_time;
|
|
time_rate = p_step;
|
|
time_step = 0;
|
|
if(p_step < 0) time_step = -p_step;
|
|
];
|
|
|
|
#IfV5;
|
|
|
|
Array cursor_pos --> 2;
|
|
|
|
[ _StatusLineHeight p_height;
|
|
if (statusline_current_height ~= p_height) {
|
|
@split_window p_height;
|
|
statusline_current_height = p_height;
|
|
}
|
|
];
|
|
|
|
|
|
[ _MoveCursor line column; ! 1-based postion on text grid
|
|
if (~~statuswin_current) {
|
|
@set_window 1;
|
|
if (clr_on && clr_bgstatus > 1) {
|
|
@set_colour clr_fgstatus clr_bgstatus;
|
|
} else {
|
|
style reverse;
|
|
}
|
|
}
|
|
if (line == 0) {
|
|
line = 1;
|
|
column = 1;
|
|
}
|
|
@set_cursor line column;
|
|
statuswin_current = true;
|
|
];
|
|
|
|
[ _MainWindow;
|
|
if (statuswin_current) {
|
|
if (clr_on && clr_bgstatus > 1) {
|
|
@set_colour clr_fg clr_bg;
|
|
} else {
|
|
style roman;
|
|
}
|
|
@set_window 0;
|
|
}
|
|
statuswin_current = false;
|
|
];
|
|
|
|
|
|
Array TenSpaces -> " ";
|
|
|
|
[ _PrintSpacesOrMoveBack p_col p_string _current_col;
|
|
p_col = (HDR_SCREENWCHARS->0) - p_col;
|
|
|
|
@get_cursor cursor_pos;
|
|
_current_col = cursor_pos --> 1;
|
|
|
|
if(_current_col > p_col || cursor_pos --> 0 > 1) {
|
|
_MoveCursor(1, p_col);
|
|
rtrue;
|
|
}
|
|
|
|
p_col = p_col - _current_col;
|
|
while(p_col > 10) {
|
|
@print_table TenSpaces 10;
|
|
p_col = p_col - 10;
|
|
}
|
|
@print_table TenSpaces p_col;
|
|
if(p_string)
|
|
print (string) p_string;
|
|
];
|
|
|
|
Constant ONE_SPACE_STRING = " ";
|
|
|
|
[ DrawStatusLine _width _visibility_ceiling _h _pm;
|
|
! For wide screens (67+ columns):
|
|
! * print a space before room name, and "Score: xxx Moves: xxxx" to the right.
|
|
! * Room names up to 39 characters are never truncated.
|
|
! For narrow screens:
|
|
! * No space before room name
|
|
! * Print "Score: xxx/yyyy", "xxx/yyyy", "xxx" or nothing, depending on screen width
|
|
! * Room names up to 21 characters are never truncated. On a 40 column screen, room names up to 24 characters are never truncated.
|
|
|
|
! If there is no player location, we shouldn't try to draw status window
|
|
if (location == nothing || parent(player) == nothing)
|
|
return;
|
|
|
|
_width = HDR_SCREENWCHARS->0;
|
|
|
|
_StatusLineHeight(statusline_height);
|
|
_MoveCursor(1, 1); ! This also sets the upper window as active.
|
|
if(_width > 66) @print_char ' ';
|
|
|
|
! _MoveCursor(1, 2);
|
|
! if (location == thedark) {
|
|
! print (name) location;
|
|
! }
|
|
! else {
|
|
! FindVisibilityLevels();
|
|
! if (visibility_ceiling == location)
|
|
_visibility_ceiling = ScopeCeiling(player);
|
|
! print (object) _visibility_ceiling;
|
|
if (location == thedark || _visibility_ceiling == location)
|
|
_PrintObjName(location); ! If it's light, location == real_location
|
|
else
|
|
print (The) _visibility_ceiling;
|
|
|
|
if (sys_statusline_flag) {
|
|
! Statusline should show time rather than score
|
|
if (_width > 29) {
|
|
if (_width > 39) {
|
|
if (_width > 66) {
|
|
! Width is 67-, print "Time: 12:34 pm" with some space to the right
|
|
_PrintSpacesOrMoveBack(20, TIME__TX);
|
|
} else {
|
|
! Width is 40-66, print "Time: 12:34 pm" at right edge
|
|
_PrintSpacesOrMoveBack(15, TIME__TX);
|
|
}
|
|
} else {
|
|
! Width is 30-, print "12:34 pm" at right edge
|
|
_PrintSpacesOrMoveBack(9, ONE_SPACE_STRING);
|
|
}
|
|
_h = status_field_1;
|
|
if (_h > 11) {
|
|
_pm = true;
|
|
}
|
|
if (_h > 12) {
|
|
_h = _h - 12;
|
|
}
|
|
! if (_h<10)
|
|
! @print_char ' ';
|
|
print _h;
|
|
@print_char ':';
|
|
if (status_field_2<10)
|
|
@print_char '0';
|
|
print status_field_2;
|
|
if (_pm)
|
|
print " pm";
|
|
else
|
|
print " am";
|
|
}
|
|
} else {
|
|
! Statusline should show score rather than time
|
|
if (_width > 24) {
|
|
if (_width < 30) {
|
|
! Width is 25-29, only print score as "0", no moves
|
|
_PrintSpacesOrMoveBack(3, ONE_SPACE_STRING);
|
|
print status_field_1;
|
|
} else {
|
|
if (_width > 66) {
|
|
! Width is 67-, print "Score: 0 Moves: 0"
|
|
_PrintSpacesOrMoveBack(28, SCORE__TX);
|
|
print status_field_1;
|
|
_PrintSpacesOrMoveBack(14, MOVES__TX);
|
|
} else {
|
|
if (_width > 36) {
|
|
! Width is 37-66, print "Score: 0/0"
|
|
_PrintSpacesOrMoveBack(15, SCORE__TX);
|
|
} else {
|
|
! Width is 29-35, print "0/0"
|
|
_PrintSpacesOrMoveBack(9, ONE_SPACE_STRING);
|
|
}
|
|
print status_field_1;
|
|
@print_char '/';
|
|
}
|
|
print status_field_2;
|
|
}
|
|
}
|
|
}
|
|
! Regardless of what kind of status line we have printed, print spaces to the end.
|
|
_PrintSpacesOrMoveBack(-1);
|
|
_MainWindow(); ! set_window
|
|
];
|
|
#EndIf;
|
|
|
|
[ _AtFullCapacity p_s _obj _k;
|
|
if (p_s == player) {
|
|
objectloop (_obj in p_s)
|
|
if (_obj hasnt worn) _k++;
|
|
} else
|
|
_k = children(p_s);
|
|
#IfDef SACK_OBJECT;
|
|
if (_k < RunRoutines(p_s, capacity) || (p_s == player && _RoomInSack())) rfalse;
|
|
#IfNot;
|
|
if (_k < RunRoutines(p_s, capacity)) rfalse;
|
|
#EndIf;
|
|
];
|
|
|
|
#IfDef SACK_OBJECT;
|
|
[ _RoomInSack _obj _ks;
|
|
if (SACK_OBJECT in player) {
|
|
for (_obj=youngest(player) : _obj : _obj=elder(_obj))
|
|
if (_obj ~= SACK_OBJECT && _obj hasnt worn or light) {
|
|
_ks = keep_silent;
|
|
keep_silent = 1;
|
|
<Insert _obj SACK_OBJECT>;
|
|
keep_silent = _ks;
|
|
if (_obj in SACK_OBJECT) {
|
|
if (keep_silent == 0) PrintMsg(MSG_SACK_PUTTING, _obj);
|
|
rtrue;
|
|
}
|
|
}
|
|
}
|
|
rfalse;
|
|
];
|
|
#EndIf;
|
|
|
|
[ PrintShortName o;
|
|
if (o == 0) { print "nothing"; rtrue; }
|
|
switch (metaclass(o)) {
|
|
Routine: print "<routine ", o, ">"; rtrue;
|
|
String: print "<string ~", (string) o, "~>"; rtrue;
|
|
nothing: print "<illegal object number ", o, ">"; rtrue;
|
|
}
|
|
if (o.short_name ~= 0 && PrintOrRun(o, short_name, true) ~= 0) rtrue;
|
|
print (object) o;
|
|
];
|
|
|
|
[ _PrintObjName p_obj p_form;
|
|
if(p_obj hasnt proper) {
|
|
if(p_form == FORM_CDEF) {
|
|
print "The ";
|
|
} else if(p_form == FORM_DEF) {
|
|
print "the ";
|
|
} else if(p_form == FORM_INDEF) {
|
|
if(p_obj.&article) {
|
|
PrintOrRun(p_obj, article, true);
|
|
print " ";
|
|
}
|
|
else if(p_obj has pluralname)
|
|
print "some ";
|
|
else
|
|
print "a ";
|
|
}
|
|
! print " "; ! not ok, adds space in room name
|
|
}
|
|
PrintShortName(p_obj);
|
|
];
|
|
|
|
[ _PrintAfterEntry p_obj;
|
|
if(p_obj has container && P_obj hasnt open) print " (which is closed)";
|
|
if(p_obj has container && (p_obj has open || p_obj has transparent)) {
|
|
if(child(p_obj) == nothing)
|
|
print " (which is empty)";
|
|
else
|
|
if(PrintContents(" (which contains ", p_obj)) print ")";
|
|
}
|
|
if(p_obj has supporter && child(p_obj) ~= nothing) {
|
|
if(PrintContents(" (on which is ", p_obj)) print ")";
|
|
}
|
|
! if(p_obj has light && action == ##Inv) print " (providing light)";
|
|
if(p_obj has light) print " (providing light)";
|
|
if(p_obj has worn && action == ##Inv) print " (worn)";
|
|
];
|
|
|
|
[ PrintContents p_first_text p_obj p_check_workflag _obj _printed_first_text _printed_any_objects _last_obj;
|
|
! print "Objectlooping...^";
|
|
objectloop(_obj in p_obj) {
|
|
! print "Considering ", (object) _obj, "...^";
|
|
! if(_obj has concealed) print "Is concealed."; else print "Isnt concealed.";
|
|
if(_obj hasnt concealed && _obj hasnt scenery &&
|
|
_obj ~= parent(player) && ! don't print container when player in it
|
|
(p_check_workflag == false || _obj has workflag)) {
|
|
! (_obj.&describe == 0 || _obj notin parent(player)) &&
|
|
! (_obj has moved || _obj.initial == 0 || _obj notin parent(player))) {
|
|
if(_printed_first_text == 0) {
|
|
if(p_first_text ofclass String)
|
|
print (string) p_first_text;
|
|
else if(p_first_text ~= 0)
|
|
p_first_text(p_obj);
|
|
_printed_first_text = 1;
|
|
}
|
|
! Push obj onto queue, printing the object that is shifted out, if any
|
|
if(_last_obj) {
|
|
if(_printed_any_objects) print ", ";
|
|
_PrintContentsPrintAnObj(_last_obj);
|
|
_printed_any_objects = 1;
|
|
}
|
|
_last_obj = _obj;
|
|
}
|
|
}
|
|
if(_last_obj) {
|
|
if(_printed_any_objects) print " and ";
|
|
_PrintContentsPrintAnObj(_last_obj);
|
|
}
|
|
|
|
return _printed_first_text;
|
|
];
|
|
|
|
[ _PrintContentsPrintAnObj p_obj _inv _skip;
|
|
if(p_obj.invent ~= 0) {
|
|
_inv = true;
|
|
inventory_stage = 1;
|
|
_skip = PrintOrRun(p_obj, invent, true);
|
|
}
|
|
if(_skip == false) {
|
|
_PrintObjName(p_obj, FORM_INDEF);
|
|
if(_inv) {
|
|
inventory_stage = 2;
|
|
if(PrintOrRun(p_obj, invent, true)) rtrue;
|
|
}
|
|
_PrintAfterEntry(p_obj);
|
|
}
|
|
];
|
|
[ RunRoutines p_obj p_prop p_switch;
|
|
if(p_switch == 0) sw__var = action; else sw__var = p_switch;
|
|
if (p_obj.&p_prop == 0 && p_prop >= INDIV_PROP_START) rfalse;
|
|
return p_obj.p_prop();
|
|
];
|
|
|
|
|
|
[ PrintOrRun p_obj p_prop p_no_string_newline _val;
|
|
_val = p_obj.p_prop;
|
|
if (p_obj.#p_prop > WORDSIZE || _val ofclass Routine) return RunRoutines(p_obj, p_prop);
|
|
if(_val ofclass String) {
|
|
print (string) p_obj.p_prop;
|
|
if(p_no_string_newline == 0) @new_line;
|
|
}
|
|
];
|
|
|
|
[ _InitFloatingObjects _i _k _stop;
|
|
_stop = top_object + 1;
|
|
for(_i = Directions : _i < _stop : _i++) {
|
|
if(_i.&found_in) {
|
|
#IfTrue RUNTIME_ERRORS > RTE_MINIMUM;
|
|
if(_k >= MAX_FLOATING_OBJECTS) {
|
|
RunTimeError(ERR_TOO_MANY_FLOATING);
|
|
rtrue;
|
|
}
|
|
#EndIf;
|
|
floating_objects-->(_k++) = _i;
|
|
}
|
|
}
|
|
];
|
|
|
|
[ MoveFloatingObjects _i _j _len _obj _present;
|
|
while((_obj = floating_objects-->_i) ~= 0 && _obj hasnt absent) {
|
|
_len = _obj.#found_in;
|
|
if(_len == 2 && UnsignedCompare(_obj.found_in, top_object) > 0) {
|
|
_present = RunRoutines(_obj, found_in);
|
|
} else {
|
|
_present = 0;
|
|
_j = _obj.&found_in;
|
|
#IfV5;
|
|
@log_shift _len (-1) -> _len;
|
|
@scan_table real_location _j _len -> _present ?~no_success; ! The position is only a throw-away value here.
|
|
_present = 1;
|
|
.no_success;
|
|
#IfNot;
|
|
_len = _len / 2;
|
|
_len = _len - 1;
|
|
.next_value;
|
|
if(_j-->_len == real_location) {
|
|
_present = 1;
|
|
jump after_loop;
|
|
}
|
|
@dec_chk _len 0 ?~next_value;
|
|
.after_loop;
|
|
#EndIf;
|
|
|
|
}
|
|
if(_present)
|
|
move _obj to real_location;
|
|
else
|
|
remove _obj;
|
|
_i++;
|
|
}
|
|
];
|
|
|
|
[ PlayerTo p_loc p_flag _old_loc _old_real_loc _old_lookmode _old_parent _vc _old_vc;
|
|
! print "PlayerTo, moving player to ", (the) p_loc, ".^";
|
|
_old_loc = location;
|
|
_old_real_loc = real_location;
|
|
move Player to p_loc;
|
|
real_location = superparent(p_loc);
|
|
location = real_location;
|
|
scope_modified = true;
|
|
MoveFloatingObjects();
|
|
_UpdateDarkness();
|
|
.recheck_vc;
|
|
_old_vc = visibility_ceiling;
|
|
if(location == thedark)
|
|
_vc = thedark;
|
|
else {
|
|
_vc = ScopeCeiling(player);
|
|
}
|
|
if(_vc == location)
|
|
visibility_ceiling = _vc;
|
|
|
|
if(visibility_ceiling == location && visibility_ceiling ~= _old_vc) {
|
|
if(location provides initial) {
|
|
_old_parent = parent(player);
|
|
location.initial();
|
|
if(parent(player) ~= _old_parent)
|
|
jump recheck_vc;
|
|
}
|
|
if(location ~= thedark)
|
|
NewRoom();
|
|
}
|
|
|
|
if(_old_real_loc ~= real_location && location == thedark && _old_loc == thedark) {
|
|
! we have moved between dark rooms
|
|
! give entry point a chance to react
|
|
DarkToDark();
|
|
}
|
|
_old_lookmode = lookmode;
|
|
if(p_flag==false)
|
|
lookmode = 2;
|
|
if(p_flag==false or 2 && deadflag == GS_PLAYING)
|
|
<Look>;
|
|
lookmode = _old_lookmode;
|
|
];
|
|
|
|
[ Superparent p_obj _parent;
|
|
while(true) {
|
|
_parent = parent(p_obj);
|
|
if(_parent == 0)
|
|
return p_obj;
|
|
p_obj = _parent;
|
|
}
|
|
];
|
|
|
|
[ _UpdateDarkness p_look _ceil _old_darkness _darkness;
|
|
if(location == thedark) _old_darkness = true;
|
|
_ceil = ScopeCeiling(player);
|
|
_darkness = ~~_LookForLightInObj(_ceil, _ceil);
|
|
if(_darkness) {
|
|
location = thedark;
|
|
} else {
|
|
location = real_location;
|
|
if(_old_darkness == true && p_look == true)
|
|
<Look>;
|
|
}
|
|
];
|
|
|
|
[ _LookForLightInObj p_obj p_ceiling _o;
|
|
! print "_LookForLightInObj, Examining: ", (the) p_obj, "^";
|
|
if(p_obj has light) rtrue;
|
|
if(p_obj == p_ceiling || p_obj has transparent || p_obj has supporter || (p_obj has container && p_obj has open))
|
|
objectloop(_o in p_obj)
|
|
if(_LookForLightInObj(_o))
|
|
rtrue;
|
|
rfalse;
|
|
];
|
|
|
|
Include "parser.h";
|
|
|
|
[ ActionPrimitive; indirect(#actions_table-->action); ];
|
|
|
|
[ PerformPreparedAction;
|
|
#IfDef DEBUG;
|
|
if(debug_flag & 2) TraceAction(action, noun, second);
|
|
#EndIf;
|
|
if ((BeforeRoutines() == false) && action < 4096) {
|
|
ActionPrimitive();
|
|
return true; ! could run the command
|
|
}
|
|
return false; ! failed to run (stopped by BeforeRoutines)
|
|
];
|
|
|
|
[ RunEachTurn _i _obj _scope_count;
|
|
! Loop over the scope to find possible react_before routines
|
|
! to run in each object, if it's found stop the action by returning true
|
|
#IfDef DEBUG;
|
|
if(debug_flag & 1 && location.&each_turn ~= 0) print "(", (name) location, ").each_turn()^";
|
|
#EndIf;
|
|
#Ifndef OPTIONAL_MANUAL_SCOPE;
|
|
scope_modified = true;
|
|
#EndIf;
|
|
_scope_count = GetScopeCopy();
|
|
RunRoutines(location, each_turn);
|
|
for(_i = 0: _i < _scope_count: _i++) {
|
|
_obj = scope_copy-->_i;
|
|
if(_obj.&each_turn ~= 0) {
|
|
#IfDef DEBUG;
|
|
if(debug_flag & 1) print "(", (name) _obj, ").each_turn()^";
|
|
#EndIf;
|
|
#Ifndef OPTIONAL_MANUAL_SCOPE;
|
|
! Assume that every each_turn routine may have modified the scope
|
|
scope_modified = true;
|
|
#EndIf;
|
|
RunRoutines(_obj, each_turn);
|
|
}
|
|
}
|
|
];
|
|
|
|
[ BeforeRoutines _i _obj _scope_count;
|
|
! react_before - Loops over the scope to find possible react_before routines
|
|
! to run in each object, if it's found stop the action by returning true
|
|
#IfnDef OPTIONAL_MANUAL_SCOPE;
|
|
scope_modified = true;
|
|
#EndIf;
|
|
_scope_count = GetScopeCopy();
|
|
#IfDef GamePreRoutine;
|
|
#IfDef DEBUG;
|
|
if(debug_flag & 1) print "GamePreRoutine()^";
|
|
#EndIf;
|
|
if(GamePreRoutine()) rtrue;
|
|
#EndIf;
|
|
|
|
#IfDef DEBUG;
|
|
if(debug_flag & 1) print "player.orders()^";
|
|
#EndIf;
|
|
#Ifndef OPTIONAL_MANUAL_SCOPE;
|
|
! Assume that every routine may modify the scope
|
|
scope_modified = true;
|
|
#EndIf;
|
|
if(RunRoutines(player, orders)) rtrue;
|
|
|
|
for(_i = 0: _i < _scope_count: _i++) {
|
|
_obj = scope_copy-->_i;
|
|
if (_obj provides react_before) {
|
|
#IfDef DEBUG;
|
|
if(debug_flag & 1) print "(", (name) _obj, ").react_before()^";
|
|
#EndIf;
|
|
#Ifndef OPTIONAL_MANUAL_SCOPE;
|
|
! Assume that every routine may modify the scope
|
|
scope_modified = true;
|
|
#EndIf;
|
|
if(RunRoutines(_obj, react_before)) {
|
|
rtrue;
|
|
}
|
|
}
|
|
}
|
|
#IfDef DEBUG;
|
|
if(debug_flag & 1) print "(", (name) location, ").before()^";
|
|
#EndIf;
|
|
if(location provides before) {
|
|
#Ifndef OPTIONAL_MANUAL_SCOPE;
|
|
! Assume that every routine may modify the scope
|
|
scope_modified = true;
|
|
#EndIf;
|
|
if(RunRoutines(location, before)) rtrue;
|
|
}
|
|
if(inp1 > 1) {
|
|
#IfDef DEBUG;
|
|
if(debug_flag & 1) print "(", (name) inp1, ").before()^";
|
|
#EndIf;
|
|
if(inp1 provides before) {
|
|
#Ifndef OPTIONAL_MANUAL_SCOPE;
|
|
! Assume that every routine may modify the scope
|
|
scope_modified = true;
|
|
#EndIf;
|
|
if(RunRoutines(inp1, before)) rtrue;
|
|
}
|
|
}
|
|
rfalse;
|
|
];
|
|
|
|
[ AfterRoutines _i _obj _scope_count;
|
|
! react_after - Loops over the scope to find possible react_before routines
|
|
! to run in each object, if it's found stop the action by returning true
|
|
#IfnDef OPTIONAL_MANUAL_SCOPE;
|
|
scope_modified = true;
|
|
#EndIf;
|
|
_scope_count = GetScopeCopy();
|
|
|
|
for(_i = 0: _i < _scope_count: _i++) {
|
|
_obj = scope_copy-->_i;
|
|
if (_obj provides react_after) {
|
|
#IfDef DEBUG;
|
|
if(debug_flag & 1) print "(", (name) _obj, ").react_after()^";
|
|
#EndIf;
|
|
#Ifndef OPTIONAL_MANUAL_SCOPE;
|
|
! Assume that every routine may modify the scope
|
|
scope_modified = true;
|
|
#EndIf;
|
|
if(RunRoutines(_obj, react_after))
|
|
rtrue;
|
|
}
|
|
}
|
|
#IfDef DEBUG;
|
|
if(debug_flag & 1) print "(", (name) location, ").after()^";
|
|
#EndIf;
|
|
if(location provides after) {
|
|
#Ifndef OPTIONAL_MANUAL_SCOPE;
|
|
! Assume that every routine may modify the scope
|
|
scope_modified = true;
|
|
#EndIf;
|
|
if(RunRoutines(location, after)) rtrue;
|
|
}
|
|
if(inp1 > 1) {
|
|
#IfDef DEBUG;
|
|
if(debug_flag & 1) print "(", (name) inp1, ").after()^";
|
|
#EndIf;
|
|
if(inp1 provides after) {
|
|
#Ifndef OPTIONAL_MANUAL_SCOPE;
|
|
! Assume that every routine may modify the scope
|
|
scope_modified = true;
|
|
#EndIf;
|
|
if(RunRoutines(inp1, after)) rtrue;
|
|
}
|
|
}
|
|
#IfDef GamePostRoutine;
|
|
#IfDef DEBUG;
|
|
if(debug_flag & 1) print "GamePostRoutine()^";
|
|
#EndIf;
|
|
#Ifndef OPTIONAL_MANUAL_SCOPE;
|
|
! Assume that every routine may modify the scope
|
|
scope_modified = true;
|
|
#EndIf;
|
|
return GamePostRoutine();
|
|
#IfNot;
|
|
rfalse;
|
|
#EndIf;
|
|
];
|
|
|
|
[ RunLife p_actor p_reason;
|
|
#IfDef DEBUG;
|
|
if(debug_flag & 1 && p_actor provides life) print "(", (name) p_actor, ").life()^";
|
|
#EndIf;
|
|
#Ifndef OPTIONAL_MANUAL_SCOPE;
|
|
! Assume that every routine may modify the scope
|
|
scope_modified = true;
|
|
#EndIf;
|
|
return RunRoutines(p_actor, life, p_reason);
|
|
];
|
|
|
|
[ DirPropToFakeObj p_dir_prop;
|
|
#IfTrue RUNTIME_ERRORS > RTE_MINIMUM;
|
|
if(p_dir_prop < N_TO_CONST || p_dir_prop > OUT_TO_CONST)
|
|
RunTimeError(ERR_NOT_DIR_PROP);
|
|
#EndIf;
|
|
return p_dir_prop - N_TO_CONST + FAKE_N_OBJ;
|
|
];
|
|
|
|
[ FakeObjToDirProp p_fake_obj;
|
|
#IfTrue RUNTIME_ERRORS > RTE_MINIMUM;
|
|
if(p_fake_obj < FAKE_N_OBJ || p_fake_obj > FAKE_OUT_OBJ)
|
|
RunTimeError(ERR_NOT_FAKE_OBJ);
|
|
#EndIf;
|
|
return p_fake_obj - FAKE_N_OBJ + N_TO_CONST;
|
|
];
|
|
|
|
[ _SetDirectionIfIsFakeDir p_obj p_noun_no _idx;
|
|
if(p_obj >= FAKE_N_OBJ && p_obj <= FAKE_OUT_OBJ) {
|
|
_idx = p_obj - FAKE_N_OBJ;
|
|
selected_direction_index = _idx + 1;
|
|
selected_direction = _idx + N_TO_CONST;
|
|
if(p_noun_no == 1)
|
|
noun = Directions;
|
|
else
|
|
second = Directions;
|
|
}
|
|
];
|
|
|
|
#IfDef DEBUG;
|
|
[ DebugParameter _w;
|
|
print _w;
|
|
if (_w >= 1 && _w <= top_object) print " (", (name) _w, ")";
|
|
if (UnsignedCompare(_w, dict_start) >= 0 &&
|
|
UnsignedCompare(_w, dict_end) < 0 &&
|
|
(_w - dict_start) % dict_entry_size == 0)
|
|
print " ('", (address) _w, "')";
|
|
];
|
|
|
|
[ DebugAction a anames;
|
|
if (a >= 4096) { print "<fake action ", a-4096, ">"; return; }
|
|
anames = #identifiers_table;
|
|
anames = anames + 2*(anames-->0) + 2*48;
|
|
print (string) anames-->a;
|
|
];
|
|
|
|
[ TraceAction p_action p_noun p_second;
|
|
print "[ Action ", (DebugAction) p_action;
|
|
if (p_noun ~= 0) print " with noun ", (DebugParameter) p_noun;
|
|
if (p_second ~= 0) print " and second ", (DebugParameter) p_second;
|
|
print "]^";
|
|
];
|
|
|
|
#EndIf;
|
|
|
|
[ PerformAction p_action p_noun p_second _sa _sn _ss _sdi _sd _sinp1 _sinp2 _result;
|
|
_sa = action; _sn = noun; _ss = second; _sinp1 = inp1; _sinp2 = inp2; _sdi = selected_direction_index; _sd = selected_direction;
|
|
action = p_action; noun = p_noun; second = p_second; inp1 = p_noun; inp2 = p_second;
|
|
selected_direction_index = 0; selected_direction = 0;
|
|
_SetDirectionIfIsFakeDir(noun, 1);
|
|
_SetDirectionIfIsFakeDir(second, 2);
|
|
_result = PerformPreparedAction();
|
|
action = _sa; noun = _sn; second = _ss; selected_direction_index = _sdi; selected_direction = _sd; inp1 = _sinp1; inp2 = _sinp2;
|
|
return _result;
|
|
];
|
|
|
|
[ R_Process p_action p_noun p_second _s1 _s2;
|
|
_s1 = inp1; _s2 = inp2;
|
|
inp1 = p_noun; inp2 = p_second;
|
|
PerformAction(p_action, p_noun, p_second);
|
|
inp1 = _s1; inp2 = _s2;
|
|
];
|
|
|
|
[ CDefArt p_obj _result;
|
|
_result = _PrintObjName(p_obj, FORM_CDEF);
|
|
];
|
|
|
|
[ DefArt p_obj _result;
|
|
_result = _PrintObjName(p_obj, FORM_DEF);
|
|
];
|
|
|
|
[ IndefArt p_obj _result;
|
|
_result = _PrintObjName(p_obj, FORM_INDEF);
|
|
];
|
|
|
|
[ StartTimer p_obj p_timer;
|
|
StartDaemon(p_obj, p_obj, p_timer);
|
|
];
|
|
|
|
[ StartDaemon p_obj p_array_val p_timer _i;
|
|
if(p_array_val == 0)
|
|
p_array_val = WORD_HIGHBIT + p_obj;
|
|
for (_i=0 : _i<active_timers : _i++)
|
|
if (the_timers-->_i == p_array_val) rfalse;
|
|
_i = active_timers++;
|
|
#IfTrue RUNTIME_ERRORS > RTE_MINIMUM;
|
|
if (_i >= MAX_TIMERS) RunTimeError(ERR_TOO_MANY_TIMERS_DAEMONS);
|
|
#EndIf;
|
|
if (p_timer > 0) {
|
|
#IfTrue RUNTIME_ERRORS > RTE_MINIMUM;
|
|
if (p_obj.&time_left == 0) {
|
|
RunTimeError(ERR_OBJECT_HASNT_PROPERTY); return;
|
|
} else
|
|
#EndIf;
|
|
p_obj.time_left = p_timer;
|
|
}
|
|
#IfDef DEBUG;
|
|
if(debug_flag & 4) {
|
|
print "[ Starting ";
|
|
if(p_array_val > 0)
|
|
print "timer ", (DebugParameter) p_obj, " with time_left = ", p_timer;
|
|
else
|
|
print "daemon ", (DebugParameter) p_obj;
|
|
print "]^";
|
|
}
|
|
#EndIf;
|
|
the_timers-->_i = p_array_val;
|
|
];
|
|
|
|
[ StopTimer p_obj;
|
|
StopDaemon(p_obj, p_obj);
|
|
];
|
|
|
|
[ StopDaemon p_obj p_array_val _i;
|
|
if(p_array_val == 0)
|
|
p_array_val = WORD_HIGHBIT + p_obj;
|
|
for (_i=0 : _i<active_timers : _i++)
|
|
if (the_timers-->_i == p_array_val) jump FoundTSlot4;
|
|
rfalse;
|
|
.FoundTSlot4;
|
|
#IfDef DEBUG;
|
|
if(debug_flag & 4) {
|
|
print "[ Stopping ";
|
|
if(p_array_val > 0)
|
|
print "timer ";
|
|
else
|
|
print "daemon ";
|
|
print (DebugParameter) p_obj, "]^";
|
|
}
|
|
#EndIf;
|
|
if (p_obj == p_array_val) { ! This is a timer, not a daemon
|
|
#IfTrue RUNTIME_ERRORS > RTE_MINIMUM;
|
|
if (p_obj.&time_left == 0) {
|
|
RunTimeError(ERR_OBJECT_HASNT_PROPERTY); return;
|
|
} else
|
|
#EndIf;
|
|
p_obj.time_left = 0;
|
|
}
|
|
if(_i <= current_timer)
|
|
current_timer--;
|
|
for (_i=_i + 1: _i < active_timers : _i++)
|
|
the_timers-->(_i - 1) = the_timers-->_i;
|
|
active_timers--;
|
|
];
|
|
|
|
[ RunTimersAndDaemons _j _t;
|
|
#IfnDef OPTIONAL_MANUAL_SCOPE;
|
|
scope_modified = true;
|
|
#EndIf;
|
|
for (current_timer=0 : current_timer<active_timers : current_timer++) {
|
|
if (deadflag >= GS_DEAD) return;
|
|
_j = the_timers-->current_timer;
|
|
#IfDef DEBUG;
|
|
if(debug_flag & 4) {
|
|
print "[ Running ";
|
|
if(_j > 0) {
|
|
print "timer ", (DebugParameter) _j;
|
|
if(_j.time_left > 0)
|
|
print " with time_left = ", _j.time_left;
|
|
else
|
|
print ": time_out";
|
|
} else
|
|
print "daemon ", (DebugParameter) (_j & ~WORD_HIGHBIT);
|
|
print "]^";
|
|
}
|
|
#EndIf;
|
|
|
|
#Ifndef OPTIONAL_MANUAL_SCOPE;
|
|
! Assume that every routine may modify the scope
|
|
scope_modified = true;
|
|
#EndIf;
|
|
if (_j < 0) RunRoutines(_j & ~WORD_HIGHBIT, daemon);
|
|
else {
|
|
_t = _j.time_left;
|
|
if (_t == 0) {
|
|
StopTimer(_j);
|
|
RunRoutines(_j, time_out);
|
|
} else {
|
|
_t--;
|
|
_j.time_left = _t;
|
|
}
|
|
}
|
|
}
|
|
];
|
|
|
|
#IfV3;
|
|
! These routines are implemented by Veneer, but the default implementations give compile errors for z3
|
|
|
|
! [ Print__PName prop p size cla i;
|
|
! if (prop & $c000)
|
|
! { cla = #classes_table-->(prop & $ff);
|
|
! print (name) cla, "::";
|
|
! if ((prop & $8000) == 0) prop = (prop & $3f00)/$100;
|
|
! else
|
|
! { prop = (prop & $7f00)/$100;
|
|
! i = cla.3;
|
|
! while ((i-->0 ~= 0) && (prop>0))
|
|
! { i = i + i->2 + 3;
|
|
! prop--;
|
|
! }
|
|
! prop = (i-->0) & $7fff;
|
|
! }
|
|
! }
|
|
! p = #identifiers_table;
|
|
! size = p-->0;
|
|
! if (prop<=0 || prop>=size || p-->prop==0)
|
|
! print "<number ", prop, ">";
|
|
! else print (string) p-->prop;
|
|
! ];
|
|
|
|
! [ FindIndivPropValue p_obj p_property _x _prop_id;
|
|
! _x = p_obj.3;
|
|
! if (_x == 0) rfalse;
|
|
! ! print "Table for ", (object) obj, " is at ", (hex) x, "^";
|
|
! while (true) {
|
|
! _prop_id = _x-->0;
|
|
! if(_prop_id == 0) break;
|
|
! if(_prop_id & 32767 == p_property) break;
|
|
! ! print (hex) x-->0, " (", (property) x-->0, ") length ", x->2, ": ";
|
|
! ! for (n = 0: n< (x->2)/2: n++)
|
|
! ! print (hex) (x+3)-->n, " ";
|
|
! ! @new_line;
|
|
! _x = _x + _x->2 + 3;
|
|
! }
|
|
! return _x;
|
|
! ];
|
|
|
|
! [ RV__Pr p_object p_property _value _address;
|
|
! if(p_object == 0) {
|
|
! print "*Error: Tried to read property ";
|
|
! Print__PName(p_property);
|
|
! " of nothing.*";
|
|
! }
|
|
! if(p_object provides p_property) {
|
|
! if(p_property >= INDIV_PROP_START) {
|
|
! _address = FindIndivPropValue(p_object, p_property);
|
|
! return (_address + 3)-->0;
|
|
! }
|
|
! @get_prop p_object p_property -> _value;
|
|
! return _value;
|
|
! }
|
|
! print "[Error: Tried to read undefined property ";
|
|
! Print__PName(p_property);
|
|
! print " of ";
|
|
! PrintShortName(p_object);
|
|
! print "]";
|
|
! rfalse;
|
|
! ];
|
|
|
|
! CA__Pr: call, that is, print-or-run-or-read, a property:
|
|
! this exactly implements obj..prop(...). Note that
|
|
! classes (members of Class) have 5 built-in properties
|
|
! inherited from Class: create, recreate, destroy,
|
|
! remaining and copy. Implementing these here prevents
|
|
! the need for a full metaclass inheritance scheme. */
|
|
|
|
[ CA__Pr obj id a x z s s2 n m;
|
|
! print "CA_Pr obj = ", obj,", id = ", id,", a = ", a, "^";
|
|
if (obj < 1 || obj > #largest_object-255) {
|
|
switch(Z__Region(obj)) {
|
|
2:
|
|
if (id == call) {
|
|
s = sender; sender = self; self = obj;
|
|
#ifdef action;sw__var=action;#endif;
|
|
x = indirect(obj, a);
|
|
self = sender; sender = s; return x;
|
|
}
|
|
jump Call__Error;
|
|
3:
|
|
if (id == print) { @print_paddr obj; rtrue; }
|
|
if (id == print_to_array) {
|
|
@output_stream 3 a; @print_paddr obj; @output_stream -3;
|
|
return a-->0;
|
|
}
|
|
jump Call__Error;
|
|
}
|
|
jump Call__Error;
|
|
}
|
|
! print "CA_Pr(2) obj = ", obj,", id = ", id,", a = ", a, "^";
|
|
! @check_arg_count 3 ?~A__x;y++;@check_arg_count 4 ?~A__x;y++;
|
|
! @check_arg_count 5 ?~A__x;y++;@check_arg_count 6 ?~A__x;y++;
|
|
! @check_arg_count 7 ?~A__x;y++;@check_arg_count 8 ?~A__x;y++;.A__x;
|
|
! #ifdef INFIX;if (obj has infix__watching) n=1;#endif;
|
|
#ifdef DEBUG;if (debug_flag & 1 ~= 0) n=1;#endif;
|
|
! if (n==1) {
|
|
! n=debug_flag & 1; debug_flag=debug_flag-n;
|
|
! print "[ ~", (name) obj, "~.", (property) id, "(";
|
|
! switch(y) {
|
|
! 1:
|
|
! print a; 2: print a,",",b; 3: print a,",",b,",",c;
|
|
! 4:
|
|
! print a,",",b,",",c,",",d;
|
|
! 5:
|
|
! print a,",",b,",",c,",",d,",",e;
|
|
! 6:
|
|
! print a,",",b,",",c,",",d,",",e,",",f;
|
|
! }
|
|
! print ") ]^"; debug_flag = debug_flag + n;
|
|
! }
|
|
if (id > 0 && id < INDIV_PROP_START) {
|
|
! print "CA_Pr OK obj = ", obj,", id = ", id,", a = ", a, "^";
|
|
x = obj.&id;
|
|
if (x==0) {
|
|
x=$000a-->0 + 2*(id-1); n=2;
|
|
} else n = obj.#id;
|
|
} else {
|
|
if (id>=64 && id<69 && obj in Class) {
|
|
! print "CA_Pr ERROR0 obj = ", obj,", id = ", id,", a = ", a, "^";
|
|
RT__Err("Class create etc", obj, id); return;
|
|
! return Cl__Ms(obj,id,y,a,b,c);
|
|
}
|
|
! print "CA_Pr(2.1) obj = ", obj,", id = ", id,", n = ", n, "^";
|
|
x = obj..&id;
|
|
! print "CA_Pr(2.2) obj = ", obj,", id = ", id,", x = ", x, "^";
|
|
if (x == 0) {
|
|
! print "CA_Pr ERROR1 obj = ", obj,", id = ", id,", a = ", a, "^";
|
|
.Call__Error;
|
|
RT__Err("send message", obj, id); return;
|
|
}
|
|
! print "Reading n at ", x-1,": ", 0->(x-1), "^";
|
|
n = 0->(x-1);
|
|
if (id&$C000==$4000)
|
|
switch (n&$C0) { 0: n=1; $40: n=2; $80: n=n&$3F; }
|
|
}
|
|
! print "CA_Pr(3) obj = ", obj,", id = ", id,", a = ", a, "^";
|
|
for (:2*m<n:m++) {
|
|
! print "Considering routine at ", x+2*m,": ", x-->m, "^";
|
|
if (x-->m==$ffff) rfalse;
|
|
switch(Z__Region(x-->m)) {
|
|
2:
|
|
s = sender; sender = self; self = obj; s2 = sw__var;
|
|
! switch(y) {
|
|
! 0:
|
|
! z = indirect(x-->m);
|
|
! 1:
|
|
z = indirect(x-->m, a);
|
|
! 2:
|
|
! z = indirect(x-->m, a, b);
|
|
! 3:
|
|
! z = indirect(x-->m, a, b, c);
|
|
! 4:
|
|
! z = indirect(x-->m, a, b, c, d);
|
|
! 5:
|
|
! z = indirect(x-->m, a, b, c, d, e);
|
|
! 6:
|
|
! z = indirect(x-->m, a, b, c, d, e, f);
|
|
! }
|
|
self = sender; sender = s; sw__var = s2;
|
|
if (z ~= 0) return z;
|
|
3:
|
|
print_ret (string) x-->m;
|
|
default:
|
|
return x-->m;
|
|
}
|
|
}
|
|
rfalse;
|
|
];
|
|
|
|
[ Cl__Ms;
|
|
rfalse;
|
|
];
|
|
#EndIf;
|
|
|
|
#IfTrue RUNTIME_ERRORS < RTE_VERBOSE;
|
|
[RT__Err err_no par1 par2;
|
|
print "Inform error: ";
|
|
if(err_no ofclass String)
|
|
print (string) err_no, " - ";
|
|
else
|
|
print_ret err_no;
|
|
print_ret " (", par1, ", ", par2, ")";
|
|
];
|
|
#EndIf;
|
|
|
|
|
|
Object selfobj "you"
|
|
with
|
|
name 'me' 'myself' 'self',
|
|
short_name "yourself",
|
|
description "As good-looking as ever.",
|
|
before NULL,
|
|
after NULL,
|
|
life NULL,
|
|
each_turn NULL,
|
|
time_out NULL,
|
|
! describe NULL, ! TODO: uncommenting causes erorr LookSub
|
|
add_to_scope 0,
|
|
capacity MAX_CARRIED,
|
|
parse_name 0,
|
|
orders 0,
|
|
number 0,
|
|
before_implicit NULL,
|
|
has concealed animate proper transparent;
|
|
|
|
Object thedark "Darkness"
|
|
with
|
|
initial 0,
|
|
description "It is pitch dark here!",
|
|
short_name 0;
|
|
|
|
[ _UpdateScoreOrTime;
|
|
if (sys_statusline_flag == 0) {
|
|
status_field_1 = score;
|
|
status_field_2 = turns;
|
|
} else {
|
|
status_field_1 = the_time/60;
|
|
status_field_2 = the_time%60;
|
|
}
|
|
];
|
|
|
|
[ main _i _j _copylength _sentencelength _parsearraylength _score _again_saved _parser_oops;
|
|
|
|
#IfDef OPTION_DEBUG_VERBS;
|
|
dict_start = HDR_DICTIONARY-->0;
|
|
dict_entry_size = dict_start->(dict_start->0 + 1);
|
|
dict_start = dict_start + dict_start->0 + 4;
|
|
dict_end = dict_start + (dict_start - 2)-->0 * dict_entry_size;
|
|
#EndIf;
|
|
|
|
parse->0 = MAX_INPUT_WORDS;
|
|
#IfV5;
|
|
buffer->0 = MAX_INPUT_CHARS;
|
|
#IfNot;
|
|
buffer->0 = MAX_INPUT_CHARS - 1;
|
|
#EndIf;
|
|
|
|
top_object = #largest_object-255;
|
|
sys_statusline_flag = ( ($1->0) & 2 ) / 2;
|
|
|
|
player = selfobj;
|
|
deadflag = GS_PLAYING;
|
|
score = 0;
|
|
#IfDef OPTIONAL_FULL_SCORE;
|
|
places_score = 0;
|
|
things_score = 0;
|
|
#IfDef TASKS_PROVIDED;
|
|
for(_i = 0 : _i < NUMBER_TASKS : _i++) task_done->_i = 0;
|
|
#EndIf;
|
|
#EndIf;
|
|
|
|
_j = Initialise();
|
|
|
|
objectloop (_i in player) give _i moved ~concealed;
|
|
|
|
if(_j ~= 2) Banner();
|
|
|
|
_InitFloatingObjects(); ! after initialise since location set there
|
|
if(parent(player) == 0) { _i = location; location = 0; PlayerTo(_i); }
|
|
|
|
@new_line;
|
|
while(deadflag == GS_PLAYING) {
|
|
scope_modified = false; ! avoid automatic scope updates during parsing
|
|
|
|
_UpdateScoreOrTime();
|
|
if(_sentencelength > 0) @new_line;
|
|
|
|
_UpdateScope(player, true);
|
|
_score = score;
|
|
if(parse->1 == 0) {
|
|
_ReadPlayerInput();
|
|
}
|
|
_parser_oops = parser_unknown_noun_found;
|
|
.do_it_again;
|
|
_sentencelength = _ParseAndPerformAction();
|
|
if(action == ##OopsCorrection) {
|
|
if(_again_saved && _parser_oops > 0) {
|
|
!print "Oops not implemented^";
|
|
_CopyInputArray(buffer2, buffer);
|
|
_CopyParseArray(parse2, parse);
|
|
_parser_oops-->0 = special_word;
|
|
_again_saved = false;
|
|
jump do_it_again;
|
|
} else {
|
|
print "Sorry, that can't be corrected.^";
|
|
}
|
|
}
|
|
if(action == ##Again) {
|
|
! restore from the 'again' buffers and reparse
|
|
if(_again_saved) {
|
|
_CopyInputArray(buffer2, buffer);
|
|
_CopyParseArray(parse2, parse);
|
|
jump do_it_again;
|
|
} else {
|
|
print "You can hardly repeat that.^";
|
|
}
|
|
} else {
|
|
! store the current buffer to 'again'
|
|
_again_saved = true;
|
|
_CopyInputArray(buffer, buffer2);
|
|
_CopyParseArray(parse, parse2);
|
|
}
|
|
|
|
if(_sentencelength <= 0) _sentencelength = -_sentencelength;
|
|
else _sentencelength = parse->1;
|
|
if(action >= 0 && meta == false) {
|
|
RunTimersAndDaemons();
|
|
RunEachTurn();
|
|
TimePasses();
|
|
turns++;
|
|
if (the_time ~= NULL) {
|
|
if (time_rate >= 0) the_time=the_time+time_rate;
|
|
else {
|
|
time_step--;
|
|
if (time_step == 0) {
|
|
the_time++;
|
|
time_step = -time_rate;
|
|
}
|
|
}
|
|
the_time = the_time % 1440;
|
|
}
|
|
}
|
|
|
|
if(deadflag ~= GS_PLAYING && deadflag ~= GS_WIN) {
|
|
! we died somehow, use entry routine to give
|
|
! a chance of resurrection
|
|
AfterLife();
|
|
}
|
|
|
|
if(deadflag == GS_PLAYING && _score < score && notify_mode == true) {
|
|
print "^[The score has just gone up by ";
|
|
if(score - _score == 1) {
|
|
print "one point.]^";
|
|
} else {
|
|
print score - _score, " points.]^";
|
|
}
|
|
}
|
|
|
|
_parsearraylength = parse->1;
|
|
if(_parsearraylength > _sentencelength) {
|
|
! the first sentence in the input has been parsed
|
|
! and executed. Now remove it from parse so that
|
|
! the next sentence can be parsed
|
|
_copylength = 2 * _parsearraylength + 1;
|
|
for(_i = 1, _j = 2 * _sentencelength + 1: _j < _copylength: _i++, _j++)
|
|
parse-->_i = parse-->_j;
|
|
|
|
parse->1 = _parsearraylength - _sentencelength;
|
|
} else {
|
|
! the input was just one sentence
|
|
parse->1 = 0;
|
|
}
|
|
_UpdateDarkness(true);
|
|
}
|
|
_UpdateScoreOrTime();
|
|
print "^^ *** ";
|
|
if(deadflag == GS_QUIT) @quit;
|
|
if(deadflag == GS_WIN) PrintMsg(MSG_YOU_HAVE_WON);
|
|
else if(deadflag == GS_DEAD) PrintMsg(MSG_YOU_HAVE_DIED);
|
|
else if(deadflag >= GS_DEATHMESSAGE) DeathMessage();
|
|
print " ***^";
|
|
for (::) {
|
|
PrintMsg(MSG_RESTART_RESTORE_OR_QUIT);
|
|
_ReadPlayerInput(true);
|
|
switch(parse-->1) {
|
|
'restart': @restart;
|
|
'restore': RestoreSub();
|
|
#IfDef OPTIONAL_FULL_SCORE;
|
|
'full': FullScoreSub();
|
|
#EndIf;
|
|
'amusing': Amusing();
|
|
'quit': @quit;
|
|
}
|
|
}
|
|
];
|
|
|
|
! provide entry point routines if the user hasn't already:
|
|
! Routines marked NO are not supported in Puny, usually
|
|
! because the implementations differ too much.
|
|
!
|
|
#Stub AfterLife 0;
|
|
#Stub AfterPrompt 0;
|
|
#Stub Amusing 0;
|
|
#Stub BeforeParsing 0;
|
|
#Stub DarkToDark 0;
|
|
#Stub DeathMessage 0;
|
|
#Stub GamePostRoutine 0;
|
|
#Stub GamePreRoutine 0;
|
|
#Stub InScope 1;
|
|
#Stub LookRoutine 0;
|
|
#Stub NewRoom 0;
|
|
#Stub ParseNumber 2;
|
|
#Stub PrintTaskName 1;
|
|
#Stub PrintVerb 1;
|
|
#Stub TimePasses 0;
|
|
#Stub UnknownVerb 1;
|
|
!NO #Stub ChooseObjects 2;
|
|
!NO #Stub ParserError 1;
|