! The following are a couple of routines that allow users of Hugo to generate ! random maps--random in the sense that the connections between ! rooms are randomly assigned at runtime and not fixed in stone. Otherwise, ! the user maintains complete control over them. This sort of thing seems ! to be most commonly found in RPG's, which is what I originally wrote ! this for. Please heed the following: ! ! All room objects must have a "coord 0, 0, 0" property in order for the ! map generator to work. They must also have explicit "dir_to" properties ! provided. ! ! Please note that this code will generate maps with cross-connections, and ! therefore it is not compatible with the FullMap() routine found in ! AUTOMAP.H. This is unfortunate, but it's due to a particularly elusive ! bug that I've spent countless hours trying to squash, to no avail. Other ! than that, though, there seems to be no problem with using the code. ! ! To use this beast, you must define your rooms as an uninterrupted series ! of objects and then call MakeMap() with the starting room, the ending ! room, and (optionally) a value of "true" to indicate that you want ! to allow up and down connections in the generated map. Otherwise, without ! the "true" argument, the generated map will potentially use every ! direction except up and down, which are disallowed by default. ! Note that there's no reason why you can't mix random map sections with ! "fixed" ones (as, for example, in Beyond Zork). The only caveat is that ! whatever rooms constitute a randomly generated section must be defined ! in your code in an uninterrupted series (such that, for example, ! Kitchen is object #52, Living Room is object #53, Bedroom is object ! #54 and so on). ! That's it! Enjoy! This document copyright (c) Cardinal Teulbachs, 1999 !---------------------------------------------------------------------------- property coord global rnd routine CheckCoord(a, start_rm, end_rm, do_updown) { local b, c :DoItAgain if do_updown rnd = random(10) else rnd = random(8) b = a - 1 ! b is preceding room select rnd case 1 : { a.coord#2 = b.coord#2-1 : a.coord#1 = b.coord#1 : a.coord#3 = b.coord#3 } case 2 : { a.coord#2 = b.coord#2-1 : a.coord#1 = b.coord#1-1 : a.coord#3 = b.coord#3 } case 3 : { a.coord#2 = b.coord#2-1 : a.coord#1 = b.coord#1+1 : a.coord#3 = b.coord#3 } case 4 : { a.coord#2 = b.coord#2+1 : a.coord#1 = b.coord#1 : a.coord#3 = b.coord#3 } case 5 : { a.coord#2 = b.coord#2+1 : a.coord#1 = b.coord#1+1 : a.coord#3 = b.coord#3 } case 6 : { a.coord#2 = b.coord#2+1 : a.coord#1 = b.coord#1-1 : a.coord#3 = b.coord#3 } case 7 : { a.coord#1 = b.coord#1-1 : a.coord#2 = b.coord#2 : a.coord#3 = b.coord#3 } case 8 : { a.coord#1 = b.coord#1+1 : a.coord#2 = b.coord#2 : a.coord#3 = b.coord#3 } case 9 : { a.coord#3 = b.coord#3-1 : a.coord#2 = b.coord#2 : a.coord#1 = b.coord#1 } case 10: { a.coord#3 = b.coord#3+1 : a.coord#2 = b.coord#2 : a.coord#1 = b.coord#1 } for (c = start_rm; c <= end_rm; c++) { if (a.coord#1 = c.coord#1) and (a.coord#2 = c.coord#2) and (a.coord#3 = c.coord#3) break elseif c = b return true } a.coord#1 = 0 a.coord#2 = 0 a.coord#3 = 0 jump DoItAgain } !---------------------------------------------------------------------------- routine MakeMap(start_rm, end_rm, do_updown) { local a, b, c, i, z for (a = (start_rm + 1); a <= end_rm; a++) { CheckCoord(a, start_rm, end_rm, do_updown) b = a - 1 ! b is preceding room select rnd case 1 : { a.n_to = b } case 2 : { a.ne_to = b } case 3 : { a.nw_to = b } case 4 : { a.s_to = b } case 5 : { a.sw_to = b } case 6 : { a.se_to = b } case 7 : { a.e_to = b } case 8 : { a.w_to = b } case 9 : { a.u_to = b } case 10: { a.d_to = b } select rnd case 1 : b.s_to = a case 2 : b.sw_to = a case 3 : b.se_to = a case 4 : b.n_to = a case 5 : b.ne_to = a case 6 : b.nw_to = a case 7 : b.w_to = a case 8 : b.e_to = a case 9 : b.d_to = a case 10: b.u_to = a for (c = start_rm; c <= b; c++) !! check for diags { ! if b is north of c if ((c.coord#1 = b.coord#1) and (c.coord#2+1 = b.coord#2)) and ((c.ne_to ~= 0) and (a.nw_to ~= 0)) { a.nw_to = 0 : b.se_to = 0 : ClearA(a) : a = b } elseif ((c.coord#1 = b.coord#1) and (c.coord#2+1 = b.coord#2)) and ((c.nw_to ~= 0) and (a.ne_to ~= 0)) { a.ne_to = 0 : b.sw_to = 0 : ClearA(a) : a = b } ! if b is south of c if ((c.coord#1 = b.coord#1) and (c.coord#2-1 = b.coord#2)) and ((c.se_to ~= 0) and (a.sw_to ~= 0)) { a.sw_to = 0 : b.ne_to = 0 : ClearA(a) : a = b } elseif ((c.coord#1 = b.coord#1) and (c.coord#2-1 = b.coord#2)) and ((c.sw_to ~= 0) and (a.se_to ~= 0)) { a.se_to = 0 : b.nw_to = 0 : ClearA(a) : a = b } ! if b is east of c if ((c.coord#1+1 = b.coord#1) and (c.coord#2 = b.coord#2)) and ((c.ne_to ~= 0) and (a.se_to ~= 0)) { a.se_to = 0 : b.nw_to = 0 : ClearA(a) : a = b } elseif ((c.coord#1+1 = b.coord#1) and (c.coord#2 = b.coord#2)) and ((c.se_to ~= 0) and (a.ne_to ~= 0)) { a.ne_to = 0 : b.sw_to = 0 : ClearA(a) : a = b } ! if b is west of c if ((c.coord#1-1 = b.coord#1) and (c.coord#2 = b.coord#2)) and ((c.nw_to ~= 0) and (a.sw_to ~= 0)) { a.sw_to = 0 : b.ne_to = 0 : ClearA(a) : a = b } elseif ((c.coord#1-1 = b.coord#1) and (c.coord#2 = b.coord#2)) and ((c.sw_to ~= 0) and (a.nw_to ~= 0)) { a.nw_to = 0 : b.se_to = 0 : ClearA(a) : a = b } } a is visited } for (a = (start_rm + 1); a <= end_rm; a++) { a is not visited for (c = start_rm; c < a; c++) { z = random(7) if ((c.coord#1+1) = a.coord#1 and c.coord#2 = a.coord#2) { if z > 5 { a.w_to = c : c.e_to = a } } elseif ((c.coord#1-1) = a.coord#1 and c.coord#2 = a.coord#2) { if z > 5 { a.e_to = c : c.w_to = a } } elseif ((c.coord#2+1) = a.coord#2 and c.coord#1 = a.coord#1) { if z > 5 { a.s_to = c : c.n_to = a } } elseif ((c.coord#2-1) = a.coord#2 and c.coord#1 = a.coord#1) { if z > 5 { a.n_to = c : c.s_to = a } } if ((c.coord#1+1) = a.coord#1 and (c.coord#2-1) = a.coord#2) { for (i = start_rm; i < a; i++) { if ((((i.coord#1+1) = a.coord#1) and (i.coord#2 = a.coord#2)) and i.ne_to ~= 0) break elseif ((((i.coord#2-1) = a.coord#2) and (i.coord#1 = a.coord#1)) and i.sw_to ~= 0) break else { if z > 5 { a.nw_to = c : c.se_to = a } } } } elseif ((c.coord#1-1) = a.coord#1 and (c.coord#2-1) = a.coord#2) { for (i = start_rm; i < a; i++) { if ((((i.coord#1-1) = a.coord#1) and (i.coord#2 = a.coord#2)) and i.nw_to ~= 0) break elseif ((((i.coord#2-1) = a.coord#2) and (i.coord#1 = a.coord#1)) and i.se_to ~= 0) break else { if z > 5 { a.ne_to = c : c.sw_to = a } } } } elseif ((c.coord#1+1) = a.coord#1 and (c.coord#2+1) = a.coord#2) { for (i = start_rm; i < a; i++) { if ((((i.coord#1+1) = a.coord#1) and (i.coord#2 = a.coord#2)) and i.se_to ~= 0) break elseif (((i.coord#1 = a.coord#1) and ((i.coord#2+1) = a.coord#2)) and i.nw_to ~= 0) break else { if z > 5 { a.sw_to = c : c.ne_to = a } } } } elseif ((c.coord#1-1) = a.coord#1 and (c.coord#2+1) = a.coord#2) { for (i = start_rm; i < a; i++) { if ((((i.coord#1-1) = a.coord#1) and (i.coord#2 = a.coord#2)) and i.sw_to ~= 0) break elseif ((((i.coord#2+1) = a.coord#2) and (i.coord#1 = a.coord#1)) and i.ne_to ~= 0) break else { if z > 5 { a.se_to = c : c.nw_to = a } } } } } } } routine ClearA(a) { a.coord#1 = 0 a.coord#2 = 0 a.coord#3 = 0 }