/* * The implementation of scarabs. * * In order to support multiple scarabs of a given type, we implement * carried-scarab effects much the way we do worn-ring effects. This * would be considerably simpler if we could simply have exactly one * scarab of each type and that's it. * * The identified and identify methods here depend on scarabs using * never_collapsible and never_identical, so we don't have to concern * ourselves with splitting collapsed objects. */ #include #include "obj.h" #include "util.h" #include "vars.h" #include "pline.h" #include "effect.h" #include "format.h" #include "structs.h" #include "objtypes.h" typedef struct scarab SCARAB; typedef struct scarabeffect SCARABEFFECT; struct scarab { SCARABEFFECT *eff; int known; } ; struct scarabeffect { MONST *m; EFFECT *eff; OBJ *o; } ; static unsigned int flagbit(int ot) { switch (ot) { case OBJ_SCARAB_OF_EARTH: return(MEF_PLANE_E); break; case OBJ_SCARAB_OF_AIR: return(MEF_PLANE_A); break; case OBJ_SCARAB_OF_FIRE: return(MEF_PLANE_F); break; case OBJ_SCARAB_OF_WATER: return(MEF_PLANE_W); break; } panic("impossible flagbit()"); } /* * Return the SCARAB * for an OBJ * (or, if the OBJ isn't a scarab, * panic). */ static SCARAB *scarab_for_obj(OBJ *o) { if (objtypes[o->type].class != OC_SCARAB) panic("non-scarab where scarab needed"); return(o->private); } /* * Apply the effect for a scarab. */ static void apply_scarab(MONST *m, void *sev) { m->effflags |= flagbit(((SCARABEFFECT *)sev)->o->type); } /* * Tear down the effect for a scarab. */ static void death_scarab(MONST *m __attribute__((__unused__)), void *sev) { free(sev); } static EFFECTOPS effops_scarab = EFFECTOPS_INIT(scarab); /* * The new method for scarabs. */ static OBJ *new_scarab(int type __attribute__((__unused__)), OBJ *o) { SCARAB *s; s = malloc(sizeof(SCARAB)); s->eff = 0; s->known = 0; o->private = s; return(o); } /* * The old method for scarabs. */ static void old_scarab(OBJ *o) { SCARAB *s; s = scarab_for_obj(o); if (s->eff) panic("freeing scarab in effect"); free(s); } /* * The identified method for scarabs. */ static int identified_scarab(INVOBJ *io) { return(scarab_for_obj(io->v[0])->known); } /* * The identify method for scarabs. */ static INVOBJ *identify_scarab(INVOBJ *io) { scarab_for_obj(io->v[0])->known = 1; return(io); } /* * The moved method for scarabs. */ static void moved_scarab(INVOBJ *io, INVENT *from, INVENT *to) { SCARAB *s; SCARABEFFECT *e; s = scarab_for_obj(io->v[0]); if (from && (from->type == IT_MON)) { effect_remove(from->u.m,s->eff->eff); free(s->eff); } if (to && (to->type == IT_MON)) { e = malloc(sizeof(SCARABEFFECT)); e->m = to->u.m; e->o = io->v[0]; e->eff = 0; e->eff = effect_add(to->u.m,e,&effops_scarab); s->eff = e; } } /* * The type-specific format conditionals for scarabs: * * K is this scarab's kind known? */ static int fmt_cond_scarab(char ch, INVOBJ *io) { switch (ch) { case 'K': return(scarab_for_obj(io->v[0])->known); break; } panic("invalid conditional +%c for scarab",ch); } #define format_scarab std_format #define fmt_spec_scarab panic_fmt_spec #define collapsible_scarab never_collapsible #define identical_scarab never_identical #define split_scarab std_split #define cursable_scarab 0 #define setcursed_scarab setcursed_uncursable #define iscursed_scarab iscursed_uncursable #define inuse_scarab inuse_never OBJOPS objops_scarab = OBJOPS_INIT(scarab);