(linenum→info "unix/slp.c:2238")

bsd-games/2.17/phantasia/fight.c

    1: /*      $NetBSD: fight.c,v 1.10 2004/04/11 13:35:06 he Exp $ */
    2: 
    3: /*
    4:  * fight.c   Phantasia monster fighting routines
    5:  */
    6: 
    7: #include "include.h"
    8: #undef bool
    9: #include <curses.h>
   10: 
   11: void
   12: encounter(particular)
   13:         int     particular;
   14: {
   15:         volatile bool    firsthit = Player.p_blessing; /* set if player gets
   16:                                                          * the first hit */
   17:         volatile int     flockcnt = 1; /* how many time flocked */
   18: 
   19:         /* let others know what we are doing */
   20:         Player.p_status = S_MONSTER;
   21:         writerecord(&Player, Fileloc);
   22: 
   23: #ifdef SYS5
   24:         flushinp();
   25: #endif
   26: 
   27:         Shield = 0.0;          /* no shield up yet */
   28: 
   29:         if (particular >= 0)
   30:                 /* monster is specified */
   31:                 Whichmonster = particular;
   32:         else
   33:                 /* pick random monster */
   34:                 Whichmonster = pickmonster();
   35: 
   36:         setjmp(Fightenv);      /* this is to enable changing fight state */
   37: 
   38:         move(6, 0);
   39:         clrtobot();            /* clear bottom area of screen */
   40: 
   41:         Lines = 9;
   42:         callmonster(Whichmonster);     /* set up monster to fight */
   43: 
   44:         Luckout = FALSE;       /* haven't tried to luckout yet */
   45: 
   46:         if (Curmonster.m_type == SM_MORGOTH)
   47:                 mvprintw(4, 0, "You've encountered %s, Bane of the Council and Valar.\n",
   48:                     Enemyname);
   49: 
   50:         if (Curmonster.m_type == SM_UNICORN) {
   51:                 if (Player.p_virgin) {
   52:                         printw("You just subdued %s, thanks to the virgin.\n", Enemyname);
   53:                         Player.p_virgin = FALSE;
   54:                 } else {
   55:                         printw("You just saw %s running away!\n", Enemyname);
   56:                         Curmonster.m_experience = 0.0;
   57:                         Curmonster.m_treasuretype = 0;
   58:                 }
   59:         } else
   60:                 /* not a special monster */
   61:                 for (;;)
   62:                         /* print header, and arbitrate between player and
   63:                          * monster */
   64:                 {
   65:                         mvprintw(6, 0, "You are being attacked by %s,   EXP: %.0f   (Size: %.0f)\n",
   66:                             Enemyname, Curmonster.m_experience, Circle);
   67: 
   68:                         displaystats();
   69:                         mvprintw(1, 26, "%20.0f", Player.p_energy + Shield); /* overprint energy */
   70:                         readmessage();
   71: 
   72:                         if (Curmonster.m_type == SM_DARKLORD
   73:                             && Player.p_blessing
   74:                             && Player.p_charms > 0)
   75:                                 /* overpower Dark Lord with blessing and charm */
   76:                         {
   77:                                 mvprintw(7, 0, "You just overpowered %s!", Enemyname);
   78:                                 Lines = 8;
   79:                                 Player.p_blessing = FALSE;
   80:                                 --Player.p_charms;
   81:                                 break;
   82:                         }
   83:                         /* allow paralyzed monster to wake up */
   84:                         Curmonster.m_speed = MIN(Curmonster.m_speed + 1.0, Curmonster.m_maxspeed);
   85: 
   86:                         if (drandom() * Curmonster.m_speed > drandom() * Player.p_speed
   87:                         /* monster is faster */
   88:                             && Curmonster.m_type != SM_DARKLORD
   89:                         /* not D. L. */
   90:                             && Curmonster.m_type != SM_SHRIEKER
   91:                         /* not mimic */
   92:                             && !firsthit)
   93:                                 /* monster gets a hit */
   94:                                 monsthits();
   95:                         else
   96:                                 /* player gets a hit */
   97:                         {
   98:                                 firsthit = FALSE;
   99:                                 playerhits();
  100:                         }
  101: 
  102:                         refresh();
  103: 
  104:                         if (Lines > LINES - 2)
  105:                                 /* near bottom of screen - pause */
  106:                         {
  107:                                 more(Lines);
  108:                                 move(Lines = 8, 0);
  109:                                 clrtobot();
  110:                         }
  111:                         if (Player.p_energy <= 0.0)
  112:                                 /* player died */
  113:                         {
  114:                                 more(Lines);
  115:                                 death(Enemyname);
  116:                                 cancelmonster();
  117:                                 break;      /* fight ends if the player is saved
  118:                                          * from death */
  119:                         }
  120:                         if (Curmonster.m_energy <= 0.0)
  121:                                 /* monster died */
  122:                                 break;
  123:                 }
  124: 
  125:         /* give player credit for killing monster */
  126:         Player.p_experience += Curmonster.m_experience;
  127: 
  128:         if (drandom() < Curmonster.m_flock / 100.0)
  129:                 /* monster flocks */
  130:         {
  131:                 more(Lines);
  132:                 ++flockcnt;
  133:                 longjmp(Fightenv, 0);
  134:                 /* NOTREACHED */
  135:         } else
  136:                 if (Circle > 1.0
  137:                     && Curmonster.m_treasuretype > 0
  138:                     && drandom() > 0.2 + pow(0.4, (double) (flockcnt / 3 + Circle / 3.0)))
  139:                         /* monster has treasure; this takes # of flocks and
  140:                          * size into account */
  141:                 {
  142:                         more(Lines);
  143:                         awardtreasure();
  144:                 }
  145:         /* pause before returning */
  146:         getyx(stdscr, Lines, flockcnt);
  147:         more(Lines + 1);
  148: 
  149:         Player.p_ring.ring_inuse = FALSE;      /* not using ring */
  150: 
  151:         /* clean up the screen */
  152:         move(4, 0);
  153:         clrtobot();
  154: }
  155: 
  156: int
  157: pickmonster()
  158: {
  159:         if (Player.p_specialtype == SC_VALAR)
  160:                 /* even chance of any monster */
  161:                 return ((int) ROLL(0.0, 100.0));
  162: 
  163:         if (Marsh)
  164:                 /* water monsters */
  165:                 return ((int) ROLL(0.0, 15.0));
  166: 
  167:         else
  168:                 if (Circle > 24)
  169:                         /* even chance of all non-water monsters */
  170:                         return ((int) ROLL(14.0, 86.0));
  171: 
  172:                 else
  173:                         if (Circle > 15)
  174:                                 /* chance of all non-water monsters, weighted
  175:                                  * toward middle */
  176:                                 return ((int) (ROLL(0.0, 50.0) + ROLL(14.0, 37.0)));
  177: 
  178:                         else
  179:                                 if (Circle > 8)
  180:                                         /* not all non-water monsters,
  181:                                          * weighted toward middle */
  182:                                         return ((int) (ROLL(0.0, 50.0) + ROLL(14.0, 26.0)));
  183: 
  184:                                 else
  185:                                         if (Circle > 3)
  186:                                                 /* even chance of some tamer
  187:                                                  * non-water monsters */
  188:                                                 return ((int) ROLL(14.0, 50.0));
  189: 
  190:                                         else
  191:                                                 /* even chance of some of the
  192:                                                  * tamest non-water monsters */
  193:                                                 return ((int) ROLL(14.0, 25.0));
  194: }
  195: 
  196: void
  197: playerhits()
  198: {
  199:         double  inflict;       /* damage inflicted */
  200:         int     ch;            /* input */
  201: 
  202:         mvaddstr(7, 0, "1:Melee  2:Skirmish  3:Evade  4:Spell  5:Nick  ");
  203: 
  204:         if (!Luckout) {
  205:                 /* haven't tried to luckout yet */
  206:                 if (Curmonster.m_type == SM_MORGOTH)
  207:                         /* cannot luckout against Morgoth */
  208:                         addstr("6:Ally  ");
  209:                 else
  210:                         addstr("6:Luckout  ");
  211:         }
  212: 
  213:         if (Player.p_ring.ring_type != R_NONE)
  214:                 /* player has a ring */
  215:                 addstr("7:Use Ring  ");
  216:         else
  217:                 clrtoeol();
  218: 
  219:         ch = inputoption();
  220: 
  221:         move(8, 0);
  222:         clrtobot();            /* clear any messages from before */
  223:         Lines = 9;
  224:         mvaddstr(4, 0, "\n\n");        /* clear status area */
  225: 
  226:         switch (ch) {
  227:         case 'T':              /* timeout; lose turn */
  228:                 break;
  229: 
  230:         case ' ':
  231:         case '1':              /* melee */
  232:                 /* melee affects monster's energy and strength */
  233:                 inflict = ROLL(Player.p_might / 2.0 + 5.0, 1.3 * Player.p_might)
  234:                     + (Player.p_ring.ring_inuse ? Player.p_might : 0.0);
  235: 
  236:                 Curmonster.m_melee += inflict;
  237:                 Curmonster.m_strength = Curmonster.m_o_strength
  238:                     - Curmonster.m_melee / Curmonster.m_o_energy
  239:                     * Curmonster.m_o_strength / 4.0;
  240:                 hitmonster(inflict);
  241:                 break;
  242: 
  243:         case '2':              /* skirmish */
  244:                 /* skirmish affects monter's energy and speed */
  245:                 inflict = ROLL(Player.p_might / 3.0 + 3.0, 1.1 * Player.p_might)
  246:                     + (Player.p_ring.ring_inuse ? Player.p_might : 0.0);
  247: 
  248:                 Curmonster.m_skirmish += inflict;
  249:                 Curmonster.m_maxspeed = Curmonster.m_o_speed
  250:                     - Curmonster.m_skirmish / Curmonster.m_o_energy
  251:                     * Curmonster.m_o_speed / 4.0;
  252:                 hitmonster(inflict);
  253:                 break;
  254: 
  255:         case '3':              /* evade */
  256:                 /* use brains and speed to try to evade */
  257:                 if ((Curmonster.m_type == SM_DARKLORD
  258:                         || Curmonster.m_type == SM_SHRIEKER
  259:                 /* can always run from D. L. and shrieker */
  260:                         || drandom() * Player.p_speed * Player.p_brains
  261:                         > drandom() * Curmonster.m_speed * Curmonster.m_brains)
  262:                     && (Curmonster.m_type != SM_MIMIC))
  263:                         /* cannot run from mimic */
  264:                 {
  265:                         mvaddstr(Lines++, 0, "You got away!");
  266:                         cancelmonster();
  267:                         altercoordinates(0.0, 0.0, A_NEAR);
  268:                 } else
  269:                         mvprintw(Lines++, 0, "%s is still after you!", Enemyname);
  270: 
  271:                 break;
  272: 
  273:         case 'M':
  274:         case '4':              /* magic spell */
  275:                 throwspell();
  276:                 break;
  277: 
  278:         case '5':              /* nick */
  279:                 /* hit 1 plus sword; give some experience */
  280:                 inflict = 1.0 + Player.p_sword;
  281:                 Player.p_experience += floor(Curmonster.m_experience / 10.0);
  282:                 Curmonster.m_experience *= 0.92;
  283:                 /* monster gets meaner */
  284:                 Curmonster.m_maxspeed += 2.0;
  285:                 Curmonster.m_speed = (Curmonster.m_speed < 0.0) ? 0.0 : Curmonster.m_speed + 2.0;
  286:                 if (Curmonster.m_type == SM_DARKLORD)
  287:                         /* Dark Lord; doesn't like to be nicked */
  288:                 {
  289:                         mvprintw(Lines++, 0,
  290:                             "You hit %s %.0f times, and made him mad!", Enemyname, inflict);
  291:                         Player.p_quickness /= 2.0;
  292:                         altercoordinates(0.0, 0.0, A_FAR);
  293:                         cancelmonster();
  294:                 } else
  295:                         hitmonster(inflict);
  296:                 break;
  297: 
  298:         case 'B':
  299:         case '6':              /* luckout */
  300:                 if (Luckout)
  301:                         mvaddstr(Lines++, 0, "You already tried that.");
  302:                 else {
  303:                         Luckout = TRUE;
  304:                         if (Curmonster.m_type == SM_MORGOTH)
  305:                                 /* Morgoth; ally */
  306:                         {
  307:                                 if (drandom() < Player.p_sin / 100.0) {
  308:                                         mvprintw(Lines++, 0, "%s accepted!", Enemyname);
  309:                                         cancelmonster();
  310:                                 } else
  311:                                         mvaddstr(Lines++, 0, "Nope, he's not interested.");
  312:                         } else
  313:                                 /* normal monster; use brains for success */
  314:                         {
  315:                                 if ((drandom() + 0.333) * Player.p_brains
  316:                                     < (drandom() + 0.333) * Curmonster.m_brains)
  317:                                         mvprintw(Lines++, 0, "You blew it, %s.", Player.p_name);
  318:                                 else {
  319:                                         mvaddstr(Lines++, 0, "You made it!");
  320:                                         Curmonster.m_energy = 0.0;
  321:                                 }
  322:                         }
  323:                 }
  324:                 break;
  325: 
  326:         case '7':              /* use ring */
  327:                 if (Player.p_ring.ring_type != R_NONE) {
  328:                         mvaddstr(Lines++, 0, "Now using ring.");
  329:                         Player.p_ring.ring_inuse = TRUE;
  330:                         if (Player.p_ring.ring_type != R_DLREG)
  331:                                 /* age ring */
  332:                                 --Player.p_ring.ring_duration;
  333:                 }
  334:                 break;
  335:         }
  336: 
  337: }
  338: 
  339: void
  340: monsthits()
  341: {
  342:         double  inflict;       /* damage inflicted */
  343:         int     ch;            /* input */
  344: 
  345:         switch (Curmonster.m_type)
  346:                 /* may be a special monster */
  347:         {
  348:         case SM_DARKLORD:
  349:                 /* hits just enough to kill player */
  350:                 inflict = (Player.p_energy + Shield) * 1.02;
  351:                 goto SPECIALHIT;
  352: 
  353:         case SM_SHRIEKER:
  354:                 /* call a big monster */
  355:                 mvaddstr(Lines++, 0,
  356:                     "Shrieeeek!!  You scared it, and it called one of its friends.");
  357:                 more(Lines);
  358:                 Whichmonster = (int) ROLL(70.0, 30.0);
  359:                 longjmp(Fightenv, 0);
  360:                 /* NOTREACHED */
  361: 
  362:         case SM_BALROG:
  363:                 /* take experience away */
  364:                 inflict = ROLL(10.0, Curmonster.m_strength);
  365:                 inflict = MIN(Player.p_experience, inflict);
  366:                 mvprintw(Lines++, 0,
  367:                     "%s took away %.0f experience points.", Enemyname, inflict);
  368:                 Player.p_experience -= inflict;
  369:                 return;
  370: 
  371:         case SM_FAERIES:
  372:                 if (Player.p_holywater > 0)
  373:                         /* holy water kills when monster tries to hit */
  374:                 {
  375:                         mvprintw(Lines++, 0, "Your holy water killed it!");
  376:                         --Player.p_holywater;
  377:                         Curmonster.m_energy = 0.0;
  378:                         return;
  379:                 }
  380:                 break;
  381: 
  382:         case SM_NONE:
  383:                 /* normal hit */
  384:                 break;
  385: 
  386:         default:
  387:                 if (drandom() > 0.2)
  388:                         /* normal hit */
  389:                         break;
  390: 
  391:                 /* else special things */
  392:                 switch (Curmonster.m_type) {
  393:                 case SM_LEANAN:
  394:                         /* takes some of the player's strength */
  395:                         inflict = ROLL(1.0, (Circle - 1.0) / 2.0);
  396:                         inflict = MIN(Player.p_strength, inflict);
  397:                         mvprintw(Lines++, 0, "%s sapped %.0f of your strength!",
  398:                             Enemyname, inflict);
  399:                         Player.p_strength -= inflict;
  400:                         Player.p_might -= inflict;
  401:                         break;
  402: 
  403:                 case SM_SARUMAN:
  404:                         if (Player.p_palantir)
  405:                                 /* take away palantir */
  406:                         {
  407:                                 mvprintw(Lines++, 0, "Wormtongue stole your palantir!");
  408:                                 Player.p_palantir = FALSE;
  409:                         } else
  410:                                 if (drandom() > 0.5)
  411:                                         /* gems turn to gold */
  412:                                 {
  413:                                         mvprintw(Lines++, 0,
  414:                                             "%s transformed your gems into gold!", Enemyname);
  415:                                         Player.p_gold += Player.p_gems;
  416:                                         Player.p_gems = 0.0;
  417:                                 } else
  418:                                         /* scramble some stats */
  419:                                 {
  420:                                         mvprintw(Lines++, 0, "%s scrambled your stats!", Enemyname);
  421:                                         scramblestats();
  422:                                 }
  423:                         break;
  424: 
  425:                 case SM_THAUMATURG:
  426:                         /* transport player */
  427:                         mvprintw(Lines++, 0, "%s transported you!", Enemyname);
  428:                         altercoordinates(0.0, 0.0, A_FAR);
  429:                         cancelmonster();
  430:                         break;
  431: 
  432:                 case SM_VORTEX:
  433:                         /* suck up some mana */
  434:                         inflict = ROLL(0, 7.5 * Circle);
  435:                         inflict = MIN(Player.p_mana, floor(inflict));
  436:                         mvprintw(Lines++, 0,
  437:                             "%s sucked up %.0f of your mana!", Enemyname, inflict);
  438:                         Player.p_mana -= inflict;
  439:                         break;
  440: 
  441:                 case SM_NAZGUL:
  442:                         /* try to take ring if player has one */
  443:                         if (Player.p_ring.ring_type != R_NONE)
  444:                                 /* player has a ring */
  445:                         {
  446:                                 mvaddstr(Lines++, 0, "Will you relinguish your ring ? ");
  447:                                 ch = getanswer("YN", FALSE);
  448:                                 if (ch == 'Y')
  449:                                         /* take ring away */
  450:                                 {
  451:                                         Player.p_ring.ring_type = R_NONE;
  452:                                         Player.p_ring.ring_inuse = FALSE;
  453:                                         cancelmonster();
  454:                                         break;
  455:                                 }
  456:                         }
  457:                         /* otherwise, take some brains */
  458:                         mvprintw(Lines++, 0,
  459:                             "%s neutralized 1/5 of your brain!", Enemyname);
  460:                         Player.p_brains *= 0.8;
  461:                         break;
  462: 
  463:                 case SM_TIAMAT:
  464:                         /* take some gold and gems */
  465:                         mvprintw(Lines++, 0,
  466:                             "%s took half your gold and gems and flew off.", Enemyname);
  467:                         Player.p_gold /= 2.0;
  468:                         Player.p_gems /= 2.0;
  469:                         cancelmonster();
  470:                         break;
  471: 
  472:                 case SM_KOBOLD:
  473:                         /* steal a gold piece and run */
  474:                         mvprintw(Lines++, 0,
  475:                             "%s stole one gold piece and ran away.", Enemyname);
  476:                         Player.p_gold = MAX(0.0, Player.p_gold - 1.0);
  477:                         cancelmonster();
  478:                         break;
  479: 
  480:                 case SM_SHELOB:
  481:                         /* bite and (medium) poison */
  482:                         mvprintw(Lines++, 0,
  483:                             "%s has bitten and poisoned you!", Enemyname);
  484:                         Player.p_poison -= 1.0;
  485:                         break;
  486: 
  487:                 case SM_LAMPREY:
  488:                         /* bite and (small) poison */
  489:                         mvprintw(Lines++, 0, "%s bit and poisoned you!", Enemyname);
  490:                         Player.p_poison += 0.25;
  491:                         break;
  492: 
  493:                 case SM_BONNACON:
  494:                         /* fart and run */
  495:                         mvprintw(Lines++, 0, "%s farted and scampered off.", Enemyname);
  496:                         Player.p_energy /= 2.0;      /* damage from fumes */
  497:                         cancelmonster();
  498:                         break;
  499: 
  500:                 case SM_SMEAGOL:
  501:                         if (Player.p_ring.ring_type != R_NONE)
  502:                                 /* try to steal ring */
  503:                         {
  504:                                 mvprintw(Lines++, 0,
  505:                                     "%s tried to steal your ring, ", Enemyname);
  506:                                 if (drandom() > 0.1)
  507:                                         addstr("but was unsuccessful.");
  508:                                 else {
  509:                                         addstr("and ran away with it!");
  510:                                         Player.p_ring.ring_type = R_NONE;
  511:                                         cancelmonster();
  512:                                 }
  513:                         }
  514:                         break;
  515: 
  516:                 case SM_SUCCUBUS:
  517:                         /* inflict damage through shield */
  518:                         inflict = ROLL(15.0, Circle * 10.0);
  519:                         inflict = MIN(inflict, Player.p_energy);
  520:                         mvprintw(Lines++, 0, "%s sapped %.0f of your energy.",
  521:                             Enemyname, inflict);
  522:                         Player.p_energy -= inflict;
  523:                         break;
  524: 
  525:                 case SM_CERBERUS:
  526:                         /* take all metal treasures */
  527:                         mvprintw(Lines++, 0,
  528:                             "%s took all your metal treasures!", Enemyname);
  529:                         Player.p_crowns = 0;
  530:                         Player.p_sword =
  531:                             Player.p_shield =
  532:                             Player.p_gold = 0.0;
  533:                         cancelmonster();
  534:                         break;
  535: 
  536:                 case SM_UNGOLIANT:
  537:                         /* (large) poison and take a quickness */
  538:                         mvprintw(Lines++, 0,
  539:                             "%s poisoned you, and took one quik.", Enemyname);
  540:                         Player.p_poison += 5.0;
  541:                         Player.p_quickness -= 1.0;
  542:                         break;
  543: 
  544:                 case SM_JABBERWOCK:
  545:                         /* fly away, and leave either a Jubjub bird or
  546:                          * Bonnacon */
  547:                         mvprintw(Lines++, 0,
  548:                             "%s flew away, and left you to contend with one of its friends.",
  549:                             Enemyname);
  550:                         Whichmonster = 55 + ((drandom() > 0.5) ? 22 : 0);
  551:                         longjmp(Fightenv, 0);
  552:                         /* NOTREACHED */