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