
 /* VERB.C  no mods for V 1.43 */

#include "advent.h"


/*  Routine to process a transitive verb  */

VOID PASCAL trverb PROTO((VOID))
{
    switch (G.verb)
    {
        case CALM:
        case WALK:
        case QUIT:
        case SCORE:
        case FOO:
        case BRIEF:
        case SUSPEND:
        case HOURS:
        case LOG:
            actspk(G.verb);
            break;

        case TAKE:
            vtake();
            break;

        case DROP:
            vdrop();
            break;

        case OPEN:
        case LOCK:
            vopen();
            break;

        case SAY:
            vsay();
            break;

        case NOTHING:
            rspeak(54);
            break;

        case ON:
            von();
            break;

        case OFF:
            voff();
            break;

        case WAVE:
            vwave();
            break;

        case KILL:
            vkill();
            break;

        case POUR:
            vpour();
            break;

        case EAT:
            veat();
            break;

        case DRINK:
            vdrink();
            break;

        case RUB:
            if (G.object != LAMP)
                rspeak(76);
            else
                actspk(RUB);

            break;

        case THROW:
            vthrow();
            break;

        case FEED:
            vfeed();
            break;

        case FIND:
        case INVENTORY:
            vfind();
            break;

        case FILL:
            vfill();
            break;

        case READ:
            vread();
            break;

        case BLAST:
            vblast();
            break;

        case BREAK:
            vbreak();
            break;

        case WAKE:
            vwake();
            break;

        case SAVE:
            saveadv();
            describe();
            descitem();
            break;

        case RESTORE:
            restore();
            describe();
            descitem();
            break;

        default:
            printf("This verb is not implemented yet.\n");
            break;
    }

    return;
}


/*  CARRY TAKE etc.  */

VOID PASCAL vtake PROTO((VOID))
{
    auto     SHORT      msg;
    auto     SHORT      i;

    if (toting(G.object))
    {
        actspk(G.verb);
        return;
    }

    /* special case objects and fixed objects */
    msg = 25;
    if (G.object == PLANT && G.prop[PLANT] <= 0)
        msg = 115;

    if (G.object == BEAR && G.prop[BEAR] == 1)
        msg = 169;

    if (G.object == CHAIN && G.prop[BEAR] != 0)
        msg = 170;

    if (G.fixed[G.object])
    {
        rspeak(msg);
        return;
    }

    /* special case for liquids */
    if (G.object == WATER || G.object == OIL)
    {
        if (!here(BOTTLE) || liq() != G.object)
        {
            G.object = BOTTLE;
            if (toting(BOTTLE) && G.prop[BOTTLE] == 1)
            {
                vfill();
                return;
            }

            if (G.prop[BOTTLE] != 1)
                msg = 105;

            if (!toting(BOTTLE))
                msg = 104;

            rspeak(msg);
            return;
        }

        G.object = BOTTLE;
    }

    if (G.holding >= 7)
    {
        rspeak(92);
        return;
    }

    /* special case for bird. */
    if (G.object == BIRD && G.prop[BIRD] == 0)
    {
        if (toting(ROD))
        {
            rspeak(26);
            return;
        }

        if (!toting(CAGE))
        {
            rspeak(27);
            return;
        }

        G.prop[BIRD] = 1;
    }

    if ((G.object == BIRD || G.object == CAGE) && G.prop[BIRD] != 0)
        carry((BIRD + CAGE) - G.object, G.loc);

    carry(G.object, G.loc);

    /* handle liquid in bottle */
    i = liq();
    if (G.object == BOTTLE && i != 0)
        G.place[i] = -1;

    rspeak(54);
    return;
}


/*  DROP etc.  */

VOID PASCAL vdrop PROTO((VOID))
{
    auto     SHORT      i;

    /* check for dynamite */
    if (toting(ROD2) && G.object == ROD && !toting(ROD))
        G.object = ROD2;

    if (!toting(G.object))
    {
        actspk(G.verb);
        return;
    }

    /* snake and bird */
    if (G.object == BIRD && here(SNAKE))
    {
        rspeak(30);
        if (G.closed)
            dwarfend();

        dstroy(SNAKE);
        G.prop[SNAKE] = -1;
    }
    else                        /* coins and vending machine */
    {
        if (G.object == COINS && here(VEND))
        {
            dstroy(COINS);
            drop(BATTERIES, G.loc);
            pspeak(BATTERIES, 0);
            return;
        }

        /* bird and dragon (ouch!!) */
        if (G.object == BIRD && at(DRAGON) && G.prop[DRAGON] == 0)
        {
            rspeak(154);
            dstroy(BIRD);
            G.prop[BIRD] = 0;
            if (G.place[SNAKE] != 0)
                ++G.tally2;

            return;
        }
    }

    /* Bear and troll */
    if (G.object == BEAR && at(TROLL))
    {
        rspeak(163);
        move(TROLL, 0);
        move((TROLL + MAXOBJ), 0);
        move(TROLL2, 117);
        move((TROLL2 + MAXOBJ), 122);
        juggle(CHASM);
        G.prop[TROLL] = 2;
    }
    else                        /* vase */
    {
        if (G.object == VASE)
        {
            if (G.loc == 96)
                rspeak(54);
            else
            {
                G.prop[VASE] = at(PILLOW) ? 0 : 2;
                pspeak(VASE, G.prop[VASE] + 1);
                if (G.prop[VASE] != 0)
                    G.fixed[VASE] = -1;
            }
        }
    }

    /* handle liquid and bottle */
    i = liq();
    if (i == G.object)
        G.object = BOTTLE;

    if (G.object == BOTTLE && i != 0)
        G.place[i] = 0;

    /* handle bird and cage */
    if (G.object == CAGE && G.prop[BIRD] != 0)
        drop(BIRD, G.loc);

    if (G.object == BIRD)
        G.prop[BIRD] = 0;

    drop(G.object, G.loc);
    return;
}


/*  LOCK, UNLOCK, OPEN, CLOSE etc.  */

VOID PASCAL vopen PROTO((VOID))
{
    auto     SHORT      msg, oyclam;

    switch (G.object)
    {
        case CLAM:
        case OYSTER:
            oyclam = (G.object == OYSTER ? 1 : 0);
            if (G.verb == LOCK)
                msg = 61;
            else
            {
                if (!toting(TRIDENT))
                    msg = 122 + oyclam;
                else
                {
                    if (toting(G.object))
                        msg = 120 + oyclam;
                    else
                    {
                        msg = 124 + oyclam;
                        dstroy(CLAM);
                        drop(OYSTER, G.loc);
                        drop(PEARL, 105);
                    }
                }
            }

            break;

        case DOOR:
            msg = (G.prop[DOOR] == 1 ? 54 : 111);
            break;

        case CAGE:
            msg = 32;
            break;

        case KEYS:
            msg = 55;
            break;

        case CHAIN:
            if (!here(KEYS))
                msg = 31;
            else
            {
                if (G.verb == LOCK)
                {
                    if (G.prop[CHAIN] != 0)
                        msg = 34;
                    else
                    {
                        if (G.loc != 130)
                            msg = 173;
                        else
                        {
                            G.prop[CHAIN] = 2;
                            if (toting(CHAIN))
                                drop(CHAIN, G.loc);

                            G.fixed[CHAIN] = -1;
                            msg = 172;
                        }
                    }
                }
                else
                {
                    if (G.prop[BEAR] == 0)
                        msg = 41;
                    else
                    {
                        if (G.prop[CHAIN] == 0)
                            msg = 37;
                        else
                        {
                            G.prop[CHAIN] = 0;
                            G.fixed[CHAIN] = 0;
                            if (G.prop[BEAR] != 3)
                                G.prop[BEAR] = 2;

                            G.fixed[BEAR] = 2 - G.prop[BEAR];
                            msg = 171;
                        }
                    }
                }
            }

            break;

        case GRATE:
            if (!here(KEYS))
                msg = 31;
            else
            {
                if (G.closing)
                {
                    if (!G.panic)
                    {
                        G.clock2 = 15;
                        ++G.panic;
                    }

                    msg = 130;
                }
                else
                {
                    msg = 34 + G.prop[GRATE];
                    G.prop[GRATE] = (G.verb == LOCK ? 0 : 1);
                    msg += 2 * G.prop[GRATE];
                }
            }

            break;

        default:
            msg = 33;
            break;
    }

    rspeak(msg);
    return;
}


/*  SAY etc.  */

VOID PASCAL vsay PROTO((VOID))
{
    auto     SHORT      wtype, wval;

    analyze(word1, &wtype, &wval);
    printf("Okay.\n%s\n", wval == SAY ? word2 : word1);
    return;
}


/*  ON etc.  */

VOID PASCAL von PROTO((VOID))
{
    if (!here(LAMP))
        actspk(G.verb);
    else
    {
        if (G.limit < 0)
            rspeak(184);
        else
        {
            G.prop[LAMP] = 1;
            rspeak(39);
            if (G.wzdark)
            {
                G.wzdark = 0;
                describe();
                descitem();
            }
        }
    }

    return;
}


/*  OFF etc.  */

VOID PASCAL voff PROTO((VOID))
{
    if (!here(LAMP))
        actspk(G.verb);
    else
    {
        G.prop[LAMP] = 0;
        rspeak(40);
    }

    return;
}


/*  WAVE etc.  */

VOID PASCAL vwave PROTO((VOID))
{
    if (!toting(G.object) && (G.object != ROD || !toting(ROD2)))
        rspeak(29);
    else
    {
        if (G.object != ROD || !at(FISSURE)
                            || !toting(G.object) || G.closing)
            actspk(G.verb);
        else
        {
            G.prop[FISSURE] = 1 - G.prop[FISSURE];
            pspeak(FISSURE, 2 - G.prop[FISSURE]);
        }
    }

    return;
}


/*  ATTACK, KILL etc.  */

VOID PASCAL vkill PROTO((VOID))
{
    auto     SHORT      msg;
    auto     SHORT      i;

    switch (G.object)
    {
        case BIRD:
            if (G.closed)
                msg = 137;
            else
            {
                dstroy(BIRD);
                G.prop[BIRD] = 0;
                if (G.place[SNAKE] == 19)
                    ++G.tally2;

                msg = 45;
            }

            break;

        case 0:
            msg = 44;
            break;

        case CLAM:
        case OYSTER:
            msg = 150;
            break;

        case SNAKE:
            msg = 46;
            break;

        case DWARF:
            if (G.closed)
                dwarfend();

            msg = 49;
            break;

        case TROLL:
            msg = 157;
            break;

        case BEAR:
            msg = 165 + (G.prop[BEAR] + 1) / 2;
            break;

        case DRAGON:
            if (G.prop[DRAGON] != 0)
            {
                msg = 167;
                break;
            }

            if (!yes(49, 0, 0))
                break;

            pspeak(DRAGON, 1);
            G.prop[DRAGON] = 2;
            G.prop[RUG] = 0;
            move((DRAGON + MAXOBJ), -1);
            move((RUG + MAXOBJ), 0);
            move(DRAGON, 120);
            move(RUG, 120);
            for (i = 1; i < MAXOBJ; ++i)
            {
                if (G.place[i] == 119 || G.place[i] == 121)
                    move(i, 120);
            }

            G.newloc = 120;
            return;

        default:
            actspk(G.verb);
            return;
    }

    rspeak(msg);
}


/*  POUR  */

VOID PASCAL vpour PROTO((VOID))
{
    if (G.object == BOTTLE || G.object == 0)
        G.object = liq();

    if (G.object == 0)
    {
        needobj();
        return;
    }

    if (!toting(G.object))
    {
        actspk(G.verb);
        return;
    }

    if (G.object != OIL && G.object != WATER)
    {
        rspeak(78);
        return;
    }

    G.prop[BOTTLE] = 1;
    G.place[G.object] = 0;

    if (at(PLANT))
    {
        if (G.object != WATER)
            rspeak(112);
        else
        {
            pspeak(PLANT, G.prop[PLANT] + 1);
            G.prop[PLANT] = (G.prop[PLANT] + 2) % 6;
            G.prop[PLANT2] = G.prop[PLANT] / 2;
            describe();
        }
    }
    else
    {
        if (at(DOOR))
        {
            G.prop[DOOR] = (G.object == OIL ? 1 : 0);
            rspeak(113 + G.prop[DOOR]);
        }
        else
            rspeak(77);
    }

    return;
}


/*  EAT  */

VOID PASCAL veat PROTO((VOID))
{
    auto     SHORT      msg;

    switch (G.object)
    {
        case FOOD:
            dstroy(FOOD);
            msg = 72;
            break;

        case BIRD:
        case SNAKE:
        case CLAM:
        case OYSTER:
        case DWARF:
        case DRAGON:
        case TROLL:
        case BEAR:
            msg = 71;
            break;

        default:
            actspk(G.verb);
            return;
    }

    rspeak(msg);
    return;
}


/*  DRINK  */

VOID PASCAL vdrink PROTO((VOID))
{
    if (G.object != WATER)
        rspeak(110);
    else
    {
        if (liq() != WATER || !here(BOTTLE))
            actspk(G.verb);
        else
        {
            G.prop[BOTTLE] = 1;
            G.place[WATER] = 0;
            rspeak(74);
        }
    }

    return;
}


/*  THROW etc.  */

VOID PASCAL vthrow PROTO((VOID))
{
    auto     SHORT      msg;
    auto     SHORT      i;

    if (toting(ROD2) && G.object == ROD && !toting(ROD))
        G.object = ROD2;

    if (!toting(G.object))
    {
        actspk(G.verb);
        return;
    }

    /* treasure to troll */
    if (at(TROLL) && G.object >= 50 && G.object < MAXOBJ)
    {
        rspeak(159);
        drop(G.object, 0);
        move(TROLL, 0);
        move((TROLL + MAXOBJ), 0);
        drop(TROLL2, 117);
        drop((TROLL2 + MAXOBJ), 122);
        juggle(CHASM);
        return;
    }

    /* feed the bears... */
    if (G.object == FOOD && here(BEAR))
    {
        G.object = BEAR;
        vfeed();
        return;
    }

    /* if not axe, same as drop... */
    if (G.object != AXE)
    {
        vdrop();
        return;
    }

    /* AXE is THROWN at a dwarf... */
    if (i = dcheck())
    {
        msg = 48;
        if (pct(33))
        {
            G.dseen[i] = G.dloc[i] = 0;
            msg = 47;
            ++G.dkill;
            if (G.dkill == 1)
                msg = 149;
        }
    }
    else                        /* at a dragon... */
    {
        if (at(DRAGON) && G.prop[DRAGON] == 0)
            msg = 152;
        else                    /* at the troll... */
        {
            if (at(TROLL))
                msg = 158;
            else                /* at the bear... */
            {
                if (here(BEAR) && G.prop[BEAR] == 0)
                {
                    rspeak(164);
                    drop(AXE, G.loc);
                    G.fixed[AXE] = -1;
                    G.prop[AXE]  = 1;
                    juggle(BEAR);
                    return;
                }

                /* otherwise it is an attack */
                G.verb = KILL;
                G.object = 0;
                itverb();
                return;
            }
        }
    }

    /* handle the left over axe... */
    rspeak(msg);
    drop(AXE, G.loc);
    describe();
    return;
}


/*  INVENTORY, FIND etc.  */

VOID PASCAL vfind PROTO((VOID))
{
    auto     SHORT      msg;

    if (toting(G.object))
        msg = 24;
    else
    {
        if (G.closed)
            msg = 138;
        else
        {
            if (dcheck() && G.dflag >= 2 && G.object == DWARF)
                msg = 94;
            else
            {
                if (at(G.object) ||
                    (liq() == G.object && here(BOTTLE)) ||
                    G.object == liqloc(G.loc))
                    msg = 94;
                else
                {
                    actspk(G.verb);
                    return;
                }
            }
        }
    }

    rspeak(msg);
    return;
}


/*  FILL  */

VOID PASCAL vfill PROTO((VOID))
{
    auto     SHORT      msg;
    auto     SHORT      i;

    switch (G.object)
    {
        case BOTTLE:
            if (liq() != 0)
                msg = 105;
            else
            {
                if (liqloc(G.loc) == 0)
                    msg = 106;
                else
                {
                    G.prop[BOTTLE] = cond[G.loc] & WATOIL;
                    i = liq();
                    if (toting(BOTTLE))
                        G.place[i] = -1;

                    msg = (i == OIL ? 108 : 107);
                }
            }

            break;

        case VASE:
            if (liqloc(G.loc) == 0)
            {
                msg = 144;
                break;
            }

            if (!toting(VASE))
            {
                msg = 29;
                break;
            }

            rspeak(145);
            vdrop();
            return;

        default:
            msg = 29;
            break;
    }

    rspeak(msg);
    return;
}


/*  FEED  */

VOID PASCAL vfeed PROTO((VOID))
{
    auto     SHORT      msg;

    switch (G.object)
    {
        case BIRD:
            msg = 100;
            break;

        case DWARF:
            if (!here(FOOD))
            {
                actspk(G.verb);
                return;
            }

            ++G.dflag;
            msg = 103;
            break;

        case BEAR:
            if (!here(FOOD))
            {
                if (G.prop[BEAR] == 0)
                    msg = 102;
                else
                {
                    if (G.prop[BEAR] == 3)
                        msg = 110;
                    else
                    {
                        actspk(G.verb);
                        return;
                    }
                }

                break;
            }

            dstroy(FOOD);
            G.prop[BEAR] = 1;
            G.fixed[AXE] = 0;
            G.prop[AXE] = 0;
            msg = 168;
            break;

        case DRAGON:
            msg = (G.prop[DRAGON] != 0 ? 110 : 102);
            break;

        case TROLL:
            msg = 182;
            break;

        case SNAKE:
            if (G.closed || !here(BIRD))
            {
                msg = 102;
                break;
            }

            msg = 101;
            dstroy(BIRD);
            G.prop[BIRD] = 0;
            ++G.tally2;
            break;

        default:
            msg = 14;
            break;
    }

    rspeak(msg);
    return;
}


/*  READ etc.  */

VOID PASCAL vread PROTO((VOID))
{
    auto     SHORT      msg;

    msg = 0;
    if (dark())
    {
        printf("I see no %s here.\n", probj(G.object));
        return;
    }

    switch (G.object)
    {
        case MAGAZINE:
            msg = 190;
            break;

        case TABLET:
            msg = 196;
            break;

        case MESSAGE:
            msg = 191;
            break;

        case OYSTER:
            if (!toting(OYSTER) || !G.closed)
                break;

            yes(192, 193, 54);
            return;

        default:
            break;
    }

    if (msg)
        rspeak(msg);
    else
        actspk(G.verb);

    return;
}


/*  BLAST etc.  */

VOID PASCAL vblast PROTO((VOID))
{
    if (G.prop[ROD2] < 0 || !G.closed)
        actspk(G.verb);
    else
    {
        G.bonus = 133;
        if (G.loc == 115)
            G.bonus = 134;

        if (here(ROD2))
            G.bonus = 135;

        rspeak(G.bonus);
        normend();
    }

    return;
}


/*  BREAK etc.  */

VOID PASCAL vbreak PROTO((VOID))
{
    auto     SHORT      msg;

    if (G.object == MIRROR)
    {
        msg = 148;
        if (G.closed)
        {
            rspeak(197);
            dwarfend();
        }
    }
    else
    {
        if (G.object == VASE && G.prop[VASE] == 0)
        {
            msg = 198;
            if (toting(VASE))
                drop(VASE, G.loc);

            G.prop[VASE]  = 2;
            G.fixed[VASE] = -1;
        }
        else
        {
            actspk(G.verb);
            return;
        }
    }

    rspeak(msg);
    return;
}


/*  WAKE etc.  */

VOID PASCAL vwake PROTO((VOID))
{
    if (G.object != DWARF || !G.closed)
        actspk(G.verb);
    else
    {
        rspeak(199);
        dwarfend();
    }

    return;
}


/*  Routine to speak default verb message  */

#if ANSI_PROTO
VOID PASCAL actspk(SHORT verb)
#else
VOID PASCAL actspk(verb)
SHORT       verb;
#endif
{
    auto SHORT      i;

    if (verb < 1 || verb > 31)
        bug(39);

    i = actmsg[verb];
    if (i)
        rspeak(i);

    return;
}


/*  Routine to indicate no reasonable object for verb found.  Used  */
/*  mostly by intransitive verbs.                                   */

VOID PASCAL needobj PROTO((VOID))
{
    auto SHORT      wtype, wval;

    analyze(word1, &wtype, &wval);
    printf("%s what?\n", wtype == 2 ? word1 : word2);
    return;
}
