/* * 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 "objtypes.h" #include "mon-@-you.h" #include "digdungeon.h" #include "obj-wand.h" typedef struct wand WAND; /* * Private data for wands. All we have here are the charge count and a * flag describing whether the player knows the charge count. */ struct wand { unsigned int flags; #define WF_KNOWN 0x00000001 int charges; } ; /* * Ray function for wand of striking. */ static int striking_cell(LOC *lc) { MONST *m; 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 ( (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) { MONST *m; m = lc->monst; if (m) { m->flags |= MF_INVISIBLE; upddisp1(lc); return(1); } else { return(!occupiable(lc)); } } /* * Ray function for wand of magic missle. */ static int magic_missle_cell(LOC *lc) { MONST *m; 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 { return(!occupiable(lc)); } } /* * Ray function for wand of digging. */ static int digging_cell(LOC *lc) { 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); resee(); return(1); break; case LOC_CAVE: return(0); 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; w = malloc(sizeof(WAND)); w->flags = 0; w->charges = roll(objtypes[type].name4); o->private = w; return(o); } /* * The old method for wands. */ static void old_wand(OBJ *o) { 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); /* * 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: ray(you->loc,dx,dy,&digging_cell); 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: ray(you->loc,dx,dy,&magic_missle_cell); break; case OBJ_WAND_OF_MAKE_INVISIBLE: ray(you->loc,dx,dy,&make_invisible_cell); break; // case OBJ_WAND_OF_POLYMORPH: case OBJ_WAND_OF_STRIKING: ray(you->loc,dx,dy,&striking_cell); 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. */ void wand_charge(INVOBJ *io) { OBJ *o; WAND *w; if (io->n != 1) panic("charging plural wand"); o = io->v[0]; w = wand_for_obj(o); w->charges ++; }