CHECK IT OUT ON BOROGOVE: https://jpj59x6w.play.borogove.io/ "Map Goof" by Ryan Veeder Volume 1 - Making a Map [The main trick here is to make a huge grid of rooms, connected in orthogonal and diagonal directions, without having to type out "room B2 is south from room B1 and east from room A2 and southeast from room A1" for hundreds of locations. I have accomplished this sort of thing before by "faking it" with a single location whose features change in response to your movements. I have also accomplished this sort of thing by writing code to generate a bunch of room-connecting code. This time around, I have an arbitrary number of "real" rooms, and I assign them latitude and longitude coordinates. Instead of "really" connecting them, I change the rules of movement. This is kind of clever in how it saves coding time (...maybe), but it has a bunch of consequences. The consequences are lag during play. So this isn't what I'd call good code; it's not going to yield a game that's fun to play. But it's fun FOR ME TO WRITE.] Book 1 - Basic Definitions Part 1 - All The Rooms You Need A map cell is a kind of room. [Inform will only let me make 100 duplicates of a kind. But if I come up with arbitrary new kinds of that kind, I can make 100 of each:] A map cell A is a kind of map cell. There are 100 map cell As. A map cell B is a kind of map cell. There are 100 map cell Bs. A map cell C is a kind of map cell. There are 100 map cell Cs. [I'll only refer to "map cells" in the future, and these subtypes will prove to be PURELY WORKAROUNDITIVE.] Part 2 - Rooms With Coordinates Chapter 1 - Maximum Dimensions [Set maximum latitude ("width") and longitude ("height") to whatever you want, as long as the product is less than the number of generic rooms declared above.] Maximum latitude is initially 16. Maximum longitude is initially 16. Chapter 2 - Specific Dimensions A map cell has a number called latitude. A map cell has a number called longitude. [Printed name of a map cell is usually "LAT: [latitude] LONG: [longitude]".] [This is useful for debugging but it kind of ruins the play experience.] Chapter 3 - Table of Movements [We'll use this to convert directions "between rooms" into differences in coordinate values.] Table of Movements direction d-lat d-long north -1 0 northeast -1 1 east 0 1 southeast 1 1 south 1 0 southwest 1 -1 west 0 -1 northwest -1 -1 Book 2 - When Play Begins When play begins: assign coordinates to cells; [So the rooms are all "connected" properly] generate the river; [make a river wind its way from north to south] generate the train tracks; [make train tracks wind their way from east to west] set up the train; [put the train on those tracks] place the player; [since we can't say "the player is in [some room]" before runtime] update the map. [this adds information about your immediate surroundings to the map] [Set the starting location to whatever coordinates you want, as long as they're within the boundaries established by maximum and longitude.] Initial latitude is initially 5. Initial longitude is initially 5. To place the player: repeat with destination running through coordinate-defined map cells: if latitude of destination is initial latitude and longitude of destination is initial longitude: move the player to destination, without printing a room description. Book 3 - Assigning Coordinates To Cells Part 1 - The Assignment Process A map cell can be coordinate-defined or coordinate-undefined. A map cell is usually coordinate-undefined. [This makes sure there's a room for every possible pair of coordinates.] To assign coordinates to cells: repeat with latitude value running from 1 to maximum latitude: repeat with longitude value running from 1 to maximum longitude: let current cell be a random coordinate-undefined map cell; now longitude of current cell is longitude value; now latitude of current cell is latitude value; now current cell is coordinate-defined. Part 2 - The New Way Moving Works [This replaces the notion of room-connected-ness. When you go in a direction, you get whisked to the room with the right coordinates relative to your original coordinates.] Before going a direction listed in the Table of Movements: choose row with direction of noun in Table of Movements; let new latitude be latitude of location plus d-lat entry; let new longitude be longitude of location plus d-long entry; if new latitude is greater than maximum latitude: say "You can't go any farther south." instead; if new latitude is less than 1: say "You can't go any farther north." instead; if new longitude is greater than maximum longitude: say "You can't go any farther east." instead; if new longitude is less than 1: say "You can't go any farther west." instead; repeat with destination running through coordinate-defined map cells: if latitude of destination is new latitude and longitude of destination is new longitude: now player is in destination instead. Book 4 - Generating the River A room can be riverine. River latitude is initially 0. River longitude is initially 0. [the coordinates of the room that we're adding a river to.] River leg length is initially 0. [the remaining length of the stretch of river we're currently working on placing.] River leg direction is initially south. ["Maximum river longitude" is one less than the maximum longitude, because I don't want the river to run up against the side of the map. To match this on the west side, "minimum river longitude" is 2. I guess this is a Magic Number but I don't care tonight.] To decide what number is maximum river longitude: let MRL be maximum longitude minus 1; decide on MRL. To generate the river: let river source be a random number between 2 and maximum river longitude; now river longitude is river source; [the river starts at some arbitrary point,] now river latitude is 1; [on the northernmost row of rooms.] let first leg distance be a random number between 2 and 4; now river leg length is first leg distance; [the first stretch of river will be just a few rooms long,] now river leg direction is south; [and it always starts out going south.] place some river; try moving the river. To place some river: repeat with river spot running through coordinate-defined map cells: if latitude of river spot is river latitude and longitude of river spot is river longitude: now river spot is riverine. To try moving the river: [Loop adding rooms in the current river direction until this leg of the river is over.] if river leg length is greater than 0: move the river along its current course; otherwise: generate a new leg for the river; To move the river along its current course: choose row with direction of river leg direction in Table of Movements; let new latitude be river latitude plus d-lat entry; let new longitude be river longitude plus d-long entry; [Calculate the next room for the river with the same rules that govern player movement between rooms.] if new longitude is greater than maximum river longitude: [we have gotten too close to the east edge of the map! turn the river!] generate a new leg for the river; else if new longitude is less than 2: [too close to the west edge!] generate a new leg for the river; else if new latitude is greater than maximum latitude: [we would be going over the south edge of the map!] finish generating the river; else if new longitude is less than 1: [this would be going over the north edge of the map—but the river never goes north, so this never comes up.] generate a new leg for the river; else: now river latitude is new latitude; now river longitude is new longitude; place some river; decrement river leg length; try moving the river; To generate a new leg for the river: if river leg direction is not south: [we must be going east or west. we want to turn 90 degrees, and we don't want to go north.] now river leg direction is south; else if river longitude is maximum river longitude: [we must be going south, and we're on the east side of the map.] now river leg direction is west; else if river longitude is 2: [we're going south, and we're on the west side of the map.] now river leg direction is east; else if a random chance of 1 in 2 succeeds: [otherwise, we're in the middle of the map, so we can pick a non-south direction at random.] now river leg direction is east; else: now river leg direction is west; let new leg length be a random number between 2 and 4; now river leg length is new leg length; move the river along its current course. To finish generating the river: do nothing. [Actually maybe we should actually put a river object in riverine rooms...] Book 5 - Generating Train Tracks [Train track generation is a copy/paste of river generation, with latitude and longitude switched so that the train starts on the west side, winds its way to the east edge, never switches back west, and never gets too close to the north or south edges. Also, as rooms get train tracks added, they also get added to the "train track list," an ordered list of train track rooms. We can use that for making the train follow the tracks later.] A room can be tracked. The train track list is a list of rooms that varies. The train track list is initially { }. Train latitude is initially 0. Train longitude is initially 0. Train leg length is initially 0. Train leg direction is initially east. To decide what number is maximum train latitude: let MTL be maximum latitude minus 1; decide on MTL. To generate the train tracks: let first leg distance be a random number between 1 and 3; now train leg length is first leg distance; let train source be a random number between 2 and maximum train latitude; now train latitude is train source; now train longitude is 1; now train leg direction is east; place some tracks; try moving the train tracks. To place some tracks: repeat with train spot running through coordinate-defined map cells: if latitude of train spot is train latitude and longitude of train spot is train longitude: now train spot is tracked; add train spot to the train track list; To try moving the train tracks: if train leg length is greater than 0: move the train along its current course; otherwise: generate a new leg for the train; To move the train along its current course: choose row with direction of train leg direction in Table of Movements; let new latitude be train latitude plus d-lat entry; let new longitude be train longitude plus d-long entry; if new latitude is greater than maximum train latitude: generate a new leg for the train; else if new latitude is less than 2: generate a new leg for the train; else if new longitude is greater than maximum longitude: finish generating the tracks; else if new latitude is less than 1: generate a new leg for the train; else: now train latitude is new latitude; now train longitude is new longitude; decrement train leg length; place some tracks; try moving the train tracks; To generate a new leg for the train: if train leg direction is not east: now train leg direction is east; else if train latitude is maximum train latitude: now train leg direction is north; else if train latitude is 2: now train leg direction is south; else if a random chance of 1 in 2 succeeds: now train leg direction is north; else: now train leg direction is south; let new leg length be a random number between 2 and 4; now train leg length is new leg length; move the train along its current course. To finish generating the tracks: do nothing. Volume 2 - A Map Book 1 - Displaying the Map Player carries the map. Instead of examining the map: say "You look at the map:[paragraph break]"; say fixed letter spacing; say "+"; repeat with dashes running from 1 to maximum longitude: say "-"; say "+"; say line break; repeat with map latitude running from 1 to maximum latitude: say "|"; repeat with map longitude running from 1 to maximum longitude: repeat with cursor running through coordinate-defined map cells: [here's why looking at the map is so laggy: for each pair of coordinates, it has to check whether EVERY SINGLE MAP CELL (that has coordinates) matches those coordinates.] if latitude of cursor is map latitude and longitude of cursor is map longitude: if player is in cursor: say "@"; [use @ to mark your location, like in Rogue] else if cursor is mapped: say map data of cursor; else: say "[unicode 9618]"; [cool fog of war character] say "|"; say line break; say "+"; repeat with dashes running from 1 to maximum longitude: say "-"; say "+"; say line break; say variable letter spacing. Book 2 - Updating the Map Every turn while player carries the map: update the map. A room can be mapped or unmapped. A room is usually unmapped. To update the map: repeat with d-lat running from -1 to 1: repeat with d-long running from -1 to 1: let checked latitude be latitude of location plus d-lat; let checked longitude be longitude of location plus d-long; repeat with cursor running through unmapped coordinate-defined map cells: if latitude of cursor is checked latitude and longitude of cursor is checked longitude: now cursor is mapped; [To update the map: [low visibility edition] now the location is mapped.] Book 3 - Presenting Map Data To say map data of (zone - a room): if a train part is in zone: let car be a random train part in zone; say map code of car; else if zone is tracked: say "#"; else if zone is riverine: say "~"; else: say " " Volume 3 - The Train Book 1 - Train Part Features A train part is a kind of thing. Instead of taking a train part, say "You can't take that!" A train part has text called the map code. A train part has a number called position. A train part has a number called relative position. ["Position" is a car's current position along the list of rooms with train tracks. "Relative position" determines where a car starts out on that list—relative to the position of the locomotive. So the cars are not really connected to each other. If the locomotive disappeared, the rest of the cars would keep going. This is just the easiest way I could think of getting the train to roll along as if it were connected.] Book 2 - Individual Train Parts The locomotive is a train part. Map code of the locomotive is "L". Relative position of the locomotive is 0. The blue train car is a train part. Map code of the blue train car is "B". Relative position of the blue train car is -1. The yellow train car is a train part. Map code of the yellow train car is "Y". Relative position of the yellow train car is -2. The caboose is a train part. Map code of the caboose is "C". Relative position of the caboose is -3. Book 3 - Setting Up and Moving the Train Part 1 - Setting Up the Train To set up the train: repeat with car running through train parts: now position of car is (number of entries in train track list) plus relative position of car; now car is in entry (position of car) in the train track list; Part 2 - Moving the Train Every turn: repeat with car running through train parts: if car is visible: say "[The car] continues down the track."; increment position of car; if position of car is greater than number of entries in train track list: now position of car is remainder after dividing position of car by number of entries in train track list; let pushnum be position of car; now car is in entry pushnum in the train track list; if car is visible: say "[The car] rolls into view."; Volume 4 - Room Descriptions Printed name of a room is usually "[if riverine]River[else]Desert[end if]". Description of a room is usually "[if riverine]There's a river running past here! [else]You're in the middle of the desert. [end if][if tracked]There are train tracks nearby.[end if]".