comparison srogue/fight.c @ 36:2128c7dc8a40

Import Super-Rogue 9.0 from the Roguelike Restoration Project (r1490)
author elwin
date Thu, 25 Nov 2010 12:21:41 +0000
parents
children 94a0d9dd5ce1
comparison
equal deleted inserted replaced
35:05018c63a721 36:2128c7dc8a40
1 /*
2 * All the fighting gets done here
3 *
4 * @(#)fight.c 9.0 (rdk) 7/17/84
5 *
6 * Super-Rogue
7 * Copyright (C) 1984 Robert D. Kindelberger
8 * All rights reserved.
9 *
10 * Based on "Rogue: Exploring the Dungeons of Doom"
11 * Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman
12 * All rights reserved.
13 *
14 * See the file LICENSE.TXT for full copyright and licensing information.
15 */
16
17 #include <ctype.h>
18 #include "rogue.h"
19 #include "rogue.ext"
20
21
22 /*
23 * fight:
24 * The player attacks the monster.
25 */
26 fight(mp, weap, thrown)
27 struct coord *mp;
28 struct object *weap;
29 bool thrown;
30 {
31
32 reg struct thing *tp;
33 reg struct stats *st;
34 reg struct linked_list *item;
35 bool did_hit = TRUE;
36
37 if (pl_on(ISETHER)) /* cant fight when ethereal */
38 return 0;
39
40 if ((item = find_mons(mp->y, mp->x)) == NULL) {
41 mvaddch(mp->y, mp->x, FLOOR);
42 mvwaddch(mw, mp->y, mp->x, ' ');
43 look(FALSE);
44 msg("That monster must have been an illusion.");
45 return 0;
46 }
47 tp = THINGPTR(item);
48 st = &tp->t_stats;
49 /*
50 * Since we are fighting, things are not quiet so
51 * no healing takes place.
52 */
53 quiet = 0;
54 isfight = TRUE;
55 runto(mp, &hero);
56 /*
57 * Let him know it was really a mimic (if it was one).
58 */
59 if(tp->t_type == 'M' && tp->t_disguise != 'M' && pl_off(ISBLIND)) {
60 msg("Wait! That's a mimic!");
61 tp->t_disguise = 'M';
62 did_hit = thrown;
63 }
64 if (did_hit) {
65 reg char *mname;
66
67 did_hit = FALSE;
68 if (pl_on(ISBLIND))
69 mname = "it";
70 else
71 mname = monsters[tp->t_indx].m_name;
72 /*
73 * If the hero can see the invisibles, then
74 * make it easier to hit.
75 */
76 if (pl_on(CANSEE) && on(*tp, ISINVIS) && off(*tp, WASHIT)) {
77 tp->t_flags |= WASHIT;
78 st->s_arm += 3;
79 }
80 if (roll_em(him, st, weap, thrown)) {
81 did_hit = TRUE;
82 if (thrown)
83 thunk(weap, mname);
84 else
85 hit(NULL);
86 if (pl_on(CANHUH)) {
87 msg("Your hands stop glowing red");
88 msg("The %s appears confused.", mname);
89 tp->t_flags |= ISHUH;
90 player.t_flags &= ~CANHUH;
91 /*
92 * If our hero was stuck by a bone devil,
93 * release him now because the devil is
94 * confused.
95 */
96 if (pl_on(ISHELD))
97 unhold(tp->t_type);
98 }
99 if (st->s_hpt <= 0)
100 killed(item, TRUE);
101 else if (monhurt(tp) && off(*tp, ISWOUND)) {
102 if (levtype != MAZELEV && tp->t_room != NULL &&
103 !rf_on(tp->t_room, ISTREAS)) {
104 tp->t_flags |= ISWOUND;
105 msg("You wounded %s.",prname(mname,FALSE));
106 unhold(tp->t_type);
107 }
108 }
109 }
110 else {
111 if (thrown)
112 bounce(weap, mname);
113 else
114 miss(NULL);
115 }
116 }
117 count = 0;
118 return did_hit;
119 }
120
121
122 /*
123 * attack:
124 * The monster attacks the player
125 */
126 attack(mp)
127 struct thing *mp;
128 {
129 reg char *mname;
130
131 if (pl_on(ISETHER)) /* ethereal players cant be hit */
132 return(0);
133 if (mp->t_flags & ISPARA) /* paralyzed monsters */
134 return(0);
135 running = FALSE;
136 quiet = 0;
137 isfight = TRUE;
138 if (mp->t_type == 'M' && pl_off(ISBLIND))
139 mp->t_disguise = 'M';
140 if (pl_on(ISBLIND))
141 mname = "it";
142 else
143 mname = monsters[mp->t_indx].m_name;
144 if (roll_em(&mp->t_stats, him, NULL, FALSE)) {
145 if (pl_on(ISINVINC)) {
146 msg("%s does not harm you.",prname(mname,TRUE));
147 }
148 else {
149 nochange = FALSE;
150 if (mp->t_type != 'E')
151 hit(mname);
152 if (him->s_hpt <= 0)
153 death(mp->t_indx);
154 if (off(*mp, ISCANC))
155 switch (mp->t_type) {
156 case 'R':
157 if (hurt_armor(cur_armor)) {
158 msg("Your armor weakens.");
159 cur_armor->o_ac++;
160 }
161 when 'E':
162 /*
163 * The gaze of the floating eye hypnotizes you
164 */
165 if (pl_off(ISBLIND) && player.t_nocmd <= 0) {
166 player.t_nocmd = rnd(16) + 25;
167 msg("You are transfixed.");
168 }
169 when 'Q':
170 if (!save(VS_POISON) && !iswearing(R_SUSAB)) {
171 if (him->s_ef.a_dex > MINABIL) {
172 chg_abil(DEX, -1, TRUE);
173 msg("You feel less agile.");
174 }
175 }
176 when 'A':
177 if (!save(VS_POISON) && herostr() > MINABIL) {
178 if (!iswearing(R_SUSTSTR) && !iswearing(R_SUSAB)) {
179 if (levcount > 0) {
180 chg_abil(STR, -1, TRUE);
181 msg("A sting has weakened you");
182 }
183 }
184 else
185 msg("Sting has no effect.");
186 }
187 when 'W':
188 if (rnd(100) < 15 && !iswearing(R_SUSAB)) {
189 if (him->s_exp <= 0)
190 death(mp->t_indx);
191 msg("You suddenly feel weaker.");
192 if (--him->s_lvl == 0) {
193 him->s_exp = 0;
194 him->s_lvl = 1;
195 }
196 else
197 him->s_exp = e_levels[him->s_lvl - 1] + 1;
198 chg_hpt(-roll(1,10),TRUE,mp->t_indx);
199 }
200 when 'F':
201 player.t_flags |= ISHELD;
202 sprintf(monsters[midx('F')].m_stats.s_dmg,"%dd1",++fung_hit);
203 when 'L': {
204 long lastpurse;
205 struct linked_list *lep;
206
207 lastpurse = purse;
208 purse -= GOLDCALC;
209 if (!save(VS_MAGIC))
210 purse -= GOLDCALC + GOLDCALC + GOLDCALC + GOLDCALC;
211 if (purse < 0)
212 purse = 0;
213 if (purse != lastpurse)
214 msg("Your purse feels lighter.");
215 lep = find_mons(mp->t_pos.y,mp->t_pos.x);
216 if (lep != NULL)
217 {
218 remove_monster(&mp->t_pos, lep);
219 mp = NULL;
220 }
221 }
222 when 'N': {
223 struct linked_list *steal, *list;
224 struct object *sobj;
225 int stworth = 0, wo;
226
227 /*
228 * Nymph's steal a magic item, look through the pack
229 * and pick out one we like, namely the object worth
230 * the most bucks.
231 */
232 steal = NULL;
233 for (list = pack; list != NULL; list = next(list)) {
234 wo = get_worth(OBJPTR(list));
235 if (wo > stworth) {
236 stworth = wo;
237 steal = list;
238 }
239 }
240 if (steal != NULL) {
241 sobj = OBJPTR(steal);
242 if (o_off(sobj, ISPROT)) {
243 struct linked_list *nym;
244
245 nym = find_mons(mp->t_pos.y, mp->t_pos.x);
246 if (nym != NULL)
247 {
248 remove_monster(&mp->t_pos, nym);
249 mp = NULL;
250 }
251 msg("She stole %s!", inv_name(sobj, TRUE));
252 detach(pack, steal);
253 discard(steal);
254 cur_null(sobj);
255 updpack();
256 }
257 }
258 }
259 when 'c':
260 if (!save(VS_PETRIFICATION)) {
261 msg("Your body begins to solidify.");
262 msg("You are turned to stone !!! --More--");
263 wait_for(cw, ' ');
264 death(mp->t_indx);
265 }
266 when 'd':
267 if (rnd(100) < 50 && !(mp->t_flags & ISHUH))
268 player.t_flags |= ISHELD;
269 if (!save(VS_POISON)) {
270 if (iswearing(R_SUSAB) || iswearing(R_SUSTSTR))
271 msg("Sting has no effect.");
272 else {
273 int fewer, ostr;
274
275 fewer = roll(1,4);
276 ostr = herostr();
277 chg_abil(STR,-fewer,TRUE);
278 if (herostr() < ostr) {
279 fewer = ostr - herostr();
280 fuse(rchg_str, fewer - 1, 10);
281 }
282 msg("You feel weaker now.");
283 }
284 }
285 when 'g':
286 if (!save(VS_BREATH) && !iswearing(R_BREATH)) {
287 msg("You feel singed.");
288 chg_hpt(-roll(1,8),FALSE,mp->t_indx);
289 }
290 when 'h':
291 if (!save(VS_BREATH) && !iswearing(R_BREATH)) {
292 msg("You are seared.");
293 chg_hpt(-roll(1,4),FALSE,mp->t_indx);
294 }
295 when 'p':
296 if (!save(VS_POISON) && herostr() > MINABIL) {
297 if (!iswearing(R_SUSTSTR) && !iswearing(R_SUSAB)) {
298 msg("You are gnawed.");
299 chg_abil(STR,-1,TRUE);
300 }
301 }
302 when 'u':
303 if (!save(VS_POISON) && herostr() > MINABIL) {
304 if (!iswearing(R_SUSTSTR) && !iswearing(R_SUSAB)) {
305 msg("You are bitten.");
306 chg_abil(STR, -1, TRUE);
307 fuse(rchg_str, 1, roll(5,10));
308 }
309 }
310 when 'w':
311 if (!save(VS_POISON) && !iswearing(R_SUSAB)) {
312 msg("You feel devitalized.");
313 chg_hpt(-1,TRUE,mp->t_indx);
314 }
315 when 'i':
316 if (!save(VS_PARALYZATION) && !iswearing(R_SUSAB)) {
317 if (pl_on(ISSLOW))
318 lengthen(notslow,roll(3,10));
319 else {
320 msg("You feel impaired.");
321 player.t_flags |= ISSLOW;
322 fuse(notslow,TRUE,roll(5,10));
323 }
324 }
325 otherwise:
326 break;
327 }
328 }
329 }
330 else if (mp->t_type != 'E') {
331 if (mp->t_type == 'F') {
332 him->s_hpt -= fung_hit;
333 if (him->s_hpt <= 0)
334 death(mp->t_indx);
335 }
336 miss(mname);
337 }
338 flushinp(); /* flush type ahead */
339 count = 0;
340
341 if (mp == NULL)
342 return(-1);
343 else
344 return(0);
345 }
346
347
348 /*
349 * swing:
350 * Returns true if the swing hits
351 */
352 swing(at_lvl, op_arm, wplus)
353 int at_lvl, op_arm, wplus;
354 {
355 reg int res = rnd(20)+1;
356 reg int need = (21 - at_lvl) - op_arm;
357
358 return (res + wplus >= need);
359 }
360
361
362 /*
363 * check_level:
364 * Check to see if the guy has gone up a level.
365 */
366 check_level()
367 {
368 reg int lev, add, dif;
369
370 for (lev = 0; e_levels[lev] != 0; lev++)
371 if (e_levels[lev] > him->s_exp)
372 break;
373 lev += 1;
374 if (lev > him->s_lvl) {
375 dif = lev - him->s_lvl;
376 add = roll(dif, 10) + (dif * getpcon(him));
377 him->s_maxhp += add;
378 if ((him->s_hpt += add) > him->s_maxhp)
379 him->s_hpt = him->s_maxhp;
380 msg("Welcome to level %d", lev);
381 }
382 him->s_lvl = lev;
383 }
384
385
386 /*
387 * roll_em:
388 * Roll several attacks
389 */
390 roll_em(att, def, weap, hurl)
391 struct stats *att, *def;
392 struct object *weap;
393 bool hurl;
394 {
395 reg char *cp;
396 reg int ndice, nsides, def_arm, prop_hplus, prop_dplus;
397 reg bool did_hit = FALSE;
398 char *mindex();
399
400 prop_hplus = prop_dplus = 0;
401 if (weap == NULL) {
402 cp = att->s_dmg;
403 }
404 else if (hurl) {
405 if (o_on(weap,ISMISL) && cur_weapon != NULL &&
406 cur_weapon->o_which == weap->o_launch) {
407 cp = weap->o_hurldmg;
408 prop_hplus = cur_weapon->o_hplus;
409 prop_dplus = cur_weapon->o_dplus;
410 }
411 else
412 cp = (o_on(weap,ISMISL) ? weap->o_damage : weap->o_hurldmg);
413 }
414 else {
415 cp = weap->o_damage;
416 /*
417 * Drain a staff of striking
418 */
419 if (weap->o_type == STICK && weap->o_which == WS_HIT
420 && weap->o_charges == 0) {
421 strcpy(weap->o_damage, "0d0");
422 weap->o_hplus = weap->o_dplus = 0;
423 }
424 }
425 while(1) {
426 int damage;
427 int hplus = prop_hplus + (weap == NULL ? 0 : weap->o_hplus);
428 int dplus = prop_dplus + (weap == NULL ? 0 : weap->o_dplus);
429
430 if (att == him && weap == cur_weapon) {
431 if (isring(LEFT, R_ADDDAM))
432 dplus += cur_ring[LEFT]->o_ac;
433 else if (isring(LEFT, R_ADDHIT))
434 hplus += cur_ring[LEFT]->o_ac;
435 if (isring(RIGHT, R_ADDDAM))
436 dplus += cur_ring[RIGHT]->o_ac;
437 else if (isring(RIGHT, R_ADDHIT))
438 hplus += cur_ring[RIGHT]->o_ac;
439 }
440 ndice = atoi(cp);
441 if ((cp = mindex(cp, 'd')) == NULL)
442 break;
443 nsides = atoi(++cp);
444
445 if (def == him) { /* defender is hero */
446 if (cur_armor != NULL)
447 def_arm = cur_armor->o_ac;
448 else
449 def_arm = def->s_arm;
450 if (isring(LEFT, R_PROTECT))
451 def_arm -= cur_ring[LEFT]->o_ac;
452 if (isring(RIGHT, R_PROTECT))
453 def_arm -= cur_ring[RIGHT]->o_ac;
454 }
455 else /* defender is monster */
456 def_arm = def->s_arm;
457 if (hurl)
458 hplus += getpdex(att,TRUE);
459 if (swing(att->s_lvl, def_arm + getpdex(def, FALSE),
460 hplus + str_plus(att))) {
461 reg int proll;
462
463 proll = roll(ndice, nsides);
464 damage = dplus + proll + add_dam(att);
465 if (pl_off(ISINVINC) || def != him)
466 def->s_hpt -= max(0, damage);
467 did_hit = TRUE;
468 }
469 if ((cp = mindex(cp, '/')) == NULL)
470 break;
471 cp++;
472 }
473 return did_hit;
474 }
475
476
477 /*
478 * mindex:
479 * Look for char 'c' in string pointed to by 'cp'
480 */
481 char *
482 mindex(cp, c)
483 char *cp, c;
484 {
485 reg int i;
486
487 for (i = 0; i < 3; i++)
488 if (*cp != c) cp++;
489 if (*cp == c)
490 return cp;
491 else
492 return NULL;
493 }
494
495
496 /*
497 * prname:
498 * The print name of a combatant
499 */
500 char *
501 prname(who, upper)
502 char *who;
503 bool upper;
504 {
505 static char tbuf[LINLEN];
506
507 *tbuf = '\0';
508 if (who == 0)
509 strcpy(tbuf, "you");
510 else if (pl_on(ISBLIND))
511 strcpy(tbuf, "it");
512 else {
513 strcpy(tbuf, "the ");
514 strcat(tbuf, who);
515 }
516 if (upper)
517 *tbuf = toupper(*tbuf);
518 return tbuf;
519 }
520
521 /*
522 * hit:
523 * Print a message to indicate a succesful hit
524 */
525 hit(er)
526 char *er;
527 {
528 msg("%s hit.",prname(er, TRUE));
529 }
530
531
532 /*
533 * miss:
534 * Print a message to indicate a poor swing
535 */
536 miss(er)
537 char *er;
538 {
539 msg("%s miss%s.",prname(er, TRUE),(er == 0 ? "":"es"));
540 }
541
542
543 /*
544 * save_throw:
545 * See if a creature saves against something
546 */
547 save_throw(which, tp)
548 int which;
549 struct thing *tp;
550 {
551 reg int need;
552 reg struct stats *st;
553
554 st = &tp->t_stats;
555 need = 14 + which - (st->s_lvl / 2) - getpwis(st);
556 return (roll(1, 20) >= need);
557 }
558
559
560 /*
561 * save:
562 * See if he saves against various nasty things
563 */
564 save(which)
565 int which;
566 {
567 return save_throw(which, &player);
568 }
569
570 /*
571 * raise_level:
572 * The guy just magically went up a level.
573 */
574 raise_level()
575 {
576 him->s_exp = e_levels[him->s_lvl-1] + 1L;
577 check_level();
578 }
579
580
581 /*
582 * thunk:
583 * A missile hits a monster
584 */
585 thunk(weap, mname)
586 struct object *weap;
587 char *mname;
588 {
589 if (weap->o_type == WEAPON)
590 msg("The %s hits the %s.",w_magic[weap->o_which].mi_name,mname);
591 else
592 msg("You hit the %s.", mname);
593 }
594
595
596 /*
597 * bounce:
598 * A missile misses a monster
599 */
600 bounce(weap, mname)
601 struct object *weap;
602 char *mname;
603 {
604 if (weap->o_type == WEAPON)
605 msg("The %s misses the %s.", w_magic[weap->o_which].mi_name,mname);
606 else
607 msg("You missed the %s.", mname);
608 }
609
610
611 /*
612 * remove:
613 * Remove a monster from the screen
614 */
615 remove_monster(mp, item)
616 struct coord *mp;
617 struct linked_list *item;
618 {
619 reg char what;
620
621 mvwaddch(mw, mp->y, mp->x, ' ');
622 if (pl_on(ISBLIND))
623 what = ' '; /* if blind, then a blank */
624 else
625 what = (THINGPTR(item))->t_oldch; /* normal char */
626 mvwaddch(cw, mp->y, mp->x, what);
627 detach(mlist, item);
628 discard(item);
629 }
630
631
632 /*
633 * is_magic:
634 * Returns true if an object radiates magic
635 */
636 is_magic(obj)
637 struct object *obj;
638 {
639 switch (obj->o_type) {
640 case ARMOR:
641 return obj->o_ac != armors[obj->o_which].a_class;
642 case WEAPON:
643 return obj->o_hplus != 0 || obj->o_dplus != 0;
644 case POTION:
645 case SCROLL:
646 case STICK:
647 case RING:
648 case AMULET:
649 return TRUE;
650 }
651 return FALSE;
652 }
653
654
655 /*
656 * killed:
657 * Called to put a monster to death
658 */
659 killed(item, pr)
660 struct linked_list *item;
661 bool pr;
662 {
663 reg struct thing *tp;
664 reg struct object *obj;
665 struct linked_list *pitem, *nexti, *itspack;
666 struct coord here;
667
668 nochange = FALSE;
669 tp = THINGPTR(item);
670 here = tp->t_pos;
671 if (pr) {
672 addmsg("Defeated ");
673 if (pl_on(ISBLIND))
674 msg("it.");
675 else
676 msg("%s.", monsters[tp->t_indx].m_name);
677 }
678 him->s_exp += tp->t_stats.s_exp;
679 isfight = FALSE;
680 check_level();
681 unhold(tp->t_type); /* free player if held */
682 if (tp->t_type == 'L') {
683 reg struct room *rp;
684
685 rp = roomin(&here);
686 if (rp != NULL) {
687 if (rp->r_goldval!=0 || fallpos(&here, &rp->r_gold, FALSE)) {
688 rp->r_goldval += GOLDCALC;
689 if (!save_throw(VS_MAGIC,tp))
690 rp->r_goldval += GOLDCALC + GOLDCALC + GOLDCALC
691 + GOLDCALC + GOLDCALC;
692 mvaddch(rp->r_gold.y, rp->r_gold.x, GOLD);
693 if (!rf_on(rp,ISDARK)) {
694 light(&hero);
695 mvwaddch(cw, hero.y, hero.x, PLAYER);
696 }
697 }
698 }
699 }
700 pitem = tp->t_pack;
701 itspack = tp->t_pack;
702 remove_monster(&here, item);
703 while (pitem != NULL) {
704 nexti = next(pitem);
705 obj = OBJPTR(pitem);
706 obj->o_pos = here;
707 detach(itspack, pitem);
708 fall(pitem, FALSE);
709 pitem = nexti;
710 }
711 }