|
|
1.1 root 1: /*
2: * All the fighting gets done here
3: *
4: * @(#)fight.c 3.28 (Berkeley) 6/15/81
5: */
6:
7: #include <curses.h>
8: #include <ctype.h>
9: #include "rogue.h"
10:
11: long e_levels[] = {
12: 10L,20L,40L,80L,160L,320L,640L,1280L,2560L,5120L,10240L,20480L,
13: 40920L, 81920L, 163840L, 327680L, 655360L, 1310720L, 2621440L, 0L };
14:
15: /*
16: * fight:
17: * The player attacks the monster.
18: */
19:
20: fight(mp, mn, weap, thrown)
21: register coord *mp;
22: char mn;
23: struct object *weap;
24: bool thrown;
25: {
26: register struct thing *tp;
27: register struct linked_list *item;
28: register bool did_hit = TRUE;
29:
30: /*
31: * Find the monster we want to fight
32: */
33: if ((item = find_mons(mp->y, mp->x)) == NULL)
34: debug("Fight what @ %d,%d", mp->y, mp->x);
35: tp = (struct thing *) ldata(item);
36: /*
37: * Since we are fighting, things are not quiet so no healing takes
38: * place.
39: */
40: quiet = 0;
41: runto(mp, &hero);
42: /*
43: * Let him know it was really a mimic (if it was one).
44: */
45: if (tp->t_type == 'M' && tp->t_disguise != 'M' && off(player, ISBLIND))
46: {
47: msg("Wait! That's a mimic!");
48: tp->t_disguise = 'M';
49: did_hit = thrown;
50: }
51: if (did_hit)
52: {
53: register char *mname;
54:
55: did_hit = FALSE;
56: if (on(player, ISBLIND))
57: mname = "it";
58: else
59: mname = monsters[mn-'A'].m_name;
60: if (roll_em(&pstats, &tp->t_stats, weap, thrown))
61: {
62: did_hit = TRUE;
63: if (thrown)
64: thunk(weap, mname);
65: else
66: hit(NULL, mname);
67: if (on(player, CANHUH))
68: {
69: msg("Your hands stop glowing red");
70: msg("The %s appears confused.", mname);
71: tp->t_flags |= ISHUH;
72: player.t_flags &= ~CANHUH;
73: }
74: if (tp->t_stats.s_hpt <= 0)
75: killed(item, TRUE);
76: }
77: else
78: if (thrown)
79: bounce(weap, mname);
80: else
81: miss(NULL, mname);
82: }
83: count = 0;
84: return did_hit;
85: }
86:
87: /*
88: * attack:
89: * The monster attacks the player
90: */
91:
92: attack(mp)
93: register struct thing *mp;
94: {
95: register char *mname;
96:
97: /*
98: * Since this is an attack, stop running and any healing that was
99: * going on at the time.
100: */
101: running = FALSE;
102: quiet = 0;
103: if (mp->t_type == 'M' && off(player, ISBLIND))
104: mp->t_disguise = 'M';
105: if (on(player, ISBLIND))
106: mname = "it";
107: else
108: mname = monsters[mp->t_type-'A'].m_name;
109: if (roll_em(&mp->t_stats, &pstats, NULL, FALSE))
110: {
111: if (mp->t_type != 'E')
112: hit(mname, NULL);
113: if (pstats.s_hpt <= 0)
114: death(mp->t_type); /* Bye bye life ... */
115: if (off(*mp, ISCANC))
116: switch (mp->t_type)
117: {
118: when 'R':
119: /*
120: * If a rust monster hits, you lose armor
121: */
122: if (cur_armor != NULL && cur_armor->o_ac < 9)
123: {
124: if (!terse)
125: msg("Your armor appears to be weaker now. Oh my!");
126: else
127: msg("Your armor weakens");
128: cur_armor->o_ac++;
129: }
130: when 'E':
131: /*
132: * The gaze of the floating eye hypnotizes you
133: */
134: if (on(player, ISBLIND))
135: break;
136: if (!no_command)
137: {
138: addmsg("You are transfixed");
139: if (!terse)
140: addmsg(" by the gaze of the floating eye.");
141: endmsg();
142: }
143: no_command += rnd(2)+2;
144: when 'A':
145: /*
146: * Ants have poisonous bites
147: */
148: if (!save(VS_POISON))
149: if (!ISWEARING(R_SUSTSTR))
150: {
151: chg_str(-1);
152: if (!terse)
153: msg("You feel a sting in your arm and now feel weaker");
154: else
155: msg("A sting has weakened you");
156: }
157: else
158: if (!terse)
159: msg("A sting momentarily weakens you");
160: else
161: msg("Sting has no effect");
162: when 'W':
163: /*
164: * Wraiths might drain energy levels
165: */
166: if (rnd(100) < 15)
167: {
168: int fewer;
169:
170: if (pstats.s_exp == 0)
171: death('W'); /* All levels gone */
172: msg("You suddenly feel weaker.");
173: if (--pstats.s_lvl == 0)
174: {
175: pstats.s_exp = 0;
176: pstats.s_lvl = 1;
177: }
178: else
179: pstats.s_exp = e_levels[pstats.s_lvl-1]+1;
180: fewer = roll(1, 10);
181: pstats.s_hpt -= fewer;
182: max_hp -= fewer;
183: if (pstats.s_hpt < 1)
184: pstats.s_hpt = 1;
185: if (max_hp < 1)
186: death('W');
187: }
188: when 'F':
189: /*
190: * Violet fungi stops the poor guy from moving
191: */
192: player.t_flags |= ISHELD;
193: sprintf(monsters['F'-'A'].m_stats.s_dmg,"%dd1",++fung_hit);
194: when 'L':
195: {
196: /*
197: * Leperachaun steals some gold
198: */
199: register long lastpurse;
200:
201: lastpurse = purse;
202: purse -= GOLDCALC;
203: if (!save(VS_MAGIC))
204: purse -= GOLDCALC + GOLDCALC + GOLDCALC + GOLDCALC;
205: if (purse < 0)
206: purse = 0;
207: if (purse != lastpurse)
208: msg("Your purse feels lighter");
209: remove(&mp->t_pos, find_mons(mp->t_pos.y, mp->t_pos.x));
210: }
211: when 'N':
212: {
213: register struct linked_list *list, *steal;
214: register struct object *obj;
215: register int nobj;
216:
217: /*
218: * Nymph's steal a magic item, look through the pack
219: * and pick out one we like.
220: */
221: steal = NULL;
222: for (nobj = 0, list = pack; list != NULL; list = next(list))
223: {
224: obj = (struct object *) ldata(list);
225: if (obj != cur_armor && obj != cur_weapon &&
226: obj != cur_ring[0] && obj != cur_ring[1] &&
227: is_magic(obj) && rnd(++nobj) == 0)
228: steal = list;
229: }
230: if (steal != NULL)
231: {
232: register struct object *obj;
233:
234: obj = (struct object *) ldata(steal);
235: remove(&mp->t_pos, find_mons(mp->t_pos.y, mp->t_pos.x));
236: if (obj->o_count > 1 && obj->o_group == 0)
237: {
238: register int oc;
239:
240: oc = obj->o_count--;
241: obj->o_count = 1;
242: msg("She stole %s!", inv_name(obj, TRUE));
243: obj->o_count = oc;
244: }
245: else
246: {
247: msg("She stole %s!", inv_name(obj, TRUE));
248: detach(pack, steal);
249: discard(steal);
250: }
251: inpack--;
252: }
253: }
254: otherwise:
255: break;
256: }
257: }
258: else if (mp->t_type != 'E')
259: {
260: if (mp->t_type == 'F')
261: {
262: pstats.s_hpt -= fung_hit;
263: if (pstats.s_hpt <= 0)
264: death(mp->t_type); /* Bye bye life ... */
265: }
266: miss(mname, NULL);
267: }
268: /*
269: * Check to see if this is a regenerating monster and let it heal if
270: * it is.
271: */
272: if (on(*mp, ISREGEN) && rnd(100) < 33)
273: mp->t_stats.s_hpt++;
274: if (fight_flush)
275: {
276: #if USG==1
277: ioctl(_tty_ch, TCFLSH, 0);
278: #else
279: raw(); /* flush typeahead */
280: noraw();
281: #endif
282: }
283: count = 0;
284: status();
285: }
286:
287: /*
288: * swing:
289: * returns true if the swing hits
290: */
291:
292: swing(at_lvl, op_arm, wplus)
293: int at_lvl, op_arm, wplus;
294: {
295: register int res = rnd(20)+1;
296: register int need = (21-at_lvl)-op_arm;
297:
298: return (res+wplus >= need);
299: }
300:
301: /*
302: * check_level:
303: * Check to see if the guy has gone up a level.
304: */
305:
306: check_level()
307: {
308: register int i, add;
309:
310: for (i = 0; e_levels[i] != 0; i++)
311: if (e_levels[i] > pstats.s_exp)
312: break;
313: i++;
314: if (i > pstats.s_lvl)
315: {
316: add = roll(i-pstats.s_lvl,10);
317: max_hp += add;
318: if ((pstats.s_hpt += add) > max_hp)
319: pstats.s_hpt = max_hp;
320: msg("Welcome to level %d", i);
321: }
322: pstats.s_lvl = i;
323: }
324:
325: /*
326: * roll_em:
327: * Roll several attacks
328: */
329:
330: roll_em(att, def, weap, hurl)
331: struct stats *att, *def;
332: struct object *weap;
333: bool hurl;
334: {
335: register char *cp;
336: register int ndice, nsides, def_arm;
337: register bool did_hit = FALSE;
338: register int prop_hplus, prop_dplus;
339: #define index strchr
340: char *index();
341:
342: prop_hplus = prop_dplus = 0;
343: if (weap == NULL)
344: cp = att->s_dmg;
345: else if (hurl)
346: if ((weap->o_flags&ISMISL) && cur_weapon != NULL &&
347: cur_weapon->o_which == weap->o_launch)
348: {
349: cp = weap->o_hurldmg;
350: prop_hplus = cur_weapon->o_hplus;
351: prop_dplus = cur_weapon->o_dplus;
352: }
353: else
354: cp = (weap->o_flags&ISMISL ? weap->o_damage : weap->o_hurldmg);
355: else
356: {
357: cp = weap->o_damage;
358: /*
359: * Drain a staff of striking
360: */
361: if (weap->o_type == STICK && weap->o_which == WS_HIT
362: && weap->o_charges == 0)
363: {
364: weap->o_damage = "0d0";
365: weap->o_hplus = weap->o_dplus = 0;
366: }
367: }
368: for (;;)
369: {
370: int damage;
371: int hplus = prop_hplus + (weap == NULL ? 0 : weap->o_hplus);
372: int dplus = prop_dplus + (weap == NULL ? 0 : weap->o_dplus);
373:
374: if (weap == cur_weapon)
375: {
376: if (ISRING(LEFT, R_ADDDAM))
377: dplus += cur_ring[LEFT]->o_ac;
378: else if (ISRING(LEFT, R_ADDHIT))
379: hplus += cur_ring[LEFT]->o_ac;
380: if (ISRING(RIGHT, R_ADDDAM))
381: dplus += cur_ring[RIGHT]->o_ac;
382: else if (ISRING(RIGHT, R_ADDHIT))
383: hplus += cur_ring[RIGHT]->o_ac;
384: }
385: ndice = atoi(cp);
386: if ((cp = index(cp, 'd')) == NULL)
387: break;
388: nsides = atoi(++cp);
389: if (def == &pstats)
390: {
391: if (cur_armor != NULL)
392: def_arm = cur_armor->o_ac;
393: else
394: def_arm = def->s_arm;
395: if (ISRING(LEFT, R_PROTECT))
396: def_arm -= cur_ring[LEFT]->o_ac;
397: else if (ISRING(RIGHT, R_PROTECT))
398: def_arm -= cur_ring[RIGHT]->o_ac;
399: }
400: else
401: def_arm = def->s_arm;
402: if (swing(att->s_lvl, def_arm, hplus+str_plus(&att->s_str)))
403: {
404: register int proll;
405:
406: proll = roll(ndice, nsides);
407: if (ndice + nsides > 0 && proll < 1)
408: debug("Damage for %dd%d came out %d.", ndice, nsides, proll);
409: damage = dplus + proll + add_dam(&att->s_str);
410: def->s_hpt -= max(0, damage);
411: did_hit = TRUE;
412: }
413: if ((cp = index(cp, '/')) == NULL)
414: break;
415: cp++;
416: }
417: return did_hit;
418: }
419: #undef index
420:
421: /*
422: * prname:
423: * The print name of a combatant
424: */
425:
426: char *
427: prname(who, upper)
428: register char *who;
429: bool upper;
430: {
431: static char tbuf[80];
432:
433: *tbuf = '\0';
434: if (who == 0)
435: strcpy(tbuf, "you");
436: else if (on(player, ISBLIND))
437: strcpy(tbuf, "it");
438: else
439: {
440: strcpy(tbuf, "the ");
441: strcat(tbuf, who);
442: }
443: if (upper)
444: *tbuf = toupper(*tbuf);
445: return tbuf;
446: }
447:
448: /*
449: * hit:
450: * Print a message to indicate a succesful hit
451: */
452:
453: hit(er, ee)
454: register char *er, *ee;
455: {
456: register char *s;
457:
458: addmsg(prname(er, TRUE));
459: if (terse)
460: s = " hit.";
461: else
462: switch (rnd(4))
463: {
464: when 0: s = " scored an excellent hit on ";
465: when 1: s = " hit ";
466: when 2: s = (er == 0 ? " have injured " : " has injured ");
467: when 3: s = (er == 0 ? " swing and hit " : " swings and hits ");
468: }
469: addmsg(s);
470: if (!terse)
471: addmsg(prname(ee, FALSE));
472: endmsg();
473: }
474:
475: /*
476: * miss:
477: * Print a message to indicate a poor swing
478: */
479:
480: miss(er, ee)
481: register char *er, *ee;
482: {
483: register char *s;
484:
485: addmsg(prname(er, TRUE));
486: switch (terse ? 0 : rnd(4))
487: {
488: when 0: s = (er == 0 ? " miss" : " misses");
489: when 1: s = (er == 0 ? " swing and miss" : " swings and misses");
490: when 2: s = (er == 0 ? " barely miss" : " barely misses");
491: when 3: s = (er == 0 ? " don't hit" : " doesn't hit");
492: }
493: addmsg(s);
494: if (!terse)
495: addmsg(" %s", prname(ee, FALSE));
496: endmsg();
497: }
498:
499: /*
500: * save_throw:
501: * See if a creature save against something
502: */
503: save_throw(which, tp)
504: int which;
505: struct thing *tp;
506: {
507: register int need;
508:
509: need = 14 + which - tp->t_stats.s_lvl / 2;
510: return (roll(1, 20) >= need);
511: }
512: /*
513: * save:
514: * See if he saves against various nasty things
515: */
516:
517: save(which)
518: int which;
519: {
520: return save_throw(which, &player);
521: }
522:
523: /*
524: * str_plus:
525: * compute bonus/penalties for strength on the "to hit" roll
526: */
527:
528: str_plus(str)
529: register str_t *str;
530: {
531: if (str->st_str == 18)
532: {
533: if (str->st_add == 100)
534: return 3;
535: if (str->st_add > 50)
536: return 2;
537: }
538: if (str->st_str >= 17)
539: return 1;
540: if (str->st_str > 6)
541: return 0;
542: return str->st_str - 7;
543: }
544:
545: /*
546: * add_dam:
547: * compute additional damage done for exceptionally high or low strength
548: */
549:
550: add_dam(str)
551: register str_t *str;
552: {
553: if (str->st_str == 18)
554: {
555: if (str->st_add == 100)
556: return 6;
557: if (str->st_add > 90)
558: return 5;
559: if (str->st_add > 75)
560: return 4;
561: if (str->st_add != 0)
562: return 3;
563: return 2;
564: }
565: if (str->st_str > 15)
566: return 1;
567: if (str->st_str > 6)
568: return 0;
569: return str->st_str - 7;
570: }
571:
572: /*
573: * raise_level:
574: * The guy just magically went up a level.
575: */
576:
577: raise_level()
578: {
579: pstats.s_exp = e_levels[pstats.s_lvl-1] + 1L;
580: check_level();
581: }
582:
583: /*
584: * thunk:
585: * A missile hits a monster
586: */
587:
588: thunk(weap, mname)
589: register struct object *weap;
590: register char *mname;
591: {
592: if (weap->o_type == WEAPON)
593: msg("The %s hits the %s", w_names[weap->o_which], mname);
594: else
595: msg("You hit the %s.", mname);
596: }
597:
598: /*
599: * bounce:
600: * A missile misses a monster
601: */
602:
603: bounce(weap, mname)
604: register struct object *weap;
605: register char *mname;
606: {
607: if (weap->o_type == WEAPON)
608: msg("The %s misses the %s", w_names[weap->o_which], mname);
609: else
610: msg("You missed the %s.", mname);
611: }
612:
613: /*
614: * remove a monster from the screen
615: */
616: remove(mp, item)
617: register coord *mp;
618: register struct linked_list *item;
619: {
620: mvwaddch(mw, mp->y, mp->x, ' ');
621: mvwaddch(cw, mp->y, mp->x, ((struct thing *) ldata(item))->t_oldch);
622: detach(mlist, item);
623: discard(item);
624: }
625:
626: /*
627: * is_magic:
628: * Returns true if an object radiates magic
629: */
630:
631: is_magic(obj)
632: register struct object *obj;
633: {
634: switch (obj->o_type)
635: {
636: case ARMOR:
637: return obj->o_ac != a_class[obj->o_which];
638: when WEAPON:
639: return obj->o_hplus != 0 || obj->o_dplus != 0;
640: when POTION:
641: case SCROLL:
642: case STICK:
643: case RING:
644: case AMULET:
645: return TRUE;
646: }
647: return FALSE;
648: }
649:
650: /*
651: * killed:
652: * Called to put a monster to death
653: */
654:
655: killed(item, pr)
656: register struct linked_list *item;
657: bool pr;
658: {
659: register struct thing *tp;
660: register struct linked_list *pitem, *nexti;
661:
662: tp = (struct thing *) ldata(item);
663: if (pr)
664: {
665: addmsg(terse ? "Defeated " : "You have defeated ");
666: if (on(player, ISBLIND))
667: msg("it.");
668: else
669: {
670: if (!terse)
671: addmsg("the ");
672: msg("%s.", monsters[tp->t_type-'A'].m_name);
673: }
674: }
675: pstats.s_exp += tp->t_stats.s_exp;
676: /*
677: * Do adjustments if he went up a level
678: */
679: check_level();
680: /*
681: * If the monster was a violet fungi, un-hold him
682: */
683: switch (tp->t_type)
684: {
685: when 'F':
686: player.t_flags &= ~ISHELD;
687: fung_hit = 0;
688: strcpy(monsters['F'-'A'].m_stats.s_dmg, "000d0");
689: when 'L':
690: {
691: register struct room *rp;
692:
693: if ((rp = roomin(&tp->t_pos)) == NULL)
694: break;
695: if (rp->r_goldval != 0 || fallpos(&tp->t_pos,&rp->r_gold,FALSE))
696: {
697: rp->r_goldval += GOLDCALC;
698: if (save(VS_MAGIC))
699: rp->r_goldval += GOLDCALC + GOLDCALC
700: + GOLDCALC + GOLDCALC;
701: mvwaddch(stdscr, rp->r_gold.y, rp->r_gold.x, GOLD);
702: if (!(rp->r_flags & ISDARK))
703: {
704: light(&hero);
705: mvwaddch(cw, hero.y, hero.x, PLAYER);
706: }
707: }
708: }
709: }
710: /*
711: * Empty the monsters pack
712: */
713: pitem = tp->t_pack;
714: /*
715: * Get rid of the monster.
716: */
717: remove(&tp->t_pos, item);
718: while (pitem != NULL)
719: {
720: register struct object *obj;
721:
722: nexti = next(tp->t_pack);
723: obj = (struct object *) ldata(pitem);
724: obj->o_pos = tp->t_pos;
725: detach(tp->t_pack, pitem);
726: fall(pitem, FALSE);
727: pitem = nexti;
728: }
729: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.