/*
 * Copyright (c) 2021 Ross Cunniff
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF $MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGE$MENT. IN NO EVENT SH$ALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */
#include "stdadv.oah"

using namespace adv;
using namespace stdadv;

/* Object properties specific to this scenario */

public
    pBroken;         // The window can be broken

proc Header(str, acnt) {
    if (acnt == 0) "", str, '\n';
    return str;
}

/* Derived classes */
class Breakable(FixedThing) {
    public var pBroken = false;
}

var score = 0;

/* Locations in this scenario */

LitRoom room1 {...}
LitRoom room2 {...}

/* The vocabulary for this scenario */

AdjecClass sun(); AdjecClass glass(); AdjecClass big();
AdjecClass red(); AdjecClass hard(); AdjecClass wooden();
AdjecClass blue(); AdjecClass soft(); AdjecClass foamy();
NounClass window();
NounClass ball();
NounClass toy();
PrepClass against();

/* Actual objects - we will continue their definitions below */
FixedThing wall($ALL)           { ... }
FixedThing floor($ALL)          { ... }
FixedThing door(room2)          { ... }
Breakable sunWindow(room2) {
    adjec = {sun, glass, big}
    noun = window
    ...
}
Thing redBall(room1) {
    adjec = {red, hard, wooden}
    noun = {ball, toy}
    ...
}
Thing blueBall(room1) {
    adjec = {blue, soft, foamy}
    noun = {ball, toy}
    ...
}

Synonym bounce(V_throw);

/* Location descriptions */
... room1 {
    ldesc = proc() {
        "You are in your bedroom.  All of your really FUN toys have been ";
        "put away, out of your reach.  There is another room to the east.\n";
    }
    sdesc = proc() {return Header("Bedroom", oadl::nargs());}
    ... // More to come below
}

... room2 {
    ldesc = proc() {
        "You are in the nursery.  A pretty yellow sunbeam is shining on the ";
        "floor.  There is another room to the west.\n";
    }
    sdesc = proc() {return Header("Nursery", oadl::nargs());}
    ... // More to come below
}


/* Transition routines */
proc cg() {"You can't go that way.\n";}

... room1 {
    action = proc() {
        Miss(     cg,  cg,   nil, cg, cg, cg, cg, cg, cg, cg);
        Hit($ME, nil, nil, room2);
    }
}

... room2 {
    action = proc() {
        Miss(     cg,  cg,  cg,   nil, cg, cg, cg, cg, cg, cg);
        Hit($ME, nil, nil, nil, room1);
    }
}



/* Object specific routines */

proc BallAct(Obj)                             // ACTION rout for balls
{
    if (Verb == V_throw) {
        if (Dobj != Obj) {
            /* We're the iobj; don't perform an action */
            ExitPhase(PHX_CURRENT);
        }
        if (Iobj != wall) {
            "You throw the ball at the floor, where it bounces a few ";
            "times, then is still.\n";
        }
        else {
            "The ball sails through the air, then bounces off the wall ";
            "onto the floor.\n";
        }
        Dobj.move($ME.loc);
        ExitPhase(PHX_ACTOR);
    }
}

... redBall {
    ldesc = proc() {"There is a hard, wooden red ball here.\n";}
    sdesc = proc() {"a red ball";}
    action = proc() { BallAct( redBall ); }
}

... blueBall {
    ldesc = proc() {"There is a soft, foamy blue ball here.\n";}
    sdesc = proc() {"a blue ball";}
    action = proc() { BallAct( blueBall ); }
}

proc NoAct(Obj)                       // ACTION rout for wall and floor
{
    if ((Verb != V_throw) || (Iobj != Obj)) {
        Silly();
    }
}

... wall {
    action = proc() { NoAct( wall ); }
}

... floor {
    action = proc() { NoAct( floor ); }
}


... sunWindow {
    ldesc = proc() {
        "There is a large sun window here";
        if (self.pBroken)
            ", shattered into a thousand pieces!\n";
        else
            ".\n";
    }
    sdesc = proc() {
        if (self.pBroken)
            "a broken window";
        else
            "a sun window";
    }
    action = proc() {
        if ((Verb == V_throw) && (Iobj == self)) {
            if (Dobj == redBall) {
                "The red ball sails through the window, shattering it!\n";
                score = -10;
                redBall.move($ALL);
                self.pBroken = true;
                ExitPhase(PHX_ACTOR);
            }
            else if (Dobj == blueBall) {
                if (self.pBroken) {
                    "The blue ball sails through the broken window!\n";
                    blueBall.move($ALL);
                }
                else {
                    "The blue ball bounces harmlessly off the window.\n";
                    blueBall.move(room2);
                }
                ExitPhase(PHX_ACTOR);
            }
            else {
                 Silly();
            }
        }
        else if (Verb == open) {
            "You can't open a sun window!\n";
            ExitPhase(PHX_ACTOR);
        }
        else if (Verb == take) {
            Silly();
        }
    }
}


... door {
    ldesc = proc() { "There is a closed door here.\n"; }
    sdesc = proc() { "a door"; }
    action = proc() {
        if ((Verb == V_throw) && (Iobj == self)) {
            "The ", Dobj.name, " bounces harmlessly off of the door.\n";
            ExitPhase(PHX_ACTOR);
        }
        else if (Verb == open) {
            "The doorknob is too high for you to reach.\n";
            ExitPhase(PHX_ACTOR);
        }
        else if (Verb == take) {
            Silly();
        }
    }
}

/* Scenario dependant routines */

proc Parent()                         // The parent fuse
{
    if ($ME.loc == room1)
        "Suddenly, the door to your bedroom opens! ";
    else
        "You hear the door in your bedroom opening! ";
    
    "Your parents enter the room. ";
    if (sunWindow.pBroken)
        "Daddy notices the broken window, and turns a funny red color. ",
        "\"I see that you haven't learned your lesson, dear,\" says ",
        "Mommy.  \"I'm afraid that you will have to stay in here for ",
        "at least another hour! ",
        "Mommy and Daddy leave you alone again.  Let's see what other ",
        "fun things there are to do around here...\n";
    else
        "\"Have you learned your lesson, kiddo?\" asks Daddy.  Seeing ",
        "your cute little face seems to have charmed them!  You're off ",
        "the hook!  Mommy and Daddy take you out to see \"The Care ",
        "Bears Eat New York\", and you live happily ever after.\n";
    oadl::halt();
}


var Rand = {
    "You wonder if the blue ball will bounce off of the window.\n",
    "You wonder if the red ball will bounce off of the window.\n" ,
    "You find a piece of lint on the floor, and eat it.  Yum!\n" ,
    "You can hear Kitty meowing outside.\n" ,
    "You hear Mommy singing in the kitchen.\n" ,
    "You practice making disgusting noises.  THPPP!  ZZZKKK!\n" ,
    "You hear Daddy hit his head on the garage door.\n" ,
    "You lick the wall, to see what it tastes like.\n" ,
    "You pretend that you're an airplane.  Zoom!\n" ,
    "You make spider shadows with your hands.\n"
};

proc Random()                 // Random message daemon
{
    var which;

    Incturn();             // Increment the turn counter
    wall.move($ME.loc);     // Move the wall to my current location
    floor.move($ME.loc);    // Move the floor to my current location
    // Not random if we are debugging
    which = echoInput ? (1 + Turns%10) : RandInt(1, 20);
    if (which == 1) {
        if (blueBall.loc != $ALL) {
            say(Rand[0]);
        }
    }
    else if (which == 2) {
        if (redBall.loc != $ALL) {
            say(Rand[1]);
        }
    }
    else if (which <= 10) {
        say(Rand[which - 1]);
    }
}

StdActor ME(room1);                     /* The main actor in this play */

proc prompter()
{
    Status($ME.loc.sdesc(1), score, Turns);
    "> ";
}

proc adv::START()
{
    Indent = true;

    "\n\n\n\n";                 // A few newlines for good measure
    "It all started so innocently!  Kitty asked you for a haircut, ";
    "so you took Daddy's neato electric razor, and gave her a Mohawk. ";
    "Unfortunately, Mommy and Daddy didn't think it was so neat, and ";
    "they stuck you in here for a fifteen minute time out period...\n\n";

    StdInit(ME);                        // Initialize standard
    Prompt = prompter;                  // The prompter
    Setdaemon(Random);                  // Set up the random message daemon
    ME.setfuse(Parent, 15);             // Set up mommy and daddy
    //define("both", "red,blue");       // Set up "both" to work TBD
    //define("balls", "ball");          // with the balls TBD
}

/* Dwimming routines */

proc adv::DWIMI(Prs,Obj) { return Dwimmer(Prs,Obj); }
proc adv::DWIMD(Prs,Obj) { return Dwimmer(Prs,Obj); }

Thing adv::STRING();
VerbClass adv::TELLER();