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