! ----------------------------------------------------- ! goto.h ! ! (c) 1999 by Toni Arnold, Zurich ! ! Serial Number 990721 ! ! Implements the verb "go to ". ! 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 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; 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; ]; ! ----------------------------------------------------------