| !---------------------------------------------------------------- | |
| ! Moderator.h, by Emily Short | |
| ! May be incorporated in Inform code freely with or without credit | |
| ! and modified according to the requirements of the author. | |
| ! Contact me at emshort@mindspring.com if you encounter any bugs. | |
| ! | |
| ! Moderator.h is primarily useful for games with a fairly complex plot | |
| ! where the author wants to be able to block certain actions and movements | |
| ! at some times but not at others. Moderator does this through the | |
| ! omnipresent "moderator" object (which supervises everything the player | |
| ! does) and a series of scene objects. Only one scene can be active | |
| ! at a time. | |
| ! | |
| ! Scenes have the following characteristics: | |
| ! | |
| ! 1. A scene can have its own set of react_befores, so that the PC is kept | |
| ! from doing certain activities during that portion of the game. | |
| ! Useful if a lot of the game is going to take place in the same rooms, | |
| ! so that these properties can't be tied to location etc. | |
| ! | |
| ! 2. A scene can determine whether a player is allowed to move into a | |
| ! certain location. | |
| ! | |
| ! 3. A scene's "trigger" property is called every turn, allowing it to do a | |
| ! check to determine whether it is time to move on to a new scene. It | |
| ! is also possible to have the trigger property print something. | |
| ! | |
| ! 4. A scene ends when its endflag is set to a non-zero value, and a | |
| ! new scene is chosen. Scenes that have already occurred receive the | |
| ! general attribute. | |
| ! | |
| !---------------------------------------------------------------- | |
| ! | |
| ! INSTRUCTIONS: | |
| ! | |
| ! Include Moderator.h after verblibm.h. | |
| ! | |
| ! Before including the verblibm, put in | |
| ! Replace GoSub; | |
| ! | |
| ! Create a scene object for each discrete segment of the game for which | |
| ! you want to be able to exert special control. | |
| ! | |
| ! During Initialise, do | |
| ! Moderator.current = <FirstSceneOfGame>; | |
| ! | |
| !---------------------------------------------------------------- | |
| ! | |
| ! SCENE PROPERTIES: | |
| ! | |
| ! locator: a routine which receives the room into which a player is moving as | |
| ! an argument during any Go action. It may print or not print as | |
| ! it chooses, but should return false to permit the go action to proceed as | |
| ! normally, true to prevent go action. (If it prevents, it should print | |
| ! to explain the failure, just as when preventing an action in before.) | |
| ! The convenient thing is that this routine works regardless of how the | |
| ! player is entering the new location and what the starting location is. | |
| ! The presence of doors is also irrelevant. | |
| ! | |
| ! NB: locator can be used to implement an NPC that follows the player; | |
| ! have locator move the NPC into the new room and print something like | |
| ! "White accompanies you as you walk." | |
| ! | |
| ! WARNING: | |
| ! One weird caveat: if you want to prevent the player moving into a | |
| ! location that is dark, you will have to specify the dark room as well | |
| ! as the actual room that's there. Personally, these days I rarely write | |
| ! a game that doesn't have light in all the rooms automatically. | |
| ! | |
| ! react_before: as always. | |
| ! | |
| ! trigger: like an each_turn property for the scene. | |
| ! | |
| ! number: incremented each turn during the scene. Can be used to make a scene | |
| ! last for a set number of turns, or to schedule events at a given | |
| ! time within the scene. | |
| ! | |
| ! endflag: indicates whether the scene is over. If it is positive, Moderator | |
| ! will call the scene's advance property during this turn. One can, | |
| ! for instance, set the endflag to different values depending on the | |
| ! outcome of the scene. | |
| ! | |
| ! advance: describe the end of the scene (optionally) and set the new scene, by | |
| ! doing Moderator.current = <name of new scene>. | |
| ! | |
| ! startup: does anything required to set up the scene as it is beginning. | |
| ! This routine could, for instance, move the player into a location, | |
| ! bring an NPC on stage, etc. | |
| ! | |
| ! | |
| ! | |
| !---------------------------------------------------------------- | |
| Object Moderator, | |
| with | |
| current 0, ! Set to whatever the current scene is | |
| found_in [; | |
| rtrue; | |
| ], | |
| react_before [ x; | |
| default: | |
| if (self.current && self.current provides react_before) | |
| { x = self.current.react_before(); | |
| return x; | |
| } | |
| rfalse; | |
| ], | |
| locator [ newroom i x; | |
| if (self.current provides locator) | |
| { i = self.current.locator(newroom); | |
| if (i) rtrue; | |
| } | |
| rfalse; | |
| ], | |
| each_turn [ ; | |
| if (self.current == 0) rfalse; | |
| self.current.number++; | |
| if (self.current provides trigger && self.current.endflag == 0) | |
| self.current.trigger(); | |
| if ((self.current == 0) || (~~(self.current provides advance)) | |
| || (~~(self.current provides endflag))) rfalse; | |
| self.advance(); | |
| ], | |
| advance [; | |
| if (self.current.endflag == 0) rfalse; | |
| give self.current general; | |
| self.current.advance(); | |
| if (self.current hasnt general) | |
| self.current.startup(); | |
| ], | |
| has scenery concealed; | |
| Class Scene, | |
| with | |
| endflag 0, | |
| number 0, | |
| startup [; | |
| rfalse; | |
| ], | |
| trigger [; | |
| rfalse; | |
| ], | |
| advance [; | |
| rfalse; | |
| ]; | |
| ! EXAMPLE CODE: | |
| ! Scene FirstScene, | |
| ! with | |
| ! react_before [; | |
| ! xyzzy: "You're too busy getting ready for Paris to mess around | |
| ! with magic spells."; | |
| ! listen: "Sounds like someone is banging around upstairs."; | |
| ! ], | |
| ! locator [ newroom; | |
| ! if (newroom == Attic) | |
| ! { "You don't dare enter the attic while your spouse is looking | |
| ! for that map of Paris."; | |
| ! | |
| ! ! (Because this returns true, the player will never enter | |
| ! ! the attic during this scene.) | |
| ! } | |
| ! | |
| ! ], | |
| ! trigger [; | |
| ! if (self.number > 5) ! true after 6 turns have elapsed | |
| ! { self.endflag = 1; ! this is the end of this scene | |
| ! | |
| ! "~Honey,~ calls a familiar voice from the attic. ~Could you give | |
| ! me some help up here?~"; | |
| ! } | |
| ! ], | |
| ! advance [; | |
| ! Moderator.current = HelpingSpouse; ! set up the new scene | |
| ! "^There's a loud thumping from upstairs. Sighing, you climb up | |
| ! through trap door..."; | |
| ! ]; | |
| ! | |
| ! Scene HelpingSpouse, | |
| ! with | |
| ! startup [; | |
| ! move spouse to Attic; | |
| ! PlayerTo(Attic); ! This begins the new scene | |
| ! ], | |
| ! locator [ newroom; | |
| ! if (newroom == Downstairs) | |
| ! { | |
| ! self.endflag = 1; | |
| ! print "~Never mind,~ you say. ~I'm no good at this. | |
| ! You'll have to find it on your own.~"; | |
| ! rfalse; | |
| ! | |
| ! ! (Returns false, so the player is allowed to go, but | |
| ! ! the scene will end at this point.) | |
| ! } | |
| ! | |
| ! ], | |
| ! trigger [; | |
| ! if (MapOfParis in player) | |
| ! { self.endflag = 2; | |
| ! } | |
| ! ], | |
| ! advance [; | |
| ! if (self.endflag == 1) | |
| ! { Moderator.current = PackingAllAlone; | |
| ! ... | |
| ! } | |
| ! else | |
| ! { Moderator.current = PackingWithSpouse; | |
| ! "^Now that you have the map, you head downstairs together to | |
| ! finish packing for Paris..."; | |
| ! } | |
| ! ]; | |
| ! Replacement GoSub is exactly like Graham's, except that it checks | |
| ! with the moderator before allowing the player to make the movement | |
| [ GoSub i j k df movewith thedir old_loc; | |
| if (second ~= 0 && second notin Compass | |
| && ObjectIsUntouchable(second)) return; | |
| old_loc = location; | |
| movewith=0; | |
| i=parent(player); | |
| if ((location~=thedark && i~=location) | |
| || (location==thedark && i~=real_location)) | |
| { j=location; | |
| if (location==thedark) location=real_location; | |
| k=RunRoutines(i,before); if (k~=3) location=j; | |
| if (k==1) | |
| { movewith=i; i=parent(i); | |
| } | |
| else | |
| { if (k==0) L__M(##Go,1,i); | |
| rtrue; | |
| } | |
| } | |
| thedir=noun.door_dir; | |
| if (ZRegion(thedir)==2) thedir=RunRoutines(noun,door_dir); | |
| j=i.thedir; k=ZRegion(j); | |
| if (k==3) { print (string) j; new_line; rfalse; } | |
| if (k==2) { j=RunRoutines(i,thedir); | |
| if (j==1) rtrue; | |
| } | |
| if (k==0 || j==0) | |
| { if (i.cant_go ~= 0) PrintOrRun(i, cant_go); | |
| rfalse; | |
| } | |
| if (j has door) ! is the direction a door object? if so... | |
| { if (j has concealed) return L__M(##Go,2); | |
| if (j hasnt open) | |
| { if (noun==u_obj) return L__M(##Go,3,j); | |
| if (noun==d_obj) return L__M(##Go,4,j); | |
| return L__M(##Go,5,j); | |
| } | |
| k=RunRoutines(j,door_to); ! where does it go? | |
| if (k==0) return L__M(##Go,6,j); | |
| if (k==1) rtrue; | |
| j = k; | |
| } | |
| if (Moderator.locator(j)==1) rtrue; ! ask the moderator | |
| if (movewith==0) move player to j; else move movewith to j; | |
| location=j; MoveFloatingObjects(); | |
| df=OffersLight(j); | |
| if (df~=0) { location=j; real_location=j; lightflag=1; } | |
| else | |
| { if (old_loc == thedark) | |
| { DarkToDark(); | |
| if (deadflag~=0) rtrue; | |
| } | |
| real_location=j; | |
| location=thedark; lightflag=0; | |
| } | |
| if (AfterRoutines()==1) rtrue; | |
| if (keep_silent==1) rtrue; | |
| LookSub(1); | |
| ]; | |
Xet Storage Details
- Size:
- 8.63 kB
- Xet hash:
- d42600a1c7cd18fdc35502ca1d09c3f55373fa6daee7d469a02856cc8d1873f2
·
Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.