Annotation of early-roguelike/urogue/fight.c, Revision 1.1.1.1
1.1 rubenllo 1: /*
2: fight.c - All the fighting gets done here
3:
4: UltraRogue: The Ultimate Adventure in the Dungeons of Doom
5: Copyright (C) 1985, 1986, 1992, 1993, 1995 Herb Chong
6: All rights reserved.
7:
8: Based on "Advanced Rogue"
9: Copyright (C) 1984, 1985 Michael Morgan, Ken Dalka
10: All rights reserved.
11:
12: Based on "Rogue: Exploring the Dungeons of Doom"
13: Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman
14: All rights reserved.
15:
16: See the file LICENSE.TXT for full copyright and licensing information.
17: */
18:
19: #include <stdlib.h>
20: #include <string.h>
21: #include <ctype.h>
22: #include "rogue.h"
23:
24: /*
25: * This are the beginning experience levels for all players all further
26: * experience levels are computed by multiplying by 2
27: */
28:
29: static long e_levels[10] =
30: {
31: 143L, /* Fighter */
32: 182L, /* Paladin */
33: 169L, /* Ranger */
34: 127L, /* Cleric */
35: 154L, /* Druid */
36: 185L, /* Magician */
37: 169L, /* Illusionist */
38: 112L, /* Thief */
39: 126L, /* Assasin */
40: 319L /* Ninja */
41: };
42:
43: static struct matrix att_mat[11] =
44: {
45: /* Base, Max_lvl, Factor, Offset, Range */
46:
47: { 10, 17, 2, 1, 2 }, /* fi */
48: { 10, 17, 2, 1, 2 }, /* pa */
49: { 10, 17, 2, 1, 2 }, /* ra */
50: { 10, 19, 2, 1, 3 }, /* cl */
51: { 10, 19, 2, 1, 3 }, /* dr */
52: { 9, 21, 2, 1, 5 }, /* mu */
53: { 9, 21, 2, 1, 5 }, /* il */
54: { 10, 21, 2, 1, 4 }, /* th */
55: { 10, 21, 2, 1, 4 }, /* as */
56: { 10, 21, 2, 1, 4 }, /* nj */
57: { 7, 25, 1, 0, 2 } /* mn */
58: };
59:
60: void
61: do_fight(coord dir, int tothedeath)
62: {
63: int x,y;
64:
65: x = dir.x;
66: y = dir.y;
67:
68: if (!tothedeath && pstats.s_hpt < max_stats.s_hpt / 3)
69: {
70: msg("That's not wise.");
71:
72: after = fighting = FALSE;
73: return;
74: }
75:
76: if (isalpha(CCHAR(winat(hero.y + y, hero.x + x))))
77: {
78: after = fighting = TRUE;
79: do_move(y, x);
80: }
81: else
82: {
83: if (fighting == FALSE)
84: msg("Nothing there.");
85:
86: after = fighting = FALSE;
87: }
88:
89: return;
90: }
91:
92: /*
93: fight()
94: The player attacks the monster.
95: */
96:
97: int
98: fight(coord *mp, struct object *weap, int thrown)
99: {
100: struct thing *tp;
101: struct linked_list *item;
102: int did_hit = TRUE;
103: char *mname;
104:
105: /* Find the monster we want to fight */
106:
107: if ((item = find_mons(mp->y, mp->x)) == NULL)
108: {
109: debug("Fight what @ %d,%d", mp->y, mp->x);
110: return 0;
111: }
112:
113: tp = THINGPTR(item);
114:
115: mname = (on(player, ISBLIND)) ? "it" : monsters[tp->t_index].m_name;
116:
117: /* Since we are fighting, things are not quiet so no healing takes place */
118:
119: player.t_rest_hpt = player.t_rest_pow = 0;
120: tp->t_rest_hpt = tp->t_rest_pow = 0;
121:
122: /* Let him know it was really a mimic (if it was one). */
123:
124: if (off(player, ISBLIND))
125: {
126: if (on(*tp, ISDISGUISE) && (tp->t_type != tp->t_disguise))
127: {
128: msg("Wait! That's a %s!", mname);
129: turn_off(*tp, ISDISGUISE);
130: did_hit = thrown;
131: }
132:
133: if (on(*tp, CANSURPRISE))
134: {
135: turn_off(*tp, CANSURPRISE);
136: if ((player.t_ctype == C_RANGER && rnd(6) != 0) ||
137: (player.t_ctype == C_NINJA && rnd(pstats.s_lvl / 2)
138: != 0))
139: msg("You notice a %s trying to hide!", mname);
140: else
141: {
142: msg("Wait! There's a %s!", mname);
143: did_hit = thrown;
144: }
145: }
146: }
147:
148: /* Protection from Normal Missiles */
149:
150: if (thrown && on(*tp, HASMSHIELD))
151: {
152: msg("The %s slows as it approaches %s.",
153: weaps[weap->o_which].w_name, mname);
154:
155: did_hit = FALSE;
156: }
157:
158: if (did_hit)
159: {
160: did_hit = FALSE;
161:
162: if (!can_blink(tp) &&
163: (off(*tp, MAGICHIT) || (weap != NULL &&
164: (weap->o_hplus > 0 || weap->o_dplus > 0))) &&
165: (off(*tp, BMAGICHIT) || (weap != NULL &&
166: (weap->o_hplus > 2 || weap->o_dplus > 2))) &&
167: roll_em(&player, tp, weap, thrown, cur_weapon))
168: {
169: did_hit = TRUE;
170: tp->t_wasshot = TRUE;
171:
172: if (thrown)
173: {
174: if (weap != NULL && weap->o_type == WEAPON
175: && weap->o_which == GRENADE)
176: {
177: hearmsg("BOOOM!");
178: aggravate();
179: }
180:
181: thunk(weap, mname);
182: }
183: else
184: hit(mname);
185:
186: /* hitting a friendly monster is curtains */
187:
188: if (on(*tp, ISFRIENDLY))
189: {
190: turn_off(*tp, ISFRIENDLY);
191: turn_on(*tp, ISMEAN);
192: }
193:
194: /* Charmed monsters become uncharmed */
195:
196: if (on(*tp, ISCHARMED))
197: {
198: turn_off(*tp, ISCHARMED);
199: turn_on(*tp, ISMEAN);
200: }
201:
202: /*
203: * If the player hit a rust monster, he better have a
204: * + weapon
205: */
206:
207: if (on(*tp, CANRUST))
208: {
209: if (!thrown && (weap != NULL) &&
210: (weap->o_flags & ISMETAL) &&
211: !(weap->o_flags & ISPROT) &&
212: !(weap->o_flags & ISSILVER) &&
213: (weap->o_hplus < 1) && (weap->o_dplus < 1))
214: {
215: if (rnd(100) < 50)
216: weap->o_hplus--;
217: else
218: weap->o_dplus--;
219:
220: msg("Your %s weakens!", weaps[weap->o_which].w_name);
221: }
222: else if (!thrown && weap != NULL && (weap->o_flags & ISMETAL))
223: msg("The rust vanishes from your %s!",
224: weaps[weap->o_which].w_name);
225: }
226:
227: /* flammable monsters die from burning weapons */
228:
229: if (thrown && on(*tp, CANBBURN) &&
230: (weap->o_flags & CANBURN) &&
231: !save_throw(VS_WAND, tp))
232: {
233: msg("The %s vanishes in a ball of flame.",
234: monsters[tp->t_index].m_name);
235:
236: tp->t_stats.s_hpt = 0;
237: }
238:
239: /* spores explode and infest hero */
240:
241: if (on(*tp, CANSPORE))
242: {
243: msg("The %s explodes in a cloud of dust.",
244: monsters[tp->t_index].m_name);
245:
246: if (is_wearing(R_HEALTH) ||
247: player.t_ctype == C_PALADIN ||
248: (player.t_ctype == C_NINJA && pstats.s_lvl
249: > 6) ||
250: thrown && rnd(50) > 0 ||
251: rnd(20) > 0)
252: {
253: msg("The dust makes it hard to breath.");
254: }
255: else
256: {
257: msg("You have contracted a parasitic infestation!");
258:
259: infest_dam++;
260: turn_on(player, HASINFEST);
261: }
262:
263: tp->t_stats.s_hpt = 0;
264: }
265:
266: /* fireproof monsters laugh at you when burning weapon hits */
267:
268: if (thrown && on(*tp, NOFIRE) && (weap->o_flags & CANBURN))
269: msg("The %s laughs as the %s bounces.",
270: monsters[tp->t_index].m_name,
271: weaps[weap->o_which].w_name);
272:
273: /* sharp weapons have no effect on NOSHARP monsters */
274:
275: if (on(*tp, NOSHARP) && (weap != NULL) &&
276: (weap->o_flags & ISSHARP))
277: {
278: msg("The %s has no effect on the %s!",
279: weaps[weap->o_which].w_name,
280: monsters[tp->t_index].m_name);
281:
282: fighting = FALSE;
283: }
284:
285: /* metal weapons pass through NOMETAL monsters */
286:
287: if (on(*tp, NOMETAL) && (weap != NULL) &&
288: (weap->o_flags & ISMETAL))
289: {
290: msg("The %s passes through the %s!",
291: weaps[weap->o_which].w_name,
292: monsters[tp->t_index].m_name);
293:
294: fighting = FALSE;
295: }
296:
297: /*
298: * If the player hit something that shrieks, wake the
299: * dungeon
300: */
301:
302: if (on(*tp, CANSHRIEK))
303: {
304: turn_off(*tp, CANSHRIEK);
305:
306: if (on(player, CANHEAR))
307: {
308: msg("You are stunned by the %s's shriek.", mname);
309: no_command += 4 + rnd(8);
310: }
311: else if (off(player, ISDEAF))
312: msg("The %s emits a piercing shriek.", mname);
313: else
314: msg("The %s seems to be trying to make some noise.", mname);
315:
316: aggravate();
317:
318: if (rnd(wizard ? 3 : 39) == 0 && cur_armor
319: != NULL
320: && cur_armor->o_which == CRYSTAL_ARMOR)
321: {
322: struct linked_list *itm;
323: struct object *obj;
324:
325: for (itm = pack; itm != NULL; itm = next(itm))
326: {
327: obj = OBJPTR(itm);
328:
329: if (obj == cur_armor)
330: break;
331: }
332:
333: if (itm == NULL)
334: debug("Can't find crystalline armor being worn.");
335: else
336: {
337: msg("Your armor shatters from the shriek.");
338: cur_armor = NULL;
339: del_pack(itm);
340: }
341: }
342: }
343:
344: /*
345: * If the player hit something that can surprise, it
346: * can't now
347: */
348:
349: if (on(*tp, CANSURPRISE))
350: turn_off(*tp, CANSURPRISE);
351:
352: /*
353: * If the player hit something that can summon, it
354: * will try to
355: */
356:
357: summon_help(tp, NOFORCE);
358:
359: /* Can the player confuse? */
360:
361: if (on(player, CANHUH) && !thrown)
362: {
363: seemsg("Your hands stop glowing red!");
364: seemsg("The %s appears confused.", mname);
365: turn_on(*tp, ISHUH);
366: turn_off(player, CANHUH);
367: }
368:
369: /* Merchants just disappear if hit */
370:
371: /*
372: * increases prices and curses objects from now on
373: * though
374: */
375:
376: if (on(*tp, CANSELL))
377: {
378: msg("The %s disappears with his wares with a BOOM and a flash.",
379: mname);
380: killed(NULL, item, NOMESSAGE, NOPOINTS);
381: aggravate();
382: luck++;
383: }
384: else if (tp->t_stats.s_hpt <= 0)
385: killed(&player, item, MESSAGE, POINTS);
386:
387: /*
388: * If the monster is fairly intelligent and about to
389: * die, it may turn tail and run.
390: */
391:
392: else if ((tp->t_stats.s_hpt < max(10, tp->maxstats.s_hpt / 10)) &&
393: (rnd(25) < tp->t_stats.s_intel))
394: {
395: turn_on(*tp, ISFLEE);
396:
397: /* If monster was suffocating, stop it */
398:
399: if (on(*tp, DIDSUFFOCATE))
400: {
401: turn_off(*tp, DIDSUFFOCATE);
402: extinguish_fuse(FUSE_SUFFOCATE);
403: }
404:
405: /* If monster held us, stop it */
406:
407: if (on(*tp, DIDHOLD) && (--hold_count == 0))
408: turn_off(player, ISHELD);
409:
410: turn_off(*tp, DIDHOLD);
411:
412: if (on(*tp, CANTELEPORT))
413: {
414: int rm;
415:
416: /*
417: * Erase the monster from the old
418: * position
419: */
420:
421: if (isalpha(mvwinch(cw, tp->t_pos.y, tp->t_pos.x)))
422: mvwaddch(cw, tp->t_pos.y, tp->t_pos.x, tp->t_oldch);
423:
424: mvwaddch(mw, tp->t_pos.y, tp->t_pos.x, ' ');
425:
426: /* Get a new position */
427:
428: do
429: {
430: rm = rnd_room();
431: rnd_pos(&rooms[rm], &tp->t_pos);
432: }
433: while (winat(tp->t_pos.y, tp->t_pos.x) != FLOOR);
434:
435: /* Put it there */
436:
437: mvwaddch(mw, tp->t_pos.y, tp->t_pos.x, tp->t_type);
438: tp->t_oldch = CCHAR( mvwinch(cw, tp->t_pos.y, tp->t_pos.x) );
439: seemsg("The %s seems to have disappeared!", mname);
440: }
441: }
442: }
443: else if (thrown)
444: bounce(weap, mname);
445: else
446: miss(mname);
447: }
448:
449: if (curr_mons)
450: chase_it(mp,&player); /* after so that backstabbing can happen */
451:
452: count = 0;
453:
454: return(did_hit);
455: }
456:
457: /*
458: attack()
459: The monster attacks the player
460: */
461:
462: int
463: attack(struct thing *mp, struct object *weapon, int thrown)
464: {
465: char *mname;
466: int did_hit = FALSE;
467:
468: /* If the monster is in a wall, it cannot attack */
469:
470: if (on(*mp, ISINWALL))
471: return (FALSE);
472:
473: /* If two monsters start to gang up on our hero, stop fight mode */
474:
475: if (fighting)
476: {
477: if (beast == NULL)
478: beast = mp;
479: else if (beast != mp)
480: fighting = FALSE;
481: }
482:
483: /*
484: Since this is an attack, stop running and any healing that was
485: going on at the time.
486: */
487:
488: running = FALSE;
489: player.t_rest_hpt = player.t_rest_pow = 0;
490: mp->t_rest_hpt = mp->t_rest_pow = 0;
491:
492: if (on(*mp, ISDISGUISE) && off(player, ISBLIND))
493: turn_off(*mp, ISDISGUISE);
494: mname = on(player, ISBLIND) ? "the monster" :
495: monsters[mp->t_index].m_name;
496:
497: if (roll_em(mp, &player, weapon, thrown, wield_weap(weapon, mp)) &&
498: (!thrown || off(player, HASMSHIELD)))
499: {
500: did_hit = TRUE;
501:
502: m_thunk(weapon, mname);
503:
504: if (pstats.s_hpt <= 0)
505: {
506: death(mp->t_index); /* Bye bye life ... */
507: return TRUE;
508: }
509:
510: /* surprising monsters appear after they shoot at you */
511:
512: if (thrown && on(*mp, CANSURPRISE))
513: turn_off(*mp, CANSURPRISE);
514: else if (!thrown)
515: {
516:
517: /*
518: If a vampire hits, it may take half your hit
519: points
520: */
521:
522: if ( on(*mp, CANSUCK) && !save(VS_MAGIC) )
523: {
524: if (pstats.s_hpt == 1)
525: {
526: death(mp->t_index);
527: return TRUE;
528: }
529: else
530: {
531: pstats.s_hpt /= 2;
532: msg("You feel your life force being drawn from you.");
533: }
534: }
535:
536: /*
537: strong monsters can shatter or gong crystalline
538: armor
539: */
540:
541: if (cur_armor != NULL && cur_armor->o_which == CRYSTAL_ARMOR)
542: {
543: if (rnd(mp->t_stats.s_str + (cur_armor->o_ac / 2)) > 20)
544: {
545: struct linked_list *item;
546: struct object *obj;
547:
548: for (item = pack; item != NULL; item = next(item))
549: {
550: obj = OBJPTR(item);
551:
552: if (obj == cur_armor)
553: break;
554: }
555:
556: if (item == NULL)
557: debug("Can't find crystalline armor being worn.");
558: else
559: {
560: msg("Your armor is shattered by the blow.");
561: cur_armor = NULL;
562: del_pack(item);
563: }
564: }
565: else if (rnd(mp->t_stats.s_str) > 15)
566: {
567: msg("Your armor rings from the blow.");
568: aggravate();
569: }
570: }
571:
572: /* Stinking monsters reduce the player's strength */
573:
574: if (on(*mp, CANSTINK))
575: {
576: turn_off(*mp, CANSTINK);
577:
578: if (player.t_ctype != C_PALADIN
579: && !(player.t_ctype == C_NINJA && pstats.s_lvl > 12)
580: && !save(VS_POISON))
581: {
582: if (on(player, CANSCENT))
583: {
584: msg("You pass out from the stench of the %s.", mname);
585: no_command += 4 + rnd(8);
586: }
587: else if (off(player, ISUNSMELL))
588: msg("The stench of the %s sickens you.", mname);
589:
590: if (on(player, HASSTINK))
591: lengthen_fuse(FUSE_UNSTINK, STINKTIME);
592: else
593: {
594: turn_on(player, HASSTINK);
595: light_fuse(FUSE_UNSTINK, 0, STINKTIME, AFTER);
596: }
597: }
598: }
599:
600: /* chilling monster reduces strength permanently */
601:
602: if (on(*mp, CANCHILL) &&
603: (cur_armor == NULL || cur_armor->o_which != CRYSTAL_ARMOR))
604: {
605: msg("You cringe at the %s's chilling touch.", mname);
606:
607: if (!is_wearing(R_SUSABILITY))
608: {
609: chg_str(-1, FALSE, TRUE);
610:
611: if (lost_str == 0)
612: light_fuse(FUSE_RES_STRENGTH, 0, CHILLTIME, AFTER);
613: else
614: lengthen_fuse(FUSE_RES_STRENGTH, CHILLTIME);
615: }
616: }
617:
618: /* itching monsters reduce dexterity (temporarily) */
619:
620: if (on(*mp, CANITCH) && player.t_ctype != C_PALADIN
621: && !(player.t_ctype == C_NINJA && pstats.s_lvl > 12)
622: && !save(VS_POISON))
623: {
624: msg("The claws of the %s scratch you!", mname);
625:
626: if (is_wearing(R_SUSABILITY))
627: msg("The scratch has no effect.");
628: else
629: {
630: msg("You feel a burning itch.");
631: turn_on(player, HASITCH);
632: chg_dext(-1, FALSE, TRUE);
633: light_fuse(FUSE_UNITCH, 0, roll(4, 6), AFTER);
634: }
635: }
636:
637: /* a hugging monster may SQUEEEEEEEZE */
638:
639: if (on(*mp, CANHUG) &&
640: (cur_armor == NULL || cur_armor->o_which != CRYSTAL_ARMOR))
641: {
642: if (roll(1, 20) >= 18 || roll(1, 20) >= 18)
643: {
644: msg("The %s squeezes you against itself.", mname);
645:
646: if ((pstats.s_hpt -= roll(2, 8)) <= 0)
647: {
648: death(mp->t_index);
649: return TRUE;
650: }
651: }
652: }
653:
654: /* a trampling monster may step on the player */
655:
656: if (on(*mp, CANTRAMPLE))
657: {
658: if (roll(1, 20) >= 16 || roll(1, 20) >= 16)
659: {
660: msg("The %s steps on you.", mname);
661:
662: if ((pstats.s_hpt -= roll(3, mp->t_stats.s_lvl)) <= 0)
663: {
664: death(mp->t_index);
665: return TRUE;
666: }
667: }
668: }
669:
670: /* a disease-carrying monster may transmit the disease */
671:
672: if (on(*mp, CANDISEASE) &&
673: (rnd(pstats.s_const) < mp->t_stats.s_lvl) &&
674: off(player, HASDISEASE))
675: {
676:
677: if (is_wearing(R_HEALTH)
678: || (player.t_ctype == C_PALADIN)
679: || (player.t_ctype == C_NINJA &&
680: pstats.s_lvl > 6))
681: msg("The wound heals quickly.");
682: else
683: {
684: turn_on(player, HASDISEASE);
685: light_fuse(FUSE_CURE_DISEASE,0,roll(4,4) * SICKTIME, AFTER);
686: msg("You have contracted a disease!");
687: }
688: }
689:
690: /* a rust monster will weaken your armor */
691:
692: if (on(*mp, CANRUST))
693: {
694: if (cur_armor != NULL &&
695: cur_armor->o_which != SOFT_LEATHER &&
696: cur_armor->o_which != HEAVY_LEATHER &&
697: cur_armor->o_which != CUIRBOLILLI &&
698: cur_armor->o_which != PADDED_ARMOR &&
699: cur_armor->o_which != CRYSTAL_ARMOR &&
700: cur_armor->o_which != MITHRIL &&
701: !(cur_armor->o_flags & ISPROT) &&
702: cur_armor->o_ac < pstats.s_arm + 1)
703: {
704: msg("Your armor weakens!");
705: cur_armor->o_ac++;
706: }
707: else if (cur_armor != NULL &&
708: (cur_armor->o_flags & ISPROT) &&
709: cur_armor->o_which != SOFT_LEATHER &&
710: cur_armor->o_which != HEAVY_LEATHER &&
711: cur_armor->o_which != CUIRBOLILLI &&
712: cur_armor->o_which != PADDED_ARMOR &&
713: cur_armor->o_which != CRYSTAL_ARMOR &&
714: cur_armor->o_which != MITHRIL)
715: msg("The rust vanishes instantly!");
716: }
717:
718: /* If a surprising monster hit you, you can see it now */
719:
720: if (on(*mp, CANSURPRISE))
721: turn_off(*mp, CANSURPRISE);
722:
723: /* an infesting monster will give you a parasite or rot */
724:
725: if (on(*mp, CANINFEST) && rnd(pstats.s_const) < mp->t_stats.s_lvl)
726: {
727: if (is_wearing(R_HEALTH) || (player.t_ctype == C_PALADIN)
728: || (player.t_ctype == C_NINJA && pstats.s_lvl > 6))
729: msg("The wound quickly heals.");
730: else
731: {
732: turn_off(*mp, CANINFEST);
733: msg("You have contracted a parasitic infestation!");
734: infest_dam++;
735: turn_on(player, HASINFEST);
736: }
737: }
738:
739: /* Some monsters have poisonous bites */
740:
741: if (on(*mp, CANPOISON) && !save(VS_POISON))
742: {
743: if (is_wearing(R_SUSABILITY) || (player.t_ctype == C_PALADIN)
744: || (player.t_ctype == C_NINJA && pstats.s_lvl > 12))
745: msg("The sting has no effect on you!");
746: else
747: {
748: chg_str(-1, FALSE, FALSE);
749: msg("You feel a sting in your arm and now feel weaker.");
750: }
751: }
752:
753: /* a hideous monster may cause fear by touching */
754:
755: if (on(*mp, TOUCHFEAR))
756: {
757: turn_off(*mp, TOUCHFEAR);
758:
759: if (!save(VS_WAND)&&!(on(player,ISFLEE)&&(player.t_chasee==mp)))
760: {
761: if (off(player, SUPERHERO)
762: && (player.t_ctype != C_PALADIN))
763: {
764: turn_on(player, ISFLEE);
765: player.t_ischasing = FALSE;
766: player.t_chasee = mp;
767: msg("The %s's touch terrifies you.", mname);
768: }
769: else
770: msg("The %s's touch feels cold and clammy.", mname);
771: }
772: }
773:
774: /* some monsters will suffocate our hero */
775:
776: if (on(*mp, CANSUFFOCATE) && (rnd(100) < 15) &&
777: (find_slot(FUSE_SUFFOCATE, FUSE) == NULL))
778: {
779: turn_on(*mp, DIDSUFFOCATE);
780: msg("The %s is beginning to suffocate you.",
781: mname);
782: light_fuse(FUSE_SUFFOCATE, 0, roll(4, 2), AFTER);
783: }
784:
785: /* don't look now, you will get turned to stone */
786:
787: if (on(*mp, TOUCHSTONE))
788: {
789: turn_off(*mp, TOUCHSTONE);
790:
791: if (on(player, CANINWALL))
792: msg("The %s's touch has no effect.", mname);
793: else
794: {
795: if (!save(VS_PETRIFICATION) && rnd(100) < 3)
796: {
797: msg("Your body begins to solidify.");
798: msg("You are turned to stone !!! --More--");
799: wait_for(' ');
800: death(D_PETRIFY);
801: return TRUE;
802: }
803: else
804: {
805: msg("The %s's touch stiffens your limbs.", mname);
806: no_command = rnd(STONETIME) + 2;
807: }
808: }
809: }
810:
811: /* Undead might drain energy levels */
812:
813: if ((on(*mp, CANDRAIN) || on(*mp, DOUBLEDRAIN)) && rnd(100) < 15)
814: {
815: if (is_carrying(TR_AMULET))
816: msg("The Amulet protects you from the %s's negative energy!",
817: mname);
818: else
819: {
820: lower_level(mp->t_index);
821:
822: if (on(*mp, DOUBLEDRAIN))
823: lower_level(mp->t_index);
824: }
825:
826: turn_on(*mp, DIDDRAIN);
827: }
828:
829: /* permanently drain a wisdom point */
830:
831: if (on(*mp, DRAINWISDOM) && rnd(100) < 15)
832: {
833: int ring_str; /* Value of ring strengths */
834:
835: /* Undo any ring changes */
836:
837: ring_str = ring_value(R_ADDWISDOM) +
838: (on(player, POWERWISDOM) ? 10 : 0);
839:
840: pstats.s_wisdom -= ring_str;
841:
842: msg("You feel slightly less wise now.");
843:
844: pstats.s_wisdom = max(pstats.s_wisdom - 1, 3);
845: max_stats.s_wisdom = pstats.s_wisdom;
846:
847: /* Now put back the ring changes */
848:
849: pstats.s_wisdom += ring_str;
850:
851: }
852:
853: /* permanently drain a intelligence point */
854:
855: if (on(*mp, DRAINBRAIN) && rnd(100) < 15)
856: {
857: int ring_str; /* Value of ring strengths */
858:
859: /* Undo any ring changes */
860:
861: ring_str = ring_value(R_ADDINTEL) +
862: (on(player, POWERINTEL) ? 10 : 0);
863:
864: pstats.s_intel -= ring_str;
865:
866: msg("You feel slightly less intelligent now.");
867: pstats.s_intel = max(pstats.s_intel - 1, 3);
868: max_stats.s_intel = pstats.s_intel;
869:
870: /* Now put back the ring changes */
871:
872: pstats.s_intel += ring_str;
873: }
874:
875: /* Violet fungi and others hold the hero */
876:
877: if (on(*mp, CANHOLD) && off(*mp, DIDHOLD)
878: && !is_wearing(R_FREEDOM))
879: {
880: turn_on(player, ISHELD);
881: turn_on(*mp, DIDHOLD);
882: hold_count++;
883: }
884:
885: /* suckers will suck blood and run away */
886:
887: if (on(*mp, CANDRAW))
888: {
889: turn_off(*mp, CANDRAW);
890: turn_on(*mp, ISFLEE);
891: msg("The %s sates itself with your blood.", mname);
892:
893: if ((pstats.s_hpt -= 12) <= 0)
894: {
895: death(mp->t_index);
896: return TRUE;
897: }
898: }
899:
900: /* el stinkos will force a reduction in strength */
901:
902: if (on(*mp, CANSMELL))
903: {
904: turn_off(*mp, CANSMELL);
905:
906: if (save(VS_MAGIC) || is_wearing(R_SUSABILITY))
907: msg("You smell an unpleasant odor.");
908: else
909: {
910: int odor_str = -(rnd(6) + 1);
911:
912: if (on(player, CANSCENT))
913: {
914: msg("You pass out from a foul odor.");
915: no_command += 4 + rnd(8);
916: }
917: else if (off(player, ISUNSMELL))
918: msg("You are overcome by a foul odor.");
919:
920: if (lost_str == 0)
921: {
922: chg_str(odor_str, FALSE, TRUE);
923: light_fuse(FUSE_RES_STRENGTH, 0, SMELLTIME, AFTER);
924: }
925: else
926: lengthen_fuse(FUSE_RES_STRENGTH, SMELLTIME);
927: }
928: }
929:
930: /* Paralyzation */
931:
932: if (on(*mp, CANPARALYZE))
933: {
934: turn_off(*mp, CANPARALYZE);
935:
936: if (!save(VS_PARALYZATION) && no_command == 0)
937: {
938: if (on(player, CANINWALL))
939: msg("The %s's touch has no effect.", mname);
940: else
941: {
942: msg("The %s's touch paralyzes you.", mname);
943: no_command = FREEZETIME;
944: }
945: }
946: }
947:
948: /* Rotting */
949:
950: if (on(*mp, CANROT))
951: {
952: turn_off(*mp, CANROT);
953: turn_on(*mp, DOROT);
954: }
955:
956: /* some monsters steal gold */
957:
958: if (on(*mp, STEALGOLD))
959: {
960: long lastpurse;
961: struct linked_list *item;
962: struct object *obj;
963:
964: lastpurse = purse;
965: purse = (purse > GOLDCALC) ? purse - GOLDCALC : 0L;
966:
967: if (!save(VS_MAGIC))
968: purse = (purse > (4*GOLDCALC)) ? purse-(4*GOLDCALC) : 0L;
969:
970: if (purse != lastpurse)
971: {
972: msg("Your purse feels lighter.");
973:
974: /* Give the gold to the thief */
975:
976: for (item = mp->t_pack; item != NULL; item = next(item))
977: {
978: obj = OBJPTR(item);
979:
980: if (obj->o_type == GOLD)
981: {
982: obj->o_count += lastpurse - purse;
983: break;
984: }
985: }
986:
987: /* Did we do it? */
988:
989: if (item == NULL) /* Then make some */
990: {
991: item = new_item(sizeof *obj);
992: obj = OBJPTR(item);
993: obj->o_type = GOLD;
994: obj->o_count = lastpurse - purse;
995: obj->o_hplus = obj->o_dplus = 0;
996: obj->o_damage = obj->o_hurldmg = "0d0";
997: obj->o_ac = 11;
998: obj->o_group = 0;
999: obj->o_flags = 0;
1000: obj->o_mark[0] = '\0';
1001: obj->o_pos = mp->t_pos;
1002:
1003: attach(mp->t_pack, item);
1004: }
1005: }
1006:
1007: if (rnd(2))
1008: turn_on(*mp, ISFLEE);
1009:
1010: turn_on(*mp, ISINVIS);
1011: }
1012:
1013: /* other monsters steal magic */
1014:
1015: if (on(*mp, STEALMAGIC))
1016: {
1017: struct linked_list *list, *stealit;
1018: struct object *obj;
1019: int worth = 0;
1020:
1021: stealit = NULL;
1022:
1023: for (list = pack; list != NULL; list = next(list))
1024: {
1025: obj = OBJPTR(list);
1026:
1027: if (rnd(33) == 0) /* some stuff degrades */
1028: {
1029: if (obj->o_flags & ISBLESSED)
1030: obj->o_flags &= ~ISBLESSED;
1031: else
1032: obj->o_flags |= ISCURSED;
1033:
1034: msg("You feel nimble fingers reach into you pack.");
1035: }
1036:
1037: if ((obj != cur_armor &&
1038: obj != cur_weapon &&
1039: obj != cur_ring[LEFT_1] &&
1040: obj != cur_ring[LEFT_2] &&
1041: obj != cur_ring[LEFT_3] &&
1042: obj != cur_ring[LEFT_4] &&
1043: obj != cur_ring[LEFT_5] &&
1044: obj != cur_ring[RIGHT_1] &&
1045: obj != cur_ring[RIGHT_2] &&
1046: obj != cur_ring[RIGHT_3] &&
1047: obj != cur_ring[RIGHT_4] &&
1048: obj != cur_ring[RIGHT_5] &&
1049: !(obj->o_flags & ISPROT) &&
1050: is_magic(obj)
1051: || level > 45)
1052: && get_worth(obj) > worth)
1053: {
1054: stealit = list;
1055: worth = get_worth(obj);
1056: }
1057: }
1058:
1059: if (stealit != NULL)
1060: {
1061: struct object *newobj;
1062:
1063: newobj = OBJPTR(stealit);
1064:
1065: if (newobj->o_count > 1 && newobj->o_group == 0)
1066: {
1067: int oc;
1068: struct linked_list *nitem;
1069: struct object *op;
1070:
1071: oc = --(newobj->o_count);
1072: newobj->o_count = 1;
1073: nitem = new_item(sizeof *newobj);
1074: op = OBJPTR(nitem);
1075: *op = *newobj;
1076:
1077: msg("The %s stole %s!",mname,inv_name(newobj,LOWERCASE));
1078: newobj->o_count = oc;
1079: attach(mp->t_pack, nitem);
1080: }
1081: else
1082: {
1083: msg("The %s stole %s!",mname,inv_name(newobj,LOWERCASE));
1084: newobj->o_flags &= ~ISCURSED;
1085: dropcheck(newobj);
1086: rem_pack(newobj);
1087: attach(mp->t_pack, stealit);
1088:
1089: if (newobj->o_type == ARTIFACT)
1090: has_artifact &= ~(1 << newobj->o_which);
1091: }
1092:
1093: if (newobj->o_flags & ISOWNED)
1094: {
1095: turn_on(*mp, NOMOVE);
1096: msg("The %s is transfixed by your ownership spell.",
1097: mname);
1098: }
1099:
1100: if (rnd(2))
1101: turn_on(*mp, ISFLEE);
1102:
1103: turn_on(*mp, ISINVIS);
1104: updpack();
1105: }
1106: }
1107: }
1108: }
1109: else /* missed */
1110: {
1111: /* If the thing was trying to surprise, no good */
1112:
1113: if (on(*mp, CANSURPRISE))
1114: turn_off(*mp, CANSURPRISE);
1115:
1116: m_bounce(weapon, mname);
1117: }
1118:
1119: count = 0;
1120:
1121: status(FALSE);
1122:
1123: return(did_hit);
1124: }
1125:
1126:
1127: /*
1128: mon_mon_attack()
1129: A monster attacks another monster
1130: */
1131:
1132: int
1133: mon_mon_attack(struct thing *attacker, struct linked_list *mon, struct object *weapon, int thrown)
1134: {
1135: struct thing *attackee = THINGPTR(mon);
1136: int did_hit = FALSE;
1137: int ee_visible = cansee(attackee->t_pos.y, attackee->t_pos.x);
1138: int er_visible = cansee(attacker->t_pos.y, attacker->t_pos.x);
1139: char *mname1 = monsters[attacker->t_index].m_name;
1140: char *mname2 = monsters[attackee->t_index].m_name;
1141:
1142: /* Similar monsters don't hit each other */
1143:
1144: if (attacker->t_index == attackee->t_index)
1145: {
1146: if (fam_ptr && attacker == THINGPTR(fam_ptr) && er_visible)
1147: msg("Master, I cannot hit one of my brethren.");
1148: if (!thrown && rnd(100) - attacker->t_stats.s_charisma + luck < 0)
1149: {
1150: if (er_visible)
1151: msg("Your %s has made a new ally.", mname1);
1152:
1153: turn_on(*attackee, ISCHARMED);
1154: }
1155:
1156: return(FALSE);
1157: }
1158:
1159: /* stop running and any healing */
1160:
1161: attackee->t_rest_hpt = attackee->t_rest_pow = 0;
1162: attacker->t_rest_hpt = attacker->t_rest_pow = 0;
1163:
1164: if (roll_em(attacker, attackee, weapon, thrown,
1165: wield_weap(weapon, attacker)))
1166: {
1167: did_hit = TRUE;
1168:
1169: if (ee_visible && on(*attackee, CANSURPRISE))
1170: turn_off(*attackee, CANSURPRISE);
1171:
1172: if (ee_visible && er_visible && weapon != NULL)
1173: msg("The %s's %s hits the %s.", mname1,
1174: weaps[weapon->o_which].w_name, mname2);
1175: else if (ee_visible && er_visible)
1176: msg("The %s hits the %s.", mname1, mname2);
1177:
1178: if (attackee->t_stats.s_hpt <= 0)
1179: {
1180: killed(attacker, mon, MESSAGE,
1181: on(*attacker, ISFAMILIAR) ? POINTS : NOPOINTS);
1182: return(TRUE);
1183: }
1184: }
1185: else /* missed */
1186: {
1187: did_hit = FALSE;
1188:
1189: if (ee_visible && er_visible && weapon != NULL)
1190: msg("The %s's %s misses the %s.", mname1,
1191: weaps[weapon->o_which].w_name, mname2);
1192: else if (ee_visible && er_visible)
1193: msg("The %s misses the %s.", mname1, mname2);
1194: }
1195:
1196: if (er_visible && !ee_visible)
1197: msg("The %s struggles with something.",mname1);
1198:
1199: if (off(*attackee, ISMEAN) && off(*attackee, ISFAMILIAR))
1200: turn_on(*attackee, ISRUN);
1201:
1202: count = 0;
1203:
1204: status(FALSE);
1205:
1206: return(did_hit);
1207: }
1208:
1209:
1210: /*
1211: swing()
1212: returns true if the swing hits
1213: */
1214:
1215: int
1216: swing(int class, int at_lvl, int op_arm, int wplus)
1217: {
1218: int res = rnd(20) + 1;
1219: int need;
1220:
1221: need = att_mat[class].base -
1222: att_mat[class].factor *
1223: ((min(at_lvl, att_mat[class].max_lvl) -
1224: att_mat[class].offset) / att_mat[class].range) +
1225: (10 - op_arm);
1226:
1227: if (need > 20 && need <= 25)
1228: need = 20;
1229:
1230: return(res + wplus >= need);
1231: }
1232:
1233: /*
1234: init_exp()
1235: set up initial experience level change threshold
1236: */
1237:
1238: void
1239: init_exp(void)
1240: {
1241: max_stats.s_exp = e_levels[player.t_ctype];
1242: }
1243:
1244: /*
1245: next_exp_level()
1246: Do the next level arithmetic Returns number of levels to jump
1247: */
1248:
1249: int
1250: next_exp_level(int print_message)
1251: {
1252: int level_jump = 0;
1253:
1254: while (pstats.s_exp >= max_stats.s_exp)
1255: {
1256: pstats.s_exp -= max_stats.s_exp; /* excess experience points */
1257: level_jump++;
1258:
1259: if (max_stats.s_exp < 0x3fffffffL) /* 2^30 - 1 */
1260: max_stats.s_exp *= 2L; /* twice as many for next */
1261: }
1262:
1263: if (print_message)
1264: msg("You need %d more points to attain the %stitle of %s.",
1265: max_stats.s_exp - pstats.s_exp,
1266: (pstats.s_lvl > 14 ? "next " : ""),
1267: cnames[player.t_ctype][min(pstats.s_lvl, 14)]);
1268:
1269: return(level_jump);
1270: }
1271:
1272: /*
1273: check_level()
1274: Check to see if the guy has gone up a level.
1275: */
1276:
1277: void
1278: check_level(void)
1279: {
1280: int num_jumped, j, add;
1281: int nsides;
1282:
1283: if ((num_jumped = next_exp_level(NOMESSAGE)) <= 0)
1284: return;
1285:
1286: pstats.s_lvl += num_jumped; /* new experience level */
1287:
1288: switch (player.t_ctype)
1289: {
1290: case C_MAGICIAN:
1291: case C_ILLUSION: nsides = 4;
1292: break;
1293: case C_THIEF:
1294: case C_ASSASIN:
1295: case C_NINJA:
1296: case C_MONSTER:
1297: default: nsides = 6;
1298: break;
1299: case C_CLERIC:
1300: case C_DRUID: nsides = 8;
1301: break;
1302:
1303: case C_FIGHTER:
1304: case C_PALADIN:
1305: case C_RANGER:
1306: nsides = 12;
1307: break;
1308: }
1309:
1310: /* Take care of multi-level jumps */
1311:
1312: for (add = 0, j = 0; j < num_jumped; j++)
1313: {
1314: int increase = roll(1, nsides) + const_bonus();
1315:
1316: add += max(1, increase);
1317: }
1318:
1319: max_stats.s_hpt += add;
1320: pstats.s_hpt += add;
1321:
1322: msg("Welcome, %s, to level %d.",
1323: cnames[player.t_ctype][min(pstats.s_lvl - 1, 14)], pstats.s_lvl);
1324:
1325: next_exp_level(MESSAGE);
1326:
1327: /* Now add new spell points and learn new spells */
1328:
1329: nsides = 16 - nsides;
1330:
1331: for (add = 0, j = 0; j < num_jumped; j++)
1332: {
1333: int increase = roll(1, nsides) + int_wis_bonus();
1334:
1335: add += max(1, increase);
1336: }
1337:
1338: max_stats.s_power += add;
1339: pstats.s_power += add;
1340:
1341: learn_new_spells();
1342:
1343: /* Create a more powerful familiar (if player has one) */
1344:
1345: if (on(player, HASFAMILIAR) && on(player, CANSUMMON))
1346: summon_monster((short) 0, FAMILIAR, NOMESSAGE);
1347: }
1348:
1349: /*
1350: roll_em()
1351: Roll several attacks
1352: */
1353:
1354: int
1355: roll_em(struct thing *att_er, struct thing *def_er, struct object *weap, int thrown, struct object *my_weapon)
1356: {
1357: struct stats *att = &att_er->t_stats;
1358: struct stats *def = &def_er->t_stats;
1359: int ndice, nsides, nplus, def_arm;
1360: char *cp;
1361: int prop_hplus = 0, prop_dplus = 0;
1362: int is_player = (att_er == &player);
1363: int did_hit = FALSE;
1364:
1365: if (weap == NULL)
1366: cp = att->s_dmg;
1367: else if (!thrown)
1368: cp = weap->o_damage;
1369: else if ((weap->o_flags & ISMISL) && my_weapon != NULL &&
1370: my_weapon->o_which == weap->o_launch)
1371: {
1372: cp = weap->o_hurldmg;
1373: prop_hplus = my_weapon->o_hplus;
1374: prop_dplus = my_weapon->o_dplus;
1375: }
1376: else
1377: cp = (weap->o_flags & ISMISL ? weap->o_damage :
1378: weap->o_hurldmg);
1379:
1380: for (;;)
1381: {
1382: int damage;
1383: int hplus = prop_hplus + (weap == NULL ? 0 : weap->o_hplus);
1384: int dplus = prop_dplus + (weap == NULL ? 0 : weap->o_dplus);
1385:
1386: /* Is attacker weak? */
1387:
1388: if (on(*att_er, HASSTINK))
1389: hplus -= 2;
1390:
1391: if (is_player)
1392: {
1393: hplus += hitweight(); /* adjust for encumberence */
1394: dplus += hung_dam(); /* adjust damage for hungry player */
1395: dplus += ring_value(R_ADDDAM);
1396: }
1397:
1398: ndice = atoi(cp);
1399:
1400: if (cp == NULL || (cp = strchr(cp, 'd')) == NULL)
1401: break;
1402:
1403: nsides = atoi(++cp);
1404:
1405: if (cp != NULL && (cp = strchr(cp, '+')) != NULL)
1406: nplus = atoi(++cp);
1407: else
1408: nplus = 0;
1409:
1410: if (def == &pstats)
1411: {
1412: if (on(*att_er, NOMETAL) && cur_armor != NULL &&
1413: (cur_armor->o_which == RING_MAIL ||
1414: cur_armor->o_which == SCALE_MAIL ||
1415: cur_armor->o_which == CHAIN_MAIL ||
1416: cur_armor->o_which == SPLINT_MAIL ||
1417: cur_armor->o_which == BANDED_MAIL ||
1418: cur_armor->o_which == GOOD_CHAIN ||
1419: cur_armor->o_which == PLATE_MAIL ||
1420: cur_armor->o_which == PLATE_ARMOR))
1421: def_arm = def->s_arm;
1422: else if (cur_armor != NULL)
1423: def_arm = cur_armor->o_ac - 10 + pstats.s_arm;
1424: else
1425: def_arm = def->s_arm;
1426: def_arm -= ring_value(R_PROTECT);
1427: }
1428: else
1429: def_arm = def->s_arm;
1430:
1431: if ((weap != NULL && weap->o_type == WEAPON &&
1432: (weap->o_flags & ISSILVER) &&
1433: !save_throw(VS_MAGIC, def_er)) ||
1434: swing(att_er->t_ctype, att->s_lvl,
1435: def_arm - dext_prot(def->s_dext),
1436: hplus + str_plus(att->s_str) + dext_plus(att->s_dext)))
1437: {
1438: damage = roll(ndice, nsides) + dplus + nplus +
1439: add_dam(att->s_str);
1440:
1441: /* Rangers do +1/lvl vs. ISLARGE */
1442:
1443: if (att_er->t_ctype == C_RANGER && on(*def_er, ISLARGE))
1444: damage += pstats.s_lvl;
1445:
1446: /* Ninja do +1 per lvl/2 */
1447:
1448: if (att_er->t_ctype == C_NINJA)
1449: damage += pstats.s_lvl / 2;
1450:
1451: /* Check for half damage monsters */
1452:
1453: if (on(*def_er, HALFDAMAGE) && (weap != NULL) &&
1454: !((weap->o_flags & CANBURN) &&
1455: on(*def_er, CANBBURN)))
1456: damage /= 2;
1457:
1458: /* undead get twice damage from silver weapons */
1459:
1460: if (on(*def_er, ISUNDEAD) &&
1461: (weap != NULL) && (weap->o_flags & ISSILVER))
1462: damage *= 2;
1463:
1464: /* Check for fireproof monsters */
1465:
1466: if (on(*def_er, NOFIRE) && (weap != NULL) &&
1467: (weap->o_flags & CANBURN))
1468: damage = 0;
1469:
1470: /* Check for metal proof monsters */
1471:
1472: if (on(*def_er, NOMETAL) && (weap != NULL) &&
1473: (weap->o_flags & ISMETAL))
1474: damage = 0;
1475:
1476: /* Check for monsters that ignore sharp weapons */
1477:
1478: if (on(*def_er, NOSHARP) && (weap != NULL) &&
1479: (weap->o_flags & ISSHARP))
1480: damage = 0;
1481:
1482: /* Check for poisoned weapons */
1483:
1484: if ((weap != NULL) && (weap->o_flags & ISPOISON)
1485: && off(*def_er, ISUNDEAD)
1486: && !save_throw(VS_POISON, def_er))
1487: damage = max(damage, (def->s_hpt / 2) + 5);
1488:
1489: /* Check for no-damage and division */
1490:
1491: if (on(*def_er, BLOWDIVIDE) && rnd(3) == 0 &&
1492: !((weap != NULL) && (weap->o_flags & CANBURN)))
1493: {
1494: damage = 0;
1495: creat_mons(def_er, def_er->t_index, NOMESSAGE);
1496: }
1497:
1498: damage = max(0, damage);
1499:
1500: /*
1501: * sleeping monsters are backstabbed by certain
1502: * player classes, but only when they can see
1503: */
1504:
1505: if (is_player && !thrown && damage > 0 &&
1506: (off(*def_er, ISRUN) || def_er->t_no_move > 0) &&
1507: (player.t_ctype == C_THIEF ||
1508: player.t_ctype == C_NINJA ||
1509: player.t_ctype == C_ASSASIN) &&
1510: off(player,ISBLIND)
1511: && (wield_ok(&player, my_weapon, NOMESSAGE))
1512: && (wear_ok(&player, cur_armor, NOMESSAGE)))
1513: {
1514: damage *= (pstats.s_lvl / 4 + 2);
1515:
1516: msg("You backstabbed the %s %d times!",
1517: monsters[def_er->t_index].m_name,
1518: (pstats.s_lvl / 4) + 2);
1519:
1520: if (player.t_ctype == C_NINJA ||
1521: player.t_ctype == C_ASSASIN)
1522: pstats.s_exp += def_er->t_stats.s_exp
1523: / 2;
1524: }
1525:
1526: def->s_hpt -= damage; /* Do the damage */
1527:
1528: debug("Hit %s for %d (%d) ",
1529: monsters[def_er->t_index].m_name, damage,
1530: def_er->t_stats.s_hpt);
1531:
1532: if (is_player && is_wearing(R_VREGEN))
1533: {
1534: damage = (ring_value(R_VREGEN) * damage) / 3;
1535: pstats.s_hpt = min(max_stats.s_hpt,
1536: pstats.s_hpt + damage);
1537: }
1538:
1539: /* stun monsters when taking more than 1/3 their max hpts */
1540:
1541: if (is_player && !thrown && !did_hit &&
1542: (player.t_ctype == C_FIGHTER) &&
1543: (damage > def_er->maxstats.s_hpt / 3) )
1544: {
1545: if (def->s_hpt > 0)
1546: {
1547: msg("The %s has been stunned!",
1548: monsters[def_er->t_index].m_name);
1549: def_er->t_no_move += rnd(4) + 1;
1550: }
1551: pstats.s_exp += def_er->t_stats.s_exp / 4;
1552: }
1553:
1554: did_hit = TRUE;
1555: }
1556:
1557: if (cp == NULL || (cp = strchr(cp, '/')) == NULL)
1558: break;
1559:
1560: cp++;
1561: }
1562:
1563: return(did_hit);
1564: }
1565:
1566: /*
1567: prname()
1568: Figure out the monsters name
1569: */
1570:
1571: const char *
1572: prname(char *who)
1573: {
1574: if (on(player, ISBLIND))
1575: return(monstern);
1576: else
1577: return(who);
1578: }
1579:
1580: /*
1581: hit()
1582: Print a message to indicate a succesful hit
1583: */
1584:
1585: void
1586: hit(char *ee)
1587: {
1588: char *s;
1589:
1590: if (fighting)
1591: return;
1592:
1593: switch (rnd(15))
1594: {
1595: default: s = "hit"; break;
1596: case 1: s = "score an excellent hit on"; break;
1597: case 2: s = "injure"; break;
1598: case 3: s = "swing and hit"; break;
1599: case 4: s = "damage"; break;
1600: case 5: s = "barely nick"; break;
1601: case 6: s = "scratch"; break;
1602: case 7: s = "gouge a chunk out of"; break;
1603: case 8: s = "severely wound"; break;
1604: case 9: s = "counted coup on"; break;
1605: case 10: s = "drew blood from"; break;
1606: case 11: s = "nearly decapitate"; break;
1607: case 12: s = "deal a wacking great blow to"; break;
1608: }
1609:
1610: msg("You %s the %s.", s, prname(ee));
1611: }
1612:
1613: /*
1614: miss()
1615: Print a message to indicate a poor swing
1616: */
1617:
1618: void
1619: miss(char *ee)
1620: {
1621: char *s;
1622:
1623: if (fighting)
1624: return;
1625:
1626: switch (rnd(10))
1627: {
1628: default: s = "miss"; break;
1629: case 1: s = "swing and miss"; break;
1630: case 2: s = "barely miss"; break;
1631: case 3: s = "don't hit"; break;
1632: case 4: s = "wildly windmill around"; break;
1633: case 5: s = "almost fumble while missing"; break;
1634: }
1635:
1636: msg("You %s the %s.", s, prname(ee));
1637: }
1638:
1639: /*
1640: save_throw()
1641: See if a creature save against something
1642: */
1643:
1644: int
1645: save_throw(int which, struct thing *tp)
1646: {
1647: int need;
1648: int ring_bonus = 0;
1649: int armor_bonus = 0;
1650: int class_bonus = 0;
1651:
1652: if (tp == &player)
1653: {
1654: if (player.t_ctype == C_PALADIN)
1655: class_bonus = 2;
1656:
1657: ring_bonus = ring_value(R_PROTECT);
1658:
1659: if (cur_armor != NULL && (which == VS_WAND ||
1660: which == VS_MAGIC))
1661: {
1662: if (cur_armor->o_which == MITHRIL)
1663: armor_bonus += 5;
1664: armor_bonus += (armors[cur_armor->o_which].a_class
1665: - cur_armor->o_ac);
1666: }
1667: }
1668:
1669: need = 14 + which - tp->t_stats.s_lvl / 2 - ring_bonus -
1670: armor_bonus - class_bonus;
1671:
1672: /* Roll of 1 always fails; 20 always saves */
1673:
1674: if (need < 1)
1675: need = 1;
1676: else if (need > 20)
1677: need = 20;
1678:
1679: return(roll(1, 20) >= need);
1680: }
1681:
1682: /*
1683: save()
1684: See if he saves against various nasty things
1685: */
1686:
1687: int
1688: save(int which)
1689: {
1690: return save_throw(which, &player);
1691: }
1692:
1693: /*
1694: dext_plus()
1695: compute to-hit bonus for dexterity
1696: */
1697:
1698: int
1699: dext_plus(int dexterity)
1700: {
1701: return ((dexterity - 10) / 3);
1702: }
1703:
1704: /*
1705: * dext_prot: compute armor class bonus for dexterity
1706: */
1707:
1708: int
1709: dext_prot(int dexterity)
1710: {
1711: return ((dexterity - 9) / 2);
1712: }
1713:
1714: /*
1715: str_plus()
1716: compute bonus/penalties for strength on the "to hit" roll
1717: */
1718:
1719: static const int strtohit[] =
1720: {
1721: 0, 0, 0, -3, -2, -2, -1, -1,
1722: 0, 0, 0, 0, 0, 0, 0, 0, 0,
1723: 1, 1, 3, 3, 4, 4, 5, 6, 7
1724: };
1725:
1726: int
1727: str_plus(int str)
1728: {
1729: int ret_val = str;
1730:
1731: if (str < 3)
1732: ret_val = 3;
1733: else if (str > 25)
1734: ret_val = 25;
1735:
1736: return(strtohit[ret_val]);
1737: }
1738:
1739: /*
1740: add_dam()
1741: compute additional damage done for exceptionally high or low strength
1742: */
1743:
1744: static const int str_damage[] =
1745: {
1746: 0, 0, 0, -1, -1, -1, 0, 0,
1747: 0, 0, 0, 0, 0, 0, 0, 0, 1,
1748: 1, 2, 7, 8, 9, 10, 11, 12, 14
1749: };
1750:
1751: int
1752: add_dam(int str)
1753: {
1754: int ret_val = str;
1755:
1756: if (str < 3)
1757: ret_val = 3;
1758: else if (str > 25)
1759: ret_val = 25;
1760:
1761: return(str_damage[ret_val]);
1762: }
1763:
1764: /*
1765: hung_dam()
1766: Calculate damage depending on players hungry state
1767: */
1768:
1769: int
1770: hung_dam(void)
1771: {
1772: int howmuch = 0;
1773:
1774: switch (hungry_state)
1775: {
1776: case F_OK:
1777: case F_HUNGRY: howmuch = 0; break;
1778: case F_WEAK: howmuch = -1; break;
1779: case F_FAINT: howmuch = -2; break;
1780: }
1781:
1782: return(howmuch);
1783: }
1784:
1785: /*
1786: raise_level()
1787: The guy just magically went up a level.
1788: */
1789:
1790: void
1791: raise_level(void)
1792: {
1793: pstats.s_exp = max_stats.s_exp;
1794: check_level();
1795: }
1796:
1797: /*
1798: thunk()
1799: A missile hits a monster
1800: */
1801:
1802: void
1803: thunk(struct object *weap, char *mname)
1804: {
1805: if (fighting)
1806: return;
1807:
1808: if (weap->o_type == WEAPON)
1809: msg("The %s hits the %s.", weaps[weap->o_which].w_name, prname(mname));
1810: else
1811: msg("You hit the %s.", prname(mname));
1812: }
1813:
1814: /*
1815: m_thunk()
1816: A missile from a monster hits the player
1817: */
1818:
1819: void
1820: m_thunk(struct object *weap, char *mname)
1821: {
1822: if (fighting)
1823: return;
1824:
1825: if (weap != NULL && weap->o_type == WEAPON)
1826: msg("The %s's %s hits you.",prname(mname),weaps[weap->o_which].w_name);
1827: else
1828: msg("The %s hits you.", prname(mname));
1829: }
1830:
1831: /*
1832: bounce()
1833: A missile misses a monster
1834: */
1835:
1836: void
1837: bounce(struct object *weap, char *mname)
1838: {
1839: if (fighting)
1840: return;
1841:
1842: if (weap->o_type == WEAPON)
1843: msg("The %s misses the %s.",weaps[weap->o_which].w_name,prname(mname));
1844: else
1845: msg("You missed the %s.", prname(mname));
1846: }
1847:
1848: /*
1849: m_bounce()
1850: A missile from a monster misses the player
1851: */
1852:
1853: void
1854: m_bounce(struct object *weap, char *mname)
1855: {
1856: if (fighting)
1857: return;
1858:
1859: if (weap != NULL && weap->o_type == WEAPON)
1860: msg("The %s's %s misses you.", prname(mname),
1861: weaps[weap->o_which].w_name);
1862: else
1863: msg("The %s misses you.", prname(mname));
1864: }
1865:
1866: /*
1867: remove_monster()
1868: remove a monster from the screen
1869: */
1870:
1871: void
1872: remove_monster(coord *mp, struct linked_list *item)
1873: {
1874: struct thing *tp = THINGPTR(item);
1875: char ch = tp->t_oldch;
1876:
1877: mvwaddch(mw, mp->y, mp->x, ' ');
1878:
1879: if (ch < 33 || ch == ' ')
1880: ch = CCHAR( mvwinch(stdscr, mp->y, mp->x) );
1881:
1882: if (cansee(mp->y, mp->x))
1883: mvwaddch(cw, mp->y, mp->x, ch);
1884:
1885: detach(mlist, item);
1886: discard(item);
1887: }
1888:
1889: /*
1890: is_magic()
1891: Returns true if an object radiates magic
1892: */
1893:
1894: int
1895: is_magic(struct object *obj)
1896: {
1897: switch (obj->o_type)
1898: {
1899: case ARMOR:
1900: return(obj->o_ac != armors[obj->o_which].a_class);
1901:
1902: case WEAPON:
1903: return(obj->o_hplus != 0 || obj->o_dplus != 0);
1904:
1905: case POTION:
1906: case SCROLL:
1907: case STICK:
1908: case RING:
1909: case ARTIFACT:
1910: return(TRUE);
1911: }
1912:
1913: return(FALSE);
1914: }
1915:
1916: /*
1917: killed()
1918: Called to put a monster to death
1919: */
1920:
1921: void
1922: killed(struct thing *killer, struct linked_list *item, int print_message,
1923: int give_points)
1924: {
1925: struct linked_list *pitem, *nitem;
1926: struct thing *tp = THINGPTR(item);
1927: int visible = cansee(tp->t_pos.y, tp->t_pos.x);
1928: int is_player = (killer == (&player));
1929:
1930: if (item == curr_mons)
1931: curr_mons = NULL;
1932: else if (item == next_mons)
1933: next_mons = next(next_mons);
1934:
1935: if (on(*tp, WASSUMMONED))
1936: {
1937: extinguish_fuse(FUSE_UNSUMMON);
1938: turn_off(player, HASSUMMONED);
1939: }
1940:
1941: if (print_message && visible)
1942: {
1943: if (is_player)
1944: addmsg("You have defeated ");
1945: else
1946: addmsg("The %s has defeated ",
1947: monsters[killer->t_index].m_name);
1948:
1949: if (on(player, ISBLIND))
1950: msg("it.");
1951: else
1952: msg("the %s.", monsters[tp->t_index].m_name);
1953: }
1954: debug("Removing %s", monsters[tp->t_index].m_name);
1955: if (killer != NULL && item == fam_ptr) /* The player's familiar died */
1956: {
1957: turn_off(player, HASFAMILIAR);
1958: fam_ptr = NULL;
1959: msg("An incredible wave of sadness sweeps over you.");
1960: }
1961:
1962: check_residue(tp);
1963:
1964: if (is_player)
1965: {
1966: fighting = FALSE;
1967:
1968: if (on(*tp, ISFRIENDLY))
1969: {
1970: msg("You feel a slight chill run up and down your spine.");
1971: luck++;
1972: }
1973: }
1974:
1975: if (give_points)
1976: {
1977: if (killer != NULL)
1978: {
1979: killer->t_stats.s_exp += tp->t_stats.s_exp;
1980:
1981: if (on(*killer, ISFAMILIAR))
1982: pstats.s_exp += tp->t_stats.s_exp;
1983: }
1984:
1985: if (is_player)
1986: {
1987: switch (player.t_ctype)
1988: {
1989: case C_CLERIC:
1990: case C_PALADIN:
1991: if (on(*tp, ISUNDEAD) || on(*tp, ISUNIQUE))
1992: {
1993: pstats.s_exp += tp->t_stats.s_exp / 2;
1994: msg("You are to be commended for smiting the ungodly.");
1995: }
1996: break;
1997:
1998: case C_DRUID:
1999: case C_RANGER:
2000: if (on(*tp, ISLARGE))
2001: {
2002: pstats.s_exp += tp->t_stats.s_exp / 2;
2003: msg("Congratulations on smiting a dangerous monster.");
2004: }
2005: break;
2006:
2007: case C_MAGICIAN:
2008: case C_ILLUSION:
2009: if (on(*tp, DRAINBRAIN))
2010: {
2011: pstats.s_exp += tp->t_stats.s_exp / 2;
2012: msg("Congratulations on smiting a dangerous monster.");
2013: }
2014:
2015: }
2016: }
2017: check_level();
2018: }
2019:
2020: /* Empty the monsters pack */
2021:
2022: for (pitem = tp->t_pack; pitem != NULL; pitem = nitem)
2023: {
2024: struct object *obj = OBJPTR(pitem);
2025:
2026: nitem = next(pitem);
2027:
2028: obj->o_pos = tp->t_pos;
2029: detach(tp->t_pack, pitem);
2030:
2031: if (killer == NULL)
2032: discard(pitem);
2033: else
2034: fall(killer, pitem, FALSE, FALSE);
2035: }
2036:
2037: remove_monster(&tp->t_pos, item);
2038: }
2039:
2040:
2041: /*
2042: wield_weap()
2043: Returns a pointer to the weapon the monster is wielding corresponding to the given thrown weapon
2044: */
2045:
2046: struct object *
2047: wield_weap(struct object *weapon, struct thing *mp)
2048: {
2049: int look_for;
2050: struct linked_list *pitem;
2051:
2052: if (weapon == NULL)
2053: return (NULL);
2054:
2055: switch (weapon->o_which)
2056: {
2057: case BOLT:
2058: look_for = CROSSBOW;
2059: break;
2060:
2061: case ARROW:
2062: look_for = BOW;
2063: break;
2064:
2065: case SILVERARROW:
2066: case FLAMEARROW:
2067: look_for = BOW;
2068: break;
2069:
2070: case ROCK:
2071: case BULLET:
2072: look_for = SLING;
2073: break;
2074:
2075: default:
2076: return(NULL);
2077: }
2078:
2079: for (pitem = mp->t_pack; pitem; pitem = next(pitem))
2080: if ((OBJPTR(pitem))->o_which == look_for)
2081: return(OBJPTR(pitem));
2082:
2083: return (NULL);
2084: }
2085:
2086: /*
2087: summon_help()
2088: Summon - see whether to summon help Returns TRUE if help comes, FALSE
2089: otherwise
2090: */
2091:
2092: void
2093: summon_help(struct thing *mons, int force)
2094: {
2095: char *helpname;
2096: int which, i;
2097: char *mname = monsters[mons->t_index].m_name;
2098:
2099: /* Try to summon if less than 1/3 max hit points */
2100:
2101: if (on(*mons, CANSUMMON) &&
2102: (force == FORCE ||
2103: (mons->t_stats.s_hpt < mons->maxstats.s_hpt / 3) &&
2104: (rnd(40 * 10) < (mons->t_stats.s_lvl * mons->t_stats.s_intel))))
2105: {
2106: turn_off(*mons, CANSUMMON);
2107: msg("The %s summons its attendants!", mname);
2108: helpname = monsters[mons->t_index].m_typesum;
2109:
2110: for (which = 1; which < nummonst; which++)
2111: {
2112: if (strcmp(helpname, monsters[which].m_name) == 0)
2113: break;
2114: }
2115:
2116: if (which >= nummonst)
2117: {
2118: debug("Couldn't find summoned one.");
2119: return;
2120: }
2121:
2122: /* summoned monster was genocided */
2123:
2124: if (!monsters[which].m_normal)
2125: {
2126: msg("The %s becomes very annoyed at you!", mname);
2127:
2128: if (on(*mons, ISSLOW))
2129: turn_off(*mons, ISSLOW);
2130: else
2131: turn_on(*mons, ISHASTE);
2132:
2133: return;
2134: }
2135: else
2136: for (i = 0; i < monsters[mons->t_index].m_numsum; i++)
2137: {
2138: struct linked_list *ip;
2139: struct thing *tp;
2140:
2141: if ((ip = creat_mons(mons, which, NOMESSAGE)) != NULL)
2142: {
2143: tp = THINGPTR(ip);
2144: turn_off(*tp, ISFRIENDLY);
2145: }
2146: }
2147: }
2148:
2149: return;
2150: }
2151:
2152: /*
2153: maxdamage()
2154: return the max damage a weapon can do
2155: */
2156:
2157: int
2158: maxdamage(char *cp)
2159: {
2160: int ndice, nsides, nplus;
2161:
2162: ndice = atoi(cp);
2163:
2164: if (cp == NULL || (cp = strchr(cp, 'd')) == NULL)
2165: return(0);
2166:
2167: nsides = atoi(++cp);
2168:
2169: if (cp != NULL && (cp = strchr(cp, '+')) != NULL)
2170: nplus = atoi(++cp);
2171: else
2172: nplus = 0;
2173:
2174: return(ndice * nsides + nplus);
2175: }
CVSweb