/* * Implementation of wands. */ #include #include #include "obj.h" #include "mon.h" #include "vars.h" #include "dice.h" #include "util.h" #include "pline.h" #include "format.h" #include "display.h" #include "signals.h" #include "structs.h" #include "obj-map.h" #include "scrsyms.h" #include "objtypes.h" #include "mon-@-you.h" #include "digdungeon.h" #include "obj-wand.h" typedef struct wand WAND; /* * Private data for wands. */ struct wand { WAND *flink; WAND *blink; unsigned int flags; #define WF_KNOWN 0x00000001 int charges; int maxcharge; int failpct; const char *expldmg; } ; /* * List of all wands. */ static WAND *allwands = 0; /* * Symbol used by some wand ray functions. */ static char wand_ray_sym; /* * Ray function for wand of striking. */ static int striking_cell(LOC *lc, int n) { MONST *m; if (lc->flags & LF_VISIBLE) { mvaddch(lc->y+dispoy,lc->x+dispox,'*'); move(you->loc->y+dispoy,you->loc->x+dispox); refresh(); } m = lc->monst; if (m) { int dd; int vis; vis = monst_cansee_monst(you,m); if (roll("3d100") < (*m->ops->defend)(m)) { if (vis) pline("The wand %smisses %s!",(dd<-10)?"":"barely ",(*m->ops->name)(m)); } else { if (vis) pline("The wand hits %s!",(*m->ops->name)(m)); if ((*m->ops->takedamage)(m,roll("8d2000")).flags & TDRV_DIED) { if (vis) pline("%s dies!",(*m->ops->Name)(m)); } } return(1); } else if (n > 20) { return(1); } else { if ( (lc->type == LOC_DOOR) && ((lc->walldoor & (LOC_DOOR_CLOSED|LOC_DOOR_OPEN)) == LOC_DOOR_CLOSED) && !rnd(10) ) { if (lc->flags & LF_VISIBLE) pline("The door is blasted apart!"); lc->type = LOC_CAVE; lc->cavetype = LOC_JUSTCAVE; resee(); return(1); } return(!occupiable(lc)); } } /* * Ray function for wand of make invisible. */ static int make_invisible_cell(LOC *lc, int n) { MONST *m; m = lc->monst; if (m) { m->flags |= MF_INVISIBLE; upddisp1(lc); return(1); } else if (n > 20) { return(1); } else { return(!occupiable(lc)); } } /* * Ray function for wand of magic missle. */ static int magic_missle_cell(LOC *lc, int n) { MONST *m; if (lc->flags & LF_VISIBLE) { mvaddch(lc->y+dispoy,lc->x+dispox,wand_ray_sym); move(you->loc->y+dispoy,you->loc->x+dispox); refresh(); } m = lc->monst; if (m) { int vis; vis = monst_cansee_monst(you,m); if (vis) pline("The wand hits %s!",(*m->ops->name)(m)); if ((*m->ops->takedamage)(m,roll("6d4000")).flags & TDRV_DIED) { if (vis) pline("%s dies!",(*m->ops->Name)(m)); } return(1); } else if (n > 20) { return(1); } else { return(!occupiable(lc)); } } /* * Ray function for wand of digging. */ static int digging_cell(LOC *lc, int n) { if (lc->flags & LF_VISIBLE) { mvaddch(lc->y+dispoy,lc->x+dispox,' '); move(you->loc->y+dispoy,you->loc->x+dispox); refresh(); } switch (lc->type) { default: panic("impossible cell type %d",(int)lc->type); break; case LOC_ROCK: case LOC_WALL: case LOC_SDOOR: digcell_(lc->on,lc->x,lc->y); if (map) { int dx; int dy; for (dx=-1;dx<=1;dx++) for (dy=-1;dy<=1;dy++) map_setcharat(map,lc->x+dx,lc->y+dy,SYM_OOS); } resee(); return(1); break; case LOC_CAVE: return(n>LEV_X); break; case LOC_GATE: return(1); break; case LOC_DOOR: if (lc->flags & LF_VISIBLE) pline("The door is blasted apart!"); lc->type = LOC_CAVE; lc->cavetype = LOC_JUSTCAVE; resee(); return(1); } } /* * Return the WAND * for an OBJ *. */ static WAND *wand_for_obj(OBJ *o) { if (objtypes[o->type].class != OC_WAND) panic("non-wand where wand needed"); return(o->private); } /* * The new method for wands. */ static OBJ *new_wand(int type, OBJ *o) { WAND *w; int p1; int p2; int n; n = -1; sscanf(objtypes[type].name5,"%d,%d,%n",&p1,&p2,&n); if (n < 0) panic("impossible wand name5"); w = malloc(sizeof(WAND)); w->flink = allwands; w->blink = 0; if (allwands) allwands->blink = w; allwands = w; w->flags = 0; w->charges = roll(objtypes[type].name4); w->maxcharge = p1; w->failpct = p2; w->expldmg = objtypes[type].name5 + n; o->private = w; return(o); } /* * The old method for wands. */ static void old_wand(OBJ *o) { WAND *w; w = wand_for_obj(o); if (w->flink) w->flink->blink = w->blink; if (w->blink) w->blink->flink = w->flink; else allwands = w->flink; free(o->private); } /* * The fmt_cond method for wands. The only conditional here is K, for * testing whether a wand's number of charges is known. */ static int fmt_cond_wand(char ch, INVOBJ *io) { switch (ch) { case 'K': return(wand_for_obj(io->v[0])->flags&WF_KNOWN); break; } panic("invalid conditional +%c for wand",ch); } /* * The fmt_spec method for wands. The only format here is C, for * generating the wand's charge count. */ static void fmt_spec_wand(FILE *f, char ch, INVOBJ *io) { switch (ch) { case 'C': fprintf(f,"%d",wand_for_obj(io->v[0])->charges); break; default: panic("invalid format %%+%c for wand",ch); break; } } /* * The identified method for wands. */ static int identified_wand(INVOBJ *io) { return( (objtypes[io->v[0]->type].flags & OTF_KNOWN) && (wand_for_obj(io->v[0])->flags & WF_KNOWN) ); } /* * The identify method for wands. */ static INVOBJ *identify_wand(INVOBJ *io) { objtypes[io->v[0]->type].flags |= OTF_KNOWN; wand_for_obj(io->v[0])->flags |= WF_KNOWN; return(io); } /* * The OBJOPS for wands. */ #define format_wand std_format #define collapsible_wand never_collapsible #define identical_wand never_identical #define split_wand std_split #define moved_wand noop_moved OBJOPS objops_wand = OBJOPS_INIT(wand); static void wand_ray(int dx, int dy, int (*cb)(LOC *, int), int ms) { ray(you->loc,dx,dy,cb,ms); resee(); } /* * Zap a wand. It is the caller's responsibility to ensure the * argument INVOBJ is exactly one wand. */ void wand_zap(INVOBJ *io) { OBJ *o; WAND *w; int k; JMP j; int dx; int dy; if (io->n != 1) panic("zapping plural wand"); o = io->v[0]; w = wand_for_obj(o); if (setjmp(j.b)) { pop_sigint_throw(); return; } while (1) { mvprintw(LINES-1,0,"In what direction? "); clrtoeol(); move(you->loc->y+dispoy,you->loc->x+dispox); refresh(); push_sigint_throw(&j); k = getch(); pop_sigint_throw(); if ((k == '\33') || (k == '\7')) return; if (dirkey(k,&dx,&dy,0,0,0)) break; } if (w->charges < 1) { pline("Nothing happens."); return; } // w->charges --; switch (o->type) { // case OBJ_WAND_OF_CANCELLATION: // case OBJ_WAND_OF_DARKNESS: // case OBJ_WAND_OF_DEATH: case OBJ_WAND_OF_DIGGING: wand_ray(dx,dy,&digging_cell,100); break; // case OBJ_WAND_OF_DISINTEGRATION: // case OBJ_WAND_OF_FIRE_BALL: // case OBJ_WAND_OF_FIRE_BOLT: // case OBJ_WAND_OF_ICE_BOLT: // case OBJ_WAND_OF_LIGHT: // case OBJ_WAND_OF_LIGHTNING: case OBJ_WAND_OF_MAGIC_MISSILE: wand_ray_sym = dirsym(dx,dy); wand_ray(dx,dy,&magic_missle_cell,25); break; case OBJ_WAND_OF_MAKE_INVISIBLE: ray(you->loc,dx,dy,&make_invisible_cell,0); break; // case OBJ_WAND_OF_POLYMORPH: case OBJ_WAND_OF_STRIKING: wand_ray(dx,dy,&striking_cell,50); break; // case OBJ_WAND_OF_TELEPORTATION: // case OBJ_WAND_OF_UNDEAD_TURNING: // case OBJ_WAND_OF_WISHING: } } /* * Charge a wand. It is the caller's responsibility to ensure the * argument INVOBJ is exactly one wand. */ int wand_charge(INVOBJ *io) { OBJ *o; WAND *w; int i; int d; if (io->n != 1) panic("charging plural wand"); o = io->v[0]; w = wand_for_obj(o); w->charges ++; for (i=w->charges;i>w->maxcharge;i--) { if (rnd(100) < w->failpct) { d = 0; for (i=w->charges;i>0;i--) d += roll(w->expldmg); w->charges = 0; pline("The overcharged wand explodes for %d damage!",d); (*you->ops->takedamage)(you,d); inv_remove(io->inv,io); invobjfree(io); return(1); } } return(0); } /* * Forget all wands' charge-count-known status. Used by potion of * amnesia. */ void wand_amnesia(void) { WAND *w; for (w=allwands;w;w=w->flink) w->flags &= ~WF_KNOWN; }