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