#import "lib.ih"
#import "doors.ih"
#import "debug.ih"
#import "switches.ih"

! Alice Through the Looking Glass Implementation
! Shamelessly stolen from Gareth Rees' tutorial to see if it
! was possible in IAGE.

LibraryMessage 1 "<br><b>THROUGH THE LOOKING GLASS</b>
                 <br><i>An interactive tutorial by Gareth Rees</i>"

LibraryMessage 200 "<br>
                   <BGCOLOR black>
                   <font color=green>
                   <CLEARSCREEN>
                   <br>
                   It's a cold winter day outside, but in the looking-glass
                   house it's summer. All you need to do is pretend there's a way of
                   getting through into it somehow...<br><WAITKEY>"

LibraryMessage 201 "<br>1. About this game
                   <br>2. About the implementation of this game
                   <br>3. What am I supposed to do?
                   <br><br>Please enter 1, 2 or 3 ------->"

LibraryMessage 202 "This game was written by Gareth Rees as a tutorial
                   for the Inform design system.
                   <br><br>The IAGE port was written by Robin Rawson-Tetley,
                   partly as an aid for anyone wanting to write complex
                   games with IAGE, and partly as a proof of concept to
                   show how good IAGE is."

LibraryMessage 203 "This implementation covers everything in Gareth's original
                   tutorial (http://www.gnelson.demon.co.uk/inform/alice/index.html).
                   I did not implement the mirror reflection code because the puzzle
                   design ensures that you would never be able to see anything
                   in the mirror anyway (so it made little sense to me)."

LibraryMessage 204 "The objective is to enter the looking glass - you need to find
                   some way of occupying the kittens to move the chair over to it..."

GameCode {
       Name "Alice"
       MaxItemsCanCarry 10
       MaxWeightCanCarry 10
       MaxSizeCanCarry 10
       StartingLocation drawingroom
       Verbose yes
       ShowAvailableExits no
       AllowPersist no
       SinglePlayerGame yes
       MaxUsers 1
       OverrideSecondaryNouns "66 68 69"
       UsingIAGECombat no
       UsingIAGEMoney no
       WideInventoryDisplay yes
       RealTimeNPCs no
       PlayersStayDead yes
       NPCsStayDead yes

       Initialise: CodeExtend [
               ' Verbs for untangling the worsted
               addverb 150 untangle
               addverb 150 wind
               ' Verbs for help menu
               addverb 4 about
               addverb 4 info
       ]


       Start: Override [

               ' Change name
               currentplayer.name = "Alice"

               ' Opening message
               message(200).show

               ' Show the game version, the library version
               ' and output the start location to the player

               game.displayversion
               call StandardLib.DisplayLibraryVersion
               game.displaycurrentlocation

               ' default male/female pronouns
               call NPCPronouns.init
       ]

       Score: Override [
               currentplayer.print |"Alice has made " & currentplayer.turns & " moves."|
       ]

       DisplayBanner: Override [
               ' Display score / turns
               returnvalue = |"Moves: " & currentplayer.turns|
       ]

       AfterInput: Override [

               ' Overriding this in library because I do not want tight
               ' scope checking - we will be handling this ourselves.

               ;help,about,info
                       var pans = ask message(201).text
                       if ( pans = 1 ) then
                               message(202).show
                       endif
                       if ( pans = 2 ) then
                               message(203).show
                       endif
                       if ( pans = 3 ) then
                               message(204).show
                       endif
                       end
               endif

               ' This line calls the standard AfterInput library, which generates
               ' stock responses. You can edit these responses by changing the
               ' messages 1 - 200
               call StandardLib.AfterInput
       ]
}

Location drawingroom "Drawing Room" {
       has light
       Nouns "snow"
       Description "The gentle sound of snow against the window pane
           suggests that it's cold outside, and you're glad to be here
           in the warmth. The drawing-room is reflected in the large
           looking-glass on the wall above the mantelpiece, and a very
           comfortable room it is too, with a warm hearth, a soft rug,
           and an arm-chair that you can curl up and sleep in."

       OnInput: [

               ;examine
               else
                       if ( input.noun = 0 ) or ( input.noun = 2 ) then
                               end
                       endif
                       var nono = getitemfromnoun input.noun
                       if ( nono <> 0 ) then
                               if ( currentplayer.stateitem <> 0 ) and ( item(nono).currentlocation = drawingroom.id ) then
                                       if ( nono = mantelpiece.id ) or ( nono = armchair.id ) or ( nono = rug.id ) then
                                               end
                                       endif
                                       var psti = currentplayer.stateitem
                                       if ( nono = mirror.id ) and ( psti = mantelpiece.id ) then
                                               end
                                       endif
                                       currentplayer.print |"You can't reach the " & item(nono).thename & " from the " & item(psti).thename & "."|
                                       end
                               endif
                       endif
               endif
       ]
}

Item redqueen "a red queen" {
       Nouns "red" "queen"
       Description "She's a fierce little chess piece."
       OnAction: [

               end
               proc before_displayinitial
                       if ( whitekitten.getvalue(state) <> 2 ) and ( blackkitten.getvalue(state) <> 2 ) then
                               returnvalue = "There is a red queen here."
                               cancelevent
                       else
                               returnvalue = " "
                               cancelevent
                       endif
               end

               proc before_insert
                       if ( input.noun2 = chessboard.nounid ) then
                               returnvalue = "Alone on the chess board, the red queen is monarch of all she surveys."
                               end
                       endif
               end

               proc before_get
                       if ( whitekitten.getvalue(state) = 2 ) then
                               whitekitten.setvalue(state) = 1
                       endif
                       if ( blackkitten.getvalue(state) = 2 ) then
                               blackkitten.setvalue(state) = 1
                       endif
               end

               proc after_get
                       this.movedfromoriginallocation = false
               end
               proc after_drop
                       this.movedfromoriginallocation = false
               end
       ]
}

Item chessboard "a chess board" {
       StartsIn drawingroom
       Size 2
       has supporter
       Nouns "chess" "board" "checker" "chequer" "chessboard"
       Initial "An abandoned chess board lies on the floor."
       Description "It's left here from the game you were playing just
           now, but the pieces are all missing - the kittens will insist
           on playing with them."
}

Item hearth "the hearth" {
       StartsIn drawingroom
       has scenery
       Nouns "hearth" "fire" "place" "fireplace"
       Description "Looking at the hearth, you wonder if they have a
           hearth in the looking-glass house. You can never tell by
           looking, unless your fire smokes, and then smoke comes up in
           the looking-glass room too - but that may be only pretence,
           just to make it look as if they had a fire."
}

Item rug "rug" {
       Nouns "hearthrug" "hearth-rug" "rug" "indian" "arabian" "beautiful" "soft"
       StartsIn drawingroom
       Size 2
       StaticMessage "The rug is much too large and heavy for you to carry."
       has invisible static supporter stand sit lay
       Description "It's a beautiful rug, made in some far off country,
                    perhaps India or Araby, wherever those might be."

       OnAction: [

               ;push,pull
                       currentplayer.print "But a hearth-rug is meant to be next to the hearth!"
                       end
               endif
               ;look
                       #under
                               if ( currentplayer.stateitem = this.id ) then
                                       currentplayer.print "You try to lift up a corner of the rug, but fail. After a while, you realise that this is because you are on top of it. How curious the world is!"
                                       end
                               else
                                       if ( this.getuserboolean(foundqueen) = false ) then
                                               currentplayer.print "You lift up a corner of the rug and, peering underneath, discover the red queen from the chess set.<br>(Taken)"
                                               redqueen.currentlocation = currentplayer.containerlocation
                                               end
                                       endif
                               endif
                       endif
               endif
       ]
}

Item armchair "arm-chair" {
       StartsIn drawingroom
       Size 2
       has static invisible supporter stand sit lay
       Nouns "arm" "chair" "armchair" "arm-chair"
       Description "It's a huge arm-chair, the perfect place for a kitten
                    or a little girl to curl up in and doze."

       OnAction: [

               ;push,pull

                       if ( currentplayer.stateitem <> 0 ) then
                               currentplayer.print |"You'll have to get off the " & item(currentplayer.stateitem).thename & " first."|
                               end
                       endif

                       if ( whitekitten.currentlocation = currentplayer.containerlocation ) or ( blackkitten.currentlocation = currentplayer.containerlocation ) then
                               currentplayer.print "Not with a kitten in your arms!"
                               end
                       endif

                       var kitway = 0
                       if ( whitekitten.getvalue(state) = 1 ) then
                               kitway = whitekitten.id
                       endif
                       if ( blackkitten.getvalue(state) = 1 ) then
                               kitway = blackkitten.id
                       endif

                       if ( kitway <> 0 ) then
                               currentplayer.print |"You are about to start moving the chair when you notice that the " & item(kitway).thename & " is right in the way. It's a good thing you spotted it, or you would have squashed flat the poor little thing."|
                               end
                       endif

                       if ( this.getuserboolean(byhearth) = true ) then
                               currentplayer.print "You push the arm-chair away from the hearth."
                               this.removeuserboolean(byhearth)
                               end
                       else
                               currentplayer.print "You push the arm-chair over to the hearth."
                               this.adduserboolean(byhearth)
                               end
                       endif
               endif

               ;examine
                       var oput = "It's a huge arm-chair, the perfect place for a kitten or a little girl to curl up in and doze. It has been pushed over to the "
                       if ( this.getuserboolean(byhearth) = true ) then
                               oput = |oput & "fireplace."|
                       else
                               oput = |oput & "window."|
                       endif
                       currentplayer.print oput
                       end
               endif
       ]
}

Item mantelpiece "mantelpiece" {
       StartsIn drawingroom
       has invisible supporter stand
       Size 2
       Nouns "mantel" "mantelpiece"
       Description "It's higher off the ground than your head, but it
           looks wide enough and sturdy enough to support you."

       OnAction: [

               ;climb,stand

                       if ( currentplayer.stateitem <> armchair.id ) then
                               currentplayer.print "The mantelpiece is much too high to climb up onto."
                               end
                       else
                               if ( armchair.getuserboolean(byhearth) = false ) then
                                       currentplayer.print "You can't reach the mantelpiece from here."
                                       end
                               endif
                               if ( currentplayer.itemscarried > 0 ) then
                                       currentplayer.print "Your hands are too full."
                                       end
                               endif
                       endif
               endif

               ;put
                       if ( currentplayer.stateitem <> armchair.id ) and ( currentplayer.stateitem <> mantelpiece.id ) then
                               currentplayer.print "The mantelpiece is so high that you can't reach."
                               end
                       endif
               endif
       ]
}

Item mirror "the looking-glass" {
       StartsIn drawingroom
       has static invisible
       Nouns "mirror" "looking" "glass" "looking-glass"

       OnAction: [

               ;examine
                       if ( currentplayer.stateitem = mantelpiece.id ) then
                               currentplayer.print "Strangely, the glass is beginning to melt away, just like a bright silvery mist."
                               end
                       endif
                       if ( currentplayer.stateitem = armchair.id ) then
                               currentplayer.print "In the looking-glass you can see the drawing-room of the looking-glass house. What you can see is very much the same as this drawing-room, only all reversed, left for right. But you are sure that out of the corners of the glass, where you can't see, the looking-glass world is quite different from yours."
                               end
                       endif
                       currentplayer.print "In the looking-glass you can see the ceiling of the drawing-room of the looking-glass house. It looks much the same as the ceiling of your drawing-room."
                       end
               endif

               ;throw
                       currentplayer.print "You don't want seven years' bad luck, do you?"
                       end
               endif

               if ( currentplayer.stateitem <> mantelpiece.id ) then
                       currentplayer.print "You can't reach the looking-glass from where you're standing."
                       end
               endif

               ;touch,pull,push
                       currentplayer.print "Your hand goes right through the silvery mist!"
                       end
               endif

               ;go,get
                       #in
                               currentplayer.print "Your hand goes right through the silvery mist, and in another moment the rest of you follows, and you are through the glass..."
                               call StandardLib.Won
                               end
                       endif
               endif
       ]
}

Item worsted "a ball of worsted"
       StartsIn drawingroom
       Initial "Worsted"
       Nouns "ball" "of" "worsted" "fine" "blue" "wool"

       OnAction: [
               ;examine
                       if ( this.getuserboolean(rolledup) = false ) then
                               currentplayer.print "It's in a terrible tangle. All that time you spent rolling it up, and now look at it!"
                               end
                       else
                               currentplayer.print "It's a ball of fine blue wool, all rolled up in preparation for some embroidery."
                               end
                       endif
               endif

               ;untangle
                       if ( this.getuserboolean(rolledup) = false ) then
                               currentplayer.print "You're as quick as can be at rolling up balls of wool, though you say so yourself! Soon it's neat and tidy again."
                               this.adduserboolean(rolledup)
                               end
                       else
                               currentplayer.print "The worsted is already neatly rolled up."
                               end
                       endif
               endif

               end

               proc before_get
                       if ( whitekitten.getvalue(state) = 3 ) then
                               whitekitten.setvalue(state) = 1
                       endif
                       if ( blackkitten.getvalue(state) = 3 ) then
                               blackkitten.setvalue(state) = 1
                       endif
               end

               proc before_displayinitial
                       if ( whitekitten.getvalue(state) <> 3 ) and ( blackkitten.getvalue(state) <> 3 ) then
                               returnvalue = "A discarded ball of worsted lies on the floor here."
                               cancelevent
                       else
                               returnvalue = " "
                               cancelevent
                       endif
               end

               proc after_get
                       this.movedfromoriginallocation = false
               end
               proc after_drop
                       this.movedfromoriginallocation = false
               end
               proc initialise
                       this.adduserboolean(rolledup)
               end
       ]
}

! Kitten class for creating kittens
Item kitten "Kitten Class" {

       OnAction: [

               ;examine
                       var otkit = this.getvalue(otherkitten)
                       currentplayer.print |"What a beautiful kitten the " & this.thename & " is. Why it's quite definitely your favourite of the pair, and much prettier than that naughty " & item(otkit).thename & "."|
                       end
               endif
               ;ask,answer,order
                       currentplayer.print |"The " & this.thename & " twitches its whiskers and looks at you with such a clever expression that you are certain it understands every word you are saying."|
                       end
               endif
               ;kiss
                       currentplayer.print |"You give the " & this.thename & " a little kiss on its nose, and it looks sweetly and demurely at you."|
                       end
               endif
               ;attack
                       currentplayer.print "You would never do such a beastly thing to such a defenceless little animal!"
                       end
               endif
               ;show
                       var shitem = 0
                       if ( input.noun > 0 ) and ( input.noun <> this.nounid ) then
                               shitem = getitemfromnoun input.noun
                       else
                               if ( input.noun2 > 0 ) and ( input.noun2 <> this.nounid ) then
                                       shitem = getitemfromnoun input.noun2
                               endif
                       endif
                       if ( shitem > 0 ) then
                               currentplayer.print |"The " & this.thename & " bats a paw at the " & item(shitem).thename & "."|
                               end
                       endif
               endif
               ;give,throw
                       var givit = 0
                       if ( input.noun > 0 ) then

                               givit = getitemfromnoun input.noun
                               item(givit).currentlocation = drawingroom.id
                               item(givit).movedfromoriginallocation = false

                               if ( givit <> worsted.id ) and ( givit <> redqueen.id ) then
                                       currentplayer.print |"You toss the " & item(givit).thename & " onto the floor, but the " & this.thename & " just examines it with a quizzical expression."|
                                       end
                               endif

                               this.currentlocation = drawingroom.id
                               this.movedfromoriginallocation = false

                               currentplayer.print |"You toss the " & item(givit).thename & " onto the floor and the " & this.thename & " scampers after it."|

                               if ( givit = worsted.id ) then
                                       currentplayer.print |"The " & this.thename & " quickly turns the neat ball into a tangle."|
                                       worsted.removeuserboolean(rolledup)
                                       this.setvalue(state) = 3
                                       end
                               else
                                       this.setvalue(state) = 2
                                       end
                               endif

                       endif
               endif

               end
               proc initialise
                       if ( this.id = blackkitten.id ) then
                               this.setvalue(otherkitten) = whitekitten.id
                       else
                               this.setvalue(otherkitten) = blackkitten.id
                       endif
                       this.setvalue(state) = 1
               end

               proc before_displayinitial
                       if ( this.getvalue(state) = 2 ) then
                               returnvalue = |"A " & this.thename & " is playing with the red queen."|
                               cancelevent
                               end
                       endif
                       if ( this.getvalue(state) = 3 ) then
                               returnvalue = |"A " & this.thename & " is playing with a ball of worsted."|
                               cancelevent
                               end
                       endif
                       if ( this.getvalue(state) = 1 ) then

                               var otkit = this.getvalue(otherkitten)
                               if ( item(otkit).getvalue(state) = 1 ) then
                                       ' Make sure we didn't already display this
                                       if ( whitekitten.getuserboolean(displayedtwo) = false ) then
                                               whitekitten.adduserboolean(displayedtwo)
                                               returnvalue = "Two kittens, one white and one black, are playing together by the arm-chair."
                                               cancelevent
                                       else
                                               returnvalue = " "
                                               cancelevent
                                       endif

                               else
                                       returnvalue = |"A " & this.thename & " is playing by the arm-chair."|
                                       cancelevent
                               endif
                       endif
               end

               proc before_get
                       var otkit = this.getvalue(otherkitten)
                       if ( item(otkit).currentlocation = currentplayer.containerlocation ) then
                               returnvalue = "You can't hold two kittens at once!"
                               cancelevent
                               end
                       else
                               returnvalue = |"You pick up the " & this.thename & ". What a beautiful creature it is!"|
                               this.setvalue(state) = 4
                               this.movedfromoriginallocation = false
                               end
                       endif
               end

               proc before_drop
                       this.setvalue(state) = 1
                       returnvalue = |"The " & this.thename & " squirms out of your arms and scampers away."|
                       this.movedfromoriginallocation = false
               end

               proc after_insert
                       this.setvalue(state) = 1
                       this.currentlocation = drawingroom.id
                       var cntnr = getitemfromnoun input.noun2
                       currentplayer.print |"The " & this.thename & " jumps off the " & item(cntnr).thename & ", landing lightly on the floor before scampering away."|
               end

               proc each_turn

                       whitekitten.removeuserboolean(displayedtwo)

                       if ( this.currentlocation = currentplayer.containerlocation ) then

                               ' This offers 3/8 chance of no action
                               var rndec = |8 * random + 1 + makeinteger|

                               var oput = |"The " & this.thename|

                               if ( rndec = 1 ) then
                                       oput = |oput & " mews plaintively."|
                               endif
                               if ( rndec = 2 ) then
                                       oput = |oput & " purrs quietly to itself."|
                               endif
                               if ( rndec = 3 ) then
                                       oput = |oput & " purrs contendly to itself."|
                               endif
                               if ( rndec = 4 ) then
                                       oput = |oput & " rubs its ears against you."|
                               endif
                               if ( rndec = 5 ) then
                                       oput = |oput & " squirms out of your arms and scampers away."|
                                       this.setvalue(state) = 1
                                       this.currentlocation = drawingroom.id
                                       this.movedfromoriginallocation = false
                               endif
                               if ( rndec < 6 ) then
                                       currentplayer.print oput
                               endif
                       endif
               end
       ]
}

Item whitekitten "a white kitten" extends kitten {
       StartsIn drawingroom
       Nouns "white" "kitten" "kittens" "kitty" "cat"
       Initial "white"
}

Item blackkitten "a black kitten" extends kitten {
       StartsIn drawingroom
       Nouns "black" "kitten" "kittens" "kitty" "cat"
       Initial "black"
}

Item chesspieces "chess pieces" {
       StartsIn drawingroom
       Nouns "rook" "bishop" "knight" "king" "pawn"
       has scenery
       OnAction: [
           currentplayer.print "Alas, that chess piece seems to be missing. Those naughty kittens!"
       ]
}

Item window "the window" {
       StartsIn drawingroom
       has scenery
       Nouns "window" "pane"
       Description "Outside the window it's snowing gently, and you're
                    glad to be in here in the warmth."

       OnAction: [
               ;open
                       currentplayer.print "You wouldn't want to catch a chill, would you? Better leave the window shut."
                       end
               endif
               ;search
                       currentplayer.print this.defaultexamine
                       end
               endif
       ]
}