// Macro file by Drablak // Write to thoom@me.com for comments or information regarding this file // This file is intended to be put alongside the main character file // Put the following line (removing the '//') into your main char file // include "Snaggy" then simply type '/snaggy' to see the help. /* Global Help System (GHS) insert This section is part of the global help system. It must include a unique index and a name corresponding to the function call that displays the help items */ setglobal gh_call[19] "Snaggydirections" "/snaggyhelp" call Snaggydirections Snaggydirections { message "* ======================" message "* Snaggy macros" message "* file: Snaggy" message "* ======================" message " " message "'/sng [from] [to]': find a way through Snaggy" message " 0 = OC1" message " 17 = Bones (to WG and HH)" message " exit to OC from Aki is ESE-SEN-W" message "'/snu [name]': gives the number of the [name]d snell in Snaggy" message "'/sna [number]': gives the name of the [number]ed snell in Snaggy" message "'/lss': list Snaggy snells with names and numbers" message " " message "'/sngd call Snaggy directions to Bones" message "'/sngds call Snaggy directions to Bones in steps" } /* END of GHS */ "/snaggy" call Snaggydirections "/snagglewoods" call Snaggydirections "/sngd" "/yell WSE - NWS,SE - N"\r "/sngds" call snaggy_directions setglobal currentsng_step 0 snaggy_directions { if @text == "0" setglobal currentsng_step 0 else if @text == "-" setglobal currentsng_step - 1 else if @text == "+" setglobal currentsng_step + 1 else setglobal currentsng_step + 1 if currentsng_step == 1 "/yell WSE - gather North" else if currentsng_step == 2 "/yell NWS,SE - gather North" else if currentsng_step == 3 "/yell Rod first then all North" else if currentsng_step == 4 setglobal currentsng_step 0 end if end if } // =============================================================== // Snaggy upward path format is snag_up[index] = snell number // when snell number is -1 that part of the special path is over set snag_up[1] 12 set snag_up[2] 11 set snag_up[3] 10 set snag_up[4] 16 set snag_up[5] 17 set snag_up[6] -1 // Snaggy downward path format is snag_down[index] = snell number // when snell number is -1 that part of the special path is over set snag_down[1] 9 set snag_down[2] 14 set snag_down[3] 13 set snag_down[4] 1 set snag_down[5] 2 set snag_down[6] -1 // Snaggy database format is snag_db[snell number] = destination snell // directions are "N E S W" set snag_db[0] "-1 1 -1 -1" set snag_db[1] "2 5 8 3" set snag_db[2] "3 6 5 0" set snag_db[3] "4 7 9 6" set snag_db[4] "7 8 3 5" set snag_db[5] "7 7 9 3" set snag_db[6] "7 5 8 4" set snag_db[7] "8 4 6 3" set snag_db[8] "9 6 7 4" set snag_db[9] "8 14 7 6" set snag_db[10] "5 16 9 8" set snag_db[11] "9 7 10 6" set snag_db[12] "9 5 11 7" set snag_db[13] "3 1 4 7" set snag_db[14] "15 3 13 9" set snag_db[15] "4 3 8 12" set snag_db[16] "17 5 6 4" set snag_db[17] "8 5 6 4" // Unique-entry snells database format is snag_un[destination snell] = snell from which // you can enter it, if value is -1 then it's not a unique-entry snell set snag_un[0] 2 set snag_un[1] 13 set snag_un[2] 1 set snag_un[3] -1 set snag_un[4] -1 set snag_un[5] -1 set snag_un[6] -1 set snag_un[7] -1 set snag_un[8] -1 set snag_un[9] -1 set snag_un[10] 11 set snag_un[11] 12 set snag_un[12] -1 set snag_un[13] 14 set snag_un[14] 9 set snag_un[15] 14 set snag_un[16] 10 set snag_un[17] 16 // From-snell database format is snag_fr[snell number] = source snells // if source-snell is -1 it means there no further source snells for that destination // it's necessary since the number of source snell vary a lot set snag_fr[0] "2 -1" set snag_fr[1] "13 -1" set snag_fr[2] "1 -1" set snag_fr[3] "1 2 4 5 7 13 14 15 -1" set snag_fr[4] "3 6 7 8 13 15 16 17 -1" set snag_fr[5] "1 2 4 6 10 12 16 17 -1" set snag_fr[6] "2 3 7 8 9 11 16 17 -1" set snag_fr[7] "3 4 5 6 8 9 11 12 13 -1" set snag_fr[8] "1 4 6 7 9 10 15 17 -1" set snag_fr[9] "3 5 8 10 11 12 -1" set snag_fr[10] "11 -1" set snag_fr[11] "12 -1" set snag_fr[12] "14 15 -1" set snag_fr[13] "14 -1" set snag_fr[14] "9 -1" set snag_fr[15] "14 -1" set snag_fr[16] "10 -1" set snag_fr[17] "16 -1" setglobal g_snag_verb "00 - Orga Camp [OC]" // =============================================================== // =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- // // Snaggy Macro // // Utilities macros "/lss" // List Snaggy Snells { message "* Snaggy snells *" message " " message "[01] Maenygh" message "[02] Newton" message "[03] Gimli" message "[04] Ptolomy" message "[05] Sycamore" message "[06] Aki" message "[07] Tonle" message "[08] Nyssa" message "[09] Oberon" message "[10] Moonbeam" message "[11] Malkor" message "[12] Vagile" message "[13] Flex" message "[14] Sagramor" message "[15] Marfisa" message "[16] Rieger" message "[17] Bones" message " " } "/snu" // Input us a Snaggy snell name, output its number { set snag_name @text if snag_name <= "maenygh" message "01 - Maenygh" else if snag_name <= "newton" message "02 - Newton" else if snag_name <= "gimli" message "03 - Gimli" else if snag_name <= "ptolomy" message "04 - Ptolomy" else if snag_name <= "sycamore" message "05 - Sycamore" else if snag_name <= "aki" message "06 - Aki" else if snag_name <= "tonle" message "07 - Tonle" else if snag_name <= "nyssa" message "08 - Nyssa" else if snag_name <= "oberon" message "09 - Oberon" else if snag_name <= "moonbeam" message "10 - Moonbeam" else if snag_name <= "malkor" message "11 - Malkor" else if snag_name <= "vagile" message "12 - Vagile" else if snag_name <= "flex" message "13 - Flex" else if snag_name <= "sagramor" message "14 - Sagramor" else if snag_name <= "marfisa" message "15 - Marfisa" else if snag_name <= "rieger" message "16 - Rieger" else if snag_name <= "bones" message "17 - Bones" else message "* Error (bad argument)" message "Enter a Snaggy snell name (no caps)" end if } "/sna" // Input us a Snaggy snell number, output its name { set snag_number 0 set snag_number @text if snag_number == 1 message "01 - Maenygh" else if snag_number == 2 message "02 - Newton" else if snag_number == 3 message "03 - Gimli" else if snag_number == 4 message "04 - Ptolomy" else if snag_number == 5 message "05 - Sycamore" else if snag_number == 6 message "06 - Aki" else if snag_number == 7 message "07 - Tonle" else if snag_number == 8 message "08 - Nyssa" else if snag_number == 9 message "09 - Oberon" else if snag_number == 10 message "10 - Moonbeam" else if snag_number == 11 message "11 - Malkor" else if snag_number == 12 message "12 - Vagile" else if snag_number == 13 message "13 - Flex" else if snag_number == 14 message "14 - Sagramor" else if snag_number == 15 message "15 - Marfisa" else if snag_number == 16 message "16 - Rieger" else if snag_number == 17 message "17 - Bones" else message "* Error (bad argument)" message "Enter a Snaggy snell number (1-17)" message "Argument used was " @text end if } verbose_snag { set snag_number 0 set snag_number g_snag if snag_number == 0 setglobal g_snag_verb "00 - Orga Camp [OC]" else if snag_number == 1 setglobal g_snag_verb "01 - Maenygh" else if snag_number == 2 setglobal g_snag_verb "02 - Newton" else if snag_number == 3 setglobal g_snag_verb "03 - Gimli" else if snag_number == 4 setglobal g_snag_verb "04 - Ptolomy" else if snag_number == 5 setglobal g_snag_verb "05 - Sycamore" else if snag_number == 6 setglobal g_snag_verb "06 - Aki" else if snag_number == 7 setglobal g_snag_verb "07 - Tonle" else if snag_number == 8 setglobal g_snag_verb "08 - Nyssa" else if snag_number == 9 setglobal g_snag_verb "09 - Oberon" else if snag_number == 10 setglobal g_snag_verb "10 - Moonbeam" else if snag_number == 11 setglobal g_snag_verb "11 - Malkor" else if snag_number == 12 setglobal g_snag_verb "12 - Vagile" else if snag_number == 13 setglobal g_snag_verb "13 - Flex" else if snag_number == 14 setglobal g_snag_verb "14 - Sagramor" else if snag_number == 15 setglobal g_snag_verb "15 - Marfisa" else if snag_number == 16 setglobal g_snag_verb "16 - Rieger" else if snag_number == 17 setglobal g_snag_verb "17 - Bones" else message "* Error (bad argument)" message "* In verbose_snag function" message "* Argument passed was: " g_snag end if } named_snag { set snag_number g_snag if snag_number == 0 setglobal g_snag_verb "OC1" else if snag_number == 1 setglobal g_snag_verb "Maenygh" else if snag_number == 2 setglobal g_snag_verb "Newton" else if snag_number == 3 setglobal g_snag_verb "Gimli" else if snag_number == 4 setglobal g_snag_verb "Ptolomy" else if snag_number == 5 setglobal g_snag_verb "Sycamore" else if snag_number == 6 setglobal g_snag_verb "Aki" else if snag_number == 7 setglobal g_snag_verb "Tonle" else if snag_number == 8 setglobal g_snag_verb "Nyssa" else if snag_number == 9 setglobal g_snag_verb "Oberon" else if snag_number == 10 setglobal g_snag_verb "Moonbeam" else if snag_number == 11 setglobal g_snag_verb "Malkor" else if snag_number == 12 setglobal g_snag_verb "Vagile" else if snag_number == 13 setglobal g_snag_verb "Flex" else if snag_number == 14 setglobal g_snag_verb "Sagramor" else if snag_number == 15 setglobal g_snag_verb "Marfisa" else if snag_number == 16 setglobal g_snag_verb "Rieger" else if snag_number == 17 setglobal g_snag_verb "Bones" else message "* Error (bad argument)" message "* In named_snag function" message "* Argument passed was: " g_snag end if } /* Global variables declaration */ set g_connect false set g_this_origine 0 set g_this_dest 0 set g_dest 0 set g_origine 0 set g_sub_path[1] 0 set g_sub_path[2] 0 set g_sub_path[3] 0 set g_sub_path[4] 0 set g_sub_path[5] 0 set g_sub_path[6] 0 set g_sub_path[7] 0 set g_sub_path[8] 0 set g_sub_path[9] 0 set g_sub_path[10] 0 /* check_tie is a function used by tie_the_not to see if two points connect. It work by checking if any of the outward connections of g_this_origine is equal to the g_this_dest. If it connects then it returns false in g_connect, otherwise it returns true. */ check_snag_tie { setglobal g_connect false set mydirectionstr "bogus" set mydirectionstr snag_db[g_this_origine] // loop_tru_directions if mydirectionstr.word[0] == g_this_dest goto found_match else if mydirectionstr.word[1] == g_this_dest goto found_match else if mydirectionstr.word[2] == g_this_dest goto found_match else if mydirectionstr.word[3] == g_this_dest goto found_match else goto match_not_found end if label found_match setglobal g_connect true goto the_end label match_not_found setglobal g_connect false goto the_end label the_end } /* tie_the_not is an algorithm to find a path from global variable g_origine to global variable g_dest. It uses two 'opposing' arrays, one starting from g_origine and moving forward and the other starting from g_dest and moving backward. the goal of the algorithm is to tie these two paths together, hence "tie the not". The algorithm works in 'steps' somewhat like this: First we check to see if any g_origine->out lead to g_dest If not (most likely) then we make a list of the g_dest<-in, we then check to see if any g_origine->out leads to those g_dest<-in, if not then we proceed one step further from g_origine to the four g_origine->out and start over. Once we found a match we reconstruct the way the "not is tied" and send the array back to the calling function. */ tie_the_not_snag { // We set-up local variables that will contain the current snells we are checking // for a tie set c_origine g_origine set c_dest g_dest setglobal sub_path_index 0 /* message "we're in tie the not" */ /* message "Current 'origine' is: " g_origine */ /* message "Current 'destination' is: " g_dest */ label the_main_loop // First see if we're finished if c_origine == c_dest goto not_is_tied end if // Then see if we're one-step away setglobal g_this_origine c_origine setglobal g_this_dest c_dest call check_snag_tie if g_connect == true setglobal sub_path_index + 1 setglobal sub_path[sub_path_index] c_dest goto not_is_tied else // we build the first forward array set mydirectionstr "bogus" set mydirectionstr snag_db[c_origine] /* message "Current 'from' str is: " mydirectionstr */ set from_array[1] mydirectionstr.word[0] set from_array[2] mydirectionstr.word[1] set from_array[3] mydirectionstr.word[2] set from_array[4] mydirectionstr.word[3] // we build the first reverse array (which is just c_dest at this point) set to_array[1] c_dest set to_n 1 goto find_a_step end if // we have an origine array and a destination array and we want to find a step // along the path. We'll loop through here until we find a tie then increase the path // with the new info, reset the destination and start at main loop again. label find_a_step set x 1 set y 1 label check_all_possibilities setglobal g_this_origine from_array[x] setglobal g_this_dest to_array[y] /* message "'Steppin' with Origine " g_this_origine */ /* message "and Destination " g_this_dest */ call check_snag_tie if g_connect == true /* message "it connected in tie the not" */ setglobal sub_path_index + 1 setglobal sub_path[sub_path_index] g_this_origine setglobal sub_path_index + 1 setglobal sub_path[sub_path_index] g_this_dest set c_origine to_array[y] goto the_main_loop else set y + 1 if y <= to_n goto check_all_possibilities else set y 1 set x + 1 if x <= 4 goto check_all_possibilities else // we need to add a level of the destination array // first we transfert the present to_array into another to preserve it // while we work /* message "Adding a level to the search" */ set an_index 1 /* message "To_array length is " to_n */ label copy_loop set copy_array[an_index] to_array[an_index] set an_index + 1 if an_index <= to_n goto copy_loop end if /* message "We're done copying array..." */ /* message "Copied array is:" copy_array[1] "." copy_array[2] "." */ /* message "."copy_array[3] "."copy_array[4] "."copy_array[5] */ // copy_array now contains the replica of the previous array // now we build the new to_array using the snag_fr for each copy_array set a 1 // we'll use this for the new to_array set b 1 // we'll use this for the copy_array set mydirectionstr "bogus" label build_array set the_snell copy_array[b] set mydirectionstr snag_fr[the_snell] set c 0 // we'll use this for the from data label add_this_data /* message "Working on snell " the_snell */ /* message "Building new to_array, 'a' is " a */ /* message "Building new to_array, 'b' is " b */ /* message "Building new to_array, 'c' is " c */ set to_array[a] mydirectionstr.word[c] /* message "currently adding " mydirectionstr.word[c] */ set c + 1 if mydirectionstr.word[c] != -1 set a + 1 goto add_this_data else set b + 1 if b <= to_n set a + 1 goto build_array else set to_n a goto find_a_step end if // if b <= to_n end if // if mydirectionstr.word[c] != -1 end if // if x <= 4 end if // if y <= to_n end if // if g_connect label not_is_tied // here we found a way to connect the two points asked, so we need to // send back the correct path so that it can be incorporated into the // main path and the process resumed. set idx 1 label build_return_loop // setglobal g_sub_path[idx] sub_path[idx] // message "Building sub path step " g_sub_path[idx] /* message "Building sub path step " sub_path[idx] */ set idx + 1 if idx <= sub_path_index goto build_return_loop else // setglobal g_sub_path_n sub_path_index goto the_end end if label the_end } /* 'sng' stands for SnaGgyDirections /sng is an attempt to make a macro to determine how best to go from any one snell in Snaggy to any other snell. \sng 1 17 would give you the direction SNE-NWS-SEN for example */ "/snghelp" { message "* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-" message "Snaggy Directions Macro" message "Type '/sng x y'" message "Where x is point of origine and y is destination" message "Valid values are 0 to 17" message "17 is Bones" message "2 is exit to OC (by going west)" message "Type '/sna [number]' to get a name" message "Type '/snu [name] to get a number" message "Type "/lss" to list all snaggy snells" message "* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-" } "/sng" { // variables initialisations set d_origine 0 set d_dest 17 set d_origine @text.word[0] set d_dest @text.word[1] // checking for bad inputs // Fill this when the rest works if d_origine < 0 goto bad_input else if d_origine > 17 goto bad_input else if d_dest < 0 goto bad_input else if d_dest > 17 goto bad_input end if set c_origine d_origine // current origin - used in the forward research set c_dest d_dest // current destination - used in the reverse research set current_snell 0 // Initialisation of both 'forward' and 'reverse' paths arrays set fwd_route[1] d_origine set rvs_route[1] d_dest set fwd_index 1 set rvs_index 1 // macro execution feedback message " " message "* Snaggy Directions" message " " // Here parse snell numbers into names for feedback setglobal g_snag d_origine call verbose_snag message "Origine: " g_snag_verb // Same with destination (might want to make a function call for this one) setglobal g_snag d_dest call verbose_snag message "Destination: " g_snag_verb message "Computing fastest route..." message " " // First check to see if it's not a trivial connection setglobal g_this_origine d_origine setglobal g_this_dest d_dest call check_snag_tie if g_connect == true set fwd_index + 1 set fwd_route[fwd_index] d_dest goto finished_forward end if // We need to determine is if the destination is a // snell with a unique entry point (meaning there is only one snell that // leads to that destination snell (there are 10 such snells out of 18) label loop_unique set current_snell rvs_route[rvs_index] if snag_un[current_snell] != -1 /* message "Found unique: " current_snell " " */ set rvs_index + 1 set rvs_route[rvs_index] snag_un[current_snell] if rvs_route[rvs_index] == d_origine goto finished_reverse end if goto loop_unique end if // END LOOP loop_unique // Here we should check fwd and rvs arrays, determine current // origine and destination and call tie_the_not_snag // we should get out of here only when finished and should goto a closing function /* message " " */ /* message "* Gone tru special cases..." */ /* message " " */ // First we check in case we're finished and didn't realised it yet if fwd_route[fwd_index] == rvs_route[rvs_index] label put_rvs_into_fwd set rvs_index - 1 if rvs_index > 0 set fwd_index + 1 set fwd_route[fwd_index] rvs_route[rvs_index] goto put_rvs_into_fwd else goto finished_forward end if else // here check if it's a trivial connection setglobal g_this_origine fwd_route[fwd_index] setglobal g_this_dest rvs_route[rvs_index] call check_snag_tie if g_connect == true // It's trivial, we're done set fwd_index + 1 set fwd_route[fwd_index] rvs_route[rvs_index] label put_rvs_into_fwd_2 set rvs_index - 1 if rvs_index > 0 set fwd_index + 1 set fwd_route[fwd_index] rvs_route[rvs_index] goto put_rvs_into_fwd_2 else goto finished_forward end if else // Ok so no luck, we need to set the current origine-dest points // and call the big guns with tie_the_not_snag setglobal g_origine fwd_route[fwd_index] setglobal g_dest rvs_route[rvs_index] call tie_the_not_snag // here transpose the subpath into the path set idx 1 label input_sub_path_3 /* message "Transposing sub path in FINAL function..." */ set fwd_index + 1 set fwd_route[fwd_index] sub_path[idx] /* message "Sub path step is " sub_path[idx] */ set idx + 1 if idx <= sub_path_index goto input_sub_path_3 end if // Now we've added the connecting path to fwd_route // We need to complete with the rvs path and we're done /* message "* we reached the final stage..." */ /* message "fwd is " fwd_route[fwd_index] */ /* message "rvs is " rvs_route[rvs_index] */ /* message "rvs index is " rvs_index */ label put_rvs_into_fwd_3 set rvs_index - 1 if rvs_index > 0 set fwd_index + 1 set fwd_route[fwd_index] rvs_route[rvs_index] goto put_rvs_into_fwd_3 else goto finished_forward end if end if end if // macro should NOT come to this point, that means we haven't gone to the // closing functions through a call (goto) message "* ERROR in /sng: solution not found!!" goto the_end // We finished finding a path through the reverse path array // We need to reverse the order then send it to the directions parsing label finished_reverse // we first clear the fwd_route array if bigger than the reverse one if fwd_index > rvs_index set an_index rvs_index set an_index + 1 set fwd_route[an_index] -1 end if set fwd_index 1 label reverse_reverse set fwd_route[fwd_index] rvs_route[rvs_index] set rvs_index - 1 if rvs_index > 0 set fwd_index + 1 goto reverse_reverse end if // END LOOP reverse_reverse // now the forward array should contain the complete path to destination // we need to send it to the direction parser to get North-South-East-West // directions instead of a succession of snell numbers // First we save the path length in the variable path_length label finished_forward set path_length fwd_index /* message "In finished_forward, fwd_index is " fwd_index */ goto direction_parser // END LOOP finished_reverse // Once we have a route in the forward array we need to transform // that succession of snell numbers into directions (North, South, East, West) label direction_parser set D[1] "N" set D[2] "E" set D[3] "S" set D[4] "W" set a_space "-" set fwd_index 1 // initialise variable to force them to be taken as integer set current_dest 0 set current_snell 0 set next_snell_index 0 /* message "About to parse path directions" */ /* message "path: " fwd_route[1] "-"fwd_route[2] "-"fwd_route[3] "-"fwd_route[4] */ /* message "path: -" fwd_route[5] "-"fwd_route[6] "-"fwd_route[7] "." */ label convert_route set next_snell_index fwd_index set next_snell_index + 1 set current_snell fwd_route[fwd_index] /* message "Processing snell " current_snell */ set current_dest fwd_route[next_snell_index] /* message "Next snell " current_dest */ set mydirectionstr "bogus" set mydirectionstr snag_db[current_snell] /* message "Direction str is " mydirectionstr */ // loop_tru_directions if mydirectionstr.word[0] == current_dest set snag_dir[fwd_index] D[1] goto found_match else if mydirectionstr.word[1] == current_dest set snag_dir[fwd_index] D[2] goto found_match else if mydirectionstr.word[2] == current_dest set snag_dir[fwd_index] D[3] goto found_match else if mydirectionstr.word[3] == current_dest set snag_dir[fwd_index] D[4] goto found_match else message "* ERROR in /sng" goto the_end end if label found_match set fwd_index + 1 if fwd_index < path_length set next_snell_index + 1 set current_snell fwd_route[fwd_index] set current_dest fwd_route[next_snell_index] goto convert_route end if // END LOOP convert_route // Now we're ready to assembled an intelligible message to give out directions // I find it's easier to deal with (often long) directions by separating them in // sequences of 3 label assemble_message set direction_str "Path from " setglobal g_snag d_origine call named_snag set direction_str + g_snag_verb set direction_str + " to " setglobal g_snag d_dest call named_snag set direction_str + g_snag_verb set direction_str + " is: " set extended_str "-> " set fwd_index 1 set dir_tag 1 label loop_tru_route set direction_str + snag_dir[fwd_index] set extended_str + snag_dir[fwd_index] set extended_str + "[" set fwd_index + 1 set extended_str + fwd_route[fwd_index] set extended_str + "] " if fwd_index == path_length goto do_say_path end if set dir_tag + 1 if dir_tag > 3 set direction_str + a_space set dir_tag 1 end if goto loop_tru_route // END LOOP loop_tru_route // END LOOP assemble_message label do_say_path message "* " direction_str " " message " " message "* [" d_origine "] " extended_str message " " direction_str goto the_end label bad_input message "* ERROR: bad argument" message "Valid numbers are 0-17" label the_end } setglobal lines_of_code + 895