| ! This is not a game in the real sense. | |
| ! This is only a demonstration of one way to implement an | |
| ! AutoMap Feature in Inform. | |
| ! Feel free to copy and paste large portions of this code into | |
| ! your game. Feel free to translate this demonstration for | |
| ! Inform 6 or for other versions of Inform. Feel free to | |
| ! add the name of the translator to the Copyright line in | |
| ! that case, as well as additional comments. | |
| ! Feel free to just improve this demonstration, tagging on | |
| ! "Edited by (whoever)" in an appropriate place. | |
| ! Feel free to make a standard library out of it, too. | |
| ! Feel free to post any of the above (including just this | |
| ! source code) to the if-archive. | |
| ! Basically, consider this to be pretty much public domain. | |
| ! The original author may be contacted via jonadab@bright.net | |
| ! or the following address: | |
| ! Nathan Eady | |
| ! 307 Gill Ave | |
| ! Galion OH 44833 | |
| ! United States of America | |
| Switches pv5rsxz; ! Everyday use. | |
| Constant Story "^Automatic Mapping"; | |
| Constant Headline "^A Somewhat Interactive Demonstration.^\ | |
| Copyright (c) 1998 by Belly Laugh Software and Nathan Eady.^"; | |
| Release 2; Serial "980717"; | |
| ! Constant DEBUG 1; | |
| Constant MAX_CARRIED 100; | |
| Property area 0; | |
| Constant NO_AREA 0; | |
| Constant MAIN_AREA 1; | |
| Constant UPSTAIRS_AREA 2; | |
| Constant MAX_MAP_X 5; | |
| Constant MAX_MAP_Y 5; | |
| Property MapNum; ! Holds the number of the room on the map. | |
| Property MapDir; | |
| ! MapDir should contain, if anything, a routine, which should | |
| ! examine automapfeature.number for a direction property | |
| ! (*_to) and return | |
| ! true if the direction should be mapped as a travellable | |
| ! path, false if not, and -1 to say | |
| ! just check the property with ValueOrRun() to see | |
| ! if it goes anywhere. | |
| ! There is also the option to print any single character | |
| ! and then return -2 to so indicate. | |
| ! However, when doing this for up, down, in, or out, | |
| ! (which are all the same), it should be handled under | |
| ! in_to (which should print a character and return -2), | |
| ! and out_to should return -2, | |
| ! and u_to and d_to must return either 0 or -2. | |
| include "parser"; | |
| [ MapLoc secnum x y; | |
| switch (secnum) | |
| { | |
| NO_AREA: return -1; | |
| MAIN_AREA: | |
| switch (10*y + x) | |
| { | |
| 12: return RoomOne; | |
| 21: return RoomTwo; | |
| 22: return junction; | |
| 23: return EastOne; | |
| 24: return RoomFive; | |
| 31: return RoomFour; | |
| 32: return SouthOne; | |
| 34: return RoomEight; | |
| 42: return SouthTwo; | |
| 43: return RoomThree; | |
| 11, 41, 33: return 0; | |
| default: return -1; | |
| } | |
| UPSTAIRS_AREA: | |
| switch (10*y + x) | |
| { 11: return RoomSeven; | |
| 12: return RoomSix; | |
| 13: return FiveTop; | |
| default: return -1; | |
| } | |
| "Can't Happen: MapLoc fell through!"; | |
| } | |
| ]; | |
| ! Main Floor: | |
| ! | |
| ! 1 | |
| ! | | |
| ! | | |
| ! 2 -- hallway-- 5* | |
| ! a | | |
| ! l | | |
| ! 4 -- l 8 | |
| ! w | |
| ! a | |
| ! y -- 3 | |
| ! | |
| !========================================= | |
| Class boring | |
| with short_name "Boring, Empty Room", | |
| description "There's nothing to do here; the room only \ | |
| exists to ~flesh out~ the map.", | |
| area MAIN_AREA, | |
| has light; | |
| Object junction "Junction" | |
| with description "Hallways lead east and south. \ | |
| There are rooms to the north and west.", | |
| n_to RoomOne, | |
| w_to RoomTwo, | |
| e_to EastOne, | |
| s_to SouthOne, | |
| area MAIN_AREA, | |
| MapNum [; print " h"; return -2; ], | |
| MapDir [; | |
| switch (automapfeature.number) | |
| { | |
| n_to, w_to: rtrue; | |
| s_to, in_to: print "a"; return -2; | |
| e_to: print "l"; return -2; | |
| out_to: return -2; | |
| default: return 0; | |
| } | |
| ], | |
| after [; | |
| MapInfo: | |
| if (noun~=self) rfalse; | |
| "(Where you started the ~game~.)"; | |
| ], | |
| has light; | |
| Nearby sign "sign" | |
| with name "sign", | |
| description "~To see a map of the area nearby (so far as you \ | |
| have explored it), type MAP at the prompt.~", | |
| has static; | |
| Object EastOne "East End of Hallway" | |
| with description "There is a room to the east. The hallway leads west.", | |
| name "crystal" "staircase", | |
| e_to RoomFive, | |
| w_to junction, | |
| area MAIN_AREA, | |
| MapNum [; print "wa"; return -2; ], | |
| MapDir [; | |
| switch (automapfeature.number) | |
| { | |
| w_to: print "l"; return -2; | |
| in_to: print "y"; return -2; | |
| out_to: return -2; | |
| e_to: rtrue; | |
| default: rfalse; | |
| } | |
| ], | |
| has light; | |
| Object RoomFive "Staircase Room (bottom)" | |
| with name "crystal" "staircase", | |
| description "A crystal staircase leads up from here.", | |
| w_to EastOne, | |
| u_to FiveTop, | |
| s_to RoomEight, | |
| area MAIN_AREA, | |
| MapNum 5, | |
| before [; | |
| MapInfo: | |
| if (noun~=self) rfalse; | |
| ! I've put this in the before rule just to illustrate. | |
| ! The usual information isn't printed, only this: | |
| "The runes on the map next to that location indicate \ | |
| a staircase."; | |
| ], | |
| has light; | |
| Object SouthOne "North-South Hallway" | |
| with description "There is a room to the west.", | |
| n_to junction, | |
| s_to SouthTwo, | |
| w_to RoomFour, | |
| MapNum [; print " l"; return -2; ], | |
| MapDir [; | |
| switch (automapfeature.number) | |
| { w_to: rtrue; | |
| n_to: print "l"; return -2; | |
| s_to: print "w"; return -2; | |
| return 0; | |
| } | |
| ], | |
| area MAIN_AREA, | |
| has light; | |
| Object SouthTwo "South End of Hallway" | |
| with description "The hallway leads north, and there is a room \ | |
| to the east.", | |
| n_to SouthOne, | |
| e_to RoomThree, | |
| MapNum [; print " y"; return -2; ], | |
| MapDir [; | |
| switch (automapfeature.number) | |
| { e_to: rtrue; | |
| n_to: print "a"; return -2; | |
| return 0; | |
| } | |
| ], | |
| area MAIN_AREA, | |
| has light; | |
| Object RoomOne "r" | |
| class boring, | |
| with MapNum 1, | |
| s_to junction; | |
| Object RoomTwo "r" | |
| class boring, | |
| with MapNum 2, | |
| e_to junction; | |
| Object RoomThree "r" | |
| class boring, | |
| with MapNum 3, | |
| w_to SouthTwo; | |
| Object RoomFour "r" | |
| class boring, | |
| with MapNum 4, | |
| e_to SouthOne; | |
| Object RoomEight "r" | |
| class boring, | |
| with MapNum 8, | |
| n_to RoomFive; | |
| ! Upstairs: | |
| ! | |
| ! 7 -- 6*-- 5* | |
| ! | |
| !========================================= | |
| Object FiveTop "Staircase Room (top)" | |
| with area UPSTAIRS_AREA, | |
| description "A crystal staircase leads down.", | |
| name "crystal" "staircase", | |
| d_to RoomFive, | |
| w_to RoomSix, | |
| MapNum 5, | |
| after [; | |
| MapInfo: | |
| if (noun~=self) rfalse; | |
| ! This appears in an after routine, so the usual | |
| ! information (room short name, but you could change | |
| ! MapInfoSub) is printed first, followed by this: | |
| "There is also a symbol indicating a staircase."; | |
| ], | |
| has light; | |
| Object RoomSix "East-West Hallway" | |
| with area UPSTAIRS_AREA, | |
| description "Aren't this game's descriptions great?", | |
| in_to ClosetDoor, | |
| e_to FiveTop, w_to RoomSeven, | |
| MapNum 6, | |
| has light; | |
| Object ClosetDoor "closet door" RoomSix | |
| with name "closet" "door", | |
| door_dir in_to, door_to Closet, | |
| has open enterable door; | |
| Object Closet "Closet" | |
| with out_to RoomSix, | |
| description "It's a closet."; | |
| Nearby thepoint "point" | |
| with name "point", | |
| description "Did you get the point yet?", | |
| each_turn [; if (score>0) deadflag = 2; ], | |
| has scored; | |
| Object RoomSeven "Lamp Room" | |
| with area UPSTAIRS_AREA, | |
| MapNum 7, | |
| e_to RoomSix, | |
| description "Everything glows brightly here.", | |
| after [; Go: move lamp to player; ], | |
| has light; | |
| Object lamp "lamp" | |
| with name "lamp", | |
| description "It's a lamp. (This game has a talent for stating \ | |
| the obvious, doesn't it?)", | |
| has light; | |
| ! --------------------------------------- | |
| [ Initialise; | |
| location = junction; | |
| give SouthOne visited; | |
| give SouthTwo visited; | |
| give EastOne visited; | |
| ]; | |
| include "verblib"; | |
| !------------------------------------------------ MapHead | |
| [ MapHead horf a; | |
| switch (a) | |
| { | |
| NO_AREA: if (horf==1) | |
| { style bold; | |
| print "^MAP OF UNMAPPED REGION:"; | |
| style roman; | |
| "^"; | |
| } | |
| "^(You are here.)^"; | |
| MAIN_AREA: | |
| if (horf==1) | |
| { style bold; print "MAP OF MAIN FLOOR:"; style roman; "^"; } | |
| "^Bold represents your location; An * indicates that \ | |
| non-compass (up, down, in, out) travel may be \ | |
| possible. Type MAP INFO ## to look up additional \ | |
| information about room number ##."; | |
| UPSTAIRS_AREA: | |
| if (horf==1) | |
| { style bold; print "MAP OF UPSTAIRS:"; style roman; "^"; } | |
| "^[This footer intentionally left blank.]^"; | |
| } | |
| ]; | |
| [ AboutSub; | |
| Print "This is not a game in the real sense.\ | |
| ^This is only a demonstration of one way to implement an\ | |
| ^AutoMap Feature in Inform.\ | |
| ^\ | |
| ^Feel free to copy and paste large portions of this code into\ | |
| ^your game. Feel free to translate this demonstration for\ | |
| ^Inform 6 or for other versions of Inform. Feel free to\ | |
| ^add the name of the translator to the Copyright line in\ | |
| ^that case, as well as additional comments.\ | |
| ^"; | |
| Print "Feel free to just improve this demonstration, tagging on\ | |
| ^~Edited by (whoever)~ in an appropriate place.\ | |
| ^\ | |
| ^Feel free to make a standard library out of it, too.\ | |
| ^Feel free to post to the if-archive either this source \ | |
| ^code or anything derived from it.\ | |
| ^\ | |
| ^Basically, consider this to be pretty much public domain.\ | |
| ^\ | |
| ^The original author may be contacted via jonadab@@64bright.net\ | |
| ^or the following address:\ | |
| ^ Nathan Eady\ | |
| ^ 307 Gill Ave\ | |
| ^ Galion OH 44833\ | |
| ^ United States of America"; | |
| Print "^^This is Release 1. I plan to implement an ~information~ feature \ | |
| to allow the user to look up any of the nodes on the map by \ | |
| number and be told (at least) the short name of that location. \ | |
| This can be implemented with a fake action so that the location's \ | |
| before (or after) rule can then trap it and provide any additional \ | |
| information the author wants to give. However, this is not \ | |
| included in this first release, since I wanted to get some \ | |
| feedback before implementing it, if possible."; | |
| ]; | |
| !------------------------------------------------ MapDirX | |
| ! MapDir should contain, if anything, a routine, which should | |
| ! examine automapfeature.number for a direction object (*_obj) | |
| ! and return | |
| ! true if the direction should be mapped as a travellable | |
| ! path, false if not, and -1 to say | |
| ! just check the property with ValueOrRun() to see | |
| ! if it goes anywhere. | |
| [ MapDirX loc d dir answer; | |
| switch (d) | |
| { w_obj: dir=w_to; | |
| e_obj: dir=e_to; | |
| n_obj: dir=n_to; | |
| s_obj: dir=s_to; | |
| u_obj: dir=u_to; | |
| d_obj: dir=d_to; | |
| se_obj: dir=se_to; | |
| ne_obj: dir=ne_to; | |
| sw_obj: dir=sw_to; | |
| nw_obj: dir=nw_to; | |
| in_obj: dir=in_to; | |
| out_obj: dir=out_to; | |
| } | |
| automapfeature.number = dir; ! MapDir routines read this value | |
| answer = -1; ! If there's no MapDir routine, it's the same | |
| ! as if it returns -1. | |
| if (loc.#MapDir~=0) | |
| { ! The room provides a routine to tell us. | |
| answer = ValueOrRun(loc, MapDir); | |
| } | |
| if (answer~=-1) return answer; ! Thus, -2 will be returned. | |
| ! So if we get here the MapDir routine doesn't help. | |
| ! We'll have to examine the property manually. | |
| if (loc.#dir==0) return 0; | |
| if (loc.dir>0) return 1; ! Note that this will cause | |
| ! serious run-time problems if | |
| ! that property has anything in it | |
| ! other than a value. | |
| ]; | |
| !------------------------------------------------ AutoMapSub | |
| [ AutoMapSub a h v l n p; | |
| a = ValueOrRun(location, area); | |
| MapHead(1, a); ! Print Header | |
| if ( (0->33)<(5*MAX_MAP_X+1) ) ! Check the screen width | |
| ! (as the interpreter reports it | |
| ! in the header) | |
| print "[Some (or all) maps may be distorted by wrapping on narrow \ | |
| displays. Sorry.]"; | |
| for (v=1:v<=MAX_MAP_Y:v++) ! VPass, the single vertical line-for-line pass. | |
| { | |
| ! First HPass: Upper Connectors | |
| for (h=1:h<=MAX_MAP_X:h++) | |
| { | |
| l = MapLoc (a, h, v); | |
| if ((h==1)&&(l~=-1)) print "^"; | |
| if ((l~=0 or -1)&&(l has visited)) | |
| { | |
| if (l==location) style bold; else style roman; | |
| p = MapDirX(l, nw_obj); | |
| if (p==1) print "@@92"; else { if (p~=-2) print " "; } | |
| print " "; | |
| p = MapDirX(l, n_obj); | |
| if (p==1) print "|"; else { if (p~=-2) print " "; } | |
| print " "; | |
| p = MapDirX(l, ne_obj); | |
| if (p==1) print "/"; else { if (p~=-2) print " "; } | |
| } | |
| else print " "; | |
| } | |
| ! Second HPass: Items & Horiz Connectors | |
| for (h=1:h<=MAX_MAP_X:h++) | |
| { | |
| l = MapLoc (a, h, v); | |
| if ((h==1)&&(l~=-1)) print "^"; | |
| if ((l~=0 or -1)&&(l has visited)) | |
| { | |
| if (l==location) style bold; else style roman; | |
| p = MapDirX(l, w_obj); | |
| if (p==1) print "-"; else { if (p~=-2) print " "; } | |
| n = ValueOrRun(l, MapNum); | |
| if (n~=-2) | |
| { if (n<10) print " "; ! MUST NOT BE > 99 | |
| ! (If you need room numbers from 100 to 999, | |
| ! it wouldn't be hard to adjust for that, | |
| ! but the depiction of each node would be | |
| ! a character wider.) | |
| print n; | |
| } | |
| n = 0; | |
| if (MapDirX(l, u_obj)==1) n++; | |
| if (MapDirX(l, d_obj)==1) n++; | |
| if (MapDirX(l, in_obj)==1) n++; | |
| if (MapDirX(l, out_obj)==1) n++; | |
| if (n>0) print "*"; | |
| else { if (MapDirX(l, out_obj)==0) print " "; } | |
| p = MapDirX(l, e_obj); | |
| if (p==1) print "-"; else { if (p~=-2) print " "; } | |
| } | |
| else print " "; | |
| } | |
| ! Third HPass: Lower Connectors | |
| for (h=1:h<=MAX_MAP_X:h++) | |
| { | |
| l = MapLoc (a, h, v); | |
| if ((h==1)&&(l~=-1)) print "^"; | |
| if ((l~=0 or -1)&&(l has visited)) | |
| { | |
| if (l==location) style bold; else style roman; | |
| p = MapDirX(l, sw_obj); | |
| if (p==1) print "/"; else { if (p~=-2) print " "; } | |
| print " "; | |
| p = MapDirX(l, s_obj); | |
| if (p==1) print "|"; else { if (p~=-2) print " "; } | |
| print " "; | |
| p = MapDirX(l, se_obj); | |
| if (p==1) print "@@92"; else { if (p~=-2) print " "; } | |
| } | |
| else print " "; | |
| } | |
| } | |
| style roman; | |
| MapHead(2, a); ! Print Footer | |
| ]; | |
| !------------------------------------------------ MapInfoSub | |
| [ MapInfoSub; | |
| if (BeforeRoutines()==1) rfalse; ! we have to do this | |
| ! explicitly since AutoMapSub | |
| ! is on the same verb & we want | |
| ! that to be meta. If your | |
| ! verb isn't meta, remove | |
| ! this call to BeforeRoutines. | |
| if (noun==0) | |
| "There's no such number on the map at the moment."; | |
| print "Map Lookup for Location "; | |
| Print ValueOrRun(noun, mapnum); | |
| ! print " in area "; Print ValueOrRun(noun, area); | |
| print ":^"; | |
| PrintShortName(noun); print "^"; | |
| ! ObviousExitsSub(noun); Diary of a Text Adventurer has | |
| ! a utility to list the obvious exits of a | |
| ! room, which I haven't included here. | |
| if (AfterRoutines()==1) rfalse; | |
| ! So you can trap MapInfo in the after routine for | |
| ! any room and provide additional information. | |
| "There is no further information for this location."; | |
| ]; | |
| !------------------------------------------------ MapInfoNumber | |
| [ MapInfoNumber a n v h q t; ! A number-parsing routine for | |
| ! MapInfoSub's command line. | |
| a = ValueOrRun(location, area); | |
| n = TryNumber(wn); | |
| if (n<=0) rfalse; | |
| ! if (n > 0) We have something. | |
| wn++; | |
| v = 1; h = 1; | |
| while ((q==0)&&(v<=MAX_MAP_Y)) | |
| { | |
| t = MapLoc(a, h, v); | |
| ! the following line was incorrect: | |
| ! if ((ValueOrRun(t, mapnum)==n)&&(t has visited)) q = t; | |
| ! Because it runs every MapNum routine on the map. | |
| ! Instead: | |
| if ((t>selfobj) ! else t isn't a reasonable object | |
| &&(t.#mapnum==2) ! else it's not a value or routine | |
| &&((t.&mapnum)-->0>0) ! else it's likely a routine | |
| &&((t.&mapnum)-->0<100) ! else it's likely a routine | |
| &&((t.&mapnum)-->0==n) ! room object we want | |
| &&(t has visited)) q = t; ! only on map if visited. | |
| #IFDEF DEBUG; | |
| DefArt(t); | |
| print ":^ValueOrRun(object,mapnum): "; | |
| print ValueOrRun(t, mapnum); | |
| print "^object.#mapnum: "; | |
| print t.#mapnum; | |
| print "^(object.&mapnum)-->0: "; | |
| print (t.&mapnum)-->0; | |
| #ENDIF; | |
| h++; | |
| if (h>MAX_MAP_X) { h = 1; v++; } | |
| } | |
| return q; | |
| ]; | |
| !------------------------------------------------ MapScope | |
| object automapfeature "map" | |
| with name "map" "automap", | |
| number 0; ! used instead of a global to hold | |
| ! the direction requested of MapDir | |
| ! routines. | |
| [ MapScope; PlaceInScope(automapfeature); ]; | |
| !------------------------------------------------ grammar lines | |
| include "grammar"; | |
| ! You may not want this to be meta in your game -- | |
| ! That's a debatable matter. | |
| ! I've made it meta here because that's how it's | |
| ! going to by in Diary of a Text Adventurer, the | |
| ! game for which I wrote the mapping system. | |
| ! If your verb isn't meta, remove the call to | |
| ! BeforeRoutines from MapInfoSub, above. | |
| Extend "examine" | |
| * scope=MapScope -> AutoMap; | |
| Extend "look" | |
| * "at" scope=MapScope -> AutoMap; | |
| verb meta "map" "automap" "whereami" | |
| * -> AutoMap | |
| * "info" MapInfoNumber -> MapInfo | |
| * MapInfoNumber -> MapInfo; | |
| verb meta "help" "about" "hint" "hints" | |
| * -> About; | |
| end; | |
Xet Storage Details
- Size:
- 20.7 kB
- Xet hash:
- 24901411d07724d653df7f58958d5d70f2060ec05e281893c2ac9b135efa6b55
·
Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.