Neale Pickett
·
2011-10-13
continue.c
1/*
2 * All the fighting gets done here
3 *
4 * @(#)continue.c 4.67 (Berkeley) 09/06/83
5 */
6
7#include <curses.h>
8#include <ctype.h>
9#include "netprot.h"
10
11#define EQSTR(a, b) (strcmp(a, b) == 0)
12
13char *H_names[] = { /* strings for hitting */
14 " scored an excellent hit on ",
15 " hit ",
16 " have injured ",
17 " swing and hit ",
18 " scored an excellent hit on ",
19 " hit ",
20 " has injured ",
21 " swings and hits "
22};
23
24char *M_names[] = { /* strings for missing */
25 " miss",
26 " swing and miss",
27 " barely miss",
28 " don't hit",
29 " misses",
30 " swings and misses",
31 " barely misses",
32 " doesn't hit",
33};
34
35/*
36 * adjustments to hit probabilities due to strength
37 */
38static int Str_plus[] = {
39 -7, -6, -5, -4, -3, -2, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1,
40 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3,
41};
42
43/*
44 * adjustments to damage done due to strength
45 */
46static int Add_dam[] = {
47 -7, -6, -5, -4, -3, -2, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3,
48 3, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6
49};
50
51/*
52 * fight:
53 * The player attacks the monster.
54 */
55bool
56fight(coord *mp, THING *weap, bool thrown)
57{
58 THING *tp;
59 bool did_hit = TRUE;
60 char *mname, ch;
61
62 /*
63 * Find the monster we want to fight
64 */
65#ifdef MASTER
66 if ((tp = moat(mp->y, mp->x)) == NULL)
67 debug("Fight what @ %d,%d", mp->y, mp->x);
68#else
69 tp = moat(mp->y, mp->x);
70#endif
71 /*
72 * Since we are fighting, things are not quiet so no healing takes
73 * place.
74 */
75 Count = 0;
76 Quiet = 0;
77 runto(mp);
78 /*
79 * Let him know it was really a xeroc (if it was one).
80 */
81 ch = '\0';
82 if (tp->t_type == 'X' && tp->t_disguise != 'X' && !on(Player, ISBLIND))
83 {
84 tp->t_disguise = 'X';
85 if (on(Player, ISHALU)) {
86 ch = rnd(26) + 'A';
87 mvaddch(tp->t_pos.y, tp->t_pos.x, ch);
88 }
89 msg(choose_str("heavy! That's a nasty critter!",
90 "wait! That's a xeroc!"));
91 if (!thrown)
92 return FALSE;
93 }
94 mname = set_mname(tp);
95 did_hit = FALSE;
96 Has_hit = (Terse && !To_death);
97 if (roll_em(&Player, tp, weap, thrown))
98 {
99 did_hit = FALSE;
100 if (thrown)
101 thunk(weap, mname, Terse);
102 else
103 hit((char *) NULL, mname, Terse);
104 if (on(Player, CANHUH))
105 {
106 did_hit = TRUE;
107 tp->t_flags |= ISHUH;
108 Player.t_flags &= ~CANHUH;
109 endmsg();
110 Has_hit = FALSE;
111 msg("your hands stop glowing %s", pick_color("red"));
112 }
113 if (tp->t_stats.s_hpt <= 0)
114 killed(tp, TRUE);
115 else if (did_hit && !on(Player, ISBLIND))
116 msg("%s appears confused", mname);
117 did_hit = TRUE;
118 }
119 else
120 if (thrown)
121 bounce(weap, mname, Terse);
122 else
123 miss((char *) NULL, mname, Terse);
124 return did_hit;
125}
126
127/*
128 * attack:
129 * The monster attacks the player
130 */
131void
132attack(THING *mp)
133{
134 char *mname, ch;
135 int oldhp;
136
137 /*
138 * Since this is an attack, stop running and any healing that was
139 * going on at the time.
140 */
141 Running = FALSE;
142 Count = 0;
143 Quiet = 0;
144 if (To_death && !on(*mp, ISTARGET))
145 {
146 To_death = FALSE;
147 Kamikaze = FALSE;
148 }
149 if (mp->t_type == 'X' && mp->t_disguise != 'X' && !on(Player, ISBLIND))
150 {
151 mp->t_disguise = 'X';
152 if (on(Player, ISHALU))
153 mvaddch(mp->t_pos.y, mp->t_pos.x, rnd(26) + 'A');
154 }
155 mname = set_mname(mp);
156 oldhp = Pstats.s_hpt;
157 if (roll_em(mp, &Player, (THING *) NULL, FALSE))
158 {
159 if (mp->t_type != 'I')
160 {
161 if (Has_hit)
162 addmsg(". ");
163 hit(mname, (char *) NULL, FALSE);
164 }
165 else
166 if (Has_hit)
167 endmsg();
168 Has_hit = FALSE;
169 if (Pstats.s_hpt <= 0)
170 death(mp->t_type); /* Bye bye life ... */
171 else if (!Kamikaze)
172 {
173 oldhp -= Pstats.s_hpt;
174 if (oldhp > Max_hit)
175 Max_hit = oldhp;
176 if (Pstats.s_hpt <= Max_hit)
177 To_death = FALSE;
178 }
179 if (!on(*mp, ISCANC))
180 switch (mp->t_type)
181 {
182 when 'A':
183 /*
184 * If an aquator hits, you can lose armor class.
185 */
186 rust_armor(Cur_armor);
187 when 'I':
188 /*
189 * The ice monster freezes you
190 */
191 Player.t_flags &= ~ISRUN;
192 if (!No_command)
193 {
194 addmsg("you are frozen");
195 if (!Terse)
196 addmsg(" by the %s", mname);
197 endmsg();
198 }
199 No_command += rnd(2) + 2;
200 if (No_command > BORE_LEVEL)
201 death('h');
202 when 'R':
203 /*
204 * Rattlesnakes have poisonous bites
205 */
206 if (!save(VS_POISON))
207 if (!ISWEARING(R_SUSTSTR))
208 {
209 chg_str(-1);
210 if (!Terse)
211 msg("you feel a bite in your leg and now feel weaker");
212 else
213 msg("a bite has weakened you");
214 }
215 else if (!To_death)
216 if (!Terse)
217 msg("a bite momentarily weakens you");
218 else
219 msg("bite has no effect");
220 when 'W':
221 case 'V':
222 /*
223 * Wraiths might drain energy levels, and Vampires
224 * can steal Max_hp
225 */
226 if (rnd(100) < (mp->t_type == 'W' ? 15 : 30))
227 {
228 int fewer;
229
230 if (mp->t_type == 'W')
231 {
232 if (Pstats.s_exp == 0)
233 death('W'); /* All levels gone */
234 if (--Pstats.s_lvl == 0)
235 {
236 Pstats.s_exp = 0;
237 Pstats.s_lvl = 1;
238 }
239 else
240 Pstats.s_exp = E_levels[Pstats.s_lvl-1]+1;
241 fewer = roll(1, 10);
242 }
243 else
244 fewer = roll(1, 3);
245 Pstats.s_hpt -= fewer;
246 Max_hp -= fewer;
247 if (Pstats.s_hpt <= 0)
248 Pstats.s_hpt = 1;
249 if (Max_hp <= 0)
250 death(mp->t_type);
251 msg("you suddenly feel weaker");
252 }
253 when 'F':
254 /*
255 * Venus Flytrap stops the poor guy from moving
256 */
257 Player.t_flags |= ISHELD;
258 sprintf(Monsters['F'-'A'].m_stats.s_dmg,"%dx1", ++Vf_hit);
259 if (--Pstats.s_hpt <= 0)
260 death('F');
261 when 'L':
262 {
263 /*
264 * Leperachaun steals some gold
265 */
266 long lastpurse;
267
268 lastpurse = Purse;
269 Purse -= GOLDCALC;
270 if (!save(VS_MAGIC))
271 Purse -= GOLDCALC + GOLDCALC + GOLDCALC + GOLDCALC;
272 if (Purse < 0)
273 Purse = 0;
274 remove_mon(&mp->t_pos, mp, FALSE);
275 if (Purse != lastpurse)
276 msg("your purse feels lighter");
277 }
278 when 'N':
279 {
280 THING *obj, *steal;
281 int nobj;
282
283 /*
284 * Nymph's steal a magic item, look through the pack
285 * and pick out one we like.
286 */
287 steal = NULL;
288 for (nobj = 0, obj = Pack; obj != NULL; obj = next(obj))
289 if (obj != Cur_armor && obj != Cur_weapon
290 && obj != Cur_ring[LEFT] && obj != Cur_ring[RIGHT]
291 && is_magic(obj) && rnd(++nobj) == 0)
292 steal = obj;
293 if (steal != NULL)
294 {
295 remove_mon(&mp->t_pos, moat(mp->t_pos.y, mp->t_pos.x), FALSE);
296 leave_pack(steal, FALSE, FALSE);
297 msg("she stole %s!", inv_name(steal, TRUE));
298 discard(steal);
299 }
300 }
301 otherwise:
302 break;
303 }
304 }
305 else if (mp->t_type != 'I')
306 {
307 if (Has_hit)
308 {
309 addmsg(". ");
310 Has_hit = FALSE;
311 }
312 if (mp->t_type == 'F')
313 {
314 Pstats.s_hpt -= Vf_hit;
315 if (Pstats.s_hpt <= 0)
316 death(mp->t_type); /* Bye bye life ... */
317 }
318 miss(mname, (char *) NULL, FALSE);
319 }
320 if (Fight_flush && !To_death)
321 flush_type();
322 Count = 0;
323 status();
324}
325
326/*
327 * set_mname:
328 * return the monster name for the given monster
329 */
330char *
331set_mname(THING *tp)
332{
333 int ch;
334 char *mname;
335 static char tbuf[MAXSTR] = { 't', 'h', 'e', ' ' };
336
337 if (!see_monst(tp) && !on(Player, SEEMONST))
338 return (Terse ? "it" : "something");
339 else if (on(Player, ISHALU))
340 {
341 move(tp->t_pos.y, tp->t_pos.x);
342 ch = toascii(inch());
343 if (!isupper(ch))
344 ch = rnd(26);
345 else
346 ch -= 'A';
347 mname = Monsters[ch].m_name;
348 }
349 else
350 mname = Monsters[tp->t_type - 'A'].m_name;
351 strcpy(&tbuf[4], mname);
352 return tbuf;
353}
354
355/*
356 * swing:
357 * Returns true if the swing hits
358 */
359bool
360swing(int at_lvl, int op_arm, int wplus)
361{
362 int res = rnd(20);
363 int need = (20 - at_lvl) - op_arm;
364
365 return (res + wplus >= need);
366}
367
368/*
369 * roll_em:
370 * Roll several attacks
371 */
372bool
373roll_em(THING *thatt, THING *thdef, THING *weap, bool hurl)
374{
375 struct stats *att, *def;
376 char *cp;
377 int ndice, nsides, def_arm;
378 bool did_hit = FALSE;
379 int hplus;
380 int dplus;
381 int damage;
382 char *index();
383
384 att = &thatt->t_stats;
385 def = &thdef->t_stats;
386 if (weap == NULL)
387 {
388 cp = att->s_dmg;
389 dplus = 0;
390 hplus = 0;
391 }
392 else
393 {
394 hplus = (weap == NULL ? 0 : weap->o_hplus);
395 dplus = (weap == NULL ? 0 : weap->o_dplus);
396 if (weap == Cur_weapon)
397 {
398 if (ISRING(LEFT, R_ADDDAM))
399 dplus += Cur_ring[LEFT]->o_arm;
400 else if (ISRING(LEFT, R_ADDHIT))
401 hplus += Cur_ring[LEFT]->o_arm;
402 if (ISRING(RIGHT, R_ADDDAM))
403 dplus += Cur_ring[RIGHT]->o_arm;
404 else if (ISRING(RIGHT, R_ADDHIT))
405 hplus += Cur_ring[RIGHT]->o_arm;
406 }
407 cp = weap->o_damage;
408 if (hurl)
409 if ((weap->o_flags&ISMISL) && Cur_weapon != NULL &&
410 Cur_weapon->o_which == weap->o_launch)
411 {
412 cp = weap->o_hurldmg;
413 hplus += Cur_weapon->o_hplus;
414 dplus += Cur_weapon->o_dplus;
415 }
416 else if (weap->o_launch < 0)
417 cp = weap->o_hurldmg;
418 }
419 /*
420 * If the creature being attacked is not running (alseep or held)
421 * then the attacker gets a plus four bonus to hit.
422 */
423 if (!on(*thdef, ISRUN))
424 hplus += 4;
425 def_arm = def->s_arm;
426 if (def == &Pstats)
427 {
428 if (Cur_armor != NULL)
429 def_arm = Cur_armor->o_arm;
430 if (ISRING(LEFT, R_PROTECT))
431 def_arm -= Cur_ring[LEFT]->o_arm;
432 if (ISRING(RIGHT, R_PROTECT))
433 def_arm -= Cur_ring[RIGHT]->o_arm;
434 }
435 while (cp != NULL && *cp != '\0')
436 {
437 ndice = atoi(cp);
438 if ((cp = index(cp, 'x')) == NULL)
439 break;
440 nsides = atoi(++cp);
441 if (swing(att->s_lvl, def_arm, hplus + Str_plus[att->s_str]))
442 {
443 int proll;
444
445 proll = roll(ndice, nsides);
446#ifdef MASTER
447 if (ndice + nsides > 0 && proll <= 0)
448 debug("Damage for %dx%d came out %d, dplus = %d, Add_dam = %d, def_arm = %d", ndice, nsides, proll, dplus, Add_dam[att->s_str], def_arm);
449#endif
450 damage = dplus + proll + Add_dam[att->s_str];
451 def->s_hpt -= max(0, damage);
452 did_hit = TRUE;
453 }
454 if ((cp = index(cp, '/')) == NULL)
455 break;
456 cp++;
457 }
458 return did_hit;
459}
460
461/*
462 * prname:
463 * The print name of a combatant
464 */
465char *
466prname(char *mname, bool upper)
467{
468 static char tbuf[MAXSTR];
469
470 *tbuf = '\0';
471 if (mname == 0)
472 strcpy(tbuf, "you");
473 else
474 strcpy(tbuf, mname);
475 if (upper)
476 *tbuf = toupper(*tbuf);
477 return tbuf;
478}
479
480/*
481 * thunk:
482 * A missile hits a monster
483 */
484void
485thunk(THING *weap, char *mname, bool noend)
486{
487 if (To_death)
488 return;
489 if (weap->o_type == WEAPON)
490 addmsg("the %s hits ", Weap_info[weap->o_which].oi_name);
491 else
492 addmsg("you hit ");
493 addmsg("%s", mname);
494 if (!noend)
495 endmsg();
496}
497
498/*
499 * hit:
500 * Print a message to indicate a succesful hit
501 */
502void
503hit(char *er, char *ee, bool noend)
504{
505 int i;
506 char *s;
507 extern char *H_names[];
508
509 if (To_death)
510 return;
511 addmsg(prname(er, TRUE));
512 if (Terse)
513 s = " hit";
514 else
515 {
516 i = rnd(4);
517 if (er != NULL)
518 i += 4;
519 s = H_names[i];
520 }
521 addmsg(s);
522 if (!Terse)
523 addmsg(prname(ee, FALSE));
524 if (!noend)
525 endmsg();
526}
527
528/*
529 * miss:
530 * Print a message to indicate a poor swing
531 */
532void
533miss(char *er, char *ee, bool noend)
534{
535 int i;
536 extern char *M_names[];
537
538 if (To_death)
539 return;
540 addmsg(prname(er, TRUE));
541 if (Terse)
542 i = 0;
543 else
544 i = rnd(4);
545 if (er != NULL)
546 i += 4;
547 addmsg(M_names[i]);
548 if (!Terse)
549 addmsg(" %s", prname(ee, FALSE));
550 if (!noend)
551 endmsg();
552}
553
554/*
555 * bounce:
556 * A missile misses a monster
557 */
558void
559bounce(THING *weap, char *mname, bool noend)
560{
561 if (To_death)
562 return;
563 if (weap->o_type == WEAPON)
564 addmsg("the %s misses ", Weap_info[weap->o_which].oi_name);
565 else
566 addmsg("you missed ");
567 addmsg(mname);
568 if (!noend)
569 endmsg();
570}
571
572/*
573 * remove_mon:
574 * Remove a monster from the screen
575 */
576void
577remove_mon(coord *mp, THING *tp, bool waskill)
578{
579 THING *obj, *nexti;
580
581 for (obj = tp->t_pack; obj != NULL; obj = nexti)
582 {
583 nexti = next(obj);
584 obj->o_pos = tp->t_pos;
585 detach(tp->t_pack, obj);
586 if (waskill)
587 fall(obj, FALSE);
588 else
589 discard(obj);
590 }
591 moat(mp->y, mp->x) = NULL;
592 mvaddch(mp->y, mp->x, tp->t_oldch);
593 detach(Mlist, tp);
594 if (on(*tp, ISTARGET))
595 {
596 Kamikaze = FALSE;
597 To_death = FALSE;
598 if (Fight_flush)
599 flush_type();
600 }
601 discard(tp);
602}
603
604/*
605 * killed:
606 * Called to put a monster to death
607 */
608void
609killed(THING *tp, bool pr)
610{
611 char *mname;
612
613 Pstats.s_exp += tp->t_stats.s_exp;
614
615 /*
616 * If the monster was a venus flytrap, un-hold him
617 */
618 switch (tp->t_type)
619 {
620 when 'F':
621 Player.t_flags &= ~ISHELD;
622 Vf_hit = 0;
623 strcpy(Monsters['F'-'A'].m_stats.s_dmg, "000x0");
624 when 'L':
625 {
626 THING *gold;
627
628 if (fallpos(&tp->t_pos, &tp->t_room->r_gold) && Level >= Max_level)
629 {
630 gold = new_item();
631 gold->o_type = GOLD;
632 gold->o_goldval = GOLDCALC;
633 if (save(VS_MAGIC))
634 gold->o_goldval += GOLDCALC + GOLDCALC
635 + GOLDCALC + GOLDCALC;
636 attach(tp->t_pack, gold);
637 }
638 }
639 }
640 /*
641 * Get rid of the monster.
642 */
643 mname = set_mname(tp);
644 remove_mon(&tp->t_pos, tp, TRUE);
645 if (pr)
646 {
647 if (Has_hit)
648 {
649 addmsg(". Defeated ");
650 Has_hit = FALSE;
651 }
652 else
653 {
654 if (!Terse)
655 addmsg("you have ");
656 addmsg("defeated ");
657 }
658 msg(mname);
659 }
660 /*
661 * Do adjustments if he went up a level
662 */
663 check_level();
664 if (Fight_flush)
665 flush_type();
666}