/*
 * 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 NONINFRINGEMENT. IN NO EVENT SHALL 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.
 */
/*** TRANSITIONS ***/
proc Hitms(vrb, loc, func)
{
    if (Verb == vrb) {
        if (loc) {
            $ME.move(loc);
            GO = true;
        }
        if (func) {
            func();
        }
    }
}

proc Synvb(vrb, newvrb)
{
    if (Verb == vrb) {
        Verb = newvrb;
    }
}

... road1 {
    action = proc() {
        Hitms(north, gard1, 0);
        Hitms(south, gard2, 0);
        Hitms(east, road2, 0);
        Hitms(west, road3, 0);
    }
}

... road2 {
    action = proc() {
        Hitms(north, gard1, 0);
        Hitms(south, gard2, 0);
        Hitms(east, road6, 0);
        Hitms(west, road1, 0);
    }
}

proc DropKill()
{
    "The drop would kill you.\n";
    MyLoc = $ME.loc;
    GO = true;
}

... road3 {
    action = proc() {
        Hitms(north, 0, DropKill);
        Hitms(south, 0, DropKill);
        Hitms(east, road1, 0);
        Hitms(west, road7, Entr7);
    }
}

... road4 {
    action = proc() {
        Hitms(north, farm1, 0);
        Hitms(south, road6, 0);
        Hitms(east, frst1, 0);
        Hitms(west, gard1, 0);
    }
}

... road5 {
    action = proc() {
        Hitms(north, road6, 0);
        Hitms(south, town1, 0);
        Hitms(east, frst1, 0);
        Hitms(west, gard2, 0);
    }
}

... road6 {
    action = proc() {
        Hitms(north, road4, 0);
        Hitms(south, road5, 0);
        Hitms(east, frst1, 0);
        Hitms(west, road2, 0);
    }
}

... road7 {
    action = proc() {
        if ((Verb == enter) && (bus.loc == road7)) {
            "You board the bus.\n";
            $ME.move(bus);
            GO = true;
        }
        Miss(Tress, Tress, East7, West7, 0, 0, 0, 0, 0, 0);
    }
}

proc East7()
{
    GO = true;
    if (!HWY7) {
        $ME.move(road3);
    }
    else {
        Dump7(road7.cont);
        HWY7 = HWY7 - 1;
        Get7(Roadx.cont);
    }
}

proc West7()
{
    GO = true;
    Dump7(road7.cont);
    HWY7 = HWY7 + 1;
    Get7(Roadx.cont);
}

proc Dump7(lst)
{
    var i, n;
    n = lst.length();

    // Dump in reverse order (why?)
    for (i = n-1; i >= 0; i--) {
        var obj = lst[i];
        if (obj != $ME) {           // Everything else leaves
            obj.RDLOC = HWY7;           // Retain its location on HWY 7
            obj.move(Roadx);            // Put it in the box
        }
    }
}

proc Get7(lst)
{
    forall (lst[i]) {
        var obj = lst[i];
        if (obj.RDLOC == HWY7) {
            obj.move(road7);
        }
    }
}

proc Entr7()
{
    Dump7(road7.cont);
    HWY7 = 0;
    Get7(Roadx.cont);
}

... gard1 {
    action = proc() {
        Hitms(north, gard1, 0);
        Hitms(south, road1, 0);
        Hitms(east, gard1, 0);
        Hitms(west, gard1, 0);
    }
}

... gard2 {
    action = proc() {
        Hitms(north, road1, 0);
        Hitms(south, gard2, 0);
        Hitms(east, gard2, 0);
        Hitms(west, gard2, 0);
    }
}

proc FLeave()
{
    if (Percent(20)) {
        $ME.move(road6);
    }
    GO = true;
}

... frst1 {
    action = proc() {
        Miss(FLeave, FLeave, FLeave, FLeave, FLeave, FLeave, FLeave, FLeave, 0, 0);
    }
}

... farm1  {
    action = proc() {
        Synvb(enter, north);
        Hitms(north, farm2, 0);
        Hitms(south, road4, 0);
        Hitms(east, farm3, 0);
        Hitms(west, farm4, 0);
        Hitms(northeast, farm3, 0);
        Hitms(northwest, farm4, 0);
    }
}

... farm2  {
    action = proc() {
        Synvb(out, south);
        Synvb(enter, north);
        Synvb(east, up);
        Hitms(north, farm6, 0);
        Hitms(south, farm1, 0);
        Hitms(up, farm7, 0);
    }
}

... farm3  {
    action = proc() {
        Hitms(north, farm5, 0);
        Hitms(south, farm1, 0);
        Hitms(east, frst1, 0);
        Hitms(northwest, farm5, 0);
        Hitms(southwest, farm1, 0);
    }
}

... farm4  {
    action = proc() {
        Hitms(north, farm5, 0);
        Hitms(south, farm1, 0);
        Hitms(west, gard1, 0);
        Hitms(northeast, farm5, 0);
        Hitms(southeast, farm1, 0);
    }
}

... farm5  {
    action = proc() {
        Hitms(east, farm3, 0);
        Hitms(west, farm4, 0);
        Hitms(southeast, farm3, 0);
        Hitms(southwest, farm4, 0);
    }
}

... farm6  {
    action = proc() {
        Hitms(out, farm2, 0);
        Hitms(south, farm2, 0);
    }
}

... farm7  {
    action = proc() {
        Hitms(east, farm2, 0);
        Hitms(down, farm2, PanL);
    }
}


... town1  {
    action = proc() {
        Hitms(north, road5, 0);
        Hitms(south, town2, 0);
        Hitms(east, town3, 0);
        Hitms(west, town4, 0);
    }
}

... town2  {
    action = proc() {
        Hitms(north, town1, 0);
        Hitms(east, town5, 0);
        Hitms(west, town6, 0);
    }
}

... town3  {
    action = proc() {
        Hitms(out, town1, 0);
        Hitms(west, town1, 0);
    }
}

... town4  {
    action = proc() {
        Hitms(east, town1, 0);
        Hitms(out, town1, 0);
    }
}

... town5  {
    action = proc() {
        Hitms(west, town2, 0);
        Hitms(out, town2, 0);
    }
}

... town6  {
    action = proc() {
        Hitms(east, town2, 0);
        Hitms(out, town2, 0);
    }
}

... cel01  {
    action = proc() {
        Hitms(north, cel02, 0);
        Hitms(west, cel04, 0);
        Hitms(up, farm7, 0);
    }
}

... cel02  {
    action = proc() {
        Hitms(north, cel05, 0);
        Hitms(south, cel01, 0);
        Hitms(east, cel20, 0);
    }
}

... cel20 {
    action = proc() {
        Hitms(west, cel02, 0);
    }
}

... cel03  {
    action = proc() {
        Hitms(south, cel05, 0);
        if (!dragon.KILLED) {
            Hitms(west, cel13, 0);
            Hitms(northeast, cel09, 0);
            Hitms(down, cel09, 0);
        }
    }
}

... cel04  {
    action = proc() {
        Synvb(down, north);
        Hitms(north, cel10, 0);
        Hitms(east, cel01, 0);
        Hitms(west, cel08, 0);
    }
}


proc MV56() {Cel6x = 5;}
proc MV76() {Cel6x = 7;}
proc MV67()
{
    if ((Cel6x != 7) && dragon.AWAKE && !dragon.KILLED) {
        "The ice dragon blocks your attempt to cross!\n\n";
    }
    else {
        $ME.move(cel07);
    }
    GO = true; // short circuit default error message
}

proc MV65()
{
    if ((Cel6x != 5) && dragon.AWAKE && !dragon.KILLED) {
        "The ice dragon blocks your attempt to leave!\n";
    }
    else {
        $ME.move(cel05);
    }
    GO = true; // short circuit default error message
}


... cel05  {
    action = proc() {
        Hitms(north, cel03, 0);
        Hitms(south, cel02, 0);
        Hitms(northeast, cel06, MV56);
    }
}

... cel06  {
    action = proc() {
        Hitms(east, 0, MV67);
        Hitms(southwest, 0, MV65);
        if ((!dragon.KILLED) && dragon.AWAKE && ($ME.loc == cel06)) {
            //still here
            MyLoc = -1;
        }
    }
}

... cel07  {
    action = proc() {
        Synvb(out, west);
        Hitms(west, cel06, MV76);
    }
}

proc Thirst()
{
    if ($ME.loc == desert) {
        "The blazing sun is too much for you, I'm afraid.\n";
        Die();
    }
}

proc Move08()
{
    if (silverRod.WAVED) {
        if (dragon.KILLED) {
            $ME.move(field);
        }
        else {
            $ME.move(desert);
            $ME.setfuse(Thirst, 10);
        }
    }
    else {
        "You bump your nose against the painting.\n";
        MyLoc = $ME.loc;
    }
    GO = true;
}

... cel08  {
    action = proc() {
        Hitms(east, cel04, 0);
        Hitms(west, 0, Move08);
    }
}

proc Slippery()
{
    "The waterfall is to slick for you to climb.\n";
    MyLoc = $ME.loc;
    GO = true;
}

proc CrackEntr()
{
    "You slip through the crack in the waterfall.\n";
}

proc Get21()
{
    var lst = riverx.cont;
    forall (lst[i]) {
        var t = lst[i];
        if (t.Loc21 == RiverLoc) {
            t.move(cel21);
        }
    }
}

proc Dump21()
{
    var lst = cel21.cont;
    forall (lst[i]) {
        var t = lst[i];
        if (t != $ME) {
            t.Loc21 = RiverLoc;
            t.move(riverx);
        }
    }
}

proc Entr21()
{
    RiverLoc = 1;
    Get21();
}

... cel09  {
    action = proc() {
        Hitms(north, cel21, Entr21);
        Hitms(up, 0, Slippery);
        Hitms(south, cel18, CrackEntr);
    }
}

proc Move11()
{
    if (dragon.KILLED) {
        if (!wetsuit.WORN) {
            "The pit is full of water!!!\n";
        }
        else {
            "That water looks mighty dangerous.  Are you sure?  ";
            if (yorn()) {
                "You leap into the pit and are immediately grabbed by a ",
                "mighty current which pulls you down, down, down...  Soon ",
                "the pressure becomes too great for you to breathe, and the ",
                "last thing you remember is feeling somewhat like an ",
                "elephant's footstool.\n";
                Die();
            }
        }
        MyLoc = $ME.loc;
    }
    else {
        $ME.move(cel11);
    }
    GO = true;
}

... cel10  {
    action = proc() {
        Synvb(up, south);
        Hitms(south, cel04, 0);
        Hitms(down, 0, Move11);
    }
}

... cel11  {
    action = proc() {
        if (GOVERB && !clearCrystal.pLight) {
            "You trip and fall into a pit that you were unable to see ",
            "in the dark!\n";
            Die();
        }
        Hitms(east, cel12, 0);
        Hitms(west, cel16, 0);
    }
}

... cel12  {
    action = proc() {
        Hitms(west, cel11, 0);
    }
}

proc WaterEntr()
{
    if ($ME.HAS > globe.WEIGH) {
        if (!wetsuit.WORN) {
            "Whatever you're carrying drags you down into the icy waters!\n";
            Die();
        }
    }
}

... cel13  {
    action = proc() {
        if (Verb == down) {
            if (cel13.HOLED) {
                WaterEntr();
                "You plunge into the icy waters!\n";
                $ME.move(cel14);
                GO = true;
                ExitPhase(PHX_ACTOR);
            }
        }
        Hitms(east, cel03, 0);
        Hitms(west, cel19, 0);
    }
}

proc Drown()
{
    if (($ME.loc == cel14) || ($ME.loc == cel17)) {
        if (!wetsuit.WORN) {
            "You can't hold your breath any longer.  The last thing you ",
            "feel is the odd sensation of water entering your lungs.\n";
            Die();
        }
    }
}

... cel14  {
    action = proc() {
        if (Verb == up) {
            if (cel13.HOLED) {
                "You pop out through a hole in the ice!\n";
                $ME.move(cel13);
                GO = true;
                ExitPhase(PHX_ACTOR);
            }
            else {
                 "You are blocked by an icy roof above!\n";
            }
        }
        Hitms(west, cel15, 0);
        Hitms(east, cel17, 0);
        $ME.setfuse(Drown, 1);
    }
}

... cel15 {
    action = proc() {
        Synvb(up, south);
        Synvb(enter, east);
        Hitms(east, cel14, WaterEntr);
        Hitms(south, cel16, 0);
    }
}

... cel16 {
    action = proc() {
        Synvb(down, north);
        Hitms(north, cel15, 0);
        Hitms(east, cel11, 0);
    }
}

... cel17 {
    action = proc() {
        Hitms(northeast, cel18, 0);
        Hitms(west, cel14, 0);
        $ME.setfuse(Drown, 1);
    }
}

proc Swim()
{
    "You dive into the icy waters.\n";
    WaterEntr();
}

... cel18 {
    action = proc() {
        Synvb(enter, southwest);
        Hitms(north, cel09, 0);
        Hitms(southwest, cel17, Swim);
    }
}

... cel19 {
    action = proc() {
        Hitms(east, cel13, 0);
    }
}

proc North21()
{
    Dump21();
    RiverLoc = RiverLoc + 1;
    GO = true;
    cel21.pSeen = false;
    Get21();
}

proc South21()
{
    Dump21();
    GO = true;
    RiverLoc = RiverLoc - 1;
    cel21.pSeen = false;
    if (!RiverLoc) {
        $ME.move(cel09);
    }
    else {
        Get21();
    }
}

proc CantClimb()
{
    "The sides of the river bed are too steep for you to climb.\n";
    MyLoc = $ME.loc;
    GO = true;
}

proc GrateThere()
{
    "The grate blocks your attempt to move that way.\n";
    MyLoc = $ME.loc;
    GO = true;
}

... cel21 {
    action = proc() {
        if (RiverLoc == GRATELOC)
            Miss(South21, GrateThere, CantClimb, CantClimb);
        else if (RiverLoc == BEND1LOC)
            Miss(CantClimb, South21, CantClimb, North21);
        else if ((RiverLoc > BEND1LOC) && (RiverLoc < BEND2LOC))
            Miss(CantClimb, CantClimb, South21, North21);
        else if (RiverLoc == BEND2LOC)
            Miss(CantClimb, North21, South21, CantClimb);
        else if (RiverLoc > BEND2LOC)
            Miss(South21, North21, CantClimb, CantClimb);
        else // RiverLoc < BEND1LOC
            Miss(North21, South21, CantClimb, CantClimb);
    }
}

... desert {
    action = proc() {
        Hitms(north, desert, 0);
        Hitms(south, desert, 0);
        Hitms(east, desert, 0);
        Hitms(west, desert, 0);
        Hitms(northeast, desert, 0);
        Hitms(northwest, desert, 0);
        Hitms(southeast, desert, 0);
        Hitms(southwest, desert, 0);
    }
}

... field {
    action = proc() {
        Hitms(north, 0, ENDGA$ME);
    }
}

proc Twist()
{
    "You wander around in the twisty city streets, eventually ",
    "returning to your starting point.\n";
}

... city {
    action = proc() {
        if ((Verb == enter) && (bus.loc == city)) {
            "You board the bus.\n";
            $ME.move(bus);
            GO = true;
        }
        else {
            Miss(Twist, 0, Twist, Twist, Twist, Twist,
                            Twist, Twist, Twist, Twist);
            Hitms(south, building, 0);
        }
    }
}

... building {
    action = proc() {
        Hitms(north, city, 0);
    }
}