!---------------------------------------------------------------------------- routine check_date(month, day, year) { local tm_year, tm_month, tm_day tm_year = GetSystemTimeValue(TIME_YEAR) !!! print "year: "; number tm_year if (tm_year < year) { return false } if (tm_year > year) { return true } tm_month = GetSystemTimeValue(TIME_MONTH) !!! print "month: "; number tm_month if (tm_month < month) { return false } if (tm_month > month) { return true } tm_day = GetSystemTimeValue(TIME_DAY) !!! print "day: "; number tm_day if (tm_day < day) { return false } return true !We're at or past day } !---------------------------------------------------------------------------- ! determine if today's date is after the the comp voting deadline. routine is_after_comp { return check_date(11, 16, 2006) ! Nov. 16th 2006 is after. } !---------------------------------------------------------------------------- ! detect for whether or not this is a GLK port. routine is_glk_port { system(PAUSE_100TH_SECOND) if (system_status = 0) { return false } else { return true } } !---------------------------------------------------------------------------- routine new_pause { local key if (glk_port) { Font(ITALIC_ON | PROP_OFF) } else { Font(BOLD_ON | PROP_OFF) } color ROOM_FRINGE_COLOR, BGCOLOR, INPUTCOLOR print "...[Continue] "; color TEXTCOLOR, BGCOLOR, INPUTCOLOR if (glk_port) { Font(ITALIC_OFF | PROP_ON) } else { Font(BOLD_OFF | PROP_ON) } !Valid keys are SPACE, ENTER, CLICK. while (key ~= 13, 32, MOUSE_CLICK) { pause : key = word[0] } print "" !Blank line after pause } !---------------------------------------------------------------------------- routine glkcls { !! Must do this due to a bug or quirk in Gargoyle. !! it crashes when calculating graphic printing !! if you haven't first printed some lines to the !! screen. I have no idea why, but it also causes !! problems with the "continue" prompt, etc. So... cls !Begin with an initial screen clear, to hide. print "\_." !Must print at least one non-space. cls !But immediately clear the screen. That's fix. } !---------------------------------------------------------------------------- routine random_dir(num_dirs) { !Get a random direction of north, south, east, or west. !Or if we pass a larger number, ne, se, and so forth. rnd = random(num_dirs) select rnd case 1: return n_obj case 2: return s_obj case 3: return e_obj case 4: return w_obj case 5: return ne_obj case 6: return se_obj case 7: return sw_obj case 8: return nw_obj case 9: return u_obj case 10: return d_obj } !---------------------------------------------------------------------------- ! This is really only used by the "illusion" handler. We should clear all ! possible nouns and adjectives for the illusion, before assigning any new ! ones, since the new ones might be fewer, and we don't want any of those ! to still be valid when the illusion changes into something else. ! routine clear_references(obj) { local loop for (loop=1; loop <= obj.#nouns; loop++) { obj.nouns #loop = "" } for (loop=1; loop <= obj.#adjectives; loop++) { obj.adjectives #loop = "" } } !---------------------------------------------------------------------------- !I bet there's an easier way to get the length of a number (i.e., how much !space does it take up on-screen). However, until I figure that out, this !will work for now. ! routine GetLengthOfNum(num) { if (num > 9999) { return(5) } elseif (num > 999) { return(4) } elseif (num > 99) { return(3) } elseif (num > 9) { return(2) } else { return(1) } } !---------------------------------------------------------------------------- !Pass in a target string and up to 5 to compare against, to check for match. !This was originally used in Trading Punches, and adapted for this game. ! routine IsEqual(s1,c1,c2,c3,c4,c5) { string(tempbuf1,s1,100) !Is there some way we can loop for # of parameters instead??? if (c1 ~= 0) { string(tempbuf2,c1,100) if StringEqual(tempbuf1,tempbuf2) { return true } } if (c2 ~= 0) { string(tempbuf2,c2,100) if StringEqual(tempbuf1,tempbuf2) { return true } } if (c3 ~= 0) { string(tempbuf2,c3,100) if StringEqual(tempbuf1,tempbuf2) { return true } } if (c4 ~= 0) { string(tempbuf2,c4,100) if StringEqual(tempbuf1,tempbuf2) { return true } } if (c5 ~= 0) { string(tempbuf2,c5,100) if StringEqual(tempbuf1,tempbuf2) { return true } } return false } !---------------------------------------------------------------------------- ! We call this any time the player has to do something that requires ! dropping an object. This may also require that we untie the rope from ! the object in question, just so we don't drag it along. ! routine DropTheObject(obj) { if Contains(player,obj) { if Contains(player,rope) and IsAttached(rope,obj) { PrintMessage(6,14,obj) !Untying the rope from the obj first. ObjectDetach(rope,obj) !We untie the rope first. print "(and then "; "dropping "; The(obj); ")" } else { PrintMessage(6,10,obj) !Dropping the (object) first. } move obj to location } else { if Contains(player,rope) and IsAttached(rope,obj) { PrintMessage(6,14,obj) !Untying the rope from the obj first. ObjectDetach(rope,obj) !And then we untie the rope from it. } } } !---------------------------------------------------------------------------- ! This is the antithesis of "DropTheObject". If an object is in this room ! and we aren't holding it, we can automatically pick it up. ! routine GetTheObject(obj) { if (obj in location) { PrintMessage(6,20,obj) !Picking up the (object) first. Acquire(player,obj) } } !---------------------------------------------------------------------------- ! We call this any time the player performs an action that would require ! both hands (lifting the wagon wheel off the contraption, putting it on ! the wagon, or whatever. If it's already sheathed, nothing happens. ! routine SheatheSword { if (not sword.misc #1) { PrintMessage(6,13) ! It isn't really necessary to keep on describing this ! action to the player, is it? Let's just do it manually. !!! perform(&DoSheathe,sword) sword.misc #1 = true !It's back in its sheath. } } !---------------------------------------------------------------------------- ! When doing cutting or stabbing actions that involve the sword (even if the ! player didn't specify the sword, we'll use it and unsheathe it if needed. ! routine MakeReadySword { local retval = true if (xobject = nothing) { xobject = sword if (sword.misc #1) { !It would be unnecessarily verbose to say "with the sword" !and then turn around and say "unsheathing it first" so if !the sword wasn't specified *and* it needs to be drawn, !the user will get the idea just from auto-unsheathing it. if CanReadySword(true) { PrintMessage(6,11,1) !"(unsheathing your sword first)" ! It isn't really necessary to keep on describing this ! action to the player, is it? Let's just do it manually. !!! perform(&DoUnsheathe,sword) sword.misc #1 = false !It's no longer sheathed. } else { retval = false !We can't draw the sword. } } else { PrintMessage(6,12,sword) !"(with your sword)" } } elseif (xobject = sword) { if (sword.misc #1) { if CanReadySword { PrintMessage(6,11,2) !"(unsheathing it first)" ! It isn't really necessary to keep on describing this ! action to the player, is it? Let's just do it manually. !!! perform(&DoUnsheathe,sword) sword.misc #1 = false !It's no longer sheathed. } else { retval = false !We can't draw the sword. } } } return (retval) !Were we successful or not. } !---------------------------------------------------------------------------- ! This routine tries to determine if it's possible for the player to draw ! their sword. Different factors may prevent it, such as carrying a large ! beam that requires both arms to hold. The "print_msg" param tells whether ! or not to print the appropriate "reason" whenever there is a failure. ! routine CanReadySword(implied) { local retval = true ! The "implied" value is only true whenever we want to say ! "with the sword" before the failure is shown. ! First, make sure it's actually sheathed right now. Otherwise, it pretty ! much doesn't matter. There should never be a way to have your sword ! drawn already *and* be in a condition where you can't draw it, but ! just in case, let's check for the possibility. ! if (sword.misc #1) { if (location = steps) and (not sail_arms.misc #1) { if (implied): PrintMessage(6,12,sword) !"(with your sword)" retval = false : PrintMessage(15,4,1) !Too dangerous. steps.misc #1 = true !Flag that we saw the warning. } else { DropTheObject(beam) !If we have it, drop it first. DropTheObject(sail_arm) !Too big to carry up with us. } } return (retval) } !---------------------------------------------------------------------------- ! If the user didn't specify an NPC in some cases, we will imply that he ! must have meant whatever NPC is in this location. ! routine CheckForNPC { if (widow in location) { return widow } elseif (girl in location) { return girl } elseif (captain in location) { return captain } elseif (tyrant in location) { return tyrant } else { return nothing } } !---------------------------------------------------------------------------- ! Print "currently open" or "currently closed" in parenthesis. The first ! parm (withperiod) true/false tells whether or not to print a period ! after it. The second parm (endline) tells whether to print a line return. ! routine PrintOpenClosed(obj, withperiod, endline) { if (obj is open) { "(currently open)"; } else { "(currently closed)"; } if (withperiod): print "."; if (endline): print "" !End the line. } !---------------------------------------------------------------------------- ! I couldn't find anything exactly like this in objlib.h. Basically, what I ! sometimes need to know is if the attachable is tied to *anything*. Well, ! the library does this, but usually inline for each specific purpose. ! There are two ways to call this. With only one param (rope), we will ! return the object that the rope is attached to. This is handy for ! determining if the rope is attached to *anything*. But, if we give a ! second parameter, we're testing to see if the rope is attached to that. ! If it's attached to something else, then we get "nothing" back. ! routine IsAttached(att, to_obj) { local ret = nothing local loop if (att.#attached_to > 0) { for (loop = 1; loop <= att.#attached_to; loop++) { if (att.attached_to #loop) { if (to_obj = nothing) ret = att.attached_to #loop elseif (att.attached_to #loop = to_obj) ret = att.attached_to #loop } } } return ret } !---------------------------------------------------------------------------- routine AttachedCount(att) { local ret = 0 local loop if (att.#attached_to > 0) { for (loop = 1; loop <= att.#attached_to; loop++) { if (att.attached_to #loop): ret++ } } return ret } !---------------------------------------------------------------------------- ! Sometimes I may call ListObjects() directly, when relies on the list_count ! global already being set. There might be a better way to do this, by ! calling something in the library first, but the simplest thing right now ! is to just have a routine that sets the list count for an object. routine SetListCount(place) { local obj list_count = 0 for obj in place: list_count++ } !---------------------------------------------------------------------------- ! This will loop through and get rid of all instances of a value for a ! given property. This was written to make it easier to remove nouns and ! adjectives (specific ones) from objects in certain cases, but it would ! probably have some general usage otherwise. It works a little like InList. ! routine RemoveProp(obj, prop, val) { local i for (i=1; i<=obj.#prop; i++) { if obj.prop #i = val obj.prop #i = nothing } } !---------------------------------------------------------------------------- routine LookForAnswer(is_waiting, needheld) { if (is_waiting) { answer_verbroutine = &verbroutine answer_object = object answer_needheld = needheld answer_verbword = VerbWord answer_counter = counter } else { answer_verbroutine = nothing answer_object = nothing answer_needheld = false answer_verbword = nothing answer_counter = 0 } } !---------------------------------------------------------------------------- ! Check to see if a certain word is part of input. This is useful for ! determining how the player might have referred to an object. For instance, ! if the player says "apple" but not "apple tree" then he/she might have ! been looking for an apple (not here) and triggered on the tree adjective. routine IsWord(w) { local i local retval = false for (i=2; i <= words; i++) { if (word[i] = w): retval = true } return (retval) } !---------------------------------------------------------------------------- routine set_colors(style) { ! GLK doesn't support the color/style changes. ! At least, gargoyle and the windows GLK don't. if (glk_port): style = 1 GAME_PRINTSTYLE = style select style !Default User Style case 1 { TEXTCOLOR = DEF_FOREGROUND BGCOLOR = DEF_BACKGROUND SL_TEXTCOLOR = DEF_SL_FOREGROUND SL_BGCOLOR = DEF_SL_BACKGROUND ROOM_TITLE_COLOR = TEXTCOLOR ROOM_TEXT_COLOR = TEXTCOLOR ROOM_FRINGE_COLOR = TEXTCOLOR INPUTCOLOR = TEXTCOLOR } !Custom Style - GRAY ON WHITE case 2 { TEXTCOLOR = DARK_GRAY BGCOLOR = BRIGHT_WHITE SL_TEXTCOLOR = BRIGHT_WHITE SL_BGCOLOR = LIGHT_BLUE ROOM_TITLE_COLOR = LIGHT_BLUE ROOM_TEXT_COLOR = DARK_GRAY ROOM_FRINGE_COLOR = WHITE !! INPUTCOLOR = LIGHT_BLUE INPUTCOLOR = CYAN } ! The color of the input prompt can only be set if all colors are ! specified (unlike the bgcolor, which remains set even if left out). ! Otherwise, it will go back to the default whenever you omit it. color TEXTCOLOR, BGCOLOR, INPUTCOLOR } !---------------------------------------------------------------------------- ! An easy way to reference the main "forward" direction, set at the start. ! routine game_fore_dir { return (grassland.misc #1) } !---------------------------------------------------------------------------- ! An easy way to reference the main "backward" direction, set at the start. ! routine game_back_dir { return (grassland.misc #1).dir_from } !---------------------------------------------------------------------------- ! There are times when the Hugo library seems to get confused by its own ! plural_class. It assumes we are trying to do something with the "plural" ! version, instead of an individual object, whenever an xobject is involved. ! Basically, I could prevent it by always checking if it's a plural_class in ! my xobject.before handling, but this late in development, it would be a ! lot to track down and check for. So, I'm just going to patch it. I'm going ! to put a handler in the swordsman character object for verbs which use an ! xobject, and if the object itself is a plural class, then I'll try to ! determine which single object can be used, and re-route the routine. ! routine GetSingleFromPlural(obj,xobj) { local newobj = nothing if (verbroutine = &DoPutIn) and (xobj = sack) { return false !Allow them all at once. } if (verbroutine = &DoGetFrom) { ! Look for an object that we're not holding. for (rnd = 1; rnd <= obj.#plural_of; rnd++) { if not Contains(player, obj.plural_of #rnd) and \ Contains(location, obj.plural_of #rnd) and \ (newobj = nothing) { newobj = obj.plural_of #rnd } } } else { ! Otherwise, look for things we are holding. Anything we have that ! isn't contained in something else we already have takes priority. for (rnd = 1; rnd <= obj.#plural_of; rnd++) { if (obj.plural_of #rnd in player) and (newobj = nothing) { newobj = obj.plural_of #rnd } } for (rnd = 1; rnd <= obj.#plural_of; rnd++) { if Contains(player, obj.plural_of #rnd) and \ (newobj = nothing) { newobj = obj.plural_of #rnd } } } if (newobj = nothing) { if (verbroutine ~= &DoGetFrom) { ParseError(15,obj) !You're not holding it. return true !So the default handling stops. } else { return false !It didn't change, so default handling } } else { !Assume the player intended to do it with just one obj. Perform(verbroutine, newobj, xobj) !Redirect intent. return true !Let the caller know we hit on a match. } } !---------------------------------------------------------------------------- ! PrintMessage ! Section Defs 0 = Room Descriptions ! 1 = Object Descriptions ! 2 = Scenery Descriptions ! 3 = Various "Can't Do That" Messages ! 3,4,obj = Object Can't Be Searched ! 3,5,obj = Enter Place Already At ! 4 = "Drop" and "Can't Drop That" Messages ! 5 = Swordsmanship (Cut, Stab, Block) ! 6 = Miscellaneous or Uncategorized #1 ! 6,3,obj = Custom Closing Something ! 7 = Cutscenes, Chapter Endings, etc. ! 8 = PC and NPC Descriptions ! 9 = Various "Can't Go That Way" Messages ! 10 = Various "Can't Take That" Messages ! 11 = Custom "Pick Up Object" Messages ! 12 = Custom "Open/Move Object" Messages ! 13 = Custom "Sniff Object" Messages ! 14 = Exit Listings for Rooms ! 15 = Miscellaneous or Uncategoriezed #2 ! 16 = Girl moves from room to room in Part1 ! 17 = Communications - Point, Show, Give ! 18 = Custom "It's Too Far Away" Responses ! ! Putting everything in one enormous blob of cases may not be the best ! way of doing it. It does get confusing as more stuff is added. I do it for ! a couple reasons. One is, I know that all my text is here. I can find it ! and make changes, without hunting through all the rest of the code. Two, ! when there are things to re-use, I can just call the same PrintMessage. ! Granted, the exact same string used in multiple places would be just as ! good since the compiler will treat identical strings as one dictionary ! entry, but then if I wanted to make an update to that text, I would have ! to track down all those identical instances in the code, to change it. ! This way is a bit bulky and hard to follow, but it suits my purposes. ! ! The bad thing about doing this, though is that it makes my code harder to ! re-use (especially verbroutines). I have to track down the right text and ! include in similar PrintMessage routines in the different game. Oh well. ! !---------------------------------------------------------------------------- routine PrintMessage(num, val1, val2) { select num case 0: PrintText00(val1,val2) case 1: PrintText01(val1,val2) case 2: PrintText02(val1,val2) case 3: PrintText03(val1,val2) case 4: PrintText04(val1,val2) case 5: PrintText05(val1,val2) case 6: PrintText06(val1,val2) case 7: PrintText07(val1,val2) case 8: PrintText08(val1,val2) case 9: PrintText09(val1,val2) case 10: PrintText10(val1,val2) case 11: PrintText11(val1,val2) case 12: PrintText12(val1,val2) case 13: PrintText13(val1,val2) case 14: PrintText14(val1,val2) case 15: PrintText15(val1,val2) case 16: PrintText16(val1,val2) case 17: PrintText17(val1,val2) case 18: PrintText18(val1,val2) case 19: PrintText19(val1,val2) } !---------------------------------------------------------------------------- routine DoCheatSkip(chap) { if (chap < chapter) { PrintMessage(15,2,15) !You are already ahead of that chapter. } elseif (chapter = chap) { PrintMessage(15,2,16) !You are already in that chapter. } else { StartChapter(chap) !Skip ahead to next. } } !---------------------------------------------------------------------------- routine AddScore(task) { local p = 0 if (not scoretask[task]) { ! Flag that we've been awarded this point. scoretask[task] = true !It's awarded now. select task !Determine which point it is. !PROLOGUE - 5% case 1: p=1 case 2: p=2 case 3: p=2 !PART 1 - 30% case 4: p=1 case 5: p=1 case 6: p=1 case 7: p=1 case 8: p=1 case 9: p=1 case 10: p=1 case 11: p=1 case 12: p=1 case 13: p=1 case 14: p=1 case 15: p=2 case 16: p=1 case 17: p=1 case 18: p=1 case 19: p=1 case 20: p=2 case 21: p=2 case 22: p=1 case 23: p=1 case 24: p=2 case 25: p=2 case 26: p=1 case 27: p=1 case 77: p=1 !PART 2 - 35% case 28: p=2 case 29: p=1 case 30: p=2 case 31: p=1 case 32: p=1 case 33: p=1 case 34: p=1 case 35: p=2 case 36: p=1 case 37: p=1 case 38: p=1 case 39: p=2 case 40: p=1 case 41: p=1 case 42: p=1 case 43: p=1 case 44: p=2 case 45: p=1 case 46: p=1 case 47: p=1 case 48: p=2 case 49: p=2 case 50: p=2 case 51: p=1 case 52: p=2 case 53: p=1 !PART 3 - 25% case 54: p=1 case 55: p=1 case 56: p=2 case 57: p=1 case 58: p=1 case 59: p=1 case 60: p=1 case 61: p=1 case 62: p=1 case 63: p=1 case 64: p=1 case 65: p=1 case 66: p=1 case 67: p=2 case 68: p=1 case 69: p=2 case 70: p=1 case 71: p=2 case 72: p=2 case 73: p=1 !EPILOGUE - 5% case 74: p=1 case 75: p=2 case 76: p=2 score += p } } !---------------------------------------------------------------------------- routine Walkthrough { local maxpages local chapname local sectname local page = 1 local ok select chapter case 0 { maxpages = 2 chapname = "prologue" } case 1 { maxpages = 6 chapname = "part-one" } case 2 { maxpages = 7 chapname = "part-two" } case 3 { maxpages = 5 chapname = "part-three" } case 4 { maxpages = 1 chapname = "epilogue" } if not (swordsman.misc #4) { PrintMessage(19,5) !Give some introductory text. } while (page >= 1) and (page <= maxpages) { if (chapter=0)and(page=1): sectname = "Starting Out" if (chapter=0)and(page=2): sectname = "Finding the Glint" if (chapter=1)and(page=1): sectname = "The Barn" if (chapter=1)and(page=2): sectname = "The Orchard" if (chapter=1)and(page=3): sectname = "The Cellar" if (chapter=1)and(page=4): sectname = "The Wagon and the Bull" if (chapter=1)and(page=5): sectname = "The Loft" if (chapter=1)and(page=6): sectname = "Cornering the Girl" if (chapter=2)and(page=1): sectname = "Up and Away" if (chapter=2)and(page=2): sectname = "A Fierce Battle" if (chapter=2)and(page=3): sectname = "A Frantic Captain" if (chapter=2)and(page=4): sectname = "The Quarters" if (chapter=2)and(page=5): sectname = "Into the Mill" if (chapter=2)and(page=6): sectname = "A Replacement Wing" if (chapter=2)and(page=7): sectname = "Fixing the Barge" if (chapter=3)and(page=1): sectname = "The Dry Riverbed" if (chapter=3)and(page=2): sectname = "The Village" if (chapter=3)and(page=3): sectname = "Tapestries" if (chapter=3)and(page=4): sectname = "Meet the Tyrant" if (chapter=3)and(page=5): sectname = "Defeat the Tyrant" if (chapter=4)and(page=1): sectname = "A Busy Day" if (page = 1): print "Begin"; else: "Continue"; print " "; chapname; " walkthrough: \B"; print sectname; "\b? "; GetInput ok = YesOrNO if (ok) { swordsman.misc #4 = true !Flag it. print "" !Do a blank line before it. PrintMessage(19,chapter,page) page ++ !increment to ask the next page. if (page <= maxpages) { print "" !Do a blank line after it. } } else { page = 0 } } }