Halloween Horror Part I

This is Roody Yogurt’s update to a game originally released as “The Ecto Horror.” It requires the glk.h and newmenu.h library extensions (and possibly beta.h).

the code

!::
! The Halloween Horror by Roody Yogurt
!::
#set GLK
!#set BETA

!$MAXDICTEXTEND = 512
#ifset HUGOFIX
#set DEBUG
#endif

#ifset HDX
#switches -d
#endif

!:: Pre-Hugolib.h Constants

!:: Grammar Library Inclusions (grammar must come first)
! put your new grammar here

verb "answer"
* (phone)           DoAnswer

verb "call"
*               DoCall
* anything          DoCall

verb "flush"
*           DoFlush

verb "smell"
    *                   DoSmell
    * object            DoSmell

xverb "about","menu"
    *                   DoAbout

xverb "version"
    *               DoVersion

verb "hooray"
    *              DoHooray
synonym "sprawl" for "sit"

! new grammar needs to be defined before the including verblib
#include "verblib.g"    ! Verb Library

#include "hugolib.h"

!:: Other Library Inclusions
#ifset BETA
#include "beta.h"
#endif

#ifset GLK
#include "glk.h"
#endif

#include "window.h"
#include "system.h"
#include "newmenu.h"

!:: Other constants and global variables
constant IFID "E361278D-4306-4051-9E47-CC3F95CEE7B6"
global 1iswon
global 2iswon

!:: Game Initialization routine
routine init
{
    LoadConfig
    SaveConfig(1)
#ifset BETA
    BetaInit
#endif
        STATUSTYPE = 0  ! 0 = none :: 1 = score/turns :: 2 = time
        counter = -1
        TEXTCOLOR = BRIGHT_WHITE
        BGCOLOR = BLACK
        SL_TEXTCOLOR = RED
        SL_BGCOLOR = WHITE
        color TEXTCOLOR, BGCOLOR

        verbosity = 2   ! 1 = normal (rooms described only if not previously
                        !     described)
                        ! 2 = full (rooms described every time they are entered)
    if not 2iswon
        display.title_caption = "Halloween Horror"
    else
        display.title_caption = "Halloween Horror Part 2"
    prompt = ">"

        window 0 ! resets the windows in case the player is restarting a game
        cls

#ifset GLK
       glkcheck
#endif

    if (not glk)
        {
        locate 1,3
        }
        DEFAULT_FONT = PROP_ON
        Font(DEFAULT_FONT)

        !:: Opening Text
    if not 2iswon
        "This is your favorite part of the week, the only night where you can
    settle down with a big bowl of popcorn and zone out to a horror movie."
    else
        "Wow, that was a pretty rocking movie. Those reviewers on Quikster had
    no idea what they were talking about! You stand up and turn off the TV."

    print ""    ! For a blank line between the intro and the game title
    color LIGHT_RED
    Font(BOLD_ON)
    if not 2iswon
        "The Halloween Horror"
    else
        "The Halloween Horror Part II"
    Font(BOLD_OFF)
    color TEXTCOLOR
    "by Roody Yogurt"
    print "Release 1 / ";
    print BANNER
#ifset BETA
        string(_temp_string, serial$, 8)
    "BETA BUILD # 20";
    StringPrint(_temp_string, 6, 8)       ! if a BETA flag is set,
    StringPrint(_temp_string, 0, 2)       ! a build # in YEARMODY
    StringPrint(_temp_string, 3, 5)       ! format is printed.
    ".1"
#endif
    print "IFID: "; IFID
    "Type \BABOUT\b for more info"
#ifset BETA
    "\n(\INOTE:  This beta release is intended for testing only, not for
    distribution to the general public.  Please report any errors,
    bugs, etc. to the author. To make a comment, type \"\B* COMMENT TEXT\b\" at the prompt.\i)"
#endif
    player = you
    if not 2iswon
        location = STARTLOCATION
    else
        location = livingroom
    move player to location
    old_location = location
    FindLight(location)
    DescribePlace(location)
    location is visited
    CalculateHolding(player)
    if 2iswon
        {
        move bowl to you
        phone is special
        }
}

!:: Main game loop
routine main
{
    counter = counter + 1
    PrintStatusLine
    run location.each_turn
    runevents
    RunScripts
    if speaking not in location
        speaking = 0
}

!: Standard Library replacements

replace PreParse
{
        if display.needs_repaint
        {
        "[Detected screen size change. Press a key to redraw.]"
        pause
        cls
        if not glk
            {
            locate 1,3
            }
        PrintStatusLine
        display.needs_repaint = false
        }
}

! the room class - so each room can have a default DoListen response
replace room
{
    type room
    is static, light, open
    after
        {
        location DoListen
            {
            "You hear nothing special."
            }
        }
}

! DoListen - to support both object and room listening
replace DoListen
{
    if not object
        {
            if not location.after
                {
                VMessage(&DoListen, 1)  ! "Be a little more specific..."
                return false
                }
            verbroutine = ""
            return true
        }
    elseif not object.after
        VMessage(&DoListen, 2)   ! "Not making any sound..."
    ! we have to clear verbroutine or else location.after.DoListen will run again
    verbroutine = ""
    return true
}

! SpeakTo - this version doesn't change the speaking global if you
! just type the name of a nearby non-living thing. plus, no jumps.
replace SpeakTo(char)
{
    local TryOrder, IgnoreResponse
#ifset USE_CHECKHELD
    if verbroutine = &DoDrop_CheckHeld
        verbroutine = &DoDrop
    elseif verbroutine = &DoPutIn_CheckHeld
        verbroutine = &DoPutIn
#endif

#ifset VERBSTUBS
    if verbroutine = &DoHelpChar and object = player
    {
        verbroutine = &DoHelp
        object = nothing
    }
#endif

#ifset USE_CHECKHELD
    ResetCheckHeld
#endif

#ifset DEBUG
    if debug_flags & D_PARSE
    {
        print "\B[Speakto("; char.name;
        if (debug_flags & D_OBJNUM)
            print " ["; number char; "]";
        print ") verbroutine="; number verbroutine;
        print ", object="; object.name;
        if (debug_flags & D_OBJNUM)
            print " ["; number object; "]";
        print ", xobject="; xobject.name;
        if (debug_flags & D_OBJNUM)
            print " ["; number xobject; "]";
        print "]\b"
    }
#endif

!   old speaking = 0 position

    if char is not living
    {
        ParseError(6)
        return
    }

    ! new speaking = 0 position
    speaking = 0 ! so typing an object won't clear the speaking global

    AssignPronoun(char)

    ! Handle player/typist-related ParseError messages:
    if not FindObject(char, location)
    {
        actor = player
        ParseError(11, char)
        return
    }
    elseif char = player
    {
        actor = player
        Message(&Speakto, 1)    ! "Stop talking to yourself..."
        return
    }
    elseif not ObjectisKnown(object) and not FindObject(object, location)
    {
        actor = player
        ParseError(10, object)
        return
    }

    if char is unfriendly
        IgnoreResponse = true
    else
        {
        speaking = char

        ! In the event of:  >CHARACTER, GO NORTH.  GET THE THING.  GO WEST., etc.
        if not FindObject(char, location)
        {
            run char.order_response
            return true
        }

        select verbroutine
            case 0                  ! Just the character name is given,
                        ! so just "X is listening."
            {
                if not char.order_response
                    Message(&Speakto, 2, char)
            }

    #ifclear NO_VERBS
            case &DoHello           ! Note the ampersands ('&')--or else
            {                       ! the routines themselves would run
                if not char.order_response
                {
                    if char is not unfriendly
                        ! "X nods hello."
                        Message(&Speakto, 3, char)
                    else
                    {
                        IgnoreResponse = true
                    }
                }
            }

            case &DoAskQuestion
                return Perform(&DoAsk, char, object)

            case &DoTalk
            {
                if xobject
                    ParseError(6)
                else
                    return Perform(&DoAsk, char, object)
            }

            case &DoTell
            {
                if object = player
                    return Perform(&DoAsk, char, xobject)
                else
                    TryOrder = true
            }
    #endif  ! ifclear NO_VERBS

            case else
            {

    ! If the character can respond to a request, this should be dealt with by
    ! an order_response property routine; order_response--if it exists--should
    ! return false if there is no response for the given verbroutine

            TryOrder = true
            }
        }

    if TryOrder
            {
            if (not char.order_response)
                IgnoreResponse = true
            else
                return true
            }
    if IgnoreResponse
            {
            if not char.ignore_response
                Message(&Speakto, 4, char)      ! "X ignores you."
            }
    return false
}

! PrintStatusLine
replace PrintStatusline
{
   if display.linelength < 40
      display.statusline_height = 2
   else
      display.statusline_height = 1

   Font(BOLD_OFF | ITALIC_OFF | UNDERLINE_OFF | PROP_OFF)
   window display.statusline_height
   {
      color SL_TEXTCOLOR, SL_BGCOLOR
      cls
      locate 1, 1
      if not location
         print "_";
      elseif not light_source
         print "In the dark";
      else
      {
         if FORMAT & DESCFORM_F:  print "_";
         print capital location.name;
      }

! (The part we're changing)
!           print to 65; ! is 65 characters good for every window size? No!

! Instead, let's begin by writing the entire 'SCORE / MOVES' to array _temp_string
! (_temp_string is an array declared by the library)

                text to _temp_string
      if STATUSTYPE = 1
         print number score; " / "; number counter;
      elseif STATUSTYPE = 2
         print HoursMinutes(counter);
           text to 0
! Ok, we've closed off the string array

! Now, if the screen is wide enough, let's move to the end of the screen MINUS the length of the _temp_string array
! plus two extra spaces for good measure (so there's a little space to the right on the status bar)
      if display.statusline_height = 1
         print to (display.screenwidth - (StringLength(_temp_string) + 2));
      else
      {
         locate 1, 2
         if FORMAT & DESCFORM_F:  print "_";
      }

 ! Now let's print it!
      if STATUSTYPE = 1,2
                     StringPrint(_temp_string)
   }
   color TEXTCOLOR, BGCOLOR
   Font(DEFAULT_FONT)
}

! PrintEndGame - ending game text
replace PrintEndGame(end_type)
{
    Font(BOLD_ON)
    color GREEN
    select end_type
        case 1
            {
            print "\n*** LET'S WATCH A MOVIE! ***\n"
            "(Now go play Part II)"
            }
        case 2:  PRINT "\n*** YOU HAVE REACHED THE NADIR OF GREATNESS ***"
      case 3:  print "\n*** A WINNER IS YOU! ***"
    color TEXTCOLOR
    Font(BOLD_OFF)
!   PrintScore(true)
}

! DoRestart - added a settings-clearing choice
replace DoRestart
{
    VMessage(&DoRestart, 1)                  ! "Are you sure?"
    GetInput
    if YesorNo = true
    {
    word[1] = ""
    "Would you also like to flush the current settings? ";
    if (YesorNo)
        {
        FlushSettings
            ""
        "Settings flushed."
        }
    else
        "\nSettings not flushed.\n"
    "PUSH A KEY TO CONTINUE"
    PAUSE
        if not restart
            VMessage(&DoRestart, 2)  ! "Unable to restart."
    }
}

!: EndGame menu routines
! EndGame - Allow for a different keypress after game is over
replace EndGame(end_type)
{
   PrintStatusLine                 ! update one last time
   PrintEndGame(end_type)          ! print appropriate ending message

#ifclear NO_VERBS
   local r

   Message(&EndGame, 1,end_type)    ! ask to RESTART, RESTORE, (UNDO), or QUIT

   r = -1
   while r = -1
   {
   GetInput
   r = ProcessKey(word[1], end_type)
   if r = -1
         Message(&EndGame, 2,end_type)    ! ask again (more succinctly)
   }

   return r

#else   ! i.e., #elseif set NO_VERBS

   return 0;
#endif
}

! ProcessKey - helper routine for the above EndGame replacement
routine ProcessKey(entry,end_type)
{
   local r
   r = -1
   select entry
            case "restart", "r"
            {
               if restart
               {
                  r = 1
                  PrintStatusline
               }
   #ifclear NO_XVERBS
               else
                  Message(&DoRestart, 2)   ! failed
   #endif

            }
            case "restore", "e"
            {
   #ifclear NO_XVERBS
               if Perform(&DoRestore)
                  r = 1
   #else
               if restore
               {
                  r = 1
                  PrintStatusline
                  DescribePlace(location)
               }
   #endif
            }
   #ifclear NO_UNDO
            case "undo", "u"
            {
               if not UNDO_OFF
               {
                  if undo
                  {
                     r = true
                     PrintStatusLine
                     DescribePlace(location)
                  }
   #ifclear NO_XVERBS
                  else
                     Message(&DoUndo, 1)  ! failed
               }
               else
                  Message(&DoUndo, 1)
   #else
               }
   #endif
            }
   #endif
                case SpecialKey(end_type)
                    {
                    if entry
                        SpecialRoutine
                    }
            case "quit", "q"
            {
               r = 0
            }

   return r
}

! SpecialKey - routine for handling extra available keypresses or inputs
!   for EndGame
routine SpecialKey(end_type)
{
    if end_type = 3 and (word[1] = "s","special")
        {
        return word[1]
        }
    else
        return false
}

! SpecialRoutine - another routine for EndGame
routine SpecialRoutine
{
    if display.linelength > 62
        {
        MakeMenu(special_menu)
        ""
        cls
        if not glk
            {
            locate 1,3
            }
        print "The game has ended. ";
        }
    else
        {
            color CYAN
            "\n\IWhat was the point of the mid-game (the movie)? I won on my first
            try!\i"
            color TEXTCOLOR
            "The middle game was the author's somewhat feeble attempt to try to get the player to \BUNDO\b
            or \BSAVE\b (at a couple parts). If one does that, the game becomes unwinnable (usually).\n"
            "I hope you enjoyed the game!\n"
        }
}

! NewMessages - some new EndGame messages
replace NewMessages(r, num, a, b)
{
       select r
         case &EndGame
            {
            select num
                case 1
                    {
                    select a
                        case 3
                            {
                            print "\nThe game has ended.  Do you want to (R)ESTART,
                            R(E)STORE a saved game, (S)pecial notes, or (Q)UIT? ";
                            return true
                            }
                        case else: return false
                    }
                case 2
                    {
                    select a
                        case 3
                            {
                            print "Do you want to (R)ESTART,
                            R(E)STORE a saved game, (S)pecial notes, or (Q)UIT? ";
                            return true
                            }
                        case else: return false
                    }
            }
        case else : return false
}

!:: Game objects
player_character you "you"
{
    long_desc
        {
        if not 2iswon
            "You are just happy to have made it through the week and are intent on
            enjoying a night to yourself."
        else
            "Sated by popcorn and a good movie, you contentedly wonder what else
            the night holds for you."
        }
}

object phone "cellphone"
{
    article "your"
    noun "phone" "cellphone"
    adjective "cell"
    long_desc
        "You are a protagonist of modern times, one who almost always has a
        cellphone handy."
    before
        {
        object DoSwitchOn
            {
            "It's already on."
            }
        object DoSwitchOff
            {
            "Nah, you like to keep it on. It has plenty of battery power left."
            }
        object DoDrop
            {
            "Nah, you'd rather hold on to it."
            }
        }
    in you
    misc 0
}

room STARTLOCATION "Kitchen"
{
    long_desc
        "Your kitchen is pretty sparse. The living room is to the east."
    extra_scenery  "table" "shelf"
    e_to {
        if microwave is switchedon
            "Better wait for the popcorn to finish."
        else
            return livingroom
        }
    each_turn   {
            if microwave is switchedon
                {
                ""
                select micropop.misc
                    case 1 : "\"Pop.\" Some kernals are beginning to pop."
                    case 2 : "\"Pop. Pop.\""
                    case 3
                            {
                            "\"Pop. Pop. Pop.\""
                            PhoneCall
                            microwave is not switchedon
                            remove micropop
                            move popped to microwave
                            }
                }
            }
    after
        {
        location DoListen
            {
            if microwave is switchedon
                {
                if micropop.misc < 2
                    {
                    "You can hear the quiet hum of the microwave."
                    }
                else
                    "You can hear the hum of the microwave and the occasional
                    popping of corn."
                }
            else
                return false
            }
        location DoSmell
            {
            if micropop.misc < 2
                {
                return false
                }
            elseif micropop.misc < 3
                "The air begins to smell of popcorn."
            else
                "The smell of fresh popcorn permeates the air."
            }
        }

}

object microwave "microwave"
{
    article "the"
    noun "microwave" "oven"
    adjective "microwave"
    long_desc
        {
        "Ah, time-saving applications. How you love them! This is one of those
        fancy models where all you have to do is put food into it and turn it on.
        It is currently ";
        if self is open
            {
            "open ";
            }
        else
           "closed ";
        "and ";
        if self is switchedon
            {
            "on";
            }
        else
            "off";
        "."
        }
    short_desc
         "All that is worth noting is the microwave that sits on an
        unimplemented shelf."
    before
        {
        object DoOpen
            {
                if self is switchedon
                    "You better wait for it to finish popping first."
                else
                    return false
            }
        object DoSwitchOn
            {
                if parent(micropop) ~= self
                    "Nothing in the microwave needs zapping!"
                else
                    {
                    if self is open
                        {
                        "(closing the microwave first)"
                        self is not open
                        }
                    "You turn on the microwave."
                    self is switchedon
                    }
            }
        object DoSwitchOff
            {
            if self is switchedon
                "Nah, it'll turn off by itself."
            else
                return false
            }
        }
    after
        {
        object DoListen
            {
            if switchedon
                "Hum."
            else
                return false
            }

        xobject DoGet
            {
            if object = popped
                {
                "You pull the popcorn out of the microwave and pour it into a bowl
                you had lying around. You are no longer lacking in popcorn!\n"
                "You remember your mysterious caller for a moment, but whatevs- out of sight, out of mind."
                Acquire(you, popped)
                }
            else
                return false
            }
        }
    in startlocation
    capacity 100
    is container transparent switchable static openable
}

object popped "popped popcorn"
{
    article "some"
    noun "popcorn" "bowl"
    adjective "of" "popped" "freshly-popped"
    long_desc
        "Perfectly-popped popcorn. Hooray!"
    before
        {
        object DoDrop
            {
            "Not after all of that \Iwork\i, you don't."
            }
        object DoEat
            {
            "Better wait until you're on the couch."
            }
        object DoSmell
            {
            "Smells num-num-derful!"
            }
        }
}

object micropop "uncooked microwave popcorn"
{
    article "some"
    adjective "uncooked" "microwave"
    noun "packet" "popcorn"
    long_desc
        "This is one of those packets of microwave popcorn, all ready to be
        microwaved."
    in startlocation
    size 5
    misc 0
    before
        {
        object DoEat
            {
            "It'd be best to microwave it first."
            }
        object DoOpen
            {
            "The packet is already unwrapped. It's all ready to be
            microwaved!"
            }
        }
    short_desc
        "A packet of microwave popcorn lies here unawares."
    is openable
}

event in microwave
{

    if microwave is switchedon
        {
        event_flag = 2
        "The microwave hums away."
        micropop.misc = ++micropop.misc
        }
}

room livingroom "Living Room"
{
    long_desc
        {
        "This room has two things that you love dearly, locked in an eternal
        cage match for your affection. In one corner, there's the TV that holds
        all of the movies and shows you love. In another corner (well, actually,
        the middle of the room), there's the couch upon which you like to
        sprawl.\n"
        Indent
        "The kitchen is to the west. The patio is to the east."
        if patiolight is special
            {
            ""
            }
        }
    w_to
        {
        if not 2iswon
            return startlocation
        else
            "You aren't hungry for anything else, and dishes can wait until
            tomorrow."
        }
    e_to
        {
        "Nah, this is your night \Iin\i."
        }
    d_to
        {
        "(sitting down on the couch)"
!       if parent(player) = couch
!           {
!           "You are already sitting down."
!           }
!       else
            Perform(&DoEnter, couch)
        }
    each_turn
        {
        if player in couch and tv is switchedon and popped in player
            {
            1iswon = true
            SaveConfig
            "\nArmed with popcorn with the TV on, sitting on your favorite seat in
            the house, you are ready for a relaxing night in!"
            endflag = 1
            }
        }
    before
        {
        location DoEnter
            {
            if (not object) or object = d_obj
                {
                object = couch
                return false
                }
            else
                return false
            }
        }
}

event in livingroom
{
    if not 2iswon
        return false
    if phone is special
        {
        phone.misc++
        select phone.misc
            case 1: "\nYour phone starts ringing."
            case else : "\nYour phone is ringing. Maybe you should answer it?"
        }
}

object bowl "empty bowl"
{
    article "an"
    adjective "empty"
    noun "bowl"
    long_desc
        "Man, that popcorn was \IYUM\i."
    before
        {
        object DoEat
            {
            "The popcorn is long gone."
            }
        object DoSmell
            {
            "There's the faint reminder of popcorn."
            }
        }
}

scenery patiolight "patio lights switch"
{
    article "the"
    adjective "patio" "light" "lights"
    noun "light" "switch"
    is switchable
    in livingroom
    before
        {
        object DoSwitchOn
            {
            if self is not special
                "You have no reason to turn on the patio lights."
            else
                {
                "With great trepidation, your shaky finger reaches for the patio
                light switch. Your curiosity eventually overcomes your fear, and the
                intensity of the situation is punctuated by the switch's
                \"CLICK.\"\n"
                "The patio is flooded with light, and with horror, you see that
                somebody has set up your garden chairs in several rows holding giant
                letter signs that, altogether, read, \"HAPPY HALLOWEEN!\" What kind
                of madman would do that?\n"
                "Oh, well, the important thing is-"
                self is switchedon
                endflag = 3
                }
            }
        }
}

scenery patio "patio"
{
    article "the"
    noun "patio"
    is enterable
    before
        {
        object DoEnter
            {
            return livingroom.e_to
            }
        }
    in livingroom
}

scenery tv "television"
{
    article "the"
    noun "tv" "television"
    is switchable
    long_desc
        "Your trusty TV."
    in livingroom
    before
        {
        object DoSwitchOn
            {
            if 2iswon
                "You have already watched enough TV for tonight."
            else
                return false
            }
        }
    after {
        object DoSwitchOn
            {
            "You turn the TV on, ready for a night of watching scary movies."
            }
        object DoSwitchOff
            {
            "You turn the TV off."
            }
        }
}

scenery couch "couch"
{
    article "the"
    noun "couch"
    is platform enterable
    long_desc
        "Your trusty couch."
    in livingroom
    before
        {
        object DoEnter
            {
            if 2iswon
                "You have already watched enough TV tonight."
            elseif tv is not switchedon
                {
                "The TV isn't on yet!"
                }
            elseif parent(popped) ~= you
                {
                "You don't have any popped popcorn!"
                }
            else
                return false
            }
        }
    after
        {
        object DoEnter
            {
            "You plop down on the couch. Ahhhhhh!"
            }
        }
}

object movie
{
misc 0
}

!:: Misc. routines
routine PhoneCall
{
    "Suddenly, your phone rings. You answer it.\n"
    Indent
    "\"Hello?\" you say.\n"

    "A voice full of gravel and malice answers you with a question, \"WHAT'S YOUR FAVORITE SCARY IF GAME??\"\n"

    "Huh, good question.\n"
    if (glk)
        GlkName()  ! do the glk-interpreter method of getting IF title
    else
        {
        Font(PROP_OFF)
        ScaryCoolPrompt
        Font(DEFAULT_FONT)
        }
!   WriteNameToDict
    Indent
    "\"";
!   print movie.name ;
    StringPrint(name_array)
    ",\" you say.\n"
    "Ding! The microwave beeps.\n"
    Indent
    "\"Popcorn's done! Gotta go!\" you say, hanging up on your probably-perplexed caller.\n"
    microwave is open
    "You open the microwave, revealing some freshly-popped popcorn."
    AssignPronoun(popped)
}

!:: The non-glk method of entering the 'scary IF' text
routine ScaryCoolPrompt
{
word[1] = ""
while (word[1] ~= "yes", "y")
    {
    ClearArray(name_array)
    DrawWindows
    Font(DEFAULT_FONT)
    if (name_array[0] ~= 0)
        {
        print "\"";
        StringPrint(name_array)
        "\#148? Is that correct? ";
        word[1] = ""
        if (not YesOrNo)
            {
            ""
            ClearArray(name_array)
            }
        }
    }

    ""
    "(Okay, good.)"
    ""
}

routine DrawWindows
{
    run border_window.win_init
    window
    {
    run border_window.win_clear
    }
    run border_window.win_end
    run text_window.win_init
    window
    {
    run text_window.win_clear
    Font(PROP_OFF)
    locate 2,1

    "ENTER FAVORITE SCARY IF GAME TITLE:"
    locate 3,3
    FakePrompt(name_array)
    Font(DEFAULT_FONT)
    run text_window.win_clear
    }

    run text_window.win_end
    run cover_window.win_init
    window
    {
    run cover_window.win_clear
    }
    run cover_window.win_end
    window 0
    PrintStatusLine
}

window_class cover_window!  window to cover everything when we are done
{
    win_left
        return (display.screenwidth / 2 - 22) ! leftmost column
    win_top
        return (display.screenheight /2 - 3)! topmost row
    win_right
        return (display.screenwidth / 2 + 22) !rightmost column
    win_bottom
        return (display.screenheight /2 + 2) ! bottommost row

    win_textcolor
        return BGCOLOR    ! text color for any output
    win_backcolor
        return BGCOLOR    ! background color

}

window_class border_window! window providing the border
{
    win_left
        return (display.screenwidth / 2 - 22) ! leftmost column
    win_top
        return (display.screenheight /2 - 3)! topmost row
    win_right
        return (display.screenwidth / 2 + 22) !rightmost column
    win_bottom
        return (display.screenheight /2 + 2) ! bottommost row

    win_textcolor
        return BGCOLOR    ! text color for any output
  win_backcolor
        return SL_TEXTCOLOR    ! background color

}

window_class text_window ! window where text will go
{
    win_left
        return (display.screenwidth / 2 - 21) ! leftmost column
    win_top
        return (display.screenheight /2 - 2)! topmost row
    win_right
        return (display.screenwidth / 2 + 21) !rightmost column
    win_bottom
        return (display.screenheight /2 + 1) ! bottommost row

    win_textcolor
        return TEXTCOLOR   ! text color for any output
    win_backcolor
        return BGCOLOR    ! background color
}

routine FakePrompt(array_to_fill)
{

    local a, key, letters,c,r,f
    c = display.cursor_column
    r = display.cursor_row
    array array_to_fill[0] = 0
    for (f = 0;f< array array_to_fill[] ; f++ )
        {
        array array_to_fill[f] = 0
        }

    while not key
        {
            locate c, r
            a++
            key = system(READ_KEY)
            if key = ENTER_KEY
                {
                Asteriskcheck(a,c,r)
                break
                }
            elseif key = 8 or key = 516 ! should be backspace
                {
                if (letters and display.cursor_column = 1)
                    {
                    Asteriskcheck(a,c,r)
                    c = display.linelength !- 1
                    locate c, --r
                    print " ";
                    array array_to_fill[--letters] = 0
                    locate --c
                    }
                elseif (letters)
                    {
                    print " ";
                    array array_to_fill[--letters] = 0
                    locate (c - 1)
                    print " ";
                    locate --c
                    }
                }
            elseif key > 31 and key < 127
                {
                if ((display.cursor_column + 1) < display.linelength)
                    {
                    array array_to_fill[letters++] = key
                    printchar key
                    c++
                    if (a>50)
                        print "*";
                    locate c
                    }
                elseif ((display.cursor_row ) < display.windowlines)
                    {
                    Asteriskcheck(a,c,r)
                    c = 2
                    r++
                    locate c,r
                    array array_to_fill[letters++] = key
                    printchar key
                    c++
                    if (a>50)
                        print "*";
                    locate c,r
                    }
                }
                if a=50
                    {
                    print "*";
                    }
                elseif a = 100
                    {
                    Asteriskcheck(a,c,r)
                    a = 0
                    }
                system_status = 0
                key = 0
                system(PAUSE_100TH_SECOND)
        }
}
    routine Asteriskcheck(a_position,cursor,row)
    {
        if (a_position>50)
            {
            print " ";
            locate (cursor)
            return true
            }
    }

!:: The glk method of entering the 'scary movie' text
routine GlkName()
{
    ClearArray(name_array)
    GetInput("ENTER FAVORITE SCARY IF GAME IN QUOTES>")
    while true
        {
        local len

        len = string(name_array, parse$, 270)    ! maximum 49 char.
        if (word[1])
            {
            len = string(name_array, word[1], 270)
            }

         if not len
            {
            "No, really, what's your favorite scary IF game?"
            GetInput("FAVORITE SCARY IF GAME IN QUOTATION MARKS>")
            }
        else
            {
            Lowercase(name_array)
            CapitalizeFirstLetter(name_array)
            "\"";
            StringPrint(name_array)
            "\"? Is that correct (did you remember the quotation
            marks?)?"
            word[1] = ""
            if (YesOrNo)
                {
                "(Okay, good.)"
                ""
                break
                }
            else
                {
                ClearArray(name_array)
                GetInput("FAVORITE SCARY IF GAME IN QUOTATION MARKS>")
                }
            }
        }
}

routine Lowercase(stringarray)
{
    local len, i
    len = StringLength(array stringarray)
    for (i=0; i<len; i=i+1) ! the actual case-conversion loop
        {
        if array stringarray[i] >= 'A' and array stringarray[i] <= 'Z'
            array stringarray[i] = array stringarray[i] + ('a'-'A')
        }
}

routine CapitalizeFirstLetter(stringarray)
{
    local len, i, new
    len = StringLength(array stringarray)
    for (i=0; i<len; i=i+1) ! the actual case-conversion loop
        {
        if new or i=0
            {
            if array stringarray[i] >= 'a' and array stringarray[i] <= 'z'
                array stringarray[i] = array stringarray[i] - ('a'-'A')
            new = 0
            }
        elseif array stringarray[i] >= 'A' and array stringarray[i] <= 'Z'
            array stringarray[i] = array stringarray[i] + ('a'-'A')

        if array stringarray[i] = ' '          ! a space
            new = 1
        }
}

!:: routines used by both methods
routine ClearArray(array_to_clear)
{
    local f
    for (f = 0;f< array array_to_clear[] ; f++ )
        {
        array array_to_clear[f] = 0
        }
}

!routine WriteNameToDict
!{
!        movie.name = dict(name_array, 270)
!}

!:: Configuration routines
array name_array[270]

routine LoadConfig
{
    local test2
    readfile "gamedata"
        {
        local a
        for (a=0;a<=49;a++)
            {
            name_array[a] = readval
            }
    !   movie.name = dict(name_array, 49)
        1iswon = readval
        2iswon = readval
        test2 = readval
      }
   if test2 ~= FILE_CHECK
        {
  !        print "Error reading file."
      }
}

routine SaveConfig(intro)
{
    local test2
    writefile "gamedata"
        {
        local a
!       text to name_array
!       print movie.name;
!       text to 0
        for (a=0;a<=49;a++)
            {
            writeval name_array[a]
            }
        writeval 1iswon
        writeval 2iswon

        test2 = FILE_CHECK
        writeval test2
        }
     if test2 ~= FILE_CHECK  ! if the program didn't get this far, we know
          {          ! something is wrong
             if (intro)
                {
                !\
                "The game detects that you are playing this Hugo file in a glk
                environment. \IThe Halloween Horror\i will \Bnot\b play correctly in
                Gargoyle. Push \"Q\" to quit if you are using Gargoyle. Otherwise,
                push any other key to continue." \!
                "A cursory test indicates that this interpreter does not support the
                saving of configuration files, a required feature for
                \IThe Halloween Horror\i. Maybe now would be a good time to try Hugor (http://ifwiki.org/index.php/Hugor)!\n"

                "PRESS ANY KEY TO QUIT"
                 pause
                 quit
                }
            else  ! this other case will probably never be called
                {
                 ""
                 print "\B[ SETTINGS COULD NOT SAVE. YOU ARE NOT USING AN
                             INTERPRETER CAPABLE OF THIS GAME. ]\b"
                }
          }
}

routine FlushSettings
{
    writefile "gamedata"
    {
    local a,test2
    for (a=0;a<=49;a++)
        {
        writeval 0
        }
    writeval 0
    writeval 0

    test2 = FILE_CHECK
    writeval test2
    }
}

!:: Verb routines
routine DoAnswer
{
    if phone is not special
        "Your phone is not ringing."
    else
        {
        phone is not special
        "You answer the phone. You are greeted by the same ominous voice.\n"

        "\"You know, it is rude to hang up on people like that! Just the same,
        I've got a surprise for you. Turn on your patio lights!\" the voice
        commands.\n"

        "The line goes dead."
        patiolight is not hidden
        patiolight is special
        }
}

routine DoCall
{
    "You have no one to call."
}

routine DoSmell
{
    if not object
        {
            if not location.after
                {
!               VMessage(&DoListen, 1)  ! "Be a little more specific..."
                "You don't smell anything of note."
                return true
                }
            verbroutine = ""
            return true
        }
    elseif not object.after
        "You can't discern any smell."
!       VMessage(&DoListen, 2)   ! "Not making any sound..."
    ! we have to clear verbroutine or else location.after.DoListen will run again
    verbroutine = ""
    return true
}

routine DoHooray
{
    "Yes, hooray!"
    return false
}

routine DoAbout
{
    MakeMenu
}

routine DoVersion
{
    color LIGHT_RED
    Font(BOLD_ON)
    if not 2iswon
        "The Halloween Horror"
    else
        "The Halloween Horror Part II"
    Font(BOLD_OFF)
    color TEXTCOLOR
    "by Roody Yogurt"
    print "Release 1 / ";
    print BANNER
    print "IFID: "; IFID
    "Type \BABOUT\b for more info"
}

routine DoFlush
{
    "Restart the game and flush all of the settings? ";
    if (YesorNo)
        {
        FlushSettings
        if not restart
            VMessage(&DoRestart, 2)  ! "Unable to restart."
        }
    else
        "Ok, then."
}

!:: Menu stuff
object main_menu "The Halloween Horror"
{
    title_gap 1
    options_gap 1
}

option history_choice "History"
{
    in main_menu    ! which menu it is
    menu_text   {
            ""
            "_ This game was originally released as \"The Ecto Horror\" on the sly
            in 2011. It was written for Duncan Bowsman's EctoComp, but
            as it was written the day \Iafter\i games were due, it was not an
            official submission.\n"
            "_ A couple of the ideas for the game were first intended for a
            submission to the Saugus Comp (http:/www.saugus.net), an annual
            Halloween game contest, but the Saugus Comp only accepts games compiled
            to z-code so the ideas were shelved.\n"
            "_ Anyhow, I am glad to clean up some of the problems with the
            original release, which was written in 5 hours, breaking \Ianother\i
            one of
            the EctoComp's rules (although I like to think that this game
            counts as more than one game, teehee). Hopefully, it'll bring
            some entertainment to more people now that it is more likely to work
            correctly.\n"
            CoolPause(1)
            }
}

option commands_choice "Special Commands"
{
    in main_menu    ! which menu it is

    menu_text   {
            ""
            "_ This game saves a configuration file. To clear this file and
            begin the game with a clean slate, type >FLUSH.\n"
            CoolPause(1)
            }
}

option credits_choice "Credits"
{
    in main_menu    ! which menu it is

    menu_text   {
            ""
            "First, I'd like to thank Kent Tessman for providing the Hugo
            system and its library!\n"
            "Thanks to Mike Snyder for laying down the groundwork for such
            things like optimising games for glk interpreters and other little
            tips and tricks.\n"
            "Thanks to Royce Odle for hosting and setting up Hugo by Example,
            the best Hugo code repository on the net!\n"
            "Thanks to Robb Sherwin for setting a great example for all other
            Hugo authors!\n"
            "Thanks to the people at ClubFloyd ( http://www.ifwiki.org/index.php/ClubFloyd ) and Paul Lee for giving me
            transcripts, resulting in the slightly-more-polished game you have
            before you!\n"
            "Lastly, thanks to \Byou\b for playing this!\n"
            CoolPause(1)
            }
}

option contact_choice "Contact"
{
    in main_menu    ! which menu it is

    menu_text   {
            ""
            "_ Feel free to send me your thoughts and suggestions at
         roody.yogurt@gmail.com! What an amazing discourse we will
         have!\n"
            CoolPause(1)
            }
}

object special_menu "Special Notes"
{
    title_gap 1
    options_gap 1
}

option movie_choice "\IWhat was the deal with the movie? I beat it on my first try!\i"
{
    in special_menu    ! which menu it is

    menu_text   {
            ""
            "The concept behind the mid-game is that if the player uses \BUNDO\b
            or \BSAVE\b, the game becomes unwinnable (usually).\n"
            "So, not exactly fair, but I just wanted to do something that'd make
            people scratch their heads for a while.\n"
            CoolPause(1)
            }
}

option killer_choice "\IWhat was the deal with the sleeping killer guy?\i"
{
    in special_menu    ! which menu it is

    menu_text   {
            ""
            "That part is a silly homage to the horror game \"House of the
            Stalker\" by Jason Clayton White. ";
            "In that game, you also dispense of the bad guy in somewhat odd
            circumstances.\n"
            CoolPause(1)
            }
}

option files_choice "\IWhy break the game into two files?\i"
{
    in special_menu    ! which menu it is

    menu_text   {
            ""
            "It is true that the game could easily have been coded all
            in one file. The two-file design
            was mostly a proof-of-concept thing (although I \Ido\i think
            that without the gimmick, the resulting movie name in the
            midgame would be that much less cool).\n"
            "I hope people don't mind too much.\n"

            CoolPause(1)
            }
}

option code_choice "\IIs the code for this game available somewhere?\i"
{
    in special_menu    ! which menu it is

    menu_text   {
            ""
            "Why, yes, it is! Go check out the \"Example Games\" section
            at Hugo by Example ( http://hugo.gerynarsabode.org ).\n"

            CoolPause(1)
            }
}