! -----------------------------------------------------
! goto.h
!
! (c) 1999 by Toni Arnold, Zurich
!
! Serial Number 990721
!
! Implements the verb "go to <room name>".
! It performs a breath-first-search on the map of the
! game and uses the nearest possible way.
! -----------------------------------------------------
! Source URL:
! http://www.copyriot.com/tarnold/goto.html
! -----------------------------------------------------
!
! Setting up goto.h
! -----------------
! Because goto.h contains a global variable
! and a common property it has to be included
! at the beginning of the game source.
!
! The grammar extension of the verb 'go'
! (at the end of this description) has
! to be copied, pasted and uncommented at
! the end of the game source.
!
! The only point which really has to be considered of
! are room direction routines: they must not produce
! side effects during the search of the way.
! For that reason side effects must check the
! global variable not_in_goto to be true before
! doing some side effects. Otherwise it must only
! return the target room.
!
!
! Example room (out of advent.inf)
! --------------------------------
!
!Object In_Hall_Of_Mists "In Hall of Mists"
! with goto_steps 0, ! ----> room <---- # this is added
! name "hall" "in" "mists" "of", # this is added
! ...
! description
! "You are at one end of a vast hall stretching,
! ....
! Rough stone steps lead up the dome.",
! s_to In_Nugget_Of_Gold_Room,
! w_to On_East_Bank_Of_Fissure,
! d_to In_Hall_Of_Mt_King,
! n_to In_Hall_Of_Mt_King,
! u_to
! [; if (not_in_goto) { ! # manually addet in the source to omit side effects during goto search
! if (large_gold_nugget in player)
! "The dome is unclimbable.";
! }
! return At_Top_Of_Small_Pit;
!
! ];
!
!
! The perl script mk_room_name.pl is provided for
! automatically adding room names to an existing game.
! For details see its html-documentation goto.html
! and the documentation in the script itself.
! -----------------------------------------------------
System_file;
! ----------------------------------------
! The grammar extension
! cut it out, uncomment it and copy it
! to the end of your game file
! ----------------------------------------
!Extend 'go' first
! * 'to' scope=scope_room -> go_to
! * 'to' 'the' scope=scope_room -> go_to;
Property goto_steps;
Global not_in_goto = true; ! flag for direction routines
! -------------------
! definition of the
! maximum way length
! -------------------
Constant max_goto_way_length = 100;
Array goto_way --> max_goto_way_length;
! ------------------------------
! the main go_to verb
! --------------------
! noun contains a room_name
! ------------------------------
[goto_destination pseudoroom; ! computes the real destination of door objects
do {
if (metaclass(pseudoroom) == string) rfalse;
if (metaclass(pseudoroom) == routine) pseudoroom = pseudoroom.call();
if (pseudoroom provides door_to) ! if the room is provided by the door object
pseudoroom = pseudoroom.door_to; ! take this room as target
} until ((pseudoroom == 0) || (pseudoroom == 1) || (metaclass(pseudoroom) == object));
return pseudoroom; ! ^ some routine could return true or false (e.g. In_Alcove in advent.inf)
];
!--------------------
! the main goto_verb
! -------------------
[go_toSub save_loc goal_room room next_room next_room2 active_number x obj dir i;
not_in_goto = false; ! flag for no side effects in room routines
goal_room = noun; ! name of the target room
active_number = 1; ! init step mark for active room (0 means inactive)
room = location;
save_loc = location; ! needed to save the current location for doors
if (room provides goto_steps) { ! darkness object has none
room.goto_steps = 1; ! mark it as starting point
}
do { ! do -------------------------
if (active_number > (max_goto_way_length+1)) { ! way too long to be stored
goto_message(0);
rtrue;
}
x = false; ! becomes true if at least one inactive neighbour room is found
objectloop (room provides goto_steps) { ! go through every room in the game
if (room.goto_steps == active_number) { ! if current room is a currently active room
if (room == goal_room) jump Found_Goal; ! if it is found OK.
location = room; ! for door objects to compute correctly
objectloop (obj in compass) { ! else loop through all directions
dir = obj.door_dir;
if (room provides dir) { ! if current direction is provided
next_room = goto_destination(room.dir);
if (next_room provides goto_steps) { ! next_room could be a routine, ignore those
if ((next_room has visited && next_room.goto_steps == 0)) { ! if neighbour is not yet searched
next_room.goto_steps = active_number+1; ! it becomes active in the next turn
x = true; ! at least one inactive neighbour room was found
}
}
}
} ! end compass loop
} ! end active room condition
} ! end of objectloop for all rooms for current step
active_number++; ! search rooms for the next step
} until (x == false); ! until no room left for search ----------------
goto_message(2); ! which means that the target room is not reachable from location
location = save_loc; ! restore location and quit
rtrue;
! --------- room is found and in real_room -------
! room_steps are set up with steps that are
! needed to get there
.Found_Goal;
if (active_number == 1) { ! if no step has to be made
goto_message(1); ! which means that target room equals current room
location = save_loc; ! restore location
rtrue;
}
! else go backwards to the original room
! room contains the current destination room
x = active_number - 1; ! 'x' is not used no more, so it becomes for-next border
! active_number is step of goal room
for (i=0: i<x: i++) {
active_number--; ! room with step - 1
objectloop (next_room provides goto_steps) { ! loops through all rooms
if(next_room.goto_steps == active_number) { ! if it's a room from where current room can be reached
location = next_room; ! because some (door) routines need it
objectloop(obj in compass) {
dir = obj.door_dir;
if (next_room provides dir) { ! next_room is a room with step = (step of room) - 1
next_room2 = goto_destination(next_room.dir); ! neighbours backwards of current room
if (next_room2 == room) { ! if it's the room before
goto_way --> i = obj; ! obj2 is the direction to take
room = next_room; ! new target room (for backwards going)
jump next_i;
}
} ! ---- room's which provide dir
} ! ---- compass loop of room
} ! ---- if condition i-1
} ! ---- objectloop for all rooms
.next_i; ! just an abbreviation
} ! ---- backward loop for all step distances i
! ------- now walk the given way ---------
location = save_loc; ! restore location
not_in_goto = true; ! activate side effects
for (i=(x-1): i>=0: i--) {
obj = location;
<Go goto_way-->i >; ! perform the go action
InformLibrary.end_turn_sequence(); ! and adjust the turns and the time
if (location == obj) { ! if go had no effect for some reason
goto_message(3);
rtrue;
}
}
]; ! ------------ end of main go verb ------------
! ==================== verb extension =====================
! ------- definition of scope of the new verb --------------
[scope_room room;
if (scope_stage == 1) rfalse;
if (scope_stage == 2) {
objectloop (room provides goto_steps) {
if (room has visited) {
room.goto_steps = 0; ! reset room step counter (= mark it as inactive)
PlaceInScope(room);
}
}
rtrue;
}
goto_message(4);
rtrue;
];
! ------------- the library messages ------------
! goto is always finished when a message occurs
[goto_message n;
switch(n) {
0: "The way there is too long. Try it with a shorter stage!";
1: "But you're already there!";
2: "The way to your destination is somehow too complicated.";
3: "There was something unexpected in your way which keeps
you from going on.";
4: "I don't understand where you want to go.";
}
not_in_goto = true; ! reset flag before finishing
rtrue;
];
! ----------------------------------------------------------