home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 2 / Apprentice-Release2.iso / Source Code / C / Games / NetHack 3.1.3 / source / src / ball.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-08-01  |  15.9 KB  |  604 lines  |  [TEXT/R*ch]

  1. /*    SCCS Id: @(#)ball.c    3.1    93/05/15    */
  2. /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
  3. /* NetHack may be freely redistributed.  See license for details. */
  4.  
  5. /* Ball & Chain =============================================================*/
  6.  
  7. #include "hack.h"
  8.  
  9. static int NDECL(bc_order);
  10. static void NDECL(litter);
  11.  
  12. void
  13. ballfall()
  14. {
  15.     boolean gets_hit;
  16.  
  17.     gets_hit = (((uball->ox != u.ux) || (uball->oy != u.uy)) &&
  18.             ((uwep == uball)? FALSE : (boolean)rn2(5)));
  19.     if (carried(uball)) {
  20.         pline("Startled, you drop the iron ball.");
  21.         if (uwep == uball)
  22.             setuwep((struct obj *)0);
  23.         if (uwep != uball)
  24.             freeinv(uball);
  25.     }
  26.     if(gets_hit){
  27.         int dmg = rn1(7,25);
  28.         pline("The iron ball falls on your %s.",
  29.             body_part(HEAD));
  30.         if (uarmh)
  31.             if(is_metallic(uarmh)) {
  32.             pline("Fortunately, you are wearing a hard helmet.");
  33.             dmg = 3;
  34.             } else if (flags.verbose)
  35.             Your("%s does not protect you.", xname(uarmh));
  36.         losehp(dmg, "Crunched in the head by an iron ball",
  37.             NO_KILLER_PREFIX);
  38.     }
  39. }
  40.  
  41. /*
  42.  *  To make this work, we have to mess with the hero's mind.  The rules for
  43.  *  ball&chain are:
  44.  *
  45.  *    1. If the hero can see them, fine.
  46.  *    2. If the hero can't see either, it isn't seen.
  47.  *    3. If either is felt it is seen.
  48.  *    4. If either is felt and moved, it disappears.
  49.  *
  50.  *  If the hero can see, then when a move is done, the ball and chain are
  51.  *  first picked up, the positions under them are corrected, then they
  52.  *  are moved after the hero moves.  Not too bad.
  53.  *
  54.  *  If the hero is blind, then she can "feel" the ball and/or chain at any
  55.  *  time.  However, when the hero moves, the felt ball and/or chain become
  56.  *  unfelt and whatever was felt "under" the ball&chain appears.  Pretty
  57.  *  nifty, but it requires that the ball&chain "remember" what was under
  58.  *  them --- i.e. they pick-up glyphs when they are felt and drop them when
  59.  *  moved (and felt).  When swallowed, the ball&chain are pulled completely
  60.  *  off of the dungeon, but are still on the object chain.  They are placed
  61.  *  under the hero when she is expelled.
  62.  */
  63.  
  64. /*
  65.  * from you.h
  66.  *    int u.bglyph        glyph under the ball
  67.  *    int u.cglyph        glyph under the chain
  68.  *    int u.bc_felt        mask for ball/chain being felt
  69.  *    #define BC_BALL  0x01    bit mask in u.bc_felt for ball
  70.  *    #define BC_CHAIN 0x02    bit mask in u.bc_felt for chain
  71.  *    int u.bc_order        ball & chain order
  72.  *
  73.  * u.bc_felt is also manipulated in display.c and read.c, the others only
  74.  * in this file.  None of these variables are valid unless the player is
  75.  * Blind.
  76.  */
  77.  
  78. /* values for u.bc_order */
  79. #define BCPOS_DIFFER    0    /* ball & chain at different positions */
  80. #define BCPOS_CHAIN    1    /* chain on top of ball */
  81. #define BCPOS_BALL    2    /* ball on top of chain */
  82.  
  83.  
  84.  
  85. /*
  86.  *  Place the ball & chain under the hero.  Make sure that the ball & chain
  87.  *  variables are set (actually only needed when blind, but what the heck).
  88.  *  It is assumed that when this is called, the ball and chain are NOT
  89.  *  attached to the object list.
  90.  *
  91.  *  Should not be called while swallowed.
  92.  */
  93. void
  94. placebc()
  95. {
  96.     if (!uchain || !uball) {
  97.     impossible("Where are your ball and chain?");
  98.     return;
  99.     }
  100.  
  101.     (void) flooreffects(uchain, u.ux, u.uy, "");    /* chain might rust */
  102.     uchain->nobj = fobj;        /* put chain on object list */
  103.     fobj = uchain;
  104.  
  105.     if (carried(uball))        /* the ball is carried */
  106.     u.bc_order = BCPOS_DIFFER;
  107.     else {
  108.     /* ball might rust -- already checked when carried */
  109.     (void) flooreffects(uball, u.ux, u.uy, "");
  110.     uball->nobj = fobj;        /* put ball on object list */
  111.     fobj = uball;
  112.  
  113.     place_object(uball, u.ux, u.uy);
  114.     u.bc_order = BCPOS_CHAIN;
  115.     }
  116.  
  117.     place_object(uchain, u.ux, u.uy);
  118.  
  119.     u.bglyph = u.cglyph = levl[u.ux][u.uy].glyph;   /* pick up glyph */
  120.  
  121.     newsym(u.ux,u.uy);
  122. }
  123.  
  124. void
  125. unplacebc()
  126. {
  127.     if (u.uswallow) return;    /* ball&chain not placed while swallowed */
  128.  
  129.     if (!carried(uball)) {
  130.     freeobj(uball);
  131.     if (Blind && (u.bc_felt & BC_BALL))        /* drop glyph */
  132.         levl[uball->ox][uball->oy].glyph = u.bglyph;
  133.  
  134.     newsym(uball->ox,uball->oy);
  135.     }
  136.     freeobj(uchain);
  137.     if (Blind && (u.bc_felt & BC_CHAIN))        /* drop glyph */
  138.     levl[uchain->ox][uchain->oy].glyph = u.cglyph;
  139.  
  140.     newsym(uchain->ox,uchain->oy);
  141.     u.bc_felt = 0;                    /* feel nothing */
  142. }
  143.  
  144.  
  145. /*
  146.  *  Return the stacking of the hero's ball & chain.  This assumes that the
  147.  *  hero is being punished.
  148.  */
  149. static int
  150. bc_order()
  151. {
  152.     struct obj *obj;
  153.  
  154.     if (uchain->ox != uball->ox || uchain->oy != uball->oy || carried(uball)
  155.         || u.uswallow)
  156.     return BCPOS_DIFFER;
  157.  
  158.     for (obj = level.objects[uball->ox][uball->oy]; obj; obj = obj->nexthere) {
  159.     if (obj == uchain) return BCPOS_CHAIN;
  160.     if (obj == uball) return BCPOS_BALL;
  161.     }
  162.     impossible("bc_order:  ball&chain not in same location!");
  163.     return BCPOS_DIFFER;
  164. }
  165.  
  166. /*
  167.  *  set_bc()
  168.  *
  169.  *  The hero is either about to go blind or already blind and just punished.
  170.  *  Set up the ball and chain variables so that the ball and chain are "felt".
  171.  */
  172. void
  173. set_bc(already_blind)
  174. int already_blind;
  175. {
  176.     int ball_on_floor = !carried(uball);
  177.  
  178.     u.bc_order = bc_order();                /* get the order */
  179.     u.bc_felt = ball_on_floor ? BC_BALL|BC_CHAIN : BC_CHAIN;    /* felt */
  180.  
  181.     if (already_blind || u.uswallow) {
  182.     u.cglyph = u.bglyph = levl[u.ux][u.uy].glyph;
  183.     return;
  184.     }
  185.  
  186.     /*
  187.      *  Since we can still see, remove the ball&chain and get the glyph that
  188.      *  would be beneath them.  Then put the ball&chain back.  This is pretty
  189.      *  disgusting, but it will work.
  190.      */
  191.     remove_object(uchain);
  192.     if (ball_on_floor) remove_object(uball);
  193.  
  194.     newsym(uchain->ox, uchain->oy);
  195.     u.cglyph = levl[uchain->ox][uchain->oy].glyph;
  196.  
  197.     if (u.bc_order == BCPOS_DIFFER) {        /* different locations */
  198.     place_object(uchain, uchain->ox, uchain->oy);
  199.     newsym(uchain->ox, uchain->oy);
  200.     if (ball_on_floor) {
  201.         newsym(uball->ox, uball->oy);        /* see under ball */
  202.         u.bglyph = levl[uball->ox][uball->oy].glyph;
  203.         place_object(uball,  uball->ox, uball->oy);
  204.         newsym(uball->ox, uball->oy);        /* restore ball */
  205.     }
  206.     } else {
  207.     u.bglyph = u.cglyph;
  208.     if (u.bc_order == BCPOS_CHAIN) {
  209.         place_object(uball,  uball->ox, uball->oy);
  210.         place_object(uchain, uchain->ox, uchain->oy);
  211.     } else {
  212.         place_object(uchain, uchain->ox, uchain->oy);
  213.         place_object(uball,  uball->ox, uball->oy);
  214.     }
  215.     newsym(uball->ox, uball->oy);
  216.     }
  217. }
  218.  
  219.  
  220. /*
  221.  *  move_bc()
  222.  *
  223.  *  Move the ball and chain.  This is called twice for every move.  The first
  224.  *  time to pick up the ball and chain before the move, the second time to
  225.  *  place the ball and chain after the move.  If the ball is carried, this
  226.  *  function should never have BC_BALL as part of its control.
  227.  *
  228.  *  Should not be called while swallowed.
  229.  */
  230. void
  231. move_bc(before, control, ballx, bally, chainx, chainy)
  232. int   before, control;
  233. xchar ballx, bally, chainx, chainy;    /* only matter !before */
  234. {
  235.     if (Blind) {
  236.     /*
  237.      *  The hero is blind.  Time to work hard.  The ball and chain that
  238.      *  are attached to the hero are very special.  The hero knows that
  239.      *  they are attached, so when they move, the hero knows that they
  240.      *  aren't at the last position remembered.  This is complicated
  241.      *  by the fact that the hero can "feel" the surrounding locations
  242.      *  at any time, hence, making one or both of them show up again.
  243.      *  So, we have to keep track of which is felt at any one time and
  244.      *  act accordingly.
  245.      */
  246.     if (!before) {
  247.         if ((control & BC_CHAIN) && (control & BC_BALL)) {
  248.         /*
  249.          *  Both ball and chain moved.  If felt, drop glyph.
  250.          */
  251.         if (u.bc_felt & BC_BALL)
  252.             levl[uball->ox][uball->oy].glyph = u.bglyph;
  253.         if (u.bc_felt & BC_CHAIN)
  254.             levl[uchain->ox][uchain->oy].glyph = u.cglyph;
  255.         u.bc_felt = 0;
  256.  
  257.         /* Pick up glyph at new location. */
  258.         u.bglyph = levl[ballx][bally].glyph;
  259.         u.cglyph = levl[chainx][chainy].glyph;
  260.  
  261.         movobj(uball,ballx,bally);
  262.         movobj(uchain,chainx,chainy);
  263.         } else if (control & BC_BALL) {
  264.         if (u.bc_felt & BC_BALL) {
  265.             if (u.bc_order == BCPOS_DIFFER) {    /* ball by itself */
  266.             levl[uball->ox][uball->oy].glyph = u.bglyph;
  267.             } else if (u.bc_order == BCPOS_BALL) {
  268.             if (u.bc_felt & BC_CHAIN) {   /* know chain is there */
  269.                 map_object(uchain, 0);
  270.             } else {
  271.                 levl[uball->ox][uball->oy].glyph = u.bglyph;
  272.             }
  273.             }
  274.             u.bc_felt &= ~BC_BALL;    /* no longer feel the ball */
  275.         }
  276.  
  277.         /* Pick up glyph at new position. */
  278.         u.bglyph = (ballx != chainx || bally != chainy) ?
  279.                     levl[ballx][bally].glyph : u.cglyph;
  280.  
  281.         movobj(uball,ballx,bally);
  282.         } else if (control & BC_CHAIN) {
  283.         if (u.bc_felt & BC_CHAIN) {
  284.             if (u.bc_order == BCPOS_DIFFER) {
  285.             levl[uchain->ox][uchain->oy].glyph = u.cglyph;
  286.             } else if (u.bc_order == BCPOS_CHAIN) {
  287.             if (u.bc_felt & BC_BALL) {
  288.                 map_object(uball, 0);
  289.             } else {
  290.                 levl[uchain->ox][uchain->oy].glyph = u.cglyph;
  291.             }
  292.             }
  293.             u.bc_felt &= ~BC_CHAIN;
  294.         }
  295.         /* Pick up glyph at new position. */
  296.         u.cglyph = (ballx != chainx || bally != chainy) ?
  297.                     levl[chainx][chainy].glyph : u.bglyph;
  298.  
  299.         movobj(uchain,chainx,chainy);
  300.         }
  301.  
  302.         u.bc_order = bc_order();    /* reset the order */
  303.     }
  304.  
  305.     } else {
  306.     /*
  307.      *  The hero is not blind.  To make this work correctly, we need to
  308.      *  pick up the ball and chain before the hero moves, then put them
  309.      *  in their new positions after the hero moves.
  310.      */
  311.     if (before) {
  312.         if (!control) {
  313.         /*
  314.          * Neither ball nor chain is moving, so remember which was
  315.          * on top until !before.  Use the variable u.bc_order
  316.          * since it is only valid when blind.
  317.          */
  318.         u.bc_order = bc_order();
  319.         }
  320.  
  321.         remove_object(uchain);
  322.         newsym(uchain->ox, uchain->oy);
  323.         if (!carried(uball)) {
  324.         remove_object(uball);
  325.         newsym(uball->ox,  uball->oy);
  326.         }
  327.     } else {
  328.         int on_floor = !carried(uball);
  329.  
  330.         if ((control & BC_CHAIN) ||
  331.                 (!control && u.bc_order == BCPOS_CHAIN)) {
  332.         /* If the chain moved or nothing moved & chain on top. */
  333.         if (on_floor) place_object(uball,  ballx, bally);
  334.         place_object(uchain, chainx, chainy);    /* chain on top */
  335.         } else {
  336.         place_object(uchain, chainx, chainy);
  337.         if (on_floor) place_object(uball,  ballx, bally);
  338.                                 /* ball on top */
  339.         }
  340.         newsym(chainx, chainy);
  341.         if (on_floor) newsym(ballx, bally);
  342.     }
  343.     }
  344. }
  345.  
  346. /* return TRUE if ball could be dragged
  347.  *
  348.  *  Should not be called while swallowed.
  349.  */
  350. boolean
  351. drag_ball(x, y, bc_control, ballx, bally, chainx, chainy)
  352. xchar x, y;
  353. int *bc_control;
  354. xchar *ballx, *bally, *chainx, *chainy;
  355. {
  356.     struct trap *t = (struct trap *)0;
  357.  
  358.     *ballx  = uball->ox;
  359.     *bally  = uball->oy;
  360.     *chainx = uchain->ox;
  361.     *chainy = uchain->oy;
  362.     *bc_control = 0;
  363.  
  364.     if (dist2(x, y, uchain->ox, uchain->oy) <= 2) {    /* nothing moved */
  365.         move_bc(1, *bc_control, *ballx, *bally, *chainx, *chainy);
  366.         return TRUE;
  367.     }
  368.  
  369.     if (carried(uball) || dist2(x, y, uball->ox, uball->oy) < 3 ||
  370.         (uball->ox == uchain->ox && uball->oy == uchain->oy)) {
  371.         *bc_control = BC_CHAIN;
  372.         move_bc(1, *bc_control, *ballx, *bally, *chainx, *chainy);
  373.         *chainx = u.ux;
  374.         *chainy = u.uy;
  375.         return TRUE;
  376.     }
  377.  
  378.     if (near_capacity() > SLT_ENCUMBER) {
  379.         You("cannot %sdrag the heavy iron ball.",
  380.                 invent ? "carry all that and also " : "");
  381.         nomul(0);
  382.         return FALSE;
  383.     }
  384.  
  385.     if ((is_pool(uchain->ox, uchain->oy) &&
  386.             /* water not mere continuation of previous water */
  387.             (levl[uchain->ox][uchain->oy].typ == POOL ||
  388.              !is_pool(uball->ox, uball->oy) ||
  389.              levl[uball->ox][uball->oy].typ == POOL))
  390.         || ((t = t_at(uchain->ox, uchain->oy)) &&
  391.             (t->ttyp == PIT ||
  392.              t->ttyp == SPIKED_PIT ||
  393.              t->ttyp == TRAPDOOR)) ) {
  394.  
  395.         if (Levitation) {
  396.         You("feel a tug from the iron ball.");
  397.         if (t) t->tseen = 1;
  398.         } else {
  399.         struct monst *victim;
  400.  
  401.         You("are jerked back by the iron ball!");
  402.         if ((victim = m_at(uchain->ox, uchain->oy)) != 0) {
  403.             int tmp;
  404.  
  405.             tmp = -2 + Luck + find_mac(victim);
  406.  
  407.             if (victim->msleep) {
  408.             victim->msleep = 0;
  409.             tmp += 2;
  410.             }
  411.             if (!victim->mcanmove) {
  412.             tmp += 4;
  413.             if (!rn2(10)) {
  414.                 victim->mcanmove = 1;
  415.                 victim->mfrozen = 0;
  416.             }
  417.             }
  418.             if (tmp >= rnd(20))
  419.             (void) hmon(victim,uball,1); 
  420.             else 
  421.             miss(xname(uball), victim);
  422.  
  423.         }         /* now check again in case mon died */
  424.         if (!m_at(uchain->ox, uchain->oy)) {
  425.             u.ux = uchain->ox;
  426.             u.uy = uchain->oy;
  427.             newsym(u.ux0, u.uy0);
  428.         }
  429.         nomul(0);
  430.  
  431.         *bc_control = BC_BALL;
  432.         move_bc(1, *bc_control, *ballx, *bally, *chainx, *chainy);
  433.         *ballx = uchain->ox;
  434.         *bally = uchain->oy;
  435.         move_bc(0, *bc_control, *ballx, *bally, *chainx, *chainy);
  436.         spoteffects();
  437.         return FALSE;
  438.         } 
  439.     }
  440.  
  441.     *bc_control = BC_BALL|BC_CHAIN;;
  442.     nomul(-2);
  443.     nomovemsg = "";
  444.  
  445.     move_bc(1, *bc_control, *ballx, *bally, *chainx, *chainy);
  446.     *ballx  = uchain->ox;
  447.     *bally  = uchain->oy;
  448.     *chainx = u.ux;
  449.     *chainy = u.uy;
  450.     return TRUE;
  451. }
  452.  
  453. /*
  454.  *  drop_ball()
  455.  *
  456.  *  The punished hero drops or throws her iron ball.  If the hero is
  457.  *  blind, we must reset the order and glyph.  Check for side effects.
  458.  *  This routine expects the ball to be already placed.
  459.  *
  460.  *  Should not be called while swallowed.
  461.  */
  462. void
  463. drop_ball(x, y)
  464. xchar x, y;
  465. {
  466.     if (Blind) {
  467.     u.bc_order = bc_order();            /* get the order */
  468.                             /* pick up glyph */
  469.     u.bglyph = (u.bc_order) ? u.cglyph : levl[x][y].glyph;
  470.     }
  471.  
  472.     if (x != u.ux || y != u.uy) {
  473.     struct trap *t;
  474.     const char *pullmsg = "The ball pulls you out of the %s!";
  475.  
  476.     if (u.utrap && u.utraptype != TT_INFLOOR) {
  477.         switch(u.utraptype) {
  478.         case TT_PIT:
  479.         pline(pullmsg, "pit");
  480.         break;
  481.         case TT_WEB:
  482.         pline(pullmsg, "web");
  483.         pline("The web is destroyed!");
  484.         deltrap(t_at(u.ux,u.uy));
  485.         break;
  486.         case TT_LAVA:
  487.         pline(pullmsg, "lava");
  488.         break;
  489.         case TT_BEARTRAP: {
  490.         register long side = rn2(3) ? LEFT_SIDE : RIGHT_SIDE;
  491.         pline(pullmsg, "bear trap");
  492.         Your("%s %s is severely damaged.",
  493.                     (side == LEFT_SIDE) ? "left" : "right",
  494.                     body_part(LEG));
  495.         set_wounded_legs(side, rn1(1000, 500));
  496.         losehp(2, "leg damage from being pulled out of a bear trap",
  497.                     KILLED_BY);
  498.         break;
  499.           }
  500.         }
  501.         u.utrap = 0;
  502.         fill_pit(u.ux, u.uy);
  503.     }
  504.  
  505.     u.ux0 = u.ux;
  506.     u.uy0 = u.uy;
  507.     if (!Levitation && !MON_AT(x, y) && !u.utrap &&
  508.                 (is_pool(x, y) ||
  509.                  ((t = t_at(x, y)) &&
  510.                   (t->ttyp == PIT || t->ttyp == SPIKED_PIT ||
  511.                    t->ttyp == TRAPDOOR)))) {
  512.         u.ux = x;
  513.         u.uy = y;
  514.     } else {
  515.         u.ux = x - u.dx;
  516.         u.uy = y - u.dy;
  517.     }
  518.     vision_full_recalc = 1;    /* hero has moved, recalculate vision later */
  519.  
  520.     if (Blind) {
  521.         /* drop glyph under the chain */
  522.         if (u.bc_felt & BC_CHAIN)
  523.         levl[uchain->ox][uchain->oy].glyph = u.cglyph;
  524.         u.bc_felt  = 0;        /* feel nothing */
  525.         /* pick up new glyph */
  526.         u.cglyph = (u.bc_order) ? u.bglyph : levl[u.ux][u.uy].glyph;
  527.     }
  528.     movobj(uchain,u.ux,u.uy);    /* has a newsym */
  529.     if (Blind) {
  530.         u.bc_order = bc_order();
  531.     }
  532.     newsym(u.ux0,u.uy0);        /* clean up old position */
  533.     spoteffects();
  534.     }
  535. }
  536.  
  537.  
  538. static void
  539. litter()
  540. {
  541.     struct obj *otmp = invent, *nextobj;
  542.     int capacity = weight_cap();
  543.  
  544.     while (otmp) {
  545.         nextobj = otmp->nobj;
  546.         if ((otmp != uball) && (rnd(capacity) <= otmp->owt)) {
  547.             if (otmp == uwep)
  548.                 setuwep((struct obj *)0);
  549.             if ((otmp != uwep) && (canletgo(otmp, ""))) {
  550.                 Your("%s you down the stairs.",
  551.                      aobjnam(otmp, "follow"));
  552.                 dropx(otmp);
  553.             }
  554.         }
  555.         otmp = nextobj;
  556.     }
  557. }
  558.  
  559. void
  560. drag_down()
  561. {
  562.     boolean forward;
  563.     uchar dragchance = 3;
  564.  
  565.     /* 
  566.      *    Assume that the ball falls forward if:
  567.      *
  568.      *    a) the character is wielding it, or
  569.      *    b) the character has both hands available to hold it (i.e. is 
  570.      *       not wielding any weapon), or 
  571.      *    c) (perhaps) it falls forward out of his non-weapon hand
  572.      */
  573.  
  574.     forward = carried(uball) && (uwep == uball || !uwep || !rn2(3));
  575.  
  576.     if (carried(uball)) 
  577.         You("lose your grip on the iron ball.");
  578.  
  579.     if (forward) {
  580.         if(rn2(6)) {
  581.             pline("The iron ball drags you downstairs!");
  582.             losehp(rnd(6), "dragged downstairs by an iron ball",
  583.                 NO_KILLER_PREFIX);
  584.             litter();
  585.         }
  586.     } else {
  587.         if(rn2(2)) {
  588.             pline("The iron ball smacks into you!");
  589.             losehp(rnd(20), "iron ball collision", KILLED_BY_AN);
  590.             exercise(A_STR, FALSE);
  591.             dragchance -= 2;
  592.         } 
  593.         if( (int) dragchance >= rnd(6)) {
  594.             pline("The iron ball drags you downstairs!");
  595.             losehp(rnd(3), "dragged downstairs by an iron ball",
  596.                 NO_KILLER_PREFIX);
  597.             exercise(A_STR, FALSE);
  598.             litter();
  599.         }
  600.     }
  601. }
  602.  
  603. /*ball.c*/
  604.