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