
 /* TURN.C  no mods for V 1.43
  *
  * Modified all calls of rand() to irand() for Eco-C88 (BW)
  */

#include "advent.h"


/*  Routine to take 1 turn  */

VOID PASCAL turn PROTO((VOID))
{
    auto     SHORT        i;

    /* if closing, then he can't leave except via the main office. */
    if (G.newloc < 9 && G.newloc != 0 && G.closing)
    {
        rspeak(130);
        G.newloc = G.loc;
        if (!G.panic)
            G.clock2 = 15;

        G.panic = 1;
    }

    /* see if a dwarf has seen him and has come from where he wants to go. */
    if (G.newloc != G.loc && !forced(G.loc) && cond[G.loc] & NOPIRAT == 0)
    {
        for (i = 1; i < (DWARFMAX - 1); ++i)
        {
            if (G.odloc[i] == G.newloc && G.dseen[i])
            {
                G.newloc = G.loc;
                rspeak(2);
                break;
            }
        }
    }

    dwarves();

    /* on to the regular move. */
    if (G.loc != G.newloc)
    {
        ++G.turns;
        G.loc = G.newloc;
        /* check for death */
        if (G.loc == 0)
        {
            death();
            return;
        }

        /* check for forced move */
        if (forced(G.loc))
        {
            describe();
            domove();
            return;
        }

        /* check for wandering in dark */
        if (G.wzdark && dark() && pct(35))
        {
            rspeak(23);
            G.oldloc2 = G.loc;
            death();
            return;
        }

        /* describe his situation */
        describe();
        if (!dark())
        {
            ++G.visited[G.loc];
            descitem();
        }
    }

    if (G.closed)
    {
        if (G.prop[OYSTER] < 0 && toting(OYSTER))
            pspeak(OYSTER, 1);

        for (i = 1; i <= MAXOBJ; ++i)
        {
            if (toting(i) && G.prop[i] < 0)
                G.prop[i] = -1 - G.prop[i];
        }
    }

    G.wzdark = dark();
    if (G.knfloc > 0 && G.knfloc != G.loc)
        G.knfloc = 0;

    /* run the timer routine */
    if (stimer())
        return;

    /* ask what he wants to do */
    /* debug */
    if (dbgflg)
        printf("Your current location is %d\n", G.loc);

    while (!english())
        ;

    /* act on his instructions */
    if (G.motion)
        domove();
    else
    {
        if (G.object)
            doobj();
        else
            itverb();
    }

    return;
}


/*  Routine to describe current location  */

VOID PASCAL describe PROTO((VOID))
{
    if (toting(BEAR))
        rspeak(141);

    if (dark())
        rspeak(16);
    else
    {
        if (G.visited[G.loc] && G.brief_sw)
            descsh(G.loc);
        else
            desclg(G.loc);
    }

    if (G.loc == 33 && pct(25) && !G.closing)
        rspeak(8);

    return;
}


/*  Routine to describe visible items  */

VOID PASCAL descitem PROTO((VOID))
{
    auto     SHORT        i, state;

    for (i = 1; i < MAXOBJ; ++i)
    {
        if (at(i))
        {
            if (i == STEPS && toting(NUGGET))
                continue;

            if (G.prop[i] < 0)
            {
                if (G.closed)
                    continue;

                G.prop[i] = 0;
                if (i == RUG || i == CHAIN)
                    ++G.prop[i];

                --G.tally;
            }

            if (i == STEPS && G.loc == G.fixed[STEPS])
                state = 1;
            else
                state = G.prop[i];

            pspeak(i, state);
        }
    }

    if (G.tally == G.tally2 && G.tally != 0 && G.limit > 35)
        G.limit = 35;

    return;
}


/*  Routine to handle motion requests  */

VOID PASCAL domove PROTO((VOID))
{
    gettrav(G.loc);
    switch (G.motion)
    {
        case NULLX:
            break;

        case BACK:
            goback();
            break;

        case LOOK:
            if (G.detail++ < 3 && G.brief_sw)
                rspeak(15);

            G.wzdark = 0;
            G.visited[G.loc] = 0;
            G.newloc = G.loc;
            G.loc = 0;
            break;

        case CAVE:
            if (G.loc < 8)
                rspeak(57);
            else
                rspeak(58);

            break;

        default:
            G.oldloc2 = G.oldloc;
            G.oldloc = G.loc;
            dotrav();
            G.loc = 0;            /* Modified BW 09/28/85   */
    }

    return;
}


/*  Routine to handle request to return from whence we came!  */

VOID PASCAL goback PROTO((VOID))
{
    auto     SHORT            kk, k2, want, temp;
    auto     TRAV            *pSavTrav;
    auto     SHORT            sSavCnt;

    if (forced(G.oldloc))
        want = G.oldloc2;
    else
        want = G.oldloc;

    G.oldloc2 = G.oldloc;
    G.oldloc = G.loc;
    k2 = 0;
    if (want == G.loc)
    {
        rspeak(91);
        return;
    }

    pSavTrav = pTravel;
    sSavCnt  = sTravCnt;

    for (kk = 0; kk < sTravCnt; ++kk)
    {
        if (!pTravel[kk].tcond && pTravel[kk].tdest == want)
        {
            G.motion = pTravel[kk].tverb;
            dotrav();
            return;
        }

        if (!pTravel[kk].tcond)
        {
            k2   = kk;
            temp = pTravel[kk].tdest;
            gettrav(temp);
            if (forced(temp) && pTravel[0].tdest == want)
                k2 = temp;

            pTravel  = pSavTrav;
            sTravCnt = sSavCnt;
        }
    }

    if (k2)
    {
        G.motion = pTravel[k2].tverb;
        dotrav();
    }
    else
        rspeak(140);

    return;
}


/*  Routine to figure out a new loc given current loc and a motion.  */

VOID PASCAL dotrav PROTO((VOID))
{
    auto     SHORT       mvflag, hitflag, kk;
    auto     SHORT       rdest, rverb, rcond, robject;
    auto     SHORT       pctt;

    G.newloc = G.loc;
    mvflag = hitflag = 0;
    pctt   = rand() % 100;

    for (kk = 0; kk < sTravCnt && !mvflag; ++kk)
    {
        rdest   = pTravel[kk].tdest;
        rverb   = pTravel[kk].tverb;
        rcond   = pTravel[kk].tcond;
        robject = rcond % 100;
        if (rverb != 1 && rverb != G.motion && !hitflag)
            continue;

        ++hitflag;
        switch (rcond / 100)
        {
            case 0:
                if (rcond == 0 || pctt < rcond)
                    ++mvflag;

                /* debug */
                if (rcond && dbgflg)
                    printf("percent move %d %d\n", pctt, mvflag);

                break;

            case 1:
                if (robject == 0)
                    ++mvflag;
                else
                {
                    if (toting(robject))
                        ++mvflag;
                }

                break;

            case 2:
                if (toting(robject) || at(robject))
                    ++mvflag;

                break;

            case 3:
            case 4:
            case 5:
            case 7:
                if (G.prop[robject] != (rcond / 100) - 3)
                    ++mvflag;

                break;

            default:
                bug(37);
        }
    }

    if (!mvflag)
        badmove();
    else
    {
        if (rdest > 500)
            rspeak(rdest - 500);
        else
        {
            if (rdest > 300)
                spcmove(rdest);
            else
                G.newloc = rdest;
        }
    }

    return;
}


/*  The player tried a poor move option.  */

VOID PASCAL badmove PROTO((VOID))
{
    auto     SHORT        msg;

    msg = 12;
    if (G.motion >= 43 && G.motion <= 50)
        msg = 9;

    if (G.motion == 29 || G.motion == 30)
        msg = 9;

    if (G.motion == 7 || G.motion == 36 || G.motion == 37)
        msg = 10;

    if (G.motion == 11 || G.motion == 19)
        msg = 11;

    if (G.verb == FIND || G.verb == INVENTORY)
        msg = 59;

    if (G.motion == 62 || G.motion == 65)
        msg = 42;

    if (G.motion == 17)
        msg = 80;

    rspeak(msg);
    return;
}


/*  Routine to handle very special movement.  */

#if ANSI_PROTO
VOID PASCAL spcmove(SHORT rdest)
#else
VOID PASCAL spcmove(rdest)
SHORT       rdest;
#endif
{
    switch (rdest - 300)
    {
        case 1:         /* plover movement via alcove */
            if (!G.holding || (G.holding == 1 && toting(EMERALD)))
                G.newloc = (99 + 100) - G.loc;
            else
                rspeak(117);

            break;

        case 2:         /* trying to remove plover, bad route */
            drop(EMERALD, G.loc);
            break;

        case 3:         /* troll bridge */
            if (G.prop[TROLL] == 1)
            {
                pspeak(TROLL, 1);
                G.prop[TROLL] = 0;
                move(TROLL2, 0);
                move((TROLL2 + MAXOBJ), 0);
                move(TROLL, 117);
                move((TROLL + MAXOBJ), 122);
                juggle(CHASM);
                G.newloc = G.loc;
            }
            else
            {
                G.newloc = (G.loc == 117 ? 122 : 117);
                if (G.prop[TROLL] == 0)
                    ++G.prop[TROLL];

                if (!toting(BEAR))
                    return;

                rspeak(162);
                G.prop[CHASM] = 1;
                G.prop[TROLL] = 2;
                drop(BEAR, G.newloc);
                G.fixed[BEAR] = -1;
                G.prop[BEAR] = 3;
                if (G.prop[SPICES] < 0)
                    ++G.tally2;

                G.oldloc2 = G.newloc;
                death();
            }

            break;

        default:
            bug(38);
    }

    return;
}


/*  Routine to handle player's demise via waking up the dwarves...  */

VOID PASCAL dwarfend PROTO((VOID))
{
    death();
    normend();                  /* no return from here */
}


/*  normal end of game  */

VOID PASCAL normend PROTO((VOID))
{
    score();
    exit(1);
}


/*  scoring  */

VOID PASCAL score PROTO((VOID))
{
    auto     SHORT      t, i, k, s;

    s = t = 0;
    for (i = 50; i <= MAXTRS; ++i)
    {
        if (i == CHEST)
            k = 14;
        else
            k = i > CHEST ? 16 : 12;

        if (G.prop[i] >= 0)
            t += 2;

        if (G.place[i] == 3 && G.prop[i] == 0)
            t += k - 2;
    }

    printf("%-20s%d\n", "Treasures:", s = t);
    t = (MAXDIE - G.numdie) * 10;
    if (t)
        printf("%-20s%d\n", "Survival:", t);

    s += t;
    if (!G.gaveup)
        s += 4;

    t = G.dflag ? 25 : 0;
    if (t)
        printf("%-20s%d\n", "Getting well in:", t);

    s += t;
    t = G.closing ? 25 : 0;
    if (t)
        printf("%-20s%d\n", "Masters section:", t);

    s += t;

    if (G.closed)
    {
        if (G.bonus == 0)
            t = 10;
        else
        {
            if (G.bonus == 135)
                t = 25;
            else
            {
                if (G.bonus == 134)
                    t = 30;
                else
                {
                    if (G.bonus == 133)
                        t = 45;
                }
            }
        }

        printf("%-20s%d\n", "bonus:", t);
        s += t;
    }

    if (G.place[MAGAZINE] == 108)
        s += 1;

    s += 2;
    printf("%-20s%d\n", "Score:", s);
    return;
}


/*  Handle the passing on of one of the player's incarnations...  */

VOID PASCAL death PROTO((VOID))
{
    auto     SHORT       yea, i, j;

    if (!G.closing)
    {
        yea = yes(81 + G.numdie * 2, 82 + G.numdie * 2, 54);
        if (++G.numdie >= MAXDIE || !yea)
            normend();

        G.place[WATER] = 0;
        G.place[OIL] = 0;
        if (toting(LAMP))
            G.prop[LAMP] = 0;

        for (j = 1; j < 101; ++j)
        {
            i = 101 - j;
            if (toting(i))
                drop(i, i == LAMP ? 1 : G.oldloc2);
        }

        G.newloc = 3;
        G.oldloc = G.loc;
        return;
    }

    /* closing -- no resurrection... */
    rspeak(131);
    ++G.numdie;
    normend();                          /* no return from here */
}


/*  Routine to process an object.  */

VOID PASCAL doobj PROTO((VOID))
{
    /* is object here?  if so, transitive */
    if (G.fixed[G.object] == G.loc || here(G.object))
        trobj();
    else
    {
        /* did he give grate as destination? */
        if (G.object == GRATE)
        {
            if (G.loc == 1 || G.loc == 4 || G.loc == 7)
            {
                G.motion = DEPRESSION;
                domove();
            }
            else
            {
                if (G.loc > 9 && G.loc < 15)
                {
                    G.motion = ENTRANCE;
                    domove();
                }
            }
        }
        else
        {
            /* is it a dwarf he is after? */
            if (dcheck() && G.dflag >= 2)
            {
                G.object = DWARF;
                trobj();
            }
            else
            {
                /* is he trying to get/use a liquid? */
                if ((liq() == G.object && here(BOTTLE))
                           || liqloc(G.loc) == G.object)
                    trobj();
                else
                {
                    if (G.object == PLANT && at(PLANT2) && G.prop[PLANT2] == 0)
                    {
                        G.object = PLANT2;
                        trobj();
                    }
                    else
                    {
                        /* is he trying to grab a knife? */
                        if (G.object == KNIFE && G.knfloc == G.loc)
                        {
                            rspeak(116);
                            G.knfloc = -1;
                        }
                        else
                        {
                            /* is he trying to get at dynamite? */
                            if (G.object == ROD && here(ROD2))
                            {
                                G.object = ROD2;
                                trobj();
                            }
                            else
                                printf("I see no %s here.\n", probj(G.object));
                        }
                    }
                }
            }
        }
    }

    return;
}


/*  Routine to process an object being referred to.  */

VOID PASCAL trobj PROTO((VOID))
{
    if (G.verb)
        trverb();
    else
        printf("What do you want to do with the %s?\n", probj(G.object));

    return;
}


/*  Routine to print word corresponding to object  */

#if ANSI_PROTO
char * PASCAL probj(SHORT object)
#else
char * PASCAL probj(object)
SHORT       object;
#endif
{
    auto     SHORT        wtype, wval;

    object = object;                        /* eliminate compiler warning */
    analyze(word1, &wtype, &wval);
    return((wtype == 1) ? word1 : word2);
}


/*  dwarf stuff.  */

VOID PASCAL dwarves PROTO((VOID))
{
    auto     SHORT      i, j, k, try, attack, stick, dtotal;

    /* see if dwarves allowed here */
    if (G.newloc == 0 || forced(G.newloc) || cond[G.newloc] & NOPIRAT)
        return;

    /* see if dwarves are active. */
    if (!G.dflag)
    {
        if (G.newloc > 15)
            ++G.dflag;

        return;
    }

    /* if first close encounter (of 3rd kind) kill 0, 1 or 2 */
    if (G.dflag == 1)
    {
        if (G.newloc < 15 || pct(95))
            return;

        ++G.dflag;
        for (i = 1; i < 3; ++i)
        {
            if (pct(50))
                G.dloc[rand() % 5 + 1] = 0;
        }

        for (i = 1; i < (DWARFMAX - 1); ++i)
        {
            if (G.dloc[i] == G.newloc)
                G.dloc[i] = G.daltloc;

            G.odloc[i] = G.dloc[i];
        }

        rspeak(3);
        drop(AXE, G.newloc);
        return;
    }

    dtotal = attack = stick = 0;
    for (i = 1; i < DWARFMAX; ++i)
    {
        if (G.dloc[i] == 0)
            continue;

        /* move a dwarf at random.  we don't have a matrix around to do it as
         * in the original version... */
        for (try = 1; try < 20; ++try)
        {
            j = rand() % 106 + 15;      /* allowed area */
            if (j != G.odloc[i] && j != G.dloc[i]
                              &&
                !(i == (DWARFMAX - 1) && cond[j] & NOPIRAT == 1))
                break;
        }

        if (j == 0)
            j = G.odloc[i];

        G.odloc[i] = G.dloc[i];
        G.dloc[i] = j;
        if ((G.dseen[i] && G.newloc >= 15) ||
            G.dloc[i] == G.newloc || G.odloc[i] == G.newloc)
            G.dseen[i] = 1;
        else
            G.dseen[i] = 0;

        if (!G.dseen[i])
            continue;

        G.dloc[i] = G.newloc;
        if (i == 6)
            dopirate();
        else
        {
            ++dtotal;
            if (G.odloc[i] == G.dloc[i])
            {
                ++attack;
                if (G.knfloc >= 0)
                    G.knfloc = G.newloc;

                if (rand() % 1000 < 30 * (G.dflag - 2))
                    ++stick;
            }
        }
    }

    if (dtotal == 0)
        return;

    if (dtotal > 1)
        printf("There are %d threatening little dwarves in the room with you!\n", dtotal);
    else
        rspeak(4);

    if (attack == 0)
        return;

    if (G.dflag == 2)
        ++G.dflag;

    if (attack > 1)
    {
        printf("%d of them throw knives at you!!\n", attack);
        k = 6;
    }
    else
    {
        rspeak(5);
        k = 52;
    }

    if (stick <= 1)
    {
        rspeak(stick + k);
        if (stick == 0)
            return;
    }
    else
        printf("%d of them get you !!!\n", stick);

    G.oldloc2 = G.newloc;
    death();

    return;
}


/*  pirate stuff  */

VOID PASCAL dopirate PROTO((VOID))
{
    auto     SHORT        j, k;

    if (G.newloc == G.chloc || G.prop[CHEST] >= 0)
        return;

    k = 0;
    for (j = 50; j <= MAXTRS; ++j)
    {
        if (j != PYRAMID
              ||
            (G.newloc != G.place[PYRAMID] && G.newloc != G.place[EMERALD]))
        {
            if (toting(j))
                goto stealit;

            if (here(j))
                ++k;
        }
    }

    if (G.tally == G.tally2 + 1 && k == 0 && G.place[CHEST] == 0
                            &&
                 here(LAMP) && G.prop[LAMP] == 1)
    {
        rspeak(186);
        move(CHEST, G.chloc);
        move(MESSAGE, G.chloc2);
        G.dloc[6] = G.chloc;
        G.odloc[6] = G.chloc;
        G.dseen[6] = 0;
        return;
    }

    if (G.odloc[6] != G.dloc[6] && pct(20))
    {
        rspeak(127);
        return;
    }

    return;

stealit:
    rspeak(128);
    if (G.place[MESSAGE] == 0)
        move(CHEST, G.chloc);

    move(MESSAGE, G.chloc2);
    for (j = 50; j <= MAXTRS; ++j)
    {
        if (j == PYRAMID &&
            (G.newloc == G.place[PYRAMID] ||
             G.newloc == G.place[EMERALD]))
            continue;

        if (at(j) && G.fixed[j] == 0)
            carry(j, G.newloc);

        if (toting(j))
            drop(j, G.chloc);
    }

    G.dloc[6] = G.chloc;
    G.odloc[6] = G.chloc;
    G.dseen[6] = 0;

    return;
}


/*  special time limit stuff...  */

BOOL PASCAL stimer PROTO((VOID))
{
    register SHORT        i;

    G.foobar = G.foobar > 0 ? -G.foobar : 0;
    if (G.tally == 0 && G.loc >= 15 && G.loc != 33)
        --G.clock1;

    if (G.clock1 == 0)
    {
        /* start closing the cave */
        G.prop[GRATE] = 0;
        G.prop[FISSURE] = 0;
        for (i = 1; i < DWARFMAX; ++i)
            G.dseen[i] = 0;

        move(TROLL, 0);
        move((TROLL + MAXOBJ), 0);
        move(TROLL2, 117);
        move((TROLL2 + MAXOBJ), 122);
        juggle(CHASM);
        if (G.prop[BEAR] != 3)
            dstroy(BEAR);

        G.prop[CHAIN] = 0;
        G.fixed[CHAIN] = 0;
        G.prop[AXE] = 0;
        G.fixed[AXE] = 0;
        rspeak(129);
        G.clock1  = -1;
        G.closing = 1;
        return(FALSE);
    }

    if (G.clock1 < 0)
        --G.clock2;

    if (G.clock2 == 0)
    {
        /* set up storage room... and close the cave... */
        G.prop[BOTTLE] = put(BOTTLE, 115, 1);
        G.prop[PLANT]  = put(PLANT, 115, 0);
        G.prop[OYSTER] = put(OYSTER, 115, 0);
        G.prop[LAMP]   = put(LAMP, 115, 0);
        G.prop[ROD]    = put(ROD, 115, 0);
        G.prop[DWARF]  = put(DWARF, 115, 0);
        G.loc        = 115;
        G.oldloc     = 115;
        G.newloc     = 115;
        put(GRATE, 116, 0);
        G.prop[SNAKE]  = put(SNAKE, 116, 1);
        G.prop[BIRD]   = put(BIRD, 116, 1);
        G.prop[CAGE]   = put(CAGE, 116, 0);
        G.prop[ROD2]   = put(ROD2, 116, 0);
        G.prop[PILLOW] = put(PILLOW, 116, 0);
        G.prop[MIRROR] = put(MIRROR, 115, 0);
        G.fixed[MIRROR] = 116;
        for (i = 1; i <= MAXOBJ; ++i)
        {
            if (toting(i))
                dstroy(i);
        }

        rspeak(132);
        G.closed = 1;
        return(TRUE);
    }

    if (G.prop[LAMP] == 1)
        --G.limit;

    if (G.limit <= 30 &&
        here(BATTERIES) && G.prop[BATTERIES] == 0 &&
        here(LAMP))
    {
        rspeak(188);
        G.prop[BATTERIES] = 1;
        if (toting(BATTERIES))
            drop(BATTERIES, G.loc);

        G.limit += 2500;
        G.lmwarn = 0;
        return(FALSE);
    }

    if (G.limit == 0)
    {
        --G.limit;
        G.prop[LAMP] = 0;
        if (here(LAMP))
            rspeak(184);

        return(FALSE);
    }

    if (G.limit < 0 && G.loc <= 8)
    {
        rspeak(185);
        G.gaveup = 1;
        normend();
    }

    if (G.limit <= 30)
    {
        if (G.lmwarn || !here(LAMP))
            return(FALSE);

        G.lmwarn = 1;
        i = 187;
        if (G.place[BATTERIES] == 0)
            i = 183;

        if (G.prop[BATTERIES] == 1)
            i = 189;

        rspeak(i);
    }

    return(FALSE);
}
