nexus/objects.c

16260 lines
553 KiB
C

#include <assert.h>
#include <ctype.h>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "attack.h"
#include "defs.h"
#include "flag.h"
#include "god.h"
#include "io.h"
#include "lf.h"
#include "map.h"
#include "move.h"
#include "nexus.h"
#include "objects.h"
#include "spell.h"
#include "text.h"
extern knowledge_t *knowledge, *lastknowledge;
extern hiddenname_t *firsthiddenname, *lasthiddenname;
extern objecttype_t *objecttype,*lastobjecttype;
extern objectclass_t *objectclass,*lastobjectclass;
extern brand_t *firstbrand,*lastbrand;
extern obmod_t *firstobmod,*lastobmod;
extern material_t *material,*lastmaterial;
extern skill_t *firstskill, *lastskill;
void (*precalclos)(lifeform_t *);
extern object_t *retobs[MAXPILEOBS+1];
extern int retobscount[MAXPILEOBS+1];
extern int nretobs;
extern prompt_t prompt;
extern glyph_t tempglyph;
extern map_t *firstmap;
extern enum GAMEMODE gamemode;
extern long curtime;
extern lifeform_t *player;
extern int reason;
extern int needredraw;
extern int statdirty;
extern int obdb;
char letorder[MAXPILEOBS] = {
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'
};
objecttype_t *lastot = NULL;
enum OBCLASS sortorder[] = {
OC_EFFECT,
OC_TERRAIN,
OC_MONEY,
OC_WEAPON,
OC_MISSILE,
OC_ARMOUR,
OC_POTION,
OC_SCROLL,
OC_WAND,
OC_FOOD,
OC_CORPSE,
OC_RING,
OC_TECH,
OC_TOOLS,
OC_BOOK,
OC_FURNITURE,
OC_GODSTONE,
OC_ROCK,
OC_FLORA,
OC_DFEATURE,
OC_TRAP,
OC_MISC,
// omitting OC_SPELL and OC_JUMP because it shouldn't ever be displayed
OC_NULL
};
char *techadjective[] = {
"crazy",
"mysterious",
"odd",
"strange",
"weird",
"",
};
char *technoun[] = {
"contraption",
"device",
"doodad",
"doohickey",
"gadget",
"thing",
"object",
"",
};
char *bookadjective[] = {
"ancient",
"clean",
"creepy",
"damp",
"dog-eared",
"dusty",
"eerie",
"fancy",
"frosty",
"furry",
"glowing",
"hot",
"humming",
"icy",
"jiggling",
"leatherbound",
"luminous",
"mouldy",
"papyrus",
"plain",
"quivering",
"muddy",
"slimy",
"small",
"soggy",
"thin",
"thick",
"tiny",
"vibrating",
"vine-covered",
"warm",
"worn",
"wrinkled",
"",
};
char *potadjective[] = {
"bubbling",
"effervescent",
"fizzy",
"fuming",
"gluggy",
"luminous", // should produce light
"steaming",
"",
};
typedef struct hiddennamewithcol_s {
char *name;
enum COLOUR col;
} hiddennamewithcol_t;
hiddennamewithcol_t colour[] = {
{ "aqua", C_CYAN, },
{ "azure",C_BOLDBLUE },
{ "black",C_BLUE },
{ "blue",C_BLUE },
{ "brown",C_BROWN },
{ "cyan",C_CYAN },
{ "green",C_GREEN },
{ "indigo",C_MAGENTA },
{ "magenta",C_BOLDMAGENTA },
{ "night-black",C_BLUE },
{ "orange",C_ORANGE },
{ "pink",C_MAGENTA },
{ "rainbow-coloured",C_ORANGE },
{ "red",C_RED },
{ "violet",C_MAGENTA },
{ "yellow",C_YELLOW },
{ "",C_GREY },
};
hiddennamewithcol_t gemtype[] = {
{ "agate", C_MAGENTA, },
{ "amethyst", C_MAGENTA, }, // should be purple
{ "brass",C_BROWN },
{ "bronze",C_BROWN },
{ "copper",C_BROWN },
{ "diamond",C_BOLDCYAN },
{ "emerald",C_GREEN },
{ "flourite",C_GREY },
{ "garnet",C_ORANGE },
{ "gold",C_YELLOW },
{ "iridium",C_WHITE },
{ "jade",C_GREEN },
{ "lapis lazuli",C_BOLDBLUE },
{ "malachite",C_BOLDCYAN },
{ "onyx",C_BLUE },
{ "opal",C_CYAN },
{ "pearl",C_WHITE },
{ "quartz",C_GREY },
{ "ruby",C_RED },
{ "sapphire",C_BLUE },
{ "zinc",C_GREY },
{ "",C_GREY },
};
long nextoid = 0;
brand_t *addbrand(enum BRAND id, char *suffix, enum BODYPART bp) {
brand_t *a, *om;
char buf[BUFLEN];
//flag_t *f;
// does this modj already exist?
om = findbrand(id);
assert(!om);
// add to the end of the list
if (firstbrand == NULL) {
firstbrand = malloc(sizeof(brand_t));
a = firstbrand;
a->prev = NULL;
} else {
// go to end of list
a = lastbrand;
a->next = malloc(sizeof(brand_t));
a->next->prev = a;
a = a->next;
}
lastbrand = a;
a->next = NULL;
// props
a->id = id;
a->bp = bp;
snprintf(buf, BUFLEN, " %s",suffix);
a->suffix = strdup(buf);
a->flags = addflagpile(NULL, NULL);
return a;
}
object_t *addemptyob(obpile_t *where, object_t *o) {
char buf[BUFLEN];
object_t *empty;
// determine what kind of empty container to drop
if (strstr(o->type->name, "vial")) {
strcpy(buf, "empty vial");
} else if (strstr(o->type->name, "potion")) {
strcpy(buf, "empty flask");
} else {
return NULL;
}
empty = addob(where, buf);
if (!empty) {
// try to drop on ground
if (where->owner) {
empty = addob(where->owner->cell->obpile, buf);
if (empty) {
char emptyname[BUFLEN];
getobname(empty, emptyname, 1);
if (isplayer(where->owner)) {
msg("You drop the %s on the ground.", noprefix(emptyname));
} else if (cansee(player, where->owner)) {
getlfname(where->owner, buf);
capitalise(buf);
msg("%s drops the %s on the ground.", buf, noprefix(emptyname));
}
}
}
}
return empty;
}
hiddenname_t *addhiddenname(enum OBCLASS obclass, char *text) {
hiddenname_t *a;
// add to the end of the list
if (firsthiddenname == NULL) {
firsthiddenname = malloc(sizeof(hiddenname_t));
a = firsthiddenname;
a->prev = NULL;
} else {
// go to end of list
a = lasthiddenname;
a->next = malloc(sizeof(hiddenname_t));
a->next->prev = a;
a = a->next;
}
lasthiddenname = a;
a->next = NULL;
// props
a->obclass = obclass;
a->text = strdup(text);
a->used = B_FALSE;
return a;
}
knowledge_t *addknowledge(enum OBCLASS id, char *hiddenname, int known) {
knowledge_t *a;
// add to the end of the list
if (knowledge == NULL) {
knowledge = malloc(sizeof(knowledge_t));
a = knowledge;
a->prev = NULL;
} else {
// go to end of list
a = lastknowledge;
a->next = malloc(sizeof(knowledge_t));
a->next->prev = a;
a = a->next;
}
lastknowledge = a;
a->next = NULL;
// props
a->id = id;
a->hiddenname = strdup(hiddenname);
a->known = known;
return a;
}
material_t *addmaterial(enum MATERIAL id, char *name, float weightrating) {
material_t *a;
// add to the end of the list
if (material == NULL) {
material = malloc(sizeof(material_t));
a = material;
a->prev = NULL;
} else {
// go to end of list
a = lastmaterial;
a->next = malloc(sizeof(material_t));
a->next->prev = a;
a = a->next;
}
lastmaterial = a;
a->next = NULL;
// props
a->id = id;
a->name = strdup(name);
a->weightrating = weightrating;
a->flags = addflagpile(NULL, NULL);
return a;
}
objectclass_t *addoc(enum OBCLASS id, char *name, char *desc, char glyph, int glyphcolour) {
objectclass_t *a;
// add to the end of the list
if (objectclass == NULL) {
objectclass = malloc(sizeof(objectclass_t));
a = objectclass;
a->prev = NULL;
} else {
// go to end of list
a = lastobjectclass;
a->next = malloc(sizeof(objectclass_t));
a->next->prev = a;
a = a->next;
}
lastobjectclass = a;
a->next = NULL;
// props
a->id = id;
a->name = strdup(name);
a->nnouns = 0;
a->desc = strdup(desc);
a->glyph.ch = glyph;
a->glyph.colour = glyphcolour;
a->flags = addflagpile(NULL, NULL);
return a;
}
void addocnoun(objectclass_t *oc, char *text) {
assert (oc->nnouns < MAXOCNOUNS);
oc->noun[oc->nnouns] = strdup(text);
oc->nnouns++;
}
// create a new object, stacking ok
object_t *addob(obpile_t *where, char *name) {
return addobject(where, name, B_TRUE, B_TRUE, OT_NONE);
}
object_t *addobfast(obpile_t *where, enum OBTYPE oid) {
return addobject(where, NULL, B_TRUE, B_TRUE, oid);
}
// create a new object
// if canstack is true, we are allwoed
// to join similar objects together into a single
// object with o->amt set, instead of
// creating new obejct entries.
// NOTE: This function MUST return number of obs created via global "nretobs"
object_t *addobject(obpile_t *where, char *name, int canstack, int wantlinkholes, enum OBTYPE forceoid) {
objecttype_t *ot;
object_t *o = NULL;
char *p,*nsp;
char numstringmin[BUFLEN];
char numstringmax[BUFLEN];
int howmany = 1;
int i;
int db = B_FALSE;
flag_t *f;
char *localname = NULL;
int wantblessed = B_UNCURSED;
race_t *corpserace = NULL;
int dorandombrand = B_FALSE;
brand_t *wantbrand = NULL;
brand_t *br;
obmod_t *om;
obmod_t *wantom[MAXOBMODS];
int bonus = 0;
int nom = 0;
int n;
int bookcontents = -1;
enum DEPTH wantdepth = DP_MAX;
int wantlit = B_FALSE;
int wantrarity = RR_NONE;
int wantgoodness = G_NA;
enum MATERIAL wantdiffmat = MT_NOTHING;
map_t *targetmap = NULL; // for portals
cell_t *targetcell = NULL; // for portals
int donesomething;
object_t *addedob[MAXPILEOBS];
int nadded = 0;
// for doors
enum FLAG doorflag[5];
int ndoorflags = 0;
char *signtext = NULL;
int trapchance = 0;
flag_t *retflag[MAXCANDIDATES];
int nretflags = 0;
// just in case we don't add any
addedob[0] = NULL;
nadded = 0;
nretobs = 0;
if (where->where) {
assert(!where->where->type->solid);
}
if (where->owner && hasflag(where->owner->flags, F_NOPACK)) {
if (db) dblog("error giving ob '%s' - owner isn't allowed to carry objects!", name);
nretobs = 0;
return NULL;
}
if (forceoid != OT_NONE) {
ot = findot(forceoid);
howmany = 1;
if (db) {
dblog("DB: called addobject() for forceoid %s, canstack = %d",ot->name, canstack);
}
} else {
char *bonusstart,*p2;
int bonussign = 1;
localname = strdup(name);
if (db) {
dblog("DB: called addobject() for %s, canstack = %d",localname, canstack);
}
// check for premods. eg. "flaming xxx" "frozen xxx" etc
for (om = firstobmod ; om ; om = om->next) {
if (db) dblog("DB: checking for '%s' in '%s'",om->prefix, localname);
if (strstr(localname, om->prefix)) {
localname = strrep(localname, om->prefix, "", NULL);
if (db) dblog("DB: found obmod prefix '%s'",om->prefix);
wantom[nom] = om;
nom++;
}
}
// parse name string
nsp = numstringmin;
for (p = localname ; isdigit(*p) ; p++) {
*nsp = *p;
nsp++;
}
*nsp = '\0';
// we have a range...
if (*p == '-') {
nsp = numstringmax;
p++;
for ( ; isdigit(*p) ; p++) {
*nsp = *p;
nsp++;
}
*nsp = '\0';
} else {
strcpy(numstringmax,numstringmin);
}
// "p" should now point at the start of the actual
// object name.
// are we giving multiple objects?
if (strlen(numstringmin) > 0) {
int min,max;
// first increment name string pointer
// past any spaces
while (!isalpha(*p)) p++;
// now figure out how many
min = atoi(numstringmin);
max = atoi(numstringmax);
if (min == max) {
howmany = min;
} else {
howmany = rnd(min,max);
}
} else {
howmany = 1;
}
bonus = 0;
// handle for bonuses. eg. "+1"
bonusstart = strchr(p, '+');
if (!bonusstart) {
bonussign = -1;
bonusstart = strchr(p, '-');
}
if (bonusstart) {
char *p3,*bonusend;
char numbuf[BUFLENSMALL];
p3 = numbuf;
bonusend = bonusstart+1; // go past the + or -
while (isdigit(*bonusend)) { // grab the full number
*p3 = *bonusend;
bonusend++;
p3++;
}
*p3 = '\0';
bonus += (atoi(numbuf) * bonussign);
// strip off the "+xxx" / "-xxx", as long as xxx was a number.
// might not be the case if it was part of the object name
// eg. "waist-deep water"
if (bonus) {
while (*bonusend == ' ') bonusend++; // go past spaces
strcpy(bonusstart, bonusend);
}
}
// handle prefixes. strip them off as we go.
donesomething = B_TRUE;
while (donesomething) {
int n;
donesomething = B_FALSE;
// water flags
for (n = DP_MAX; n >= DP_FIRST; n--) {
char wpre[BUFLEN];
snprintf(wpre, BUFLEN, "%s ", getwaterdepthname(n));
if (strstarts(p, wpre)) {
wantdepth = n;
p += strlen(wpre);
p++; // go past space
donesomething = B_TRUE;
break;
}
}
if (donesomething) continue;
if (strstarts(p, "blessed ")) {
if (db) dblog("DB: ob is blessed (%s)",p);
wantblessed = B_BLESSED;
p += strlen("blessed ");
donesomething = B_TRUE;
} else if (strstarts(p, "uncursed ")) {
if (db) dblog("DB: ob is uncursed (%s)",p);
wantblessed = B_UNCURSED;
p += strlen("uncursed ");
donesomething = B_TRUE;
} else if (strstarts(p, "cursed ")) {
if (db) dblog("DB: ob is cursed (%s)",p);
wantblessed = B_CURSED;
p += strlen("cursed ");
donesomething = B_TRUE;
// door flags
} else if (strstarts(p, "locked ")) {
doorflag[ndoorflags++] = F_LOCKED;
p += strlen("locked ");
donesomething = B_TRUE;
} else if (strstarts(p, "jammed ")) {
doorflag[ndoorflags++] = F_JAMMED;
p += strlen("jammed ");
donesomething = B_TRUE;
} else if (strstarts(p, "secret ")) {
doorflag[ndoorflags++] = F_SECRET;
p += strlen("secret ");
donesomething = B_TRUE;
// tool flags
} else if (strstarts(p, "lit ")) {
wantlit = B_TRUE;
p += strlen("lit ");
donesomething = B_TRUE;
// different materials
} else if (strstarts(p, "silver ")) {
wantdiffmat = MT_SILVER;
p += strlen("silver ");
donesomething = B_TRUE;
// rarity
} else if (strstarts(p, "common ")) {
wantrarity = RR_COMMON;
p += strlen("common ");
donesomething = B_TRUE;
} else if (strstarts(p, "uncommon ")) {
wantrarity = RR_UNCOMMON;
p += strlen("uncommon ");
donesomething = B_TRUE;
} else if (strstarts(p, "rare ")) {
wantrarity = RR_RARE;
p += strlen("rare ");
donesomething = B_TRUE;
} else if (strstarts(p, "very rare ")) {
wantrarity = RR_VERYRARE;
p += strlen("very rare ");
donesomething = B_TRUE;
// weapon "goodness"
} else if (strstarts(p, "average ")) {
wantgoodness = G_AVERAGE;
p += strlen("average ");
donesomething = B_TRUE;
} else if (strstarts(p, "good ")) {
wantgoodness = G_GOOD;
if (onein(4)) wantblessed = B_BLESSED;
p += strlen("good ");
donesomething = B_TRUE;
} else if (strstarts(p, "great ")) {
wantgoodness = G_GREAT;
if (onein(3)) wantblessed = B_BLESSED;
if (onein(10)) dorandombrand = B_TRUE;
p += strlen("great ");
donesomething = B_TRUE;
} else if (strstarts(p, "excellent ")) {
wantgoodness = G_EXCELLENT;
if (onein(2)) wantblessed = B_BLESSED;
if (onein(4)) dorandombrand = B_TRUE;
p += strlen("excellent ");
donesomething = B_TRUE;
// brands
} else if (strstarts(p, "branded ")) {
dorandombrand = B_TRUE;
p += strlen("branded ");
donesomething = B_TRUE;
} else if (strstarts(p, "trapped ")) {
trapchance = 100;
p += strlen("trapped ");
donesomething = B_TRUE;
}
}
if (strstr(p, "holy water") || strstr(p, "incompetence")) {
if (db) dblog("DB: ob is blessed (%s)",p);
wantblessed = B_BLESSED;
}
////////////////////////////////////
// handle special object names
////////////////////////////////////
if (strstr(p, "corpse")) {
int len;
char racename[BUFLEN];
p2 = strstr(p, "corpse");
len = p2 - p;
snprintf(racename, len, "%s",p);
corpserace = findracebyname(racename);
ot = findot(OT_CORPSE);
} else if (strstr(p, "statue of ")) {
char racename[BUFLEN];
// go to end
p2 = strstr(p, "statue of ");
p2 += 10; // now on either 'a' or 'an'
p2++; // now on either ' ' or 'n'
for (;*p2 != ' ';p2++);
p2++;
// now at start of name
snprintf(racename, BUFLEN, "%s",p2);
corpserace = findracebyname(racename);
ot = findot(OT_STATUE);
} else if (strstr(p, " head")) {
int len;
char racename[BUFLEN];
p2 = strstr(p, " head");
len = p2 - p + 1;
snprintf(racename, len, "%s",p);
corpserace = findracebyname(racename);
ot = findot(OT_HEAD);
} else if (strstarts(p, "portal to lv")) {
char *pp;
int dlev;
pp = p + strlen("portal to lv");
dlev = atoi(pp);
if (dlev > 0) {
cell_t *c;
c = getobpilelocation(where);
if (c) {
// find map within this region with the given depth
targetmap = findregionmap(c->map->region->id, dlev);
if (!targetmap) {
// create it
targetmap = addmap();
createmap(targetmap, dlev, c->map->region, NULL, D_NONE, NULL);
}
targetcell = getrandomroomcell(targetmap, ANYROOM);
while (!cellwalkable(NULL, targetcell, NULL)) {
targetcell = getrandomadjcell(targetcell, WE_WALKABLE, B_ALLOWEXPAND);
}
} else {
// ie. adding to dummy cell
targetmap = NULL;
targetcell = NULL;
}
} else {
return NULL;
}
ot = findot(OT_PORTAL);
} else if (strstarts(p, "sign ")) {
char *pp;
pp = strchr(p, '\"');
if (pp) {
char sbuf[BUFLEN];
char *sbp;
sbp = sbuf;
pp++;
while (*pp && (*pp != '\"')) {
*sbp = *pp;
sbp++;
pp++;
}
*sbp = '\0';
signtext = strdup(sbuf);
}
ot = findot(OT_SIGN);
} else if (strstr(p, "spellbook of ")) {
char *pp;
pp = p + 13;
if (*pp) {
objecttype_t *spelltype = NULL;
spelltype = findspelln(pp);
if (spelltype) {
bookcontents = spelltype->id;
}
}
ot = findot(OT_SPELLBOOK);
} else if (strstr(p, "manual of ")) {
char *pp;
pp = p + 10;
if (*pp) {
skill_t *sk;
sk = findskillbyname(pp);
if (sk) {
bookcontents = sk->id;
}
}
ot = findot(OT_MANUAL);
////////////////////////////////////
// also handle generic names
////////////////////////////////////
} else {
objectclass_t *oc;
char tempname[BUFLEN];
int found = B_FALSE;
// check for things like "weapon" or "random ring"
for (oc = objectclass; oc ; oc = oc->next) {
int i;
int matched = B_FALSE;
for (i = 0; i < oc->nnouns; i++) {
snprintf(tempname, BUFLEN, "random %s", oc->noun[i]);
if (strstarts(p, tempname) || streq(p, oc->noun[i])) {
matched = B_TRUE;
}
if (matched) {
int minrarity,maxrarity;
// want a specific rarity?
rrtorarity(wantrarity, &minrarity, &maxrarity);
ot = getrandomobofclass(oc->id, minrarity, maxrarity);
if (ot) {
found = B_TRUE;
break;
}
}
}
if (found) break;
}
if (!found) {
// look up the object name
if (db) dblog("DB: Looking for object name '%s'", p );
ot = findotn(p);
if (!ot) {
//if (gamestarted) msg("DB: No match for object name '%s'", p );
if (db) dblog("DB: No match for object name '%s'", p );
nretobs = 0;
return NULL;
}
}
}
if (db) dblog("DB: FOUND: ot->name = '%s'", ot->name );
// check for specific brands. eg. "xxx of pyromania"
// NOTE: this will override any random brands from "branded"
for (br = firstbrand ; br ; br = br->next) {
if (strstr(localname, br->suffix)) {
// does this brand apply to this objecttype?
if (brandappliesto(br, ot)) {
wantbrand = br;
break;
}
}
}
} // end if forceoid given
////////////////////////////////////
// we now have the objecttype!
////////////////////////////////////
if ((gamemode != GM_LOADING) && hasflag(ot->flags, F_ONEPERCELL)) {
if (hasob(where, ot->id)) {
if (db) dblog("DB: trying to add >1 ONEPERCELL object to a cell. (%s) bailing out.", ot->name);
nretobs = 0;
return NULL;
}
}
// override blessed status from flags...
f = hasflag(ot->flags, F_STARTBLESSED);
if (f) {
wantblessed = f->val[0];
}
// don't give nopickup objects to lifeforms
if (hasflag(ot->flags, F_NOPICKUP) && where->owner) {
nretobs = 0;
return NULL;
}
if (ot->obclass->id == OC_SPELL) {
if (db) dblog("DB: Cannot give a spell object! object name '%s'", p );
nretobs = 0;
return NULL;
}
// override canstack if required
if (!hasflag(ot->flags, F_STACKABLE)) {
if (db) dblog("DB: setting canstack = false, objecttype '%s' not stackable", ot->name );
canstack = B_FALSE;
}
// special checks for unique objects
if (hasflag(ot->flags, F_UNIQUE)) {
// does this unique ob already exist?
if (obexists(ot->id)) {
if (db) dblog("DB: Unique ob %s already exists!", p );
nretobs = 0;
return NULL;
}
// otherwise make sure we are only getting one
howmany = 1;
}
// we asked for a different material. is this possible?
if ((wantdiffmat != MT_NOTHING) && !hasflagval(ot->flags, F_CANBEDIFFMAT, wantdiffmat, NA, NA, NULL)) {
wantdiffmat = MT_NOTHING;
}
// chance of being a different material baesd on ob flags
if (wantdiffmat == MT_NOTHING) {
getflags(ot->flags, retflag, &nretflags, F_CANBEDIFFMAT, F_NONE);
for (i = 0; i < nretflags; i++) {
if (pctchance(retflag[i]->val[1])) {
wantdiffmat = retflag[i]->val[0]; break;
}
}
}
if (db) dblog("DB: '%s' -> adding %d x %s",name, howmany, ot->name);
for (i = 0; i < howmany; i++) {
int added = B_FALSE;
if (canstack) {
object_t *existob;
if (db) dblog("DB: Looking for stacks...");
// TODO: if object is stackable
// TODO: if (hasflag(ob,stackable) && hasobject(where, ot)) {
// does the pile already contain one?
existob = canstacknewot(where, ot);
if (existob) {
int n,found = B_FALSE;
if (db) dblog("DB: STACK FOUND (%d x %s). Adding %d obs to existing stack.",existob->amt, existob->type->name, howmany);
existob->amt++;
added = B_TRUE;
o = existob;
// if this isn't already in our list of added obs, add it
for (n = 0; n < nadded; n++) {
if (addedob[n] == o) {
found = B_TRUE;
break;
}
}
if (!found) {
addedob[nadded++] = o;
}
} else {
if (db) dblog("DB: No stacks found.");
}
}
if (!added) {
flag_t *f;
if (db) dblog("DB: Creating new object (%s).",ot->name);
// otherwise add to list
if (where->first == NULL) {
where->first = malloc(sizeof(object_t));
o = where->first;
o->prev = NULL;
} else {
// go to end of list
o = where->last;
o->next = malloc(sizeof(object_t));
o->next->prev = o;
o = o->next;
}
where->last = o;
o->next = NULL;
// fill in props
o->id = nextoid++; // increment next ob id
o->type = ot;
o->pile = where;
o->contents = addobpile(NOOWNER, NOLOC, o);
o->birthtime = curtime;
// inherit props from objecttype
o->material = ot->material;
assert(o->material);
o->weight = ot->weight;
o->flags = addflagpile(NULL, o);
o->inscription = NULL; // non-inherited
// inherit flags from objecttype
copyflags(o->flags, ot->flags, NA);
// don't want certain objecttype only flags...
//killflagsofid(o->flags, F_RARITY);
// random flags...
f = hasflag(o->flags, F_RNDCHARGES);
if (f) {
int amt;
flag_t *chargeflag;
amt = rnd(f->val[0], f->val[1]);
chargeflag = hasflag(o->flags, F_CHARGES);
if (chargeflag) {
chargeflag->val[0] = amt;
chargeflag->val[1] = amt;
chargeflag->known = B_FALSE;
} else {
chargeflag = addflag_real(o->flags, F_CHARGES, amt, amt, NA, NULL, PERMENANT, B_UNKNOWN, -1);
}
}
// charge flag always starts unknown.
f = hasflag(o->flags, F_CHARGES);
if (f) {
f->known = B_FALSE;
}
// non-inherited from here on:
// if adding to a player...
if (where->owner) {
if (o->type->obclass->id == OC_MONEY) {
o->letter = '$';
} else {
o->letter = getnextletter(where, NULL);
}
} else {
// new object on the ground - has no letter yet.
o->letter = '\0';
}
if (canstack) {
// add the full amount!
o->amt = howmany;
} else {
o->amt = 1;
}
if (hasflag(o->flags, F_NOBLESS)) {
setblessed(o, B_UNCURSED);
} else {
setblessed(o, wantblessed);
}
o->blessknown = B_FALSE;
addedob[nadded++] = o;
if (canstack) {
// stop looping through
break;
}
}
}
/*
need to do the below for _all_ objects added!
*/
for (i = 0; i < nadded; i++) {
cell_t *obloc;
o = addedob[i];
obloc = getoblocation(o);
if (wantdiffmat != MT_NOTHING) {
changemat(o, wantdiffmat);
}
// fill in sign text
if (signtext) {
addflag(o->flags, F_SIGNTEXT, NA, NA, NA, signtext);
}
// fill in portal destinations
if (targetmap) {
int tx = NA,ty = NA;
if (targetcell) {
tx = targetcell->x;
ty = targetcell->y;
}
addflag(o->flags, F_MAPLINK, targetmap->id, tx, ty, NULL);
}
// fill in door flags
if (ndoorflags && isdoor(o, NULL)) {
int n;
for (n = 0; n < ndoorflags; n++) {
int val[3];
int ok = B_FALSE;
if (obloc) {
// fill in flag vals
switch (doorflag[n]) {
case F_LOCKED:
val[0] = B_TRUE;
val[1] = getdoorlockdiff(obloc->map->depth);
val[2] = NA;
ok = B_TRUE;
break;
case F_JAMMED:
val[0] = rnd(1,obloc->map->depth+3);
val[1] = NA;
val[2] = NA;
ok = B_TRUE;
break;
case F_SECRET:
val[0] = getdoorsecretdiff(obloc->map->depth);
val[1] = NA;
val[2] = NA;
ok = B_TRUE;
break;
default:
break;
}
if (ok) {
addflag(o->flags, doorflag[n], val[0], val[1], val[2], NULL);
}
}
}
}
// foundtain flags
if (o && (o->type->id == OT_FOUNTAIN)) {
f = hasflag(o->flags, F_LINKOB);
if (where->where && (where->where->habitat->id != H_VILLAGE)) {
objecttype_t *ot;
int min,max;
getrarityrange(where->where->map->depth, &min, &max, RARITYVARIANCEOB, B_FALSE);
// random potion type
ot = getrandomobofclass(OC_POTION, min, max);
if (ot) {
f->val[0] = ot->id;
}
}
}
// tool flags
if (o && hasflag(o->flags, F_LIGHTSOURCE) && wantlit) {
turnon(NULL, o);
}
// fill in book types
if (o && (o->type->obclass->id == OC_BOOK)) {
hiddenname_t *hn,*selhn = NULL;
int numhiddennames;
int n,sel;
if (bookcontents == -1) {
int maxlev;
maxlev = getmapdifficulty(obloc->map) / 3;
limit(&maxlev, 1, 9);
if (o->type->id == OT_SPELLBOOK) {
bookcontents = getrandomspell(maxlev);
while (!schoolappearsinbooks(getspellschool(bookcontents))) {
bookcontents = getrandomspell(maxlev);
}
} else { // ie. manual
bookcontents = getrandomskill();
}
}
// link
if (o->type->id == OT_SPELLBOOK) {
addflag(o->flags, F_LINKSPELL, bookcontents, NA, NA, NULL);
} else {
addflag(o->flags, F_MANUALOF, bookcontents, NA, NA, NULL);
}
// count hidden names
numhiddennames = 0;
for (hn = firsthiddenname ; hn ; hn = hn->next) {
if (hn->obclass == o->type->obclass->id) {
numhiddennames++;
}
}
// assign hidden name
sel = rnd(0,numhiddennames-1);
n = 0;
for (hn = firsthiddenname ; hn ; hn = hn->next) {
if (hn->obclass == o->type->obclass->id) {
if (n == sel) {
selhn = hn;
break;
}
n++;
}
}
addflag(o->flags, F_HASHIDDENNAME, B_TRUE, NA, NA, selhn->text);
}
// create linked holes in adjacent maps
if (wantlinkholes && o && hasflag(o->flags, F_PIT)) {
cell_t *c;
map_t *adjmap = NULL;
f = hasflag(o->flags, F_PIT);
c = getoblocation(o);
adjmap = getmapindir(c->map, f->val[0]);
if ((c->map->region->rtype->id == RG_WORLDMAP) && !adjmap) {
// ie. going down from the surface, and no dungeon below.
// ( MUST be down because holes going up make no sense! )
createregionlink(c->map, c, o, NULL, RG_PIT, c->map->region);
} else {
// create linked holes on the map at the other end of this one.
if (adjmap) {
linkholes(adjmap);
}
}
}
// other special changes we need to make based on what was
// asked for
if ((gamemode != GM_LOADING) && o) {
// corpses - fill in details
if (o->type->id == OT_CORPSE) {
flag_t *rf, *cf;
if (!corpserace) {
// random one.
corpserace = getrandomrace(NULL, NA);
}
o->weight = corpserace->weight;
o->material = corpserace->material;
// remember the race type
addflag(o->flags, F_CORPSEOF, corpserace->id, NA, NA, NULL);
// override ot_corpse nutrition flag based on race's size
rf = hasflag(corpserace->flags, F_SIZE);
if (rf) {
cf = hasflag(o->flags, F_EDIBLE);
if (cf) {
switch (rf->val[0]) {
case SZ_MINI:
cf->val[1] = 1;
break;
case SZ_TINY:
cf->val[1] = 10;
break;
case SZ_SMALL:
cf->val[1] = 25;
break;
case SZ_MEDIUM:
cf->val[1] = 75;
break;
case SZ_HUMAN:
cf->val[1] = 120;
break;
case SZ_LARGE:
cf->val[1] = 150;
break;
case SZ_HUGE:
cf->val[1] = 200;
break;
case SZ_ENORMOUS:
cf->val[1] = 250;
break;
}
}
}
} else if (o->type->id == OT_STATUE) {
flag_t *f, *rf;
float ratio;
if (!corpserace) {
cell_t *where;
where = getoblocation(o);
// select random race
if (where) {
corpserace = getrandomrace(where, NA);
} else {
// ie. vending machine
corpserace = getrandomrace(NULL, NA);
}
}
ratio = o->material->weightrating / corpserace->material->weightrating;
o->weight = corpserace->weight * ratio;
// remember the race type
addflag(o->flags, F_CORPSEOF, corpserace->id, NA, NA, NULL);
// set impassable size
f = hasflag(o->flags, F_IMPASSABLE);
if (f) {
rf = hasflag(corpserace->flags, F_SIZE);
if (rf) {
f->val[0] = SZ_MIN;
f->val[1] = rf->val[0];
} else {
killflag(f);
}
}
// set ob hp
f = hasflag(o->flags, F_OBHP);
if (f) {
rf = hasflag(corpserace->flags, F_HITDICE);
if (rf) {
int maxhp;
maxhp = roll(rf->text);
f->val[0] = maxhp;
f->val[1] = maxhp;
}
}
} else if (o->type->id == OT_HEAD) {
flag_t *rf, *cf;
assert(corpserace);
o->weight = corpserace->weight;
o->material = corpserace->material;
// remember the race type
addflag(o->flags, F_CORPSEOF, corpserace->id, NA, NA, NULL);
// override ot_corpse nutrition flag based on race's size
rf = hasflag(corpserace->flags, F_SIZE);
if (rf) {
cf = hasflag(o->flags, F_EDIBLE);
if (cf) {
switch (rf->val[0]) {
case SZ_MINI:
cf->val[1] = 1;
break;
case SZ_TINY:
cf->val[1] = 2;
break;
case SZ_SMALL:
cf->val[1] = 5;
break;
case SZ_MEDIUM:
cf->val[1] = 25;
break;
case SZ_HUMAN:
cf->val[1] = 50;
break;
case SZ_LARGE:
cf->val[1] = 75;
break;
case SZ_HUGE:
cf->val[1] = 100;
break;
case SZ_ENORMOUS:
cf->val[1] = 150;
break;
}
}
}
} else if (o->type->id == OT_WATERDEEP) {
f = hasflag(o->flags, F_DEEPWATER);
if (f && (f->val[0] != wantdepth)) {
f->val[0] = wantdepth;
}
}
// chance of masterwork based on wantgoodness
switch (wantgoodness) {
case G_GREAT:
if (onein(6)) {
wantom[nom++] = findobmod(OM_MASTERWORK);
}
break;
case G_EXCELLENT:
if (onein(3)) {
wantom[nom++] = findobmod(OM_MASTERWORK);
}
break;
}
for (n = 0; n < nom; n++) {
// add flags from obmod
applyobmod(o, wantom[n]);
// other effects...
switch (wantom[n]->id) {
case OM_FLAMING: // flaming weapons are immune to fire
if (o->type->obclass->id == OC_WEAPON) {
if (!isimmuneto(o->flags, DT_FIRE)) {
addflag(o->flags, F_DTIMMUNE, DT_FIRE, NA, NA, NULL);
}
}
break;
case OM_FROZEN:
if (o->material->id != MT_FIRE) { // fire can't be frozen!
// made of ice
// note: not using changemat() here to avoid adding f_frozen twice.
o->material = findmaterial(MT_ICE);
}
break;
case OM_MASTERWORK:
if (isweapon(o) || isarmour(o)) {
flag_t *f;
f = hasflag(o->flags, F_OBHP);
if (f) {
f->val[0] *= 2;
f->val[1] *= 2;
}
}
if (isweapon(o)) {
flag_t *f;
// always does near high end of damage range
f = hasflag(o->flags, F_DAM);
if (f) {
int ndice,dsides,bonus;
texttodice(f->text, &ndice,&dsides,&bonus);
// half the number of sides on the dice (dsides).
dsides /= 2; if (dsides < 1) dsides = 1;
// increase modifier by (ndice * dsides)
bonus += (ndice * dsides);
if (bonus <= 0) {
bonus = NA;
}
dicetotext(ndice,dsides,bonus,NULL,NULL,f->text, NULL);
}
}
break;
case OM_SHODDY:
if (isweapon(o) || isarmour(o)) {
flag_t *f;
f = hasflag(o->flags, F_OBHP);
if (f) {
f->val[0] /= 2; if (f->val[0] < 1) f->val[0] = 1;
f->val[1] /= 2; if (f->val[1] < 1) f->val[1] = 1;
}
}
if (isweapon(o)) {
flag_t *f;
// half the damage
f = hasflag(o->flags, F_DAM);
if (f) {
int ndice, dsides,bonus;
texttodice(f->text, &ndice, &dsides, &bonus);
// half the number of sides on the dice (dsides).
dsides /= 2;
// half modifier
if (bonus > 0) {
bonus /= 2; if (bonus <= 0) bonus = NA;
}
dicetotext(ndice,dsides,bonus,NULL,NULL,f->text, NULL);
}
}
break;
default:
break;
}
}
// if no bonus yet, get one based on 'wantgoodness'
if (!bonus) {
switch (wantgoodness) {
case G_GOOD: // 1 - 2
bonus = 1;
if (onein(2)) bonus++;
break;
case G_GREAT: // 1 - 3
bonus = 1;
while (onein(2) && (bonus < 3)) {
bonus++;
}
break;
case G_EXCELLENT: // 1 - 4
bonus = 1;
while (onein(2) && (bonus < 4)) {
bonus++;
}
break;
default: // no bonus
break;
}
}
if (bonus && hasflag(o->flags, F_ENCHANTABLE)) {
// for swords, armour etc
addflag_real(o->flags, F_BONUS, bonus, NA, NA, NULL, PERMENANT, B_UNKNOWN, -1);
}
// special rings which get randomized...
if (o->type->id == OT_RING_CON) {
flag_t *f;
f = hasflagval(o->flags, F_EQUIPCONFER, F_ATTRMOD, A_CON, NA, NULL);
if (f) {
if (bonus) f->val[2] = bonus;
else f->val[2] = rnd(1,3);
}
if (o->blessed == B_CURSED) f->val[2] *= -1;
} else if (o->type->id == OT_RING_DEX) {
flag_t *f;
f = hasflagval(o->flags, F_EQUIPCONFER, F_ATTRMOD, A_DEX, NA, NULL);
if (f) {
if (bonus) f->val[2] = bonus;
else f->val[2] = rnd(1,3);
}
if (o->blessed == B_CURSED) f->val[2] *= -1;
} else if (o->type->id == OT_RING_IQ) {
flag_t *f;
f = hasflagval(o->flags, F_EQUIPCONFER, F_ATTRMOD, A_IQ, NA, NULL);
if (f) {
if (bonus) f->val[2] = bonus;
else f->val[2] = rnd(1,3);
}
if (o->blessed == B_CURSED) f->val[2] *= -1;
} else if (o->type->id == OT_RING_STR) {
flag_t *f;
f = hasflagval(o->flags, F_EQUIPCONFER, F_ATTRMOD, A_STR, NA, NULL);
if (f) {
if (bonus) f->val[2] = bonus;
else f->val[2] = rnd(1,3);
}
if (o->blessed == B_CURSED) f->val[2] *= -1;
}
// now apply a random brand if we wanted one
if (!wantbrand && dorandombrand) {
wantbrand = getrandombrandfor(ot);
}
}
// apply the brand
if (wantbrand) {
if (brandappliesto(wantbrand, o->type)) {
copyflags(o->flags, wantbrand->flags, FROMBRAND);
addflag(o->flags, F_HASBRAND, wantbrand->id, NA, NA, NULL);
}
}
if (where->owner) {
// new owner gains "hold confer" flags conferred by this object
giveobflags(where->owner, o, F_HOLDCONFER);
}
// special cases
// ie. don't do these things when just creating objects
// for validation purposes
if (obloc) {
// containers
if (hasflag(o->flags, F_CONTAINER)) {
if (getoblocation(o)) {
givestartobs(NULL, o, o->flags);
}
}
// trapped? l1=10%, l5=20%, l10=30%, l15=40%, l20+=60%
if (!trapchance) {
f = hasflag(o->flags, F_CANBETRAPPED);
if (f) {
trapchance = f->val[0] + (f->val[1] * (obloc->map->depth/5));
limit(&trapchance, f->val[0], f->val[2]);
}
}
if (trapchance) {
if (pctchance(trapchance)) {
enum OBTYPE traptype;
// get a random trap
//
traptype = getrandomtrapforob();
addflag(o->flags, F_TRAPPED, traptype, NA, NA, NULL);
}
}
}
// apply cost to shop items
if (o->pile->where) {
vault_t *v;
v = getcellvault(o->pile->where);
if (v && hasflag(v->flags, F_VAULTISSHOP)) {
if (canpickup(NULL, o, 1)) {
addflag(o->flags, F_SHOPITEM, getobvalue(o), getroomid(o->pile->where), NA, NULL);
}
}
}
if (gamemode == GM_GAMESTARTED) {
if (o && where->where && !hasflag(o->flags, F_NOGLYPH) && haslos(player, where->where) ) {
needredraw = B_TRUE;
}
}
} // end foreach added object
// don't need the name anymore.
if (localname) free(localname);
// populate retobs
for (i = 0; i < nadded; i++) {
if (addedob[i]) {
retobs[i] = addedob[i];
retobscount[i] = addedob[i]->amt;
}
}
nretobs = nadded;
// return the first object given
return addedob[0];
}
// add objects in a circle
// returns # added.
int addobburst(cell_t *where, int range, int dirtype, char *name, lifeform_t *fromlf, enum LOFTYPE needlof) {
int nadded = 0;
cell_t *cell[MAXCANDIDATES];
int ncells,i;
if (!where) return 0;
redrawpause();
getradiuscells(where, range, dirtype, needlof, B_TRUE, cell, &ncells, B_FALSE);
for (i = 0; i < ncells; i++) {
cell_t *c;
c = cell[i];
if (!c->type->solid) {
object_t *o;
o = addob(c->obpile, name);
if (o) {
if (fromlf) setobcreatedby(o, fromlf);
nadded++;
}
}
}
redrawresume();
return nadded;
}
obmod_t *addobmod(enum OBMOD id, char *prefix) {
obmod_t *a, *om;
char buf[BUFLEN];
//flag_t *f;
// does this modj already exist?
om = findobmod(id);
assert(!om);
// add to the end of the list
if (firstobmod == NULL) {
firstobmod = malloc(sizeof(obmod_t));
a = firstobmod;
a->prev = NULL;
} else {
// go to end of list
a = lastobmod;
a->next = malloc(sizeof(obmod_t));
a->next->prev = a;
a = a->next;
}
lastobmod = a;
a->next = NULL;
// props
a->id = id;
snprintf(buf, BUFLEN, "%s ",prefix);
a->prefix = strdup(buf);
a->flags = addflagpile(NULL, NULL);
return a;
}
obpile_t *addobpile(lifeform_t *owner, cell_t *where, object_t *parentob) {
obpile_t *op;
op = malloc(sizeof(obpile_t));
op->first = NULL;
op->last = NULL;
op->owner = owner;
op->where = where;
op->parentob = parentob;
return op;
}
void addobsinradius(cell_t *centre, int radius, int dirtype, char *name, int allowdupes) {
int x,y;
objecttype_t *ot;
ot = findotn(name);
if (!ot) return;
for (y = centre->y - radius ; y <= centre->y + radius; y++) {
for (x = centre->x - radius ; x <= centre->x + radius; x++) {
int valid = B_FALSE;
cell_t *c;
c = getcellat(centre->map, x, y);
if (c && !c->type->solid && haslof(centre, c, LOF_WALLSTOP, NULL)) {
if (allowdupes || !hasob(c->obpile, ot->id)) {
if ((dirtype == DT_COMPASS) && (getcelldist(centre, c) <= radius)) {
valid = B_TRUE;
} else if ((dirtype == DT_ORTH) && (getcelldistorth(centre, c) <= radius)) {
valid = B_TRUE;
}
}
}
if (valid) {
addob(c->obpile, name);
}
}
}
}
objecttype_t *addot(enum OBTYPE id, char *name, char *description, int material, float weight, int obclassid, enum LFSIZE size) {
objecttype_t *a, *ot;
//flag_t *f;
// does this ob already exist?
ot = findot(id);
assert(!ot);
// add to the end of the list
if (objecttype == NULL) {
objecttype = malloc(sizeof(objecttype_t));
a = objecttype;
a->prev = NULL;
} else {
// go to end of list
a = lastobjecttype;
a->next = malloc(sizeof(objecttype_t));
a->next->prev = a;
a = a->next;
}
lastobjecttype = a;
a->next = NULL;
// props
a->id = id;
if (a->id == OT_BERRY) {
int a;
a = 2;
}
a->name = strdup(name);
a->desc = strdup(description);
a->material = findmaterial(material);
a->weight = weight;
a->size = size;
a->obclass = findoc(obclassid);
a->flags = addflagpile(NULL, NULL);
// inherit flags from object class
/*
for (f = a->obclass->flags->first ; f ; f = f->next) {
addflag(a->flags, f->id, f->val[0], f->val[1], f->val[2], f->text);
}
*/
copyflags(a->flags, a->obclass->flags, NA);
if (a->material) {
// inherit flags from material
/*
for (f = a->material->flags->first ; f ; f = f->next) {
addflag(a->flags, f->id, f->val[0], f->val[1], f->val[2], f->text);
}
*/
copyflags(a->flags, a->material->flags, FROMMAT);
}
// for easy addition of flags
lastot = a;
return a;
}
void adjustdamhardness(unsigned int *dam, enum DAMTYPE damtype, enum MATERIAL mat) {
// now check for hardness
if (isphysicaldam(damtype)) {
material_t *m;
m = findmaterial(mat);
if (m) {
flag_t *f;
f = hasflag(m->flags, F_HARDNESS);
if (f && (*dam < f->val[0])) {
*dam = 0;
}
}
}
}
// adjust damage based on material being damaged
void adjustdammaterial(unsigned int *dam, enum DAMTYPE damtype, enum MATERIAL mat) {
// adjust based on material
if (mat == MT_MAGIC) {
switch (damtype) {
case DT_DIRECT:
case DT_NONE:
break;
default:
*dam = 0;
return;
}
} else if (mat == MT_GAS) {
switch (damtype) {
case DT_HOLY:
case DT_DIRECT:
case DT_NONE:
break;
default:
*dam = 0;
return;
}
}
// adjust based on damage type
if (damtype == DT_FIRE) {
switch (mat) {
case MT_WOOD:
case MT_ICE:
case MT_SLIME:
*dam *= 2;
break;
case MT_METAL:
case MT_BONE:
case MT_STONE:
case MT_BLOOD:
case MT_FIRE: // immune to itself
*dam = 0;
break;
default:
break;
}
} else if (damtype == DT_CHOP) {
switch (mat) {
case MT_WOOD:
*dam *= 2;
break;
case MT_SLIME:
*dam /= 2;
break;
default:
break;
}
} else if (damtype == DT_SLASH) {
switch (mat) {
case MT_WOOD:
case MT_SLIME:
case MT_BONE:
*dam /= 2;
break;
default:
break;
}
} else if (damtype == DT_PIERCE) {
switch (mat) {
case MT_WOOD:
case MT_SLIME:
case MT_BONE:
*dam /= 2;
break;
default:
break;
}
} else if (damtype == DT_BASH) {
switch (mat) {
case MT_PAPER:
*dam = 0;
break;
default:
break;
}
} else if (damtype == DT_WATER) {
switch (mat) {
case MT_WATER: // immune to itself
*dam = 0;
break;
default:
break;
}
}
}
void adjustdamob(object_t *o, unsigned int *dam, enum DAMTYPE damtype) {
// objects can't get hurt the turn they
// were created.
if (o->birthtime == curtime) {
*dam = 0;
return;
}
// only some objects can be hurt
if (!hasflag(o->flags, F_DAMAGABLE)) {
if (damtype != DT_DIRECT) {
*dam = 0;
return;
}
}
if (hasflag(o->flags, F_INVULNERABLE)) {
*dam = 0;
return;
}
// immune?
if (isimmuneto(o->flags, damtype)) {
*dam = 0;
return;
}
if (isresistantto(o->flags, damtype)) {
// no resistances etc if rusty...
if (!hasflag(o->flags, F_RUSTED)) {
*dam /= 2;
}
}
if (isvulnto(o->flags, damtype)) {
*dam *= 2;
}
// some damage types never hurts objects
if (damtype == DT_POISONGAS) {
*dam = 0;
return;
}
if (damtype == DT_WATER) {
if (!isvulnto(o->flags, damtype)) {
*dam = 0;
return;
}
}
// adjust damage
if (o->blessed == B_BLESSED) {
// high chance of no hp loss
if (pctchance(90)) {
lifeform_t *owner;
owner = o->pile->owner;
if (owner && isplayer(owner)) {
// become known if owned by player
if (!isblessknown(o)) {
char obname[BUFLEN];
getobname(o, obname, o->amt);
msg("Your %s pulses with holy light as it is struck!",noprefix(obname));
}
o->blessknown = B_TRUE;
}
*dam = 0;
return;
}
} else if (o->blessed == B_CURSED) {
// 50% chance of double damage!
if (onein(2)) {
lifeform_t *owner;
(*dam) *= 2;
owner = o->pile->owner;
if (owner && isplayer(owner)) {
// become known if a player's
if (!isblessknown(o)) {
char obname[BUFLEN];
getobname(o, obname, o->amt);
msg("Your %s emits a wave of dread as it is struck!",noprefix(obname));
}
o->blessknown = B_TRUE;
}
}
}
// adjust damage for material & hardness too
adjustdammaterial(dam, damtype, o->material->id);
adjustdamhardness(dam, damtype, o->material->id);
}
// adjust price for magical effects etc
/*
void adjustprice(objecttype_t *ot, float *price) {
int min,max;
flag_t *f;
// bonuses/penalties
}
*/
// adjusts armour's ac//evasion penalty based on skill
int adjustarmourpenalty(lifeform_t *lf, float amt) {
enum SKILLLEVEL slev;
// no penalties for monsters
if (!isplayer(lf)) {
return 0;
}
slev = getskill(lf, SK_ARMOUR);
amt -= (slev*10);
limitf(&amt, 0, NA);
return amt;
}
// adjusts shield's accuracy penalty based on skill
int adjustshieldpenalty(lifeform_t *lf, float amt) {
enum SKILLLEVEL slev;
// monsters suffer no penalties
if (!isplayer(lf)) {
return 0;
}
slev = getskill(lf, SK_SHIELDS);
switch (slev) {
case PR_INEPT:
amt *= 3;
break;
default:
amt -= (5*slev);
break;
}
limitf(&amt, 0, NA);
return amt;
}
void appendinscription(object_t *o, char *text) {
if (o->inscription) {
int len;
char *buf;
len = strlen(o->inscription) + strlen(text) + 1;
if (len > BUFLEN) len = BUFLEN;
buf = malloc(len * sizeof(char));
snprintf(buf, len, "%s%s",o->inscription, text);
setinscription(o, buf);
free(buf);
} else {
setinscription(o, text);
}
}
void applyobmod(object_t *o, obmod_t *om) {
flag_t *f;
if ((om->id == OM_MASTERWORK) || (om->id == OM_SHODDY)) {
if (hasflag(o->flags, F_NOQUALITY)) {
return;
}
}
if (om->id == OM_FROZEN) {
// frozen things don't decay...
f = hasflagval(o->flags, F_OBHPDRAIN, NA, DT_DECAY, NA, NULL);
if (f) {
killflag(f);
}
// ...but they do melt!
f = addtempflag(o->flags, F_OBHPDRAIN, 1, DT_MELT, NA, NULL, FROMOBMOD);
// it needs HP to melt
if (!hasflag(o->flags, F_OBHP)) {
int myhp;
// give hp
myhp = getobweight(o) * 20;
if (myhp <= 0) myhp = 2;
addtempflag(o->flags, F_OBHP, myhp, myhp, NA, NULL, FROMOBMOD);
}
if (!hasflag(o->flags, F_DAMAGABLE)) {
addtempflag(o->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL, FROMOBMOD);
}
}
copyflags(o->flags, om->flags, FROMOBMOD);
}
int blessob(object_t *o) {
char obname[BUFLEN];
int rv = B_FALSE;
lifeform_t *owner;
if (hasflag(o->flags, F_NOBLESS)) return B_TRUE;
getobname(o, obname, o->amt);
switch (o->blessed) {
case B_BLESSED:
rv = B_TRUE;
break;
case B_CURSED:
case B_UNCURSED:
setblessed(o, B_BLESSED);
break;
}
if (rv == B_FALSE) {
int seen = B_FALSE;
owner = o->pile->owner;
if (owner) {
if (isplayer(owner)) {
msg("Your %s is bathed in a divine glow!", noprefix(obname));
seen = B_TRUE;
} else if (cansee(player, owner)) {
char ownername[BUFLEN];
msg("%s%s %s is bathed in a divine glow!", ownername, getpossessive(ownername),
noprefix(obname));
seen = B_TRUE;
}
} else if (haslos(player, o->pile->where)) {
msg("%s is bathed in a divine glow!", obname);
seen = B_TRUE;
}
if (seen) {
o->blessknown = B_TRUE;
}
}
return rv;
}
void brightflash(cell_t *centre, int range, lifeform_t *immunelf) {
int x,y;
cell_t *c;
animradial(centre, range, '}', C_WHITE);
// announce
if (haslos(player, centre) && !isblind(player)) {
msg("You see an intense flash of light!");
more();
}
/*
if (getcelldist(player->cell, centre) <= range) {
// player is in range but can't see - announce it beacuse it
// will make you deaf!
youhear(centre, "a deafening bang!");
} else { // not in range of the flash
youhear(centre, "a loud bang!");
}
*/
// blind monsters
for (y = centre->y - range; y <= centre->y + range; y++) {
for (x = centre->x - range; x <= centre->x + range; x++) {
c = getcellat(centre->map, x, y);
if (c) {
lifeform_t *lf;
lf = haslf(c);
if (lf && (lf != immunelf)) {
if (haslos(lf, centre) && !isblind(lf)) {
if (!isplayer(lf)) { // we'll blind the player last
if (!eyesshaded(lf)) {
if (lfhasflag(lf, F_SEEINDARK)) {
// blind for 20-30 turns
addtempflag(lf->flags, F_BLIND, B_TRUE, NA, NA, NULL, rnd(20,30));
} else {
// blind for 5-10 turns
addtempflag(lf->flags, F_BLIND, B_TRUE, NA, NA, NULL, rnd(5,10));
}
}
}
} else {
// TODO: deafen
}
}
}
}
}
// handle the player last, so that you see all the
// 'xx is blinded' messages before losing your own
// sight.
if (player != immunelf) {
if (haslos(player, centre) && (getcelldist(player->cell, centre) <= range) && !isblind(player)) {
if (!eyesshaded(player)) {
if (lfhasflag(player, F_SEEINDARK)) {
msg("You eyes feel like they are burning!");
addtempflag(player->flags, F_BLIND, B_TRUE, NA, NA, NULL, rnd(20,30));
} else {
addtempflag(player->flags, F_BLIND, B_TRUE, NA, NA, NULL, rnd(5,10));
}
}
}
}
}
void calcshopprice(object_t *o, flag_t *shopitemflag) {
// initial value
shopitemflag->val[0] = (int) getshopprice(o, o->pile->owner);
}
int canbepoisoned(enum OBTYPE oid) {
flag_t *f;
objecttype_t *ot;
ot = findot(oid);
if (!ot) return B_FALSE;
if (ot->obclass->id != OC_WEAPON) return B_FALSE;
f = hasflag(ot->flags, F_DAM);
if (f) {
switch (f->val[0]) {
case DT_SLASH:
case DT_PIERCE:
return B_TRUE;
default:
break;
}
}
if (hasflagval(ot->flags, F_CANHAVEOBMOD, OM_POISONED, NA, NA, NULL)) {
return B_TRUE;
}
return B_FALSE;
}
int canseeob(lifeform_t *lf, object_t *o) {
flag_t *f;
if (gamemode != GM_GAMESTARTED) {
return B_TRUE;
}
if (hasflag(o->flags, F_SECRET) && isplayer(lf)) {
// can't see
return B_FALSE;
}
if (o->pile->where && hasobwithflag(o->pile, F_BLOCKSVIEW)) {
return B_FALSE;
}
f = hasflag(o->flags, F_TRAIL);
if (f) {
if (f->val[2] == S_SIGHT) {
enum SKILLLEVEL slev;
int cutoffpct;
int cutoff;
slev = getskill(lf, SK_PERCEPTION);
switch (slev) {
case PR_NOVICE: cutoffpct = 80; break;
case PR_BEGINNER: cutoffpct = 65; break;
case PR_ADEPT: cutoffpct = 50; break;
case PR_SKILLED: cutoffpct = 35; break;
case PR_EXPERT: cutoffpct = 20; break;
case PR_MASTER: cutoffpct = 0; break;
default:
case PR_INEPT: cutoffpct = 200; break;
}
cutoff = pctof(cutoffpct, TM_FOOTPRINT);
if (f->lifetime >= cutoff) {
return B_TRUE;
} else {
return B_FALSE;
}
} else {
// ie. SCENT
// special case: if lf is the player's pet, they can always "smell" the player
if (ispetof(lf, player) && strlen(f->text)) {
// scent belongs to the player?
if (atoi(f->text) == player->id) {
return B_TRUE;
}
}
// can't smell your own race...
if ((f->val[0] != lf->race->id) && lfhasflag(lf, F_ENHANCESMELL)) {
return B_TRUE;
} else {
return B_FALSE;
}
}
}
if (isblind(player) && hasflag(o->flags, F_NOFEEL)) {
return B_FALSE;
}
return B_TRUE;
}
// does the pile "op" have an object we can
// stack "match" with
object_t *canstackob(obpile_t *op, object_t *match) {
object_t *o;
flag_t *f;
if (!hasflag(match->flags, F_STACKABLE)) {
return NULL;
}
// can't stack damaged objects
f = hasflag(match->flags, F_OBHP);
if (f) {
if (f->val[0] != f->val[1]) return NULL;
}
for (o = op->first ; o ; o = o->next) {
if (o != match) {
if (obpropsmatch(o, match)) return o;
}
}
return NULL;
}
// does the pile "op" have an object we can
// stack a new object of type "ot" with
object_t *canstacknewot(obpile_t *op, objecttype_t *match) {
object_t *o;
if (!hasflag(match->flags, F_STACKABLE)) {
return NULL;
}
for (o = op->first ; o ; o = o->next) {
if (o->type == match) {
if (isplainob(o)) return o;
}
}
return NULL;
}
int changemat(object_t *o, enum MATERIAL mat) {
material_t *m;
flag_t *f, *nextf;
m = findmaterial(mat);
if (!m) {
return E_FAILED;
}
if (o->material->id == mat) return E_NOEFFECT;
// won't work on pyromania objects
f = hasflag(o->flags, F_FLAMESTRIKE);
if (f) {
if (isplayer(o->pile->owner)) {
f->known = B_TRUE;
} else if (o->pile->owner && cansee(player, o->pile->owner)) {
f->known = B_TRUE;
} else if (haslos(player, o->pile->where)) {
f->known = B_TRUE;
}
return E_NOEFFECT;
}
// remove flags which came from old material
for (f = o->flags->first ; f; f = nextf) {
nextf = f->next;
if (f->lifetime == FROMMAT) {
killflag(f);
}
}
// change material
o->material = m;
// inherit flags from new material
copyflags(m->flags, o->flags, FROMMAT);
if (mat == MT_ICE) {
obmod_t *om;
// if it turned to ice..
// it stops burning
extinguish(o);
// it will melt...
// note that it is frozen
om = findobmod(OM_FROZEN);
applyobmod(o, om);
}
return B_FALSE;
}
int checkobnames(char *haystack, char *needle) {
char *pluralname;
int db = B_FALSE;
// search for exact match
if (!strcmp(haystack, needle)) {
// found it!
if (db) dblog("checkobnames(): got exact match: '%s'",haystack);
return B_TRUE;
}
// search for words ending in "s" (eg. "swords")
pluralname = strdup(needle);
//if (db) dblog("findotn(): plural is '%s'",pluralname);
if (pluralname[strlen(pluralname)-1] == 's') {
// remove trailing 's'
pluralname[strlen(pluralname)-1] = '\0';
// search again (for exact matches)
if (!strcmp(haystack, pluralname)) {
if (db) dblog("checkobnames(): got match after stripping 's': '%s' -> '%s'",pluralname, needle);
free(pluralname);
return B_TRUE;
}
// search for words ending in "es" (eg. tomatoes)
if ((pluralname[strlen(pluralname)-1] == 'e') &&
(pluralname[strlen(pluralname)-2] == 'o')
) {
// remove trailing 'es'
pluralname[strlen(pluralname)-1] = '\0';
pluralname[strlen(pluralname)-2] = '\0';
//if (db) dblog("findotn(): pluralname without 'es' is '%s'",pluralname);
// search again
if (!strcmp(haystack, pluralname)) {
if (db) dblog("checkobnames(): got match after stripping 'es': '%s' -> '%s'",pluralname, needle);
free(pluralname);
return B_TRUE;
}
}
}
free(pluralname);
return B_FALSE;
}
void colourmatchob(object_t *o, lifeform_t *lf) {
flag_t *f;
glyph_t *lfglyph;
lfglyph = getlfglyph(lf);
f = hasflag(o->flags, F_GLYPH);
if (f) {
f->val[0] = lfglyph->colour;
} else {
glyph_t *obglyph;
char buf[2];
obglyph = getglyph(o);
buf[0] = obglyph->ch;
buf[1] = '\0';
addflag(o->flags, F_GLYPH, lfglyph->colour, NA, NA, buf);
}
}
void copyobprops(object_t *dst, object_t *src) {
dst->material = src->material;
dst->weight = src->weight;
if (src->inscription) {
dst->inscription = strdup(src->inscription);
}
setblessed(dst, src->blessed);
dst->blessknown = src->blessknown;
// copy flags
while (dst->flags->first) {
killflag(dst->flags->first);
}
copyflags(dst->flags, src->flags, NA);
}
int countnames(char **list) {
int count;
for (count = 0; list[count]; count++);
return count;
}
int countobs(obpile_t *op, int onlyifknown) {
object_t *o;
int count = 0;
for (o = op->first ; o ; o = o->next) {
if (onlyifknown) {
if (canseeob(player, o)) {
count++;
}
} else {
count++;
}
}
return count;
}
int countobsoftype(obpile_t *op, enum OBTYPE oid) {
object_t *o;
int count = 0;
for (o = op->first ; o ; o = o->next) {
if (o->id == oid) {
count++;
}
}
return count;
}
int countnoncosmeticobs(obpile_t *op, int onlyifknown) {
object_t *o;
int count = 0;
for (o = op->first ; o ; o = o->next) {
if (!hasflag(o->flags, F_COSMETIC) && !hasflag(o->flags, F_SECRET)) {
if (onlyifknown) {
if (canseeob(player, o)) {
count++;
}
} else {
count++;
}
}
}
return count;
}
int curseob(object_t *o) {
int rv = B_FALSE;
lifeform_t *lf;
lf = o->pile->owner;
// announce
if (gamemode == GM_GAMESTARTED) {
if (lf) {
if (cansee(player, lf)) {
char lfname[BUFLEN];
char obname[BUFLEN];
getlfname(lf, lfname);
getobname(o, obname,o->amt);
msg("A black aura surrounds %s%s %s.",lfname,getpossessive(lfname),noprefix(obname));
}
} else { // not held
cell_t *loc = NULL;
loc = getoblocation(o);
if (haslos(player, loc)) {
char obname[BUFLEN];
getobname(o, obname,o->amt);
msg("A black aura surrounds %s.",obname);
}
}
}
switch (o->blessed) {
case B_BLESSED: // uncurse it
setblessed(o, B_UNCURSED);
break;
case B_CURSED: // nothing happens
rv = B_TRUE;
break;
case B_UNCURSED: // curse it
setblessed(o, B_CURSED);
break;
}
return rv;
}
void damageallobs(object_t *srcob, obpile_t *op, int howmuch, int damtype) {
object_t *o, *nexto;
for (o = op->first ; o ; o = nexto) {
nexto = o->next;
// special case to stop steam from hurting water
if (srcob && (srcob->material->id == MT_GAS)) {
continue;
}
if ((o != srcob) && !hasflag(o->flags, F_DEAD)) {
takedamage(o, howmuch, damtype);
}
}
}
int doobtraps(object_t *o, lifeform_t *lf) {
flag_t *f;
f = hasflag(o->flags, F_TRAPPED);
if (f) {
enum OBTYPE trapid;
// announce...
if (isplayer(lf)) {
msg("^wA trap goes off!"); more();
}
trapid = f->val[0];
trapeffects(NULL, trapid, lf->cell);
killflag(f); // now the trap gets removed
// explosion traps kill the object
if (trapid == OT_TRAPMINE) {
killob(o);
}
return B_TRUE;
}
return B_FALSE;
}
void dumpobrarity(void) {
enum RARITY rr;
objecttype_t *ot;
flag_t *f;
int min,max;
for (rr = RR_COMMON; rr <= RR_VERYRARE; rr++) {
rrtorarity(rr, &min, &max);
dblog("Obs with rarity %s:", getrarityname(rr));
for (ot = objecttype ; ot ; ot = ot->next) {
if (ot->obclass->id == OC_ARMOUR) {
int thisrar;
f = hasflag(ot->flags, F_RARITY);
if (!f) continue;
thisrar = f->val[1];
if ((thisrar >= min) && (thisrar <= max)) {
dblog("\t%s", ot->name);
}
}
}
}
}
void explodeob(object_t *o, flag_t *f, int bigness) {
cell_t *c;
int dam;
char obname[BUFLEN];
dam = roll(f->text);
c = getoblocation(o);
getobname(o, obname, o->amt);
// announce
if (o->pile->owner) {
if (isplayer(o->pile->owner)) {
msg("Your %s explode%s!", noprefix(obname), (o->amt == 1) ? "s" : "");
} else if (cansee(player, o->pile->owner)) {
char lfname[BUFLEN];
getlfname(o->pile->owner, lfname);
msg("%s%s %s explode%s!", lfname, getpossessive(lfname), noprefix(obname), (o->amt == 1) ? "s" : "");
}
} else if (haslos(player, c)) {
msg("%s explode%s!", obname, (o->amt == 1) ? "s" : "");
}
explodecells(c, dam * o->amt, bigness ? B_TRUE : B_FALSE, o, bigness ? 1 : 0, DT_COMPASS, B_FALSE);
// hurt everything!
/*
if (bigness) {
int dir;
cell_t *cc;
explodecell(c, dam, (bigness) ? B_TRUE : B_FALSE, NULL);
for (dir = DC_N; dir <= DC_NW; dir++) {
cc = getcellindir(c, dir);
}
} else {
explodecell(c, dam, (bigness) ? B_TRUE : B_FALSE, NULL);
}
*/
// object dies.
removeob(o, o->amt);
}
void extinguish(object_t *o) {
flag_t *f;
char obname[BUFLEN];
f = hasflag(o->flags, F_ONFIRE);
getobname(o, obname, o->amt);
if (f) {
if (o->pile->owner) {
if (isplayer(o->pile->owner)) {
msg("Your %s %s extinguished.", noprefix(obname),
(o->amt == 1) ? "is" : "are");
} else if (cansee(player, o->pile->owner)) {
char lfname[BUFLEN];
getlfname(o->pile->owner, lfname);
msg("%s%s %s %s extinguished.", lfname, getpossessive(lfname), noprefix(obname),
(o->amt == 1) ? "is" : "are");
}
} else if (o->pile->where && haslos(player, o->pile->where)) {
getobname(o, obname, o->amt);
msg("%s %s extinguished.", obname,
(o->amt == 1) ? "is" : "are");
}
killflag(f);
}
}
material_t *findmaterial(int id) {
material_t *m;
for (m = material ; m ; m = m->next) {
if (m->id == id) return m;
}
return NULL;
}
objectclass_t *findoc(int id) {
objectclass_t *oc;
for (oc = objectclass ; oc ; oc = oc->next) {
if (oc->id == id) return oc;
}
return NULL;
}
object_t *findobbyid(obpile_t *op, long oid) {
object_t *o;
for (o = op->first; o ; o = o->next) {
if (o->id == oid) return o;
}
return NULL;
}
object_t *findobl(obpile_t *op, char let) {
object_t *o;
for (o = op->first; o ; o = o->next) {
if (o->letter == let) return o;
}
return NULL;
}
brand_t *findbrand(enum BRAND id) {
brand_t *om;
for (om = firstbrand ; om ; om = om->next) {
if (om->id == id) return om;
}
return NULL;
}
obmod_t *findobmod(enum OBMOD id) {
obmod_t *om;
for (om = firstobmod ; om ; om = om->next) {
if (om->id == id) return om;
}
return NULL;
}
objecttype_t *findot(enum OBTYPE id) {
objecttype_t *ot;
for (ot = objecttype ; ot ; ot = ot->next) {
if (ot->id == id) return ot;
}
return NULL;
}
objecttype_t *findotn(char *name) {
objecttype_t *ot;
knowledge_t *k;
char *modname;
char *p;
int db = B_FALSE;
brand_t *om;
if (!strlen(name)) {
return NULL;
}
modname = strdup(name);
// make some replacements
//replace scrolls with scroll etc
modname = strrep(modname, "bags ", "bag ", NULL);
modname = strrep(modname, "berries ", "berry ", NULL);
modname = strrep(modname, "blocks ", "block ", NULL);
modname = strrep(modname, "cans ", "can ", NULL);
modname = strrep(modname, "chunks ", "chunk ", NULL);
modname = strrep(modname, "cloves ", "clove ", NULL);
modname = strrep(modname, "flasks ", "flask ", NULL);
modname = strrep(modname, "gems ", "gem ", NULL);
modname = strrep(modname, "leaves ", "leaf ", NULL);
modname = strrep(modname, "loaves ", "load ", NULL);
modname = strrep(modname, "lumps ", "lump ", NULL);
modname = strrep(modname, "pieces ", "piece ", NULL);
modname = strrep(modname, "piles ", "pile ", NULL);
modname = strrep(modname, "pools ", "pool ", NULL);
modname = strrep(modname, "potions ", "potion ", NULL);
modname = strrep(modname, "puddles ", "puddle ", NULL);
modname = strrep(modname, "rings ", "ring ", NULL);
modname = strrep(modname, "scrolls ", "scroll ", NULL);
modname = strrep(modname, "sets ", "set ", NULL);
modname = strrep(modname, "splashes ", "splash ", NULL);
modname = strrep(modname, "sprigs ", "sprig ", NULL);
modname = strrep(modname, "suits ", "suit ", NULL);
modname = strrep(modname, "vials ", "vial ", NULL);
// only at start...
if (strstr(modname, "the ") == modname) modname = strrep(modname, "the ", "", NULL);
if (strstr(modname, "an ") == modname) modname = strrep(modname, "an ", "", NULL);
if (strstr(modname, "a ") == modname) modname = strrep(modname, "a ", "", NULL);
modname = strrep(modname, "blessed ", "", NULL);
modname = strrep(modname, "uncursed ", "", NULL);
modname = strrep(modname, "cursed ", "", NULL);
//realloc(modname, strlen(temp)); strcpy(modname, temp); free(temp); // swap
// strip out pre mods
modname = strrep(modname, "flaming ", "", NULL);
modname = strrep(modname, "headless ", "", NULL);
// strip out brands (but not only for certain object classes)
for (om = firstbrand; om ; om = om->next) {
modname = strrep(modname, om->suffix, "", NULL);
}
// special cases
modname = strrep(modname, "holy water", "water", NULL);
modname = strrep(modname, "incompetence", "competence", NULL);
// skip past bonusses
p = strchr(modname, '+');
if (p) {
while (!isalpha(*p)) {
p++;
}
strcpy(modname, p);
}
p = strchr(modname, '-');
if (p) {
while (!isalpha(*p)) {
p++;
}
strcpy(modname, p);
}
if (db) dblog("findotn(): modname is '%s'",modname);
// check for exact matches on real name (and plural versions) first
for (ot = objecttype ; ot ; ot = ot->next) {
if ((ot->obclass->id != OC_SPELL) && (ot->obclass->id != OC_ABILITY)) {
if (checkobnames(ot->name, modname)) {
free(modname);
return ot;
}
}
}
// then matches on hidden name
for (k = knowledge; k ; k = k->next) {
if (checkobnames(k->hiddenname, modname)) {
free(modname);
// found it!
return findot(k->id);
}
}
// then partial matches on real name
for (ot = objecttype ; ot ; ot = ot->next) {
if ((ot->obclass->id != OC_SPELL) && (ot->obclass->id != OC_ABILITY)) {
if (strstr(ot->name, modname)) {
free(modname);
// found it!
return ot;
}
}
}
free(modname);
return NULL;
}
// ie. "the apple is xxx"
// ie. "the apples are xxx"
char *getfillingname(int nutrition) {
if (nutrition > 100) {
return "extremely substantial";
} else if (nutrition >= 90) {
return "very filling";
} else if (nutrition >= 70) {
return "ample for a meal";
} else if (nutrition >= 50) {
return "enough for a light meal";
} else if (nutrition >= 25) {
return "snack-sized";
} else if (nutrition > 0) {
return "barely worth eating";
}
// ie. < 0
return "of zero nutritional substance";
}
int getfirearmrange(object_t *o) {
flag_t *f;
f = hasflag(o->flags, F_RANGE);
if (f) {
return f->val[0];
}
return 0;
}
int getfirearmspeed(object_t *o) {
int firespeed;
flag_t *f;
f = hasflag(o->flags, F_FIRESPEED);
if (f) {
firespeed = f->val[0];
} else {
// default to very slow
firespeed = 1;
}
return firespeed;
}
glyph_t *getglyph(object_t *o) {
flag_t *f;
int isopen;
char g = ' '; // default
int col = C_GREY;
cell_t *obloc;
obloc = getoblocation(o);
if (isdoor(o, &isopen)) {
if (issecretdoor(o)) {
return &(findcelltype(obloc->map->habitat->solidcelltype)->glyph);
} else {
if (isopen) {
g = '-';
} else {
g = '+';
}
col = getmaterialcolour(o->material->id);
}
} else {
f = hasflag(o->flags, F_GLYPH);
if (f) {
g = f->text[0];
if (f->val[0] != NA) {
col = f->val[0];
}
} else {
g = o->type->obclass->glyph.ch;
//col = o->type->obclass->glyph.colour;
col = getmaterialcolour(o->material->id);
}
}
// special case
if (o->type->id == OT_WATERDEEP) {
cell_t *loc;
// override colour
if (getobdepth(o, player) >= DP_HEAD) {
col = C_BOLDBLUE;
} else {
col = C_BLUE;
}
loc = getoblocation(o);
if (getcellwaterdepth(loc, player) >= DP_WAIST) {
g = '{';
} else {
g = '~';
}
}
tempglyph.ch = g;
tempglyph.colour = col;
return &tempglyph;
}
void fragments(cell_t *centre, char *what, int speed, int howfar) {
cell_t *c,*dst;
int n;
int dir;
for (dir = DC_N; dir <= DC_NW; dir++) {
int wantdist = 0;
int maxdist = 0;
int done = B_FALSE;
// get max distance
c = centre;
done = B_FALSE;
while (!done) {
c = getcellindir(c, dir);
if (c && cellwalkable(NULL, c, NULL)) {
maxdist++;
} else {
done = B_TRUE;
}
}
// pick random distance
if (maxdist == 0) {
wantdist = 0;
} else {
int realmax;
if (howfar > maxdist) {
realmax = (maxdist-1);
} else {
realmax = howfar-1;
}
if (realmax < 1) {
wantdist = 0;
} else {
wantdist = rnd(1,realmax);
}
}
// go that far
dst = centre;
for (n = 0; n < wantdist; n++) {
cell_t *newdst;
newdst = getcellindir(dst, dir);
if (newdst) {
dst = newdst;
} else {
break;
}
}
// add object
addob(dst->obpile, what);
}
}
void genhiddennames(void) {
objecttype_t *ot;
flag_t *f;
for (ot = objecttype ; ot ; ot = ot->next) {
f = hasflag(ot->flags, F_HASHIDDENNAME);
if (f) {
char *thisname;
if (strlen(f->text)) {
thisname = strdup(f->text);
} else {
thisname = genhiddenname(ot->obclass->id);
}
sethiddenname(ot, thisname);
free(thisname);
}
}
}
// get the first hidden name for this objectclass
char *genhiddenname(enum OBCLASS id) {
hiddenname_t *hn;
for (hn = firsthiddenname ; hn ; hn = hn->next) {
if (hn->obclass == id) {
if (!hn->used) {
// found one
hn->used = B_TRUE;
return hn->text;
}
}
}
assert("out of hidden names" == 0);
return NULL;
}
// returns largest posisble container with free space
object_t *getbestcontainer(obpile_t *op) {
object_t *o,*poss[MAXPILEOBS],*poss2[MAXPILEOBS];
int nposs = 0,nposs2 = 0,i;
enum LFSIZE bestsize = SZ_MIN;
// find best container size
for (o = op->first ; o ; o = o->next) {
if (hasflag(o->flags, F_CONTAINER)) {
enum LFSIZE thissize;
poss[nposs] = o;
nposs++;
thissize = getobsize(o);
if (thissize > bestsize) bestsize = thissize;
}
}
if (!nposs) {
return NULL;
}
// now find all containers of this size
for (i = 0; i < nposs; i++) {
int valid = B_TRUE;
if (getobsize(poss[i]) != bestsize) {
valid = B_FALSE;
}
if (countobs(poss[i]->contents, B_FALSE) >= MAXPILEOBS) {
// no space
valid = B_FALSE;
}
if (valid) {
poss2[nposs2++] = poss[i];
}
}
if (!nposs2) {
return NULL;
}
return poss2[rnd(0,nposs2-1)];
}
// returns -1 if object doesn't have the flag
int getchargeinfo(object_t *o, int *cur, int *max) {
flag_t *f;
int amt = -1;
f = hasflag(o->flags, F_CHARGES);
if (f) {
amt = f->val[0];
if (cur) *cur = amt;
if (max) *max = f->val[1];
}
return amt;
}
// returns -1 if object doesn't have the flag
int getcharges(object_t *o) {
flag_t *f;
int amt = -1;
f = hasflag(o->flags, F_CHARGES);
if (f) {
amt = f->val[0];
}
return amt;
}
int getobaccuracy(object_t *wep, lifeform_t *weilder) {
int acc;
flag_t *f;
acc = 100; // default accuracy of 100%
if (wep) {
// override with weapon's (lack of) accuracy
f = hasflag(wep->flags, F_ACCURACY);
if (f) {
// ie. accuracy of 100% means no penalty
// ie. accuracy of 75% means 25% penalty
// etc
acc = f->val[0];
}
// blessed weapons have better base accuracy
if (wep->blessed == B_BLESSED) acc += 50;
acc += (getobbonus(wep)*5);
if (weilder) {
skill_t *sk;
// modify for weilder's skill
sk = getobskill(wep);
if (sk) {
enum SKILLLEVEL slev;
slev = getskill(weilder, sk->id);
if (hasflag(wep->flags, F_MASTERWORK)) {
if (slev < PR_ADEPT) slev++;
}
switch (slev) {
case PR_INEPT:
acc -= 30;
break;
case PR_NOVICE:
acc -= 10;
break;
case PR_BEGINNER:
acc -= 5;
break;
case PR_ADEPT:
break;
case PR_SKILLED:
acc += 25;
break;
case PR_EXPERT:
case PR_MASTER:
acc += 50;
break;
}
}
}
// modify for attacker's level
if (wep->pile->owner) {
acc += (wep->pile->owner->level * 2);
}
}
return acc;
}
int getobbonus(object_t *o) {
int bonus = 0,i;
flag_t *retflag[MAXCANDIDATES];
int nretflags = 0;
getflags(o->flags, retflag, &nretflags, F_BONUS, F_NONE);
for (i = 0; i < nretflags; i++) {
bonus += retflag[i]->val[0];
}
return bonus;
}
int getobpoints(object_t *o) {
if (hasflag(o->flags, F_NOPOINTS)) {
return 0;
}
return getobvalue(o);
}
// returns the skill associated with this object
skill_t *getobskill(object_t *o) {
flag_t *f;
f = hasflag(o->flags, F_USESSKILL);
if (f) {
return findskill(f->val[0]);
}
return NULL;
}
enum LFSIZE getobsize(object_t *o) {
flag_t *f;
f = hasflag(o->flags, F_CORPSEOF);
if (f) {
race_t *r;
flag_t *ff;
r = findrace(f->val[0]);
ff = hasflag(r->flags, F_SIZE);
if (ff) {
return ff->val[0];
} else {
return SZ_MEDIUM;
}
}
return o->type->size;
}
int getobspellpower(object_t *o, lifeform_t *lf) {
flag_t *f;
int power = 1;
f = hasflag(o->flags, F_LINKSPELL);
if (f) {
power = f->val[1];
if (power == NA) power = 1;
if (lf) {
// increase based on your magic item usage skill
enum SKILLLEVEL slev;
slev = getskill(lf, SK_CHANNELING);
power += slev;
if (slev >= PR_ADEPT) power += (slev - 2);
}
// blessed objects are more powerful
if (isblessed(o)) power += 4;
// enforce limits
}
limit(&power, 1, 10);
return power;
}
// returns value of obejcts, in gold
int getobvalue(object_t *o) {
float price;
flag_t *f;
int rarity = 0,i;
enum RARITY rr = RR_COMMON;
flag_t *retflag[MAXCANDIDATES];
int nretflags = 0;
if (o->type->id == OT_GOLD) {
return o->amt;
}
// base value: weight * material value
price = (float)getobweight(o) * (float)getmaterialvalue(o->material->id);
//adjustprice(o->type, &price);
// fixed prices
f = hasflag(o->flags, F_VALUE);
if (f) {
price += f->val[0];
}
getflags(o->flags, retflag, &nretflags, F_ARMOURRATING, F_BONUS, F_DAM, F_EDIBLE, F_LINKSPELL, F_MANUALOF, F_NONE);
for (i = 0; i < nretflags; i++) {
f = retflag[i];
// damage
if (f->id == F_DAM) {
int min,max;
getdamrange(f, &min, &max);
price += (max*5);
}
// armour rating
if (f->id == F_ARMOURRATING) {
float rating;
rating = (float)f->val[0];
price += (rating * 20.0);
}
// bonus/penalties
if (f->id == F_BONUS) {
price += (f->val[0] * 100);
}
// food
if (f->id == F_EDIBLE) {
price += ((float)f->val[1] / 5.0);
}
// one-off magical effects (linkspell) - use spell price
if (f->id == F_LINKSPELL) {
if (o->type->obclass->id == OC_BOOK) {
price += (pow(getspelllevel(f->val[0]), 2) * 30);
} else if (o->type->obclass->id == OC_SCROLL) {
price += (pow(getspelllevel(f->val[0]), 2) * 2);
} else if (o->type->obclass->id == OC_POTION) {
price += (pow(getspelllevel(f->val[0]), 2));
} else if (o->type->obclass->id == OC_WAND) {
price += (pow(getspelllevel(f->val[0]), 2) * 15);
}
} else if (f->id == F_MANUALOF) {
price *= 124;
}
}
// TODO: rings?
if (hasflag(o->flags, F_HASBRAND)) {
price += 1000;
}
// rarity
rarity = getobrarity(o, &rr);
// potions
if (o->type->obclass->id == OC_POTION) {
// potion value is based on rarity
price += ((100 - rarity)*0.5);
} else if (o->type->obclass->id == OC_TOOLS) {
// tool value is based on rarity
price += ((100 - rarity)*3.75);
} else if (o->type->obclass->id == OC_TECH) {
// tech value is based on tech level & rarity
float multiplier = 1;
switch (gettechlevel(o->type->id)) {
case PR_INEPT:
multiplier = 3.25;
break;
case PR_NOVICE:
multiplier = 5.25;
break;
case PR_BEGINNER:
multiplier = 6.25;
break;
case PR_ADEPT:
multiplier = 7.25;
break;
case PR_SKILLED:
multiplier = 8.25;
break;
case PR_EXPERT:
multiplier = 9.25;
break;
case PR_MASTER:
multiplier = 10.25;
break;
}
price += ((100 - rarity)*multiplier);
}
// TODO: conferred intrinsics - depends on which one
// TODO: conferred spells - use spell price * multiplier
// speical material prices like velvet, silk
if (strstr(o->type->name, "velvet")) {
price *= 1.5;
}
if (strstr(o->type->name, "silk")) {
price *= 2;
}
// scarcity...
switch (rr) {
case RR_UNIQUE:
price *= 5;
break;
case RR_VERYRARE:
price *= 3;
break;
case RR_RARE:
price *= 2;
break;
case RR_UNCOMMON:
break;
case RR_COMMON:
price *= 0.75;
break;
default:
break;
}
/*
if (rarity >= 70) {
price /= 1.5;
} else if (rarity <= 40) {
price *= 1.5;
} else if (rarity <= 20) {
price *= 2;
} else if (rarity <= 10) {
price *= 5;
}
*/
// blessed/cursed
if (isblessed(o) || iscursed(o)) price *= 1.25;
// minimum
limitf(&price, 1, NA);
price = ((int)price * o->amt);
return (int) price;
}
/*
int getobtypevalue(objecttype_t *ot) {
float price;
if (ot->id == OT_GOLD) {
return 1;
}
// base value: weight * material value
price = (float)ot->weight * (float)getmaterialvalue(ot->material->id);
adjustprice(ot, &price);
return (int) price;
}
*/
char *getoperateverb(object_t *o) {
if (hasflag(o->flags, F_CONTAINER) && (o->type->id != OT_VENDINGMACHINE)) {
return "open";
}
return "operate";
}
// get outermost object in a pile
// ie if you call this on a gem inside a bag inside
// a barrel, will return the barrel.
object_t *getoutercontainer(object_t *o) {
/*
while (o->pile->parentob) {
o = o->pile->parentob;
}
return o;
*/
return getoutercontainerop(o->pile);
}
object_t *getoutercontainerop(obpile_t *op) {
object_t *o = NULL;
while (op->parentob) {
o = op->parentob;
op = o->pile;
}
return o;
}
// ie. "it has xxx accuracy"
char *getaccuracyname(int accpct) {
if (accpct >= 200) {
return "godlike";
} else if (accpct >= 150) {
return "incredible";
} else if (accpct >= 100) {
return "very good";
} else if (accpct >= 70) {
return "good";
} else if (accpct >= 50) {
return "average";
} else if (accpct >= 30) {
return "poor";
} else if (accpct >= 20) {
return "very poor";
} else if (accpct >= 0) {
return "incredibly poor";
} else {
return "a complete lack of";
}
}
object_t *getammo(object_t *gun) {
object_t *o;
o = gun->contents->first;
return o;
}
objecttype_t *getbasicweaponforskill(enum SKILL skid) {
switch (skid) {
case SK_AXES:
return findot(OT_AXE);
case SK_CLUBS:
return findot(OT_CLUB);
case SK_LONGBLADES:
return findot(OT_LONGSWORD);
case SK_POLEARMS:
return findot(OT_SPEAR);
case SK_SHORTBLADES:
return findot(OT_SHORTSWORD);
case SK_STAVES:
return findot(OT_QUARTERSTAFF);
default:
break;
}
return NULL;
}
object_t *getrandomammo(lifeform_t *lf) {
object_t *gun;
object_t *o;
flag_t *f;
int i;
flag_t *retflag[MAXCANDIDATES];
int nretflags = 0;
gun = getfirearm(lf);
if (!gun) {
return NULL;
}
// TODO: at the moment we are jsut picking the first
// possible ammo. Need to allow the player to
// pick a specific ammo to use. USe a flag on wep
// to do this? Or a flag on the player?
getflags(gun->flags, retflag, &nretflags, F_AMMOOB, F_NONE);
for (i = 0; i < nretflags; i++) {
f = retflag[i];
for (o = lf->pack->first ; o ; o = o->next) {
if (o->type->id == f->val[0]) {
return o;
}
}
}
return NULL;
}
objecttype_t *getrandomammofor(object_t *o) {
objecttype_t *ot;
objecttype_t *poss[MAXCANDIDATES];
int nposs = 0;
if (!o || !isfirearm(o)) {
return NULL;
}
for (ot = objecttype ; ot ; ot = ot->next) {
if (isammofor(ot, o)) {
poss[nposs++] = ot;
}
}
if (nposs) {
ot = poss[rnd(0,nposs-1)];
} else {
ot = NULL;
}
return ot;
}
brand_t *getrandombrandfor(objecttype_t *ot) {
brand_t *br, **poss;
brand_t *result = NULL;
int numbr;
int nposs = 0;
// count number of brands
numbr = 0;
for (br = firstbrand ; br ; br = br->next) {
numbr++;
}
poss = malloc(numbr * sizeof(brand_t *));
for (br = firstbrand ; br ; br = br->next) {
if (brandappliesto(br, ot)) {
poss[nposs] = br;
nposs++;
}
}
if (nposs > 0) {
result = poss[rnd(0,nposs-1)];
}
free(poss);
return result;
}
objecttype_t *getrandomobofclass(enum OBCLASS ocid, int minrarity, int maxrarity) {
objecttype_t *ot;
int count = 0,sel,n;
flag_t *f;
for (ot = objecttype ; ot ; ot = ot->next) {
if ((ot->obclass->id == ocid) && !hasflag(ot->flags, F_UNIQUE)) {
f = hasflag(ot->flags, F_RARITY);
if (f) {
if ( ((minrarity == NA) || (f->val[1] >= minrarity)) &&
((maxrarity == NA) || (f->val[1] <= maxrarity)) ) {
count++;
}
}
}
}
if (count <= 0) {
return NULL;
}
sel = rnd(1,count);
n = 0;
for (ot = objecttype ; ot ; ot = ot->next) {
if ((ot->obclass->id == ocid) && !hasflag(ot->flags, F_UNIQUE)) {
f = hasflag(ot->flags, F_RARITY);
if (f) {
if ( ((minrarity == NA) || (f->val[1] >= minrarity)) &&
((maxrarity == NA) || (f->val[1] <= maxrarity)) ) {
n++;
if (n == sel) {
return ot;
}
}
}
}
}
return NULL;
}
enum OBTYPE getrandomtrapforob(void) {
objecttype_t *ot;
enum OBTYPE poss[MAXCANDIDATES];
int nposs = 0;
for (ot = objecttype ; ot ;ot = ot->next) {
if ((ot->obclass->id == OC_TRAP) && hasflag(ot->flags, F_OBJECTTRAP)) {
poss[nposs++] = ot->id;
}
}
return poss[rnd(0,nposs-1)];
}
char *getdamname(enum DAMTYPE damtype) {
switch (damtype) {
case DT_ALL: return "all damage";
case DT_ACID: return "acid";
case DT_BASH: return "bludgeoning";
case DT_BITE: return "biting";
case DT_CHOP: return "chopping";
case DT_COLD: return "cold";
case DT_CRUSH: return "crushing";
case DT_DIRECT: return "direct";
case DT_DECAY: return "decay";
case DT_ELECTRIC: return "electricity";
case DT_EXPLOSIVE: return "explosive";
case DT_FALL: return "falling";
case DT_FIRE: return "fire";
case DT_HOLY: return "holy damage";
case DT_LIGHT: return "light";
case DT_MAGIC: return "magical";
case DT_MELT: return "melting";
case DT_NECROTIC: return "lifedrain";
case DT_PETRIFY: return "petrification";
case DT_PIERCE: return "piercing";
case DT_POISON: return "poison";
case DT_POISONGAS: return "poison gas";
case DT_PROJECTILE: return "projectile";
case DT_SLASH: return "slashing";
case DT_TOUCH: return "touch";
case DT_UNARMED: return "unarmed";
case DT_WATER: return "water";
default: return "unknown";
}
return "unknown";
}
char *getdamnamenoun(enum DAMTYPE damtype) {
switch (damtype) {
case DT_ALL: return "all damage";
case DT_ACID: return "acid";
case DT_MELT: return "melting";
case DT_PETRIFY: return "petrification";
case DT_PIERCE: return "piercing damage";
case DT_POISONGAS: return "poison gas";
case DT_POISON: return "poison";
case DT_SLASH: return "slashing damage";
case DT_ELECTRIC: return "electricity";
case DT_EXPLOSIVE: return "explosives";
case DT_FIRE: return "fire";
case DT_BITE: return "bite";
case DT_BASH: return "bludgeoning";
case DT_CHOP: return "chopping";
case DT_COLD: return "cold";
case DT_PROJECTILE: return "projectiles";
case DT_HOLY: return "holy damage";
case DT_DIRECT: return "direct damage";
case DT_DECAY: return "decay damage";
case DT_WATER: return "water";
case DT_MAGIC: return "magical damage";
case DT_NECROTIC: return "lifedrain damage";
case DT_TOUCH: return "touch effects";
case DT_UNARMED: return "unarmed damage";
case DT_LIGHT: return "light damage";
case DT_CRUSH: return "crushing damage";
case DT_FALL: return "damage from falling";
default: return "unknown";
}
return "unkmown";
}
char *gethiddenname(object_t *o) {
knowledge_t *k;
// if id'd, return the full name
if (hasflag(o->flags, F_IDENTIFIED)) {
return o->type->name;
}
// otherwise check if it has a hidden name
for (k = knowledge; k ; k = k->next) {
if (k->id == o->type->id) {
// it DOES have a hidden name.
// does the player know about it?
if (k->known == B_KNOWN) {
// if so, return real name
return o->type->name;
} else {
// otherwise return hidden one
return k->hiddenname;
}
}
}
// no hidden name, return real one
return o->type->name;
}
char *gethiddennameot(enum OBTYPE otid) {
knowledge_t *k;
objecttype_t *ot;
ot = findot(otid);
for (k = knowledge; k ; k = k->next) {
if (k->id == ot->id) {
// it DOES have a hidden name.
// does the player know about it?
if (k->known == B_KNOWN) {
// if so, return real name
return ot->name;
} else {
// otherwise return hidden one
return k->hiddenname;
}
}
}
return ot->name;
}
int getobattackdelay(object_t *o) {
int delay = 100; // ie. 100%
flag_t *f;
f = hasflag(o->flags, F_OBATTACKDELAY);
if (f) {
delay = f->val[0];
}
return delay;
}
float getobhppct(object_t *o) {
float pct;
flag_t *f;
f = hasflag(o->flags, F_OBHP);
if (f) {
pct = ((float) f->val[0] / (float) f->val[1]) * 100.0;
} else {
pct = 100;
}
return pct;
}
int getletidx(char let) {
int i;
for (i = 0; i < MAXPILEOBS; i++) {
if (letorder[i] == let) return i;
}
return -1;
}
int getmaterialvalue(enum MATERIAL mat) {
switch (mat) {
case MT_NOTHING:
case MT_MAGIC:
case MT_FIRE:
case MT_GAS:
case MT_ACID:
return 0;
case MT_WIRE:
case MT_FOOD:
case MT_PLANT:
case MT_ICE:
case MT_STONE:
return 1;
case MT_WATER:
return 1;
case MT_FLESH:
case MT_BONE:
case MT_BLOOD:
case MT_SLIME:
case MT_WAX:
case MT_OIL:
return 2;
case MT_CLOTH:
case MT_LEATHER:
return 2;
case MT_WOOD:
return 3;
case MT_PAPER:
case MT_WETPAPER:
return 4;
case MT_PLASTIC:
case MT_RUBBER:
case MT_GLASS:
case MT_SILK:
case MT_METAL:
return 5;
case MT_SILVER:
return 6;
case MT_GOLD:
return 7;
}
// default
return 1;
}
int getmaxthrowrange(lifeform_t *lf, object_t *o) {
int maxdist;
float str;
float obweight;
// adjust for lifeform strength
// mighty = can throw 1kilo 10 metres
// mighty = can throw 10kilos 1 metre
// 11 - kilos = distance
str = getattr(lf, A_STR); // ie. 1 - 18
str -= 2;
limitf(&str, 1, NA); // ie. 1 to 16
obweight = getobunitweight(o);
maxdist = ceil(str - obweight);
if (maxdist < 1) maxdist = 0;
return maxdist;
}
// select lowest possible letter
char getnextletter(obpile_t *op, char *wantletter) {
int curidx = -1;
char let;
//int db = B_FALSE;
// try 'wantletter' first
if (wantletter && (*wantletter != '\0')) {
if (!pilehasletter(op, *wantletter)) {
return *wantletter;
}
}
curidx = 0; // ie 'a'
for (curidx = 0; curidx < MAXPILEOBS; curidx++) {
// does any other object in the pile have this letter?
let = letorder[curidx];
if (!pilehasletter(op, let)) {
// if we didn't find it, this letter is okay.
return let;
}
}
return '\0';
}
int getnumshards(object_t *o) {
int numshards,maxshards;
maxshards = ceil(getobunitweight(o)) * 10;
if (maxshards < 1) maxshards = 1;
numshards = rnd(1,maxshards);
numshards *= o->amt;
return numshards;
}
int getnutritionbase(object_t *o) {
float basenutr;
flag_t *f;
if (o->material->id == MT_ICE) {
// use the object's weight
basenutr = getobweight(o) * 10;
} else {
// use nutrition flag
f = hasflag(o->flags, F_EDIBLE);
if (!f) {
f = hasflag(o->flags, F_DRINKABLE);
}
if (f) {
basenutr = (float)f->val[1];
} else {
return 0;
}
}
return basenutr;
}
int getnutrition(object_t *o) {
float nutrpct;
float nutrition;
if (isrotting(o)) {
nutrition = -(HUNGERCONST/2);
} else {
nutrpct = getnutritionbase(o);
if (nutrpct <= 0) {
nutrition = 0;
} else {
nutrition = pctof(nutrpct, (float) HUNGERCONST);
}
}
if (hasflag(o->flags, F_HEADLESS)) {
// -25% nutrition
nutrition *= 0.75;
}
return (int)nutrition;
}
enum DEPTH getobdepth(object_t *o, lifeform_t *lf) {
int depth = DP_NONE;
flag_t *f;
f = hasflag(o->flags, F_DEEPWATER);
if (f) {
depth = f->val[0];
if (lf) {
int mod;
mod = (SZ_HUMAN - getlfsize(lf)) * DP_CALF;
depth += mod;
limit(&depth, DP_NONE, DP_HEAD);
}
}
return depth;
}
char *getobdesc(object_t *o, char *buf) {
if (isknown(o)) {
if (o->type->id == OT_CORPSE) {
flag_t *f;
f = hasflag(o->flags, F_CORPSEOF);
if (f) {
race_t *corpserace;
corpserace = findrace(f->val[0]);
snprintf(buf, BUFLEN, "The dead body of %s %s.", isvowel(corpserace->name[0]) ? "an" : "a",
corpserace->name);
} else {
snprintf(buf, BUFLEN, "%s", o->type->desc);
}
} else if (o->type->id == OT_HEAD) {
flag_t *f;
f = hasflag(o->flags, F_CORPSEOF);
if (f) {
race_t *corpserace;
corpserace = findrace(f->val[0]);
snprintf(buf, BUFLEN, "The decapitated head of %s %s.", isvowel(corpserace->name[0]) ? "an" : "a",
corpserace->name);
} else {
snprintf(buf, BUFLEN, "%s", o->type->desc);
}
} else if (o->type->id == OT_STATUE) {
flag_t *f;
f = hasflag(o->flags, F_CORPSEOF);
if (f) {
race_t *corpserace;
corpserace = findrace(f->val[0]);
snprintf(buf, BUFLEN, "A stone statue of %s %s.", isvowel(corpserace->name[0]) ? "an" : "a",
corpserace->name);
} else {
snprintf(buf, BUFLEN, "%s", o->type->desc);
}
} else if (o->type->id == OC_SCROLL) {
flag_t *f;
f = hasflag(o->flags, F_LINKSPELL);
if (f) {
objecttype_t *spelltype;
spelltype = findot(f->val[0]);
if (spelltype) {
snprintf(buf, BUFLEN, "%s", spelltype->desc);
} else {
snprintf(buf, BUFLEN, "%s", o->type->desc);
}
} else {
snprintf(buf, BUFLEN, "%s", o->type->desc);
}
} else if (o->type->id == OT_WATERDEEP) {
snprintf(buf, BUFLEN, "%s water.", getwaterdepthname(getobdepth(o, player)));
capitalise(buf);
} else {
snprintf(buf, BUFLEN, "%s", o->type->desc);
}
} else {
objecttype_t *ot = NULL;
flag_t *f;
f = hasflag(o->flags, F_HASHIDDENNAME);
if (f) {
ot = findotn(f->text);
}
if (ot) {
snprintf(buf, BUFLEN, "%s", ot->desc);
} else {
snprintf(buf, BUFLEN, "%s", o->type->obclass->desc);
}
}
return buf;
}
char *getobequipinfo(object_t *o, char *buf) {
object_t *ammo = NULL;
flag_t *f;
strcpy(buf, "");
if (o->pile->owner) {
object_t *gun;
gun = getfirearm(o->pile->owner);
if (gun) {
ammo = getammo(gun);
}
}
f = hasflag(o->flags,F_EQUIPPED);
if (f) {
if (f->val[0] == BP_WEAPON) {
if (hasflag(o->flags, F_TWOHANDED)) {
strcat(buf, " (two-handed weapon)");
} else if (ismeleeweapon(o)) {
strcat(buf, " (weapon)");
} else {
strcat(buf, " (makeshift weapon)");
}
} else if (f->val[0] == BP_SECWEAPON) {
if (hasflag(o->flags, F_TWOHANDED)) {
strcat(buf, " (two-handed weapon)");
} else if (isshield(o)) {
strcat(buf, " (shield)");
} else if (ismeleeweapon(o)) {
strcat(buf, " (second weapon)");
} else if (isfirearm(o)) {
strcat(buf, " (firearm)");
} else {
strcat(buf, " (in left hand)");
}
} else {
strcat(buf, " (");
strcat(buf, getbodypartequipname(f->val[0]));
strcat(buf, " ");
strcat(buf, getbodypartname(f->val[0]));
strcat(buf, ")");
}
}
// ammo?
if (ammo && (ammo == o)) {
strcat(buf, " (current ammo)");
}
return buf;
}
char *getobextrainfo(object_t *o, char *buf) {
flag_t *f;
strcpy(buf, "");
// charges
f = hasflag(o->flags, F_CHARGES);
if (f && f->known) {
if (!hasflag(o->flags, F_DONTSHOWCHARGES)) {
char chargestr[BUFLEN];
if (o->type->obclass->id == OC_GODSTONE) {
if (f->val[0] == f->val[1]) {
snprintf(chargestr, BUFLEN, " (charged)");
} else {
snprintf(chargestr, BUFLEN, " (depleted)");
}
} else {
if (f->val[0] > 0) {
snprintf(chargestr, BUFLEN, " (%d charges left)",f->val[0]);
} else {
snprintf(chargestr, BUFLEN, " (empty)");
}
}
strcat(buf, chargestr);
}
}
// loaded guns
if (isfirearm(o) && getammo(o)) {
strcat(buf, " [loaded]");
}
// activated
if (!hasflag(o->flags, F_ACTIVATEPREFIX)) {
f = hasflag(o->flags, F_ACTIVATED);
if (f) {
strcat(buf, " [activated]");
}
}
return buf;
}
cell_t *getoblocation(object_t *o) {
return getobpilelocation(o->pile);
/*
if (o->pile->owner) { // held by someone
return o->pile->owner->cell;
} else if (o->pile->where) { // on the ground
return o->pile->where;
} else if (o->pile->parentob) { // inside another object
object_t *outerob;
// get outside object
outerob = getoutercontainer(o);
return getoblocation(outerob);
}
// in a dummy cell
return NULL;
*/
}
cell_t *getobpilelocation(obpile_t *op) {
if (op->owner) { // held by someone
return op->owner->cell;
} else if (op->where) { // on the ground
return op->where;
} else if (op->parentob) { // inside another object
object_t *outerob;
// get outside object
outerob = getoutercontainerop(op);
return getoblocation(outerob);
}
// in a dummy cell
return NULL;
}
char *getobname(object_t *o, char *buf, int count) {
return real_getobname(o, buf, count, B_TRUE, B_TRUE, B_TRUE, B_TRUE, B_FALSE);
}
char *getobnametrue(object_t *o, char *buf, int count) {
return real_getobname(o, buf, count, B_TRUE, B_TRUE, B_FALSE, B_TRUE, B_TRUE);
}
// buf must already be allocated
char *real_getobname(object_t *o, char *buf, int count, int wantpremods, int wantcondition, int adjustforblind, int wantblesscurse, int showall) {
char *pluralname;
char prefix[BUFLEN];
char basename[BUFLEN];
char localbuf[BUFLEN];
char buf2[BUFLEN];
char triedbuf[BUFLEN];
int venditem = B_FALSE;
flag_t *f;
brand_t *br;
int hasunknownmod = B_FALSE;
cell_t *where;
int no_a = B_FALSE;
flag_t *retflag[MAXCANDIDATES];
int nretflags = 0;
// default to normal name
if (hasflag(o->flags, F_VENDITEM)) {
venditem = B_TRUE;
}
where = getoblocation(o);
if (venditem) {
showall = B_TRUE;
}
f = hasflag(o->flags, F_TRAIL);
if (f) {
race_t *r = NULL;
enum SKILLLEVEL slev;
slev = getskill(player, SK_PERCEPTION);
r = findrace(f->val[0]);
assert(r);
if (f->val[2] == S_SMELL) {
char buf[BUFLEN];
float pct;
char dname[BUFLEN];
char adjective[BUFLEN];
lifeform_t *who = NULL;
pct = ((float)f->lifetime / (float)TM_SCENT)*100;
if (pct >= 66) {
strcpy(adjective, "strong ");
} else if (pct >= 33) {
strcpy(adjective, "");
} else {
strcpy(adjective, "weak ");
}
strcpy(basename, "");
if (strlen(f->text)) {
who = findlf(where->map, atoi(f->text));
}
if (who) {
char lfname[BUFLEN];
real_getlfname(who, lfname, B_FALSE);
snprintf(buf, BUFLEN, "%s%s %sscent",lfname,getpossessive(lfname), adjective);
} else {
snprintf(buf, BUFLEN, "%s %sscent",r->name, adjective);
}
strcat(basename, buf);
strcat(basename, " leading ");
snprintf(dname, BUFLEN, "%s", getdirname(f->val[1]));
dname[0] = tolower(dname[0]);
strcat(basename, dname);
} else {
char buf[BUFLEN];
// adept and upwards gets depth
if (slev >= PR_BEGINNER) {
float pct;
pct = ((float)f->lifetime / (float)TM_FOOTPRINT)*100;
if (pct >= 66) {
strcpy(basename, "fresh ");
} else if (pct >= 33) {
strcpy(basename, "");
} else {
strcpy(basename, "faint ");
}
} else {
strcpy(basename, "");
}
// adept and upwards get "monstername footprints"
if (slev >= PR_ADEPT) {
snprintf(buf, BUFLEN, "%s %s",r->name, o->type->name);
strcat(basename, buf);
} else {
strcat(basename, o->type->name);
}
// skilled and upwards get the direction
if (slev >= PR_SKILLED) {
char dname[BUFLEN];
strcat(basename, " leading ");
snprintf(dname, BUFLEN, "%s", getdirname(f->val[1]));
dname[0] = tolower(dname[0]);
strcat(basename, dname);
}
} // end if sight/smell
} else if ((o->type->id == OT_SIGN) && !hasflag(o->flags, F_SIGNTEXT)) {
strcpy(basename, "blank sign");
} else if (o->type->id == OT_MAP) {
flag_t *f;
f = hasflag(o->flags, F_MAPTO);
if (f && getskill(player, SK_CARTOGRAPHY)) {
snprintf(basename, BUFLEN, "map to %s", f->text);
} else {
strcpy(basename, "map");
}
} else if (o->type->id == OT_WATERDEEP) {
snprintf(basename, BUFLEN, "%s water", getwaterdepthname(getobdepth(o, player)));
} else {
strcpy(basename, "");
// show "lit candle" etc
if (isactivated(o) && hasflag(o->flags, F_ACTIVATEPREFIX)) {
f = hasflag(o->flags, F_ACTIVATEPREFIX);
snprintf(basename, BUFLEN, "%s ", f->text);
} else if (hasflagval(o->flags, F_TRAPPED, NA, NA, B_TRUE, NULL)) {
// known trap?
strcpy(basename, "trapped ");
}
if (showall) {
strcat(basename,o->type->name);
} else {
strcat(basename,gethiddenname(o));
}
}
if (o->type->obclass->id == OC_BOOK) {
if (!strcmp(basename, o->type->name)) {
if (o->type->id == OT_SPELLBOOK) {
f = hasflag(o->flags, F_LINKSPELL);
if (f) {
objecttype_t *st;
st = findot(f->val[0]);
strcat(basename, " of ");
strcat(basename, st->name);
}
} else {
f = hasflag(o->flags, F_MANUALOF);
if (f) {
skill_t *sk;
sk = findskill(f->val[0]);
strcat(basename, " of ");
strcat(basename, sk->name);
}
}
}
}
if (!showall) {
if ((gamemode == GM_GAMESTARTED) && adjustforblind && !haslos(player, where) ) {
f = hasflag(o->flags, F_FEELTEXT);
if (f) {
strcpy(basename, f->text);
} else {
// override with obclass names
switch (o->type->obclass->id) {
case OC_BOOK:
strcpy(basename, "book");
break;
case OC_POTION:
strcpy(basename, "potion");
break;
case OC_RING:
strcpy(basename, "ring");
break;
case OC_SCROLL:
strcpy(basename, "scroll");
break;
case OC_WAND:
strcpy(basename, "wand");
break;
default:
break;
}
}
}
}
if ((o->type->id == OT_POT_WATER) && (o->blessed == B_BLESSED) && isblessknown(o) && isknown(o)) {
strcpy(basename, "potion of holy water");
}
if ((o->type->id == OT_POT_COMPETENCE) && (o->blessed == B_CURSED) && isblessknown(o) && isknown(o)) {
strcpy(basename, "potion of incompetence");
}
// override corpse name
if (o->type->id == OT_CORPSE) {
f = hasflag(o->flags, F_CORPSEOF);
if (f) {
race_t *corpserace;
flag_t *ff;
corpserace = findrace(f->val[0]);
ff = hasflag(corpserace->flags, F_NAME);
if (ff) {
snprintf(basename, BUFLEN, "%s%s corpse",ff->text, getpossessive(ff->text));
no_a = B_TRUE;
} else {
snprintf(basename, BUFLEN, "%s corpse",corpserace->name);
}
}
} else if (o->type->id == OT_FOUNTAIN) {
objecttype_t *ot;
// find out what kind of fountain this is
f = hasflag(o->flags, F_LINKOB);
if (f) {
ot = findot(f->val[0]);
if (ot) {
char *srcp;
// get potion name (or hidden name if we don't recognise it)
srcp = gethiddennameot(ot->id);
// if this is "potion of xxx"
if (strstarts(srcp, "potion ")) {
// skip first word from potion name.
// ie. we're left with " of xxx"
while (*srcp != ' ') {
srcp++;
}
srcp++; // go past the space
// now copy the rest into buf
strcpy(buf, srcp);
if (streq(buf, "of water")) {
strcpy(basename, "water fountain");
} else {
snprintf(basename, BUFLEN, "fountain %s",buf);
}
} else {
char *dstp;
// ie. "orange potion"
// get rid of "potion" onwards
dstp = buf;
while (!streq(srcp, "potion")) {
*dstp = *srcp;
srcp++;
dstp++;
}
*dstp = '\0';
// buf should now be something like "orange "
snprintf(basename, BUFLEN, "%sfountain",buf);
}
} else {
// should never happen
strcpy(basename, "??strange fountain??");
}
} else { // end if f
// should never happen in gameplay, but might be triggered
// during object creation.
strcpy(basename, "??strange fountain2??");
}
} else if (o->type->id == OT_STATUE) {
f = hasflag(o->flags, F_CORPSEOF);
if (f) {
race_t *corpserace;
corpserace = findrace(f->val[0]);
snprintf(basename, BUFLEN, "statue of a %s",corpserace->name);
}
} else if ((o->type->id == OT_STEW) || (o->type->id == OT_JERKY)) {
f = hasflag(o->flags, F_LINKRACE);
if (f) {
race_t *r;
r = findrace(f->val[0]);
snprintf(basename, BUFLEN, "%s %s",r->name, o->type->name);
}
}
// handle ALL
if (count == ALL) {
count = o->amt;
}
strcpy(localbuf, "");
// figure out pluralname
if (count == 1) {
pluralname = strdup(basename);
} else {
// multiple objects?
if (hasflag(o->flags, F_NO_PLURAL)) {
pluralname = strdup(basename);
} else {
pluralname = makeplural(basename);
}
}
// blessed status
if (!hasflag(o->flags, F_NOBLESS) && wantblesscurse) {
if (showall || isblessknown(o)) {
switch (o->blessed) {
case B_BLESSED:
// blessed water is known as "holy water"
if ((o->type->id == OT_POT_WATER) && isknown(o)) {
} else {
strcat(localbuf, "blessed ");
}
break;
case B_UNCURSED:
strcat(localbuf, "uncursed ");
break;
case B_CURSED:
if ((o->type->id == OT_POT_COMPETENCE) && isknown(o)) {
} else {
strcat(localbuf, "cursed ");
}
break;
}
}
}
// eaten?
f = hasflag(o->flags, F_EDIBLE);
if (f && (f->val[2] != NA)) {
strcat(localbuf, "partially eaten ");
}
// material changed?
if (o->material != o->type->material) {
switch (o->material->id) {
case MT_GOLD:
strcat(localbuf, "golden ");
break;
case MT_WOOD:
strcat(localbuf, "wooden ");
break;
case MT_ICE: // we'll use the 'frozen' obmod instead
break;
default:
strcat(localbuf, o->material->name);
strcat(localbuf, " ");
break;
}
}
// include mods (ie. a flaming sword)
if (wantpremods) {
obmod_t *om;
for (om = firstobmod ; om; om = om->next) {
if (hasobmod(o, om)) {
strcat(localbuf, om->prefix);
}
}
}
// condition
if (wantcondition) {
if (!hasflag(o->flags, F_NOOBDAMTEXT)) {
getobconditionname(o, buf2);
if (strlen(buf2) > 0) {
strcat(localbuf, buf2);
strcat(localbuf, " ");
}
}
}
// include enchantments (ie. a blessed +5 sword)
f = hasflag(o->flags, F_BONUS);
if (f && (f->known || showall)) {
char buf2[BUFLENSMALL];
int bonus;
bonus = f->val[0];
if (bonus != 0) {
snprintf(buf2, BUFLENSMALL, "%s%d ", (bonus < 0) ? "-" : "+", abs(bonus));
strcat(localbuf, buf2);
}
}
// special rings
if (isidentified(o)) {
switch (o->type->id) {
char buf2[BUFLENSMALL];
case OT_RING_CON:
case OT_RING_DEX:
case OT_RING_IQ:
case OT_RING_STR:
f = hasflag(o->flags, F_EQUIPCONFER);
if (f) {
snprintf(buf2, BUFLENSMALL, "+%d ",f->val[2]);
strcat(localbuf, buf2);
}
break;
default:
break;
}
}
if (issecretdoor(o)) {
strcat(localbuf, "secret ");
}
// object name
strcat(localbuf, pluralname);
free(pluralname);
// include mods if identified - ie. xxx of pyromania
for (br = firstbrand; br; br = br->next) {
if (hasflagval(o->flags, F_HASBRAND, br->id, NA, NA, NULL)) {
flag_t *brf;
int ok = B_TRUE;
// are all of the brand flags known?
for (brf = br->flags->first ; brf ; brf = brf->next) {
int i;
getflags(o->flags, retflag, &nretflags, brf->id, F_NONE);
for (i = 0; i < nretflags; i++) {
f = retflag[i];
if (f->lifetime == FROMBRAND) {
if (f->known || showall) {
} else {
ok = B_FALSE;
hasunknownmod = B_TRUE;
break;
}
}
}
}
if (ok) {
strcat(localbuf, br->suffix);
}
}
}
// make sure obname doesn't start with a space
while (localbuf[0] == ' ') {
strcpy(localbuf, localbuf + 1);
}
// show portal/stair destination
f = hasflag(o->flags, F_MAPLINK);
if (f && f->known && !hasflag(o->flags, F_PIT)) {
cell_t *thiscell;
map_t *thismap;
map_t *newmap;
thiscell = getoblocation(o);
thismap = thiscell->map;
newmap = findmap(f->val[0]);
if (newmap) {
if (newmap->region == thismap->region) {
char buf2[BUFLEN];
snprintf(buf2, BUFLEN, " to level %d", newmap->depth);
strcat(localbuf, buf2);
} else {
char buf2[BUFLEN];
strcat(localbuf, " to ");
getregionname(buf2, newmap, B_FALSE);
strcat(localbuf, buf2);
}
}
}
// show sign text
if (o->type->id == OT_SIGN) {
f = hasflag(o->flags, F_SIGNTEXT);
if (f) {
strcat(localbuf, " reading '");
strcat(localbuf, f->text);
strcat(localbuf, "'");
}
}
// append inscription
if (o->inscription) {
strcat(localbuf, " {");
strcat(localbuf, o->inscription);
strcat(localbuf, "}");
}
// show if we've tried this
if (gamemode == GM_GAMESTARTED) {
strcpy(triedbuf, "");
if (hasflag(o->flags, F_BEINGUSED)) {
if (strlen(triedbuf)) strcat(triedbuf, ", ");
else strcpy(triedbuf, " [");
strcat(triedbuf, "currently being read");
}
if (istried(o)) {
if (strlen(triedbuf)) strcat(triedbuf, ", ");
else strcpy(triedbuf, " [");
strcat(triedbuf, "tried");
}
if (lfhasflagval(player, F_FAILEDINSPECT, o->type->id, NA, NA, NULL)) {
if (strlen(triedbuf)) strcat(triedbuf, ", ");
else strcpy(triedbuf, " [");
strcat(triedbuf, "inspected");
}
if (strlen(triedbuf)) {
strcat(triedbuf, "]");
strcat(localbuf, triedbuf);
}
// detect magic - append [magic]
if (lfhasflag(player, F_DETECTMAGIC)) {
if (ismagical(o)) {
strcat(localbuf, " [magic]");
}
}
if (getskill(player, SK_COOKING) >= PR_BEGINNER) {
if (isbadfood(o)) {
strcat(localbuf, " [badfood]");
}
}
}
// in a shop?
f = hasflag(o->flags, F_SHOPITEM);
if (f) {
char pricebuf[BUFLEN];
// get price for _player_
snprintf(pricebuf, BUFLEN, " [$%d%s]", (int)getshopprice(o, player), o->pile->owner ? ", unpaid" : "");
strcat(localbuf, pricebuf);
}
// apply prefix now!
if (count == 1) {
if (hasflag(o->flags, F_NO_A)) {
no_a = B_TRUE;
}
if (no_a) {
if (o->type->id == OT_GOLD) {
snprintf(prefix, BUFLEN, "%d ",count);
} else {
// nothing.
strcpy(prefix, "");
}
} else {
if (hasflag(o->flags, F_UNIQUE) && isknown(o)) {
strcpy(prefix, "The ");
} else {
if (needan(localbuf)) {
strcpy(prefix, "an ");
} else {
strcpy(prefix, "a ");
}
}
}
} else {
// multiple objects?
snprintf(prefix, BUFLEN, "%d ",count);
}
// prepend prefix on to buf
snprintf(buf, BUFLEN, "%s%s", prefix, localbuf);
return buf;
}
float getobpileweight(obpile_t *op) {
object_t *o;
float weight = 0;
if (op->parentob && hasflag(op->parentob->flags, F_HOLDING)) {
return 0;
}
for (o = op->first ; o ; o = o->next) {
weight += getobweight(o);
}
return weight;
}
char *getobconditionname(object_t *o, char *buf) {
float pct;
enum ATTRBRACKET iqb;
if (player) {
iqb = getattrbracket(getattr(player, A_IQ), A_IQ, NULL);
} else {
iqb = AT_AVERAGE; // this should be sufficient to show everything
}
if (iscorpse(o)) {
// you only know it's rotting if you are smart or a cook
if (isrotting(o) &&
( (iqb >= AT_GTAVERAGE) || getskill(player, SK_COOKING)) ) {
snprintf(buf, BUFLEN, "rotting");
} else {
strcpy(buf, "");
}
} else {
if (iqb >= AT_LOW) {
pct = getobhppct(o);
if (pct >= 100) {
strcpy(buf, "");
} else if (pct >= 75) {
snprintf(buf, BUFLEN, "battered");
} else if (pct >= 50) {
snprintf(buf, BUFLEN, "damaged");
} else if (pct >= 25) {
snprintf(buf, BUFLEN, "very damaged");
} else {
snprintf(buf, BUFLEN, "critically damaged");
}
} else {
strcpy(buf, "");
}
}
return buf;
}
char *getobhurtname(object_t *o, enum DAMTYPE damtype) {
switch (damtype) {
case DT_ACID:
if (o->amt == 1) {
return "corrodes";
} else {
return "corrode";
}
case DT_DECAY:
if (o->amt == 1) {
return "decays";
} else {
return "decay";
}
case DT_FIRE:
if (o->amt == 1) {
return "burns";
} else {
return "burn";
}
case DT_MELT:
if (o->amt == 1) {
return "melts a bit";
} else {
return "melt a bit";
}
default:
if (o->amt == 1) {
return "is damaged";
} else {
return "are damaged";
}
}
return "is damaged";
}
float getobweight(object_t *o) {
float weight;
weight = getobunitweight(o) * o->amt;
// object contents
if (hasflag(o->flags, F_CONTAINER) && !hasflag(o->flags, F_HOLDING)) {
float containerweight = 0;
containerweight = getobpileweight(o->contents);
weight += containerweight;
}
return weight;
}
float getobunitweight(object_t *o) {
float weight;
flag_t *f;
// bag of holding?
if (o->pile->parentob && hasflag(o->pile->parentob->flags, F_HOLDING)) {
return 0;
}
if (o->type->id == OT_WATERDEEP) {
weight = 75 * getobdepth(o, NULL);
} else {
weight = o->weight;
}
// has its material been changed?
if (o->material != o->type->material) {
// changed - some materials will
// modify the item's weight
float ratio;
ratio = o->material->weightrating / o->type->material->weightrating;
weight *= ratio;
}
f = hasflag(o->flags, F_WET);
if (f) {
switch (f->val[0]) {
case W_DAMP:
weight *= 1.05;
break;
case W_WET:
weight *= 1.25;
break;
case W_SOAKED:
weight *= 1.5;
break;
default:
break;
}
}
return weight;
}
objecttype_t *getoppositestairs(objecttype_t *ot) {
flag_t *f;
f = hasflag(ot->flags, F_OPPOSITESTAIRS);
assert(f);
return findot(f->val[0]);
}
char *real_getrandomob(map_t *map, char *buf, int cond, int cval, int forcedepth, int forcehabitat, enum LFSIZE maxsize) {
objecttype_t *ot;
objecttype_t *poss[MAXRANDOMOBCANDIDATES];
int nposs = 0;
int selidx;
int amt;
flag_t *f;
int db = B_FALSE;
char *pluralname;
char brandname[BUFLEN];
char cursestr[BUFLEN];
int raritymin,raritymax;
int depth;
int done = B_FALSE;
obmod_t *om;
flag_t *omposs[MAXCANDIDATES];
int noms = 0;
enum RARITY wantrr = RR_COMMON;
db = obdb;
//if (forcedepth != NA) {
if (forcedepth >= 0) {
depth = forcedepth;
} else {
depth = getmapdifficulty(map);
}
getrarityrange(depth, &raritymin, &raritymax, RARITYVARIANCEOB, B_TRUE);
// pick rr...
wantrr = RR_COMMON;
while ((wantrr < RR_VERYRARE) && onein(3)) {
wantrr++;
}
while (!done) {
if (db) dblog("adding random object with rarity value between %d - %d and rr <= %d",raritymin,raritymax,wantrr);
if (db) {
objectclass_t *oc = NULL;
switch (cond) {
case RO_DAMTYPE:
dblog(" (must have damtype = %s)",getdamname(cval));
break;
case RO_OBCLASS:
oc = findoc(cval);
dblog(" (must have obclass = %s)",oc->name);
break;
case RO_HOLDABLE:
dblog(" (must be holdable)",oc->name);
break;
}
}
// try to find an object of this type which will
// fit in the map's habitat
nposs = 0;
for (ot = objecttype ; ot ; ot = ot->next) {
int rarok = B_FALSE, condok = B_FALSE;
flag_t *rarflag = NULL;
// correct rarity?
rarflag = hasflagval(ot->flags, F_RARITY, H_ALL, NA, NA, NULL);
if (!rarflag) {
if (forcehabitat != NA) {
rarflag = hasflagval(ot->flags, F_RARITY, forcehabitat, NA, NA, NULL);
} else if (map) {
rarflag = hasflagval(ot->flags, F_RARITY, map->habitat->id, NA, NA, NULL);
} else {
rarflag = hasflagval(ot->flags, F_RARITY, NA, NA, NA, NULL);
}
}
if (rarflag) {
if ((rarflag->val[1] >= raritymin) && (rarflag->val[1] <= raritymax)) {
if ((rarflag->val[2] == NA) || (rarflag->val[2] <= wantrr)) {
rarok = B_TRUE;
}
}
}
if (rarok) {
// matches condition?
if (cond == RO_NONE) {
condok = B_TRUE;
} else if (cond == RO_DAMTYPE) {
if (hasflagval(ot->flags, F_DAM, cval, NA, NA, NULL)) {
condok = B_TRUE;
}
} else if (cond == RO_OBCLASS) {
if (ot->obclass->id == cval) {
condok = B_TRUE;
}
} else if (cond == RO_HOLDABLE) {
if (!hasflag(ot->flags, F_NOPICKUP)) {
condok = B_TRUE;
}
}
}
if (rarok && condok && (ot->size <= maxsize)) {
if (db) dblog("-> possibility: %s, rarity=%d",ot->name, rarflag->val[1]);
poss[nposs] = ot;
nposs++;
if (nposs >= MAXRANDOMOBCANDIDATES) break;
}
}
// nothing found?
if (nposs == 0) {
// already at lowest rarity?
if ((raritymax >= 100) && (raritymin <= 0)) {
// give up
strcpy(buf, "");
if (db) dblog("no possible objects at all! giving up.");
return NULL;
}
// expand range and try again
raritymax += 10; if (raritymax > 100) raritymax = 100;
raritymin -= 10; if (raritymin < 0) raritymin = 0;
if (db) dblog("no possible objects like this. trying again with rarity %d-%d\n",raritymin,raritymax);
} else {
// something found
done = B_TRUE;
}
} // end while !done
if (db) dblog("got %d possibilities. now adjusting for RR_",nposs);
// pick a random object from our possiblities
selidx = rnd(0,nposs-1);
ot = poss[selidx];
// handle objects which appear in multiples (ie. rocks)
f = hasflag(ot->flags, F_NUMAPPEAR);
if (f) {
amt = rnd(f->val[0], f->val[1]);
} else {
amt = 1;
}
if (amt > 1) {
pluralname = makeplural(ot->name);
} else {
pluralname = strdup(ot->name);
}
// blessed or cursed? 15% chance each way
strcpy(cursestr, "");
if (!hasflag(ot->flags, F_NOBLESS)) {
int num;
num = rnd(1,100);
if (num <= 15) {
strcpy(cursestr, "cursed ");
} else if (num >= 85) {
strcpy(cursestr, "blessed ");
}
}
if (hasflag(ot->flags, F_ENCHANTABLE)) {
char buf2[BUFLENSMALL];
int bonus = 0;
int dir,chance;
if (strstr(cursestr, "cursed")){ // cursed WILL have a negative bonus
bonus = -1; // always at least -1
chance = 25;
dir = -1;
} else if (strstr(cursestr, "blessed")) { // blessed/uncursed MAY have a bonus
chance = 30;
dir = 1;
} else {
chance = 25;
dir = 1;
}
while (rnd(1,100) <= chance) {
bonus += dir;
}
snprintf(buf2, BUFLENSMALL, "%s%d ", (bonus >= 0) ? "+" : "", bonus);
strcat(cursestr, buf2);
}
// random chance of having an obmod
for (om = firstobmod ; om ; om = om->next) {
if (!hasflag(ot->flags, F_NOQUALITY)) {
f = hasflagval(ot->flags, F_CANHAVEOBMOD, om->id, NA, NA, NULL);
if (f && (f->val[1] != NA)) {
omposs[noms] = f;
noms++;
}
}
}
if (noms) {
// pick a random one to maybe apply
f = omposs[rnd(0,noms-1)];
if (rnd(1,100) <= f->val[1]) {
om = findobmod(f->val[0]);
if (om) {
strcat(cursestr, om->prefix);
}
}
}
// get random chance of having a brand (1% per depth)...
// if so...
strcpy(brandname, "");
if (rnd(1,100) <= depth) {
brand_t *br;
br = getrandombrandfor(ot);
if (br) strcpy(brandname, br->suffix);
}
snprintf(buf, BUFLEN, "%d %s%s%s", amt, cursestr, pluralname,brandname);
if (db) dblog("random ob: %d x %s ('%s')", amt, ot->name,pluralname);
free(pluralname);
return buf;
}
char *getrandomob(map_t *map, char *buf) {
return real_getrandomob(map, buf, RO_NONE, NA, NA, NA, SZ_MAX);
}
char *getrandomobofsize(map_t *map, char *buf, enum LFSIZE maxsize) {
return real_getrandomob(map, buf, RO_NONE, NA, NA, NA, maxsize);
}
char *getrandomobwithdt(map_t *map, enum DAMTYPE damtype, char *buf) {
return real_getrandomob(map, buf, RO_DAMTYPE, damtype, NA, NA, SZ_MAX);
}
char *getrandomobwithclass(map_t *map, enum OBCLASS cid, char *buf, int depthmod) {
//return real_getrandomob(map, buf, RO_OBCLASS, cid, map->depth + depthmod);
if (depthmod == NA) depthmod = 0;
return real_getrandomob(map, buf, RO_OBCLASS, cid, getmapdifficulty(map) + depthmod, NA, SZ_MAX);
}
int getobrarity(object_t *o, enum RARITY *rr) {
cell_t *c;
map_t *m = NULL;
flag_t *f;
if (rr) *rr = RR_COMMON;
// check for rarity on this object's map first
c = getoblocation(o);
if (c) {
m = c->map;
}
if (m) {
f = hasflagval(o->flags, F_RARITY,m->habitat->id, NA, NA, NULL);
if (f) {
if (rr) {
*rr = (f->val[2] == NA) ? RR_COMMON : f->val[2];
}
return f->val[1];
}
}
// any rarity value at all?
f = hasflag(o->flags, F_RARITY);
if (f) {
if (rr) {
*rr = (f->val[2] == NA) ? RR_COMMON : f->val[2];
}
return f->val[1];
}
// ie. doesn't randomly appear
return 0;
}
enum SPELLSCHOOL getschool(enum OBTYPE sid) {
objecttype_t *ot;
ot = findot(sid);
if (ot) {
flag_t *f;
f = hasflag(ot->flags, F_SPELLSCHOOL);
if (f) {
return f->val[0];
}
}
return SS_NONE;
}
char *getschoolname(enum SPELLSCHOOL sch) {
switch (sch) {
case SS_ABILITY: return "Abilities";
case SS_ALLOMANCY: return "Allomancy";
case SS_DIVINE: return "Divine Powers";
case SS_ENCHANTMENT: return "Enchantments";
case SS_WILD: return "Wild Magic";
case SS_MENTAL: return "Psionic Powers";
case SS_AIR: return "Elemental/Air Magic";
case SS_FIRE: return "Elemental/Fire Magic";
case SS_COLD: return "Elemental/Cold Magic";
case SS_MODIFICATION: return "Modification Magic";
case SS_DEATH: return "Necromancy";
case SS_NATURE: return "Nature";
case SS_LIFE: return "Life Magic";
case SS_DIVINATION: return "Divination Magic";
case SS_TRANSLOCATION: return "Translocation Magic";
case SS_SUMMONING: return "Summoning Magic";
case SS_GRAVITY: return "Gravitation Magic";
case SS_LAST: return "!invalid school!";
default:
break;
}
return "unknown school";
}
char *getschoolnameshort(enum SPELLSCHOOL sch) {
switch (sch) {
case SS_ABILITY: return "Abilities";
case SS_ALLOMANCY: return "Allomancy";
case SS_DIVINE: return "Divine Powers";
case SS_WILD: return "Wild Magic";
case SS_AIR: return "Air Magic";
case SS_FIRE: return "Fire Magic";
case SS_COLD: return "Cold Magic";
case SS_DEATH: return "Necromancy";
case SS_ENCHANTMENT: return "Enchantment";
case SS_LIFE: return "Life Magic";
case SS_MENTAL: return "Psionic Powers";
case SS_MODIFICATION: return "Modification";
case SS_NATURE: return "Nature";
case SS_DIVINATION: return "Divination";
case SS_TRANSLOCATION: return "Translocation";
case SS_SUMMONING: return "Summoning";
case SS_GRAVITY: return "Gravitation";
case SS_LAST: return "!invalid school!";
default:
break;
}
return "unknown school";
}
void setwaterdepth(cell_t *c, int depth) {
object_t *o;
if (depth > 0) {
o = hasobwithflag(c->obpile, F_DEEPWATER);
if (o) {
flag_t *f;
// adjust depth
f = hasflag(o->flags, F_DEEPWATER);
f->val[0] = depth;
}
} else {
int nkilled = 0;
// water depth is now zero.
o = hasobwithflag(c->obpile, F_DEEPWATER);
while (o) {
killob(o);
nkilled++;
o = hasobwithflag(c->obpile, F_DEEPWATER);
}
if (nkilled) {
addob(c->obpile, "large puddle of water");
}
}
}
int getshatterdam(object_t *o) {
int shatterdam = 0;
if (willshatter(o->material->id)) {
int maxshatterdam;
maxshatterdam = ceil(getobweight(o));
if (maxshatterdam < 1) maxshatterdam = 1;
shatterdam = rnd(1, maxshatterdam);
}
return shatterdam;
}
float getshopprice(object_t *o, lifeform_t *buyer) {
float val;
val = getobvalue(o);
if (buyer) {
float pricepctmod = 0;
enum SKILLLEVEL slev;
// price goes up/down for charisma (+/- 25%)
pricepctmod -= ((getstatmod(buyer, A_CHA)/2) * -1);
// modify for speech (up to -30%);
slev = getskill(buyer, SK_SPEECH);
if (slev) {
pricepctmod -= (slev*5);
}
val = pctof(val, 100 + pricepctmod);
}
return val;
}
enum SKILLLEVEL gettechlevel(enum OBTYPE oid) {
flag_t *f;
objecttype_t *ot;
enum SKILLLEVEL tlev = PR_INEPT;
ot = findot(oid);
if (ot) {
f = hasflag(ot->flags, F_TECHLEVEL);
if (f) {
tlev = f->val[0];
}
}
return tlev;
}
int getthrowdam(object_t *o) {
double dam = 0;
flag_t *f;
// modify if it has a damage value
f = hasflag(o->flags, F_MISSILEDAM);
if (f) {
dam = f->val[0];
} else {
// base damage is = kilograms.
// ie. 1 kg object does 1 damage
// ie. 5 kg object does 5 damage
// ie. 100 kg object does 100 damage (person)
// ie. 1 tonne object does 1000 damage (car)
dam = ceil((double)getobunitweight(o));
// missile objects do extra damage
if (hasflag(o->flags, F_THROWMISSILE)) {
dam *= 2;
}
// max
if (dam > 20) dam = 20;
}
// modify for bonus
f = hasflag(o->flags, F_BONUS);
if (f) {
dam += f->val[0];
}
// note: damage will also be modified based on speed in fireat()
// adjust for material
switch (o->material->id) {
// soft materials do less damage
case MT_PAPER:
case MT_WETPAPER:
case MT_CLOTH:
dam /= 2;
break;
break;
default:
break;
}
return (int)dam;
}
// get either name of top object, or cell type if solid
char *gettopobname(cell_t *c, char *retbuf) {
char buf[BUFLEN];
int nother;
if (c->type->solid) {
strcpy(retbuf, c->type->name);
nother = countnoncosmeticobs(c->obpile, B_TRUE);
if (nother) {
snprintf(buf, BUFLEN, " (+%d other thing%s)", nother, (nother == 1) ? "" : "s");
strcat(retbuf, buf);
}
return retbuf;
} else {
object_t *o;
o = gettopobject(c, B_FALSE);
if (o) {
getobname(o, buf, o->amt);
strcat(retbuf, buf);
// other obs here too?
nother = countnoncosmeticobs(c->obpile, B_TRUE) - 1;
if (nother >= 1) {
snprintf(buf, BUFLEN, " (+%d other thing%s)", nother, (nother == 1) ? "" : "s");
strcat(retbuf, buf);
}
return retbuf;
}
}
return NULL;
}
enum BODYPART getweildloc(object_t *o, enum BODYPART *otherloc, int *twohanded) {
enum BODYPART weildloc;
if (o) {
if (hasflag(o->flags, F_FIREARM)) {
weildloc = BP_SECWEAPON;
} else {
weildloc = BP_WEAPON;
}
if (twohanded) {
if (hasflag(o->flags, F_TWOHANDED)) {
*twohanded = B_TRUE;
} else {
*twohanded = B_FALSE;
}
}
} else {
// ie. unarmed
weildloc = BP_WEAPON;
if (twohanded) *twohanded = B_FALSE;
}
if (otherloc) {
if (weildloc == BP_WEAPON) {
*otherloc = BP_SECWEAPON;
} else {
*otherloc = BP_WEAPON;
}
}
return weildloc;
}
int hasedibleob(obpile_t *op) {
object_t *o;
for (o = op->first ; o ; o = o->next) {
if (isedible(o)) {
return B_TRUE;
}
}
return B_FALSE;
}
object_t *hasknownob(obpile_t *op, enum OBTYPE oid) {
object_t *o;
for (o = op->first ; o ; o = o->next) {
if (o->type->id == oid) {
if (isknown(o)) {
return o;
}
}
}
return NULL;
}
object_t *hasob(obpile_t *op, enum OBTYPE oid) {
object_t *o;
for (o = op->first ; o ; o = o->next) {
if (o->type->id == oid) return o;
}
return NULL;
}
object_t *hasobletter(obpile_t *op, char letter) {
object_t *o;
for (o = op->first ; o ; o = o->next) {
if (o->letter == letter) return o;
}
return NULL;
}
object_t *hasobofclass(obpile_t *op, enum OBCLASS cid) {
object_t *o;
for (o = op->first ; o ; o = o->next) {
if (o->type->obclass->id == cid) return o;
}
return NULL;
}
int hasobmod(object_t *o, obmod_t *om) {
flag_t *omf;
int found = B_TRUE;
for (omf = om->flags->first ; omf ; omf = omf->next){
if (!hasflagval(o->flags, omf->id, omf->val[0], omf->val[1], omf->val[2], NULL)) {
found = B_FALSE;
break;
}
}
return found;
}
object_t *hasobmulti(obpile_t *op, enum OBTYPE *oid, int noids) {
object_t *o;
int n;
for (o = op->first ; o ; o = o->next) {
for (n = 0; n < noids; n++) {
if (o->type->id == oid[n]) return o;
}
}
return NULL;
}
object_t *hasobwithflag(obpile_t *op, enum FLAG flagid) {
object_t *o;
for (o = op->first ; o ; o = o->next) {
if (hasflag(o->flags, flagid)) return o;
}
return NULL;
}
object_t *hasobwithflagval(obpile_t *op, enum FLAG flagid, int val0, int val1, int val2, char *text) {
object_t *o;
for (o = op->first ; o ; o = o->next) {
if (hasflagval(o->flags, flagid, val0, val1, val2, text)) return o;
}
return NULL;
}
object_t *hasobid(obpile_t *op, int id) {
object_t *o;
for (o = op->first ; o ; o = o->next) {
if (o->id == id) return o;
}
return NULL;
}
// fully identify a single object.
void identify(object_t *o) {
flag_t *f;
if (!isknown(o) && (o->type->obclass->id != OC_BOOK)) {
makeknown(o->type->id);
}
addflag(o->flags, F_IDENTIFIED, B_TRUE, -1, -1, NULL);
o->blessknown = B_TRUE;
for (f = o->flags->first ; f ; f = f->next) {
if (!f->known) f->known = B_TRUE;
}
}
void ignite(object_t *o) {
flag_t *ff;
char convertto[BUFLEN];
int howlong = 3; // default
strcpy(convertto, ""); // default
ff = hasflag(o->flags, F_FLAMMABLE);
if (ff) {
howlong = ff->val[0];
strcpy(convertto, ff->text);
}
if (!hasflag(o->flags, F_ONFIRE)) {
if (strlen(convertto)) {
cell_t *where;
object_t *newob;
where = getoblocation(o);
// change
newob = addob(where->obpile, convertto);
if (newob) {
// announce
if (haslos(player, where)) {
char obname[BUFLEN];
char newobname[BUFLEN];
getobname(o, obname, o->amt);
getobname(newob, newobname, newob->amt);
msg("%s ignites into %s!",obname,newobname);
}
// kill old ob
addflag(o->flags, F_DEAD, B_TRUE, NA, NA, NULL);
addflag(o->flags, F_NOOBDIETEXT, B_TRUE, NA, NA, NULL);
}
} else {
// make it damagable, if it isn't already.
if (!hasflag(o->flags, F_DAMAGABLE)) {
addflag(o->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL);
}
// on fire for 3 turns
addtempflag(o->flags, F_ONFIRE, B_TRUE, NA, NA, NULL, howlong);
}
}
}
void initobjects(void) {
//int ch;
int i,n;
// generate hidden name text
for (n = 0; strlen(colour[n].name); n++) {
char buf[BUFLEN];
// add it without an adjective
snprintf(buf, BUFLEN, "%s book", colour[n].name);
addhiddenname(OC_BOOK, buf);
// add it with all known adjectives
for (i = 0; strlen(bookadjective[i]) ; i++) {
snprintf(buf, BUFLEN, "%s %s book",bookadjective[i], colour[n].name);
addhiddenname(OC_BOOK, buf);
}
}
addhiddenname(OC_SCROLL, "scroll titled ABRA CA DABRA");
addhiddenname(OC_SCROLL, "scroll titled BARBAR");
addhiddenname(OC_SCROLL, "scroll titled CRATOL JEM");
addhiddenname(OC_SCROLL, "scroll titled DELENTH YIN");
addhiddenname(OC_SCROLL, "scroll titled ETEE NOM");
addhiddenname(OC_SCROLL, "scroll titled FIE JOOHM");
addhiddenname(OC_SCROLL, "scroll titled GREE VII");
addhiddenname(OC_SCROLL, "scroll titled HERE HERE");
addhiddenname(OC_SCROLL, "scroll titled HTEB IH");
addhiddenname(OC_SCROLL, "scroll titled HOCUS POCUS");
addhiddenname(OC_SCROLL, "scroll titled ILU-MA ZEE");
addhiddenname(OC_SCROLL, "scroll titled JUNIPO CHECK");
addhiddenname(OC_SCROLL, "scroll titled KARELS");
addhiddenname(OC_SCROLL, "scroll titled LUMLEE GWON");
addhiddenname(OC_SCROLL, "scroll titled MARIGON");
addhiddenname(OC_SCROLL, "scroll titled MAXIMOR BLATHUS");
addhiddenname(OC_SCROLL, "scroll titled NORTH");
addhiddenname(OC_SCROLL, "scroll titled ORI GREEBLE");
addhiddenname(OC_SCROLL, "scroll titled POCUS HOCUS");
addhiddenname(OC_SCROLL, "scroll titled QUANDRILAR");
addhiddenname(OC_SCROLL, "scroll titled REZZ KINETO");
addhiddenname(OC_SCROLL, "scroll titled SHAZZARIO");
addhiddenname(OC_SCROLL, "scroll titled THERIUM LARGOS");
addhiddenname(OC_SCROLL, "scroll titled TAKA TAKA TAKA");
addhiddenname(OC_SCROLL, "scroll titled UNDWEL");
addhiddenname(OC_SCROLL, "scroll titled VOLTR YI MEN");
addhiddenname(OC_SCROLL, "scroll titled WII");
addhiddenname(OC_SCROLL, "scroll titled XAND");
addhiddenname(OC_SCROLL, "scroll titled YES");
addhiddenname(OC_SCROLL, "scroll titled ZAREL NOR");
for (n = 0; strlen(colour[n].name); n++) {
char buf[BUFLEN];
// add it without an adjective
snprintf(buf, BUFLEN, "%s potion", colour[n].name);
addhiddenname(OC_POTION, buf);
// add it with all known adjectives
for (i = 0; strlen(potadjective[i]) ; i++) {
snprintf(buf, BUFLEN, "%s %s potion",potadjective[i], colour[n].name);
addhiddenname(OC_POTION, buf);
}
}
for (n = 0; strlen(gemtype[n].name); n++) {
char buf[BUFLEN];
// add it without an adjective
snprintf(buf, BUFLEN, "%s wand", gemtype[n].name);
addhiddenname(OC_WAND, buf);
}
for (n = 0; strlen(gemtype[n].name); n++) {
char buf[BUFLEN];
// add it without an adjective
snprintf(buf, BUFLEN, "%s ring", gemtype[n].name);
addhiddenname(OC_RING, buf);
}
for (n = 0; strlen(technoun[n]); n++) {
// add it without an adjective
addhiddenname(OC_TECH, technoun[n]);
// add it with all known adjectives
for (i = 0; strlen(techadjective[i]) ; i++) {
char buf[BUFLEN];
snprintf(buf, BUFLEN, "%s %s",techadjective[i], technoun[n]);
addhiddenname(OC_TECH, buf);
}
}
shufflehiddennames();
// object modifiers - flags can be either known or not, depending on if it's obvious
addobmod(OM_BLOODSTAINED,"bloodstained");
addflag_real(lastobmod->flags, F_SCARY, 2, NA, NA, NULL, PERMENANT, B_KNOWN, -1);
addobmod(OM_FLAMING,"flaming");
addflag_real(lastobmod->flags, F_ONFIRE, B_TRUE, NA, NA, NULL, PERMENANT, B_KNOWN, -1);
addobmod(OM_FROZEN,"frozen");
addflag_real(lastobmod->flags, F_FROZEN, B_TRUE, NA, NA, NULL, PERMENANT, B_KNOWN, -1);
addobmod(OM_HEADLESS,"headless");
addflag_real(lastobmod->flags, F_HEADLESS, B_TRUE, NA, NA, NULL, PERMENANT, B_KNOWN, -1);
addobmod(OM_MASTERWORK,"masterwork");
addflag_real(lastobmod->flags, F_MASTERWORK, B_TRUE, NA, NA, NULL, PERMENANT, B_KNOWN, -1);
addobmod(OM_SHODDY,"shoddy");
addflag_real(lastobmod->flags, F_SHODDY, B_TRUE, NA, NA, NULL, PERMENANT, B_KNOWN, -1);
addobmod(OM_POISONED,"poisoned");
addflag_real(lastobmod->flags, F_HITCONFER, F_POISONED, SC_POISON, 25, "15-30", PERMENANT, B_KNOWN, -1);
addflag_real(lastobmod->flags, F_HITCONFERVALS, P_VENOM, 1, NA, NULL, PERMENANT, B_KNOWN, -1);
addobmod(OM_WET1,"damp");
addflag_real(lastobmod->flags, F_WET, W_DAMP, NA, NA, NULL, PERMENANT, B_KNOWN, -1);
addobmod(OM_WET2,"wet");
addflag_real(lastobmod->flags, F_WET, W_WET, NA, NA, NULL, PERMENANT, B_KNOWN, -1);
addobmod(OM_WET3,"soaked");
addflag_real(lastobmod->flags, F_WET, W_SOAKED, NA, NA, NULL, PERMENANT, B_KNOWN, -1);
addobmod(OM_RUSTY1,"rusty");
addflag_real(lastobmod->flags, F_RUSTED, R_RUSTY, NA, NA, NULL, PERMENANT, B_KNOWN, -1);
addobmod(OM_RUSTY2,"very rusty");
addflag_real(lastobmod->flags, F_RUSTED, R_VRUSTY, NA, NA, NULL, PERMENANT, B_KNOWN, -1);
addobmod(OM_RUSTY3,"thoroughly rusty");
addflag_real(lastobmod->flags, F_RUSTED, R_TRUSTY, NA, NA, NULL, PERMENANT, B_KNOWN, -1);
// brands modifiers - flags should be UNKNOWN!
// also don't double up with names of scrolls etc.
// ie. spellbook of flight, boots of flight.
// weapons
addbrand(BR_BALANCE, "of balance", BP_WEAPON);
addflag_real(lastbrand->flags, F_BALANCE, B_TRUE, NA, NA, NULL, PERMENANT, B_UNKNOWN, -1);
addbrand(BR_PYROMANIA, "of pyromania", BP_WEAPON);
addflag_real(lastbrand->flags, F_FLAMESTRIKE, B_TRUE, NA, NA, NULL, PERMENANT, B_UNKNOWN, -1);
addbrand(BR_REVENGE, "of revenge", BP_WEAPON);
addflag_real(lastbrand->flags, F_REVENGE, B_TRUE, NA, NA, NULL, PERMENANT, B_UNKNOWN, -1);
addbrand(BR_SHARPNESS, "of sharpness", BP_WEAPON);
addflag_real(lastbrand->flags, F_ARMOURPIERCE, B_TRUE, NA, NA, NULL, PERMENANT, B_UNKNOWN, -1);
addbrand(BR_IMPACT, "of impact", BP_WEAPON); // TODO: make thisonly go ont obashing weapons
addflag_real(lastbrand->flags, F_HEAVYBLOW, B_TRUE, NA, NA, NULL, PERMENANT, B_UNKNOWN, -1);
// feet
addbrand(BR_LEVITATION, "of hovering", BP_FEET);
addflag_real(lastbrand->flags, F_EQUIPCONFER, F_LEVITATING, NA, NA, NULL, PERMENANT, B_UNKNOWN, -1);
addbrand(BR_FEATHERFALL, "of featherfall", BP_FEET);
addflag_real(lastbrand->flags, F_EQUIPCONFER, F_DTIMMUNE, DT_FALL, NA, NULL, PERMENANT, B_UNKNOWN, -1);
addbrand(BR_SWIFTNESS, "of swiftness", BP_FEET);
addflag_real(lastbrand->flags, F_EQUIPCONFER, F_FASTMOVE, 5, NA, NULL, PERMENANT, B_UNKNOWN, -1);
addbrand(BR_SLOTH, "of sloth", BP_FEET);
addflag_real(lastbrand->flags, F_EQUIPCONFER, F_SLOWMOVE, 5, NA, NULL, PERMENANT, B_UNKNOWN, -1);
addbrand(BR_STEALTH, "of stealth", BP_FEET);
addflag_real(lastbrand->flags, F_EQUIPCONFER, F_SILENTMOVE, B_TRUE, NA, NULL, PERMENANT, B_UNKNOWN, -1);
// hands
addbrand(BR_POWER, "of power", BP_HANDS);
addflag_real(lastbrand->flags, F_EQUIPCONFER, F_ATTRMOD, A_STR, 3, NULL, PERMENANT, B_UNKNOWN, -1);
addbrand(BR_WEAKNESS, "of feebleness", BP_HANDS);
addflag_real(lastbrand->flags, F_EQUIPCONFER, F_ATTRMOD, A_STR, -3, NULL, PERMENANT, B_UNKNOWN, -1);
addbrand(BR_NIMBLENESS, "of nimbleness", BP_HANDS);
addflag_real(lastbrand->flags, F_EQUIPCONFER, F_ATTRMOD, A_DEX, 3, NULL, PERMENANT, B_UNKNOWN, -1);
// head
addbrand(BR_THINKING, "of thinking", BP_HEAD);
addflag_real(lastbrand->flags, F_EQUIPCONFER, F_ATTRMOD, A_IQ, 3, NULL, PERMENANT, B_UNKNOWN, -1);
addbrand(BR_KNOWLEDGE, "of knowledge", BP_HEAD);
addflag_real(lastbrand->flags, F_EQUIPCONFER, F_DETECTAURAS, B_TRUE, NA, NULL, PERMENANT, B_UNKNOWN, -1);
addflag_real(lastbrand->flags, F_EQUIPCONFER, F_DETECTMAGIC, B_TRUE, NA, NULL, PERMENANT, B_UNKNOWN, -1);
addbrand(BR_TELEPATHY, "of telepathy", BP_HEAD);
addflag_real(lastbrand->flags, F_EQUIPCONFER, F_DETECTLIFE, 5, NA, NULL, PERMENANT, B_UNKNOWN, -1);
addbrand(BR_TELEKINESIS, "of the poltergeist", BP_HEAD);
addflag_real(lastbrand->flags, F_EQUIPCONFER, F_CANWILL, OT_S_TELEKINESIS, NA, NULL, PERMENANT, B_UNKNOWN, -1);
// waist
addbrand(BR_GIANTSTRENGTH, "of giant strength", BP_WAIST);
addflag_real(lastbrand->flags, F_EQUIPCONFER, F_ATTRSET, A_STR, 18, NULL, PERMENANT, B_UNKNOWN, -1);
addbrand(BR_FEEBLENESS, "of feebleness", BP_WAIST);
addflag_real(lastbrand->flags, F_EQUIPCONFER, F_ATTRSET, A_STR, 3, NULL, PERMENANT, B_UNKNOWN, -1);
addbrand(BR_FLIGHT, "of the eagle", BP_WAIST);
addflag_real(lastbrand->flags, F_EQUIPCONFER, F_FLYING, B_TRUE, NA, NULL, PERMENANT, B_UNKNOWN, -1);
addbrand(BR_SPEED, "of swiftness", BP_WAIST);
addflag_real(lastbrand->flags, F_EQUIPCONFER, F_FASTACT, 5, NA, NULL, PERMENANT, B_UNKNOWN, -1);
// shoulders
addbrand(BR_CONCEALMENT, "of concealment", BP_SHOULDERS);
addflag_real(lastbrand->flags, F_EQUIPCONFER, F_INVISIBLE, B_TRUE, NA, NULL, PERMENANT, B_UNKNOWN, -1);
addbrand(BR_ANTIMAG, "of antimagic", BP_SHOULDERS);
addflag_real(lastbrand->flags, F_EQUIPCONFER, F_RESISTMAG, 10, NA, NULL, PERMENANT, B_UNKNOWN, -1);
addbrand(BR_SHADOWS, "of shadows", BP_SHOULDERS);
addflag_real(lastbrand->flags, F_EQUIPCONFER, F_CANWILL, OT_A_DARKWALK, NA, NULL, PERMENANT, B_UNKNOWN, -1);
// body
addbrand(BR_HEALTH, "of health", BP_BODY);
addflag_real(lastbrand->flags, F_EQUIPCONFER, F_ATTRMOD, A_CON, 3, NULL, PERMENANT, B_UNKNOWN, -1);
// materials
addmaterial(MT_NOTHING, "nothing", 0);
addmaterial(MT_MAGIC, "magical energy", 0);
addmaterial(MT_FIRE, "fire", 0);
addmaterial(MT_GAS, "gas", 0.5);
addmaterial(MT_WIRE, "wire", 1);
addflag(lastmaterial->flags, F_DTIMMUNE, DT_BASH, NA, NA, NULL);
addflag(lastmaterial->flags, F_DTIMMUNE, DT_COLD, NA, NA, NULL);
addflag(lastmaterial->flags, F_DTIMMUNE, DT_PROJECTILE, NA, NA, NULL);
addflag(lastmaterial->flags, F_DTIMMUNE, DT_HOLY, NA, NA, NULL);
addflag(lastmaterial->flags, F_DTIMMUNE, DT_WATER, NA, NA, NULL);
addflag(lastmaterial->flags, F_DTIMMUNE, DT_MELT, NA, NA, NULL);
addflag(lastmaterial->flags, F_DTIMMUNE, DT_ELECTRIC, NA, NA, NULL);
addflag(lastmaterial->flags, F_DTIMMUNE, DT_DECAY, NA, NA, NULL);
addflag(lastmaterial->flags, F_DTIMMUNE, DT_POISON, NA, NA, NULL);
addflag(lastmaterial->flags, F_DTIMMUNE, DT_POISONGAS, NA, NA, NULL);
addflag(lastmaterial->flags, F_DTIMMUNE, DT_UNARMED, NA, NA, NULL);
addflag(lastmaterial->flags, F_DTIMMUNE, DT_LIGHT, NA, NA, NULL);
addflag(lastmaterial->flags, F_DTIMMUNE, DT_NECROTIC, NA, NA, NULL);
addmaterial(MT_PLANT, "plant matter", 1);
addflag(lastmaterial->flags, F_FLAMMABLE, PERMENANT, NA, NA, NULL);
addflag(lastmaterial->flags, F_DTVULN, DT_FIRE, NA, NA, NULL);
addflag(lastmaterial->flags, F_DTVULN, DT_ACID, NA, NA, NULL);
addflag(lastmaterial->flags, F_DTIMMUNE, DT_WATER, NA, NA, NULL);
addmaterial(MT_PAPER, "paper", 1);
addflag(lastmaterial->flags, F_MATCONVERT, MT_WATER, NA, NA, "lump of soggy paper");
addflag(lastmaterial->flags, F_MATCONVERTTEXT, MT_WATER, NA, NA, "goes soggy");
addflag(lastmaterial->flags, F_MATCONVERTTEXTPL, MT_WATER, NA, NA, "go soggy");
addflag(lastmaterial->flags, F_FLAMMABLE, PERMENANT, NA, NA, NULL);
addflag(lastmaterial->flags, F_DTVULN, DT_FIRE, NA, NA, NULL);
addmaterial(MT_SILK, "silk", 1);
addflag(lastmaterial->flags, F_FLAMMABLE, 6, NA, NA, NULL);
addflag(lastmaterial->flags, F_DTVULN, DT_FIRE, NA, NA, NULL); // doesn't catch on fire, but IS vulnerable to it
addflag(lastmaterial->flags, F_DTVULN, DT_ACID, NA, NA, NULL);
addmaterial(MT_FLESH, "flesh", 2);
addflag(lastmaterial->flags, F_FLAMMABLE, 3, NA, NA, NULL);
addmaterial(MT_WETPAPER, "wet paper", 3);
addmaterial(MT_CLOTH, "cloth", 3);
addflag(lastmaterial->flags, F_FLAMMABLE, 3, NA, NA, NULL);
addflag(lastmaterial->flags, F_CANGETWET, B_TRUE, NA, NA, NULL);
addflag(lastmaterial->flags, F_DTIMMUNE, DT_BASH, NA, NA, NULL);
addflag(lastmaterial->flags, F_DTVULN, DT_FIRE, NA, NA, NULL); // doesn't catch on fire, but IS vulnerable to it
addmaterial(MT_FOOD, "food", 3);
addmaterial(MT_PLASTIC, "plastic", 3);
addflag(lastmaterial->flags, F_HARDNESS, 2, NA, NA, NULL);
addmaterial(MT_WAX, "wax", 3);
addflag(lastmaterial->flags, F_MATCONVERT, MT_FIRE, NA, NA, "lump of melted wax");
addflag(lastmaterial->flags, F_MATCONVERTTEXT, MT_FIRE, NA, NA, "melts");
addflag(lastmaterial->flags, F_MATCONVERTTEXTPL, MT_FIRE, NA, NA, "melt");
addmaterial(MT_RUBBER, "rubber", 4);
addmaterial(MT_LEATHER, "leather", 4);
addflag(lastmaterial->flags, F_CANGETWET, B_TRUE, NA, NA, NULL);
addflag(lastmaterial->flags, F_DTIMMUNE, DT_BASH, NA, NA, NULL);
addmaterial(MT_BONE, "bone", 5);
addflag(lastmaterial->flags, F_HARDNESS, 3, NA, NA, NULL);
addmaterial(MT_OIL, "oil", 5);
addmaterial(MT_ICE, "ice",6);
addflag(lastmaterial->flags, F_HARDNESS, 3, NA, NA, NULL);
addmaterial(MT_WOOD, "wood", 6);
addflag(lastmaterial->flags, F_HARDNESS, 3, NA, NA, NULL);
addflag(lastmaterial->flags, F_FLAMMABLE, 5, NA, NA, NULL);
addflag(lastmaterial->flags, F_CANGETWET, B_TRUE, NA, NA, NULL);
addmaterial(MT_ACID, "acid", 7);
addmaterial(MT_WATER, "water", 7);
addmaterial(MT_BLOOD, "blood", 7);
addmaterial(MT_SLIME, "slime", 9);
addmaterial(MT_STONE, "stone", 10);
addflag(lastmaterial->flags, F_HARDNESS, 4, NA, NA, NULL);
addflag(lastmaterial->flags, F_DTIMMUNE, DT_FIRE, NA, NA, NULL);
addflag(lastmaterial->flags, F_DTIMMUNE, DT_PIERCE, NA, NA, NULL);
addflag(lastmaterial->flags, F_DTIMMUNE, DT_BITE, NA, NA, NULL);
addflag(lastmaterial->flags, F_DTIMMUNE, DT_SLASH, NA, NA, NULL);
addflag(lastmaterial->flags, F_DTRESIST, DT_CHOP, NA, NA, NULL);
addflag(lastmaterial->flags, F_DTRESIST, DT_PROJECTILE, NA, NA, NULL);
addmaterial(MT_SILVER, "silver", 11);
addflag(lastmaterial->flags, F_HARDNESS, 2, NA, NA, NULL);
addmaterial(MT_METAL, "metal", 13);
addflag(lastmaterial->flags, F_HARDNESS, 5, NA, NA, NULL);
addflag(lastmaterial->flags, F_DTIMMUNE, DT_FIRE, NA, NA, NULL);
addflag(lastmaterial->flags, F_DTRESIST, DT_BITE, NA, NA, NULL);
addflag(lastmaterial->flags, F_DTRESIST, DT_PIERCE, NA, NA, NULL);
addflag(lastmaterial->flags, F_DTRESIST, DT_SLASH, NA, NA, NULL);
addflag(lastmaterial->flags, F_DTRESIST, DT_PROJECTILE, NA, NA, NULL);
addmaterial(MT_GLASS, "glass", 13);
addflag(lastmaterial->flags, F_HARDNESS, 2, NA, NA, NULL);
addflag(lastmaterial->flags, F_DTVULN, DT_BASH, NA, NA, NULL);
addflag(lastmaterial->flags, F_DTVULN, DT_COLD, NA, NA, NULL);
addmaterial(MT_GOLD, "gold", 16);
addflag(lastmaterial->flags, F_HARDNESS, 3, NA, NA, NULL);
// object classes
addoc(OC_DFEATURE, "Dungeon Features", "Doors, etc.", '\\', C_GREY);
addoc(OC_FURNITURE, "Furniture", "Various kinds of mundane (or not so mundane) furnishings.", '\\', C_BROWN);
addocnoun(lastobjectclass, "furniture");
addoc(OC_TERRAIN, "Terrain", "Water, etc.", '\\', C_GREY);
addoc(OC_TRAP, "Trap", "Fiendish traps.", '^', C_GREY);
addocnoun(lastobjectclass, "trap");
addoc(OC_MONEY, "Money", "The standard currency of Nexus.", '$', C_GREY);
addoc(OC_SCROLL, "Scrolls", "An arcane roll of parchment, inscribed with many magical glyphs.", '?', C_GREY);
addocnoun(lastobjectclass, "scroll");
addflag(lastobjectclass->flags, F_HASHIDDENNAME, B_TRUE, NA, NA, NULL);
addflag(lastobjectclass->flags, F_STACKABLE, B_TRUE, NA, NA, NULL);
addflag(lastobjectclass->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL);
//addflag(lastobjectclass->flags, F_DTCONVERT, DT_WATER, NA, NA, "lump of soggy paper");
//addflag(lastobjectclass->flags, F_MATCONVERT, MT_WATER, NA, NA, "lump of soggy paper");
//addflag(lastobjectclass->flags, F_MATCONVERTTEXT, MT_WATER, NA, NA, "goes soggy");
//addflag(lastobjectclass->flags, F_MATCONVERTTEXTPL, MT_WATER, NA, NA, "go soggy");
addoc(OC_WAND, "Wands", "A limited-use magical wand which casts the imbued spell.", '/', C_GREY);
addocnoun(lastobjectclass, "wand");
addflag(lastobjectclass->flags, F_DTIMMUNE, DT_FIRE, NA, NA, NULL);
addflag(lastobjectclass->flags, F_HASHIDDENNAME, B_TRUE, NA, NA, NULL);
addflag(lastobjectclass->flags, F_OPERABLE, B_TRUE, NA, NA, NULL);
addflag(lastobjectclass->flags, F_OPERWITHOUTID, B_TRUE, NA, NA, NULL);
addflag(lastobjectclass->flags, F_OPERUSECHARGE, B_TRUE, NA, NA, NULL);
addflag(lastobjectclass->flags, F_RNDCHARGES, 1, 8, NA, NULL);
addoc(OC_POTION, "Potions", "A strange concoction contained within a small flask.", '!', C_GREY);
addocnoun(lastobjectclass, "potion");
addflag(lastobjectclass->flags, F_HASHIDDENNAME, B_TRUE, NA, NA, NULL);
addflag(lastobjectclass->flags, F_STACKABLE, B_TRUE, NA, NA, NULL);
addflag(lastobjectclass->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL);
addflag(lastobjectclass->flags, F_POURABLE, B_TRUE, NA, NA, NULL);
addflag(lastobjectclass->flags, F_DRINKABLE, B_TRUE, NA, NA, NULL);
addoc(OC_RING, "Rings", "A circular band, worn on the finger.", '=', C_GREY);
addocnoun(lastobjectclass, "ring");
addflag(lastobjectclass->flags, F_HASHIDDENNAME, B_TRUE, NA, NA, NULL);
addflag(lastobjectclass->flags, F_GOESON, BP_RIGHTFINGER, NA, NA, NULL);
addflag(lastobjectclass->flags, F_GOESON, BP_LEFTFINGER, NA, NA, NULL);
addoc(OC_WEAPON, "Weapons", "An instrument used for the purpose of causing harm or death.", ')', C_GREY);
addocnoun(lastobjectclass, "weapon");
addflag(lastobjectclass->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL);
addflag(lastobjectclass->flags, F_ENCHANTABLE, B_TRUE, NA, NA, NULL);
addflag(lastobjectclass->flags, F_CANHAVEOBMOD, OM_MASTERWORK, 17, NA, NULL);
addflag(lastobjectclass->flags, F_CANHAVEOBMOD, OM_SHODDY, 34, NA, NULL);
addoc(OC_ARMOUR, "Armour/Clothing", "Protective gear.", ']', C_GREY);
addocnoun(lastobjectclass, "armour");
addocnoun(lastobjectclass, "clothing");
addocnoun(lastobjectclass, "clothes");
addflag(lastobjectclass->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL);
addflag(lastobjectclass->flags, F_ENCHANTABLE, B_TRUE, NA, NA, NULL);
addflag(lastobjectclass->flags, F_CANHAVEOBMOD, OM_MASTERWORK, 17, NA, NULL);
addflag(lastobjectclass->flags, F_CANHAVEOBMOD, OM_SHODDY, 34, NA, NULL);
addflag(lastobjectclass->flags, F_CANHAVEOBMOD, OM_BLOODSTAINED, 17, NA, NULL);
addoc(OC_MISSILE, "Missiles/Ammunition", "An instrument used for the purpose of causing harm or death.", ';', C_GREY);
addocnoun(lastobjectclass, "missile");
addocnoun(lastobjectclass, "ammo");
addocnoun(lastobjectclass, "ammunition");
addflag(lastobjectclass->flags, F_ENCHANTABLE, B_TRUE, NA, NA, NULL);
addflag(lastobjectclass->flags, F_STACKABLE, B_TRUE, NA, NA, NULL);
addflag(lastobjectclass->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL);
addoc(OC_FLORA, "Plants", "Some kind of plant/foliage.", ',', C_GREEN);
addocnoun(lastobjectclass, "plant");
addoc(OC_ROCK, "Rocks/Gems", "Boring (or not so boring) rocks or plants.", '*', C_GREY);
addoc(OC_FOOD, "Food", "Yum!", '%', C_GREY);
addocnoun(lastobjectclass, "food");
addflag(lastobjectclass->flags, F_STACKABLE, B_TRUE, NA, NA, "");
addflag(lastobjectclass->flags, F_NOBLESS, B_TRUE, NA, NA, NULL);
addoc(OC_GODSTONE, "Godstones", "Ancient artifacts, created by the elder gods.", '*', C_BOLDMAGENTA);
addflag(lastobjectclass->flags, F_UNIQUE, NA, NA, NA, NULL);
addflag(lastobjectclass->flags, F_HASHIDDENNAME, B_TRUE, NA, NA, "pulsating purple stone");
addflag(lastobjectclass->flags, F_UNIQUE, NA, NA, NA, NULL);
addflag(lastobjectclass->flags, F_INVULNERABLE, B_TRUE, NA, NA, NULL);
addflag(lastobjectclass->flags, F_OPERABLE, B_TRUE, NA, NA, NULL);
addflag(lastobjectclass->flags, F_NOBLESS, B_TRUE, NA, NA, NULL);
addoc(OC_CORPSE, "Corpses", "Dead flesh which was once living.", '%', C_GREY);
addflag(lastobjectclass->flags, F_STACKABLE, B_TRUE, NA, NA, "");
addflag(lastobjectclass->flags, F_NOBLESS, B_TRUE, NA, NA, NULL);
addflag(lastobjectclass->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL);
addflag(lastobjectclass->flags, F_OBHP, 50, 50, NA, NULL);
addflag(lastobjectclass->flags, F_OBHPDRAIN, 1, DT_DECAY, NA, NULL); // ie. corpses last for 50 turns
addoc(OC_TECH, "Technology", "A strange piece of futuristic technology.", '[', C_GREY);
addocnoun(lastobjectclass, "technology");
addocnoun(lastobjectclass, "tech");
addflag(lastobjectclass->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL);
addflag(lastobjectclass->flags, F_NOBLESS, B_TRUE, NA, NA, NULL);
addoc(OC_TOOLS, "Tools", "Useful items, from the common to the obscure.", '[', C_GREY);
addocnoun(lastobjectclass, "tool");
addflag(lastobjectclass->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL);
addflag(lastobjectclass->flags, F_NOBLESS, B_TRUE, NA, NA, NULL);
addoc(OC_MISC, "Miscellaneous", "This could be anything.", '\\', C_GREY);
addoc(OC_EFFECT, "Environmental Effects", "Smoke, fire, etc.", '}', C_GREY);
addflag(lastobjectclass->flags, F_NOBLESS, B_TRUE, NA, NA, NULL);
addflag(lastobjectclass->flags, F_NOPICKUP, B_TRUE, NA, NA, NULL);
addoc(OC_BOOK, "Books", "Spellbooks, tomes or manuals.", '+', C_GREY);
addocnoun(lastobjectclass, "spellbook");
addocnoun(lastobjectclass, "book");
addocnoun(lastobjectclass, "tome");
addflag(lastobjectclass->flags, F_HASHIDDENNAME, B_TRUE, NA, NA, NULL);
addflag(lastobjectclass->flags, F_NOBLESS, B_TRUE, NA, NA, NULL);
addoc(OC_SPELL, "Spells", "A magical spell", '&', C_GREY); // this is a "virtual" object class
addoc(OC_ABILITY, "Abilities", "A special ability", '&', C_GREY); // this is a "virtual" object class
// object types
// dungeon features
addot(OT_DOORWOOD, "wooden door", "A sturdy wooden door.", MT_WOOD, 150, OC_DFEATURE, SZ_LARGE);
// GLYPH here is a special case in getglyph
addflag(lastot->flags, F_DOOR, SZ_MIN, SZ_MAX, NA, NULL);
addflag(lastot->flags, F_IMPASSABLE, SZ_MIN, SZ_MAX, NA, NULL);
addflag(lastot->flags, F_BLOCKSVIEW, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_BLOCKSLOF, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_LOCKABLE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_CANBETRAPPED, 5, 10, 60, NULL);
addflag(lastot->flags, F_OBHP, 20, 20, NA, NULL);
addflag(lastot->flags, F_DTVULN, DT_BASH, NA, NA, NULL);
addflag(lastot->flags, F_DTVULN, DT_CHOP, NA, NA, NULL);
addot(OT_DOORIRON, "iron door", "A strong iron door.", MT_METAL, 300, OC_DFEATURE, SZ_LARGE);
// GLYPH here is a special case in getglyph
addflag(lastot->flags, F_DOOR, SZ_MIN, SZ_MAX, NA, NULL);
addflag(lastot->flags, F_IMPASSABLE, SZ_MIN, SZ_MAX, NA, NULL);
addflag(lastot->flags, F_BLOCKSVIEW, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_BLOCKSLOF, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_LOCKABLE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_CANBETRAPPED, 10, 10, 60, NULL);
addflag(lastot->flags, F_OBHP, 60, 60, NA, NULL);
addflag(lastot->flags, F_DTIMMUNE, DT_PIERCE, NA, NA, NULL);
addflag(lastot->flags, F_DTIMMUNE, DT_SLASH, NA, NA, NULL);
addflag(lastot->flags, F_DTRESIST, DT_CHOP, NA, NA, NULL);
addot(OT_FOUNTAIN, "fountain", "A running fountain of some kind of liquid.", MT_WATER, 20, OC_MISC, SZ_MEDIUM);
addflag(lastot->flags, F_STACKABLE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_GLYPH, C_BLUE, NA, NA, "_");
addflag(lastot->flags, F_RARITY, H_VILLAGE, 100, RR_COMMON, NULL);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 90, RR_UNCOMMON, NULL);
addflag(lastot->flags, F_NOPICKUP, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_DTCONVERT, DT_COLD, NA, NA, "sheet of ice");
addflag(lastot->flags, F_DTCREATEOB, DT_FIRE, 0, DT_COMPASS, "cloud of steam");
addflag(lastot->flags, F_DRINKABLE, B_TRUE, NA, B_DONTKILL, NULL);
addflag(lastot->flags, F_LINKOB, OT_POT_WATER, NA, NA, NULL);
// blocks movement, but you can see and fire through them.
addot(OT_GATEIRON, "iron gate", "A gate comprised of a series of vertical iron bars, raised slightly above the floor.", MT_METAL, 500, OC_DFEATURE, SZ_LARGE);
addflag(lastot->flags, F_GLYPH, C_GREY, NA, NA, "+");
addflag(lastot->flags, F_DOOR, SZ_MEDIUM, SZ_MAX, NA, NULL);
addflag(lastot->flags, F_IMPASSABLE, SZ_MEDIUM, SZ_MAX, NA, NULL);
addflag(lastot->flags, F_LOCKABLE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_NOPICKUP, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_OBHP, 120, 120, NA, NULL);
addflag(lastot->flags, F_DTIMMUNE, DT_PIERCE, NA, NA, NULL);
addflag(lastot->flags, F_DTIMMUNE, DT_SLASH, NA, NA, NULL);
addflag(lastot->flags, F_DTRESIST, DT_CHOP, NA, NA, NULL);
addot(OT_GATEWOOD, "wooden gate", "A gate comprised of a series of wooden slats.", MT_WOOD, 200, OC_DFEATURE, SZ_LARGE);
addflag(lastot->flags, F_GLYPH, C_BROWN, NA, NA, "+");
addflag(lastot->flags, F_DOOR, SZ_MIN, SZ_MAX, NA, NULL);
addflag(lastot->flags, F_IMPASSABLE, SZ_MIN, SZ_MAX, NA, NULL);
addflag(lastot->flags, F_LOCKABLE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_NOPICKUP, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_OBHP, 30, 30, NA, NULL);
addflag(lastot->flags, F_DTVULN, DT_CHOP, NA, NA, NULL);
addot(OT_FENCEWOOD, "wooden fence", "A tell fence created from a series of upright logs of wood.", MT_WOOD, 200, OC_DFEATURE, SZ_LARGE);
addflag(lastot->flags, F_IMPASSABLE, SZ_MIN, SZ_MAX, NA, NULL);
addflag(lastot->flags, F_BLOCKSVIEW, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_BLOCKSLOF, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_LOCKABLE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_OBHP, 30, 30, NA, NULL);
addflag(lastot->flags, F_DTVULN, DT_CHOP, NA, NA, NULL);
addot(OT_BOULDER, "boulder", "A massive stone boulder.", MT_STONE, 80, OC_ROCK, SZ_HUGE);
addflag(lastot->flags, F_RARITY, H_ALL, 75, NA, "");
addflag(lastot->flags, F_GLYPH, NA, NA, NA, "'");
addflag(lastot->flags, F_IMPASSABLE, SZ_MIN, SZ_LARGE, NA, NULL);
addflag(lastot->flags, F_PUSHABLE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_BLOCKSVIEW, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_BLOCKSLOF, B_TRUE, NA, NA, NULL);
// addflag(lastot->flags, F_NOPICKUP, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_THROWMISSILE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_OBHP, 80, 80, NA, NULL);
addflag(lastot->flags, F_DIECONVERT, NA, NA, NA, "50-100 stones");
addot(OT_ICICLE, "huge icicle", "A massive ice stalacmite.", MT_ICE, 200, OC_ROCK, SZ_LARGE);
addflag(lastot->flags, F_GLYPH, C_CYAN, NA, NA, "'");
addflag(lastot->flags, F_IMPASSABLE, SZ_MIN, SZ_LARGE, NA, NULL);
addflag(lastot->flags, F_BLOCKSVIEW, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_BLOCKSLOF, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_OBHP, 80, 80, NA, NULL);
addot(OT_STATUE, "statue", "A stone statue of a monster.", MT_STONE, 80, OC_ROCK, SZ_HUMAN);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 75, NA, "");
addflag(lastot->flags, F_RARITY, H_VILLAGE, 80, NA, "");
addflag(lastot->flags, F_GLYPH, NA, NA, NA, "'");
addflag(lastot->flags, F_IMPASSABLE, SZ_MIN, SZ_LARGE, NA, NULL); // will be overridden
addflag(lastot->flags, F_PUSHABLE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_BLOCKSLOF, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_OBHP, 80, 80, NA, NULL);
addflag(lastot->flags, F_DIECONVERT, NA, NA, NA, "20-50 stones");
addflag(lastot->flags, F_FEELTEXT, NA, NA, NA, "a statue");
addot(OT_HOLEINGROUND, "hole in the ground", "A gaping hole in the ground.", MT_NOTHING, 0, OC_DFEATURE, SZ_LARGE);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_RARE, NULL);
addflag(lastot->flags, F_GLYPH, C_BLUE, NA, NA, "^");
addflag(lastot->flags, F_CLIMBABLE, D_DOWN, NA, NA, NULL);
addflag(lastot->flags, F_PIT, D_DOWN, NA, NA, NULL);
addflag(lastot->flags, F_OPPOSITESTAIRS, OT_HOLEINROOF, NA, NA, NULL);
addflag(lastot->flags, F_NOPICKUP, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_ONEPERCELL, B_TRUE, NA, NA, NULL);
addot(OT_HOLEINROOF, "hole in the roof", "A gaping hole in the roof.", MT_NOTHING, 0, OC_DFEATURE, SZ_LARGE);
addflag(lastot->flags, F_GLYPH, C_BLUE, NA, NA, "<");
addflag(lastot->flags, F_CLIMBABLE, D_UP, NA, NA, NULL);
addflag(lastot->flags, F_PIT, D_UP, NA, NA, NULL);
addflag(lastot->flags, F_OPPOSITESTAIRS, OT_HOLEINGROUND, NA, NA, NULL);
addflag(lastot->flags, F_NOPICKUP, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_ONEPERCELL, B_TRUE, NA, NA, NULL);
addot(OT_STAIRSDOWN, "staircase going down", "A stone staircase winding downwards.", MT_STONE, 3000, OC_DFEATURE, SZ_HUGE);
addflag(lastot->flags, F_GLYPH, NA, NA, NA, ">");
addflag(lastot->flags, F_CLIMBABLE, D_DOWN, NA, NA, NULL);
addflag(lastot->flags, F_OPPOSITESTAIRS, OT_STAIRSUP, NA, NA, NULL);
addflag(lastot->flags, F_NOPICKUP, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL);
addot(OT_STAIRSUP, "staircase going up", "A stone staircase climbing upwards.", MT_STONE, 3000, OC_DFEATURE, SZ_HUGE);
addflag(lastot->flags, F_GLYPH, NA, NA, NA, "<");
addflag(lastot->flags, F_CLIMBABLE, D_UP, NA, NA, NULL);
addflag(lastot->flags, F_OPPOSITESTAIRS, OT_STAIRSDOWN, NA, NA, NULL);
addflag(lastot->flags, F_NOPICKUP, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL);
addot(OT_VENDINGMACHINE, "vending machine", "A gold-operated vending machine.", MT_METAL, 500, OC_DFEATURE, SZ_LARGE);
addflag(lastot->flags, F_RARITY, H_ALL, 70, NA, "");
addflag(lastot->flags, F_GLYPH, C_GREY, NA, NA, "_");
addflag(lastot->flags, F_NOPICKUP, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_OPERABLE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_CONTAINER, B_TRUE, NA, NA, NULL);
// 10 random objects
addflag(lastot->flags, F_STARTOBRND, 100, RANDOM, NA, NULL);
addflag(lastot->flags, F_STARTOBRND, 100, RANDOM, NA, NULL);
addflag(lastot->flags, F_STARTOBRND, 100, RANDOM, NA, NULL);
addflag(lastot->flags, F_STARTOBRND, 100, RANDOM, NA, NULL);
addflag(lastot->flags, F_STARTOBRND, 100, RANDOM, NA, NULL);
addflag(lastot->flags, F_STARTOBRND, 100, RANDOM, NA, NULL);
addflag(lastot->flags, F_STARTOBRND, 100, RANDOM, NA, NULL);
addflag(lastot->flags, F_STARTOBRND, 100, RANDOM, NA, NULL);
addflag(lastot->flags, F_STARTOBRND, 100, RANDOM, NA, NULL);
addflag(lastot->flags, F_STARTOBRND, 100, RANDOM, NA, NULL);
addot(OT_HOLYCIRCLE, "holy circle", "A consecrated area imbued with holy power.", MT_NOTHING, 0, OC_DFEATURE, SZ_LARGE);
addflag(lastot->flags, F_RARITY, H_ALL, 80, NA, "");
addflag(lastot->flags, F_GLYPH, C_CYAN, NA, NA, "_");
addflag(lastot->flags, F_NOPICKUP, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_THEREISHERE, B_TRUE, NA, NA, ".");
addflag(lastot->flags, F_REPELBLESSED, B_CURSED, NA, NA, NULL);
addflag(lastot->flags, F_NOFEEL, B_TRUE, NA, NA, NULL);
addot(OT_PENTAGRAM, "pentagram", "A area imbued with evil.", MT_NOTHING, 0, OC_DFEATURE, SZ_LARGE);
addflag(lastot->flags, F_RARITY, H_ALL, 80, NA, "");
addflag(lastot->flags, F_GLYPH, C_RED, NA, NA, "_");
addflag(lastot->flags, F_NOPICKUP, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_THEREISHERE, B_TRUE, NA, NA, ".");
addflag(lastot->flags, F_REPELBLESSED, B_BLESSED, NA, NA, NULL);
addflag(lastot->flags, F_NOFEEL, B_TRUE, NA, NA, NULL);
addot(OT_PORTAL, "magic portal", "A magical portal to a different place...", MT_MAGIC, 0, OC_DFEATURE, SZ_LARGE);
addflag(lastot->flags, F_GLYPH, C_BOLDGREEN, NA, NA, "^");
addflag(lastot->flags, F_CLIMBABLE, D_IN, NA, NA, NULL);
addflag(lastot->flags, F_NOPICKUP, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_NOFEEL, B_TRUE, NA, NA, NULL);
// terrain
addot(OT_WATERDEEP, "water", "Deep water.", MT_WATER, 300, OC_TERRAIN, SZ_HUGE);
addflag(lastot->flags, F_NO_A, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_GLYPH, C_BOLDBLUE, NA, NA, "{");
addflag(lastot->flags, F_NOPICKUP, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_DTCONVERT, DT_COLD, NA, NA, "sheet of ice");
addflag(lastot->flags, F_DTCREATEOB, DT_FIRE, 1, DT_COMPASS, "cloud of steam");
addflag(lastot->flags, F_DRINKABLE, B_TRUE, NA, B_DONTKILL, NULL);
addflag(lastot->flags, F_LINKOB, OT_POT_WATER, NA, NA, NULL);
addflag(lastot->flags, F_DEEPWATER, DP_MAX, NA, NA, NULL);
addflag(lastot->flags, F_ONEPERCELL, B_TRUE, NA, NA, NULL);
// traps - cell only
addot(OT_TRAPARROW, "arrow trap", "A pressure plate which causes arrows to shoot at you.", MT_NOTHING, 0, OC_TRAP, SZ_SMALL);
addflag(lastot->flags, F_TRAP, 25, B_TRUE, NA, NULL);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 76, NA, NULL);
addflag(lastot->flags, F_GLYPH, C_GREY, NA, NA, "^");
addflag(lastot->flags, F_NOPICKUP, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_THEREISHERE, B_TRUE, NA, NA, ".");
addflag(lastot->flags, F_SECRET, 30, NA, NA, NULL);
addflag(lastot->flags, F_NOFEEL, B_TRUE, NA, NA, NULL);
addot(OT_TRAPARROWP, "poison arrow trap", "A pressure plate which causes poisoned arrows to shoot at you.", MT_NOTHING, 0, OC_TRAP, SZ_SMALL);
addflag(lastot->flags, F_TRAP, 25, B_TRUE, NA, NULL);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 69, NA, NULL);
addflag(lastot->flags, F_GLYPH, C_GREY, NA, NA, "^");
addflag(lastot->flags, F_NOPICKUP, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_THEREISHERE, B_TRUE, NA, NA, ".");
addflag(lastot->flags, F_SECRET, 30, NA, NA, NULL);
addflag(lastot->flags, F_NOFEEL, B_TRUE, NA, NA, NULL);
addot(OT_TRAPPIT, "pit trap", "A pressure plate which causes the floor to drop away.", MT_NOTHING, 0, OC_TRAP, SZ_SMALL);
addflag(lastot->flags, F_TRAP, 20, B_TRUE, 22, NULL);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 85, NA, NULL);
addflag(lastot->flags, F_GLYPH, C_GREY, NA, NA, "^");
addflag(lastot->flags, F_NOPICKUP, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL);
addot(OT_TRAPROCK, "falling rock trap", "A pressure plate which causes heavy rocks to drop from the ceiling.", MT_NOTHING, 0, OC_TRAP, SZ_SMALL);
addflag(lastot->flags, F_TRAP, 20, B_TRUE, 22, NULL);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 85, NA, NULL);
addflag(lastot->flags, F_GLYPH, C_GREY, NA, NA, "^");
addflag(lastot->flags, F_NOPICKUP, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_THEREISHERE, B_TRUE, NA, NA, ".");
addflag(lastot->flags, F_SECRET, 25, NA, NA, NULL);
addflag(lastot->flags, F_NOFEEL, B_TRUE, NA, NA, NULL);
addot(OT_TRAPSUMMON, "summoning trap", "A magical trap which causes a monster to appear.", MT_NOTHING, 0, OC_TRAP, SZ_SMALL);
addflag(lastot->flags, F_TRAP, 30, B_TRUE, NA, NULL);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 60, NA, NULL);
addflag(lastot->flags, F_GLYPH, C_GREEN, NA, NA, "^");
addflag(lastot->flags, F_NOPICKUP, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_THEREISHERE, B_TRUE, NA, NA, ".");
addflag(lastot->flags, F_SECRET, 30, NA, NA, NULL);
addflag(lastot->flags, F_NOFEEL, B_TRUE, NA, NA, NULL);
addot(OT_TRAPTRIP, "tripwire", "A thin wire at ankle height.", MT_WIRE, 0.1, OC_TRAP, SZ_SMALL);
addflag(lastot->flags, F_TRAP, 10, B_FALSE, 20, NULL);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 90, NA, NULL);
addflag(lastot->flags, F_GLYPH, C_GREY, NA, NA, "^");
addflag(lastot->flags, F_NOPICKUP, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_THEREISHERE, B_TRUE, NA, NA, ".");
addflag(lastot->flags, F_SECRET, 25, NA, NA, NULL);
addflag(lastot->flags, F_ATTACKABLE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_OBHP, 1, 1, NA, NULL);
// traps - object only
addot(OT_TRAPNEEDLEP, "poison needle trap", "A springed needle coated with poison.", MT_NOTHING, 0, OC_TRAP, SZ_SMALL);
addflag(lastot->flags, F_OBJECTTRAP, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_TRAP, 23, B_TRUE, 25, NULL);
addflag(lastot->flags, F_GLYPH, C_GREY, NA, NA, "^");
addflag(lastot->flags, F_NOPICKUP, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL);
addot(OT_TRAPWIND, "wind trap", "A magical trap which assails the target with a blast of air.", MT_NOTHING, 0, OC_TRAP, SZ_SMALL);
addflag(lastot->flags, F_OBJECTTRAP, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_TRAP, 20, B_TRUE, NA, NULL);
addflag(lastot->flags, F_GLYPH, C_MAGENTA, NA, NA, "^");
addflag(lastot->flags, F_NOPICKUP, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL);
// traps - either cell on object
addot(OT_TRAPALARM, "alarm trap", "A trap which sounds a loud siren.", MT_NOTHING, 0, OC_TRAP, SZ_SMALL);
addflag(lastot->flags, F_TRAP, 18, B_TRUE, NA, NULL);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, NA, NULL);
addflag(lastot->flags, F_OBJECTTRAP, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_GLYPH, C_GREY, NA, NA, "^");
addflag(lastot->flags, F_NOPICKUP, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_THEREISHERE, B_TRUE, NA, NA, ".");
addflag(lastot->flags, F_SECRET, 30, NA, NA, NULL);
addflag(lastot->flags, F_NOFEEL, B_TRUE, NA, NA, NULL);
addot(OT_TRAPEBLAST, "energy blast trap", "A magical trap which blasts its victim with energy.", MT_NOTHING, 0, OC_TRAP, SZ_SMALL);
addflag(lastot->flags, F_TRAP, 30, B_TRUE, NA, NULL);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 75, NA, NULL);
addflag(lastot->flags, F_OBJECTTRAP, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_GLYPH, C_MAGENTA, NA, NA, "^");
addflag(lastot->flags, F_NOPICKUP, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_THEREISHERE, B_TRUE, NA, NA, ".");
addflag(lastot->flags, F_SECRET, 30, NA, NA, NULL);
addflag(lastot->flags, F_NOFEEL, B_TRUE, NA, NA, NULL);
addot(OT_TRAPFIRE, "fire trap", "A trap which fires a pillar of flame.", MT_NOTHING, 0, OC_TRAP, SZ_SMALL);
addflag(lastot->flags, F_TRAP, 30, B_TRUE, NA, NULL);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 59, NA, NULL);
addflag(lastot->flags, F_OBJECTTRAP, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_GLYPH, C_GREY, NA, NA, "^");
addflag(lastot->flags, F_NOPICKUP, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_THEREISHERE, B_TRUE, NA, NA, ".");
addflag(lastot->flags, F_SECRET, 30, NA, NA, NULL);
addflag(lastot->flags, F_NOFEEL, B_TRUE, NA, NA, NULL);
addot(OT_TRAPGAS, "gas trap", "A trap which releases poisonous gas.", MT_NOTHING, 0, OC_TRAP, SZ_SMALL);
addflag(lastot->flags, F_TRAP, 27, B_TRUE, NA, NULL);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 69, NA, NULL);
addflag(lastot->flags, F_GLYPH, C_GREY, NA, NA, "^");
addflag(lastot->flags, F_NOPICKUP, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_THEREISHERE, B_TRUE, NA, NA, ".");
addflag(lastot->flags, F_SECRET, 30, NA, NA, NULL);
addflag(lastot->flags, F_NOFEEL, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_OBJECTTRAP, B_TRUE, NA, NA, NULL);
addot(OT_TRAPMINE, "landmine trap", "A buried, pressure-sensitive explosive device.", MT_NOTHING, 0, OC_TRAP, SZ_SMALL);
addflag(lastot->flags, F_TRAP, 30, B_TRUE, NA, NULL);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 50, NA, NULL);
addflag(lastot->flags, F_RARITY, H_FOREST, 20, NA, NULL);
addflag(lastot->flags, F_OBJECTTRAP, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_GLYPH, C_GREY, NA, NA, "^");
addflag(lastot->flags, F_NOPICKUP, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_THEREISHERE, B_TRUE, NA, NA, ".");
addflag(lastot->flags, F_SECRET, 30, NA, NA, NULL);
addflag(lastot->flags, F_NOFEEL, B_TRUE, NA, NA, NULL);
addot(OT_TRAPTELEPORT, "teleportation trap", "A magical dispersal field.", MT_NOTHING, 0, OC_TRAP, SZ_LARGE);
addflag(lastot->flags, F_TRAP, NA, B_TRUE, NA, NULL);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 80, NA, NULL);
addflag(lastot->flags, F_GLYPH, C_MAGENTA, NA, NA, "^");
addflag(lastot->flags, F_NOPICKUP, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_THEREISHERE, B_TRUE, NA, NA, ".");
addflag(lastot->flags, F_SECRET, 30, NA, NA, NULL);
addflag(lastot->flags, F_NOFEEL, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_OBJECTTRAP, B_TRUE, NA, NA, NULL);
// money etc
addot(OT_GOLD, "gold coin", "Sparkling nuggets of gold, the standard currency of Nexus.", MT_GOLD, 0.01, OC_MONEY, SZ_MINI);
addflag(lastot->flags, F_STACKABLE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_RARITY, H_ALL, 100, NA, "");
addflag(lastot->flags, F_NUMAPPEAR, 1, 100, NA, "");
addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_FEELTEXT, NA, NA, NA, "some gold");
addot(OT_STONE, "stone", "A medium-sized roundish stone.", MT_STONE, 0.5, OC_ROCK, SZ_TINY);
addflag(lastot->flags, F_STACKABLE, B_TRUE, NA, NA, "");
addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, NA, "");
addflag(lastot->flags, F_NUMAPPEAR, 1, 10, NA, "");
addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_THROWMISSILE, B_TRUE, NA, NA, NULL);
addot(OT_ASH, "pile of ash", "A pile of ash.", MT_STONE, 0.1, OC_ROCK, SZ_TINY);
addflag(lastot->flags, F_GLYPH, NA, NA, NA, ",");
addflag(lastot->flags, F_STACKABLE, B_TRUE, NA, NA, "");
addflag(lastot->flags, F_RARITY, H_DUNGEON, 70, NA, "");
addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_POWDER, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_FEELTEXT, NA, NA, NA, "some ash");
addot(OT_ASHEXPLODE, "pile of exploding powder", "A pile of ash.", MT_STONE, 0.1, OC_ROCK, SZ_TINY);
addflag(lastot->flags, F_GLYPH, NA, NA, NA, ",");
addflag(lastot->flags, F_STACKABLE, B_TRUE, NA, NA, "");
addflag(lastot->flags, F_EXPLODEONDAM, NA, NA, NA, "1d6");
addflag(lastot->flags, F_RARITY, H_DUNGEON, 70, NA, "");
addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_POWDER, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_HASHIDDENNAME, B_TRUE, NA, NA, "pile of ash");
addflag(lastot->flags, F_FEELTEXT, NA, NA, NA, "some ash");
addot(OT_ASHCONCEAL, "pile of concealing powder", "A pile of ash.", MT_STONE, 0.1, OC_ROCK, SZ_TINY);
addflag(lastot->flags, F_GLYPH, NA, NA, NA, ",");
addflag(lastot->flags, F_STACKABLE, B_TRUE, NA, NA, "");
addflag(lastot->flags, F_RARITY, H_DUNGEON, 70, NA, "");
addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_POWDER, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_HASHIDDENNAME, B_TRUE, NA, NA, "pile of ash");
addflag(lastot->flags, F_FEELTEXT, NA, NA, NA, "some ash");
addflag(lastot->flags, F_AIFLEEITEM, B_TRUE, NA, NA, NULL);
addot(OT_ASHSLEEP, "pile of sleeping powder", "A pile of ash.", MT_STONE, 0.1, OC_ROCK, SZ_TINY);
addflag(lastot->flags, F_GLYPH, NA, NA, NA, ",");
addflag(lastot->flags, F_STACKABLE, B_TRUE, NA, NA, "");
addflag(lastot->flags, F_RARITY, H_DUNGEON, 70, NA, "");
addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_POWDER, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_HASHIDDENNAME, B_TRUE, NA, NA, "pile of ash");
addflag(lastot->flags, F_FEELTEXT, NA, NA, NA, "some ash");
addot(OT_GEMOFSEEING, "gem of seeing", "Magically enhances your eyesight.", MT_STONE, 1, OC_ROCK, SZ_TINY);
addflag(lastot->flags, F_HOLDCONFER, F_XRAYVIS, 2, NA, NULL);
addflag(lastot->flags, F_HOLDCONFER, F_SEEINVIS, B_TRUE, NA, NULL);
addflag(lastot->flags, F_HOLDCONFER, F_ENHANCESEARCH, 20, NA, NULL);
addflag(lastot->flags, F_HOLDCONFER, F_DETECTAURAS, B_TRUE, NA, NULL);
addflag(lastot->flags, F_HOLDCONFER, F_DETECTMAGIC, B_TRUE, NA, NULL);
addflag(lastot->flags, F_VALUE, 1000, NA, NA, NULL);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 50, NA, NULL);
// godstones
addot(OT_GODSTONEJ, "Godstone of Justice", "An ancient artifact representing the power of justice.", MT_STONE, 3, OC_GODSTONE, SZ_SMALL);
addflag(lastot->flags, F_VALUE, 1000, NA, NA, NULL);
addflag(lastot->flags, F_CHARGES, 100, 100, NA, NULL);
addflag(lastot->flags, F_RECHARGE, 1, NA, NA, NULL);
addflag(lastot->flags, F_AIFLEEITEM, B_TRUE, NA, NA, NULL);
// flora
addot(OT_FLOWER, "flower", "A colourful woodland flower.", MT_PLANT, 0.01, OC_FLORA, SZ_TINY);
addflag(lastot->flags, F_RARITY, H_FOREST, 100, NA, "");
addflag(lastot->flags, F_STACKABLE, B_TRUE, NA, NA, "");
addflag(lastot->flags, F_GLYPH, C_MAGENTA, NA, NA, ",");
addflag(lastot->flags, F_NUMAPPEAR, 1, 10, NA, NULL);
addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_DTVULN, DT_FIRE, NA, NA, "3d6");
addot(OT_LEAF, "leaf", "A fallen leaf from a tree.", MT_PLANT, 0.01, OC_FLORA, SZ_TINY);
addflag(lastot->flags, F_RARITY, H_FOREST, 100, NA, "");
addflag(lastot->flags, F_STACKABLE, B_TRUE, NA, NA, "");
addflag(lastot->flags, F_GLYPH, C_BROWN, NA, NA, ",");
addflag(lastot->flags, F_NUMAPPEAR, 1, 10, NA, NULL);
addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_DTVULN, DT_FIRE, NA, NA, "3d6");
addot(OT_MISTLETOE, "sprig of mistletoe", "A small cutting of mistletoe.", MT_PLANT, 0.01, OC_FLORA, SZ_TINY);
addflag(lastot->flags, F_HASHIDDENNAME, B_TRUE, NA, NA, "leaf");
addflag(lastot->flags, F_RARITY, H_FOREST, 100, NA, "");
addflag(lastot->flags, F_STACKABLE, B_TRUE, NA, NA, "");
addflag(lastot->flags, F_GLYPH, C_WHITE, NA, NA, ",");
addflag(lastot->flags, F_NUMAPPEAR, 1, 3, NA, NULL);
addflag(lastot->flags, F_DTVULN, DT_FIRE, NA, NA, "3d6");
addflag(lastot->flags, F_OPERABLE, B_TRUE, NA, NA, NULL);
addot(OT_SHRUB, "shrub", "A small but dense shrub.", MT_PLANT, 50, OC_FLORA, SZ_MEDIUM);
addflag(lastot->flags, F_RARITY, H_FOREST, 100, NA, "");
addflag(lastot->flags, F_GLYPH, C_GREEN, NA, NA, "%");
addflag(lastot->flags, F_IMPASSABLE, SZ_MIN, SZ_MEDIUM, NA, NULL);
addflag(lastot->flags, F_REDUCEMOVEMENT, 1, NA, NA, NULL);
addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_OBHP, 20, 20, NA, NULL);
addflag(lastot->flags, F_DTVULN, DT_FIRE, NA, NA, "2d6");
addflag(lastot->flags, F_DTVULN, DT_CHOP, NA, NA, NULL);
addot(OT_STUMP, "stump", "A large tree stump.", MT_WOOD, 150, OC_FLORA, SZ_LARGE);
addflag(lastot->flags, F_RARITY, H_FOREST, 100, NA, "");
addflag(lastot->flags, F_GLYPH, C_BROWN, NA, NA, "'");
addflag(lastot->flags, F_IMPASSABLE, SZ_MIN, SZ_HUMAN, NA, NULL);
addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_OBHP, 30, 30, NA, NULL);
addflag(lastot->flags, F_DTVULN, DT_FIRE, NA, NA, "2d6");
addflag(lastot->flags, F_DTVULN, DT_CHOP, NA, NA, NULL);
addot(OT_TREE, "tree", "A tree.", MT_WOOD, 200, OC_FLORA, SZ_LARGE);
addflag(lastot->flags, F_RARITY, H_FOREST, 100, NA, "");
addflag(lastot->flags, F_GLYPH, C_GREEN, NA, NA, "#");
addflag(lastot->flags, F_IMPASSABLE, SZ_MIN, SZ_LARGE, NA, NULL);
addflag(lastot->flags, F_BLOCKSVIEW, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_BLOCKSLOF, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_OBHP, 80, 80, NA, NULL);
addflag(lastot->flags, F_THROWMISSILE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_DTVULN, DT_FIRE, NA, NA, "2d6");
addflag(lastot->flags, F_DTVULN, DT_CHOP, NA, NA, NULL);
// food
addot(OT_BERRY, "berry", "Juicy, brightly coloured berries.", MT_FOOD, 0.1, OC_FOOD, SZ_TINY);
addflag(lastot->flags, F_GLYPH, C_ORANGE, NA, NA, "%");
addflag(lastot->flags, F_EDIBLE, B_TRUE, 8, NA, "");
addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, NA, NULL);
addflag(lastot->flags, F_RARITY, H_FOREST, 100, NA, NULL);
addflag(lastot->flags, F_NUMAPPEAR, 1, 15, NA, "");
addot(OT_CACFRUIT, "cactus fruit", "The nutritous fruit from a cactus plant.", MT_FOOD, 0.5, OC_FOOD, SZ_TINY);
addflag(lastot->flags, F_GLYPH, C_RED, NA, NA, "%");
addflag(lastot->flags, F_EDIBLE, B_TRUE, 100, NA, "");
addflag(lastot->flags, F_RARITY, H_FOREST, 90, NA, NULL);
addot(OT_GARLIC, "clove of garlic", "A very pungent clove of raw garlic. ", MT_FOOD, 0.1, OC_FOOD, SZ_TINY);
addflag(lastot->flags, F_GLYPH, C_BROWN, NA, NA, "%");
addflag(lastot->flags, F_EDIBLE, B_TRUE, 5, NA, "");
addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_UNCOMMON, NULL);
addflag(lastot->flags, F_RARITY, H_FOREST, 100, RR_UNCOMMON, NULL);
addflag(lastot->flags, F_NUMAPPEAR, 1, 3, NA, "");
addot(OT_NUT, "peanut", "A species in the legume family.", MT_FOOD, 0.1, OC_FOOD, SZ_TINY);
addflag(lastot->flags, F_GLYPH, C_BROWN, NA, NA, "%");
addflag(lastot->flags, F_EDIBLE, B_TRUE, 12, NA, "");
addflag(lastot->flags, F_RARITY, H_FOREST, 90, NA, NULL);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 90, NA, NULL);
addflag(lastot->flags, F_NUMAPPEAR, 1, 12, NA, "");
addot(OT_BANANA, "banana", "Ba-na-na-na-na-na na-na na-na-na.", MT_FOOD, 0.3, OC_FOOD, SZ_TINY);
addflag(lastot->flags, F_GLYPH, C_YELLOW, NA, NA, "%");
addflag(lastot->flags, F_EDIBLE, B_TRUE, 50, NA, "");
addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_UNCOMMON, NULL);
addflag(lastot->flags, F_RARITY, H_FOREST, 100, NA, NULL);
addot(OT_BANANASKIN, "banana skin", "A slippery banana skin.", MT_FOOD, 0.1, OC_FOOD, SZ_TINY);
addflag(lastot->flags, F_GLYPH, C_YELLOW, NA, NA, "%");
addflag(lastot->flags, F_RARITY, H_DUNGEON, 70, NA, NULL);
addflag(lastot->flags, F_SLIPPERY, 15, NA, NA, NULL);
addflag(lastot->flags, F_SLIPMOVE, 15, NA, NA, NULL);
addot(OT_APPLE, "apple", "A crunchy apple.", MT_FOOD, 0.5, OC_FOOD, SZ_TINY);
addflag(lastot->flags, F_GLYPH, C_GREEN, NA, NA, "%");
addflag(lastot->flags, F_EDIBLE, B_TRUE, 50, NA, "");
addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, NA, NULL);
addflag(lastot->flags, F_RARITY, H_FOREST, 100, NA, NULL);
addot(OT_MUSHROOM, "mushroom", "A large brown mushroom.", MT_FOOD, 0.2, OC_FOOD, SZ_TINY);
addflag(lastot->flags, F_EDIBLE, B_TRUE, 60, NA, "");
addflag(lastot->flags, F_RARITY, H_DUNGEON, 90, NA, NULL);
addflag(lastot->flags, F_RARITY, H_FOREST, 100, NA, NULL);
addflag(lastot->flags, F_NUMAPPEAR, 1, 3, NA, "");
addot(OT_BREADSTALE, "loaf of stale bread", "A small loaf of old, stale bread.", MT_FOOD, 0.5, OC_FOOD, SZ_TINY);
addflag(lastot->flags, F_GLYPH, C_BROWN, NA, NA, "%");
addflag(lastot->flags, F_EDIBLE, B_TRUE, 100, NA, "");
addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_UNCOMMON, NULL);
addflag(lastot->flags, F_FEELTEXT, NA, NA, NA, "some bread");
addot(OT_CHEESE, "chunk of cheese", "A chunk of hard cheese.", MT_FOOD, 0.5, OC_FOOD, SZ_TINY);
addflag(lastot->flags, F_GLYPH, C_YELLOW, NA, NA, "%");
addflag(lastot->flags, F_EDIBLE, B_TRUE, 85, NA, "");
addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, NA, NULL);
addot(OT_STEW, "stew", "Some kind of meat soaked in water.", MT_FOOD, 1.5, OC_FOOD, SZ_TINY);
addflag(lastot->flags, F_GLYPH, C_BROWN, NA, NA, "%");
addflag(lastot->flags, F_EDIBLE, B_TRUE, 100, NA, "");
addot(OT_ROASTMEAT, "chunk of roast meat", "A chunk of flame-roasted flesh.", MT_FLESH, 1, OC_FOOD, SZ_TINY); // weight normally comes from corpse type
addflag(lastot->flags, F_GLYPH, C_BROWN, NA, NA, "%");
addflag(lastot->flags, F_EDIBLE, B_TRUE, 100, NA, "");
addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_UNCOMMON, NULL);
addot(OT_BREADFRESH, "loaf of fresh bread", "A freshly-baked loaf of bread.", MT_FOOD, 0.5, OC_FOOD, SZ_TINY);
addflag(lastot->flags, F_GLYPH, C_BROWN, NA, NA, "%");
addflag(lastot->flags, F_EDIBLE, B_TRUE, 200, NA, "");
addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_UNCOMMON, NULL);
addflag(lastot->flags, F_FEELTEXT, NA, NA, NA, "some bread");
addot(OT_CLOVER, "four leafed clover", "A rare 4-leafed clover.", MT_FOOD, 0.5, OC_FOOD, SZ_TINY);
addflag(lastot->flags, F_GLYPH, C_GREEN, NA, NA, "%");
addflag(lastot->flags, F_EDIBLE, B_TRUE, 5, NA, "");
addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_RARE, NULL);
addflag(lastot->flags, F_RARITY, H_FOREST, 100, RR_RARE, NULL);
addflag(lastot->flags, F_HOLDCONFER, F_EXTRALUCK, 1, NA, NULL);
addot(OT_CARROT, "carrot", "A stout orange carrot. Rumour has it that carrots are good for your eyesight.", MT_FOOD, 0.2, OC_FOOD, SZ_TINY);
addflag(lastot->flags, F_GLYPH, C_ORANGE, NA, NA, "%");
addflag(lastot->flags, F_EDIBLE, B_TRUE, 60, NA, "");
addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_UNCOMMON, NULL);
addflag(lastot->flags, F_RARITY, H_FOREST, 100, RR_UNCOMMON, NULL);
addot(OT_CHOCOLATE, "block of chocolate", "An entire block of chocolate.", MT_FOOD, 0.5, OC_FOOD, SZ_TINY);
addflag(lastot->flags, F_GLYPH, C_BROWN, NA, NA, "%");
addflag(lastot->flags, F_EDIBLE, B_TRUE, 250, NA, "");
addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_RARE, NULL);
// corpses
addot(OT_CORPSE, "corpse", "xxx", MT_FLESH, 1, OC_CORPSE, SZ_TINY);
addflag(lastot->flags, F_EDIBLE, B_TRUE, 1, NA, NULL); // will be overridden
addot(OT_HEAD, "head", "xxx", MT_FLESH, 1, OC_CORPSE, SZ_SMALL);
addflag(lastot->flags, F_EDIBLE, B_TRUE, 1, NA, NULL); // will be overridden
addot(OT_FLESHCHUNK, "chunk of flesh", "A chunk of flesh from something.", MT_FLESH, 1, OC_FOOD, SZ_SMALL);
addflag(lastot->flags, F_GLYPH, C_BROWN, NA, NA, "%");
addflag(lastot->flags, F_EDIBLE, B_TRUE, 25, NA, NULL);
addot(OT_FINGER, "severed finger", "The severed finger from some kind of creature.", MT_FLESH, 0.02, OC_CORPSE, SZ_TINY);
addflag(lastot->flags, F_EDIBLE, B_TRUE, 1, NA, NULL);
// potions (sorted by rarity)
addot(OT_POT_JUICE, "potion of fruit juice", "Tasty (but not very fresh) fruit juice!", MT_GLASS, 1, OC_POTION, SZ_TINY);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, NA, NULL);
addot(OT_POT_HEALINGMIN, "potion of minor healing", "Restores 1-10 health to whoever drinks it.", MT_GLASS, 1, OC_POTION, SZ_TINY);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, NA, NULL);
addflag(lastot->flags, F_AIHEALITEM, B_TRUE, NA, NA, NULL);
addot(OT_POT_WATER, "potion of water", "Plain, regular water.", MT_GLASS, 1, OC_POTION, SZ_TINY);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, NA, NULL);
addflag(lastot->flags, F_RARITY, H_VILLAGE, 100, NA, NULL);
addflag(lastot->flags, F_DIECONVERT, NA, NA, NA, "small puddle of water");
modflag(lastot->flags, F_HASHIDDENNAME, NA, NA, NA, "clear potion");
addot(OT_POT_HEALING, "potion of healing", "Restores 10-20 health to whoever drinks it.", MT_GLASS, 1, OC_POTION, SZ_TINY);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 90, NA, NULL);
addflag(lastot->flags, F_AIHEALITEM, B_TRUE, NA, NA, NULL);
addot(OT_POT_HEALINGMAJ, "potion of major healing", "Restores 20-30 health to whoever drinks it.", MT_GLASS, 1, OC_POTION, SZ_TINY);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 72, NA, NULL);
addflag(lastot->flags, F_AIHEALITEM, B_TRUE, NA, NA, NULL);
addot(OT_POT_OIL, "potion of oil", "A bottle of cooking oil.", MT_GLASS, 1, OC_POTION, SZ_TINY);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 83, NA, NULL);
addflag(lastot->flags, F_DIECONVERT, NA, NA, NA, "puddle of oil");
addflag(lastot->flags, F_THROWMISSILE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_DTVULN, DT_FIRE, NA, NA, NULL);
addflag(lastot->flags, F_EXPLODEONDAM, DT_FIRE, NA, NA, "2d4");
addot(OT_POT_COFFEE, "potion of coffee", "A caffeinated beverage prepared from coffee beans.", MT_GLASS, 1, OC_POTION, SZ_TINY);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 83, NA, NULL);
addot(OT_POT_RUM, "potion of rum", "Strong liqour which is sure to make you tipsy.", MT_GLASS, 1, OC_POTION, SZ_TINY);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 83, NA, NULL);
addflag(lastot->flags, F_FLAMMABLE, 1, NA, NA, "medium fire");
addflag(lastot->flags, F_DTVULN, DT_FIRE, NA, NA, NULL);
addflag(lastot->flags, F_EXPLODEONDAM, DT_FIRE, NA, NA, "2d6");
addot(OT_POT_RESTORATION, "potion of restoration", "Restores lost abilities to the drinker.", MT_GLASS, 1, OC_POTION, SZ_TINY);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 75, NA, NULL);
addot(OT_POT_SLEEP, "potion of sleep", "Puts the drinker into a deep sleep.", MT_GLASS, 1, OC_POTION, SZ_TINY);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 83, NA, NULL);
addflag(lastot->flags, F_THROWMISSILE, B_TRUE, NA, NA, NULL);
addot(OT_POT_SPEED, "potion of haste", "Temporarily increasees the drinker's speed.", MT_GLASS, 1, OC_POTION, SZ_TINY);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 75, NA, NULL);
addflag(lastot->flags, F_AIBOOSTITEM, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_AIFLEEITEM, B_TRUE, NA, NA, NULL);
addot(OT_POT_LEVITATION, "potion of levitation", "Causes the drinker to float up in the air.", MT_GLASS, 1, OC_POTION, SZ_TINY);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 78, NA, NULL);
addot(OT_POT_MAGIC, "potion of magic", "Fully restores the drinker's magical energy.", MT_GLASS, 1, OC_POTION, SZ_TINY);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 75, NA, NULL);
addflag(lastot->flags, F_THROWMISSILE, B_TRUE, NA, NA, NULL);
addot(OT_POT_ACROBATICS, "potion of acrobatics", "Allows the drinker to leap large distances.", MT_GLASS, 1, OC_POTION, SZ_TINY);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 70, NA, NULL);
addot(OT_POT_INVIS, "potion of invisibility", "Temporarily renders the drinker invisible.", MT_GLASS, 1, OC_POTION, SZ_TINY);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 70, NA, NULL);
addflag(lastot->flags, F_AIBOOSTITEM, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_AIFLEEITEM, B_TRUE, NA, NA, NULL);
addot(OT_POT_POISON, "potion of poison", "Poisons the drinker.", MT_GLASS, 1, OC_POTION, SZ_TINY);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 70, NA, NULL);
addflag(lastot->flags, F_THROWMISSILE, B_TRUE, NA, NA, NULL);
addot(OT_POT_ACID, "flask of battery acid", "Causes massive internal burning if ingested.", MT_GLASS, 1, OC_POTION, SZ_TINY);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 70, NA, NULL);
addflag(lastot->flags, F_DIECONVERT, NA, NA, NA, "puddle of acid");
addflag(lastot->flags, F_THROWMISSILE, B_TRUE, NA, NA, NULL);
addot(OT_POT_ELEMENTIMMUNE, "potion of elemental immunity", "Grants the imbiber temporary immunity to both fire and cold.", MT_GLASS, 1, OC_POTION, SZ_TINY);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 60, NA, NULL);
addot(OT_POT_BLOOD, "potion of blood", "A small quantity of blood.", MT_GLASS, 1, OC_POTION, SZ_TINY);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 60, NA, NULL);
addflag(lastot->flags, F_DIECONVERT, NA, NA, NA, "splash of blood");
addot(OT_POT_SANCTUARY, "potion of sanctuary", "Creates a temporary magical barrier abour the drinker.", MT_GLASS, 1, OC_POTION, SZ_TINY);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 60, NA, NULL);
addot(OT_POT_ETHEREALNESS, "potion of etherealness", "Allows the walker to temporarily pass through walls.", MT_GLASS, 1, OC_POTION, SZ_TINY);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 65, NA, NULL);
addot(OT_POT_EXPERIENCE, "potion of experience", "Instantly grants the imbiber the next experience level.", MT_GLASS, 1, OC_POTION, SZ_TINY);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 40, NA, NULL);
addflag(lastot->flags, F_AIBOOSTITEM, B_TRUE, 40, NA, NULL);
addot(OT_POT_BLOODC, "potion of cockatrice blood", "A small quantity of cockatrice blood.", MT_GLASS, 1, OC_POTION, SZ_TINY);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 50, NA, NULL);
addflag(lastot->flags, F_DIECONVERT, NA, NA, NA, "splash of cockatrice blood");
addot(OT_POT_COMPETENCE, "potion of competence", "Permemantly increases the drinker's strength, intelligence or dexterity.", MT_GLASS, 1, OC_POTION, SZ_TINY);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 50, NA, NULL);
addot(OT_POT_GASEOUSFORM, "potion of gaseous form", "Turns the drinker into a cloud of gas.", MT_GLASS, 1, OC_POTION, SZ_TINY);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 50, NA, NULL);
addflag(lastot->flags, F_AIFLEEITEM, B_TRUE, NA, NA, NULL);
addot(OT_POT_POLYMORPH, "potion of polymorph self", "Transmutes the drinker into another living race.", MT_GLASS, 1, OC_POTION, SZ_TINY);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 50, NA, NULL);
addflag(lastot->flags, F_THROWMISSILE, B_TRUE, NA, NA, NULL);
addot(OT_POT_INVULN, "potion of invulnerability", "Grants the drinker temporary immunity to physical harm.", MT_GLASS, 1, OC_POTION, SZ_TINY);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 40, NA, NULL);
addflag(lastot->flags, F_AIBOOSTITEM, B_TRUE, NA, NA, NULL);
addot(OT_POT_AMBROSIA, "vial of ambrosia", "The nectar of the gods, said to completely restore the drinker's health.", MT_GLASS, 1, OC_POTION, SZ_TINY);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 35, NA, NULL);
addflag(lastot->flags, F_AIHEALITEM, B_TRUE, NA, NA, NULL);
// scrolls
addot(OT_SCR_REMOVECURSE, "scroll of remove curse", "Removes curses from all weilded equipment.", MT_PAPER, 0.5, OC_SCROLL, SZ_SMALL);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_COMMON, NULL);
addot(OT_SCR_IDENTIFY, "scroll of identify", "Completely identifies any one item.", MT_PAPER, 0.5, OC_SCROLL, SZ_SMALL);
addflag(lastot->flags, F_LINKSPELL, OT_S_IDENTIFY, NA, NA, NULL);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_COMMON, NULL);
addot(OT_SCR_MENDING, "scroll of mending", "Repairs damage to objects.", MT_PAPER, 0.5, OC_SCROLL, SZ_SMALL);
addflag(lastot->flags, F_LINKSPELL, OT_S_MENDING, NA, NA, NULL);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 98, RR_COMMON, NULL);
addflag(lastot->flags, F_MAXPOWER, 4, NA, NA, NULL);
addot(OT_SCR_NOTHING, "scroll of nothing", "Looks like a magic scroll, but doesn't do anything.", MT_PAPER, 0.5, OC_SCROLL, SZ_SMALL);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 84, RR_UNCOMMON, NULL);
addot(OT_GRAPHPAPER, "piece of graph paper", "Paper containing a set of grid-lines, intended for mapping.", MT_PAPER, 0.5, OC_SCROLL, SZ_SMALL);
addflag(lastot->flags, F_HOLDCONFER, F_PHOTOMEM, NA, IFKNOWN, NULL);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_UNCOMMON, NULL);
addot(OT_MAP, "map", "A visual representation of the area.", MT_PAPER, 0.5, OC_SCROLL, SZ_SMALL);
addot(OT_SCR_CREATEMONSTER, "scroll of create monster", "Summons a (probably hostile) monster to a nearby location.", MT_PAPER, 0.5, OC_SCROLL, SZ_SMALL);
addflag(lastot->flags, F_LINKSPELL, OT_S_CREATEMONSTER, 4, NA, NULL);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_UNCOMMON, NULL);
addflag(lastot->flags, F_AIBOOSTITEM, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_AIFLEEITEM, B_TRUE, NA, NA, NULL);
addot(OT_SCR_DETECTAURA, "scroll of detect aura", "Senses holiness or evil near the caster.", MT_PAPER, 0.5, OC_SCROLL, SZ_SMALL);
addflag(lastot->flags, F_LINKSPELL, OT_S_DETECTAURA, NA, NA, NULL);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_UNCOMMON, NULL);
addot(OT_SCR_DETECTLIFE, "scroll of detect life", "Senses life near the caster.", MT_PAPER, 0.5, OC_SCROLL, SZ_SMALL);
addflag(lastot->flags, F_LINKSPELL, OT_S_DETECTLIFE, NA, NA, NULL);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_UNCOMMON, NULL);
addot(OT_SCR_DETECTOBS, "scroll of detect objects", "Senses objects near the caster.", MT_PAPER, 0.5, OC_SCROLL, SZ_SMALL);
addflag(lastot->flags, F_LINKSPELL, OT_S_DETECTOBS, NA, NA, NULL);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_UNCOMMON, NULL);
addot(OT_SCR_DETECTMAGIC, "scroll of detect magic", "Allows the reader to detect magical enchantments.", MT_PAPER, 0.5, OC_SCROLL, SZ_SMALL);
addflag(lastot->flags, F_LINKSPELL, OT_S_DETECTMAGIC, NA, NA, NULL);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_RARE, NULL);
addot(OT_SCR_FLAMEPILLAR, "scroll of flame pillar", "Creates a tall pillar of flame.", MT_PAPER, 0.5, OC_SCROLL, SZ_SMALL);
addflag(lastot->flags, F_LINKSPELL, OT_S_FLAMEPILLAR, NA, NA, NULL);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_UNCOMMON, NULL);
addot(OT_SCR_FLAMEBURST, "scroll of flame burst", "Creates a radial blast of fire out from the caster, dealing 2d6 damage. Range is based on spell power.", MT_PAPER, 0.5, OC_SCROLL, SZ_SMALL);
addflag(lastot->flags, F_LINKSPELL, OT_S_FLAMEBURST, NA, NA, NULL);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_UNCOMMON, NULL);
addot(OT_SCR_ENCHANT, "scroll of enchantment", "Magically enhances a weapon or piece of armour.", MT_PAPER, 0.5, OC_SCROLL, SZ_SMALL);
addflag(lastot->flags, F_LINKSPELL, OT_S_ENCHANT, NA, NA, NULL);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_RARE, NULL);
addot(OT_SCR_FREEZEOB, "scroll of freezing touch", "Permenantly changes the next object touched into solid ice.", MT_PAPER, 0.5, OC_SCROLL, SZ_SMALL);
addflag(lastot->flags, F_LINKSPELL, OT_S_FREEZEOB, NA, NA, NULL);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 75, RR_RARE, NULL);
addot(OT_SCR_KNOCK, "scroll of knock", "Magically opens a barrier.", MT_PAPER, 0.5, OC_SCROLL, SZ_SMALL);
addflag(lastot->flags, F_LINKSPELL, OT_S_KNOCK, NA, NA, NULL);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 80, RR_COMMON, NULL);
addot(OT_SCR_LIGHT, "scroll of light", "Creates a permenant light source centred on the caster.", MT_PAPER, 0.5, OC_SCROLL, SZ_SMALL);
addflag(lastot->flags, F_LINKSPELL, OT_S_LIGHT, NA, NA, NULL);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_COMMON, NULL);
addflag(lastot->flags, F_AIFLEEITEM, B_TRUE, NA, NA, NULL);
addot(OT_SCR_MAPPING, "scroll of sense surroundings", "Magically imbues the caster with a map of his/her surroundings.", MT_PAPER, 0.5, OC_SCROLL, SZ_SMALL);
addflag(lastot->flags, F_LINKSPELL, OT_S_MAPPING, 4, NA, NULL);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 80, RR_UNCOMMON, NULL);
addot(OT_SCR_MINDSCAN, "scroll of mind scan", "Allows you to view the world through another creature's eyes.", MT_PAPER, 0.5, OC_SCROLL, SZ_SMALL);
addflag(lastot->flags, F_LINKSPELL, OT_S_MINDSCAN, NA, NA, NULL);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 75, RR_UNCOMMON, NULL);
addot(OT_SCR_PERMENANCE, "scroll of permenance", "Makes all effects on an object last forever.", MT_PAPER, 0.5, OC_SCROLL, SZ_SMALL);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 50, RR_RARE, NULL);
addot(OT_SCR_TELEPORT, "scroll of teleportation", "Causes the caster to teleport to a random location within the same level.", MT_PAPER, 0.5, OC_SCROLL, SZ_SMALL);
addflag(lastot->flags, F_LINKSPELL, OT_S_TELEPORT, 4, NA, NULL);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_COMMON, NULL);
addflag(lastot->flags, F_AIFLEEITEM, B_TRUE, NA, NA, NULL);
addot(OT_SCR_TURNUNDEAD, "scroll of turn undead", "Instills fear in undead creatures.", MT_PAPER, 0.5, OC_SCROLL, SZ_SMALL);
addflag(lastot->flags, F_LINKSPELL, OT_S_TURNUNDEAD, NA, NA, NULL);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 70, RR_UNCOMMON, NULL);
addot(OT_SCR_WISH, "scroll of wishing", "Grants the caster any item of their choice (with some limitations).", MT_PAPER, 0.5, OC_SCROLL, SZ_SMALL);
addflag(lastot->flags, F_LINKSPELL, OT_S_WISHLIMITED, NA, NA, NULL);
// spells - actually defined as object types
// MUST DEFINE THESE _AFTER_ SCROLLS
///////////////////
// allomancy
///////////////////
// l1
addot(OT_S_ABSORBMETAL, "absorb metal", "Draws mana from nearby metallic objects.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "Spell power determines the maximum amount of metal which can be absorbed.");
addflag(lastot->flags, F_SPELLSCHOOL, SS_ALLOMANCY, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 1, NA, NA, NULL);
addflag(lastot->flags, F_MPCOST, 0, NA, NA, NULL);
// l2
addot(OT_S_PULLMETAL, "pull metal", "Pulls metal objects to the caster.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_SPELLSCHOOL, SS_ALLOMANCY, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 2, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOATTACK, ST_VICTIM, NA, NA, NULL);
addflag(lastot->flags, F_MAXPOWER, 1, NA, NA, NULL);
addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_WALLSTOP, NA, NULL);
addot(OT_S_ACCELMETAL, "accelerate metal", "Greatly accelerates a metal object thrown by the caster.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "Spell power determines how fast the object is propelled.");
addflag(lastot->flags, F_SPELLSCHOOL, SS_ALLOMANCY, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 2, NA, NA, NULL);
addflag(lastot->flags, F_LOSLOF, B_FALSE, LOF_WALLSTOP, NA, NULL);
addot(OT_S_METALHEAL, "metal healing", "Uses nearby metal for accelerated healing.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "Spell power determines how much damage is healed.");
addflag(lastot->flags, F_SPELLSCHOOL, SS_ALLOMANCY, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 2, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOFLEE, ST_SELF, NA, NA, NULL);
// l3
addot(OT_S_EXPLODEMETAL, "explode metal", "Causes all metal objects in a location explode.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_SPELLSCHOOL, SS_ALLOMANCY, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 3, NA, NA, NULL);
addflag(lastot->flags, F_MAXPOWER, 1, NA, NA, NULL);
addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_DONTNEED, NA, NULL);
addot(OT_S_MAGSHIELD, "magnetic shield", "Surrounds the caster with magnetic force, repelling metal objects and attacks.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "Spell power determines how long the magnetic shield will last.");
addflag(lastot->flags, F_SPELLSCHOOL, SS_ALLOMANCY, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 3, NA, NA, NULL);
// l4
addot(OT_S_ANIMATEMETAL, "animate metal", "Imbues a metallic weapon with temporary life, enabling it to fight on its own.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_SPELLSCHOOL, SS_ALLOMANCY, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 4, NA, NA, NULL);
addflag(lastot->flags, F_MAXPOWER, 1, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOATTACK, ST_SELF, NA, NA, NULL);
///////////////////
// death
///////////////////
// l1
addot(OT_S_STENCH, "stench", "Nauseates the target.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "Spell power determines resistability and duration.");
addflag(lastot->flags, F_SPELLSCHOOL, SS_DEATH, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 1, NA, NA, NULL);
addflag(lastot->flags, F_MAXPOWER, 4, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOATTACK, ST_VICTIM, NA, NA, NULL);
addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_DONTNEED, NA, NULL);
// l2
addot(OT_S_BLINDNESS, "blindness", "Temporarily blinds the target.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "Spell power determines resistability and duration.");
addflag(lastot->flags, F_SPELLSCHOOL, SS_ENCHANTMENT, NA, NA, NULL);
addflag(lastot->flags, F_SPELLSCHOOL, SS_DEATH, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 2, NA, NA, NULL);
addflag(lastot->flags, F_MAXPOWER, 1, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOATTACK, ST_VICTIM, NA, NA, NULL);
addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_DONTNEED, NA, NULL);
addot(OT_S_COMMANDUNDEAD, "command undead", "Compels an undead creature to follow a single simple command.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "Spell power determines resistability.");
addflag(lastot->flags, F_SPELLSCHOOL, SS_DEATH, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 2, NA, NA, NULL);
addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_DONTNEED, NA, NULL);
addot(OT_S_FEAR, "cause fear", "Causes intense fear in the target.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "Spell power determines resistability and duration.");
addflag(lastot->flags, F_SPELLSCHOOL, SS_ENCHANTMENT, NA, NA, NULL);
addflag(lastot->flags, F_SPELLSCHOOL, SS_MENTAL, NA, NA, NULL);
addflag(lastot->flags, F_SPELLSCHOOL, SS_DEATH, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 2, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOFLEE, ST_VICTIM, NA, NA, NULL);
addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_DONTNEED, NA, NULL);
addot(OT_S_SMITEGOOD, "smite good", "Instantly deals 1-^bpower*2^n damage to good creatures.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_SPELLSCHOOL, SS_DEATH, NA, NA, NULL);
addflag(lastot->flags, F_MAXPOWER, 6, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 2, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOATTACK, ST_VICTIM, NA, NA, NULL);
addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_DONTNEED, NA, NULL);
// l3
addot(OT_S_POISONBOLT, "venom bolt", "Fires a glob of venom at the target.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "Spell power determines how difficult the venom is to dodge, and how powerful the poison is.");
addflag(lastot->flags, F_SPELLSCHOOL, SS_DEATH, NA, NA, NULL);
addflag(lastot->flags, F_SPELLSCHOOL, SS_NATURE, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 3, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOATTACK, ST_VICTIM, NA, NA, NULL);
addflag(lastot->flags, F_LOSLOF, B_FALSE, LOF_NEED, NA, NULL);
addot(OT_S_DRAINLIFE, "drain life", "Draws life force from the victim in order to heal the caster.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "The amount of life force drained is ^b1d6+power^n.");
addflag(lastot->flags, F_SPELLSCHOOL, SS_DEATH, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 3, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOATTACK, ST_VICTIM, NA, NA, NULL);
addflag(lastot->flags, F_LOSLOF, B_FALSE, LOF_NEED, NA, NULL);
addot(OT_S_PAIN, "pain", "Causes extreme pain in the target whenever they move.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "Spell power determines the duration of the pain effect.");
addflag(lastot->flags, F_SPELLSCHOOL, SS_ENCHANTMENT, NA, NA, NULL);
addflag(lastot->flags, F_SPELLSCHOOL, SS_DEATH, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 3, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOATTACK, ST_VICTIM, NA, NA, NULL);
addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_DONTNEED, NA, NULL);
// l4
addot(OT_S_WEAKEN, "weaken", "Temporarily lowers the target's muscle strength by ^bpower^n points.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "Spell power determines the duration of the weakness effect.");
addflag(lastot->flags, F_SPELLSCHOOL, SS_ENCHANTMENT, NA, NA, NULL);
addflag(lastot->flags, F_SPELLSCHOOL, SS_DEATH, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 4, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOATTACK, ST_VICTIM, NA, NA, NULL);
addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_DONTNEED, NA, NULL);
addot(OT_S_PARALYZE, "paralyze", "Disables the target's muscles, leaving them unable to move for ^bpower*2^n turns.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_SPELLSCHOOL, SS_ENCHANTMENT, NA, NA, NULL);
addflag(lastot->flags, F_SPELLSCHOOL, SS_DEATH, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 3, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOATTACK, ST_VICTIM, NA, NA, NULL);
addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_DONTNEED, NA, NULL);
// l5
addot(OT_S_ANIMATEDEAD, "animate dead", "Imbues nearby corpses with life, creating an undead zombie.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "Spell power determines the chances of the zombies being friendly.");
addflag(lastot->flags, F_SPELLSCHOOL, SS_DEATH, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 5, NA, NA, NULL);
// TODO: should be "castnearob ot_corpse"
addflag(lastot->flags, F_AICASTTOATTACK, ST_ANYWHERE, NA, NA, NULL);
addot(OT_S_FEEBLEMIND, "brain freeze", "Temporarily lowers the target's intelligence to that of an animal.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "Spell power determines duration.");
addflag(lastot->flags, F_SPELLSCHOOL, SS_ENCHANTMENT, NA, NA, NULL);
addflag(lastot->flags, F_SPELLSCHOOL, SS_DEATH, NA, NA, NULL);
addflag(lastot->flags, F_SPELLSCHOOL, SS_MENTAL, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 5, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOATTACK, ST_VICTIM, NA, NA, NULL);
addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_DONTNEED, NA, NULL);
// l6
addot(OT_S_POSSESSION, "possession", "Completely possess an enemy, moving your consciousness into their body.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "Spell power determines its resistability.");
addflag(lastot->flags, F_SPELLSCHOOL, SS_DEATH, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 6, NA, NA, NULL);
addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_DONTNEED, NA, NULL);
addot(OT_S_INFINITEDEATH, "infinite death", "Annihilates all nearby life, including the caster!", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "Spell power determines resistability.");
addflag(lastot->flags, F_SPELLSCHOOL, SS_DEATH, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 6, NA, NA, NULL);
addflag(lastot->flags, F_CASTINGTIME, 2, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOATTACK, ST_ANYWHERE, NA, NA, NULL);
///////////////////
// divination
///////////////////
// l1
addot(OT_S_DETECTLIFE, "detect life", "Senses the size of creatures near the caster.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "Spell power determines the detection range.");
addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "At power VI, exact creatures types are detected.");
addflag(lastot->flags, F_SPELLSCHOOL, SS_DIVINATION, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 1, NA, NA, NULL);
// l2
addot(OT_S_LOCATEOBJECT, "locate object", "Locates any object within an area the caster has previously travelled.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_SPELLSCHOOL, SS_DIVINATION, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 2, NA, NA, NULL);
addflag(lastot->flags, F_MAXPOWER, 1, NA, NA, NULL);
addot(OT_S_MAPPING, "sense surroundings", "Magically imbues the caster with a map of his/her surroundings.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "Spell power determines the detection range.");
addflag(lastot->flags, F_SPELLSCHOOL, SS_DIVINATION, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 2, NA, NA, NULL);
// l3
addot(OT_S_SEEINVIS, "see invisible", "Allows the caster to see invisible creatures.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_SPELLSCHOOL, SS_DIVINATION, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 3, NA, NA, NULL);
addflag(lastot->flags, F_MAXPOWER, 1, NA, NA, NULL);
addflag(lastot->flags, F_ONGOING, B_TRUE, NA, NA, NULL);
addot(OT_S_DETECTOBS, "detect objects", "Senses objects near the caster.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "Spell power determines the detection range and spell duration.");
addflag(lastot->flags, F_SPELLSCHOOL, SS_DIVINATION, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 3, NA, NA, NULL);
// l4
addot(OT_S_DETECTAURA, "detect aura", "Senses holiness or evil near the caster.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_SPELLSCHOOL, SS_DIVINATION, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 4, NA, NA, NULL);
addflag(lastot->flags, F_MAXPOWER, 1, NA, NA, NULL);
addot(OT_S_LORE, "lore", "Obtain knowledge about any one species.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "At power I, you gain Novice level knowledge.");
addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "At power II, you gain Beginner level knowledge.");
addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "At power IV, you gain Adept level knowledge.");
addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "At power VI, you gain Skilled level knowledge.");
addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "At power VIII, you gain Expert level knowledge.");
addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "At power X, you gain Master level knowledge.");
addflag(lastot->flags, F_SPELLSCHOOL, SS_DIVINATION, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 4, NA, NA, NULL);
addflag(lastot->flags, F_ONGOING, B_TRUE, NA, NA, NULL);
addot(OT_S_REVEALHIDDEN, "reveal hidden", "Reveals hidden doors or invisible creatures in the caster's line of sight.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_SPELLSCHOOL, SS_DIVINATION, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 4, NA, NA, NULL);
addflag(lastot->flags, F_MAXPOWER, 1, NA, NA, NULL);
// l5
addot(OT_S_DETECTMAGIC, "detect magic", "Allows the caster to detect magical enchantments.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "Spell power determines duration.");
addflag(lastot->flags, F_SPELLSCHOOL, SS_DIVINATION, NA, NA, NULL);
addflag(lastot->flags, F_SPELLSCHOOL, SS_NATURE, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 5, NA, NA, NULL);
// l6
addot(OT_S_IDENTIFY, "identification", "Completely identifies any one item.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_MAXPOWER, 1, NA, NA, NULL);
addflag(lastot->flags, F_SPELLSCHOOL, SS_DIVINATION, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 6, NA, NA, NULL);
///////////////////
// enchantment
///////////////////
// l7
addot(OT_S_ENCHANT, "enchantment", "Magically enhances a weapon or piece of armour.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_MAXPOWER, 1, NA, NA, NULL);
addflag(lastot->flags, F_SPELLSCHOOL, SS_ENCHANTMENT, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 6, NA, NA, NULL);
// TODO: hardcode how ai casts this spell
///////////////////
// elemental - air
///////////////////
// l1
addot(OT_S_MIST, "pea soup", "Hides the caster from view with a thick cloud of mist.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "Spell power determines how long the mist will last.");
addflag(lastot->flags, F_SPELLSCHOOL, SS_AIR, NA, NA, NULL);
addflag(lastot->flags, F_SPELLSCHOOL, SS_NATURE, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 1, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOFLEE, ST_ADJSELF, NA, NA, NULL);
addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_DONTNEED, NA, NULL);
addot(OT_S_CALLWIND, "zephyr", "Conjures a friendly wind, carrying a single object to the caster's hands.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "Spell power determines its range and the weight of objects affected.");
addflag(lastot->flags, F_SPELLSCHOOL, SS_AIR, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 1, NA, NA, NULL);
addflag(lastot->flags, F_MAXPOWER, 5, NA, NA, NULL);
addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_NEED, NA, NULL);
addot(OT_S_JOLT, "jolt", "Jolts an adjacent enemy with a short pulse of electricity, dealing 1-^bpower^n damage.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_SPELLSCHOOL, SS_AIR, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 1, NA, NA, NULL);
addflag(lastot->flags, F_MAXPOWER, 6, NA, NA, NULL);
addflag(lastot->flags, F_RANGE, 1, NA, NA, NULL);
addflag(lastot->flags, F_LOSLOF, B_FALSE, LOF_NEED, NA, NULL);
addflag(lastot->flags, F_AICASTTOATTACK, ST_ADJVICTIM, NA, NA, NULL);
// l2
addot(OT_S_GUSTOFWIND, "gust of wind", "Causes a gust of wind to blow up to ^bpower^n of the target's objects away.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "The chance of each object blowing away is determined by the spell's power.");
addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "This spell's power is boosted when cast outside.");
addflag(lastot->flags, F_SPELLSCHOOL, SS_AIR, NA, NA, NULL);
addflag(lastot->flags, F_SPELLSCHOOL, SS_NATURE, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 2, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOATTACK, ST_VICTIM, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOFLEE, ST_VICTIM, NA, NA, NULL);
addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_NEED, NA, NULL);
addot(OT_S_SHATTER, "shatter", "Instantly shatters all glass in the target location.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_SPELLSCHOOL, SS_AIR, NA, NA, NULL);
addflag(lastot->flags, F_SPELLSCHOOL, SS_COLD, NA, NA, NULL);
addflag(lastot->flags, F_SPELLSCHOOL, SS_GRAVITY, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 2, NA, NA, NULL);
addflag(lastot->flags, F_MAXPOWER, 1, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOATTACK, ST_VICTIM, NA, NA, NULL);
addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_DONTNEED, NA, NULL);
// l3
addot(OT_S_AIRBLAST, "airblast", "Knocks enemies back with a powerful blast of air.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "This spell's power determines how far objects or enemies will be knocked back.");
addflag(lastot->flags, F_SPELLSCHOOL, SS_AIR, NA, NA, NULL);
addflag(lastot->flags, F_SPELLSCHOOL, SS_NATURE, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 3, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOFLEE, ST_VICTIM, NA, NA, NULL);
addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_NEED, NA, NULL);
addot(OT_S_WINDSHIELD, "cyclonic shield", "Surrounds the caster with a whirling cyclone to repel missiles.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "The spell's power determines the speed of missile which can be repelled.");
addflag(lastot->flags, F_SPELLSCHOOL, SS_AIR, NA, NA, NULL);
addflag(lastot->flags, F_SPELLSCHOOL, SS_NATURE, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 3, NA, NA, NULL);
addflag(lastot->flags, F_VARPOWER, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_ONGOING, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOATTACK, ST_SELF, NA, NA, NULL);
// l4
addot(OT_S_CLOUDKILL, "cloudkill", "Creates a cloud of poisonous gas. The cloud's size is 1-3 cells, depending on the spell power.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_SPELLSCHOOL, SS_AIR, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 4, NA, NA, NULL);
addflag(lastot->flags, F_LOSLOF, B_FALSE, LOF_NEED, NA, NULL);
addflag(lastot->flags, F_AICASTTOATTACK, ST_VICTIM, NA, NA, NULL);
// l5
addot(OT_S_CHAINLIGHTNING, "chain lightning", "Electricity arcs up to 5 times between all nearby enemies. The initial arc deals 3d6 damage, the next deals 3d5 damage, etc.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "The spell's range is based on its power.");
addflag(lastot->flags, F_SPELLSCHOOL, SS_AIR, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 5, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOATTACK, ST_VICTIM, NA, NA, NULL);
addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_NEED, NA, NULL);
///////////////////
// elemental - fire
///////////////////
// l1
addot(OT_S_SPARK, "spark", "Creates a tiny spark of flame, dealing 1-3 fire damage to creatures and objects.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_SPELLSCHOOL, SS_FIRE, NA, NA, NULL);
addflag(lastot->flags, F_SPELLSCHOOL, SS_NATURE, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 1, NA, NA, NULL);
addflag(lastot->flags, F_MAXPOWER, 1, NA, NA, NULL);
addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_DONTNEED, NA, NULL);
// l2
addot(OT_S_BLADEBURN, "bladeburn", "Ignites the target's bladed weapon, causing it to temporarily deal fire damage. The spell's power determines how long it will last.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "The spell's power determines its duration.");
addflag(lastot->flags, F_SPELLSCHOOL, SS_FIRE, NA, NA, NULL);
addflag(lastot->flags, F_SPELLSCHOOL, SS_ENCHANTMENT, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 2, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOATTACK, ST_SELF, NA, NA, NULL);
addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_DONTNEED, NA, NULL);
addot(OT_S_FIREDART, "flame dart", "Fires a medium-sized dart of fire, dealing 1d6+^bpower^n fire damage.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_SPELLSCHOOL, SS_FIRE, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 2, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOATTACK, ST_VICTIM, NA, NA, NULL);
addflag(lastot->flags, F_LOSLOF, B_FALSE, LOF_NEED, NA, NULL);
// l3
addot(OT_S_FLAMEBURST, "flame burst", "Creates a radial blast of fire out from the caster, inflicting 2d6 fire damage to all within.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "The size of the radial blast is based on the spell's power.");
addflag(lastot->flags, F_SPELLSCHOOL, SS_FIRE, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 3, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOATTACK, ST_ADJSELF, NA, NA, NULL);
// l4
addot(OT_S_FLAMEPILLAR, "flame pillar", "Creates a tall pillar of flame.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "Spell power determines how long the flames will persist.");
addflag(lastot->flags, F_SPELLSCHOOL, SS_FIRE, NA, NA, NULL);
addflag(lastot->flags, F_SPELLSCHOOL, SS_NATURE, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 4, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOATTACK, ST_VICTIM, NA, NA, NULL);
addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_WALLSTOP, NA, NULL);
// l5
addot(OT_S_BURNINGWAVE, "burning wave", "Fire bursts from the ground in a line towards the target.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "The spell's range is based on its power.");
addflag(lastot->flags, F_SPELLSCHOOL, SS_FIRE, NA, NA, NULL);
addflag(lastot->flags, F_SPELLSCHOOL, SS_NATURE, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 5, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOATTACK, ST_VICTIM, NA, NA, NULL);
addflag(lastot->flags, F_RANGE, 3, NA, NA, NULL);
addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_WALLSTOP, NA, NULL);
addot(OT_S_FIREBALL, "fireball", "Creates a huge ball of fire, dealing up to ^bpower^nd3 damage.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "The damage is lower for enemies further away from the ball's centre.");
addflag(lastot->flags, F_SPELLSCHOOL, SS_FIRE, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 5, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOATTACK, ST_VICTIM, NA, NA, NULL); // TODO: should be "near victim"
addflag(lastot->flags, F_LOSLOF, B_FALSE, LOF_NEED, NA, NULL);
///////////////////
// elemental - cold
///////////////////
// l1
addot(OT_S_CHILL, "chill", "Deals minor (1d3) cold damage to a single target.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_SPELLSCHOOL, SS_COLD, NA, NA, NULL);
addflag(lastot->flags, F_MAXPOWER, 1, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 1, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOATTACK, ST_VICTIM, NA, NA, NULL);
addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_DONTNEED, NA, NULL);
addot(OT_S_GLACIATE, "glaciate", "Slows down molecules in a given area, instantly freezing any water present. Has no effect on living creatures.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_SPELLSCHOOL, SS_COLD, NA, NA, NULL);
addflag(lastot->flags, F_MAXPOWER, 1, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 1, NA, NA, NULL);
addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_DONTNEED, NA, NULL);
addot(OT_S_SNOWBALL, "snowball", "Throws a large snowball, dealing 1 cold damage to all within its blast. The remaining snow will quickly melt to water.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_SPELLSCHOOL, SS_COLD, NA, NA, NULL);
addflag(lastot->flags, F_MAXPOWER, 1, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 1, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOATTACK, ST_VICTIM, NA, NA, NULL);
addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_NEED, NA, NULL);
// l2
addot(OT_S_FREEZEOB, "freezing touch", "Changes the next thing touched into solid ice. The effect is permenant for inanimate objects, but will wear off on living creatures.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_SPELLSCHOOL, SS_MODIFICATION, NA, NA, NULL);
addflag(lastot->flags, F_SPELLSCHOOL, SS_COLD, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 2, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOATTACK, ST_SELF, NA, NA, NULL);
addot(OT_S_ICEEDGE, "ice edge", "Enhances the edge of a bladed weapon with a layer of ice.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "Spell power determines how long the enchantment will remain.");
addflag(lastot->flags, F_SPELLSCHOOL, SS_ENCHANTMENT, NA, NA, NULL);
addflag(lastot->flags, F_SPELLSCHOOL, SS_COLD, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 2, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOATTACK, ST_SELF, NA, NA, NULL);
addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_DONTNEED, NA, NULL);
addot(OT_S_CRYSTALSHIELD, "crystalline shield", "Summons a shield of ice crystals to protect you from missiles.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "Spell power determines how effective the shield is.");
addflag(lastot->flags, F_SPELLSCHOOL, SS_COLD, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 2, NA, NA, NULL);
addflag(lastot->flags, F_MAXPOWER, 6, NA, NA, NULL);
addflag(lastot->flags, F_ONGOING, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_LOSLOF, B_FALSE, LOF_DONTNEED, NA, NULL);
// l3
addot(OT_S_COLDRAY, "cold ray", "Shoots a blast of ice cold air, dealing 3d6 cold damage.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "Spell power determines how difficult the ray is to dodge.");
addflag(lastot->flags, F_SPELLSCHOOL, SS_COLD, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 3, NA, NA, NULL);
addflag(lastot->flags, F_MAXPOWER, 1, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOATTACK, ST_VICTIM, NA, NA, NULL);
addflag(lastot->flags, F_LOSLOF, B_FALSE, LOF_NEED, NA, NULL);
addot(OT_S_COLDBURST, "cold burst", "Creates a radial blast of coldness out from the caster, dealing 1d8+3 cold damage.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "The spell's range is based on its power.");
addflag(lastot->flags, F_SPELLSCHOOL, SS_COLD, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 3, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOATTACK, ST_ADJSELF, NA, NA, NULL);
addot(OT_S_ICICLE, "icicle", "A huge icicle rises form the ground, knocking enemies away and blocking passage.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "The spell's power determines how long the icicle will remain.");
addflag(lastot->flags, F_SPELLSCHOOL, SS_COLD, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 3, NA, NA, NULL);
addflag(lastot->flags, F_MAXPOWER, 1, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOFLEE, ST_VICTIM, NA, NA, NULL);
addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_DONTNEED, NA, NULL);
addot(OT_S_SLIDE, "slipslide", "Generate ice underneath your feet, allowing you to slide along the ground at high speeds.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "The spell's duration is based on its power, however its effects will also end if you stop moving.");
addflag(lastot->flags, F_SPELLSCHOOL, SS_COLD, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 3, NA, NA, NULL);
addflag(lastot->flags, F_ONGOING, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOFLEE, ST_SELF, NA, NA, NULL);
addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_DONTNEED, NA, NULL);
// l4
addot(OT_S_FROSTBITE, "frostbite", "Deals 1d3 cold damage to target creature per exposed body part.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_SPELLSCHOOL, SS_COLD, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 4, NA, NA, NULL);
addflag(lastot->flags, F_MAXPOWER, 1, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOATTACK, ST_VICTIM, NA, NA, NULL);
addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_DONTNEED, NA, NULL);
addot(OT_S_WALLOFICE, "wall of ice", "Creates an impassable wall of solid ice.", MT_ICE, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "The spell's power determines how long the wall will remain.");
addflag(lastot->flags, F_SPELLSCHOOL, SS_COLD, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 4, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOFLEE, ST_VICTIM, NA, NA, NULL);
addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_DONTNEED, NA, NULL);
addot(OT_S_CRYSTALARM, "crystalline armour", "Summons ice crystal armour to protect you from damage.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "At power 1-3: one piece of armour is created.");
addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "At power 4-6: two pieces of armour are created.");
addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "At power 7-9: three pieces of armour are created.");
addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "At power 10: four pieces of armour are created.");
addflag(lastot->flags, F_SPELLSCHOOL, SS_COLD, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 4, NA, NA, NULL);
addflag(lastot->flags, F_ONGOING, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_LOSLOF, B_FALSE, LOF_DONTNEED, NA, NULL);
addot(OT_S_SHARDSHOT, "shard shot", "Fires a scattered burst of small, fast moving ice shards. The shot will pass through multiple creatures, but damage is reduced with range.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "The spell's range is determined by its power.");
addflag(lastot->flags, F_SPELLSCHOOL, SS_COLD, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 5, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOATTACK, ST_VICTIM, NA, NA, NULL);
addflag(lastot->flags, F_LOSLOF, B_FALSE, LOF_WALLSTOP, NA, NULL);
addot(OT_S_SNAPFREEZE, "snap freeze", "Instantly freezes the target creature. Cold-resistant creatures will take minor damage instead.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_SPELLSCHOOL, SS_COLD, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 5, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOATTACK, ST_VICTIM, NA, NA, NULL);
addflag(lastot->flags, F_RANGE, 1, NA, NA, NULL);
addflag(lastot->flags, F_LOSLOF, B_FALSE, LOF_NEED, NA, NULL);
// l6
addot(OT_S_ABSOLUTEZERO, "absolute zero", "Instantly freezes everything around the caster - creatures, objects, even the ground itself.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_SPELLSCHOOL, SS_COLD, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 6, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOATTACK, ST_ANYWHERE, NA, NA, NULL);
addflag(lastot->flags, F_LOSLOF, B_FALSE, LOF_DONTNEED, NA, NULL);
///////////////////
// nature
///////////////////
// l1
addot(OT_S_CALMANIMALS, "calm animals", "Makes animals within the casters line of sight become peaceful.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "The spell's power determines how many hit dice worth of creatures will be affected.");
addflag(lastot->flags, F_SPELLSCHOOL, SS_NATURE, NA, NA, NULL);
addflag(lastot->flags, F_SPELLSCHOOL, SS_MENTAL, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 1, NA, NA, NULL);
addot(OT_S_DETECTPOISON, "detect poison", "Detects any poisoned object in sight of the caster.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_SPELLSCHOOL, SS_NATURE, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 1, NA, NA, NULL);
addflag(lastot->flags, F_MAXPOWER, 1, NA, NA, NULL);
addot(OT_S_PURIFYFOOD, "purify food", "Removes rot or poison from food or drink.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_SPELLSCHOOL, SS_NATURE, NA, NA, NULL);
addflag(lastot->flags, F_SPELLSCHOOL, SS_ENCHANTMENT, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 1, NA, NA, NULL);
addflag(lastot->flags, F_MAXPOWER, 1, NA, NA, NULL);
addot(OT_S_STICKTOSNAKE, "sticks to snakes", "Transforms all seen wooden weapons into snakes.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_SPELLSCHOOL, SS_NATURE, NA, NA, NULL);
addflag(lastot->flags, F_SPELLSCHOOL, SS_MODIFICATION, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 1, NA, NA, NULL);
addflag(lastot->flags, F_MAXPOWER, 1, NA, NA, NULL);
// l2
addot(OT_S_BARKSKIN, "barkskin", "Covers the caster with a skin of bark, reducing damage but making them vulnerable to fire.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_SPELLSCHOOL, SS_ENCHANTMENT, NA, NA, NULL);
addflag(lastot->flags, F_SPELLSCHOOL, SS_NATURE, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 2, NA, NA, NULL);
addflag(lastot->flags, F_ONGOING, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOATTACK, ST_SELF, NA, NA, NULL);
addot(OT_S_CHARMANIMAL, "befriend animal", "Temporarily makes a single animal friendly to you.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "The spell's power determines how the maximum hit dice creature which can be affected.");
addflag(lastot->flags, F_SPELLSCHOOL, SS_NATURE, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 2, NA, NA, NULL);
addflag(lastot->flags, F_MAXPOWER, 5, NA, NA, NULL);
addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_DONTNEED, NA, NULL);
addot(OT_S_LESSENPOISON, "lessen poison", "Reduces the effects of poison within the caster's bloodstream.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_SPELLSCHOOL, SS_NATURE, NA, NA, NULL);
addflag(lastot->flags, F_SPELLSCHOOL, SS_LIFE, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 2, NA, NA, NULL);
addflag(lastot->flags, F_MAXPOWER, 1, NA, NA, NULL);
addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_DONTNEED, NA, NULL);
addot(OT_S_REPELINSECTS, "repel insects", "Surrounds the caster with an insect-repelling smell.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_SPELLSCHOOL, SS_NATURE, NA, NA, NULL);
addflag(lastot->flags, F_ONGOING, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 2, NA, NA, NULL);
addflag(lastot->flags, F_MAXPOWER, 1, NA, NA, NULL);
addot(OT_S_SOFTENEARTH, "soften earth", "Converts earth into mud, slowing down.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "The spell's power determines how much mud will be created.");
addflag(lastot->flags, F_SPELLSCHOOL, SS_NATURE, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 2, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOFLEE, ST_VICTIM, NA, NA, NULL);
addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_DONTNEED, NA, NULL);
addot(OT_S_SUMMONANIMALSSM, "summon small animals", "Summons 2-3 small animals.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "The spell's power determines how long the summoned creatures will remain.");
addflag(lastot->flags, F_SPELLSCHOOL, SS_NATURE, NA, NA, NULL);
addflag(lastot->flags, F_SPELLSCHOOL, SS_SUMMONING, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 2, NA, NA, NULL);
addflag(lastot->flags, F_MAXPOWER, 5, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOATTACK, ST_ANYWHERE, NA, NA, NULL);
addot(OT_S_WARPWOOD, "warp wood", "Causes damage to all wooden object in the target area.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_SPELLSCHOOL, SS_NATURE, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 2, NA, NA, NULL);
addflag(lastot->flags, F_MAXPOWER, 1, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOATTACK, ST_VICTIM, NA, NA, NULL);
addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_DONTNEED, NA, NULL);
// l3
addot(OT_S_CALLLIGHTNING, "call lightning", "Blasts a single enemy with a bolt of lightning from the sky, dealing 3d6 damage (4d6 if outdoors).", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_SPELLSCHOOL, SS_NATURE, NA, NA, NULL);
addflag(lastot->flags, F_SPELLSCHOOL, SS_AIR, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 3, NA, NA, NULL);
addflag(lastot->flags, F_MAXPOWER, 1, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOATTACK, ST_VICTIM, NA, NA, NULL);
addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_DONTNEED, NA, NULL);
addot(OT_S_LIGHTNINGBOLT, "electricity bolt", "Fires a bolt of electricity through multiple enemies, dealing 2d6 damage to each.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "The spell's range is based on its power.");
addflag(lastot->flags, F_SPELLSCHOOL, SS_AIR, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 3, NA, NA, NULL);
addflag(lastot->flags, F_MAXPOWER, 1, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOATTACK, ST_VICTIM, NA, NA, NULL);
addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_WALLSTOP, NA, NULL);
addot(OT_S_ENDUREELEMENTS, "endure elements", "Provides resistance to fire and cold.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_SPELLSCHOOL, SS_ENCHANTMENT, NA, NA, NULL);
addflag(lastot->flags, F_SPELLSCHOOL, SS_NATURE, NA, NA, NULL);
addflag(lastot->flags, F_ONGOING, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_MAXPOWER, 1, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 3, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOATTACK, ST_SELF, NA, NA, NULL);
addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_DONTNEED, NA, NULL);
addot(OT_S_QUENCH, "quench", "Extinguishes all fires within the given area.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_SPELLSCHOOL, SS_NATURE, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 3, NA, NA, NULL);
addflag(lastot->flags, F_MAXPOWER, 1, NA, NA, NULL);
addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_DONTNEED, NA, NULL);
addot(OT_S_EVAPORATE, "evaporate", "Instantly converts all water in the given area into steam.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "The spell's power determines the amount of water affected.");
addflag(lastot->flags, F_SPELLSCHOOL, SS_NATURE, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 3, NA, NA, NULL);
addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_DONTNEED, NA, NULL);
addot(OT_S_SLEETSTORM, "sleet storm", "Creates an cloud of sleet, hampering vision and movement.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "The spell's power determines the size of the storm.");
addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "This spell's power is boosted when cast outside.");
addflag(lastot->flags, F_SPELLSCHOOL, SS_NATURE, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 3, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOFLEE, ST_VICTIM, NA, NA, NULL);
addflag(lastot->flags, F_MAXPOWER, 4, NA, NA, NULL);
addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_DONTNEED, NA, NULL);
addot(OT_S_THORNS, "thorns", "Sharp thorns grow from your skin, dealing 1d4 damage to attackers.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_SPELLSCHOOL, SS_NATURE, NA, NA, NULL);
addflag(lastot->flags, F_ONGOING, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 3, NA, NA, NULL);
addflag(lastot->flags, F_MAXPOWER, 1, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOATTACK, ST_SELF, NA, NA, NULL);
addflag(lastot->flags, F_LOSLOF, B_FALSE, LOF_DONTNEED, NA, NULL);
addot(OT_S_WEB, "web", "Slows down pursuers with a burst of sticky spider web.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "The spell's power determines how much webbing is created.");
addflag(lastot->flags, F_SPELLSCHOOL, SS_NATURE, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 3, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOATTACK, ST_VICTIM, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOFLEE, ST_VICTIM, NA, NA, NULL);
addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_NEED, NA, NULL);
// l4
addot(OT_S_DIG, "dig", "Blasts away earth to create passages.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "The spell's power determines how much earth can be destroyed.");
addflag(lastot->flags, F_SPELLSCHOOL, SS_NATURE, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 4, NA, NA, NULL);
addflag(lastot->flags, F_LOSLOF, B_FALSE, LOF_DONTNEED, NA, NULL);
addot(OT_S_ENTANGLE, "entangle", "Causes magical vines to hold enemies.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "The spell's power determines the strength of the vines.");
addflag(lastot->flags, F_SPELLSCHOOL, SS_NATURE, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 4, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOATTACK, ST_VICTIM, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOFLEE, ST_VICTIM, NA, NA, NULL);
addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_DONTNEED, NA, NULL);
addot(OT_S_CALMINGSCENT, "calming scent", "Automatically calms any nearby animals.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_SPELLSCHOOL, SS_NATURE, NA, NA, NULL);
addflag(lastot->flags, F_ONGOING, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 4, NA, NA, NULL);
addflag(lastot->flags, F_MAXPOWER, 1, NA, NA, NULL);
addot(OT_S_SATEHUNGER, "sate hunger", "Immediately satisfies the hunger of one living creature.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_SPELLSCHOOL, SS_NATURE, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 4, NA, NA, NULL);
addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_DONTNEED, NA, NULL);
addflag(lastot->flags, F_MAXPOWER, 1, NA, NA, NULL);
addot(OT_S_SUMMONANIMALSMD, "summon medium animals", "Summons 2-3 medium animals.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "The spell's power determines how long the summoned creatures will remain.");
addflag(lastot->flags, F_SPELLSCHOOL, SS_NATURE, NA, NA, NULL);
addflag(lastot->flags, F_SPELLSCHOOL, SS_SUMMONING, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 4, NA, NA, NULL);
addflag(lastot->flags, F_MAXPOWER, 5, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOATTACK, ST_ANYWHERE, NA, NA, NULL);
addot(OT_S_WATERJET, "water spray", "Fires a high pressure blast of water from the caster's hands.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "The spell's power determines how far enemies are knocked back.");
addflag(lastot->flags, F_SPELLSCHOOL, SS_NATURE, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 4, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOATTACK, ST_VICTIM, NA, NA, NULL);
addflag(lastot->flags, F_LOSLOF, B_FALSE, LOF_NEED, NA, NULL);
// l5
addot(OT_S_HAILSTORM, "hail storm", "Creates an intense storm of hail, causing damage to all within.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "The spell's power determines the size of the storm.");
addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "This spell's power is boosted when cast outside.");
addflag(lastot->flags, F_SPELLSCHOOL, SS_NATURE, NA, NA, NULL);
addflag(lastot->flags, F_SPELLSCHOOL, SS_COLD, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 5, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOATTACK, ST_VICTIM, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOFLEE, ST_VICTIM, NA, NA, NULL);
addflag(lastot->flags, F_MAXPOWER, 5, NA, NA, NULL);
addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_DONTNEED, NA, NULL);
// l6
addot(OT_S_LIGHTNINGSTORM, "lightning storm", "Blasts all visible enemies bolts of lightning from the sky, dealing 3d6 damage (4d6 if outdoors).", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "The spell's power determines how many bolts will appear.");
addflag(lastot->flags, F_SPELLSCHOOL, SS_NATURE, NA, NA, NULL);
addflag(lastot->flags, F_SPELLSCHOOL, SS_AIR, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 6, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOATTACK, ST_ANYWHERE, NA, NA, NULL);
addot(OT_S_SUMMONANIMALSLG, "summon large animals", "Summons 2-3 large animals.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "The spell's power determines how long the summoned creatures will remain.");
addflag(lastot->flags, F_SPELLSCHOOL, SS_NATURE, NA, NA, NULL);
addflag(lastot->flags, F_SPELLSCHOOL, SS_SUMMONING, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 6, NA, NA, NULL);
addflag(lastot->flags, F_MAXPOWER, 5, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOATTACK, ST_ANYWHERE, NA, NA, NULL);
addot(OT_S_FLOOD, "flood", "Creates a massive ball of water.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "The spell's power determines the amount of water which appears.");
addflag(lastot->flags, F_SPELLSCHOOL, SS_NATURE, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 6, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOATTACK, ST_VICTIM, NA, NA, NULL);
///////////////////
// gravity
///////////////////
// l1
addot(OT_S_TRUESTRIKE, "weapon attraction", "Gives the target unerring accuracy, making their attacks always hit.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "The spell's power determines the amount of strikes before it expires.");
addflag(lastot->flags, F_SPELLSCHOOL, SS_ENCHANTMENT, NA, NA, NULL);
addflag(lastot->flags, F_SPELLSCHOOL, SS_GRAVITY, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 1, NA, NA, NULL);
addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_DONTNEED, NA, NULL);
addflag(lastot->flags, F_VARPOWER, B_TRUE, NA, NA, NULL);
// l2
addot(OT_S_GRAVLOWER, "lessen gravity", "Causes the caster to fall very slowly.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_SPELLSCHOOL, SS_GRAVITY, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 3, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 1, NA, NA, NULL);
addflag(lastot->flags, F_ONGOING, B_TRUE, NA, NA, NULL);
// l3
addot(OT_S_SLOW, "slowness", "Decreases the speed of the target.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "The spell's power determines how long the slowness will last.");
addflag(lastot->flags, F_SPELLSCHOOL, SS_ENCHANTMENT, NA, NA, NULL);
addflag(lastot->flags, F_SPELLSCHOOL, SS_GRAVITY, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 3, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOATTACK, ST_VICTIM, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOFLEE, ST_VICTIM, NA, NA, NULL);
// l4
addot(OT_S_GRAVBOOST, "boost gravity", "Greatly increases gravity around the target, stopping them from moving.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "The spell's power determines how long its effects will last.");
addflag(lastot->flags, F_SPELLSCHOOL, SS_GRAVITY, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 4, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOATTACK, ST_VICTIM, NA, NA, NULL);
addot(OT_S_LEVITATION, "levitation", "Causes the caster hover a metre above the ground.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_SPELLSCHOOL, SS_ENCHANTMENT, NA, NA, NULL);
addflag(lastot->flags, F_SPELLSCHOOL, SS_GRAVITY, NA, NA, NULL);
addflag(lastot->flags, F_SPELLSCHOOL, SS_NATURE, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 4, NA, NA, NULL);
addflag(lastot->flags, F_MAXPOWER, 1, NA, NA, NULL);
addflag(lastot->flags, F_ONGOING, B_TRUE, NA, NA, NULL);
// l5
// l6
addot(OT_S_FLIGHT, "fly", "Allows the caster to fly.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_SPELLSCHOOL, SS_ENCHANTMENT, NA, NA, NULL);
addflag(lastot->flags, F_SPELLSCHOOL, SS_GRAVITY, NA, NA, NULL);
addflag(lastot->flags, F_SPELLSCHOOL, SS_AIR, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 6, NA, NA, NULL);
addflag(lastot->flags, F_MAXPOWER, 1, NA, NA, NULL);
addflag(lastot->flags, F_ONGOING, B_TRUE, NA, NA, NULL);
addot(OT_S_HASTE, "haste", "Increases the speed of the target.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "The spell's power determines how long its effects will last.");
addflag(lastot->flags, F_SPELLSCHOOL, SS_GRAVITY, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 6, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOATTACK, ST_SELF, NA, NA, NULL);
addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_DONTNEED, NA, NULL);
///////////////////
// life / cleric spells
///////////////////
// l1
addot(OT_S_HEALINGMIN, "minor healing", "Restores 1-8 health to the caster.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "This spell heals an extra 2 damage per power level.");
addflag(lastot->flags, F_SPELLSCHOOL, SS_LIFE, NA, NA, NULL);
addflag(lastot->flags, F_SPELLSCHOOL, SS_NATURE, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 1, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOFLEE, ST_SELF, NA, NA, NULL);
addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_DONTNEED, NA, NULL);
addot(OT_S_TURNUNDEAD, "turn undead", "Instills fear in undead creatures.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_SPELLSCHOOL, SS_LIFE, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 1, NA, NA, NULL);
// l2
addot(OT_S_SPEAKDEAD, "speak with dead", "Temporarily allow a corpse to answer questions about its former life.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_SPELLSCHOOL, SS_LIFE, NA, NA, NULL);
addflag(lastot->flags, F_SPELLSCHOOL, SS_DEATH, NA, NA, NULL);
addflag(lastot->flags, F_MAXPOWER, 1, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 2, NA, NA, NULL);
addot(OT_S_SMITEEVIL, "smite evil", "Instantly deals 1-^bpower*2^n damage to evil creatures.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_SPELLSCHOOL, SS_LIFE, NA, NA, NULL);
addflag(lastot->flags, F_MAXPOWER, 10, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 2, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOATTACK, ST_VICTIM, NA, NA, NULL);
addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_DONTNEED, NA, NULL);
// l3
addot(OT_S_HEALING, "healing", "Restores 10-20 health to the caster.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "This spell heals an extra 2 damage per power level.");
addflag(lastot->flags, F_SPELLSCHOOL, SS_LIFE, NA, NA, NULL);
addflag(lastot->flags, F_SPELLSCHOOL, SS_NATURE, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 3, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOFLEE, ST_SELF, NA, NA, NULL);
addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_DONTNEED, NA, NULL);
addot(OT_S_HOLYAURA, "holy aura", "Surrounds the target with a holy aura, causing their weapon to deal holy damage.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_SPELLSCHOOL, SS_LIFE, NA, NA, NULL);
addflag(lastot->flags, F_ONGOING, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 3, NA, NA, NULL);
addflag(lastot->flags, F_MAXPOWER, 1, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOATTACK, ST_SELF, NA, NA, NULL);
addflag(lastot->flags, F_LOSLOF, B_FALSE, LOF_DONTNEED, NA, NULL);
// l4
addot(OT_S_HEALINGMAJ, "major healing", "Restores 20-30 health to the caster.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "This spell heals an extra 2 damage per power level.");
addflag(lastot->flags, F_SPELLSCHOOL, SS_LIFE, NA, NA, NULL);
addflag(lastot->flags, F_SPELLSCHOOL, SS_NATURE, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 4, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOFLEE, ST_SELF, NA, NA, NULL);
addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_DONTNEED, NA, NULL);
addot(OT_S_CUREPOISON, "cure poison", "Cures the target of all poisons.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_SPELLSCHOOL, SS_LIFE, NA, NA, NULL);
addflag(lastot->flags, F_SPELLSCHOOL, SS_NATURE, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 4, NA, NA, NULL);
addflag(lastot->flags, F_MAXPOWER, 1, NA, NA, NULL);
addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_DONTNEED, NA, NULL);
///////////////////
// mental/psionic
///////////////////
// l1
addot(OT_S_MINDSCAN, "mind scan", "Reveals detailed information about the target.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_SPELLSCHOOL, SS_MENTAL, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 1, NA, NA, NULL);
addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_DONTNEED, NA, NULL);
addot(OT_S_STUN, "stun", "Stuns the target, preventing them from taking action for a few seconds.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_SPELLSCHOOL, SS_MENTAL, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 1, NA, NA, NULL);
addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_DONTNEED, NA, NULL);
addflag(lastot->flags, F_AICASTTOATTACK, ST_VICTIM, NA, NA, NULL);
// l2
addot(OT_S_LOWERMETAB, "lower metabolism", "Slow your body's functions, decreasing your rate of hunger but also your movement speed.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "At power level III: your speed penalty is reduced.");
addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "At power level V: you no longer suffer a speed penalty.");
addflag(lastot->flags, F_SPELLSCHOOL, SS_MENTAL, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 2, NA, NA, NULL);
addflag(lastot->flags, F_ONGOING, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_DONTNEED, NA, NULL);
addot(OT_S_TELEKINESIS, "telekinesis", "Mentally move or manipulate nearby objects.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "This spell can lift up to 10kg per power level.");
addflag(lastot->flags, F_SPELLSCHOOL, SS_MENTAL, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 2, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOATTACK, ST_SPECIAL, NA, NA, NULL);
addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_WALLSTOP, NA, NULL);
addot(OT_S_BAFFLE, "baffle", "Confuses the target, causing them to lose control of their movement.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "The target will be confused for ^bpower^n*4 turns.");
addflag(lastot->flags, F_SPELLSCHOOL, SS_MENTAL, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 2, NA, NA, NULL);
addflag(lastot->flags, F_MAXPOWER, 5, NA, NA, NULL);
addflag(lastot->flags, F_LOSLOF, B_FALSE, LOF_DONTNEED, NA, NULL);
addflag(lastot->flags, F_AICASTTOATTACK, ST_VICTIM, NA, NA, NULL);
// l3
addot(OT_S_PSYARMOUR, "psychic armour", "Mentally block incoming attacks.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "The psychic armour's Armour Rating is ^bpower*4^n.");
addflag(lastot->flags, F_SPELLSCHOOL, SS_MENTAL, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 3, NA, NA, NULL);
addflag(lastot->flags, F_VARPOWER, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_ONGOING, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOATTACK, ST_SELF, NA, NA, NULL);
// TODO: hardcode how ai casts this
addot(OT_S_PACIFY, "pacify", "Induces calmness in another, preventing them from attacking.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "Spell power determines resistability.");
addflag(lastot->flags, F_SPELLSCHOOL, SS_ENCHANTMENT, NA, NA, NULL);
addflag(lastot->flags, F_SPELLSCHOOL, SS_MENTAL, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 3, NA, NA, NULL);
addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_DONTNEED, NA, NULL);
addot(OT_S_HUNGER, "hunger", "Causes the target to become ravenously hungry.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_SPELLSCHOOL, SS_MENTAL, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 3, NA, NA, NULL);
addflag(lastot->flags, F_MAXPOWER, 1, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOATTACK, ST_VICTIM, NA, NA, NULL);
addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_DONTNEED, NA, NULL);
// l4
addot(OT_S_STUNMASS, "mass stun", "Stuns all creatures within sight.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_SPELLSCHOOL, SS_MENTAL, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 4, NA, NA, NULL);
addflag(lastot->flags, F_LOSLOF, B_FALSE, LOF_DONTNEED, NA, NULL);
addflag(lastot->flags, F_AICASTTOATTACK, ST_VICTIM, NA, NA, NULL);
addot(OT_S_SLEEP, "sleep", "Puts the target creature to sleep.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "Spell power determines how long the sleep effect will last.");
addflag(lastot->flags, F_SPELLSCHOOL, SS_MENTAL, NA, NA, NULL);
addflag(lastot->flags, F_SPELLSCHOOL, SS_ENCHANTMENT, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 4, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOATTACK, ST_VICTIM, NA, NA, NULL);
addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_DONTNEED, NA, NULL);
// l5
addot(OT_S_CHARM, "charm", "Causes another lifeform to temporary become friendly.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "Spell power determines resistability and duration.");
addflag(lastot->flags, F_SPELLSCHOOL, SS_ENCHANTMENT, NA, NA, NULL);
addflag(lastot->flags, F_SPELLSCHOOL, SS_MENTAL, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 5, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOATTACK, ST_SPECIAL, NA, NA, NULL);
addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_DONTNEED, NA, NULL);
///////////////////
// modification
///////////////////
// l1
addot(OT_S_HOLDPORTAL, "hold portal", "Prevents a door from opening.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_SPELLSCHOOL, SS_MODIFICATION, NA, NA, NULL);
addflag(lastot->flags, F_SPELLSCHOOL, SS_ENCHANTMENT, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 1, NA, NA, NULL);
addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_DONTNEED, NA, NULL);
addot(OT_S_INSCRIBE, "inscribe", "Creates a magical inscription viewable to anyone standing nearby.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_SPELLSCHOOL, SS_MODIFICATION, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 1, NA, NA, NULL);
addot(OT_S_KNOCK, "knock", "Magically opens doors or other such barriers.\n", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "At Power VII, this spell will also knock back living creatures.");
addflag(lastot->flags, F_SPELLSCHOOL, SS_MODIFICATION, NA, NA, NULL);
addflag(lastot->flags, F_SPELLSCHOOL, SS_WILD, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 1, NA, NA, NULL);
addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_DONTNEED, NA, NULL);
addot(OT_S_LIGHT, "light area", "Creates a temporary light source centred on the caster.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "At Power III, you can control where the light appears.");
addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "At Power VIII, the light becomes permenant.");
addflag(lastot->flags, F_SPELLSCHOOL, SS_MODIFICATION, NA, NA, NULL);
addflag(lastot->flags, F_SPELLSCHOOL, SS_LIFE, NA, NA, NULL);
addflag(lastot->flags, F_SPELLSCHOOL, SS_NATURE, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 1, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOATTACK, ST_ANYWHERE, NA, NA, NULL);
addflag(lastot->flags, F_LOSLOF, B_FALSE, LOF_DONTNEED, NA, NULL);
// l2
addot(OT_S_DARKNESS, "darkness", "Permenantly darkens the area around the caster.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "At Power III, you can control where the darkness appears.");
addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "At Power VIII, the darkness becomes permenant.");
addflag(lastot->flags, F_SPELLSCHOOL, SS_MODIFICATION, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 2, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOATTACK, ST_ANYWHERE, NA, NA, NULL);
addot(OT_S_MENDING, "mending", "Repairs minor damage to objects (1d6 + ^bpower^n).", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_SPELLSCHOOL, SS_ENCHANTMENT, NA, NA, NULL);
addflag(lastot->flags, F_SPELLSCHOOL, SS_MODIFICATION, NA, NA, NULL);
addflag(lastot->flags, F_SPELLSCHOOL, SS_NATURE, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 2, NA, NA, NULL);
addot(OT_S_GREASE, "grease", "Creates a large pool of greasy oil.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "The spell's power determines the size of the grease pool.");
addflag(lastot->flags, F_SPELLSCHOOL, SS_MODIFICATION, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 2, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOATTACK, ST_VICTIM, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOFLEE, ST_VICTIM, NA, NA, NULL);
// l3
addot(OT_S_INVISIBILITY, "invisibility", "Temporarily renders the target invisible.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "The spell's power determines how long the invisibility will last.");
addflag(lastot->flags, F_SPELLSCHOOL, SS_MODIFICATION, NA, NA, NULL);
addflag(lastot->flags, F_SPELLSCHOOL, SS_ENCHANTMENT, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 3, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOATTACK, ST_SELF, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOFLEE, ST_SELF, NA, NA, NULL);
//addflag(lastot->flags, F_XPVAL, 50, NA, NA, NULL);
addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_DONTNEED, NA, NULL);
addot(OT_S_PASSWALL, "passwall", "Allows the caster to temporarily walk through a single wall.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "The spell's power determines how long the caster can wait before entering a wall.");
addflag(lastot->flags, F_SPELLSCHOOL, SS_ENCHANTMENT, NA, NA, NULL);
addflag(lastot->flags, F_SPELLSCHOOL, SS_TRANSLOCATION, NA, NA, NULL);
addflag(lastot->flags, F_SPELLSCHOOL, SS_NATURE, NA, NA, NULL);
addflag(lastot->flags, F_ONGOING, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 3, NA, NA, NULL);
// l5
addot(OT_S_GASEOUSFORM, "gaseous form", "Changes the caster into a cloud of gas.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_SPELLSCHOOL, SS_MODIFICATION, NA, NA, NULL);
addflag(lastot->flags, F_SPELLSCHOOL, SS_NATURE, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 5, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOATTACK, ST_SELF, NA, NA, NULL);
// l6
addot(OT_S_PETRIFY, "petrify", "Causes a living creature to turn into stone.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "Spell power determines resistability.");
addflag(lastot->flags, F_SPELLSCHOOL, SS_MODIFICATION, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 6, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOATTACK, ST_VICTIM, NA, NA, NULL);
addot(OT_S_POLYMORPH, "polymorph", "Transmutes the target into a new living race.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "Spell power determines resistability.");
addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "At power V, you can polymorph other creatures.");
addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "At power VIII, you can choose what kind of creature to polymorph into.");
addflag(lastot->flags, F_SPELLSCHOOL, SS_MODIFICATION, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 6, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOATTACK, ST_SELF, 10, NA, NULL);
addflag(lastot->flags, F_AICASTTOFLEE, ST_SELF, NA, NA, NULL);
///////////////////
// summoning
///////////////////
// l1
addot(OT_S_FLOATINGDISC, "floating disc", "Creates a disc of energy to carry your equipment.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "The spell's power level determines how much wight the disc can carry.");
addflag(lastot->flags, F_SPELLSCHOOL, SS_SUMMONING, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 1, NA, NA, NULL);
addflag(lastot->flags, F_MAXPOWER, 6, NA, NA, NULL);
addflag(lastot->flags, F_ONGOING, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_LOSLOF, B_FALSE, LOF_DONTNEED, NA, NULL);
addot(OT_S_SUMMONWEAPON, "summon weapon", "Summons a blade of pure magic into your hands. Deals 1-^bpower^n damage.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_SPELLSCHOOL, SS_SUMMONING, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 1, NA, NA, NULL);
addflag(lastot->flags, F_MAXPOWER, 6, NA, NA, NULL);
addflag(lastot->flags, F_VARPOWER, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_ONGOING, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_LOSLOF, B_FALSE, LOF_DONTNEED, NA, NULL);
// l2
addot(OT_S_CREATEMONSTER, "create monster", "Summons a (probably hostile) monster to a nearby location.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "At Power V you can control where the monster appears.");
addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "At Power VII you can control the type of monster created.");
addflag(lastot->flags, F_SPELLSCHOOL, SS_SUMMONING, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 2, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOATTACK, ST_ANYWHERE, NA, NA, NULL);
addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_DONTNEED, NA, NULL);
// l5
addot(OT_S_SUMMONDEMON, "summon demon", "Summons a random demonic entity.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "The spell's power determines its chances of success, and how long the demon will remain.");
addflag(lastot->flags, F_SPELLSCHOOL, SS_SUMMONING, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 5, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOATTACK, ST_ANYWHERE, NA, NA, NULL);
///////////////////
// translocation
///////////////////
// l2
addot(OT_S_BLINK, "blink", "Teleports the caster to a random location within view.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "At Power VI you can choose where to blink to.");
addflag(lastot->flags, F_SPELLSCHOOL, SS_TRANSLOCATION, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 2, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOFLEE, ST_SELF, NA, NA, NULL);
addflag(lastot->flags, F_MAXPOWER, 6, NA, NA, NULL);
addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_DONTNEED, NA, NULL);
addot(OT_S_SUCK, "suck", "Sucks the target lifeform towards the caster.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "Spell power determines resistability.");
addflag(lastot->flags, F_SPELLSCHOOL, SS_TRANSLOCATION, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 2, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOATTACK, ST_VICTIM, NA, NA, NULL);
addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_WALLSTOP, NA, NULL);
// l3
addot(OT_S_TWIDDLE, "twiddle", "Swaps places with the target creature.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_SPELLSCHOOL, SS_TRANSLOCATION, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 3, NA, NA, NULL);
addflag(lastot->flags, F_MAXPOWER, 1, NA, NA, NULL);
addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_DONTNEED, NA, NULL);
// l4
addot(OT_S_TELEPORT, "teleportation", "Teleports the caster (and Power-1 adjacent allies) to a new location within the same level.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "At power V, you can choose the general direction to teleport in.");
addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "At power VII, you can choose exactly where to teleport to.");
addflag(lastot->flags, F_SPELLSCHOOL, SS_TRANSLOCATION, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 4, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOFLEE, ST_SELF, NA, NA, NULL);
addflag(lastot->flags, F_LOSLOF, B_FALSE, LOF_DONTNEED, NA, NULL);
addot(OT_S_DISPERSAL, "dispersal", "Scatters everything in the target cell around the area.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "Spell power determines resistability.");
addflag(lastot->flags, F_SPELLSCHOOL, SS_TRANSLOCATION, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 5, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOFLEE, ST_VICTIM, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOATTACK, ST_VICTIM, NA, NA, NULL);
addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_DONTNEED, NA, NULL);
// l5
addot(OT_S_GATE, "gate", "Creates a portal to a different dungeon level (within ^bpower^n*2 levels).", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_SPELLSCHOOL, SS_TRANSLOCATION, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 5, NA, NA, NULL);
// l6
addot(OT_S_PLANESHIFT, "planeshift", "Instantly transports the caster to a different plane of existence.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_SPELLSCHOOL, SS_TRANSLOCATION, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 6, NA, NA, NULL);
addflag(lastot->flags, F_MAXPOWER, 1, NA, NA, NULL);
addflag(lastot->flags, F_LOSLOF, B_FALSE, LOF_DONTNEED, NA, NULL);
addflag(lastot->flags, F_AICASTTOFLEE, ST_SELF, NA, NA, NULL);
///////////////////
// wild
///////////////////
// l1
addot(OT_S_MANASPIKE, "mana spike", "Fires a small bolt of wild magic, dealing 1d2 magical damage per power level.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_SPELLSCHOOL, SS_WILD, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 1, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOATTACK, ST_VICTIM, NA, NA, NULL);
addflag(lastot->flags, F_MAXPOWER, 3, NA, NA, NULL);
addflag(lastot->flags, F_LOSLOF, B_FALSE, LOF_NEED, NA, NULL);
// l2
addot(OT_S_ENERGYBOLT, "energy bolt", "Fires a medium-sized bolt of wild magic, dealing 1d4 damage per power level.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_SPELLSCHOOL, SS_WILD, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 2, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOATTACK, ST_VICTIM, NA, NA, NULL);
addflag(lastot->flags, F_MAXPOWER, 3, NA, NA, NULL);
addflag(lastot->flags, F_LOSLOF, B_FALSE, LOF_NEED, NA, NULL);
addot(OT_S_ALARM, "alarm", "Creates a passive alarm which goes off when an enemy is nearby.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_SPELLSCHOOL, SS_WILD, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 2, NA, NA, NULL);
addflag(lastot->flags, F_LOSLOF, B_FALSE, LOF_DONTNEED, NA, NULL);
addflag(lastot->flags, F_ONGOING, B_TRUE, NA, NA, NULL);
// l3
addot(OT_S_ENERGYBLAST, "energy blast", "Causes a ring of energy to expand from the caster, causing 2d6 damage to anything in sight.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "Spell power determines the radius of the blast.");
addflag(lastot->flags, F_SPELLSCHOOL, SS_WILD, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 3, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOATTACK, ST_ADJSELF, NA, NA, NULL);
addot(OT_S_FLASH, "flash", "Causes a very bright flash, stunning anyone who sees it.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "Spell power determines the size of the flash.");
addflag(lastot->flags, F_SPELLSCHOOL, SS_WILD, NA, NA, NULL);
addflag(lastot->flags, F_SPELLSCHOOL, SS_NATURE, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 3, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOATTACK, ST_ANYWHERE, NA, NA, NULL);
// l6
addot(OT_S_DETONATE, "detonate", "Causes a given area to explode with massive force.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "Spell power determines the size of the explosion.");
addflag(lastot->flags, F_SPELLSCHOOL, SS_WILD, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 6, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOATTACK, ST_VICTIM, NA, NA, NULL);
// divine powers (spells/abilities)
addot(OT_A_BLINDALL, "nosight", "Make everyone on the level blind.", MT_NOTHING, 0, OC_ABILITY, SZ_TINY);
addflag(lastot->flags, F_SPELLSCHOOL, SS_ABILITY, NA, NA, NULL);
addot(OT_A_DEBUG, "debug", "You can toggle debugging for a lifeform.", MT_NOTHING, 0, OC_ABILITY, SZ_TINY);
addflag(lastot->flags, F_SPELLSCHOOL, SS_ABILITY, NA, NA, NULL);
addot(OT_A_ENHANCE, "enhance", "Enhance a lifeform's stats.", MT_NOTHING, 0, OC_ABILITY, SZ_TINY);
addflag(lastot->flags, F_SPELLSCHOOL, SS_ABILITY, NA, NA, NULL);
addot(OT_A_LEARN, "learn", "Learn new skills.", MT_NOTHING, 0, OC_ABILITY, SZ_TINY);
addflag(lastot->flags, F_SPELLSCHOOL, SS_ABILITY, NA, NA, NULL);
addot(OT_A_LEVELUP, "levelup", "Bestow the given xp level.", MT_NOTHING, 0, OC_ABILITY, SZ_TINY);
addflag(lastot->flags, F_SPELLSCHOOL, SS_ABILITY, NA, NA, NULL);
addot(OT_S_WISH, "wish", "Grants the caster any item of their choice. Beware - casting this powerful spell will reduce the caster's hit points by 50%.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_SPELLLEVEL, 6, NA, NA, NULL);
addflag(lastot->flags, F_SPELLSCHOOL, SS_DIVINE, NA, NA, NULL);
addot(OT_S_WISHLIMITED, "limited wish", "Grants the caster a wish of their choice. Beware - casting this powerful spell will reduce the caster's hit points by 25%.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_SPELLLEVEL, 5, NA, NA, NULL);
addflag(lastot->flags, F_SPELLSCHOOL, SS_DIVINE, NA, NA, NULL);
addot(OT_S_CONFISCATE, "confiscate", "Takes any object from the target.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_SPELLSCHOOL, SS_DIVINE, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 6, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOATTACK, ST_VICTIM, NA, NA, NULL);
addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_DONTNEED, NA, NULL);
addot(OT_S_GIFT, "gift", "Grants the target any item of their choice (with some limitations).", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_SPELLLEVEL, 6, NA, NA, NULL);
addflag(lastot->flags, F_SPELLSCHOOL, SS_DIVINE, NA, NA, NULL);
addot(OT_S_CLEARLEVEL, "blank level", "Blanks out the current map.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_SPELLLEVEL, 6, NA, NA, NULL);
addflag(lastot->flags, F_SPELLSCHOOL, SS_DIVINE, NA, NA, NULL);
addflag(lastot->flags, F_LOSLOF, B_FALSE, LOF_DONTNEED, NA, NULL);
addot(OT_S_CREATEVAULT, "create vault", "Create a vault of the given type.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_SPELLLEVEL, 6, NA, NA, NULL);
addflag(lastot->flags, F_SPELLSCHOOL, SS_DIVINE, NA, NA, NULL);
addflag(lastot->flags, F_LOSLOF, B_FALSE, LOF_DONTNEED, NA, NULL);
// abilities
addot(OT_A_EMPLOY, "employ", "Assigns a job to the target lifeform.", MT_NOTHING, 0, OC_ABILITY, SZ_TINY);
addflag(lastot->flags, F_SPELLSCHOOL, SS_ABILITY, NA, NA, NULL);
addot(OT_A_CHARGE, "charge", "You can quickly charge into close quarters for battle.", MT_NOTHING, 0, OC_ABILITY, SZ_TINY);
addflag(lastot->flags, F_SPELLSCHOOL, SS_ABILITY, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOATTACK, ST_VICTIM, NA, NA, NULL);
addot(OT_A_CRUSH, "crush", "You can crush enemies after grabbing them.", MT_NOTHING, 0, OC_ABILITY, SZ_TINY);
addflag(lastot->flags, F_SPELLSCHOOL, SS_ABILITY, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOATTACK, ST_ADJVICTIM, NA, NA, NULL);
addflag(lastot->flags, F_NEEDSGRAB, B_TRUE, NA, NA, NULL);
addot(OT_A_COOK, "cook", "Combine food and water into a healthy meals.", MT_NOTHING, 0, OC_ABILITY, SZ_TINY);
addflag(lastot->flags, F_SPELLSCHOOL, SS_ABILITY, NA, NA, NULL);
addot(OT_A_DARKWALK, "darkwalk", "Step between the shadows.", MT_NOTHING, 0, OC_ABILITY, SZ_TINY);
addflag(lastot->flags, F_SPELLSCHOOL, SS_ABILITY, NA, NA, NULL);
// ai will cast this spell in a special manner...
addot(OT_A_COMBOSTRIKE, "combination strike", "Perform a combination of blows which continues each time you defeat an enemy.", MT_NOTHING, 0, OC_ABILITY, SZ_TINY);
addflag(lastot->flags, F_SPELLSCHOOL, SS_ABILITY, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOATTACK, ST_ADJVICTIM, NA, NA, NULL);
addot(OT_A_DISARM, "disarm", "Attempt to disable a known trap.", MT_NOTHING, 0, OC_ABILITY, SZ_TINY);
addflag(lastot->flags, F_SPELLSCHOOL, SS_ABILITY, NA, NA, NULL);
addot(OT_A_FEIGNDEATH, "feign death", "Pretend to be dead.", MT_NOTHING, 0, OC_ABILITY, SZ_TINY);
addflag(lastot->flags, F_SPELLSCHOOL, SS_ABILITY, NA, NA, NULL);
addot(OT_A_FLURRY, "flurry", "Perform a flurry of attacks, forcing your opponent backwards.", MT_NOTHING, 0, OC_ABILITY, SZ_TINY);
addflag(lastot->flags, F_SPELLSCHOOL, SS_ABILITY, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOATTACK, ST_ADJVICTIM, NA, NA, NULL);
addot(OT_A_GRAB, "grab", "You can grab hold of nearby enemies to prevent their escape.", MT_NOTHING, 0, OC_ABILITY, SZ_TINY);
addflag(lastot->flags, F_SPELLSCHOOL, SS_ABILITY, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOATTACK, ST_ADJVICTIM, NA, NA, NULL);
addflag(lastot->flags, F_XPVAL, 10, NA, NA, NULL);
addot(OT_A_HEAVYBLOW, "heavy blow", "Mighty blow which knocks enemies backwards.", MT_NOTHING, 0, OC_ABILITY, SZ_TINY);
addflag(lastot->flags, F_SPELLSCHOOL, SS_ABILITY, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOATTACK, ST_ADJVICTIM, NA, NA, NULL);
addot(OT_A_HIDE, "hide", "You can hide in the shadows.", MT_NOTHING, 0, OC_ABILITY, SZ_TINY);
addflag(lastot->flags, F_SPELLSCHOOL, SS_ABILITY, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOFLEE, ST_SELF, NA, NA, NULL);
addot(OT_A_HURRICANESTRIKE, "hurricane strike", "A sweeping attack aginst everything nearby.", MT_NOTHING, 0, OC_ABILITY, SZ_TINY);
addflag(lastot->flags, F_SPELLSCHOOL, SS_ABILITY, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOATTACK, ST_ADJSELF, NA, NA, NULL);
addot(OT_A_INSPECT, "inspect", "Try to identify an unknown scroll, book, wand or ring from your pack.", MT_NOTHING, 0, OC_ABILITY, SZ_TINY);
addflag(lastot->flags, F_SPELLSCHOOL, SS_ABILITY, NA, NA, NULL);
addot(OT_A_JUMP, "jump", "You can leap large distances.", MT_NOTHING, 0, OC_ABILITY, SZ_TINY);
addflag(lastot->flags, F_SPELLSCHOOL, SS_ABILITY, NA, NA, NULL);
addot(OT_A_POLYREVERT, "revertform", "Revert to your original form.", MT_NOTHING, 0, OC_ABILITY, SZ_TINY);
addflag(lastot->flags, F_SPELLSCHOOL, SS_ABILITY, NA, NA, NULL);
addflag(lastot->flags, F_NOANNOUNCE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOATTACK, ST_SELF, 10, NA, NULL);
addot(OT_A_QUIVERINGPALM, "quivering palm", "A deadly palm strike which knocks the molecules in the target's body out of alignment.", MT_NOTHING, 0, OC_ABILITY, SZ_TINY);
addflag(lastot->flags, F_SPELLSCHOOL, SS_ABILITY, NA, NA, NULL);
addot(OT_A_PRAY, "pray", "Ask for help from a higher being.", MT_NOTHING, 0, OC_ABILITY, SZ_TINY);
addflag(lastot->flags, F_SPELLSCHOOL, SS_ABILITY, NA, NA, NULL);
addot(OT_A_RAGE, "rage", "Enter a state of berzerker rage, gaining attack and defence bonuses.", MT_NOTHING, 0, OC_ABILITY, SZ_TINY);
addflag(lastot->flags, F_SPELLSCHOOL, SS_ABILITY, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOATTACK, ST_ADJSELF, NA, NA, NULL);
addot(OT_A_REPAIR, "repair equipment", "Repair damage done to your equipment.", MT_NOTHING, 0, OC_ABILITY, SZ_TINY);
addflag(lastot->flags, F_SPELLSCHOOL, SS_ABILITY, NA, NA, NULL);
addot(OT_A_SPRINT, "sprint", "You can run at high speed over short distances.", MT_NOTHING, 0, OC_ABILITY, SZ_TINY);
addflag(lastot->flags, F_SPELLSCHOOL, SS_ABILITY, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOFLEE, ST_SELF, NA, NA, NULL);
addot(OT_A_STEAL, "steal", "Try to steal an item from an enemy.", MT_NOTHING, 0, OC_ABILITY, SZ_TINY);
addflag(lastot->flags, F_SPELLSCHOOL, SS_ABILITY, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOATTACK, ST_ADJVICTIM, NA, NA, NULL);
addot(OT_A_STINGACID, "sting (acid)", "You can sting your enemies.", MT_NOTHING, 0, OC_ABILITY, SZ_TINY);
addflag(lastot->flags, F_SPELLSCHOOL, SS_ABILITY, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOATTACK, ST_ADJVICTIM, NA, NA, NULL);
addflag(lastot->flags, F_RANGE, 1, NA, NA, NULL);
addot(OT_A_STUDYSCROLL, "study scroll", "Attempt to learn a spell directly from a scroll.", MT_NOTHING, 0, OC_ABILITY, SZ_TINY);
addflag(lastot->flags, F_SPELLSCHOOL, SS_ABILITY, NA, NA, NULL);
addot(OT_A_SUCKBLOOD, "suck blood", "You can suck the blood from enemies after attaching to them.", MT_NOTHING, 0, OC_ABILITY, SZ_TINY);
addflag(lastot->flags, F_SPELLSCHOOL, SS_ABILITY, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOATTACK, ST_ADJVICTIM, NA, NA, NULL);
addot(OT_A_SWOOP, "swoop", "You can attack an enemy while flying past them.", MT_NOTHING, 0, OC_ABILITY, SZ_TINY);
addflag(lastot->flags, F_SPELLSCHOOL, SS_ABILITY, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOATTACK, ST_VICTIM, NA, NA, NULL);
addot(OT_A_TRAIN, "train skills", "Start training to gain a new experience level or enhance skill.", MT_NOTHING, 0, OC_ABILITY, SZ_TINY);
addflag(lastot->flags, F_SPELLSCHOOL, SS_ABILITY, NA, NA, NULL);
addot(OT_A_TUMBLE, "tumble", "You can tumble across the ground.", MT_NOTHING, 0, OC_ABILITY, SZ_TINY);
addflag(lastot->flags, F_SPELLSCHOOL, SS_ABILITY, NA, NA, NULL);
addot(OT_A_WARCRY, "warcry", "Inspire fear in your enemies with a mighty war cry.", MT_NOTHING, 0, OC_ABILITY, SZ_TINY);
addflag(lastot->flags, F_SPELLSCHOOL, SS_ABILITY, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOATTACK, ST_ANYWHERE, NA, NA, NULL);
// books
addot(OT_MANUAL, "manual", "Teaches you one level of its subject matter.", MT_PAPER, 1.5, OC_BOOK, SZ_SMALL);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_RARE, NULL);
addot(OT_SPELLBOOK, "spellbook", "Teaches you the spell contained within.", MT_PAPER, 1.5, OC_BOOK, SZ_SMALL);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_RARE, NULL);
// wands
addot(OT_WAND_KNOCK, "wand of opening", "A limited-use magical wand which casts the imbued spell.", MT_METAL, 0.5, OC_WAND, SZ_SMALL);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 80, RR_UNCOMMON, NULL);
addflag(lastot->flags, F_LINKSPELL, OT_S_KNOCK, NA, NA, NULL);
addflag(lastot->flags, F_OPERNEEDTARGET, TT_DOOR, NA, NA, NULL);
addot(OT_WAND_LIGHT, "wand of light", "A limited-use magical wand which casts the imbued spell.", MT_METAL, 0.5, OC_WAND, SZ_SMALL);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 83, RR_UNCOMMON, NULL);
addflag(lastot->flags, F_LINKSPELL, OT_S_LIGHT, 3, NA, NULL);
addflag(lastot->flags, F_OPERNEEDTARGET, TT_MONSTER, NA, NA, NULL);
addot(OT_WAND_REVEALHIDDEN, "wand of reveal hidden", "A limited-use magical wand which casts the imbued spell.", MT_METAL, 0.5, OC_WAND, SZ_SMALL);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 80, RR_UNCOMMON, NULL);
addflag(lastot->flags, F_LINKSPELL, OT_S_REVEALHIDDEN, NA, NA, NULL);
addot(OT_WAND_SLOW, "wand of slowness", "A limited-use magical wand which casts the imbued spell.", MT_METAL, 0.5, OC_WAND, SZ_SMALL);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 80, RR_RARE, NULL);
addflag(lastot->flags, F_LINKSPELL, OT_S_SLOW, NA, NA, NULL);
addflag(lastot->flags, F_OPERNEEDTARGET, TT_MONSTER, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOATTACK, ST_VICTIM, NA, NA, NULL);
addot(OT_WAND_DIGGING, "wand of digging", "A limited-use magical wand which casts the imbued spell.", MT_METAL, 0.5, OC_WAND, SZ_SMALL);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 80, RR_RARE, NULL);
addflag(lastot->flags, F_LINKSPELL, OT_S_DIG, NA, NA, NULL);
//addflag(lastot->flags, F_OPERNEEDTARGET, TT_NONE, NA, NA, NULL);
addot(OT_WAND_COLD, "wand of cold", "A limited-use magical wand which casts the imbued spell.", MT_METAL, 0.5, OC_WAND, SZ_SMALL);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 73, RR_RARE, NULL);
addflag(lastot->flags, F_LINKSPELL, OT_S_COLDRAY, NA, NA, NULL);
addflag(lastot->flags, F_OPERNEEDTARGET, TT_MONSTER, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOATTACK, ST_VICTIM, NA, NA, NULL);
addot(OT_WAND_FIRE, "wand of fire", "A limited-use magical wand which casts the imbued spell.", MT_METAL, 0.5, OC_WAND, SZ_SMALL);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 73, RR_RARE, NULL);
addflag(lastot->flags, F_LINKSPELL, OT_S_FIREDART, NA, NA, NULL);
addflag(lastot->flags, F_OPERNEEDTARGET, TT_MONSTER, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOATTACK, ST_VICTIM, NA, NA, NULL);
addot(OT_WAND_HASTE, "wand of haste", "A limited-use magical wand which casts the imbued spell.", MT_METAL, 0.5, OC_WAND, SZ_SMALL);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 70, RR_RARE, NULL);
addflag(lastot->flags, F_LINKSPELL, OT_S_HASTE, NA, NA, NULL);
addflag(lastot->flags, F_OPERNEEDTARGET, TT_MONSTER, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOATTACK, ST_SELF, NA, NA, NULL);
addot(OT_WAND_WEAKNESS, "wand of enfeeblement", "A limited-use magical wand which casts the imbued spell.", MT_METAL, 0.5, OC_WAND, SZ_SMALL);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 70, RR_RARE, NULL);
addflag(lastot->flags, F_LINKSPELL, OT_S_WEAKEN, NA, NA, NULL);
addflag(lastot->flags, F_OPERNEEDTARGET, TT_MONSTER, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOATTACK, ST_VICTIM, NA, NA, NULL);
addot(OT_WAND_WONDER, "wand of wonder", "Produces random effects.", MT_METAL, 0.5, OC_WAND, SZ_SMALL);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 70, RR_RARE, NULL);
addflag(lastot->flags, F_OPERNEEDTARGET, TT_NONE, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOATTACK, ST_VICTIM, NA, NA, NULL);
addot(OT_WAND_INVIS, "wand of invisibility", "A limited-use magical wand which casts the imbued spell.", MT_METAL, 0.5, OC_WAND, SZ_SMALL);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 65, RR_RARE, NULL);
addflag(lastot->flags, F_LINKSPELL, OT_S_INVISIBILITY, NA, NA, NULL);
addflag(lastot->flags, F_OPERNEEDTARGET, TT_MONSTER, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOATTACK, ST_SELF, NA, NA, NULL);
addot(OT_WAND_DISPERSAL, "wand of dispersal", "A limited-use magical wand which casts the imbued spell.", MT_METAL, 0.5, OC_WAND, SZ_SMALL);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 65, RR_RARE, NULL);
addflag(lastot->flags, F_LINKSPELL, OT_S_DISPERSAL, NA, NA, NULL);
addflag(lastot->flags, F_OPERNEEDTARGET, TT_MONSTER|TT_OBJECT, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOATTACK, ST_VICTIM, NA, NA, NULL);
addflag(lastot->flags, F_AIFLEEITEM, B_TRUE, NA, NA, NULL);
addot(OT_WAND_FIREBALL, "wand of fireball", "A limited-use magical wand which casts the imbued spell.", MT_METAL, 0.5, OC_WAND, SZ_SMALL);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 65, RR_RARE, NULL);
addflag(lastot->flags, F_LINKSPELL, OT_S_FIREBALL, NA, NA, NULL);
addflag(lastot->flags, F_OPERNEEDTARGET, TT_MONSTER, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOATTACK, ST_VICTIM, NA, NA, NULL);
addot(OT_WAND_DETONATION, "wand of detonation", "A limited-use magical wand which casts the imbued spell.", MT_METAL, 0.5, OC_WAND, SZ_SMALL);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 60, RR_RARE, NULL);
addflag(lastot->flags, F_LINKSPELL, OT_S_DETONATE, NA, NA, NULL);
addflag(lastot->flags, F_OPERNEEDTARGET, TT_MONSTER|TT_DOOR, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOATTACK, ST_VICTIM, NA, NA, NULL);
addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_DONTNEED, NA, NULL);
addot(OT_WAND_POLYMORPH, "wand of polymorph", "A limited-use magical wand which casts the imbued spell.", MT_METAL, 0.5, OC_WAND, SZ_SMALL);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 60, RR_RARE, NULL);
addflag(lastot->flags, F_LINKSPELL, OT_S_POLYMORPH, NA, NA, NULL);
addflag(lastot->flags, F_OPERNEEDTARGET, TT_MONSTER, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOATTACK, ST_VICTIM, NA, NA, NULL);
addot(OT_WAND_TURNUNDEAD, "wand of turn undead", "A limited-use magical wand which casts the imbued spell.", MT_METAL, 0.5, OC_WAND, SZ_SMALL);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 72, RR_RARE, NULL);
addflag(lastot->flags, F_LINKSPELL, OT_S_TURNUNDEAD, NA, NA, NULL);
addflag(lastot->flags, F_OPERNEEDTARGET, TT_MONSTER, NA, NA, NULL);
// tools - unique
addot(OT_ORBDUNGEONEXIT, "dungeon exit orb", "When operated, this magical key will disable the barriers around the dungeon exit stairs.", MT_STONE, 2, OC_TOOLS, SZ_SMALL);
addflag(lastot->flags, F_GLYPH, C_MAGENTA, NA, NA, "[");
addflag(lastot->flags, F_UNIQUE, NA, NA, NA, NULL);
addflag(lastot->flags, F_INVULNERABLE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_OPERABLE, B_TRUE, NA, NA, NULL);
// tools
addot(OT_BLANKET, "wool blanket", "A warm wool blanket for those cold winter nights.", MT_CLOTH, 2, OC_TOOLS, SZ_MEDIUM);
addflag(lastot->flags, F_RARITY, H_ALL, 80, NA, NULL);
addflag(lastot->flags, F_HELPSREST, 10, NA, NA, NULL);
addot(OT_BLINDFOLD, "blindfold", "Short length of wide cloth, used for blocking eyesight.", MT_CLOTH, 0.01, OC_TOOLS, SZ_TINY);
addflag(lastot->flags, F_GOESON, BP_EYES, NA, NA, NULL);
addflag(lastot->flags, F_EQUIPCONFER, F_BLIND, B_TRUE, NA, NULL);
addflag(lastot->flags, F_VALUE, 20, NA, NA, NULL);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 60, NA, NULL);
addot(OT_CALTROP, "caltrop", "Connected metal spikes arranged such that one will always point upwards.", MT_METAL, 0.2, OC_TOOLS, SZ_TINY);
addflag(lastot->flags, F_STACKABLE, NA, NA, NA, NULL);
addflag(lastot->flags, F_NUMAPPEAR, 1, 3, NA, NULL);
addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_GLYPH, C_GREY, NA, NA, "^");
addflag(lastot->flags, F_SHARP, 2, 5, NA, NULL);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 75, NA, NULL);
addot(OT_BUGLAMP, "glowing flask", "A glass flask with a glowbug corpse inside.", MT_GLASS, 0.3, OC_TOOLS, SZ_SMALL);
addflag(lastot->flags, F_GLYPH, NA, NA, NA, "!");
addflag(lastot->flags, F_PRODUCESLIGHT, 2, NA, NA, NULL);
addflag(lastot->flags, F_HOLDCONFER, F_PRODUCESLIGHT, 2, IFKNOWN, NULL);
addflag(lastot->flags, F_FEELTEXT, NA, NA, NA, "a flask");
addot(OT_CANDLE, "candle", "A short wax candle.", MT_WAX, 0.2, OC_TOOLS, SZ_TINY);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 90, NA, NULL);
addflag(lastot->flags, F_OPERABLE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_OPERONOFF, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_ACTIVATEPREFIX, NA, NA, NA, "lit");
addflag(lastot->flags, F_ACTIVATECONFER, F_PRODUCESLIGHT, 1, NA, NULL);
addflag(lastot->flags, F_PRODUCESLIGHT, 1, NA, IFACTIVE, NULL);
addflag(lastot->flags, F_RNDCHARGES, 50, 100, NA, NULL);
addflag(lastot->flags, F_LIGHTSOURCE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_CHARGELOWMSG, B_TRUE, NA, NA, "flickers");
addflag(lastot->flags, F_CHARGEOUTMSG, B_TRUE, NA, NA, "goes out");
addot(OT_GUNPOWDER, "pile of gunpowder", "A black metallic powder.", MT_METAL, 0.5, OC_TOOLS, SZ_TINY);
addflag(lastot->flags, F_HASHIDDENNAME, B_TRUE, NA, NA, "pile of black powder");
addflag(lastot->flags, F_GLYPH, NA, NA, NA, ",");
addflag(lastot->flags, F_STACKABLE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 65, NA, NULL);
addflag(lastot->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_EXPLODEONDAM, DT_FIRE, NA, NA, "8d2");
addflag(lastot->flags, F_DTVULN, DT_FIRE, NA, NA, "2d6");
addflag(lastot->flags, F_FLAMMABLE, 3, NA, NA, NULL);
addflag(lastot->flags, F_POWDER, B_TRUE, NA, NA, NULL);
addot(OT_LAMPOIL, "oil lamp", "An oil-powered lamp which produces light.", MT_METAL, 1, OC_TOOLS, SZ_SMALL);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 70, NA, NULL);
addflag(lastot->flags, F_OPERABLE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_OPERONOFF, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_ACTIVATECONFER, F_PRODUCESLIGHT, 2, NA, NULL);
addflag(lastot->flags, F_PRODUCESLIGHT, 2, NA, IFACTIVE, NULL);
addflag(lastot->flags, F_RNDCHARGES, 200, 400, NA, NULL);
addflag(lastot->flags, F_REFILLWITH, OT_POT_OIL, NA, NA, NULL);
addflag(lastot->flags, F_LIGHTSOURCE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_CHARGELOWMSG, B_TRUE, NA, NA, "flickers");
addflag(lastot->flags, F_CHARGEOUTMSG, B_TRUE, NA, NA, "goes out");
addot(OT_LANTERNOIL, "oil lantern", "An oil-powered lantern which produces a lot of light.", MT_METAL, 1, OC_TOOLS, SZ_SMALL);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 55, NA, NULL);
addflag(lastot->flags, F_OPERABLE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_OPERONOFF, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_ACTIVATECONFER, F_PRODUCESLIGHT, 3, NA, NULL);
addflag(lastot->flags, F_PRODUCESLIGHT, 3, NA, IFACTIVE, NULL);
addflag(lastot->flags, F_RNDCHARGES, 300, 500, NA, NULL);
addflag(lastot->flags, F_REFILLWITH, OT_POT_OIL, NA, NA, NULL);
addflag(lastot->flags, F_LIGHTSOURCE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_CHARGELOWMSG, B_TRUE, NA, NA, "flickers");
addflag(lastot->flags, F_CHARGEOUTMSG, B_TRUE, NA, NA, "goes out");
addot(OT_LOCKPICK, "lockpick", "An angled piece of metal, used to open locks.", MT_METAL, 0.05, OC_TOOLS, SZ_TINY);
addflag(lastot->flags, F_STACKABLE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 75, NA, NULL);
addflag(lastot->flags, F_PICKLOCKS, 10, B_DIEONFAIL, NA, NULL);
addflag(lastot->flags, F_OPERABLE, B_TRUE, NA, NA, NULL);
addot(OT_PANPIPES, "set of panpipes", "A set of musical pipes.", MT_METAL, 0.5, OC_TOOLS, SZ_TINY);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 60, NA, NULL);
addflag(lastot->flags, F_OPERABLE, B_TRUE, NA, NA, NULL);
addot(OT_PICKAXE, "pickaxe", "A heavy tool for breaking rock.", MT_METAL, 8, OC_TOOLS, SZ_MEDIUM);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 65, NA, NULL);
addflag(lastot->flags, F_OPERABLE, B_TRUE, NA, NA, NULL);
addot(OT_ROPE, "rope", "A long length of strong rope.", MT_CLOTH, 5, OC_TOOLS, SZ_MEDIUM);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 75, NA, NULL);
addflag(lastot->flags, F_RARITY, H_FOREST, 75, NA, NULL);
addflag(lastot->flags, F_HELPSCLIMB, 3, NA, NA, NULL);
addot(OT_SACK, "sack", "A small cloth sack.", MT_CLOTH, 0.5, OC_TOOLS, SZ_SMALL);
addflag(lastot->flags, F_RARITY, H_ALL, 100, RR_COMMON, NULL);
addflag(lastot->flags, F_GLYPH, C_YELLOW, NA, NA, "(");
addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_OBHP, 3, 3, NA, NULL);
addflag(lastot->flags, F_OPERABLE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_CONTAINER, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_STARTOBRND, 50, NA, NA, NULL);
addflag(lastot->flags, F_STARTOBRND, 30, NA, NA, NULL);
addflag(lastot->flags, F_STARTOBRND, 10, NA, NA, NULL);
addot(OT_SACKLARGE, "large sack", "A large cloth sack.", MT_CLOTH, 1, OC_TOOLS, SZ_MEDIUM);
addflag(lastot->flags, F_GLYPH, C_YELLOW, NA, NA, "(");
addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_OBHP, 50, 50, NA, NULL);
addflag(lastot->flags, F_OPERABLE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_CONTAINER, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_STARTOBRND, 100, NA, NA, NULL);
addflag(lastot->flags, F_STARTOBRND, 100, NA, NA, NULL);
addflag(lastot->flags, F_STARTOBRND, 50, NA, NA, NULL);
addflag(lastot->flags, F_STARTOBRND, 50, NA, NA, NULL);
addot(OT_SACKHUGE, "huge sack", "An enormous cloth sack.", MT_CLOTH, 1, OC_TOOLS, SZ_LARGE);
addflag(lastot->flags, F_GLYPH, C_YELLOW, NA, NA, "(");
addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_OBHP, 50, 50, NA, NULL);
addflag(lastot->flags, F_OPERABLE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_CONTAINER, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_STARTOBRND, 100, NA, NA, NULL);
addflag(lastot->flags, F_STARTOBRND, 100, NA, NA, NULL);
addflag(lastot->flags, F_STARTOBRND, 100, NA, NA, NULL);
addflag(lastot->flags, F_STARTOBRND, 50, NA, NA, NULL);
addflag(lastot->flags, F_STARTOBRND, 50, NA, NA, NULL);
addflag(lastot->flags, F_STARTOBRND, 50, NA, NA, NULL);
addflag(lastot->flags, F_STARTOBRND, 50, NA, NA, NULL);
addflag(lastot->flags, F_STARTOBRND, 50, NA, NA, NULL);
addot(OT_BAGOFHOLDING, "bag of holding", "A magical sack which causes items placed inside it to become weightless.", MT_CLOTH, 0.5, OC_TOOLS, SZ_SMALL);
addflag(lastot->flags, F_RARITY, H_ALL, 80, RR_RARE, NULL);
addflag(lastot->flags, F_GLYPH, C_YELLOW, NA, NA, "(");
addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_OPERWITHOUTID, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_NOTRIED, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_OPERABLE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_CONTAINER, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_HOLDING, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_STARTOBRND, 50, NA, NA, NULL);
addflag(lastot->flags, F_STARTOBRND, 30, NA, NA, NULL);
addflag(lastot->flags, F_STARTOBRND, 10, NA, NA, NULL);
addflag(lastot->flags, F_HASHIDDENNAME, B_TRUE, NA, NA, "sack");
addot(OT_BAGOFHOLDINGLARGE, "large bag of holding", "A large magical sack which causes items placed inside it to become weightless.", MT_CLOTH, 0.5, OC_TOOLS, SZ_MEDIUM);
addflag(lastot->flags, F_RARITY, H_ALL, 80, RR_RARE, NULL);
addflag(lastot->flags, F_GLYPH, C_YELLOW, NA, NA, "(");
addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_OPERWITHOUTID, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_NOTRIED, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_OPERABLE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_CONTAINER, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_HOLDING, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_STARTOBRND, 100, NA, NA, NULL);
addflag(lastot->flags, F_STARTOBRND, 100, NA, NA, NULL);
addflag(lastot->flags, F_STARTOBRND, 50, NA, NA, NULL);
addflag(lastot->flags, F_STARTOBRND, 50, NA, NA, NULL);
addflag(lastot->flags, F_HASHIDDENNAME, B_TRUE, NA, NA, "large sack");
addot(OT_BAGOFHOLDINGHUGE, "huge bag of holding", "An enormous magical sack which causes items placed inside it to become weightless.", MT_CLOTH, 0.5, OC_TOOLS, SZ_LARGE);
addflag(lastot->flags, F_RARITY, H_ALL, 80, RR_VERYRARE, NULL);
addflag(lastot->flags, F_GLYPH, C_YELLOW, NA, NA, "(");
addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_OPERWITHOUTID, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_NOTRIED, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_OPERABLE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_CONTAINER, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_HOLDING, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_STARTOBRND, 100, NA, NA, NULL);
addflag(lastot->flags, F_STARTOBRND, 100, NA, NA, NULL);
addflag(lastot->flags, F_STARTOBRND, 100, NA, NA, NULL);
addflag(lastot->flags, F_STARTOBRND, 50, NA, NA, NULL);
addflag(lastot->flags, F_STARTOBRND, 50, NA, NA, NULL);
addflag(lastot->flags, F_STARTOBRND, 50, NA, NA, NULL);
addflag(lastot->flags, F_STARTOBRND, 50, NA, NA, NULL);
addflag(lastot->flags, F_STARTOBRND, 50, NA, NA, NULL);
addflag(lastot->flags, F_HASHIDDENNAME, B_TRUE, NA, NA, "huge sack");
addot(OT_SAFEBOX, "safebox", "A small metal container for safely storing valuables.", MT_METAL, 2, OC_TOOLS, SZ_SMALL);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 77, RR_UNCOMMON, NULL);
addflag(lastot->flags, F_GLYPH, C_YELLOW, NA, NA, "(");
addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_OBHP, 15, 15, NA, NULL);
addflag(lastot->flags, F_OPERABLE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_CONTAINER, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_CANBETRAPPED, 20, 25, 66, NULL);
addflag(lastot->flags, F_STARTOBRND, 50, NA, NA, NULL);
addflag(lastot->flags, F_STARTOBRND, 50, NA, NA, NULL);
addot(OT_TORCH, "torch", "A metre-long wooden rod with a flammable end.", MT_WOOD, 2, OC_TOOLS, SZ_SMALL);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 85, NA, NULL);
addflag(lastot->flags, F_OPERABLE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_OPERONOFF, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_ACTIVATEPREFIX, NA, NA, NA, "lit");
addflag(lastot->flags, F_ACTIVATECONFER, F_PRODUCESLIGHT, 2, NA, NULL);
addflag(lastot->flags, F_PRODUCESLIGHT, 2, NA, IFACTIVE, NULL);
addflag(lastot->flags, F_RNDCHARGES, 100, 200, NA, NULL);
addflag(lastot->flags, F_REFILLWITH, OT_POT_OIL, NA, NA, NULL);
addflag(lastot->flags, F_RODSHAPED, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_DAM, DT_FIRE, NA, NA, "1d4");
addflag(lastot->flags, F_ACCURACY, 80, NA, NA, NULL);
addflag(lastot->flags, F_USESSKILL, SK_CLUBS, NA, NA, NULL);
addflag(lastot->flags, F_LIGHTSOURCE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_CHARGELOWMSG, B_TRUE, NA, NA, "flickers");
addflag(lastot->flags, F_CHARGEOUTMSG, B_TRUE, NA, NA, "goes out");
addot(OT_TOWEL, "towel", "An large absorbent cloth used for drawing off moisture.", MT_CLOTH, 1.5, OC_TOOLS, SZ_MEDIUM);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 73, NA, NULL);
addflag(lastot->flags, F_OPERABLE, B_TRUE, NA, NA, NULL);
// tech - l0
addot(OT_CREDITCARD, "credit card", "A rectangular plastic card.", MT_PLASTIC, 0.01, OC_TECH, SZ_TINY);
addflag(lastot->flags, F_RARITY, H_ALL, 90, NA, NULL);
addflag(lastot->flags, F_STACKABLE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 70, NA, NULL);
addflag(lastot->flags, F_PICKLOCKS, 2, NA, NA, NULL);
addflag(lastot->flags, F_OPERABLE, B_TRUE, NA, NA, NULL);
addot(OT_PAPERCLIP, "paperclip", "A thin, looped wire for holding paper together.", MT_WIRE, 0.01, OC_TECH, SZ_TINY);
addflag(lastot->flags, F_RARITY, H_ALL, 90, NA, NULL);
addflag(lastot->flags, F_STACKABLE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 70, NA, NULL);
addflag(lastot->flags, F_PICKLOCKS, 4, B_DIEONFAIL, NA, NULL);
addflag(lastot->flags, F_OPERABLE, B_TRUE, NA, NA, NULL);
// can use as a (very bad) weapon too...
addflag(lastot->flags, F_DAM, DT_PIERCE, NA, NA, "1d1");
addflag(lastot->flags, F_ACCURACY, 50, NA, NA, NULL);
addot(OT_SLEEPINGBAG, "sleeping bag", "An insulated bag for sleeping in. Very comfortable.", MT_CLOTH, 4, OC_TECH, SZ_MEDIUM);
addflag(lastot->flags, F_RARITY, H_ALL, 70, NA, NULL);
addflag(lastot->flags, F_HELPSREST, 15, NA, NA, NULL);
// tech - l1
addot(OT_POCKETWATCH, "pocket watch", "A portable timekeeping device made to be carried in a pocket.", MT_METAL, 0.1, OC_TECH, SZ_TINY);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 90, NA, NULL);
addflag(lastot->flags, F_OPERABLE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_TECHLEVEL, PR_NOVICE, NA, NA, NULL);
addflag(lastot->flags, F_HASHIDDENNAME, B_TRUE, NA, NA, NULL);
addot(OT_DIGITALWATCH, "digital watch", "An electronic timekeeping device which shows the time as a number.", MT_METAL, 0.1, OC_TECH, SZ_TINY);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 85, NA, NULL);
addflag(lastot->flags, F_OPERABLE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_TECHLEVEL, PR_NOVICE, NA, NA, NULL);
addflag(lastot->flags, F_HASHIDDENNAME, B_TRUE, NA, NA, NULL);
addot(OT_INSECTICIDE, "can of insecticide", "A spraycan containing poisonous chemicals.", MT_METAL, 0.5, OC_TECH, SZ_TINY);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 85, RR_UNCOMMON, NULL);
addflag(lastot->flags, F_OPERABLE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_OPERUSECHARGE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_OPERNEEDTARGET, TT_MONSTER, NA, NA, "Where will you spray?");
addflag(lastot->flags, F_RNDCHARGES, 1, 5, NA, NULL);
addflag(lastot->flags, F_TECHLEVEL, PR_NOVICE, NA, NA, NULL);
addflag(lastot->flags, F_HASHIDDENNAME, B_TRUE, NA, NA, NULL);
addot(OT_LANTERNLED, "LED lantern", "A low-powered but efficient lantern which will last almost forever.", MT_METAL, 0.5, OC_TECH, SZ_TINY);
addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 75, RR_UNCOMMON, NULL);
addflag(lastot->flags, F_OPERABLE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_OPERONOFF, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_ACTIVATECONFER, F_PRODUCESLIGHT, 2, NA, NULL);
addflag(lastot->flags, F_PRODUCESLIGHT, 2, NA, IFACTIVE, NULL);
addflag(lastot->flags, F_TECHLEVEL, PR_NOVICE, NA, NA, NULL);
addflag(lastot->flags, F_HASHIDDENNAME, B_TRUE, NA, NA, NULL);
addot(OT_TENT, "tent", "A easy to use, portable shelter made of fabric.", MT_CLOTH, 10, OC_TECH, SZ_HUMAN);
addflag(lastot->flags, F_RARITY, H_ALL, 70, NA, NULL);
addflag(lastot->flags, F_HELPSREST, 15, 1, NA, NULL);
addflag(lastot->flags, F_HASHIDDENNAME, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_TECHLEVEL, PR_NOVICE, NA, NA, NULL);
// tech - l2
addot(OT_FLASHBANG, "flashbang", "A stun grenade which temporarily blinds all within sight.", MT_METAL, 1, OC_TECH, SZ_TINY);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 90, RR_UNCOMMON, NULL);
addflag(lastot->flags, F_STACKABLE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_OPERABLE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_OPERONOFF, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_CHARGES, 2, 2, NA, NULL);
addflag(lastot->flags, F_DONTSHOWCHARGES, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_RECHARGEWHENOFF, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_NOOBDAMTEXT, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_NOOBDIETEXT, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_FLASHONDEATH, 4, NA, B_IFACTIVATED, NULL);
addflag(lastot->flags, F_FLASHONDAM, 4, NA, B_IFACTIVATED, NULL);
addflag(lastot->flags, F_GRENADE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_TECHLEVEL, PR_BEGINNER, NA, NA, NULL);
addflag(lastot->flags, F_HASHIDDENNAME, B_TRUE, NA, NA, NULL);
addot(OT_GRENADE, "grenade", "An explosive weapon which explodes a short time after activation.", MT_METAL, 1, OC_TECH, SZ_TINY);
addflag(lastot->flags, F_STACKABLE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 80, RR_UNCOMMON, NULL);
addflag(lastot->flags, F_OPERABLE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_OPERONOFF, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_CHARGES, 2, 2, NA, NULL);
addflag(lastot->flags, F_DONTSHOWCHARGES, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_RECHARGEWHENOFF, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_NOOBDAMTEXT, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_NOOBDIETEXT, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_EXPLODEONDEATH, NA, NA, B_IFACTIVATED, "8d2");
addflag(lastot->flags, F_EXPLODEONDAM, NA, NA, B_IFACTIVATED, "5d2");
addflag(lastot->flags, F_GRENADE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_TECHLEVEL, PR_BEGINNER, NA, NA, NULL);
addflag(lastot->flags, F_HASHIDDENNAME, B_TRUE, NA, NA, NULL);
addot(OT_C4, "block of c4", "A highly explosive plastic which explodes a medium time after activation.", MT_PLASTIC, 1, OC_TECH, SZ_TINY);
addflag(lastot->flags, F_STACKABLE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 76, RR_UNCOMMON, NULL);
addflag(lastot->flags, F_OPERABLE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_OPERONOFF, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_CHARGES, 5, 5, NA, NULL);
addflag(lastot->flags, F_DONTSHOWCHARGES, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_RECHARGEWHENOFF, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_NOOBDAMTEXT, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_NOOBDIETEXT, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_EXPLODEONDEATH, NA, B_BIG, B_IFACTIVATED, "15d2");
addflag(lastot->flags, F_GRENADE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_TECHLEVEL, PR_BEGINNER, NA, NA, NULL);
addflag(lastot->flags, F_HASHIDDENNAME, B_TRUE, NA, NA, NULL);
addot(OT_MOTIONSCANNER, "motion scanner", "Small scanning device which detects nearby lifeforms.", MT_METAL, 1.5, OC_TECH, SZ_TINY);
addflag(lastot->flags, F_RARITY, H_ALL, 70, RR_RARE, NULL);
addflag(lastot->flags, F_HOLDCONFER, F_DETECTLIFE, 10, NA, NULL);
addflag(lastot->flags, F_TECHLEVEL, PR_BEGINNER, NA, NA, NULL);
addflag(lastot->flags, F_HASHIDDENNAME, B_TRUE, NA, NA, NULL);
addot(OT_NVGOGGLES, "nightvis goggles", "Special goggles which allow the wear to see in the dark.", MT_METAL, 1.5, OC_TECH, SZ_MEDIUM);
addflag(lastot->flags, F_RARITY, H_ALL, 70, RR_RARE, NULL);
addflag(lastot->flags, F_HASHIDDENNAME, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_TECHLEVEL, PR_BEGINNER, NA, NA, NULL);
addflag(lastot->flags, F_GOESON, BP_EYES, NA, NA, NULL);
addflag(lastot->flags, F_ARMOURRATING, 1, NA, NA, NULL);
addflag(lastot->flags, F_OBHP, 2, 2, NA, NULL);
addflag(lastot->flags, F_EQUIPCONFER, F_SEEINDARK, 5, NA, NULL);
addflag(lastot->flags, F_NOQUALITY, B_TRUE, NA, NA, NULL);
// tech - l3
addot(OT_INFOVISOR, "infovisor", "Sleek looking metal visor which displays info directly into the retina.", MT_METAL, 0.2, OC_TECH, SZ_SMALL);
addflag(lastot->flags, F_GOESON, BP_EYES, NA, NA, NULL);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 70, RR_RARE, NULL);
addflag(lastot->flags, F_EQUIPCONFER, F_EXTRAINFO, B_TRUE, NA, NULL);
addflag(lastot->flags, F_EQUIPCONFER, F_ENHANCESEARCH, 10, NA, NULL);
addflag(lastot->flags, F_TECHLEVEL, PR_ADEPT, NA, NA, NULL);
addflag(lastot->flags, F_HASHIDDENNAME, B_TRUE, NA, NA, NULL);
addot(OT_LOCKHACKER, "lock hacker", "A sophisticated machine to manipulate physical locks.", MT_METAL, 3, OC_TECH, SZ_TINY);
addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 78, RR_UNCOMMON, NULL);
addflag(lastot->flags, F_OPERABLE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_TECHLEVEL, PR_ADEPT, NA, NA, NULL);
addflag(lastot->flags, F_HASHIDDENNAME, B_TRUE, NA, NA, NULL);
addot(OT_PORTLADDER, "portable ladder", "A lightweight two metre ladder which automatically folds down to pocket size.", MT_METAL, 2, OC_TECH, SZ_TINY);
addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 83, RR_UNCOMMON, NULL);
addflag(lastot->flags, F_TECHLEVEL, PR_ADEPT, NA, NA, NULL);
addflag(lastot->flags, F_HASHIDDENNAME, B_TRUE, NA, NA, NULL);
// tech - l4
addot(OT_JETPACK, "jet pack", "A portable ion-thruster which allows the wearer to fly.", MT_METAL, 10, OC_TECH, SZ_MEDIUM);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 68, RR_RARE, NULL);
addflag(lastot->flags, F_OPERABLE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_OPERONOFF, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_RNDCHARGES, 10, 30, NA, NULL);
addflag(lastot->flags, F_REFILLWITH, OT_POT_OIL, NA, NA, NULL);
addflag(lastot->flags, F_ACTIVATECONFER, F_FLYING, B_TRUE, NA, NULL);
addflag(lastot->flags, F_ACTIVATECONFER, F_PRODUCESLIGHT, 1, NA, NULL);
addflag(lastot->flags, F_TECHLEVEL, PR_SKILLED, NA, NA, NULL);
addflag(lastot->flags, F_HASHIDDENNAME, B_TRUE, NA, NA, NULL);
// tech - l5
addot(OT_TELEPAD, "teleport beacon", "A metal cone which will teleport the user to the nearest similar cone.", MT_METAL, 3, OC_TECH, SZ_MEDIUM);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 68, RR_UNCOMMON, NULL);
addflag(lastot->flags, F_OPERABLE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_TECHLEVEL, PR_EXPERT, NA, NA, NULL);
addflag(lastot->flags, F_HASHIDDENNAME, B_TRUE, NA, NA, NULL);
addot(OT_XRAYGOGGLES, "pair of xray goggles", "Bulky looking goggles which allow you to see through walls.", MT_METAL, 0.3, OC_TECH, SZ_TINY);
addflag(lastot->flags, F_GOESON, BP_EYES, NA, NA, NULL);
addflag(lastot->flags, F_EQUIPCONFER, F_XRAYVIS, 2, NA, NULL);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 60, RR_RARE, NULL);
addflag(lastot->flags, F_TECHLEVEL, PR_EXPERT, NA, NA, NULL);
addflag(lastot->flags, F_HASHIDDENNAME, B_TRUE, NA, NA, NULL);
// tech - l6 ???
// misc
addot(OT_BONE, "bone", "A bone from an unknown creature.", MT_BONE, 0.1, OC_MISC, SZ_SMALL);
addflag(lastot->flags, F_RARITY, H_ALL, 75, NA, NULL);
addflag(lastot->flags, F_RARITY, H_FOREST, 90, NA, NULL);
addflag(lastot->flags, F_GLYPH, NA, NA, NA, ",");
addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_STACKABLE, B_TRUE, NA, NA, NULL);
addot(OT_CHEST, "chest", "A small wooden treasure chest.", MT_METAL, 40, OC_FURNITURE, SZ_MEDIUM);
addflag(lastot->flags, F_RARITY, H_ALL, 100, RR_UNCOMMON, NULL);
addflag(lastot->flags, F_GLYPH, C_YELLOW, NA, NA, "(");
addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_OBHP, 6, 6, NA, NULL);
addflag(lastot->flags, F_OPERABLE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_CANBETRAPPED, 20, 20, 66, NULL);
addflag(lastot->flags, F_CONTAINER, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_STARTOBRND, 90, NA, NA, NULL);
addflag(lastot->flags, F_STARTOBRND, 80, NA, NA, NULL);
addflag(lastot->flags, F_STARTOBRND, 70, NA, NA, NULL);
addflag(lastot->flags, F_STARTOBRND, 60, NA, NA, NULL);
addflag(lastot->flags, F_STARTOBRND, 50, NA, NA, NULL);
addot(OT_EMPTYFLASK, "empty flask", "An empty glass flask.", MT_GLASS, 0.2, OC_MISC, SZ_TINY);
addflag(lastot->flags, F_STACKABLE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_GLYPH, NA, NA, NA, "!");
addflag(lastot->flags, F_RARITY, H_DUNGEON, 90, NA, NULL);
addflag(lastot->flags, F_OPERABLE, B_TRUE, NA, NA, NULL);
addot(OT_EMPTYVIAL, "empty vial", "An empty glass vial.", MT_GLASS, 0.1, OC_MISC, SZ_TINY);
addflag(lastot->flags, F_STACKABLE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_GLYPH, NA, NA, NA, "!");
addflag(lastot->flags, F_RARITY, H_DUNGEON, 82, NA, NULL);
addflag(lastot->flags, F_OPERABLE, B_TRUE, NA, NA, NULL);
addot(OT_BROKENGLASS, "piece of broken glass", "Sharp shards of broken glass.", MT_GLASS, 0.1, OC_MISC, SZ_MINI);
addflag(lastot->flags, F_STACKABLE, NA, NA, NA, NULL);
addflag(lastot->flags, F_NUMAPPEAR, 1, 8, NA, NULL);
addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_GLYPH, NA, NA, NA, "^");
addflag(lastot->flags, F_SHARP, 1, 2, NA, NULL);
addflag(lastot->flags, F_CRUSHABLE, SZ_MEDIUM, NA, NA, NULL);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 65, NA, NULL);
addflag(lastot->flags, F_NOSHATTER, B_TRUE, NA, NA, NULL);
addot(OT_ICESHEET, "sheet of ice", "A large sheet of slippery ice.", MT_ICE, 0.5, OC_MISC, SZ_MEDIUM);
addflag(lastot->flags, F_STACKABLE, NA, NA, NA, NULL);
addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_GLYPH, C_WHITE, NA, NA, "_");
addflag(lastot->flags, F_DTCONVERT, DT_FIRE, NA, NA, "large puddle of water");
addflag(lastot->flags, F_DIECONVERT, NA, NA, NA, "large puddle of water");
addflag(lastot->flags, F_DIECONVERTTEXT, NA, NA, NA, "melts");
addflag(lastot->flags, F_DIECONVERTTEXTPL, NA, NA, NA, "melt");
addflag(lastot->flags, F_OBHP, 50, 50, NA, NULL);
addflag(lastot->flags, F_OBHPDRAIN, 1, NA, NA, NULL);
addflag(lastot->flags, F_NOOBDAMTEXT, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_NOPICKUP, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_SLIPPERY, 14, NA, NA, NULL);
addot(OT_ICECHUNK, "chunk of ice", "A chunk of ice.", MT_ICE, 0.5, OC_MISC, SZ_SMALL);
addflag(lastot->flags, F_EDIBLE, B_TRUE, 3, NA, NULL);
addflag(lastot->flags, F_STACKABLE, NA, NA, NA, NULL);
addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_GLYPH, NA, NA, NA, ",");
addflag(lastot->flags, F_DIECONVERT, NA, NA, NA, "small puddle of water");
addflag(lastot->flags, F_DIECONVERTTEXT, NA, NA, NA, "melts");
addflag(lastot->flags, F_DIECONVERTTEXTPL, NA, NA, NA, "melt");
addflag(lastot->flags, F_OBHP, 10, 10, NA, NULL);
addflag(lastot->flags, F_OBHPDRAIN, 1, NA, NA, NULL);
addflag(lastot->flags, F_NOOBDAMTEXT, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_NOSHATTER, B_TRUE, NA, NA, NULL);
addot(OT_MELTEDWAX, "lump of melted wax", "A useless lump of melted wax.", MT_WAX, 0.1, OC_MISC, SZ_TINY);
addflag(lastot->flags, F_STACKABLE, NA, NA, NA, NULL);
addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_GLYPH, NA, NA, NA, ",");
addflag(lastot->flags, F_NOMATCONVERT, B_TRUE, NA, NA, NULL);
addot(OT_SOGGYPAPER, "lump of soggy paper", "A useless lump of soggy paper.", MT_WETPAPER, 0.1, OC_MISC, SZ_TINY);
addflag(lastot->flags, F_STACKABLE, NA, NA, NA, NULL);
addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_GLYPH, NA, NA, NA, "?");
addflag(lastot->flags, F_NOMATCONVERT, NA, NA, NA, NULL);
addot(OT_VOMITPOOL, "pool of vomit", "A disgusting pool of regurgitated food.", MT_WATER, 1, OC_MISC, SZ_SMALL);
addflag(lastot->flags, F_RARITY, H_VILLAGE, 90, RR_UNCOMMON, NULL);
addflag(lastot->flags, F_STACKABLE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_GLYPH, C_GREEN, NA, NA, ",");
addflag(lastot->flags, F_NOPICKUP, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_SLIPPERY, 1, NA, NA, NULL);
addflag(lastot->flags, F_DRINKABLE, B_TRUE, 0, NA, NULL);
addflag(lastot->flags, F_TAINTED, B_TRUE, NA, NA, NULL);
addot(OT_ACIDPOOL, "pool of acid", "A pool of corrosive acid.", MT_ACID, 0, OC_MISC, SZ_MEDIUM);
addflag(lastot->flags, F_STACKABLE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_GLYPH, NA, NA, NA, "~");
addflag(lastot->flags, F_NOPICKUP, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_DIECONVERTTEXT, NA, NA, NA, "evaporates");
addflag(lastot->flags, F_DIECONVERT, NA, NA, NA, "puddle of acid");
addflag(lastot->flags, F_OBHP, 4, 4, NA, NULL);
addflag(lastot->flags, F_OBHPDRAIN, 1, NA, NA, NULL);
addflag(lastot->flags, F_NOOBDAMTEXT, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_WALKDAMBP, BP_FEET, DT_ACID, FALLTHRU, "2d4");
addflag(lastot->flags, F_DRINKABLE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_LINKOB, OT_POT_ACID, NA, NA, NULL);
addot(OT_ACIDPUDDLE, "puddle of acid", "A small puddle of corrosive acid.", MT_ACID, 0, OC_MISC, SZ_SMALL);
addflag(lastot->flags, F_STACKABLE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_GLYPH, NA, NA, NA, "~");
addflag(lastot->flags, F_NOPICKUP, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_OBDIETEXT, NA, NA, NA, "evaporates");
addflag(lastot->flags, F_OBHP, 4, 4, NA, NULL);
addflag(lastot->flags, F_OBHPDRAIN, 1, NA, NA, NULL);
addflag(lastot->flags, F_NOOBDAMTEXT, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_WALKDAMBP, BP_FEET, DT_ACID, FALLTHRU, "1d4");
addflag(lastot->flags, F_DRINKABLE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_LINKOB, OT_POT_ACID, NA, NA, NULL);
addot(OT_ACIDSPLASH, "splash of acid", "A splash corrosive acid.", MT_ACID, 0, OC_MISC, SZ_SMALL);
addflag(lastot->flags, F_STACKABLE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_GLYPH, NA, NA, NA, ",");
addflag(lastot->flags, F_NOPICKUP, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_OBDIETEXT, NA, NA, NA, "evaporates");
addflag(lastot->flags, F_OBHP, 2, 2, NA, NULL);
addflag(lastot->flags, F_OBHPDRAIN, 1, NA, NA, NULL);
addflag(lastot->flags, F_NOOBDAMTEXT, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_WALKDAMBP, BP_FEET, DT_ACID, FALLTHRU, "1d2");
addflag(lastot->flags, F_DRINKABLE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_LINKOB, OT_POT_ACID, NA, NA, NULL);
addot(OT_SLIMEPOOL, "pool of slime", "A disgusting mass of sticky slime.", MT_WATER, 20, OC_MISC, SZ_MEDIUM);
addflag(lastot->flags, F_STACKABLE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_GLYPH, NA, NA, NA, ",");
addflag(lastot->flags, F_NOPICKUP, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_EDIBLE, B_TRUE, 2, NA, NULL);
addot(OT_PUDDLEOIL, "puddle of oil", "A slippery puddle of oil.", MT_OIL, 15, OC_MISC, SZ_SMALL);
addflag(lastot->flags, F_STACKABLE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_GLYPH, C_GREY, NA, NA, ","); // should really be dark grey
addflag(lastot->flags, F_RARITY, H_DUNGEON, 70, NA, NULL);
addflag(lastot->flags, F_NOPICKUP, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_FLAMMABLE, 5, NA, NA, "medium fire");
addflag(lastot->flags, F_DRINKABLE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_LINKOB, OT_POT_OIL, NA, NA, NULL);
addflag(lastot->flags, F_SLIPPERY, 13, NA, NA, NULL);
addflag(lastot->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_OBHP, 5, 5, NA, NULL);
addflag(lastot->flags, F_OBHPDRAIN, 1, NA, NA, NULL);
addflag(lastot->flags, F_NOOBDAMTEXT, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_OBDIETEXT, NA, NA, NA, "evaporates");
// this isn't made out of water, so that it won't put out fire etc
addot(OT_SPLASHWATER, "splash of water", "A small splash of water.", MT_NOTHING, 0.5, OC_MISC, SZ_SMALL);
addflag(lastot->flags, F_STACKABLE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_GLYPH, C_BLUE, NA, NA, ",");
addflag(lastot->flags, F_RARITY, H_DUNGEON, 75, NA, NULL);
addflag(lastot->flags, F_NOPICKUP, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_OBDIETEXT, NA, NA, NA, "evaporates");
addflag(lastot->flags, F_OBHP, 5, 5, NA, NULL);
addflag(lastot->flags, F_OBHPDRAIN, 1, NA, NA, NULL);
addflag(lastot->flags, F_NOOBDAMTEXT, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_DTVULN, DT_FIRE, NA, NA, "0d1+100");
addflag(lastot->flags, F_LINKOB, OT_POT_WATER, NA, NA, NULL);
addot(OT_MUDPOOL, "pool of mud", "A large puddle of wet mud.", MT_WATER, 60, OC_MISC, SZ_MEDIUM);
addflag(lastot->flags, F_STACKABLE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_GLYPH, C_BROWN, NA, NA, "~");
addflag(lastot->flags, F_RARITY, H_DUNGEON, 75, NA, NULL);
addflag(lastot->flags, F_RARITY, H_FOREST, 90, NA, NULL);
addflag(lastot->flags, F_NOPICKUP, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_DTIMMUNE, DT_WATER, NA, NA, NULL);
addflag(lastot->flags, F_REDUCEMOVEMENT, 2, NA, NA, NULL);
addflag(lastot->flags, F_THEREISHERE, B_TRUE, NA, NA, "!");
//addflag(lastot->flags, F_WALKDAM, DT_WATER, NA, NA, "0d1+1");
addflag(lastot->flags, F_WALKDAMBP, BP_FEET, DT_WATER, FALLTHRU, "0d1+1");
addot(OT_PUDDLEWATER, "small puddle of water", "A small puddle of water.", MT_WATER, 10, OC_MISC, SZ_SMALL);
addflag(lastot->flags, F_STACKABLE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_GLYPH, C_BLUE, NA, NA, ",");
addflag(lastot->flags, F_RARITY, H_VILLAGE, 100, RR_COMMON, NULL);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 75, NA, NULL);
addflag(lastot->flags, F_RARITY, H_FOREST, 90, NA, NULL);
addflag(lastot->flags, F_NOPICKUP, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_DTCONVERT, DT_COLD, NA, NA, "sheet of ice");
addflag(lastot->flags, F_DTCONVERT, DT_FIRE, NA, NA, "puff of steam");
addflag(lastot->flags, F_DRINKABLE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_OBHP, 10, 10, NA, NULL);
addflag(lastot->flags, F_OBHPDRAIN, 1, NA, NA, NULL);
addflag(lastot->flags, F_NOOBDAMTEXT, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_NOOBDIETEXT, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_LINKOB, OT_POT_WATER, NA, NA, NULL);
//addflag(lastot->flags, F_WALKDAM, DT_WATER, NA, NA, "0d1+1");
addflag(lastot->flags, F_WALKDAMBP, BP_FEET, DT_WATER, FALLTHRU, "0d1+1");
addot(OT_PUDDLEWATERL, "large puddle of water", "A large pool of water.", MT_WATER, 20, OC_MISC, SZ_MEDIUM);
addflag(lastot->flags, F_STACKABLE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_GLYPH, C_BLUE, NA, NA, "~");
addflag(lastot->flags, F_RARITY, H_VILLAGE, 100, RR_COMMON, NULL);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 70, NA, NULL);
addflag(lastot->flags, F_RARITY, H_FOREST, 85, NA, NULL);
addflag(lastot->flags, F_NOPICKUP, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_DTCONVERT, DT_COLD, NA, NA, "sheet of ice");
addflag(lastot->flags, F_DTCONVERT, DT_FIRE, NA, NA, "cloud of steam");
addflag(lastot->flags, F_DRINKABLE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_OBHP, 30, 30, NA, NULL);
addflag(lastot->flags, F_OBHPDRAIN, 1, NA, NA, NULL);
addflag(lastot->flags, F_NOOBDAMTEXT, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_NOOBDIETEXT, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_LINKOB, OT_POT_WATER, NA, NA, NULL);
addflag(lastot->flags, F_WALKDAMBP, BP_FEET, DT_WATER, FALLTHRU, "0d1+2");
addot(OT_BLOODSTAIN, "blood stain", "A dried stain of blood.", MT_BLOOD, 0, OC_MISC, SZ_TINY);
addflag(lastot->flags, F_STACKABLE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_GLYPH, C_RED, NA, NA, ",");
addflag(lastot->flags, F_RARITY, H_DUNGEON, 60, NA, NULL);
addflag(lastot->flags, F_NOPICKUP, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_COSMETIC, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_NOFEEL, B_TRUE, NA, NA, NULL);
addot(OT_BLOODCSPLASH, "splash of cockatrice blood", "A small pool of cockatrice blood.", MT_BLOOD, 0, OC_MISC, SZ_SMALL);
addflag(lastot->flags, F_STACKABLE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_GLYPH, NA, NA, NA, ",");
addflag(lastot->flags, F_RARITY, H_DUNGEON, 50, NA, NULL);
addflag(lastot->flags, F_NOPICKUP, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_SLIPPERY, 1, NA, NA, NULL);
addflag(lastot->flags, F_OBDIETEXT, NA, NA, NA, "evaporates");
addflag(lastot->flags, F_OBHP, 3, 3, NA, NULL);
addflag(lastot->flags, F_OBHPDRAIN, 1, NA, NA, NULL);
addflag(lastot->flags, F_NOOBDAMTEXT, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_DRINKABLE, B_TRUE, 0, NA, NULL);
addflag(lastot->flags, F_LINKOB, OT_POT_BLOODC, NA, NA, NULL);
addflag(lastot->flags, F_NOFEEL, B_TRUE, NA, NA, NULL);
addot(OT_BLOODSPLASH, "splash of blood", "A small pool of blood.", MT_BLOOD, 0, OC_MISC, SZ_SMALL);
addflag(lastot->flags, F_STACKABLE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_GLYPH, NA, NA, NA, ",");
addflag(lastot->flags, F_RARITY, H_VILLAGE, 100, RR_UNCOMMON, NULL);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 75, NA, NULL);
addflag(lastot->flags, F_NOPICKUP, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_SLIPPERY, 1, NA, NA, NULL);
addflag(lastot->flags, F_DIECONVERT, NA, NA, NA, "blood stain");
//addflag(lastot->flags, F_DIECONVERTTEXT, NA, NA, NA, "dries up");
//addflag(lastot->flags, F_DIECONVERTTEXTPL, NA, NA, NA, "dry up");
addflag(lastot->flags, F_NODIECONVERTTEXT, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_OBHP, 30, 30, NA, NULL);
addflag(lastot->flags, F_OBHPDRAIN, 1, NA, NA, NULL);
addflag(lastot->flags, F_NOOBDAMTEXT, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_LINKOB, OT_POT_BLOOD, NA, NA, NULL);
addflag(lastot->flags, F_COSMETIC, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_NOFEEL, B_TRUE, NA, NA, NULL);
addot(OT_BLOODPOOL, "pool of blood", "A large pool of blood.", MT_BLOOD, 0, OC_MISC, SZ_MEDIUM);
addflag(lastot->flags, F_STACKABLE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_GLYPH, NA, NA, NA, "~");
addflag(lastot->flags, F_RARITY, H_DUNGEON, 65, NA, NULL);
addflag(lastot->flags, F_NOPICKUP, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_SLIPPERY, 3, NA, NA, NULL);
addflag(lastot->flags, F_DIECONVERT, NA, NA, NA, "blood stain");
addflag(lastot->flags, F_DIECONVERTTEXT, NA, NA, NA, "dries up");
addflag(lastot->flags, F_DIECONVERTTEXTPL, NA, NA, NA, "dry up");
addflag(lastot->flags, F_OBHP, 45, 45, NA, NULL);
addflag(lastot->flags, F_OBHPDRAIN, 1, NA, NA, NULL);
addflag(lastot->flags, F_NOOBDAMTEXT, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_DRINKABLE, B_TRUE, 0, NA, NULL);
addflag(lastot->flags, F_LINKOB, OT_POT_BLOOD, NA, NA, NULL);
addflag(lastot->flags, F_NOFEEL, B_TRUE, NA, NA, NULL);
addot(OT_SIGN, "sign", "A marker with something written on it.", MT_WOOD, 25, OC_MISC, SZ_MEDIUM);
addflag(lastot->flags, F_GLYPH, C_BROWN, NA, NA, "|");
addflag(lastot->flags, F_NOPICKUP, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_OBHP, 6, 6, NA, NULL);
// furniture
addot(OT_CANDELABRUM, "candelabrum", "A large (and heavy) decorative candle, about human height.", MT_METAL, 60, OC_FURNITURE, SZ_HUMAN);
addflag(lastot->flags, F_GLYPH, C_YELLOW, NA, NA, "\\");
addflag(lastot->flags, F_RARITY, H_DUNGEON, 85, NA, NULL);
addflag(lastot->flags, F_OPERABLE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_OPERONOFF, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_ACTIVATEPREFIX, NA, NA, NA, "lit");
addflag(lastot->flags, F_ACTIVATECONFER, F_PRODUCESLIGHT, 4, NA, NULL);
addflag(lastot->flags, F_PRODUCESLIGHT, 4, NA, IFACTIVE, NULL);
addflag(lastot->flags, F_REFILLWITH, OT_POT_OIL, NA, NA, NULL);
addflag(lastot->flags, F_RODSHAPED, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_LIGHTSOURCE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_CHARGELOWMSG, B_TRUE, NA, NA, "flickers");
addflag(lastot->flags, F_CHARGEOUTMSG, B_TRUE, NA, NA, "goes out");
addot(OT_COFFIN, "coffin", "A wooden coffin, made for holding the dead.", MT_WOOD, 100, OC_FURNITURE, SZ_HUMAN);
addflag(lastot->flags, F_RARITY, H_ALL, 75, RR_RARE, NULL);
addflag(lastot->flags, F_GLYPH, C_GREY, NA, NA, "|");
addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_OPERABLE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_CONTAINER, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_STARTOB, 80, NA, NA, "3-4 piles of ash");
addflag(lastot->flags, F_STARTOB, 80, NA, NA, "5-10 bones");
addflag(lastot->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_OBHP, 30, 30, NA, NULL);
addot(OT_FIREPLACE, "fireplace", "A roaring fireplace.", MT_STONE, 200, OC_FURNITURE, SZ_LARGE);
addflag(lastot->flags, F_GLYPH, C_RED, NA, NA, "\\");
addflag(lastot->flags, F_PRODUCESLIGHT, 3, NA, IFACTIVE, NULL);
addflag(lastot->flags, F_NOPICKUP, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_ONFIRE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_IMPASSABLE, SZ_MIN, SZ_MAX, NA, NULL);
addot(OT_WEAPONRACK, "weapon rack", "A large matel frame, made to store weapons.", MT_METAL, 150, OC_FURNITURE, SZ_HUMAN);
addflag(lastot->flags, F_RARITY, H_ALL, 80, RR_RARE, NULL);
addflag(lastot->flags, F_GLYPH, C_GREY, NA, NA, "\\");
addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_NOPICKUP, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_OPERABLE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_CONTAINER, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_STARTOB, 80, NA, NA, "random weapon");
addflag(lastot->flags, F_STARTOB, 60, NA, NA, "random weapon");
addflag(lastot->flags, F_STARTOB, 50, NA, NA, "good weapon");
addflag(lastot->flags, F_STARTOB, 50, NA, NA, "great weapon");
addot(OT_WOODENBARREL, "wooden barrel", "A solid wooden barrel.", MT_WOOD, 40, OC_FURNITURE, SZ_HUMAN);
addflag(lastot->flags, F_RARITY, H_VILLAGE, 75, RR_COMMON, NULL);
addflag(lastot->flags, F_RARITY, H_ALL, 75, NA, NULL);
addflag(lastot->flags, F_GLYPH, NA, NA, NA, "(");
addflag(lastot->flags, F_IMPASSABLE, SZ_MIN, SZ_LARGE, NA, NULL);
addflag(lastot->flags, F_CRUSHABLE, SZ_HUGE, NA, NA, NULL);
addflag(lastot->flags, F_PUSHABLE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_NOPICKUP, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_OBHP, 12, 12, NA, NULL);
addflag(lastot->flags, F_OPERABLE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_CONTAINER, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_STARTOBCLASS, 50, OC_POTION, NA, NULL);
addflag(lastot->flags, F_STARTOBCLASS, 50, OC_POTION, NA, NULL);
addflag(lastot->flags, F_STARTOBCLASS, 50, OC_FOOD, NA, NULL);
addflag(lastot->flags, F_STARTOBCLASS, 50, OC_FOOD, NA, NULL);
addflag(lastot->flags, F_STARTOBCLASS, 50, OC_FOOD, NA, NULL);
addflag(lastot->flags, F_STARTOBCLASS, 50, OC_FOOD, NA, NULL);
addflag(lastot->flags, F_STARTOBCLASS, 50, OC_FOOD, NA, NULL);
addflag(lastot->flags, F_STARTOBCLASS, 50, OC_FOOD, NA, NULL);
addot(OT_WOODENTABLE, "wooden table", "A waist-height wooden table.", MT_WOOD, 25, OC_FURNITURE, SZ_HUMAN);
addflag(lastot->flags, F_RARITY, H_ALL, 70, NA, NULL);
addflag(lastot->flags, F_GLYPH, C_BROWN, NA, NA, "\\");
addflag(lastot->flags, F_IMPASSABLE, SZ_MIN, SZ_HUMAN, NA, NULL);
addflag(lastot->flags, F_CRUSHABLE, SZ_LARGE, NA, NA, NULL);
addflag(lastot->flags, F_PUSHABLE, B_TRUE, NA, NA, NULL);
//addflag(lastot->flags, F_NOPICKUP, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_OBHP, 10, 10, NA, NULL);
addflag(lastot->flags, F_DTVULN, DT_BASH, NA, NA, NULL);
addflag(lastot->flags, F_DTVULN, DT_CHOP, NA, NA, NULL);
addot(OT_WOODENSTOOL, "wooden footstool", "A small, wooden footstool.", MT_WOOD, 5, OC_FURNITURE, SZ_SMALL);
addflag(lastot->flags, F_RARITY, H_ALL, 83, NA, NULL);
addflag(lastot->flags, F_GLYPH, NA, NA, NA, "\\");
addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_OBHP, 4, 4, NA, NULL);
addflag(lastot->flags, F_DTVULN, DT_CHOP, NA, NA, NULL);
// trail objects
addot(OT_FOOTPRINT, "footprints", "Footprints which show the passage of some kind of creature.", MT_NOTHING, 0, OC_MISC, SZ_MINI);
addflag(lastot->flags, F_NO_A, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_NO_PLURAL, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_NOFEEL, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_INVULNERABLE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_NOGLYPH, NA, NA, NA, NULL);
addflag(lastot->flags, F_NOPICKUP, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_NOFEEL, B_TRUE, NA, NA, NULL);
// NOTE: must add F_TRAIL when creating this object.
addot(OT_SCENT, "scent", "The scent of a creature, only perceivable to those with an enhanced sense of smell.", MT_NOTHING, 0, OC_MISC, SZ_MINI);
addflag(lastot->flags, F_NO_A, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_NO_PLURAL, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_INVULNERABLE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_NOGLYPH, NA, NA, NA, NULL);
addflag(lastot->flags, F_NOPICKUP, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_NOFEEL, B_TRUE, NA, NA, NULL);
// NOTE: must add F_TRAIL when creating this object.
// effects
addot(OT_FIRELARGE, "large fire", "A large, roaring inferno.", MT_FIRE, 0, OC_EFFECT, SZ_HUMAN);
addflag(lastot->flags, F_GLYPH, C_ORANGE, NA, NA, "{");
addflag(lastot->flags, F_DIECONVERTTEXT, NA, NA, NA, "dies down a little");
addflag(lastot->flags, F_DIECONVERT, NA, NA, NA, "medium fire");
addflag(lastot->flags, F_OBHP, 3, 3, NA, NULL);
addflag(lastot->flags, F_OBHPDRAIN, 1, NA, NA, NULL);
addflag(lastot->flags, F_NOOBDAMTEXT, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_WALKDAM,DT_FIRE, NA, NA, "2d4+4");
addflag(lastot->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_PRODUCESLIGHT, 3, NA, NA, NULL);
addflag(lastot->flags, F_THEREISHERE, B_TRUE, NA, NA, "!");
addot(OT_FIREMED, "medium fire", "A medium-sized roaring fire.", MT_FIRE, 0, OC_EFFECT, SZ_MEDIUM);
addflag(lastot->flags, F_GLYPH, C_RED, NA, NA, "{");
addflag(lastot->flags, F_DIECONVERT, NA, NA, NA, "small fire");
addflag(lastot->flags, F_DIECONVERTTEXT, NA, NA, NA, "dies down a little");
addflag(lastot->flags, F_OBHP, 3, 3, NA, NULL);
addflag(lastot->flags, F_OBHPDRAIN, 1, NA, NA, NULL);
addflag(lastot->flags, F_NOOBDAMTEXT, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_WALKDAM, DT_FIRE, NA, NA, "2d4");
addflag(lastot->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_PRODUCESLIGHT, 2, NA, NA, NULL);
addflag(lastot->flags, F_THEREISHERE, B_TRUE, NA, NA, "!");
addot(OT_FIRESMALL, "small fire", "A small blaze.", MT_FIRE, 0, OC_EFFECT, SZ_SMALL);
addflag(lastot->flags, F_GLYPH, C_RED, NA, NA, "{");
addflag(lastot->flags, F_OBDIETEXT, B_TRUE, NA, NA, "goes out");
addflag(lastot->flags, F_OBHP, 3, 3, NA, NULL);
addflag(lastot->flags, F_OBHPDRAIN, 1, NA, NA, NULL);
addflag(lastot->flags, F_NOOBDAMTEXT, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_WALKDAM, DT_FIRE, NA, NA, "1d4");
addflag(lastot->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_PRODUCESLIGHT, 1, NA, NA, NULL);
addflag(lastot->flags, F_THEREISHERE, B_TRUE, NA, NA, "!");
addot(OT_STEAMCLOUD, "cloud of steam", "A thick cloud of scalding steam.", MT_GAS, 0, OC_EFFECT, SZ_HUMAN);
addflag(lastot->flags, F_GLYPH, NA, NA, NA, "}");
addflag(lastot->flags, F_NODIECONVERTTEXT, NA, NA, NA, NULL);
addflag(lastot->flags, F_DIECONVERT, NA, NA, NA, "puff of steam");
addflag(lastot->flags, F_OBHP, 3, 3, NA, NULL);
addflag(lastot->flags, F_OBHPDRAIN, 1, NA, NA, NULL);
addflag(lastot->flags, F_NOOBDAMTEXT, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_BLOCKSVIEW, 3, NA, NA, NULL);
addflag(lastot->flags, F_WALKDAM, DT_FIRE, NA, NA, "1d2");
addflag(lastot->flags, F_THEREISHERE, B_TRUE, NA, NA, "!");
addot(OT_STEAMPUFF, "puff of steam", "A small puff of scalding steam.", MT_GAS, 0, OC_EFFECT, SZ_MEDIUM);
addflag(lastot->flags, F_GLYPH, C_GREY, NA, NA, "}");
addflag(lastot->flags, F_OBDIETEXT, B_TRUE, NA, NA, "disperses");
addflag(lastot->flags, F_OBHP, 2, 2, NA, NULL);
addflag(lastot->flags, F_OBHPDRAIN, 1, NA, NA, NULL);
addflag(lastot->flags, F_NOOBDAMTEXT, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_BLOCKSVIEW, 1, NA, NA, NULL);
addflag(lastot->flags, F_WALKDAM, DT_FIRE, NA, NA, "1d1+1");
addflag(lastot->flags, F_THEREISHERE, B_TRUE, NA, NA, "!");
addot(OT_SLEETSTORM, "storm of sleet", "An intense storm of sleet. Hampers movement", MT_GAS, 0, OC_EFFECT, SZ_LARGE);
addflag(lastot->flags, F_GLYPH, C_CYAN, NA, NA, "}");
addflag(lastot->flags, F_NODIECONVERTTEXT, NA, NA, NA, NULL);
addflag(lastot->flags, F_OBHP, 10, 10, NA, NULL);
addflag(lastot->flags, F_OBHPDRAIN, 1, NA, NA, NULL);
addflag(lastot->flags, F_NOOBDAMTEXT, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_NOOBDIETEXT, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_BLOCKSVIEW, 3, NA, NA, NULL);
addflag(lastot->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_REDUCEMOVEMENT, 3, NA, NA, NULL);
addflag(lastot->flags, F_THEREISHERE, B_TRUE, NA, NA, "!");
addflag(lastot->flags, F_WALKDAMBP, BP_HEAD, DT_WATER, NA, "1d2");
addflag(lastot->flags, F_WALKDAMBP, BP_SHOULDERS, DT_WATER, NA, "1d2");
addflag(lastot->flags, F_WALKDAMBP, BP_BODY, DT_WATER, NA, "1d2");
addflag(lastot->flags, F_WALKDAMBP, BP_HANDS, DT_WATER, NA, "1d2");
addflag(lastot->flags, F_WALKDAMBP, BP_LEGS, DT_WATER, NA, "1d2");
addflag(lastot->flags, F_WALKDAMBP, BP_FEET, DT_WATER, NA, "1d2");
addot(OT_MIST, "thick mist", "A thick cloud of obscuring mist.", MT_GAS, 0, OC_EFFECT, SZ_LARGE);
addflag(lastot->flags, F_GLYPH, NA, NA, NA, "}");
addflag(lastot->flags, F_OBDIETEXT, B_TRUE, NA, NA, "clears");
addflag(lastot->flags, F_OBHP, 4, 4, NA, NULL);
addflag(lastot->flags, F_OBHPDRAIN, 1, NA, NA, NULL);
addflag(lastot->flags, F_NOOBDAMTEXT, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_BLOCKSVIEW, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_THEREISHERE, B_TRUE, NA, NA, "!");
addot(OT_SMOKECLOUD, "cloud of smoke", "A thick cloud of black smoke.", MT_GAS, 0, OC_EFFECT, SZ_LARGE);
addflag(lastot->flags, F_GLYPH, NA, NA, NA, "}");
addflag(lastot->flags, F_NODIECONVERTTEXT, NA, NA, NA, NULL);
addflag(lastot->flags, F_DIECONVERT, NA, NA, NA, "puff of smoke");
addflag(lastot->flags, F_OBHP, 3, 3, NA, NULL);
addflag(lastot->flags, F_OBHPDRAIN, 1, NA, NA, NULL);
addflag(lastot->flags, F_NOOBDAMTEXT, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_BLOCKSVIEW, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_THEREISHERE, B_TRUE, NA, NA, "!");
addflag(lastot->flags, F_CAUSESCOUGH, 26, NA, NA, NULL);
addot(OT_SMOKEPUFF, "puff of smoke", "A small puff of black smoke.", MT_GAS, 0, OC_EFFECT, SZ_MEDIUM);
addflag(lastot->flags, F_GLYPH, NA, NA, NA, "}");
addflag(lastot->flags, F_OBDIETEXT, B_TRUE, NA, NA, "disperses");
addflag(lastot->flags, F_OBHP, 2, 2, NA, NULL);
addflag(lastot->flags, F_OBHPDRAIN, 1, NA, NA, NULL);
addflag(lastot->flags, F_NOOBDAMTEXT, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_BLOCKSVIEW, 4, NA, NA, NULL);
addflag(lastot->flags, F_THEREISHERE, B_TRUE, NA, NA, ".");
addflag(lastot->flags, F_CAUSESCOUGH, 18, NA, NA, NULL);
addot(OT_POISONCLOUD, "cloud of poison gas", "A thick cloud of poisonous gas.", MT_GAS, 0, OC_EFFECT, SZ_LARGE);
addflag(lastot->flags, F_GLYPH, C_GREEN, NA, NA, "}");
addflag(lastot->flags, F_DIECONVERTTEXT, NA, NA, NA, "thins out a little");
addflag(lastot->flags, F_DIECONVERT, NA, NA, NA, "puff of gas");
addflag(lastot->flags, F_OBHP, 3, 3, NA, NULL);
addflag(lastot->flags, F_OBHPDRAIN, 1, NA, NA, NULL);
addflag(lastot->flags, F_NOOBDAMTEXT, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_WALKDAM, DT_POISONGAS, NA, NA, "1d4");
addflag(lastot->flags, F_THEREISHERE, B_TRUE, NA, NA, "!");
addflag(lastot->flags, F_BLOCKSVIEW, 2, NA, NA, NULL);
addot(OT_POISONPUFF, "puff of poison gas", "A small puff of poisonous gas.", MT_GAS, 0, OC_EFFECT, SZ_MEDIUM);
addflag(lastot->flags, F_GLYPH, C_GREEN, NA, NA, "}");
addflag(lastot->flags, F_OBDIETEXT, B_TRUE, NA, NA, "disperses");
addflag(lastot->flags, F_OBHP, 2, 2, NA, NULL);
addflag(lastot->flags, F_OBHPDRAIN, 1, NA, NA, NULL);
addflag(lastot->flags, F_NOOBDAMTEXT, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_WALKDAM, DT_POISONGAS, NA, NA, "1d2");
addflag(lastot->flags, F_THEREISHERE, B_TRUE, NA, NA, "!");
addot(OT_HAILSTORM, "hail storm", "An intense storm of damaging hail.", MT_GAS, 0, OC_EFFECT, SZ_LARGE);
addflag(lastot->flags, F_GLYPH, C_WHITE, NA, NA, "}");
addflag(lastot->flags, F_NODIECONVERTTEXT, NA, NA, NA, NULL);
addflag(lastot->flags, F_OBHP, 10, 10, NA, NULL);
addflag(lastot->flags, F_OBHPDRAIN, 1, NA, NA, NULL);
addflag(lastot->flags, F_BLOCKSVIEW, 5, NA, NA, NULL);
addflag(lastot->flags, F_NOOBDAMTEXT, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_NOOBDIETEXT, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_THEREISHERE, B_TRUE, NA, NA, "!");
addflag(lastot->flags, F_WALKDAM, DT_COLD, NA, NA, "1d4");
addflag(lastot->flags, F_WALKDAMBP, BP_HEAD, DT_WATER, NA, "1d2");
addflag(lastot->flags, F_WALKDAMBP, BP_SHOULDERS, DT_WATER, NA, "1d2");
addflag(lastot->flags, F_WALKDAMBP, BP_BODY, DT_WATER, NA, "1d2");
addflag(lastot->flags, F_WALKDAMBP, BP_HANDS, DT_WATER, NA, "1d2");
addflag(lastot->flags, F_WALKDAMBP, BP_LEGS, DT_WATER, NA, "1d2");
addflag(lastot->flags, F_WALKDAMBP, BP_FEET, DT_WATER, NA, "1d2");
addot(OT_ICEWALL, "wall of ice", "A wall made of solid ice.", MT_ICE, 0, OC_EFFECT, SZ_LARGE);
addflag(lastot->flags, F_GLYPH, C_CYAN, NA, NA, "#");
addflag(lastot->flags, F_IMPASSABLE, SZ_MIN, SZ_MAX, NA, NULL);
addflag(lastot->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_OBHP, 100, 100, NA, NULL);
addflag(lastot->flags, F_NOOBDAMTEXT, B_TRUE, NA, NA, NULL);
addot(OT_MAGICBARRIER, "magical barrier", "A glowing, impassable barrier of magical energy.", MT_MAGIC, 0, OC_EFFECT, SZ_LARGE);
addflag(lastot->flags, F_GLYPH, C_YELLOW, NA, NA, "#");
addflag(lastot->flags, F_IMPASSABLE, SZ_MIN, SZ_MAX, NA, NULL);
addflag(lastot->flags, F_REALLYIMPASSABLE, NA, NA, NA, NULL);
addflag(lastot->flags, F_BLOCKSLOF, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_NOOBDAMTEXT, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_OBDIETEXT, B_TRUE, NA, NA, "vanishes");
addflag(lastot->flags, F_PRODUCESLIGHT, 1, NA, NA, NULL);
addot(OT_VINE, "entangling vine", "A living vine which grasps nearby creature", MT_SILK, 0.1, OC_EFFECT, SZ_HUMAN);
addflag(lastot->flags, F_STACKABLE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 82, NA, NULL);
addflag(lastot->flags, F_RARITY, H_FOREST, 90, NA, NULL);
addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_GLYPH, C_GREEN, NA, NA, "^");
addflag(lastot->flags, F_RESTRICTMOVEMENT, 30, B_TRUE, B_TRUE, NULL);// the value here will be filled in by the spell.
addflag(lastot->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_OBHP, 5, 5, NA, NULL);
addflag(lastot->flags, F_DTVULN, DT_FIRE, NA, NA, NULL);
addflag(lastot->flags, F_DTVULN, DT_ACID, NA, NA, NULL);
addflag(lastot->flags, F_THEREISHERE, B_TRUE, NA, NA, "!");
addot(OT_WEB, "web", "A huge, sticky spider web.", MT_SILK, 0.1, OC_EFFECT, SZ_HUMAN);
addflag(lastot->flags, F_STACKABLE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_GLYPH, C_GREY, NA, NA, "^");
addflag(lastot->flags, F_RARITY, H_DUNGEON, 86, NA, NULL);
addflag(lastot->flags, F_RARITY, H_FOREST, 88, NA, NULL);
addflag(lastot->flags, F_RESTRICTMOVEMENT, 25, B_TRUE, B_TRUE, NULL);
addflag(lastot->flags, F_NOOBDAMTEXT, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_OBHP, 5, 5, NA, NULL);
addflag(lastot->flags, F_DTVULN, DT_FIRE, NA, NA, NULL);
addflag(lastot->flags, F_DTVULN, DT_ACID, NA, NA, NULL);
addflag(lastot->flags, F_THEREISHERE, B_TRUE, NA, NA, "!");
// armour - body
addot(OT_COTTONSHIRT, "cotton shirt", "A comfortable white cotton shirt.", MT_CLOTH, 0.7, OC_ARMOUR, SZ_MEDIUM);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_COMMON, NULL);
addflag(lastot->flags, F_RARITY, H_FOREST, 100, RR_UNCOMMON, NULL);
addflag(lastot->flags, F_GOESON, BP_BODY, NA, NA, NULL);
addflag(lastot->flags, F_ARMOURRATING, 0, NA, NA, NULL);
addflag(lastot->flags, F_OBHP, 10, 10, NA, NULL);
addflag(lastot->flags, F_ATTREQ, A_DEX, 3, NA, NULL);
addot(OT_ARMOURLEATHER, "leather armour", "Body armour created from soft leather.", MT_LEATHER, 10, OC_ARMOUR, SZ_MEDIUM);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_COMMON, NULL);
addflag(lastot->flags, F_GOESON, BP_BODY, NA, NA, NULL);
addflag(lastot->flags, F_ARMOURRATING, 4, NA, NA, NULL);
addflag(lastot->flags, F_EQUIPCONFER, F_ARMOURPENALTY, 10, 10, NULL);
addflag(lastot->flags, F_OBHP, 20, 20, NA, NULL);
addflag(lastot->flags, F_ATTREQ, A_STR, 3, NA, NULL);
addot(OT_ARMOURRING, "suit of ring mail", "Body armour formed by a series of metallic rings sewn to a leather foundation.", MT_METAL, 15, OC_ARMOUR, SZ_MEDIUM);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_COMMON, NULL);
addflag(lastot->flags, F_GOESON, BP_BODY, NA, NA, NULL);
addflag(lastot->flags, F_ARMOURRATING, 6, NA, NA, NULL);
addflag(lastot->flags, F_EQUIPCONFER, F_ARMOURPENALTY, 20, 20, NULL);
addflag(lastot->flags, F_ATTREQ, A_STR, 7, NA, NULL);
addflag(lastot->flags, F_OBHP, 30, 30, NA, NULL);
addot(OT_ARMOURSCALE, "suit of scale armour", "Body armour consisting of many small scales attached to leather.", MT_METAL, 20, OC_ARMOUR, SZ_MEDIUM);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_UNCOMMON, NULL);
addflag(lastot->flags, F_GOESON, BP_BODY, NA, NA, NULL);
addflag(lastot->flags, F_ARMOURRATING, 10, NA, NA, NULL);
addflag(lastot->flags, F_EQUIPCONFER, F_ARMOURPENALTY, 30, 30, NULL);
addflag(lastot->flags, F_ATTREQ, A_STR, 9, NA, NULL);
addflag(lastot->flags, F_OBHP, 35, 35, NA, NULL);
addot(OT_ARMOURCHAIN, "suit of chainmail", "Heavy body armour consisting of tightly meshed metal rings.", MT_METAL, 25, OC_ARMOUR, SZ_MEDIUM);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_UNCOMMON, NULL);
addflag(lastot->flags, F_GOESON, BP_BODY, NA, NA, NULL);
addflag(lastot->flags, F_ARMOURRATING, 15, NA, NA, NULL);
addflag(lastot->flags, F_EQUIPCONFER, F_ARMOURPENALTY, 40, 40, NULL);
addflag(lastot->flags, F_ATTREQ, A_STR, 9, NA, NULL);
addflag(lastot->flags, F_OBHP, 45, 45, NA, NULL);
addot(OT_ARMOURSPLINT, "suit of splint mail", "Heavy armour, consisting of strips of metal attached to a leather backing.", MT_METAL, 35, OC_ARMOUR, SZ_MEDIUM);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_UNCOMMON, NULL);
addflag(lastot->flags, F_GOESON, BP_BODY, NA, NA, NULL);
addflag(lastot->flags, F_ARMOURRATING, 20, NA, NA, NULL);
addflag(lastot->flags, F_EQUIPCONFER, F_ARMOURPENALTY, 50, 50, NULL);
addflag(lastot->flags, F_ATTREQ, A_STR, 11, NA, NULL);
addflag(lastot->flags, F_OBHP, 50, 50, NA, NULL);
addot(OT_ARMOURPLATE, "suit of plate mail", "Heavy armour with embedded metal plates.", MT_METAL, 40, OC_ARMOUR, SZ_MEDIUM);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 90, RR_RARE, NULL);
addflag(lastot->flags, F_GOESON, BP_BODY, NA, NA, NULL);
addflag(lastot->flags, F_ARMOURRATING, 25, NA, NA, NULL);
addflag(lastot->flags, F_EQUIPCONFER, F_ARMOURPENALTY, 60, 60, NULL);
addflag(lastot->flags, F_ATTREQ, A_STR, 13, NA, NULL);
addflag(lastot->flags, F_OBHP, 60, 60, NA, NULL);
addot(OT_FLAKJACKET, "flak jacket", "Heavy metal body armour. Designed to stop a bullet, but only once.", MT_METAL, 30, OC_ARMOUR, SZ_MEDIUM);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_RARE, NULL);
addflag(lastot->flags, F_GOESON, BP_BODY, NA, NA, NULL);
addflag(lastot->flags, F_ARMOURRATING, 10, NA, NA, NULL);
addflag(lastot->flags, F_EQUIPCONFER, F_ARMOURPENALTY, 10, 10, NULL);
addflag(lastot->flags, F_ATTREQ, A_STR, 10, NA, NULL);
addflag(lastot->flags, F_OBHP, 3, 3, NA, NULL);
addot(OT_OVERALLS, "pair of overalls", "Well-made, brightly coloured workman overalls.", MT_CLOTH, 1, OC_ARMOUR, SZ_MEDIUM);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_COMMON, NULL);
addflag(lastot->flags, F_GOESON, BP_LEGS, NA, NA, NULL);
addflag(lastot->flags, F_ARMOURRATING, 2, NA, NA, NULL);
addflag(lastot->flags, F_ATTREQ, A_DEX, 7, NA, NULL);
addflag(lastot->flags, F_OBHP, 10, 10, NA, NULL);
addot(OT_SILKSHIRT, "silk shirt", "A lightweight, comfortable white silk shirt.", MT_SILK, 0.5, OC_ARMOUR, SZ_MEDIUM);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_COMMON, NULL);
addflag(lastot->flags, F_RARITY, H_FOREST, 100, RR_UNCOMMON, NULL);
addflag(lastot->flags, F_GOESON, BP_BODY, NA, NA, NULL);
addflag(lastot->flags, F_ARMOURRATING, 0, NA, NA, NULL);
addflag(lastot->flags, F_OBHP, 5, 5, NA, NULL);
addflag(lastot->flags, F_ATTREQ, A_DEX, 3, NA, NULL);
addot(OT_ROBE, "robe", "A plain robe.", MT_CLOTH, 4, OC_ARMOUR, SZ_MEDIUM);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_COMMON, NULL);
addflag(lastot->flags, F_GOESON, BP_BODY, NA, NA, NULL);
addflag(lastot->flags, F_ARMOURRATING, 1, NA, NA, NULL);
addflag(lastot->flags, F_OBHP, 10, 10, NA, NULL);
addot(OT_VELVETROBE, "velvet robe", "A luxurious velvet robe.", MT_CLOTH, 4, OC_ARMOUR, SZ_MEDIUM);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 90, RR_UNCOMMON, NULL);
addflag(lastot->flags, F_GOESON, BP_BODY, NA, NA, NULL);
addflag(lastot->flags, F_ARMOURRATING, 1, NA, NA, NULL);
addflag(lastot->flags, F_OBHP, 10, 10, NA, NULL);
// armour - shoulders
addot(OT_CLOAK, "cloak", "A standard leather cloak.", MT_LEATHER, 4, OC_ARMOUR, SZ_MEDIUM);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_COMMON, NULL);
addflag(lastot->flags, F_RARITY, H_FOREST, 100, RR_UNCOMMON, NULL);
addflag(lastot->flags, F_GOESON, BP_SHOULDERS, NA, NA, NULL);
addflag(lastot->flags, F_ARMOURRATING, 1, NA, NA, NULL);
addflag(lastot->flags, F_OBHP, 10, 10, NA, NULL);
addflag(lastot->flags, F_WATERPROOF, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_HELPSREST, 5, NA, NA, NULL);
// armour - waist
addot(OT_BELTLEATHER, "leather belt", "A plain leather belt.", MT_LEATHER, 0.2, OC_ARMOUR, SZ_SMALL);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_COMMON, NULL);
addflag(lastot->flags, F_GOESON, BP_WAIST, NA, NA, NULL);
addflag(lastot->flags, F_ATTREQ, A_DEX, 3, NA, NULL);
addflag(lastot->flags, F_OBHP, 2, 2, NA, NULL);
// armour - legs
addot(OT_CLOTHTROUSERS, "pair of cloth trousers", "A rough pair of cloth trousers.", MT_CLOTH, 2, OC_ARMOUR, SZ_MEDIUM);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_COMMON, NULL);
addflag(lastot->flags, F_RARITY, H_FOREST, 100, RR_COMMON, NULL);
addflag(lastot->flags, F_GOESON, BP_LEGS, NA, NA, NULL);
addflag(lastot->flags, F_ARMOURRATING, 1, NA, NA, NULL);
addflag(lastot->flags, F_OBHP, 10, 10, NA, NULL);
addflag(lastot->flags, F_ATTREQ, A_DEX, 3, NA, NULL);
addot(OT_RIDINGTROUSERS, "pair of riding trousers", "A fitted pair of leather trousers.", MT_LEATHER, 2, OC_ARMOUR, SZ_MEDIUM);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_COMMON, NULL);
addflag(lastot->flags, F_RARITY, H_FOREST, 100, RR_COMMON, NULL);
addflag(lastot->flags, F_GOESON, BP_LEGS, NA, NA, NULL);
addflag(lastot->flags, F_ARMOURRATING, 2, NA, NA, NULL);
addflag(lastot->flags, F_OBHP, 15, 15, NA, NULL);
addflag(lastot->flags, F_ATTREQ, A_DEX, 3, NA, NULL);
addot(OT_COMBATPANTS, "pair of combat pants", "An lightly-armoured pair of camoflauged trousers.", MT_CLOTH, 2, OC_ARMOUR, SZ_MEDIUM);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_COMMON, NULL);
addflag(lastot->flags, F_GOESON, BP_LEGS, NA, NA, NULL);
addflag(lastot->flags, F_ARMOURRATING, 3, NA, NA, NULL);
addflag(lastot->flags, F_OBHP, 15, 15, NA, NULL);
addflag(lastot->flags, F_ATTREQ, A_DEX, 3, NA, NULL);
addot(OT_GREAVES, "set of greaves", "A set of heavy metal greaves.", MT_METAL, 4, OC_ARMOUR, SZ_MEDIUM);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_UNCOMMON, NULL);
addflag(lastot->flags, F_GOESON, BP_LEGS, NA, NA, NULL);
addflag(lastot->flags, F_ARMOURRATING, 4, NA, NA, NULL);
addflag(lastot->flags, F_OBHP, 25, 25, NA, NULL);
addflag(lastot->flags, F_EQUIPCONFER, F_ARMOURPENALTY, 15, 15, NULL);
addflag(lastot->flags, F_ATTREQ, A_STR, 9, NA, NULL);
addflag(lastot->flags, F_ATTREQ, A_DEX, 3, NA, NULL);
// armour - feet
addot(OT_SANDALS, "pair of sandals", "Comfortable pair of open leather sandals.", MT_LEATHER, 1, OC_ARMOUR, SZ_SMALL);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_COMMON, NULL);
addflag(lastot->flags, F_RARITY, H_FOREST, 100, RR_COMMON, NULL);
addflag(lastot->flags, F_GOESON, BP_FEET, NA, NA, NULL);
addflag(lastot->flags, F_ARMOURRATING, 0, NA, NA, NULL);
addflag(lastot->flags, F_OBHP, 1, 1, NA, NULL);
addot(OT_SHOESLEATHER, "pair of leather shoes", "Cheap and rather uncomfortable leather shoes.", MT_LEATHER, 2, OC_ARMOUR, SZ_SMALL);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_COMMON, NULL);
addflag(lastot->flags, F_RARITY, H_FOREST, 100, RR_COMMON, NULL);
addflag(lastot->flags, F_GOESON, BP_FEET, NA, NA, NULL);
addflag(lastot->flags, F_ARMOURRATING, 1, NA, NA, NULL);
addflag(lastot->flags, F_OBHP, 3, 3, NA, NULL);
addflag(lastot->flags, F_ATTREQ, A_DEX, 7, NA, NULL);
addot(OT_BOOTSRUBBER, "pair of rubber boots", "A waterproof (but somewhat cumbersome) pair of rubber boots.", MT_RUBBER, 6, OC_ARMOUR, SZ_SMALL);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_UNCOMMON, NULL);
addflag(lastot->flags, F_GOESON, BP_FEET, NA, NA, NULL);
addflag(lastot->flags, F_ARMOURRATING, 1, NA, NA, NULL);
addflag(lastot->flags, F_EQUIPCONFER, F_ARMOURPENALTY, 0, 5, NULL);
addflag(lastot->flags, F_OBHP, 10, 10, NA, NULL);
addflag(lastot->flags, F_EQUIPCONFER, F_DTRESIST, DT_ELECTRIC, NA, NULL);
addflag(lastot->flags, F_ATTREQ, A_DEX, 3, NA, NULL);
addot(OT_BOOTSSPIKED, "pair of spiked boots", "A plain pair of leather boots with spikes on the bottom.", MT_LEATHER, 3, OC_ARMOUR, SZ_SMALL);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_RARE, NULL);
addflag(lastot->flags, F_GOESON, BP_FEET, NA, NA, NULL);
addflag(lastot->flags, F_ARMOURRATING, 2, NA, NA, NULL);
addflag(lastot->flags, F_OBHP, 10, 10, NA, NULL);
addflag(lastot->flags, F_EQUIPCONFER, F_STABILITY, NA, NA, NULL);
addflag(lastot->flags, F_ATTREQ, A_DEX, 7, NA, NULL);
addot(OT_BOOTSLEATHER, "pair of leather boots", "A stout pair of leather boots.", MT_LEATHER, 4, OC_ARMOUR, SZ_SMALL);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_COMMON, NULL);
addflag(lastot->flags, F_RARITY, H_FOREST, 100, RR_COMMON, NULL);
addflag(lastot->flags, F_GOESON, BP_FEET, NA, NA, NULL);
addflag(lastot->flags, F_ARMOURRATING, 2, NA, NA, NULL);
addflag(lastot->flags, F_OBHP, 10, 10, NA, NULL);
addflag(lastot->flags, F_ATTREQ, A_DEX, 7, NA, NULL);
addot(OT_BOOTSMETAL, "pair of metal boots", "A strong pair of metal boots.", MT_METAL, 5, OC_ARMOUR, SZ_SMALL);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_UNCOMMON, NULL);
addflag(lastot->flags, F_RARITY, H_FOREST, 100, RR_RARE, NULL);
addflag(lastot->flags, F_GOESON, BP_FEET, NA, NA, NULL);
addflag(lastot->flags, F_ARMOURRATING, 2, NA, NA, NULL);
addflag(lastot->flags, F_OBHP, 20, 20, NA, NULL);
addflag(lastot->flags, F_ATTREQ, A_DEX, 7, NA, NULL);
// armour - gloves
addot(OT_GLOVESCLOTH, "pair of cloth gloves", "A pair of soft cloth gloves.", MT_CLOTH, 0.15, OC_ARMOUR, SZ_SMALL);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_COMMON, NULL);
addflag(lastot->flags, F_RARITY, H_FOREST, 100, RR_COMMON, NULL);
addflag(lastot->flags, F_GOESON, BP_HANDS, NA, NA, NULL);
addflag(lastot->flags, F_ARMOURRATING, 0, NA, NA, NULL);
addflag(lastot->flags, F_OBHP, 5, 5, NA, NULL);
addflag(lastot->flags, F_ATTREQ, A_DEX, 3, NA, NULL);
addot(OT_GLOVESLEATHER, "pair of leather gloves", "A pair of coarse leather gloves.", MT_LEATHER, 0.25, OC_ARMOUR, SZ_SMALL);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_COMMON, NULL);
addflag(lastot->flags, F_GOESON, BP_HANDS, NA, NA, NULL);
addflag(lastot->flags, F_ARMOURRATING, 1, NA, NA, NULL);
addflag(lastot->flags, F_OBHP, 10, 10, NA, NULL);
addflag(lastot->flags, F_ATTREQ, A_DEX, 3, NA, NULL);
addot(OT_GAUNTLETS, "pair of gauntlets", "A durable pair of metal gauntlets.", MT_METAL, 2, OC_ARMOUR, SZ_SMALL);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_COMMON, NULL);
addflag(lastot->flags, F_GOESON, BP_HANDS, NA, NA, NULL);
addflag(lastot->flags, F_ARMOURRATING, 2, NA, NA, NULL);
addflag(lastot->flags, F_EQUIPCONFER, F_ARMOURPENALTY, 10, 5, NULL);
addflag(lastot->flags, F_OBHP, 15, 15, NA, NULL);
addflag(lastot->flags, F_ATTREQ, A_DEX, 3, NA, NULL);
// armour - head
addot(OT_SUNHAT, "sun hat", "Wide-brimmed hat made for working in the sun.", MT_CLOTH, 1, OC_ARMOUR, SZ_SMALL);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_UNCOMMON, NULL);
addflag(lastot->flags, F_RARITY, H_FOREST, 100, RR_COMMON, NULL);
addflag(lastot->flags, F_GOESON, BP_HEAD, NA, NA, NULL);
addflag(lastot->flags, F_ARMOURRATING, 1, NA, NA, NULL);
addflag(lastot->flags, F_OBHP, 3, 3, NA, NULL);
addflag(lastot->flags, F_NOQUALITY, B_TRUE, NA, NA, NULL);
addot(OT_PIRATEHAT, "tricorne", "A three cornered hat with a skull and crossbones emblem.", MT_CLOTH, 1, OC_ARMOUR, SZ_SMALL);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_UNCOMMON, NULL);
addflag(lastot->flags, F_GOESON, BP_HEAD, NA, NA, NULL);
addflag(lastot->flags, F_ARMOURRATING, 1, NA, NA, NULL);
addflag(lastot->flags, F_OBHP, 2, 2, NA, NULL);
addflag(lastot->flags, F_SCARY, 2, NA, NA, NULL);
addflag(lastot->flags, F_NOQUALITY, B_TRUE, NA, NA, NULL);
addot(OT_CAP, "cap", "Close-fitting headwear with a short shade visor at the front.", MT_CLOTH, 1, OC_ARMOUR, SZ_SMALL);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_COMMON, NULL);
addflag(lastot->flags, F_RARITY, H_FOREST, 100, RR_COMMON, NULL);
addflag(lastot->flags, F_GOESON, BP_HEAD, NA, NA, NULL);
addflag(lastot->flags, F_ARMOURRATING, 1, NA, NA, NULL);
addflag(lastot->flags, F_OBHP, 3, 3, NA, NULL);
addflag(lastot->flags, F_NOQUALITY, B_TRUE, NA, NA, NULL);
addot(OT_GASMASK, "gas mask", "A full face mask which protects the wearer from toxic gasses.", MT_METAL, 3.5, OC_ARMOUR, SZ_SMALL);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 75, RR_UNCOMMON, NULL);
addflag(lastot->flags, F_GOESON, BP_HEAD, NA, NA, NULL);
addflag(lastot->flags, F_ARMOURRATING, 2, NA, NA, NULL);
addflag(lastot->flags, F_ACCURACYMOD, -10, NA, NA, NULL);
addflag(lastot->flags, F_OBHP, 10, 10, NA, NULL);
addflag(lastot->flags, F_EQUIPCONFER, F_DTIMMUNE, DT_POISONGAS, NA, NULL);
addflag(lastot->flags, F_EQUIPCONFER, F_VISRANGEMOD, -2, NA, NULL);
addflag(lastot->flags, F_NOQUALITY, B_TRUE, NA, NA, NULL);
addot(OT_HELM, "helmet", "A plain metal helmet.", MT_METAL, 2, OC_ARMOUR, SZ_SMALL);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_COMMON, NULL);
addflag(lastot->flags, F_GOESON, BP_HEAD, NA, NA, NULL);
addflag(lastot->flags, F_ARMOURRATING, 3, NA, NA, NULL);
addflag(lastot->flags, F_OBHP, 20, 20, NA, NULL);
addot(OT_HELMFOOTBALL, "football helmet", "A metal helmet with a grill in front of the face.", MT_METAL, 1, OC_ARMOUR, SZ_SMALL);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_COMMON, NULL);
addflag(lastot->flags, F_GOESON, BP_HEAD, NA, NA, NULL);
addflag(lastot->flags, F_ARMOURRATING, 2, NA, NA, NULL);
addflag(lastot->flags, F_ACCURACYMOD, -10, NA, NA, NULL);
addflag(lastot->flags, F_OBHP, 20, 20, NA, NULL);
addflag(lastot->flags, F_EQUIPCONFER, F_VISRANGEMOD, -1, NA, NULL);
addot(OT_GOLDCROWN, "golden crown", "A heavy gold crown, encrusted with jewels.", MT_GOLD, 5, OC_ARMOUR, SZ_SMALL);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 25, RR_RARE, NULL);
addflag(lastot->flags, F_GOESON, BP_HEAD, NA, NA, NULL);
addflag(lastot->flags, F_ARMOURRATING, 1, NA, NA, NULL);
addflag(lastot->flags, F_OBHP, 10, 10, NA, NULL);
addot(OT_HELMBONE, "bone helmet", "Scary-looking helmet made from the bones of an animal (?).", MT_BONE, 1, OC_ARMOUR, SZ_SMALL);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_COMMON, NULL);
addflag(lastot->flags, F_RARITY, H_FOREST, 100, RR_UNCOMMON, NULL);
addflag(lastot->flags, F_GOESON, BP_HEAD, NA, NA, NULL);
addflag(lastot->flags, F_ARMOURRATING, 2, NA, NA, NULL);
addflag(lastot->flags, F_OBHP, 15, 15, NA, NULL);
addflag(lastot->flags, F_SCARY, 4, NA, NA, NULL);
// armour - ears
addot(OT_EARPLUGS, "set of earplugs", "A pair of cloth plugs designed to give the wearer a peaceful night's sleep. ", MT_CLOTH, 0.01, OC_ARMOUR, SZ_SMALL);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_UNCOMMON, NULL);
addflag(lastot->flags, F_GOESON, BP_EARS, NA, NA, NULL);
addflag(lastot->flags, F_OBHP, 1, 1, NA, NULL);
addflag(lastot->flags, F_EQUIPCONFER, F_DEAF, NA, NA, NULL);
addflag(lastot->flags, F_NOQUALITY, B_TRUE, NA, NA, NULL);
// armour - eyes
addot(OT_SUNGLASSES, "pair of sunglasses", "Tinted eyewear to protect against sunlight.", MT_GLASS, 0.01, OC_ARMOUR, SZ_SMALL);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_COMMON, NULL);
addflag(lastot->flags, F_RARITY, H_FOREST, 100, RR_COMMON, NULL);
addflag(lastot->flags, F_GOESON, BP_EYES, NA, NA, NULL);
addflag(lastot->flags, F_ARMOURRATING, 0, NA, NA, NULL);
addflag(lastot->flags, F_OBHP, 2, 2, NA, NULL);
addflag(lastot->flags, F_EQUIPCONFER, F_VISRANGEMOD, -1, NA, NULL);
addflag(lastot->flags, F_EQUIPCONFER, F_NIGHTVISRANGEMOD, -1, NA, NULL);
addflag(lastot->flags, F_TINTED, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_NOQUALITY, B_TRUE, NA, NA, NULL);
addot(OT_EYEPATCH, "eyepatch", "A small patch of black material which covers one eye. Scary looking.", MT_CLOTH, 0.01, OC_ARMOUR, SZ_SMALL);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_UNCOMMON, NULL);
addflag(lastot->flags, F_RARITY, H_FOREST, 100, RR_UNCOMMON, NULL);
addflag(lastot->flags, F_GOESON, BP_EYES, NA, NA, NULL);
addflag(lastot->flags, F_NOQUALITY, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_SCARY, 2, NA, NA, NULL);
addflag(lastot->flags, F_EQUIPCONFER, F_VISRANGEMOD, -2, NA, NULL);
// armour - shields
addot(OT_BUCKLER, "buckler", "A small, unobtrusive wooden shield.", MT_WOOD, 3.00, OC_ARMOUR, SZ_SMALL);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_COMMON, NULL);
addflag(lastot->flags, F_SHIELD, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_GOESON, BP_SECWEAPON, NA, NA, NULL);
addflag(lastot->flags, F_ARMOURRATING, 4, NA, NA, NULL);
addflag(lastot->flags, F_EQUIPCONFER, F_SHIELDPENALTY, 5, NA, NULL);
addflag(lastot->flags, F_OBHP, 20, 20, NA, NULL);
// similar to a buckler, but repairable, lighter, and less durable
addot(OT_SHIELDHIDE, "hide shield", "A small shield constructed out of animal skin.", MT_LEATHER, 2.00, OC_ARMOUR, SZ_SMALL);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_COMMON, NULL);
addflag(lastot->flags, F_SHIELD, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_GOESON, BP_SECWEAPON, NA, NA, NULL);
addflag(lastot->flags, F_ARMOURRATING, 4, NA, NA, NULL);
addflag(lastot->flags, F_EQUIPCONFER, F_SHIELDPENALTY, 5, NA, NULL);
addflag(lastot->flags, F_OBHP, 18, 18, NA, NULL);
addot(OT_SHIELD, "shield", "A medium-sized metal shield.", MT_METAL, 4.00, OC_ARMOUR, SZ_MEDIUM);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_UNCOMMON, NULL);
addflag(lastot->flags, F_SHIELD, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_GOESON, BP_SECWEAPON, NA, NA, NULL);
addflag(lastot->flags, F_ARMOURRATING, 6, NA, NA, NULL);
addflag(lastot->flags, F_EQUIPCONFER, F_SHIELDPENALTY, 15, NA, NULL);
addflag(lastot->flags, F_OBHP, 30, 30, NA, NULL);
addot(OT_SHIELDLARGE, "large shield", "A large (if somewhat cumbersome) shield.", MT_METAL, 6.00, OC_ARMOUR, SZ_MEDIUM);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_UNCOMMON, NULL);
addflag(lastot->flags, F_SHIELD, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_GOESON, BP_SECWEAPON, NA, NA, NULL);
addflag(lastot->flags, F_ARMOURRATING, 8, NA, NA, NULL);
addflag(lastot->flags, F_EQUIPCONFER, F_SHIELDPENALTY, 20, NA, NULL);
addflag(lastot->flags, F_OBHP, 40, 40, NA, NULL);
addot(OT_SHIELDTOWER, "tower shield", "An enormous but very cumbersome shield.", MT_METAL, 11.00, OC_ARMOUR, SZ_HUMAN);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_RARE, NULL);
addflag(lastot->flags, F_SHIELD, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_GOESON, BP_SECWEAPON, NA, NA, NULL);
addflag(lastot->flags, F_ARMOURRATING, 12, NA, NA, NULL);
addflag(lastot->flags, F_EQUIPCONFER, F_SHIELDPENALTY, 30, NA, NULL);
addflag(lastot->flags, F_OBHP, 50, 50, NA, NULL);
// rings
addot(OT_RING_SIGHT, "ring of sight", "Allows the caster to see the invisible, and in the dark.", MT_METAL, 0.1, OC_RING, SZ_MINI);
addflag(lastot->flags, F_RARITY, H_ALL, 75, NA, "");
addflag(lastot->flags, F_EQUIPCONFER, F_SEEINVIS, NA, NA, NULL);
addflag(lastot->flags, F_EQUIPCONFER, F_SEEINDARK, 2, NA, NULL);
addflag(lastot->flags, F_EQUIPCONFER, F_VISRANGEMOD, 1, NA, NULL);
addot(OT_RING_MANA, "ring of mana", "Increases the wearer's MP pool.", MT_METAL, 0.1, OC_RING, SZ_MINI);
addflag(lastot->flags, F_RARITY, H_ALL, 75, NA, "");
addflag(lastot->flags, F_EQUIPCONFER, F_EXTRAMP, 10, NA, NULL);
addot(OT_RING_LUCK, "ring of luck", "Makes the wearer more lucky.", MT_METAL, 0.1, OC_RING, SZ_MINI);
addflag(lastot->flags, F_RARITY, H_ALL, 75, NA, "");
addflag(lastot->flags, F_EQUIPCONFER, F_EXTRALUCK, 5, NA, NULL);
addot(OT_RING_PROTFIRE, "ring of fire immunity", "Grants the caster complete immunity to fire.", MT_METAL, 0.1, OC_RING, SZ_MINI);
addflag(lastot->flags, F_RARITY, H_ALL, 75, NA, "");
addflag(lastot->flags, F_EQUIPCONFER, F_DTIMMUNE, DT_FIRE, NA, NULL);
addot(OT_RING_PROTCOLD, "ring of cold immunity", "Grants the caster complete immunity to cold.", MT_METAL, 0.1, OC_RING, SZ_MINI);
addflag(lastot->flags, F_RARITY, H_ALL, 75, NA, "");
addflag(lastot->flags, F_EQUIPCONFER, F_DTIMMUNE, DT_COLD, NA, NULL);
addot(OT_RING_STR, "ring of strength", "Increases the wearer's strength.", MT_METAL, 0.1, OC_RING, SZ_MINI);
addflag(lastot->flags, F_RARITY, H_ALL, 70, NA, "");
addflag(lastot->flags, F_EQUIPCONFER, F_ATTRMOD, A_STR, 1, NULL); // '1' is randomized during generation
addflag(lastot->flags, F_IDWHENUSED, B_TRUE, NA, NA, NULL);
addot(OT_RING_IQ, "ring of intelligence", "Increases the wearer's intelligence.", MT_METAL, 0.1, OC_RING, SZ_MINI);
addflag(lastot->flags, F_RARITY, H_ALL, 70, NA, "");
addflag(lastot->flags, F_EQUIPCONFER, F_ATTRMOD, A_IQ, 1, NULL); // '1' is randomized during generation
addflag(lastot->flags, F_IDWHENUSED, B_TRUE, NA, NA, NULL);
addot(OT_RING_CON, "ring of fitness", "Increases the wearer's fitness.", MT_METAL, 0.1, OC_RING, SZ_MINI);
addflag(lastot->flags, F_RARITY, H_ALL, 70, NA, "");
addflag(lastot->flags, F_EQUIPCONFER, F_ATTRMOD, A_CON, 1, NULL); // '1' is randomized during generation
addflag(lastot->flags, F_IDWHENUSED, B_TRUE, NA, NA, NULL);
addot(OT_RING_DEX, "ring of dexterity", "Increases the wearer's dexterity.", MT_METAL, 0.1, OC_RING, SZ_MINI);
addflag(lastot->flags, F_RARITY, H_ALL, 70, NA, "");
addflag(lastot->flags, F_EQUIPCONFER, F_ATTRMOD, A_DEX, 1, NULL); // '1' is randomized during generation
addflag(lastot->flags, F_IDWHENUSED, B_TRUE, NA, NA, NULL);
addot(OT_RING_HUNGER, "ring of hunger", "Greatly increases the metabolic rate of the wearer.", MT_METAL, 0.1, OC_RING, SZ_MINI);
addflag(lastot->flags, F_RARITY, H_ALL, 73, NA, "");
addflag(lastot->flags, F_EQUIPCONFER, F_FASTMETAB, 3, NA, NULL);
addflag(lastot->flags, F_STARTBLESSED, B_CURSED, NA, NA, NULL);
addot(OT_RING_WOUNDING, "ring of wounding", "Increases the damage output of the wearer.", MT_METAL, 0.1, OC_RING, SZ_MINI);
addflag(lastot->flags, F_RARITY, H_ALL, 73, NA, "");
addflag(lastot->flags, F_EQUIPCONFER, F_EXTRADAM, NA, NA, "0d0+4");
addflag(lastot->flags, F_ENCHANTABLE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_IDWHENUSED, B_TRUE, NA, NA, NULL);
addot(OT_RING_INVIS, "ring of invisibility", "Renders the wearer invisible.", MT_METAL, 0.1, OC_RING, SZ_MINI);
addflag(lastot->flags, F_RARITY, H_ALL, 60, NA, "");
addflag(lastot->flags, F_EQUIPCONFER, F_INVISIBLE, NA, NA, NULL);
addot(OT_RING_INVULN, "ring of invulnerability", "Grants the caster complete immunity to physical harm.", MT_METAL, 0.1, OC_RING, SZ_MINI);
addflag(lastot->flags, F_EQUIPCONFER, F_INVULNERABLE, NA, NA, NULL);
addot(OT_RING_MPREGEN, "ring of recharging", "Slowly regenerates the wearer's mana.", MT_METAL, 0.1, OC_RING, SZ_MINI);
addflag(lastot->flags, F_RARITY, H_ALL, 50, NA, "");
addflag(lastot->flags, F_EQUIPCONFER, F_MPREGEN, 1, NA, NULL);
addot(OT_RING_CONTROL, "ring of control", "Allows the wearer control over teleportation and polymorphic effects.", MT_METAL, 0.1, OC_RING, SZ_MINI);
addflag(lastot->flags, F_RARITY, H_ALL, 50, NA, "");
addflag(lastot->flags, F_EQUIPCONFER, F_CONTROL, NA, NA, NULL);
addot(OT_RING_REGENERATION, "ring of regeneration", "Slowly regenerates the wearer's health, even when not resting.", MT_METAL, 0.1, OC_RING, SZ_MINI);
addflag(lastot->flags, F_RARITY, H_ALL, 50, NA, "");
addflag(lastot->flags, F_EQUIPCONFER, F_REGENERATES, 1, NA, NULL);
addot(OT_RING_RESISTMAG, "ring of magic resistance", "Renders the wearer immune to most magical effects.", MT_METAL, 0.1, OC_RING, SZ_MINI);
addflag(lastot->flags, F_RARITY, H_ALL, 50, NA, "");
addflag(lastot->flags, F_EQUIPCONFER, F_RESISTMAG, 5, NA, NULL);
addot(OT_RING_MIRACLES, "ring of miracles", "Grants a limited number of miracles to the wearer.", MT_METAL, 0.1, OC_RING, SZ_MINI);
addflag(lastot->flags, F_RARITY, H_ALL, 40, NA, "");
addflag(lastot->flags, F_CHARGES, 1, 3, NA, NULL);
// unarmed weapons - note these damage/accuracys can be
// overridded with the lifeform flag F_HASATTACK
//
// DAMTYPE _cannot_ be overridden (yet)!
addot(OT_FISTS, "fists", "human fists", MT_FLESH, 0, OC_WEAPON, SZ_TINY);
addflag(lastot->flags, F_DAM, DT_UNARMED, NA, NA, "1d2");
addflag(lastot->flags, F_ACCURACY, 100, NA, NA, NULL);
addflag(lastot->flags, F_USESSKILL, SK_UNARMED, NA, NA, NULL);
addflag(lastot->flags, F_UNARMEDWEP, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_CRITCHANCE, 1, NA, NA, NULL);
// this one is for the pirate
addot(OT_HOOKHAND, "hook", "hook", MT_METAL, 0, OC_WEAPON, SZ_TINY);
addflag(lastot->flags, F_DAM, DT_PIERCE, NA, NA, "1d4");
addflag(lastot->flags, F_ACCURACY, 100, NA, NA, NULL);
addflag(lastot->flags, F_USESSKILL, SK_UNARMED, NA, NA, NULL);
addflag(lastot->flags, F_UNARMEDWEP, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_ATTACKVERB, NA, 5, NA, "scratch");
addflag(lastot->flags, F_ATTACKVERB, 6, 15, NA, "scrape");
addflag(lastot->flags, F_ATTACKVERB, 16, NA, NA, "rake");
addot(OT_TEETH, "teeth", "teeth object", MT_BONE, 0, OC_WEAPON, SZ_TINY);
addflag(lastot->flags, F_DAM, DT_BITE, NA, NA, "1d2");
addflag(lastot->flags, F_ACCURACY, 100, NA, NA, NULL);
addflag(lastot->flags, F_STACKABLE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_NOSTRDAMMOD, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_USESSKILL, SK_NONE, NA, NA, NULL);
addflag(lastot->flags, F_UNARMEDWEP, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_CRITCHANCE, 3, NA, NA, NULL);
addot(OT_CLAWS, "claws", "claws object", MT_BONE, 0, OC_WEAPON, SZ_TINY);
addflag(lastot->flags, F_DAM, DT_SLASH, NA, NA, "1d2");
addflag(lastot->flags, F_ATTACKVERB, NA, 5, NA, "scratch");
addflag(lastot->flags, F_ATTACKVERB, 6, 15, NA, "claw");
addflag(lastot->flags, F_ATTACKVERB, 16, 30, NA, "tear");
addflag(lastot->flags, F_ATTACKVERB, 31, 40, NA, "rake");
addflag(lastot->flags, F_ATTACKVERB, 41, 50, NA, "gouge");
addflag(lastot->flags, F_ATTACKVERB, 51, NA, NA, "eviscerate");
addflag(lastot->flags, F_KILLVERB, 70, NA, NA, "disembowel");
addflag(lastot->flags, F_ACCURACY, 100, NA, NA, NULL);
addflag(lastot->flags, F_USESSKILL, SK_NONE, NA, NA, NULL);
addflag(lastot->flags, F_UNARMEDWEP, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_CRITCHANCE, 5, NA, NA, NULL);
addot(OT_HOOF, "hooves", "hoof object", MT_BONE, 0, OC_WEAPON, SZ_TINY);
addflag(lastot->flags, F_DAM, DT_BASH, NA, NA, "1d2");
addflag(lastot->flags, F_ATTACKVERB, NA, NA, NA, "kick");
addflag(lastot->flags, F_ACCURACY, 100, NA, NA, NULL);
addflag(lastot->flags, F_USESSKILL, SK_NONE, NA, NA, NULL);
addflag(lastot->flags, F_UNARMEDWEP, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_CRITCHANCE, 5, NA, NA, NULL);
addot(OT_BUTT, "headbutt", "headbutt object", MT_BONE, 0, OC_WEAPON, SZ_TINY);
addflag(lastot->flags, F_DAM, DT_BASH, NA, NA, "1d2");
addflag(lastot->flags, F_ATTACKVERB, NA, NA, NA, "butt");
addflag(lastot->flags, F_ACCURACY, 100, NA, NA, NULL);
addflag(lastot->flags, F_USESSKILL, SK_NONE, NA, NA, NULL);
addflag(lastot->flags, F_UNARMEDWEP, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_CRITCHANCE, 5, NA, NA, NULL);
addot(OT_STING, "sting", "sting object", MT_BONE, 0, OC_WEAPON, SZ_TINY);
addflag(lastot->flags, F_ATTACKVERB, NA, NA, NA, "sting");
addflag(lastot->flags, F_DAM, DT_ACID, NA, NA, "1d2");
addflag(lastot->flags, F_ACCURACY, 100, NA, NA, NULL);
addflag(lastot->flags, F_NOSTRDAMMOD, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_USESSKILL, SK_NONE, NA, NA, NULL);
addflag(lastot->flags, F_UNARMEDWEP, B_TRUE, NA, NA, NULL);
addot(OT_TAIL, "tail", "tail object", MT_FLESH, 0, OC_WEAPON, SZ_TINY);
addflag(lastot->flags, F_ATTACKVERB, NA, NA, NA, "tailslap");
addflag(lastot->flags, F_DAM, DT_BASH, NA, NA, "1d4");
addflag(lastot->flags, F_ACCURACY, 80, NA, NA, NULL);
addflag(lastot->flags, F_USESSKILL, SK_NONE, NA, NA, NULL);
addflag(lastot->flags, F_UNARMEDWEP, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_CRITCHANCE, 5, NA, NA, NULL);
addot(OT_TENTACLE, "tentacle", "tentacle object", MT_FLESH, 0, OC_WEAPON, SZ_TINY);
addflag(lastot->flags, F_DAM, DT_BASH, NA, NA, "2d6");
addflag(lastot->flags, F_ACCURACY, 100, NA, NA, NULL);
addflag(lastot->flags, F_USESSKILL, SK_NONE, NA, NA, NULL);
addflag(lastot->flags, F_UNARMEDWEP, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_CRITCHANCE, 5, NA, NA, NULL);
addot(OT_ZAPPER, "zapper", "zapper object", MT_NOTHING, 0, OC_WEAPON, SZ_TINY);
addflag(lastot->flags, F_DAM, DT_ELECTRIC, NA, NA, "1d2");
addflag(lastot->flags, F_ACCURACY, 100, NA, NA, NULL);
addflag(lastot->flags, F_NOSTRDAMMOD, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_USESSKILL, SK_NONE, NA, NA, NULL);
addflag(lastot->flags, F_UNARMEDWEP, B_TRUE, NA, NA, NULL);
// monster weapons
addot(OT_ACIDATTACK, "acidattack", "acid attack object", MT_WATER, 0, OC_WEAPON, SZ_TINY);
addflag(lastot->flags, F_DAM, DT_ACID, NA, NA, "1d2");
addflag(lastot->flags, F_ACCURACY, 60, NA, NA, NULL);
addflag(lastot->flags, F_NOSTRDAMMOD, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_USESSKILL, SK_NONE, NA, NA, NULL);
addflag(lastot->flags, F_UNARMEDWEP, B_TRUE, NA, NA, NULL);
addot(OT_TOUCHPARALYZE, "paralyzing touch", "paralyzing touch object", MT_BONE, 0, OC_WEAPON, SZ_TINY);
addflag(lastot->flags, F_ARMOURPIERCE, B_TRUE, NA, NA, "");
addflag(lastot->flags, F_DAM, DT_TOUCH, NA, NA, "1d1");
addflag(lastot->flags, F_ACCURACY, 100, NA, NA, NULL);
addflag(lastot->flags, F_HITCONFER, F_PARALYZED, SC_CON, 22, "2-4");
addflag(lastot->flags, F_HITCONFERVALS, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_NOSTRDAMMOD, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_USESSKILL, SK_NONE, NA, NA, NULL);
addflag(lastot->flags, F_UNARMEDWEP, B_TRUE, NA, NA, NULL);
addot(OT_TOUCHPARALYZE2, "strong paralyzing touch", "strong paralyzing touch object", MT_BONE, 0, OC_WEAPON, SZ_TINY);
addflag(lastot->flags, F_ARMOURPIERCE, B_TRUE, NA, NA, "");
addflag(lastot->flags, F_DAM, DT_TOUCH, NA, NA, "1d1");
addflag(lastot->flags, F_ACCURACY, 100, NA, NA, NULL);
addflag(lastot->flags, F_HITCONFER, F_PARALYZED, SC_CON, 30, "5-10");
addflag(lastot->flags, F_HITCONFERVALS, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_NOSTRDAMMOD, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_USESSKILL, SK_NONE, NA, NA, NULL);
addflag(lastot->flags, F_UNARMEDWEP, B_TRUE, NA, NA, NULL);
// missiles
addot(OT_DART, "dart", "A small, sharp projectile weapon.", MT_WOOD, 0.5, OC_MISSILE, SZ_SMALL);
addflag(lastot->flags, F_STACKABLE, B_TRUE, NA, NA, "");
addflag(lastot->flags, F_THROWMISSILE, B_TRUE, NA, NA, "");
addflag(lastot->flags, F_MISSILEDAM, 2, NA, NA, "");
addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, NA, "");
addflag(lastot->flags, F_NUMAPPEAR, 1, 3, NA, "");
addflag(lastot->flags, F_CANHAVEOBMOD, OM_POISONED, 17, NA, NULL);
addflag(lastot->flags, F_RODSHAPED, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_CANBEDIFFMAT, MT_SILVER, 15, NA, NULL);
addot(OT_NANODART, "nanodart", "A metal dart with a laser-sharpened point.", MT_METAL, 0.5, OC_MISSILE, SZ_TINY);
addflag(lastot->flags, F_STACKABLE, B_TRUE, NA, NA, "");
addflag(lastot->flags, F_THROWMISSILE, B_TRUE, NA, NA, "");
addflag(lastot->flags, F_MISSILEDAM, 2, NA, NA, "");
addflag(lastot->flags, F_ARMOURPIERCE, B_TRUE, NA, NA, "");
addflag(lastot->flags, F_RARITY, H_DUNGEON, 67, NA, "");
addflag(lastot->flags, F_NUMAPPEAR, 1, 10, NA, "");
addflag(lastot->flags, F_CANHAVEOBMOD, OM_POISONED, 17, NA, NULL);
addot(OT_NEEDLE, "needle", "A tiny pointed needle.", MT_METAL, 0.02, OC_MISSILE, SZ_TINY);
addflag(lastot->flags, F_STACKABLE, B_TRUE, NA, NA, "");
addflag(lastot->flags, F_THROWMISSILE, B_TRUE, NA, NA, "");
addflag(lastot->flags, F_MISSILEDAM, 1, NA, NA, "");
addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, NA, "");
addflag(lastot->flags, F_NUMAPPEAR, 1, 3, NA, "");
addflag(lastot->flags, F_CANHAVEOBMOD, OM_POISONED, 25, NA, NULL);
addflag(lastot->flags, F_RODSHAPED, B_TRUE, NA, NA, NULL);
addot(OT_JAVELIN, "javelin", "A long, sharp missile weapon.", MT_METAL, 6, OC_MISSILE, SZ_MEDIUM);
addflag(lastot->flags, F_STACKABLE, B_TRUE, NA, NA, "");
addflag(lastot->flags, F_THROWMISSILE, B_TRUE, NA, NA, "");
addflag(lastot->flags, F_MISSILEDAM, 3, NA, NA, "");
addflag(lastot->flags, F_RARITY, H_DUNGEON, 90, NA, "");
addflag(lastot->flags, F_NUMAPPEAR, 1, 2, NA, "");
addflag(lastot->flags, F_OBHP, 3, 3, NA, "");
addflag(lastot->flags, F_CANHAVEOBMOD, OM_POISONED, 17, NA, NULL);
addot(OT_ARROW, "arrow", "A sharp wooden arrow.", MT_WOOD, 0.25, OC_MISSILE, SZ_SMALL);
addflag(lastot->flags, F_STACKABLE, B_TRUE, NA, NA, "");
addflag(lastot->flags, F_RARITY, H_DUNGEON, 85, NA, "");
addflag(lastot->flags, F_NUMAPPEAR, 1, 10, NA, "");
addflag(lastot->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_OBHP, 2, 2, NA, NULL);
addflag(lastot->flags, F_NOOBDIETEXT, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_CANHAVEOBMOD, OM_POISONED, 17, NA, NULL);
addflag(lastot->flags, F_RODSHAPED, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_CANBEDIFFMAT, MT_SILVER, 15, NA, NULL);
addot(OT_BOLT, "bolt", "A sharp metal spike, meant for firing from a crossbow.", MT_METAL, 0.5, OC_MISSILE, SZ_SMALL);
addflag(lastot->flags, F_STACKABLE, B_TRUE, NA, NA, "");
addflag(lastot->flags, F_RARITY, H_DUNGEON, 80, NA, "");
addflag(lastot->flags, F_NUMAPPEAR, 1, 10, NA, "");
addflag(lastot->flags, F_NOOBDIETEXT, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_CANHAVEOBMOD, OM_POISONED, 17, NA, NULL);
addflag(lastot->flags, F_CANBEDIFFMAT, MT_SILVER, 20, NA, NULL);
addot(OT_BULLET, "bullet", "A regular gun bullet.", MT_METAL, 0.1, OC_MISSILE, SZ_MINI);
addflag(lastot->flags, F_STACKABLE, B_TRUE, NA, NA, "");
addflag(lastot->flags, F_RARITY, H_DUNGEON, 70, NA, "");
addflag(lastot->flags, F_NUMAPPEAR, 1, 10, NA, "");
addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_OBHP, 1, 1, NA, NULL);
addflag(lastot->flags, F_NOOBDIETEXT, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_CANBEDIFFMAT, MT_SILVER, 10, NA, NULL);
addot(OT_RUBBERBULLET, "rubber bullet", "A rubber gun bullet - does not do much damage.", MT_RUBBER, 0.05, OC_MISSILE, SZ_MINI);
addflag(lastot->flags, F_STACKABLE, B_TRUE, NA, NA, "");
addflag(lastot->flags, F_RARITY, H_DUNGEON, 80, NA, "");
addflag(lastot->flags, F_NUMAPPEAR, 1, 10, NA, "");
addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_OBHP, 1, 1, NA, NULL);
addflag(lastot->flags, F_NOOBDIETEXT, B_TRUE, NA, NA, NULL);
// axes
addot(OT_AXE, "axe", "A short pole with a heavy, wedge-shaped blade for chopping.", MT_METAL, 5, OC_WEAPON, SZ_MEDIUM);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 90, NA, NULL);
addflag(lastot->flags, F_DAM, DT_CHOP, NA, NA, "1d6");
addflag(lastot->flags, F_ACCURACY, 80, NA, NA, NULL);
addflag(lastot->flags, F_USESSKILL, SK_AXES, NA, NA, NULL);
addflag(lastot->flags, F_ATTREQ, A_STR, 9, NA, NULL);
addflag(lastot->flags, F_CRITCHANCE, 5, NA, NA, NULL);
addot(OT_BATTLEAXE, "battleaxe", "An large axe specifically designed for combat.", MT_METAL, 8, OC_WEAPON, SZ_MEDIUM);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 70, NA, NULL);
addflag(lastot->flags, F_DAM, DT_CHOP, NA, NA, "1d8+1");
addflag(lastot->flags, F_TWOHANDED, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_ACCURACY, 80, NA, NA, NULL);
addflag(lastot->flags, F_USESSKILL, SK_AXES, NA, NA, NULL);
addflag(lastot->flags, F_ATTREQ, A_STR, 13, NA, NULL);
addot(OT_GREATAXE, "greataxe", "An enormous axe made designed for combat.", MT_METAL, 10, OC_WEAPON, SZ_MEDIUM);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 50, NA, NULL);
addflag(lastot->flags, F_OBATTACKDELAY, 150, NA, NA, NULL);
addflag(lastot->flags, F_DAM, DT_CHOP, NA, NA, "1d9+1");
addflag(lastot->flags, F_TWOHANDED, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_ACCURACY, 70, NA, NA, NULL);
addflag(lastot->flags, F_USESSKILL, SK_AXES, NA, NA, NULL);
addflag(lastot->flags, F_ATTREQ, A_STR, 16, NA, NULL);
addot(OT_HANDAXE, "hand axe", "A fast one-handed axe, ideal for throwing.", MT_METAL, 2.5, OC_WEAPON, SZ_SMALL);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 80, NA, NULL);
addflag(lastot->flags, F_DAM, DT_CHOP, NA, NA, "1d7");
addflag(lastot->flags, F_ACCURACY, 85, NA, NA, NULL);
addflag(lastot->flags, F_THROWMISSILE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_USESSKILL, SK_AXES, NA, NA, NULL);
addflag(lastot->flags, F_ATTREQ, A_STR, 7, NA, NULL);
addflag(lastot->flags, F_CRITCHANCE, 5, NA, NA, NULL);
addot(OT_WARAXE, "war axe", "An axe made for combat.", MT_METAL, 7, OC_WEAPON, SZ_MEDIUM);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 80, NA, NULL);
addflag(lastot->flags, F_DAM, DT_CHOP, NA, NA, "1d7+1");
addflag(lastot->flags, F_ACCURACY, 85, NA, NA, NULL);
addflag(lastot->flags, F_USESSKILL, SK_AXES, NA, NA, NULL);
addflag(lastot->flags, F_ATTREQ, A_STR, 11, NA, NULL);
// short blades
addot(OT_COMBATKNIFE, "combat knife", "A sharp knife designed for military use.", MT_METAL, 1, OC_WEAPON, SZ_SMALL);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 65, NA, NULL);
addflag(lastot->flags, F_DAM, DT_PIERCE, NA, NA, "1d4+1");
addflag(lastot->flags, F_ACCURACY, 100, NA, NA, NULL);
addflag(lastot->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_OBHP, 5, 5, NA, NULL);
addflag(lastot->flags, F_THROWMISSILE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_PICKLOCKS, 7, B_BLUNTONFAIL, NA, NULL);
addflag(lastot->flags, F_USESSKILL, SK_SHORTBLADES, NA, NA, NULL);
addflag(lastot->flags, F_CRITCHANCE, 2, NA, NA, NULL);
addot(OT_DAGGER, "dagger", "A short stabbing weapon with a pointed blade.", MT_METAL, 1, OC_WEAPON, SZ_SMALL);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 90, NA, NULL);
addflag(lastot->flags, F_DAM, DT_PIERCE, NA, NA, "1d4");
addflag(lastot->flags, F_ACCURACY, 100, NA, NA, NULL);
addflag(lastot->flags, F_THROWMISSILE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_OBHP, 2, 2, NA, NULL);
addflag(lastot->flags, F_PICKLOCKS, 7, B_BLUNTONFAIL, NA, NULL);
addflag(lastot->flags, F_USESSKILL, SK_SHORTBLADES, NA, NA, NULL);
addflag(lastot->flags, F_CRITCHANCE, 2, NA, NA, NULL);
addflag(lastot->flags, F_CANBEDIFFMAT, MT_SILVER, 10, NA, NULL);
addot(OT_KNIFE, "knife", "A moderately sharp stabbing tool.", MT_METAL, 0.5, OC_WEAPON, SZ_SMALL);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, NA, NULL);
addflag(lastot->flags, F_DAM, DT_SLASH, NA, NA, "1d3");
addflag(lastot->flags, F_ACCURACY, 100, NA, NA, NULL);
addflag(lastot->flags, F_THROWMISSILE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_PICKLOCKS, 7, B_BLUNTONFAIL, NA, NULL);
addflag(lastot->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_OBHP, 5, 5, NA, NULL);
addflag(lastot->flags, F_USESSKILL, SK_SHORTBLADES, NA, NA, NULL);
addot(OT_ORNDAGGER, "ornamental dagger", "This dagger is pretty, but not particularly effective.", MT_METAL, 1, OC_WEAPON, SZ_SMALL);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 50, NA, NULL);
addflag(lastot->flags, F_SHINY, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_DAM, DT_PIERCE, NA, NA, "1d3");
addflag(lastot->flags, F_ACCURACY, 100, NA, NA, NULL);
addflag(lastot->flags, F_THROWMISSILE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_PICKLOCKS, 7, B_BLUNTONFAIL, NA, NULL);
addflag(lastot->flags, F_USESSKILL, SK_SHORTBLADES, NA, NA, NULL);
addot(OT_QUICKBLADE, "quickblade", "A short blade of exceptional quality, which somehow allows its bearer to attack faster.", MT_METAL, 3.0, OC_WEAPON, SZ_MEDIUM);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 73, NA, NULL);
addflag(lastot->flags, F_OBATTACKDELAY, 75, NA, NA, NULL);
addflag(lastot->flags, F_DAM, DT_PIERCE, NA, NA, "1d4");
addflag(lastot->flags, F_ACCURACY, 100, NA, NA, NULL);
addflag(lastot->flags, F_USESSKILL, SK_SHORTBLADES, NA, NA, NULL);
addflag(lastot->flags, F_CRITCHANCE, 2, NA, NA, NULL);
addot(OT_RAPIER, "rapier", "A long, narrow French sword lacking a cutting edge. Made for stabbing.", MT_METAL, 3.5, OC_WEAPON, SZ_MEDIUM);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 80, NA, NULL);
addflag(lastot->flags, F_DAM, DT_PIERCE, NA, NA, "1d8");
addflag(lastot->flags, F_ACCURACY, 90, NA, NA, NULL);
addflag(lastot->flags, F_USESSKILL, SK_SHORTBLADES, NA, NA, NULL);
addflag(lastot->flags, F_ATTREQ, A_STR, 6, NA, NULL);
addflag(lastot->flags, F_CRITCHANCE, 3, NA, NA, NULL);
addot(OT_SAI, "sai", "A dagger with two long prongs on either side, made to trap opponents' weapons.", MT_METAL, 1.5, OC_WEAPON, SZ_SMALL);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 81, NA, NULL);
addflag(lastot->flags, F_DAM, DT_PIERCE, NA, NA, "1d4");
addflag(lastot->flags, F_DISARMATTACK, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_ACCURACY, 100, NA, NA, NULL);
addflag(lastot->flags, F_USESSKILL, SK_SHORTBLADES, NA, NA, NULL);
addflag(lastot->flags, F_ATTREQ, A_DEX, 10, NA, NULL);
addot(OT_SHORTSWORD, "short sword", "A short blade for fighting. Better for stabbing.", MT_METAL, 4, OC_WEAPON, SZ_MEDIUM);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 90, NA, NULL);
addflag(lastot->flags, F_DAM, DT_PIERCE, NA, NA, "1d6");
addflag(lastot->flags, F_ACCURACY, 90, NA, NA, NULL);
addflag(lastot->flags, F_USESSKILL, SK_SHORTBLADES, NA, NA, NULL);
addflag(lastot->flags, F_ATTREQ, A_STR, 6, NA, NULL);
addflag(lastot->flags, F_CRITCHANCE, 5, NA, NA, NULL);
addflag(lastot->flags, F_CANBEDIFFMAT, MT_SILVER, 5, NA, NULL);
addot(OT_SICKLE, "sickle", "A hand-held agricultural tool with a curved blade.", MT_METAL, 1, OC_WEAPON, SZ_SMALL);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 60, NA, NULL);
addflag(lastot->flags, F_DAM, DT_SLASH, NA, NA, "1d6");
addflag(lastot->flags, F_ACCURACY, 60, NA, NA, NULL);
addflag(lastot->flags, F_USESSKILL, SK_SHORTBLADES, NA, NA, NULL);
addflag(lastot->flags, F_CRITCHANCE, 2, NA, NA, NULL);
addot(OT_STEAKKNIFE, "steak knife", "A common kitchen knife.", MT_METAL, 0.2, OC_WEAPON, SZ_SMALL);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, NA, NULL);
addflag(lastot->flags, F_DAM, DT_SLASH, NA, NA, "1d2");
addflag(lastot->flags, F_ACCURACY, 100, NA, NA, NULL);
addflag(lastot->flags, F_THROWMISSILE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_OBHP, 5, 5, NA, NULL);
addflag(lastot->flags, F_USESSKILL, SK_SHORTBLADES, NA, NA, NULL);
// long blades
addot(OT_FALCHION, "falchion", "A single-edged heavy sword made for chopping.", MT_METAL, 6.5, OC_WEAPON, SZ_MEDIUM);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 61, NA, NULL);
addflag(lastot->flags, F_DAM, DT_CHOP, NA, NA, "1d8+3");
addflag(lastot->flags, F_ACCURACY, 80, NA, NA, NULL);
addflag(lastot->flags, F_USESSKILL, SK_LONGBLADES, NA, NA, NULL);
addflag(lastot->flags, F_ATTREQ, A_STR, 13, NA, NULL);
addflag(lastot->flags, F_CRITCHANCE, 5, NA, NA, NULL);
addot(OT_GREATSWORD, "greatsword", "A massive two-handed sword.", MT_METAL, 10, OC_WEAPON, SZ_MEDIUM);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 55, NA, NULL);
addflag(lastot->flags, F_OBATTACKDELAY, 150, NA, NA, NULL);
addflag(lastot->flags, F_DAM, DT_SLASH, NA, NA, "1d12+6");
addflag(lastot->flags, F_ACCURACY, 80, NA, NA, NULL);
addflag(lastot->flags, F_TWOHANDED, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_USESSKILL, SK_LONGBLADES, NA, NA, NULL);
addflag(lastot->flags, F_ATTREQ, A_STR, 13, NA, NULL);
addflag(lastot->flags, F_CRITCHANCE, 7, NA, NA, NULL);
addot(OT_LONGSWORD, "longsword", "Standard issue long slashing weapon.", MT_METAL, 5, OC_WEAPON, SZ_MEDIUM);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 70, NA, NULL);
addflag(lastot->flags, F_DAM, DT_SLASH, NA, NA, "1d8");
addflag(lastot->flags, F_ACCURACY, 80, NA, NA, NULL);
addflag(lastot->flags, F_USESSKILL, SK_LONGBLADES, NA, NA, NULL);
addflag(lastot->flags, F_ATTREQ, A_STR, 10, NA, NULL);
addflag(lastot->flags, F_CRITCHANCE, 5, NA, NA, NULL);
addflag(lastot->flags, F_CANBEDIFFMAT, MT_SILVER, 5, NA, NULL);
addot(OT_ORNSWORD, "ornamental sword", "A gleaming (but quite blunt) blade.", MT_METAL, 6, OC_WEAPON, SZ_MEDIUM);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 50, NA, NULL);
addflag(lastot->flags, F_SHINY, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_DAM, DT_SLASH, NA, NA, "1d6");
addflag(lastot->flags, F_ACCURACY, 70, NA, NA, NULL);
addflag(lastot->flags, F_USESSKILL, SK_LONGBLADES, NA, NA, NULL);
addot(OT_SCIMITAR, "scimitar", "A fast, sharp, curved blade.", MT_METAL, 5, OC_WEAPON, SZ_MEDIUM);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 75, NA, NULL);
addflag(lastot->flags, F_OBATTACKDELAY, 90, NA, NA, NULL);
addflag(lastot->flags, F_DAM, DT_SLASH, NA, NA, "1d7");
addflag(lastot->flags, F_ACCURACY, 80, NA, NA, NULL);
addflag(lastot->flags, F_USESSKILL, SK_LONGBLADES, NA, NA, NULL);
addflag(lastot->flags, F_ATTREQ, A_STR, 8, NA, NULL);
addflag(lastot->flags, F_CRITCHANCE, 7, NA, NA, NULL);
addot(OT_CUTLASS, "cutlass", "An accurate, light-weight pirate blade.", MT_METAL, 4, OC_WEAPON, SZ_MEDIUM);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 80, NA, NULL);
addflag(lastot->flags, F_DAM, DT_SLASH, NA, NA, "1d7");
addflag(lastot->flags, F_ACCURACY, 90, NA, NA, NULL);
addflag(lastot->flags, F_USESSKILL, SK_LONGBLADES, NA, NA, NULL);
addflag(lastot->flags, F_ATTREQ, A_STR, 8, NA, NULL);
addflag(lastot->flags, F_CRITCHANCE, 5, NA, NA, NULL);
// polearms
addot(OT_GLAIVE, "glaive", "A single-edged blade attached to a long pole.", MT_METAL, 10, OC_WEAPON, SZ_HUMAN);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 73, NA, NULL);
addflag(lastot->flags, F_OBATTACKDELAY, 150, NA, NA, NULL);
addflag(lastot->flags, F_DAM, DT_SLASH, NA, NA, "1d7+3");
addflag(lastot->flags, F_ACCURACY, 80, NA, NA, NULL);
addflag(lastot->flags, F_TWOHANDED, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_USESSKILL, SK_POLEARMS, NA, NA, NULL);
addflag(lastot->flags, F_ATTREQ, A_STR, 13, NA, NULL);
addflag(lastot->flags, F_CRITCHANCE, 1, NA, NA, NULL);
addot(OT_GUISARME, "guisarme", "A hooked polearm, made by attaching a hook to a spear shaft.", MT_METAL, 10, OC_WEAPON, SZ_HUMAN);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 67, NA, NULL);
addflag(lastot->flags, F_TRIPATTACK, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_TWOHANDED, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_OBATTACKDELAY, 130, NA, NA, NULL);
addflag(lastot->flags, F_DAM, DT_SLASH, NA, NA, "2d4");
addflag(lastot->flags, F_ACCURACY, 70, NA, NA, NULL);
addflag(lastot->flags, F_USESSKILL, SK_POLEARMS, NA, NA, NULL);
addflag(lastot->flags, F_ATTREQ, A_STR, 13, NA, NULL);
addflag(lastot->flags, F_ATTREQ, A_DEX, 7, NA, NULL);
addflag(lastot->flags, F_CRITCHANCE, 1, NA, NA, NULL);
addot(OT_HALBERD, "halberd", "A spiked axe blade mounted on a long shaft, with a hook on the back.", MT_METAL, 12, OC_WEAPON, SZ_HUMAN);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 71, NA, NULL);
addflag(lastot->flags, F_OBATTACKDELAY, 130, NA, NA, NULL);
addflag(lastot->flags, F_TRIPATTACK, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_DAM, DT_CHOP, NA, NA, "1d9+2");
addflag(lastot->flags, F_ACCURACY, 80, NA, NA, NULL);
addflag(lastot->flags, F_TWOHANDED, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_USESSKILL, SK_POLEARMS, NA, NA, NULL);
addflag(lastot->flags, F_ATTREQ, A_STR, 13, NA, NULL);
addflag(lastot->flags, F_ATTREQ, A_DEX, 9, NA, NULL);
addflag(lastot->flags, F_CRITCHANCE, 2, NA, NA, NULL);
addot(OT_LANCE, "lance", "A pole weapon designed for use while mounted.", MT_METAL, 12, OC_WEAPON, SZ_HUMAN);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 67, NA, NULL);
addflag(lastot->flags, F_TWOHANDED, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_OBATTACKDELAY, 140, NA, NA, NULL);
addflag(lastot->flags, F_DAM, DT_PIERCE, NA, NA, "1d8+2");
addflag(lastot->flags, F_ACCURACY, 70, NA, NA, NULL);
addflag(lastot->flags, F_USESSKILL, SK_POLEARMS, NA, NA, NULL);
addflag(lastot->flags, F_ATTREQ, A_STR, 13, NA, NULL);
addflag(lastot->flags, F_CRITCHANCE, 1, NA, NA, NULL);
addot(OT_RANSEUR, "ranseur", "A long spear and cross hilt, resembling a pole-mounted sai. Good for disarming.", MT_METAL, 12, OC_WEAPON, SZ_HUMAN);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 67, NA, NULL);
addflag(lastot->flags, F_DISARMATTACK, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_TWOHANDED, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_OBATTACKDELAY, 120, NA, NA, NULL);
addflag(lastot->flags, F_DAM, DT_PIERCE, NA, NA, "2d4");
addflag(lastot->flags, F_ACCURACY, 70, NA, NA, NULL);
addflag(lastot->flags, F_USESSKILL, SK_POLEARMS, NA, NA, NULL);
addflag(lastot->flags, F_ATTREQ, A_STR, 13, NA, NULL);
addflag(lastot->flags, F_ATTREQ, A_DEX, 9, NA, NULL);
addot(OT_SCYTHE, "scythe", "An agricultural hand tool for mowing grass, or reaping crops.", MT_METAL, 6, OC_WEAPON, SZ_HUMAN);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 75, NA, NULL);
addflag(lastot->flags, F_OBATTACKDELAY, 150, NA, NA, NULL);
addflag(lastot->flags, F_DAM, DT_SLASH, NA, NA, "2d4");
addflag(lastot->flags, F_ACCURACY, 65, NA, NA, NULL);
addflag(lastot->flags, F_USESSKILL, SK_POLEARMS, NA, NA, NULL);
addflag(lastot->flags, F_ATTREQ, A_STR, 9, NA, NULL);
addot(OT_SPEAR, "spear", "A long pole with a sharpened head.", MT_METAL, 9, OC_WEAPON, SZ_HUMAN);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 75, NA, NULL);
addflag(lastot->flags, F_TWOHANDED, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_OBATTACKDELAY, 140, NA, NA, NULL);
addflag(lastot->flags, F_DAM, DT_PIERCE, NA, NA, "1d8");
addflag(lastot->flags, F_ACCURACY, 75, NA, NA, NULL);
addflag(lastot->flags, F_THROWMISSILE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_OBHP, 15, 15, NA, NULL);
addflag(lastot->flags, F_USESSKILL, SK_POLEARMS, NA, NA, NULL);
addflag(lastot->flags, F_ATTREQ, A_STR, 7, NA, NULL);
addflag(lastot->flags, F_CRITCHANCE, 1, NA, NA, NULL);
addot(OT_TRIDENT, "trident", "A three-pronged stabbing weapon.", MT_METAL, 5, OC_WEAPON, SZ_HUMAN);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 75, NA, NULL);
addflag(lastot->flags, F_DAM, DT_PIERCE, NA, NA, "1d10");
addflag(lastot->flags, F_ACCURACY, 80, NA, NA, NULL);
addflag(lastot->flags, F_USESSKILL, SK_POLEARMS, NA, NA, NULL);
addflag(lastot->flags, F_ATTREQ, A_STR, 7, NA, NULL);
addflag(lastot->flags, F_CRITCHANCE, 5, NA, NA, NULL);
// staves
addot(OT_QUARTERSTAFF, "quarterstaff", "A long, stout pole.", MT_WOOD, 4, OC_WEAPON, SZ_HUMAN);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, NA, NULL);
addflag(lastot->flags, F_DAM, DT_BASH, NA, NA, "1d8");
addflag(lastot->flags, F_OBATTACKDELAY, 110, NA, NA, NULL);
addflag(lastot->flags, F_ACCURACY, 80, NA, NA, NULL);
addflag(lastot->flags, F_TWOHANDED, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_USESSKILL, SK_STAVES, NA, NA, NULL);
addflag(lastot->flags, F_ATTREQ, A_STR, 7, NA, NULL);
addflag(lastot->flags, F_RODSHAPED, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_CRITCHANCE, 5, NA, NA, NULL);
addot(OT_BAMBOOSTAFF, "bamboo staff", "A long hard pole made from bamboo.", MT_WOOD, 3, OC_WEAPON, SZ_HUMAN);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 85, NA, NULL);
addflag(lastot->flags, F_DAM, DT_BASH, NA, NA, "2d4");
addflag(lastot->flags, F_ACCURACY, 80, NA, NA, NULL);
addflag(lastot->flags, F_TWOHANDED, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_USESSKILL, SK_STAVES, NA, NA, NULL);
addflag(lastot->flags, F_ATTREQ, A_STR, 6, NA, NULL);
addflag(lastot->flags, F_RODSHAPED, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_CRITCHANCE, 5, NA, NA, NULL);
addot(OT_BLADEDSTAFF, "bladed staff", "A long wooden pole with blades on either end.", MT_WOOD, 5, OC_WEAPON, SZ_HUMAN);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 85, NA, NULL);
addflag(lastot->flags, F_OBATTACKDELAY, 110, NA, NA, NULL);
addflag(lastot->flags, F_DAM, DT_SLASH, NA, NA, "2d4+3");
addflag(lastot->flags, F_ACCURACY, 75, NA, NA, NULL);
addflag(lastot->flags, F_TWOHANDED, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_USESSKILL, SK_STAVES, NA, NA, NULL);
addflag(lastot->flags, F_ATTREQ, A_STR, 7, NA, NULL);
addflag(lastot->flags, F_ATTREQ, A_DEX, 9, NA, NULL);
addflag(lastot->flags, F_RODSHAPED, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_CRITCHANCE, 5, NA, NA, NULL);
addot(OT_IRONSTAFF, "iron staff", "A long, stout metal pole.", MT_METAL, 8, OC_WEAPON, SZ_HUMAN);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 60, NA, NULL);
addflag(lastot->flags, F_OBATTACKDELAY, 110, NA, NA, NULL);
addflag(lastot->flags, F_DAM, DT_BASH, NA, NA, "3d4+1");
addflag(lastot->flags, F_ACCURACY, 80, NA, NA, NULL);
addflag(lastot->flags, F_TWOHANDED, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_USESSKILL, SK_STAVES, NA, NA, NULL);
addflag(lastot->flags, F_ATTREQ, A_STR, 9, NA, NULL);
addflag(lastot->flags, F_RODSHAPED, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_CRITCHANCE, 8, NA, NA, NULL);
// clubs (bashing)
addot(OT_CLUB, "club", "A heavy, blunt wooden instrument to hit things with.", MT_WOOD, 8, OC_WEAPON, SZ_MEDIUM);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, NA, NULL);
addflag(lastot->flags, F_DAM, DT_BASH, NA, NA, "1d6");
addflag(lastot->flags, F_ACCURACY, 80, NA, NA, NULL);
addflag(lastot->flags, F_USESSKILL, SK_CLUBS, NA, NA, NULL);
addflag(lastot->flags, F_ATTREQ, A_STR, 7, NA, NULL);
addflag(lastot->flags, F_CRITCHANCE, 5, NA, NA, NULL);
addot(OT_FLAIL, "flail", "A flexible chain attached to a heavy weight.", MT_METAL, 9, OC_WEAPON, SZ_MEDIUM);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 75, NA, NULL);
addflag(lastot->flags, F_DAM, DT_BASH, NA, NA, "2d4");
addflag(lastot->flags, F_ACCURACY, 80, NA, NA, NULL);
addflag(lastot->flags, F_USESSKILL, SK_CLUBS, NA, NA, NULL);
addflag(lastot->flags, F_ATTREQ, A_STR, 9, NA, NULL);
addflag(lastot->flags, F_CRITCHANCE, 5, NA, NA, NULL);
addot(OT_FLAILHEAVY, "heavy flail", "A flexible chain attached to a very heavy weight.", MT_METAL, 12, OC_WEAPON, SZ_MEDIUM);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 75, NA, NULL);
addflag(lastot->flags, F_OBATTACKDELAY, 115, NA, NA, NULL);
addflag(lastot->flags, F_DAM, DT_BASH, NA, NA, "2d6");
addflag(lastot->flags, F_ACCURACY, 80, NA, NA, NULL);
addflag(lastot->flags, F_USESSKILL, SK_CLUBS, NA, NA, NULL);
addflag(lastot->flags, F_ATTREQ, A_STR, 13, NA, NULL);
addflag(lastot->flags, F_CRITCHANCE, 8, NA, NA, NULL);
addot(OT_GREATCLUB, "great club", "An enormous, very heavy, blunt instrument to hit things with.", MT_STONE, 15, OC_WEAPON, SZ_MEDIUM);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 50, NA, NULL);
addflag(lastot->flags, F_OBATTACKDELAY, 180, NA, NA, NULL);
addflag(lastot->flags, F_DAM, DT_BASH, NA, NA, "1d10+5");
addflag(lastot->flags, F_ACCURACY, 80, NA, NA, NULL);
addflag(lastot->flags, F_TWOHANDED, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_USESSKILL, SK_CLUBS, NA, NA, NULL);
addflag(lastot->flags, F_ATTREQ, A_STR, 16, NA, NULL);
addot(OT_MACE, "mace", "A weapon with a heavy head on a solid shaft used to bludgeon opponents.", MT_METAL, 10, OC_WEAPON, SZ_MEDIUM);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 90, NA, NULL);
addflag(lastot->flags, F_DAM, DT_BASH, NA, NA, "1d7+1");
addflag(lastot->flags, F_ACCURACY, 80, NA, NA, NULL);
addflag(lastot->flags, F_USESSKILL, SK_CLUBS, NA, NA, NULL);
addflag(lastot->flags, F_ATTREQ, A_STR, 9, NA, NULL);
addflag(lastot->flags, F_CRITCHANCE, 7, NA, NA, NULL);
addot(OT_MORNINGSTAR, "morningstar", "A heavy, spiked mace.", MT_METAL, 12, OC_WEAPON, SZ_MEDIUM);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 70, NA, NULL);
addflag(lastot->flags, F_OBATTACKDELAY, 150, NA, NA, NULL);
addflag(lastot->flags, F_DAM, DT_BASH, NA, NA, "1d9+3");
addflag(lastot->flags, F_ACCURACY, 80, NA, NA, NULL);
addflag(lastot->flags, F_TWOHANDED, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_USESSKILL, SK_CLUBS, NA, NA, NULL);
addflag(lastot->flags, F_ATTREQ, A_STR, 13, NA, NULL);
addflag(lastot->flags, F_CRITCHANCE, 8, NA, NA, NULL);
addot(OT_NUNCHAKU, "nunchaku", "Two stout sticks connected with a short or rope. Good for disarming.", MT_WOOD, 4.5, OC_WEAPON, SZ_MEDIUM);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 80, NA, NULL);
addflag(lastot->flags, F_DISARMATTACK, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_DAM, DT_BASH, NA, NA, "1d6+1");
addflag(lastot->flags, F_ACCURACY, 75, NA, NA, NULL);
addflag(lastot->flags, F_USESSKILL, SK_CLUBS, NA, NA, NULL);
addflag(lastot->flags, F_ATTREQ, A_DEX, 10, NA, NULL);
addflag(lastot->flags, F_CRITCHANCE, 3, NA, NA, NULL);
addot(OT_SPANNER, "spanner", "A long, heavy metal wrench.", MT_METAL, 1, OC_WEAPON, SZ_MEDIUM);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 70, NA, NULL);
addflag(lastot->flags, F_DAM, DT_BASH, NA, NA, "1d4");
addflag(lastot->flags, F_ACCURACY, 65, NA, NA, NULL);
addflag(lastot->flags, F_OPERABLE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_OPERNEEDDIR, B_TRUE, NA, NA, "Use your spanner in which direction");
addflag(lastot->flags, F_USESSKILL, SK_CLUBS, NA, NA, NULL);
addot(OT_STICK, "stick", "A sturdy wooden stick.", MT_WOOD, 0.5, OC_WEAPON, SZ_SMALL);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, NA, NULL);
addflag(lastot->flags, F_RARITY, H_FOREST, 100, NA, NULL);
addflag(lastot->flags, F_DAM, DT_BASH, NA, NA, "1d2");
addflag(lastot->flags, F_ACCURACY, 80, NA, NA, NULL);
addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_USESSKILL, SK_CLUBS, NA, NA, NULL);
addflag(lastot->flags, F_NOQUALITY, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_RODSHAPED, B_TRUE, NA, NA, NULL);
// projectile weapons
addot(OT_BOW, "short bow", "A weapon which projects arrows via its elasticity.", MT_WOOD, 5, OC_WEAPON, SZ_MEDIUM);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 75, NA, NULL);
addflag(lastot->flags, F_FIREARM, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_OPERABLE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_FIRESPEED, 8, NA, NA, NULL);
addflag(lastot->flags, F_ACCURACY, 80, NA, NA, NULL);
addflag(lastot->flags, F_RANGE, 5, NA, NA, NULL);
addflag(lastot->flags, F_AMMOOB, OT_ARROW, NA, NA, NULL);
addflag(lastot->flags, F_AMMOCAPACITY, 1, NA, NA, NULL);
addflag(lastot->flags, F_FIRETURNS, 1, NA, NA, NULL);
addflag(lastot->flags, F_RELOADTURNS, 1, NA, NA, NULL);
addflag(lastot->flags, F_ATTREQ, A_STR, 9, NA, NULL);
addflag(lastot->flags, F_RODSHAPED, B_TRUE, NA, NA, NULL);
addot(OT_CROSSBOW, "crossbow", "A standard crossbow. Very powerful, but needs high strength to use.", MT_WOOD, 8, OC_WEAPON, SZ_MEDIUM);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 75, NA, NULL);
addflag(lastot->flags, F_FIREARM, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_OPERABLE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_FIRESPEED, 12, NA, NA, NULL);
addflag(lastot->flags, F_ACCURACY, 80, NA, NA, NULL);
addflag(lastot->flags, F_RANGE, 10, NA, NA, NULL);
addflag(lastot->flags, F_AMMOOB, OT_BOLT, NA, NA, NULL);
addflag(lastot->flags, F_AMMOCAPACITY, 1, NA, NA, NULL);
addflag(lastot->flags, F_FIRETURNS, 2, NA, NA, NULL);
addflag(lastot->flags, F_RELOADTURNS, 2, NA, NA, NULL);
addflag(lastot->flags, F_ATTREQ, A_STR, 13, NA, NULL);
addot(OT_CROSSBOWHAND, "hand crossbow", "A small one-handed crossbow. Lightweight, but less powerful than a full-sized one.", MT_WOOD, 3, OC_WEAPON, SZ_SMALL);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 75, NA, NULL);
addflag(lastot->flags, F_FIREARM, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_OPERABLE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_FIRESPEED, 6, NA, NA, NULL);
addflag(lastot->flags, F_ACCURACY, 75, NA, NA, NULL);
addflag(lastot->flags, F_RANGE, 10, NA, NA, NULL);
addflag(lastot->flags, F_AMMOOB, OT_BOLT, NA, NA, NULL);
addflag(lastot->flags, F_AMMOCAPACITY, 1, NA, NA, NULL);
addflag(lastot->flags, F_FIRETURNS, 1, NA, NA, NULL);
addflag(lastot->flags, F_RELOADTURNS, 1, NA, NA, NULL);
addot(OT_LONGBOW, "longbow", "A very large (human-sized) bow, capable of firing arrows with great power.", MT_WOOD, 7, OC_WEAPON, SZ_MEDIUM);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 75, NA, NULL);
addflag(lastot->flags, F_FIREARM, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_OPERABLE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_FIRESPEED, 12, NA, NA, NULL);
addflag(lastot->flags, F_ACCURACY, 80, NA, NA, NULL);
addflag(lastot->flags, F_RANGE, 10, NA, NA, NULL);
addflag(lastot->flags, F_AMMOOB, OT_ARROW, NA, NA, NULL);
addflag(lastot->flags, F_AMMOCAPACITY, 1, NA, NA, NULL);
addflag(lastot->flags, F_FIRETURNS, 1, NA, NA, NULL);
addflag(lastot->flags, F_RELOADTURNS, 1, NA, NA, NULL);
addflag(lastot->flags, F_ATTREQ, A_STR, 13, NA, NULL);
addot(OT_REVOLVER, "revolver", "Basic one-handed firearm.", MT_METAL, 1, OC_WEAPON, SZ_SMALL);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 60, NA, NULL);
addflag(lastot->flags, F_FIREARM, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_OPERABLE, B_TRUE, NA, NA, NULL);
//addflag(lastot->flags, F_DAMTYPE, DT_BASH, NA, NA, NULL);
//addflag(lastot->flags, F_DAM, 3, 4, NA, NULL);
addflag(lastot->flags, F_FIRESPEED, 20, NA, NA, NULL);
addflag(lastot->flags, F_ACCURACY, 80, NA, NA, NULL);
addflag(lastot->flags, F_RANGE, 10, NA, NA, NULL);
addflag(lastot->flags, F_AMMOOB, OT_BULLET, NA, NA, NULL);
addflag(lastot->flags, F_AMMOOB, OT_RUBBERBULLET, NA, NA, NULL);
addflag(lastot->flags, F_AMMOCAPACITY, 6, NA, NA, NULL);
addflag(lastot->flags, F_FIRETURNS, 1, NA, NA, NULL);
addflag(lastot->flags, F_RELOADTURNS, 2, NA, NA, NULL);
addot(OT_SHOTGUN, "shotgun", "Powerful but short-ranged gun.", MT_METAL, 5, OC_WEAPON, SZ_MEDIUM);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 60, NA, NULL);
addflag(lastot->flags, F_FIREARM, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_OPERABLE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_TWOHANDED, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_FIRESPEED, 30, NA, NA, NULL);
addflag(lastot->flags, F_ACCURACY, 80, NA, NA, NULL);
addflag(lastot->flags, F_RANGE, 3, NA, NA, NULL);
addflag(lastot->flags, F_AMMOOB, OT_BULLET, NA, NA, NULL);
addflag(lastot->flags, F_AMMOCAPACITY, 2, NA, NA, NULL);
addflag(lastot->flags, F_FIRETURNS, 1, NA, NA, NULL);
addflag(lastot->flags, F_RELOADTURNS, 3, NA, NA, NULL);
addot(OT_SLING, "sling", "Stretchy piece of rubber for launching projectiles.", MT_RUBBER, 0.5, OC_WEAPON, SZ_SMALL);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 80, NA, NULL);
addflag(lastot->flags, F_FIREARM, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_OPERABLE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_FIRESPEED, 6, NA, NA, NULL);
addflag(lastot->flags, F_ACCURACY, 70, NA, NA, NULL);
addflag(lastot->flags, F_RANGE, 5, NA, NA, NULL);
addflag(lastot->flags, F_AMMOOB, OT_STONE, NA, NA, NULL);
addflag(lastot->flags, F_AMMOCAPACITY, 1, NA, NA, NULL);
addflag(lastot->flags, F_FIRETURNS, 1, NA, NA, NULL);
addflag(lastot->flags, F_RELOADTURNS, 1, NA, NA, NULL);
// special weapons
addot(OT_ENERGYBLADE, "energy blade", "A summoned weapon made of pure magical energy.", MT_MAGIC, 0, OC_WEAPON, SZ_MEDIUM);
addflag(lastot->flags, F_DAM, DT_MAGIC, NA, NA, "1d4"); // will be replaced when summoned
addflag(lastot->flags, F_ACCURACY, 100, NA, NA, NULL);
addflag(lastot->flags, F_CRITCHANCE, 5, NA, NA, NULL);
addot(OT_HANDOFGOD, "hand of god", "The ultimate power.", MT_FLESH, 0.1, OC_WEAPON, SZ_MEDIUM);
//addflag(lastot->flags, F_RARITY, H_DUNGEON, RR_UNIQUE, NA, NULL);
//addflag(lastot->flags, F_DAMTYPE, DT_HOLY, NA, NA, NULL);
addflag(lastot->flags, F_DAM, DT_SLASH, NA, NA, "1d6+100");
addflag(lastot->flags, F_ACCURACY, 500, NA, NA, NULL);
addflag(lastot->flags, F_UNIQUE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_USESSKILL, SK_NONE, NA, NA, NULL);
addot(OT_ICESHIELD, "ice crystal shield", "A summoned shield made of ice crystals.", MT_ICE, 0, OC_ARMOUR, SZ_SMALL);
addflag(lastot->flags, F_SHIELD, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_GOESON, BP_SECWEAPON, NA, NA, NULL);
addflag(lastot->flags, F_ARMOURRATING, 1, NA, NA, NULL); // will be replaced when summoned
addflag(lastot->flags, F_OBHP, 5, 5, NA, NULL); // will be replaced when summoned
addot(OT_ICEARMOUR, "ice crystal armour", "Summoned body armour made of ice crystals.", MT_ICE, 0, OC_ARMOUR, SZ_HUMAN);
addflag(lastot->flags, F_GOESON, BP_BODY, NA, NA, NULL);
addflag(lastot->flags, F_ARMOURRATING, 5, NA, NA, NULL);
addflag(lastot->flags, F_OBHP, 5, 5, NA, NULL); // will be replaced when summoned
addot(OT_ICEBOOTS, "pair of ice crystal boots", "Summoned boots made of ice crystals.", MT_ICE, 0, OC_ARMOUR, SZ_SMALL);
addflag(lastot->flags, F_GOESON, BP_FEET, NA, NA, NULL);
addflag(lastot->flags, F_ARMOURRATING, 5, NA, NA, NULL);
addflag(lastot->flags, F_OBHP, 5, 5, NA, NULL); // will be replaced when summoned
addot(OT_ICEGLOVES, "pair of ice crystal gauntlets", "Summoned gauntlets made of ice crystals.", MT_ICE, 0, OC_ARMOUR, SZ_SMALL);
addflag(lastot->flags, F_GOESON, BP_HANDS, NA, NA, NULL);
addflag(lastot->flags, F_ARMOURRATING, 5, NA, NA, NULL);
addflag(lastot->flags, F_OBHP, 5, 5, NA, NULL); // will be replaced when summoned
addot(OT_ICEHELMET, "ice crystal helmet", "A summoned helmet made of ice crystals.", MT_ICE, 0, OC_ARMOUR, SZ_SMALL);
addflag(lastot->flags, F_GOESON, BP_HEAD, NA, NA, NULL);
addflag(lastot->flags, F_ARMOURRATING, 5, NA, NA, NULL);
addflag(lastot->flags, F_OBHP, 5, 5, NA, NULL); // will be replaced when summoned
// special obs
addot(OT_PLAYERSTART, "playerstart", "starting pos for player", MT_NOTHING, 0, OC_MISC, SZ_MINI);
}
// returns the 'armourrating' flag
flag_t *isarmour(object_t *o) {
flag_t *f;
if (hasflag(o->flags, F_GOESON)) {
f = hasflag(o->flags, F_ARMOURRATING);
if (f) {
return f;
}
}
return NULL;
}
int isactivated(object_t *o) {
if (hasflag(o->flags, F_ACTIVATED)) {
return B_TRUE;
}
return B_FALSE;
}
int isammofor(objecttype_t *ammo, object_t *gun) {
if (hasflagval(gun->flags, F_AMMOOB, ammo->id, NA, NA, NULL)) {
return B_TRUE;
}
return B_FALSE;
}
int isbadfood(object_t *o) {
if (hasflag(o->flags, F_TAINTED)) {
return B_TRUE;
}
if (isrotting(o)) {
return B_TRUE;
}
switch (o->type->id) {
case OT_POT_POISON:
case OT_POT_ACID:
return B_TRUE;
default:
break;
}
return B_FALSE;
}
// is armour 'a' better than armour 'b'?
int isbetterarmourthan(object_t *a, object_t *b) {
int arma, armb;
flag_t *f;
if (!a) return B_FALSE;
if (!b) return B_TRUE;
f = isarmour(a);
if (f) {
arma = f->val[0];
} else {
arma = 0;
}
f = isarmour(b);
if (f) {
armb = f->val[0];
} else {
armb = 0;
}
if (arma > armb) return B_TRUE;
return B_FALSE;
}
// compare weapons using max damage
int isbetterwepthan(object_t *a, object_t *b) {
//flag_t *f;
int dama,damb;
float acca,accb;
int db = B_FALSE;
char namea[BUFLEN];
char nameb[BUFLEN];
if (!a) return B_FALSE;
if (!b) return B_TRUE;
/* if (a->pile->owner && lfhasflag(a->pile->owner, F_DEBUG)) {
db = B_TRUE;
}
if (b->pile->owner && lfhasflag(b->pile->owner, F_DEBUG)) {
db = B_TRUE;
} */
if (db) {
getobname(a, namea, a->amt);
getobname(b, nameb, b->amt);
}
getdamrange(hasflag(a->flags, F_DAM), NULL, &dama);
getdamrange(hasflag(b->flags, F_DAM), NULL, &damb);
// modify based on extra props
if (hasflag(a->flags, F_HASBRAND)) {
dama *= 3;
}
if (hasflag(a->flags, F_ONFIRE)) {
dama += 8;
}
if (hasflag(b->flags, F_HASBRAND)) {
damb *= 3;
}
if (hasflag(b->flags, F_ONFIRE)) {
damb += 8;
}
// modify with accuracy
acca = getobaccuracy(a, a->pile->owner);
accb = getobaccuracy(b, b->pile->owner);
if (db) {
msg("PREACC:a=%s:%d(acc %d), b=%s:%d(acc %d)",namea,dama,(int)acca, nameb, damb,(int)accb);
}
dama = (int)((float)dama * (acca/100));
damb = (int)((float)damb * (accb/100));
if (db) {
msg("POST:a=%s:%d(acc %d), b=%s:%d(acc %d)",namea,dama,(int)acca, nameb, damb,(int)accb);
}
if (dama > damb) return B_TRUE;
return B_FALSE;
}
int isblessed(object_t *o) {
if (o->blessed == B_BLESSED) return B_TRUE;
return B_FALSE;
}
int isblessknown(object_t *o) {
if (o->blessknown) return B_TRUE;
if ((gamemode == GM_GAMESTARTED) && hasflag(player->flags, F_DETECTAURAS)) {
return B_TRUE;
}
return B_FALSE;
}
int iscorpse(object_t *o) {
if (o->type->obclass->id == OC_CORPSE) {
return B_TRUE;
}
return B_FALSE;
}
int iscursed(object_t *o) {
if (o->blessed == B_CURSED) return B_TRUE;
return B_FALSE;
}
int isdamaged(object_t *o) {
flag_t *f;
f = hasflag(o->flags, F_OBHP);
if (f && (f->val[0] < f->val[1])) {
return B_TRUE;
}
return B_FALSE;
}
int isdangerousob(object_t *o, lifeform_t *lf, int onlyifknown) {
enum ATTRBRACKET iqb;
iqb = getattrbracket(getattr(lf, A_IQ), A_IQ, NULL);
if (!onlyifknown || (iqb >= AT_AVERAGE)) {
if (hasflag(o->flags, F_SHARP)) {
if (!getequippedob(lf->pack, BP_HANDS) && !isimmuneto(lf->flags, DT_SLASH)) {
return B_TRUE;
}
}
}
if (!onlyifknown || (iqb >= IQ_ANIMAL)) {
if (hasflag(o->flags, F_ONFIRE)) {
if (!isimmuneto(lf->flags, DT_FIRE)) {
return B_TRUE;
}
}
}
// undead won't touch blessed things - don't worry about
// onlyifknown, they can sense this.
if (hasflag(lf->flags, F_UNDEAD) && isblessed(o)) {
return B_TRUE;
}
return B_FALSE;
}
int isdeadob(object_t *o) {
if (hasflag(o->flags, F_DEAD)) {
return B_TRUE;
}
return B_FALSE;
}
int isdrinkable(object_t *o) {
switch (o->type->obclass->id) {
case OC_POTION:
return B_TRUE;
default: break;
}
if (hasflag(o->flags, F_DRINKABLE)) {
return B_TRUE;
}
return B_FALSE;
}
int isedible(object_t *o) {
if (hasflag(o->flags, F_EDIBLE)) {
return B_TRUE;
}
if (o->material->id == MT_ICE) {
return B_TRUE;
}
return B_FALSE;
}
flag_t *isequipped(object_t *o) {
flag_t *f;
f = hasflag(o->flags, F_EQUIPPED);
if (f) {
return f;
}
return NULL;
}
int isequippedon(object_t *o, enum BODYPART bp) {
if (hasflagval(o->flags, F_EQUIPPED, bp, NA, NA, NULL)) {
return B_TRUE;
}
return B_FALSE;
}
int isfirearm(object_t *o) {
if (!o) return B_FALSE;
if (hasflag(o->flags, F_FIREARM)) {
return B_TRUE;
}
return B_FALSE;
}
int isflammable(object_t *o) {
if (hasflag(o->flags, F_WET)) {
return B_FALSE;
}
if (hasflag(o->flags, F_FLAMMABLE)) {
return B_TRUE;
}
return B_FALSE;
}
int isknown(object_t *o) {
// if id'd, return the full name
if (hasflag(o->flags, F_IDENTIFIED)) {
return B_TRUE;
}
return isknownot(o->type);
}
int isknownot(objecttype_t *ot) {
knowledge_t *k;
// if id'd, return the full name
for (k = knowledge; k ; k = k->next) {
if (k->id == ot->id) {
// it DOES have a hidden name.
// does the player know about it?
if (k->known == B_KNOWN) {
return B_TRUE;
} else {
return B_FALSE;
}
}
}
// no hidden name, return real one
return B_TRUE;
}
int isheavyweapon(object_t *o) {
if (getobunitweight(o) >= HEAVYWEPKG) {
return B_TRUE;
}
return B_FALSE;
}
// is the object fully identified?
// ie. its type is known ("potion of healing" rather than "red potion")
// AND
// you know whether it is cursed or not
int isidentified(object_t *o) {
flag_t *f;
// blessed status not known?
if (!isblessknown(o)) return B_FALSE;
// unknown object type?
if (!isknown(o)) return B_FALSE;
// unknown flags?
for (f = o->flags->first ; f ; f = f->next) {
if (!f->known) return B_FALSE;
}
return B_TRUE;
}
int isimpassableob(object_t *o, lifeform_t *lf) {
flag_t *f;
f = hasflag(o->flags, F_IMPASSABLE);
if (f) {
enum LFSIZE lfsize;
enum LFSIZE blockmin, blockmax;
if (!lf) return B_TRUE;
lfsize = getlfsize(lf);
blockmin = f->val[0];
blockmax = f->val[1];
if ((lfsize >= blockmin) && (lfsize <= blockmax)) {
return B_TRUE;
}
}
if (lf && (lf->race->raceclass->id == RC_UNDEAD)) {
if (hasflagval(o->flags, F_REPELBLESSED, B_CURSED, NA, NA, NULL)) {
return B_TRUE;
}
}
return B_FALSE;
}
int ismagical(object_t *o) {
if (hasflag(o->flags, F_HASBRAND)) {
return B_TRUE;
}
switch (o->type->obclass->id) {
case OC_SCROLL:
switch (o->type->id) {
case OT_GRAPHPAPER:
case OT_SCR_NOTHING:
// these scrolls are non-magical
break;
default:
return B_TRUE;
break;
}
break;
case OC_RING:
case OC_WAND:
// all rings/wands are magical
return B_TRUE;
break;
case OC_POTION:
switch (o->type->id) {
case OT_POT_ACID:
case OT_POT_OIL:
case OT_POT_WATER:
case OT_POT_BLOOD:
case OT_POT_RUM:
case OT_POT_JUICE:
// these potions are non-magical
break;
default:
return B_TRUE;
break;
}
break;
case OC_BOOK:
if (hasflag(o->flags, F_LINKSPELL)) {
// ie. spellbooks
return B_TRUE;
}
break;
default:
break;
}
if (hasflag(o->flags, F_ENCHANTABLE) && hasflag(o->flags, F_BONUS)) {
return B_TRUE;
}
return B_FALSE;
}
int ismeleeweapon(object_t *o) {
if (hasflag(o->flags, F_DAM)) {
return B_TRUE;
}
return B_FALSE;
}
int ismetal(enum MATERIAL mat) {
int metal = B_FALSE;
switch (mat) {
case MT_METAL:
case MT_GOLD:
case MT_SILVER:
case MT_WIRE:
metal = B_TRUE;
break;
default:
metal = B_FALSE;
break;
}
return metal;
}
int isthrowmissile(object_t *o) {
if (hasflag(o->flags, F_THROWMISSILE)) {
return B_TRUE;
}
// special cases...
switch (o->type->id) {
case OT_EMPTYFLASK: // (because it will shatter)
case OT_EMPTYVIAL: // (because it will shatter)
case OT_BROKENGLASS: // (because it will cut)
case OT_ICECHUNK: // (because it will cut)
return B_TRUE;
default:
break;
}
return B_FALSE;
}
// shoudl we append {tried} to this object?
int istried(object_t *o) {
if (hasflag(o->flags, F_IDENTIFIED)) {
return B_FALSE;
}
return istriedot(o->type);
}
int istriedot(objecttype_t *ot) {
knowledge_t *k;
if (ot->obclass->id == OC_BOOK) return B_FALSE;
for (k = knowledge; k ; k = k->next) {
if (k->id == ot->id) {
// it DOES have a hidden name.
// has the player tried it?
if (k->known == B_TRIED) {
return B_TRUE;
} else {
return B_FALSE;
}
}
}
// no hidden name, so can't be "tried"
return B_FALSE;
}
int isoperable(object_t *o) {
if (hasflag(o->flags, F_OPERABLE)) return B_TRUE;
//if (o->type->obclass->id == OC_TECH) return B_TRUE;
return B_FALSE;
}
// has this object changed proerties from its
// parent objecttype?
int isplainob(object_t *o) {
if (o->material != o->type->material) return B_FALSE;
if (o->weight != o->type->weight) return B_FALSE;
if (o->inscription) return B_FALSE;
if (o->blessed != B_UNCURSED) return B_FALSE;
if (isblessknown(o)) return B_FALSE;
return B_TRUE;
}
int ispourable(object_t *o) {
if (hasflag(o->flags, F_POURABLE)) {
if (o->material->id != MT_ICE) {
return B_TRUE;
}
}
return B_FALSE;
}
int ispushable(object_t *o) {
if (hasflag(o->flags, F_PUSHABLE)) {
return B_TRUE;
}
return B_FALSE;
}
int isreadable(object_t *o) {
switch (o->type->obclass->id) {
case OC_SCROLL:
case OC_BOOK:
return B_TRUE;
default: break;
}
return B_FALSE;
}
int isrotting(object_t *o) {
flag_t *f;
float pct;
if (hasflag(o->flags, F_TAINTED)) {
return B_TRUE;
}
if (!iscorpse(o)) return B_FALSE;
f = hasflag(o->flags, F_OBHP);
if (f) {
pct = ((float) f->val[0] / (float) f->val[1]) * 100.0;
} else {
pct = 100;
}
if (pct < 25) {
return B_TRUE;
}
return B_FALSE;
}
flag_t *issecretdoor(object_t *o) {
if (isdoor(o, NULL)) {
return hasflag(o->flags, F_SECRET);
}
return NULL;
}
// returns the 'shield' flag
flag_t *isshield(object_t *o) {
return hasflag(o->flags, F_SHIELD);
}
int isthrownmissile(object_t *o) {
if (hasflag(o->flags, F_THROWMISSILE)) {
return B_TRUE;
}
return B_FALSE;
}
int isweapon(object_t *o) {
if (o->type->obclass->id == OC_WEAPON) {
return B_TRUE;
}
return B_FALSE;
}
int iswearable(object_t *o) {
if (hasflag(o->flags, F_GOESON)) {
return B_TRUE;
}
return B_FALSE;
}
void killallobs(obpile_t *op) {
while (op->first) {
killob(op->first);
}
}
void killmaterial(material_t *m) {
material_t *nextone, *lastone;
// free mem
free(m->name);
killflagpile(m->flags);
// remove from list
nextone = m->next;
if (nextone != NULL) {
nextone->prev = m->prev;
} else { /* last */
lastmaterial = m->prev;
}
if (m->prev == NULL) {
/* first */
nextone = m->next;
free(material);
material = nextone;
} else {
lastone = m->prev;
free (lastone->next );
lastone->next = nextone;
}
}
void killob(object_t *o) {
object_t *nextone, *lastone;
// debugging
if (o->type->id == OT_STAIRSUP) {
msg("warning: removing an up staircase!");
dblog("warning: removing an up staircase!");
}
// remove flags conferred by this object
if (o->pile->owner) {
loseobflags(o->pile->owner, o, ALLCONFERRED);
} else if (o->pile->where && !o->pile->where->lf && !hasflag(o->flags, F_NOGLYPH) && haslos(player, o->pile->where)) {
needredraw = B_TRUE;
}
// free mem
if (o->inscription) free(o->inscription);
// remove from list
nextone = o->next;
if (nextone != NULL) {
nextone->prev = o->prev;
} else { /* last */
o->pile->last = o->prev;
}
if (o->prev == NULL) {
/* first */
nextone = o->next;
o->pile->first = nextone;
free(o);
} else {
lastone = o->prev;
free (lastone->next );
lastone->next = nextone;
}
}
void killobpile(obpile_t *op) {
killallobs(op);
free(op);
}
void killoc(objectclass_t *oc) {
objectclass_t *nextone, *lastone;
int i;
// free mem
free(oc->name);
free(oc->desc);
if (oc->flags) killflagpile(oc->flags);
for (i = 0; i < oc->nnouns; i++) {
free(oc->noun[i]);
}
// remove from list
nextone = oc->next;
if (nextone != NULL) {
nextone->prev = oc->prev;
} else { /* last */
lastobjectclass = oc->prev;
}
if (oc->prev == NULL) {
/* first */
nextone = oc->next;
free(objectclass);
objectclass = nextone;
} else {
lastone = oc->prev;
free (lastone->next );
lastone->next = nextone;
}
}
void killot(objecttype_t *ot) {
objecttype_t *nextone, *lastone;
// free mem
free(ot->name);
free(ot->desc);
if (ot->flags) killflagpile(ot->flags);
// remove from list
nextone = ot->next;
if (nextone != NULL) {
nextone->prev = ot->prev;
} else { /* last */
lastobjecttype = ot->prev;
}
if (ot->prev == NULL) {
/* first */
nextone = ot->next;
free(objecttype);
objecttype = nextone;
} else {
lastone = ot->prev;
free (lastone->next );
lastone->next = nextone;
}
}
int knockbackob(object_t *o, int dir, int howfar, int power, lifeform_t *pusher) {
int i;
char obname[BUFLEN];
int seen;
cell_t *obcell, *c;
getobname(o,obname, o->amt);
obcell = getoblocation(o);
if (haslos(player, obcell)) {
seen = B_TRUE;
} else {
seen = B_FALSE;
}
if (dir == D_NONE) {
// failed!
return B_TRUE;
}
c = obcell;
for (i = 0; i < howfar; i++) {
cell_t *newcell;
newcell = getcellindir(c, dir);
if (!newcell) {
// hit a wall - stop here
break;
} else if (newcell->lf) {
// hit them - stop here
c = newcell;
break;
} else if (!cellwalkable(NULL, newcell, NULL)) {
// hit a wall - stop here
break;
}
c = newcell;
}
fireat(NULL, o, o->amt, c, power, NULL);
return B_FALSE;
}
// animate a weapon
lifeform_t *makeanimated(lifeform_t *lf, object_t *o, int level) {
cell_t *where;
flag_t *f;
lifeform_t *newlf;
where = getrandomadjcell(lf->cell, WE_EMPTY, B_NOEXPAND);
if (!where) return NULL;
newlf = addlf(where, R_DANCINGWEAPON, level);
if (newlf) {
if (isplayer(lf)) {
addflag(newlf->flags, F_FRIENDLY, B_TRUE, NA, NA, NULL);
} else if (hasflag(lf->flags, F_HOSTILE)) {
addflag(newlf->flags, F_HOSTILE, B_TRUE, NA, NA, NULL);
}
addflag(lf->flags, F_NODEATHANNOUNCE, B_TRUE, NA, NA, NULL);
o = relinkob(o, newlf->pack);
weild(newlf, o);
f = hasflag(o->flags, F_OBHP);
if (f) {
newlf->maxhp = f->val[1];
newlf->hp = newlf->maxhp;
}
f = hasflag(o->flags, F_OBATTACKDELAY);
if (f) {
int origspeed;
int newspeed;
origspeed = getmovespeed(newlf);
killflagsofid(newlf->flags, F_MOVESPEED);
newspeed = (int)((float)origspeed * ((float)f->val[0] / 100.0));
addflag(newlf->flags, F_MOVESPEED, newspeed, NA, NA, NULL);
}
}
if (newlf) {
petify(newlf, lf);
}
return newlf;
}
// returns true if something hapepned
int makeduller(object_t *o, int howmuch) {
char obname[BUFLEN];
int oldbonus,newbonus;
int rv = B_FALSE;
// get object name before changing the bonus
getobname(o,obname, 1);
oldbonus = getobbonus(o);
modbonus(o, -howmuch);
newbonus = getobbonus(o);
if (newbonus < oldbonus) {
if (o->pile->owner) {
if (isplayer(o->pile->owner)) {
msg("Your %s seems duller!",noprefix(obname));
} else if (cansee(player, o->pile->owner)) {
char lfname[BUFLEN];
getlfname(o->pile->owner, lfname);
msg("%s%s %s seems duller!",lfname, getpossessive(lfname), noprefix(obname));
}
} else {
cell_t *obloc;
obloc = getoblocation(o);
if (haslos(player, obloc)) {
msg("%s seems duller!",obname);
}
}
rv = B_TRUE;
} else {
rv = B_FALSE;
}
return rv;
}
void makeknown(enum OBTYPE otid) {
knowledge_t *k;
object_t *o;
flag_t *f;
object_t *srcob[MAXPILEOBS*3];
enum FLAG fttogive[MAXPILEOBS*3];
int nobs = 0;
int i;
flag_t *retflag[MAXCANDIDATES];
int nretflags = 0;
if (player) {
// if player is holding an object of that type with F_CONFER.. IFKNOWN... and isn't known...
// then by making the object known, we also need to give them the flag.
//
// keep a list of objects and flags here, then give them afterwards.
for (o = player->pack->first ; o ; o = o->next) {
if ((o->type->id == otid) && !isknown(o)) {
getflags(o->flags, retflag, &nretflags, F_ACTIVATECONFER, F_EQUIPCONFER, F_HOLDCONFER, F_NONE);
for (i = 0; i < nretflags; i++) {
f = retflag[i];
if ((f->id == F_HOLDCONFER) && (f->val[2] == IFKNOWN)) {
srcob[nobs] = o;
fttogive[nobs] = F_HOLDCONFER;
nobs++;
} else if ((f->id == F_EQUIPCONFER) && (f->val[2] == IFKNOWN) && isequipped(o)) {
srcob[nobs] = o;
fttogive[nobs] = F_EQUIPCONFER;
nobs++;
} else if ((f->id == F_ACTIVATECONFER) && (f->val[2] == IFKNOWN) && isactivated(o)) {
srcob[nobs] = o;
fttogive[nobs] = F_ACTIVATECONFER;
nobs++;
}
}
}
}
}
for (k = knowledge; k ; k = k->next) {
if (k->id == otid) {
k->known = B_KNOWN;
}
}
for (i = 0; i < nobs; i++) {
giveobflags(player, srcob[i], fttogive[i]);
}
}
void maketried(enum OBTYPE otid) {
knowledge_t *k;
objecttype_t *ot;
// avoid adding '[tried]' to certain objects
ot = findot(otid);
if (ot && hasflag(ot->flags, F_NOTRIED)) {
return;
}
for (k = knowledge; k ; k = k->next) {
if (k->id == otid) {
if (k->known == B_UNKNOWN) {
k->known = B_TRIED;
}
}
}
}
void makewet(object_t *o, int amt) {
cell_t *loc;
lifeform_t *owner;
char ownername[BUFLEN];
char obname[BUFLEN];
char obnamefull[BUFLEN];
flag_t *f;
if (hasflag(o->flags, F_WATERPROOF)) {
return;
}
loc = getoblocation(o);
owner = o->pile->owner;
if (owner) {
getlfname(owner, ownername);
}
getobname(o,obname,o->amt);
if (owner) {
snprintf(obnamefull, BUFLEN, "%s%s %s",ownername, getpossessive(ownername), noprefix(obname));
} else {
strcpy(obnamefull, obname);
}
if (o->material->id == MT_METAL) {
if (amt < R_RUSTY) amt = R_RUSTY;
if (amt > R_TRUSTY) amt = R_TRUSTY;
f = hasflag(o->flags, F_RUSTED);
if (f) {
if (f->val[0] < R_TRUSTY) {
// make more rusty
f->val[0] += amt;
}
} else {
// rust
if (haslos(player, loc) && !isdead(player)) {
msg("%s rust%s.",obnamefull, (o->amt == 1) ? "s" : "");
}
f = addflag(o->flags, F_RUSTED, amt, NA, NA, NULL);
}
} else {
if (hasflag(o->flags, F_CANGETWET)) {
if (amt < W_DAMP) amt = W_DAMP;
if (amt > W_SOAKED) amt = W_SOAKED;
f = hasflag(o->flags, F_WET);
if (f) {
if (f->val[0] < W_SOAKED) {
// make wetter
/*
if (haslos(player, loc)) {
msg("%s get%s wetter.",obnamefull, (o->amt == 1) ? "s" : "");
}
*/
f->val[0] += amt;
f->val[1] = TM_WETTIME;
} else {
// jsut reset wettime
f->val[1] = TM_WETTIME;
}
} else {
// get wet
if (haslos(player, loc) && !isdead(player)) {
msg("%s get%s wet.",obnamefull, (o->amt == 1) ? "s" : "");
}
f = addflag(o->flags, F_WET, amt, TM_WETTIME, NA, NULL);
}
}
}
}
object_t *moveob(object_t *src, obpile_t *dst, int howmany) {
return real_moveob(src, dst, howmany, B_TRUE);
}
object_t *real_moveob(object_t *src, obpile_t *dst, int howmany, int stackok) {
object_t *o, *existob;
int i,preburdened = B_FALSE;
int db = B_FALSE;
flag_t *f;
reason = E_OK;
if (!obfits(src, dst)) {
reason = E_NOSPACE;
return NULL;
}
// adjust destination for pits
if (dst->where) {
object_t *pit;
pit = hasobwithflagval(dst->where->obpile, F_PIT, D_DOWN, NA, NA, NULL);
if (pit) {
cell_t *newcell;
newcell = getstairdestination(pit);
if (newcell) {
if (haslos(player, dst->where)) {
char obname[BUFLEN];
char pitname[BUFLEN];
getobname(src, obname, src->amt);
getobname(pit, pitname, 1);
msg("%s fall%s down %s.", obname, (src->amt == 1) ? "s" : "", pitname);
}
dst = newcell->obpile;
}
}
} else if (dst->owner) {
preburdened = isburdened(dst->owner);
}
if (db) dblog("DB: moveob() - moving %d x %s",howmany, src->type->name);
if (stackok) {
existob = canstackob(dst, src);
} else {
existob = NULL;
}
if (existob) {
if (db) dblog("DB: moveob() - found stack to join");
if (howmany == ALL) howmany = src->amt;
existob->amt += howmany;
src->amt -= howmany;
if (src->amt == 0) {
killob(src);
}
o = existob;
} else {
if (db) dblog("DB: moveob() - no stack to join");
// space in destination pile?
if (getnextletter(dst, NULL) == '\0') {
reason = E_NOSPACE;
return NULL;
}
// no similar objects in the dest pile.
if ((howmany == ALL) || (howmany == src->amt)) {
if (db) dblog("DB: dropping ALL - relinking object to new pile");
// just move the whole object to the new pile
o = relinkob(src, dst);
} else {
obpile_t *tempop;
if (db) dblog("DB: moving only some of a stack.");
// create temporary object pile
tempop = addobpile(NULL, NULL, NULL);
// add new object to the temporary pile
o = addob(tempop, src->type->name);
// copy props from original object
copyobprops(o, src);
// just move some of them
for (i = 0; i < howmany; i++ ) {
// the first one is already there!
if (i != 0) {
// inc counter in temp pile
o->amt++;
}
// dec counter on original
src->amt--;
}
if (src->amt <= 0) {
killob(src);
}
// now move the object entry from the temporary pile to the
// real destination pile.
while (tempop->first) {
o = relinkob(tempop->first, dst);
}
free(tempop);
}
}
if (o) {
if (dst->owner && isplayer(dst->owner) && isblessknown(o)) {
o->blessknown = B_TRUE;
}
if (hasflag(o->flags, F_DOOR)) {
killflagsofid(o->flags, F_LOCKED);
killflagsofid(o->flags, F_JAMMED);
killflagsofid(o->flags, F_SECRET);
if (!hasflag(o->flags, F_OPEN)) {
addflag(o->flags, F_OPEN, B_TRUE, NA, NA, NULL);
killflagsofid(o->flags, F_IMPASSABLE);
}
}
}
if (o && dst->where && !hasflag(o->flags, F_NOGLYPH) && haslos(player, dst->where)) {
if ((dst->where->lf) && !cansee(player, dst->where->lf)) {
// we can see the floor here
// someone invisible there who we can't see
needredraw = B_TRUE;
drawscreen();
} else {
// we can see the floor here
// noone there
needredraw = B_TRUE;
drawscreen();
}
}
// special effects when an object moves
f = hasflag(o->flags, F_SHOPITEM);
if (f) {
// recalculate object price baesd on who is holding it
calcshopprice(o, f);
}
// special effects if a lifeform picked up an object
if (dst->owner) {
flag_t *f;
// picked up an object in a shop
f = hasflag(o->flags, F_SHOPITEM);
if (f) {
lifeform_t *shk;
shk = findshopkeeper(dst->owner->cell->map, f->val[1]);
if (shk) {
askforpayment(shk, dst->owner);
}
}
// did this make us burdened?
if (isplayer(dst->owner)) {
if (isburdened(dst->owner) != preburdened) {
if (preburdened == BR_NONE) {
msg("^wThe weight of your possessions is burdening you!");
} else {
msg("^wThe weight of your possessions is burdening you even more!");
}
}
}
// in case you picked up money, something which changes your AR, etc
if (isplayer(dst->owner)) {
statdirty = B_TRUE;
}
} else if (dst->where) {
object_t *oo,*nextoo;
// object hit the ground?
// triggered a trap?
for (oo = dst->where->obpile->first ; oo ; oo = nextoo ) {
nextoo = oo->next;
if ((oo != o) && hasflag(oo->flags, F_TRAP)) {
triggertrap(NULL, o, oo, dst->where);
}
}
}
//o = newobeffects(o);
return o;
}
void modbonus(object_t *o, int amt) {
flag_t *f;
f = hasflag(o->flags, F_BONUS);
if (f) {
f->val[0] += amt;
} else {
cell_t *loc;
int known;
loc = getoblocation(o);
if (haslos(player, loc)) {
known = B_TRUE;
} else {
known = B_FALSE;
}
f = addflag_real(o->flags, F_BONUS, amt, NA, NA, NULL, PERMENANT, known, -1);
}
// enforce limit
limit(&f->val[0], -7, 7);
}
void obaction(object_t *o, char *text) {
char obname[BUFLEN];
getobname(o, obname, o->amt);
if (o->pile->owner) {
if (isplayer(o->pile->owner)) {
msg("Your %s %s!", noprefix(obname), text);
} else if (cansee(player, o->pile->owner)) {
char lfname[BUFLEN];
getlfname(o->pile->owner, lfname);
msg("%s%s %s %s!", lfname, getpossessive(lfname),
noprefix(obname), text);
}
} else if (haslos(player, o->pile->where)) { // on ground
msg("%s %s!", obname, text);
}
}
object_t *obexists(enum OBTYPE obid) {
map_t *m;
int x,y;
object_t *o;
lifeform_t *lf;
// do any objects of this id already exist?
for (m = firstmap ; m ; m = m->next) {
// check cells
for (y = 0; y < m->h; y++) {
for (x = 0; x < m->w; x++) {
cell_t *c;
c = getcellat(m, x, y);
if (c) {
o = hasob(c->obpile, obid);
if (o) return o;
}
}
}
// check lifeforms
for (lf = m->lf ; lf ; lf = lf->next) {
o = hasob(lf->pack, obid);
if (o) return o;
}
}
return NULL;
}
void obdie(object_t *o) {
char obname[BUFLEN];
flag_t *f;
f = hasflag(o->flags, F_DIECONVERT);
if (f) {
flag_t *f2;
object_t *newob;
char desc[BUFLEN];
if (!hasflag(o->flags, F_NODIECONVERTTEXT)) {
// announce the change
real_getobname(o, obname, o->amt, B_TRUE, B_FALSE, B_TRUE, B_TRUE, B_FALSE);
strcpy(desc, "");
f2 = NULL;
if (o->amt > 1) {
f2 = hasflag(o->flags, F_DIECONVERTTEXTPL);
}
if (!f2) {
f2 = hasflag(o->flags, F_DIECONVERTTEXT);
}
if (f2) {
snprintf(desc, BUFLEN, "%s", f2->text);
} else if (oblastdamtype(o) == DT_DECAY) {
// don't announce devay death while traning
if (!lfhasflag(player, F_TRAINING)) {
snprintf(desc, BUFLEN, "%s completed rotted away", (o->amt == 1) ? "has" : "have");
}
} else {
snprintf(desc, BUFLEN, "%s destroyed", (o->amt == 1) ? "is" : "are");
}
if (strstr(o->type->name, "stain") || (o->type->id == OT_ROASTMEAT)) {
assert(0 == 1);
}
if (strlen(desc)) {
if (o->pile->owner) {
if (isplayer(o->pile->owner)) {
msg("Your %s %s!",noprefix(obname), desc);
} else if (cansee(player, o->pile->owner)) {
// don't announce decay death unless we are holding it
if (oblastdamtype(o) != DT_DECAY) {
char monname[BUFLEN];
getlfname(o->pile->owner, monname);
msg("%s's %s %s!",monname, noprefix(obname), desc);
}
}
} else if (haslos(player, o->pile->where)) {
// don't announce decay death unless we are holding it
if (oblastdamtype(o) != DT_DECAY) {
capitalise(obname);
msg("%s %s.",obname, desc);
}
}
} // end if desc != ""
}
// change into something else
newob = addob(o->pile, f->text);
if (newob) {
// only set amt if text wasn't "x-y somethings"
if (!strchr(f->text, '-')) {
newob->amt = o->amt;
}
}
} else {
char desc[BUFLEN];
real_getobname(o, obname, o->amt, B_TRUE, B_FALSE, B_TRUE, B_TRUE, B_FALSE);
if (!hasflag(o->flags, F_NOOBDIETEXT)) {
// announce the death
strcpy(desc, "");
f = hasflag(o->flags, F_OBDIETEXT);
if (f) {
snprintf(desc, BUFLEN, "%s", f->text);
} else if (oblastdamtype(o) == DT_DECAY) {
if (!lfhasflag(player, F_TRAINING)) {
snprintf(desc, BUFLEN, "%s completely rotted away", (o->amt == 1) ? "has" : "have" );
}
} else {
snprintf(desc, BUFLEN, "%s destroyed", (o->amt == 1) ? "is" : "are");
}
if (strlen(desc)) {
if (o->pile->owner) {
if (isplayer(o->pile->owner)) {
msg("Your %s %s!",noprefix(obname), desc);
} else if (cansee(player, o->pile->owner)) {
char monname[BUFLEN];
getlfname(o->pile->owner, monname);
msg("%s's %s %s!",monname, noprefix(obname), desc);
}
} else if (haslos(player, o->pile->where)) {
msg("%s %s.",obname, desc);
}
}
}
// explodes?
f = hasflag(o->flags, F_EXPLODEONDEATH);
if (f) {
if (f->val[2] == B_IFACTIVATED) {
if (isactivated(o)) {
explodeob(o, f, (f->val[1] == B_BIG) ? 1 : 0);
}
} else {
explodeob(o, f, (f->val[1] == B_BIG) ? 1 : 0);
}
return;
}
if (hasflag(o->flags, F_CONTAINER)) {
// dump object's contents into parent container
while (o->contents->first) {
moveob(o->contents->first, o->pile, ALL);
}
}
// flashes?
f = hasflag(o->flags, F_FLASHONDEATH);
if (f) {
if (f->val[2] == B_IFACTIVATED) {
if (isactivated(o)) {
brightflash(getoblocation(o),f->val[0], NULL);
}
} else {
brightflash(getoblocation(o),f->val[0], NULL);
}
}
// corpse decaying and on the ground?
if ((oblastdamtype(o) == DT_DECAY) && (o->type->id == OT_CORPSE)) {
if (o->pile->where) {
int minbones,maxbones;
char bonestr[BUFLEN];
minbones = o->weight / 10;
maxbones = o->weight / 5;
if (minbones <= 0) minbones = 1;
if (maxbones <= minbones) maxbones = 2;
snprintf(bonestr, BUFLEN, "%d-%d bones",minbones,maxbones);
addob(o->pile, bonestr);
}
}
}
killob(o);
}
int obfits(object_t *o, obpile_t *op) {
if (countobs(op, B_FALSE) >= MAXPILEOBS) {
return B_FALSE;
}
if (op->owner && (getnextletter(op, NULL) == '\0')) {
reason = E_NOSPACE;
return B_FALSE;
}
if (op->parentob && (getobsize(o) > getobsize(op->parentob) )) {
reason = E_NOSPACE;
return B_FALSE;
}
return B_TRUE;
}
enum DAMTYPE oblastdamtype(object_t *o) {
flag_t *f;
f = hasflag(o->flags, F_LASTDAMTYPE);
if (f) {
return f->val[0];
}
return DT_NONE;
}
int brandappliesto(brand_t *om, objecttype_t *ot) {
if (om->bp == BP_WEAPON) {
if (ot->obclass->id == OC_WEAPON) {
return B_TRUE;
}
} else {
// TODO: how do we differentiate shields from guns?
if (hasflagval(ot->flags, F_GOESON, om->bp, NA, NA, NULL)) {
return B_TRUE;
}
}
return B_FALSE;
}
int obmatchescondition(object_t *o, long opts) {
int ok;
if (opts) {
// default to not ok
ok = B_FALSE;
} else {
// default to ok
ok = B_TRUE;
}
if ((opts & AO_ONLYEQUIPPED) && hasflag(o->flags, F_EQUIPPED)) {
ok = B_TRUE;
}
if ((opts & AO_EQUIPPEDNONWEAPON)) {
flag_t *ff;
ff = hasflag(o->flags, F_EQUIPPED);
if (ff && !isweapon(o)) {
ok = B_TRUE;
}
}
if ((opts & AO_EDIBLE) && isedible(o)) ok = B_TRUE;
if ((opts & AO_DRINKABLE) && isdrinkable(o)) ok = B_TRUE;
if ((opts & AO_READABLE) && isreadable(o)) ok = B_TRUE;
if ((opts & AO_ARMOUR) && (o->type->obclass->id == OC_ARMOUR)) ok = B_TRUE;
if (opts & AO_DAMAGED) {
if (isdamaged(o)) {
ok = B_TRUE;
}
}
if ((opts & AO_WEARABLE) && iswearable(o)) ok = B_TRUE;
if ((opts & AO_WEILDABLE) && isweapon(o)) ok = B_TRUE;
if ((opts & AO_OPERABLE) && isoperable(o)) ok = B_TRUE;
if ((opts & AO_POURABLE) && ispourable(o)) ok = B_TRUE;
if ((opts & AO_NOTIDENTIFIED) && !isidentified(o)) ok = B_TRUE;
if ((opts & AO_NOTKNOWN) && !isknown(o)) ok = B_TRUE;
if (opts & AO_SPECIFIED) {
int n;
int found = B_FALSE;
// does retlist contain this?
for (n = 0; n < nretobs; n++) {
if (retobs[n] == o) {
found = B_TRUE;
break;
}
}
if (found) {
ok = B_TRUE;
}
}
return ok;
}
// returns the amount of light produced
int obproduceslight(object_t *o) {
flag_t *f;
int amt = 0;
f = hasflag(o->flags, F_PRODUCESLIGHT);
if (f) {
int thisamt = 0;
if (f->val[2] == IFACTIVE) {
if (isactivated(o)) {
sumflags(o->flags, F_PRODUCESLIGHT, &thisamt, NULL, NULL);
}
} else {
sumflags(o->flags, F_PRODUCESLIGHT, &thisamt, NULL, NULL);
}
amt += thisamt;
}
// flaming things should produce fire
if (amt == 0) {
if (hasflag(o->flags, F_ONFIRE) || (o->material->id == MT_FIRE)) {
amt += 1;
}
}
return amt;
}
// has this object changed proerties from its
// parent objecttype?
int obpropsmatch(object_t *a, object_t *b) {
if (a->type != b->type) return B_FALSE;
if (a->material != b->material) return B_FALSE;
if (a->weight != b->weight) return B_FALSE;
if (a->inscription || b->inscription) return B_FALSE;
// only really need to check one of them, because at this point
// we know they are of the same type.
if (!hasflag(a->flags, F_NOBLESS) && !hasflag(b->flags, F_NOBLESS)) {
if (a->blessed != b->blessed) return B_FALSE;
if (isblessknown(a) != isblessknown(b)) return B_FALSE;
}
return B_TRUE;
}
flag_t *obrestrictsmovement(object_t *o, lifeform_t *lf) {
flag_t *f;
f = hasflag(o->flags, F_RESTRICTMOVEMENT);
if (f) {
if (!lf) return NULL;
if (lf) {
if ((o->type->id == OT_WEB) && (lf->race->baseid == R_SPIDER)) {
} else if ((o->type->id == OT_VINE) && hasjob(lf, J_DRUID)) {
} else if (isairborne(lf) && (f->val[2] != B_TRUE)) {
} else {
return f;
}
}
}
return NULL;
}
// returns # objects which fell through
int obsfallthrough(cell_t *c, object_t *pit) {
object_t *oo,*uphole;
cell_t *belowcell;
char obname[BUFLEN],downholename[BUFLEN],upholename[BUFLEN];
int nfallen = 0;
belowcell = getstairdestination(pit);
if (!belowcell) return 0;
uphole = hasobwithflagval(belowcell->obpile, F_PIT, D_UP, NA, NA, NULL);
getobname(pit,downholename, 1);
getobname(uphole,upholename, 1);
for (oo = c->obpile->first ; oo ; oo = oo->next) {
if (oo == pit) continue;
if (!hasflag(oo->flags, F_NOPICKUP)) {
int canseebelowlf = B_FALSE;
// fall through!
if (haslos(player, c)) {
// player can see the top of the hole
getobname(oo,obname, oo->amt);
msg("%s fall%s through %s.", obname,
(oo->amt == 1) ? "s" : "",
downholename);
}
// remember if we can see the bottom cell before the object drops
if (belowcell->lf && cansee(player, belowcell->lf)) {
canseebelowlf = B_TRUE;
}
moveob(oo, belowcell->obpile, oo->amt);
if (haslos(player, belowcell)) {
// player can see the bottom of the hole
getobname(oo,obname, oo->amt);
msg("%s fall%s through %s.", obname,
(oo->amt == 1) ? "s" : "",
upholename);
}
// does the object hit anyone?
if (belowcell->lf) {
lifeform_t *lf;
char dambuf[BUFLEN];
lf = belowcell->lf;
if (canseebelowlf) {
char lfname[BUFLEN];
getobname(oo,obname, oo->amt);
getlfname(lf, lfname);
msg("%s hit%s %s!", obname,
(oo->amt == 1) ? "s" : "",
lfname);
}
snprintf(dambuf, BUFLEN, "a falling %s", oo->type->name);
losehp(lf, getthrowdam(oo) * 6, DT_PROJECTILE, NULL, dambuf);
}
nfallen++;
}
}
return nfallen;
}
int operate(lifeform_t *lf, object_t *o, cell_t *where) {
char buf[BUFLEN],obname[BUFLEN];
int playercansee;
flag_t *f;
int willid = B_FALSE;
if (!lfhasflag(lf, F_HUMANOID) || !hasbp(lf, BP_HANDS)) {
// only humanoids can zap things
if (isplayer(lf)) {
msg("You lack the manual dexterity to operate this.");
}
return B_TRUE;
}
getobname(o, obname, 1);
if ((isplayer(lf)) || cansee(player, lf)) {
playercansee = B_TRUE;
} else {
playercansee = B_FALSE;
}
// if not a wand, must know what a tool is before you can use it
// also use the same message whn you try to operate something non-operable
// to avoid using this to identify mistletoe, etc.
if (!isoperable(o)) {
if (isplayer(lf)) {
msg("You don't know how to use %s!", obname);
}
return B_TRUE;
}
if (!isknown(o) && !hasflag(o->flags, F_OPERWITHOUTID)) {
if (isplayer(lf)) {
msg("You don't know how to use %s!", obname);
}
return B_TRUE;
}
if (gettechlevel(o->type->id) > getskill(lf, SK_TECHUSAGE)) {
if (isplayer(lf)) {
msg("This technology is beyond your understanding.");
}
return B_TRUE;
}
// has known trap?
if (isplayer(lf)) {
if (hasflagval(o->flags, F_TRAPPED, NA, NA, B_TRUE, NULL)) {
if (getattrbracket(getattr(lf, A_WIS), A_WIS, NULL) >= AT_AVERAGE) {
char ch;
snprintf(buf, BUFLEN,"Really operate %s?", obname);
ch = askchar(buf,"yn","n", B_TRUE);
if (ch != 'y') {
msg("Cancelled.");
return B_TRUE;
}
}
}
}
// objects with charges...
if (hasflag(o->flags, F_OPERUSECHARGE)) { // operating toggles on/off
int chargesleft;
chargesleft = getcharges(o);
if (chargesleft > 0) {
chargesleft = usecharge(o);
// TODO: notify if getting low
} else {
if (isplayer(lf)) {
nothinghappens();
// you know it's out
f = hasflag(o->flags, F_CHARGES);
f->known = B_TRUE;
return B_FALSE;
}
}
}
// ask for target, if required
f = hasflag(o->flags, F_OPERNEEDTARGET);
if (f && !where) {
int ttype = TT_NONE;
// don't give hints about the object
if (isknown(o)) {
ttype = f->val[0];
}
if (isplayer(lf)) {
char subprompt[BUFLEN];
snprintf(subprompt, BUFLEN, "%s->Aim->", obname);
if (strlen(f->text) > 0) {
where = askcoords(f->text, subprompt, ttype, lf, UNLIMITED, LOF_NEED, B_TRUE);
} else {
snprintf(buf, BUFLEN, "Where will you aim %s?",obname);
where = askcoords(buf, subprompt, ttype, lf, UNLIMITED, LOF_NEED, B_TRUE);
if (!haslos(lf, where)) {
msg("You can't see there!");
return B_TRUE;
}
}
} else {
char lfname[BUFLEN];
getlfname(lf, lfname);
dblog("BUG - ai (%s, id %d) using wand (%s) without target.",
lfname, lf->id, obname);
where = NULL;
}
if (!where) {
// cancel.
if (isplayer(lf)) msg("Cancelled.");
return B_TRUE;
} else {
if (f->val[1] != NA) {
cell_t *newwhere = NULL;
if ((f->val[1] & TR_NEEDLOS) && !haslos(lf, where)) {
if (isplayer(lf)) msg("You can't see there!");
return B_TRUE;
}
if ((f->val[1] & TR_NEEDLOF) && !haslof(lf->cell, where, B_TRUE, &newwhere)) {
if (newwhere) {
// update destination
where = newwhere;
} else {
if (isplayer(lf)) msg("You have no line of fire to there!");
return B_TRUE;
}
}
}
}
}
f = hasflag(o->flags, F_OPERNEEDDIR);
if (f) {
char ch;
int dir;
// ask direction
ch = askchar(f->text, "yuhjklbn-","-", B_FALSE);
if (ch == '-') {
msg("Cancelled.");
return B_TRUE;
} else {
dir = chartodir(ch);
where = getcellindir(lf->cell, dir);
}
}
if (touch(lf, o)) {
return B_TRUE;
}
if (hasflag(o->flags, F_DEAD)) return B_TRUE;
// TODO: change to be based on item type
// TODO: move this to the end in case 'operate' fails
taketime(lf, getactspeed(lf));
// mark obejct as tried
maketried(o->type->id);
// trapped?
if (doobtraps(o, lf)) {
return B_TRUE;
}
/*
if (lf->controller != C_PLAYER) {
if (haslos(player, lf->cell)) {
getlfname(lf, buf);
capitalise(buf);
msg("%s operates %s.", buf, obname);
}
}
*/
if (hasflag(o->flags, F_CONTAINER) && (o->type->id != OT_VENDINGMACHINE)) { // loot it
if (isplayer(lf)) { // only player can loot.
char ch;
snprintf(buf, BUFLEN, "Looting %s. Will you:",obname);
initprompt(&prompt, buf);
if (countobs(lf->pack, B_FALSE)) {
snprintf(buf, BUFLEN, "Put items in %s",obname);
addchoice(&prompt, 'i', buf, NULL, NULL);
}
if (countobs(o->contents, B_FALSE)) {
snprintf(buf, BUFLEN, "Take items out of %s",obname);
addchoice(&prompt, 'o', buf, NULL, NULL);
}
snprintf(buf, BUFLEN, "Both");
addchoice(&prompt, 'b', buf, NULL, NULL);
snprintf(buf, BUFLEN, "Neither");
addchoice(&prompt, 'n', buf, NULL, NULL);
ch = getchoice(&prompt);
switch (ch) {
case 'i':
dodrop(player->pack, B_MULTIPLE, o->contents);
break;
case 'o':
dopickup(o->contents, B_TRUE);
break;
case 'b':
dodrop(player->pack, B_MULTIPLE, o->contents);
dopickup(o->contents, B_TRUE);
break;
case 'n':
msg("Cancelled.");
return B_FALSE;
}
}
} else if (hasflag(o->flags, F_OPERONOFF)) { // operating toggles on/off
if (isactivated(o)) {
turnoff(lf, o);
} else {
turnon(lf, o);
}
} else if (hasflag(o->flags, F_FIREARM)) { // special case - change ammo
object_t *oo;
// construct list of possible ammo
clearretobs();
for (oo = lf->pack->first ; oo ; oo = oo->next) {
if (isammofor(oo->type, o)) {
retobs[nretobs] = oo;
nretobs++;
}
}
if (nretobs <= 0) {
snprintf(buf, BUFLEN, "You have no ammo for your %s!",noprefix(obname));
msg(buf);
return B_TRUE;
} else {
snprintf(buf, BUFLEN, "Load %s with what ammo",obname);
oo = askobject(lf->pack, buf, NULL, AO_SPECIFIED);
if (oo) {
loadfirearm(lf, o, oo);
}
}
} else if (o->type->obclass->id == OC_WAND) {
if (!isplayer(lf) && cansee(player, lf)) {
char lfname[BUFLEN];
getlfname(lf, lfname);
msg("%s zaps %s.",lfname,obname);
}
f = hasflag(o->flags, F_LINKSPELL);
if (f) {
enum OBTYPE spelltocast;
int power;
enum SKILLLEVEL chanlev;
spelltocast = f->val[0];
power = f->val[1];
if (power == NA) power = 1;
if (isblessed(o)) power += 4;
// increase based on your magic item usage skill
chanlev = getskill(lf, SK_CHANNELING);
power += chanlev;
if (chanlev >= PR_ADEPT) power += (chanlev - 2);
// certain wands always used the blessed version of spells
// certain wands have different effects when cursed
switch (o->type->id) {
case OT_WAND_LIGHT:
if (iscursed(o)) {
spelltocast = OT_S_DARKNESS;
}
break;
default:
break;
}
dospelleffects(lf, spelltocast, power, where ? where->lf : NULL, NULL, where, isblessed(o), &willid, B_FALSE);
// special wands
} else if (o->type->id == OT_WAND_WONDER) {
int power;
// random power
power = rnd(1,10);
// 1 in 3 chance of targetting yourself
if (onein(3)) {
where = lf->cell;
}
// random effect
switch (rnd(0,21)) {
case 0: // butterflies around user
willid = B_TRUE;
where = getrandomadjcell(lf->cell, WE_WALKABLE, B_ALLOWEXPAND);
addmonster(where, R_BUTTERFLY, NULL, B_FALSE, rnd(10,20), B_FALSE, NULL);
if (haslos(player, where)) {
msg("A swarm of butterflies appears!");
}
break;
case 1: // summon monster
dospelleffects(lf, OT_S_CREATEMONSTER, rnd(1,4), NULL, NULL, NULL, B_UNCURSED, &willid, B_FALSE);
break;
case 2: // animate dead
dospelleffects(lf, OT_S_ANIMATEDEAD, power, where ? where->lf : NULL, NULL, where, B_UNCURSED, &willid, B_FALSE);
break;
case 3: // blindness
dospelleffects(lf, OT_S_BLINDNESS, power, where ? where->lf : NULL, NULL, where, B_UNCURSED, &willid, B_FALSE);
break;
case 4: // levitate
dospelleffects(lf, OT_S_LEVITATION, power, where ? where->lf : NULL, NULL, where, B_UNCURSED, &willid, B_FALSE);
break;
case 5: // dispersal
dospelleffects(lf, OT_S_DISPERSAL, power, where ? where->lf : NULL, NULL, where, o->blessed, &willid, B_FALSE);
break;
case 6: // flash
dospelleffects(lf, OT_S_FLASH, power, where ? where->lf : NULL, NULL, where, o->blessed, &willid, B_FALSE);
break;
case 7: // light
dospelleffects(lf, OT_S_LIGHT, power, where ? where->lf : NULL, NULL, where, B_UNCURSED, &willid, B_FALSE);
break;
case 8: // heal
dospelleffects(lf, OT_S_HEALING, power, where ? where->lf : NULL, NULL, where, B_UNCURSED, &willid, B_FALSE);
break;
case 9: // minor heal
dospelleffects(lf, OT_S_HEALINGMIN, power, where ? where->lf : NULL, NULL, where, B_UNCURSED, &willid, B_FALSE);
break;
case 10: // invis
dospelleffects(lf, OT_S_INVISIBILITY, power, where ? where->lf : NULL, NULL, where, B_UNCURSED, &willid, B_FALSE);
break;
case 11: // haste
dospelleffects(lf, OT_S_HASTE, power, where ? where->lf : NULL, NULL, where, B_UNCURSED, &willid, B_FALSE);
break;
case 12: // pull
dospelleffects(lf, OT_S_SUCK, power, where ? where->lf : NULL, NULL, where, o->blessed, &willid, B_FALSE);
break;
case 13: // blast
dospelleffects(lf, OT_S_AIRBLAST, power, where ? where->lf : NULL, NULL, where, B_UNCURSED, &willid, B_FALSE);
break;
case 14: // slow
dospelleffects(lf, OT_S_SLOW, power, where ? where->lf : NULL, NULL, where, o->blessed, &willid, B_FALSE);
break;
case 15: // sleep
dospelleffects(lf, OT_S_SLEEP, power, where ? where->lf : NULL, NULL, where, o->blessed, &willid, B_FALSE);
break;
case 16: // gas
dospelleffects(lf, OT_S_CLOUDKILL, power, where ? where->lf : NULL, NULL, where, o->blessed, &willid, B_FALSE);
break;
case 17: // dark
dospelleffects(lf, OT_S_DARKNESS, power, where ? where->lf : NULL, NULL, where, B_UNCURSED, &willid, B_FALSE);
break;
case 18: // stone
dospelleffects(lf, OT_S_PETRIFY, power, where ? where->lf : NULL, NULL, where, o->blessed, &willid, B_FALSE);
break;
case 19: // fireball
dospelleffects(lf, OT_S_FIREBALL, power, where ? where->lf : NULL, NULL, where, o->blessed, &willid, B_FALSE);
break;
case 20: // poly
dospelleffects(lf, OT_S_POLYMORPH, power, where ? where->lf : NULL, NULL, where, o->blessed, &willid, B_FALSE);
break;
case 21: // teleport
dospelleffects(lf, OT_S_TELEPORT, power, lf , NULL, lf->cell, o->blessed, &willid, B_FALSE);
break;
//oooooooooo
}
}
if (!isknown(o) && willid) {
if (isplayer(lf) || cansee(player, lf)) {
// tell player
makeknown(o->type->id);
if (iscursed(o)) {
o->blessknown = B_TRUE;
}
if (isplayer(lf)) {
real_getobname(o, obname, 1, B_FALSE, B_TRUE, B_FALSE, B_TRUE, B_FALSE); // don't adjust for blindness
msg("This is %s!",obname);
}
}
}
// FROM HERE ON ARE INDIVIDUAL ONES
} else if (o->type->id == OT_GODSTONEJ) {
f = hasflag(o->flags, F_CHARGES);
if (f && (f->val[0] == f->val[1])) {
int x,y;
// announce
if (isplayer(lf)){
msg("Your %s unleashes a blast of power!", noprefix(obname));
} else if (cansee(player, lf)) {
char lfname[BUFLEN];
getlfname(lf, lfname);
msg("%s%s %s unleashes a blast of power!", lfname, getpossessive(lfname), noprefix(obname));
}
noise(lf->cell, NULL, NC_OTHER, 10, "an ear-splitting crack", NULL);
// everyone in lof drops to same hp as user
for (y = 0; y < lf->cell->map->h; y++) {
for (x = 0; x < lf->cell->map->w; x++) {
cell_t *c;
c = getcellat(lf->cell->map, x, y);
if (c && c->lf && (c->lf != lf) && haslof(lf->cell, c, LOF_NEED, NULL)) {
c->lf->hp = lf->hp;
if (isplayer(c->lf)) {
msg("You are blasted with the power of justice!");
} else if (cansee(player, c->lf)) {
char lfname[BUFLEN];
getlfname(c->lf, lfname);
msg("%s is blasted with the power of justice!", lfname);
}
}
}
}
f->val[0] = 0; // use up all charges
} else {
if (isplayer(lf)) {
nothinghappens();
}
}
taketime(lf, getactspeed(lf));
} else if (o->type->id == OT_INSECTICIDE) {
int seen = B_FALSE;
// if above half charges, big spray
f = hasflag(o->flags, F_CHARGES);
if (f->val[0] >= (f->val[1] / 2)) {
// big spray
int dir;
cell_t *c;
for (dir = DC_N; dir <= DC_W; dir += 2) {
c = getcellindir(where, dir);
if (c && cellwalkable(NULL, c, NULL)) {
o = addob(c->obpile, "puff of gas");
}
}
// big spray
addob(where->obpile, "cloud of poison gas");
if (isplayer(lf)) {
msg("Psssssssst!");
seen = B_TRUE;
} else if (cansee(player, lf)) {
getlfname(lf, buf);
msg("%s%s %s emits a spray of gas.", buf, getpossessive(buf), noprefix(obname));
seen = B_TRUE;
}
} else {
// little spray
addob(where->obpile, "puff of gas");
if (isplayer(lf)) {
msg("Psst!");
seen = B_TRUE;
} else if (cansee(player, lf)) {
getlfname(lf, buf);
msg("%s%s %s emits a puff of gas.", buf, getpossessive(buf), noprefix(obname));
seen = B_TRUE;
}
}
// announce
if (!seen) {
noise(where, NULL, NC_OTHER, 0, "something spraying.", NULL);
}
} else if ((o->type->id == OT_EMPTYFLASK) || (o->type->id == OT_EMPTYVIAL)) {
object_t *oo,*nextoo;
if (isplayer(lf)) {
int donedip = B_FALSE;
// anything here to fill with?
for (oo = lf->cell->obpile->first ; (oo && !donedip); oo = nextoo) {
int dippable = B_FALSE;
nextoo = oo->next;
switch (oo->type->id) {
case OT_BLOODSPLASH:
case OT_SPLASHWATER:
if (oo->amt >= 5) {
dippable = B_TRUE;
}
break;
case OT_BLOODPOOL:
case OT_PUDDLEWATER:
case OT_PUDDLEWATERL:
case OT_FOUNTAIN:
dippable = B_TRUE;
break;
default:
break;
}
if (dippable) {
char ch;
char ques[BUFLEN];
char liquidname[BUFLEN];
int autoid = B_FALSE;
object_t *newob;
getobname(oo, liquidname, 1);
snprintf(ques, BUFLEN, "Fill your %s from %s?", noprefix(obname), liquidname);
ch = askchar(ques, "yn", "y", B_TRUE);
if (ch == 'y') {
char newobname[BUFLEN];
if (oo->type->id == OT_FOUNTAIN) {
objecttype_t *ot;
// same type as fountain
f = hasflag(oo->flags, F_LINKOB);
ot = findot(f->val[0]);
strcpy(newobname, ot->name);
// if you knew what the fountain was, you'll
// know what the potion object is.
if (f->val[2] == B_TRUE) autoid = B_TRUE;
} else {
switch (oo->material->id) {
case MT_BLOOD:
strcpy(newobname, "potion of blood");
break;
case MT_WATER:
strcpy(newobname, "potion of water");
break;
default:
strcpy(newobname, "");
break;
}
}
if (strlen(newobname)) {
// kill the empty flask
removeob(o, 1);
// give the new potion
newob = addob(lf->pack, newobname);
if (newob) {
if (autoid) makeknown(newob->type->id);
// overwrite newobname
getobname(newob, newobname, newob->amt);
msgnocap("%c - %s.",newob->letter, newobname);
}
// kill the ground object?
switch (oo->type->id) {
case OT_SPLASHWATER:
case OT_BLOODSPLASH:
removeob(oo, 5);
break;
case OT_PUDDLEWATER:
removeob(oo, 1);
break;
case OT_FOUNTAIN:
if (onein(ONEIN_FOUNTAINDRYUP)) {
cell_t *loc;
loc = getoblocation(oo);
if (haslos(player, loc)) {
char fname[BUFLEN];
getobname(oo, fname, oo->amt);
msg("%s dries up.", obname);
}
removeob(oo, oo->amt);
}
break;
default:
break;
}
} else {
msg("That doesn't seem like a very good idea.");
}
donedip = B_TRUE;
} // if (ch == y)
}
}
if (!donedip) {
msg("There is nothing here to fill your %s from.",noprefix(obname));
}
}
} else if (o->type->id == OT_MISTLETOE) {
if (hasjob(lf, J_DRUID)) {
int amt;
if (isplayer(lf)) {
msg("You sacrifice %s.", obname);
} else if (cansee(player, lf)) {
char lfname[BUFLEN];
getlfname(lf, lfname);
msg("%s sacrifices %s.", lfname, obname);
}
removeob(o, 1);
// regain mp
amt = getspellduration(getmaxmp(lf)/2, getmaxmp(lf), o->blessed);
if (amt > 0) {
if (isplayer(lf)) {
msg("You feel a surge of magical power!");
}
gainmp(lf, amt);
}
} else {
if (isplayer(lf)) {
msg("You don't know how to use this.");
}
}
} else if (o->type->id == OT_ORBDUNGEONEXIT) {
map_t *m;
m = lf->cell->map;
if ((m->region->rtype->id == RG_FIRSTDUNGEON) && (m->depth == 1)) {
cell_t *cell[MAXCANDIDATES];
int ncells,i;
getradiuscells(lf->cell, 1, DT_COMPASS, B_FALSE, B_TRUE, cell, &ncells, B_FALSE);
for (i = 0; i < ncells; i++) {
if (hasob(cell[i]->obpile, OT_STAIRSUP)) {
object_t *o;
o = hasob(cell[i]->obpile, OT_MAGICBARRIER);
if (o) {
addflag(o->flags, F_DEAD, B_TRUE, NA, NA, NULL);
}
}
}
} else {
if (isplayer(lf)) {
nothinghappens();
}
}
} else if (o->type->id == OT_POCKETWATCH) {
if (isplayer(lf)) {
if (haslos(lf, lf->cell)) {
// if above ground, use wantpm (ie. can see the sun)
gettimetextfuzzy(buf, isoutdoors(lf->cell->map) ? B_TRUE : B_FALSE);
msg("It is currently %s.",buf);
} else {
msg("You cannot see!");
}
} else if (cansee(player, lf)) {
getlfname(lf, buf);
msg("%s looks at %s.",buf, obname);
}
} else if (o->type->id == OT_DIGITALWATCH) {
if (isplayer(lf)) {
if (haslos(lf, lf->cell)) {
gettimetext(buf);
msg("It is currently %s.",buf);
} else {
msg("You cannot see!");
}
} else if (cansee(player, lf)) {
getlfname(lf, buf);
capitalise(buf);
msg("%s looks at %s.",buf, obname);
}
} else if ((o->type->id == OT_LOCKPICK)
|| (o->type->id == OT_PAPERCLIP)
|| (o->type->id == OT_CREDITCARD)) {
char ch;
int dir;
// ask direction
ch = askchar("Lockpick in which direction (- to cancel)", "yuhjklbn-","-", B_FALSE);
dir = chartodir(ch);
if (dir == D_NONE) {
clearmsg();
return B_TRUE;
} else {
cell_t *c;
c = getcellindir(player->cell, dir);
if (c) {
object_t *targ;
// something to lockpick there?
targ = hasobwithflag(c->obpile, F_LOCKED);
if (targ) {
lockpick(player, targ, o);
} else {
// fail
msg("There is nothing locked there!");
}
} else {
clearmsg();
return B_TRUE;
}
}
} else if (o->type->id == OT_LOCKHACKER) {
char ch;
int dir;
// ask direction
ch = askchar("Manipulate lock in which direction (- to cancel)", "yuhjklbn-","-", B_FALSE);
dir = chartodir(ch);
if (dir == D_NONE) {
clearmsg();
return B_TRUE;
} else {
cell_t *c;
c = getcellindir(lf->cell, dir);
if (c) {
object_t *oo,*nextoo;
// lock/unlock everything there
for (oo = c->obpile->first ; oo ; oo = nextoo) {
nextoo = oo->next;
if (hasflag(oo->flags, F_LOCKABLE)) {
flag_t *f;
f = hasflag(oo->flags, F_LOCKED);
if (f) {
killflag(f);
if (isplayer(lf)) {
msg("Your %s beeps.", noprefix(obname));
} else if (cansee(player, lf)) {
char lfname[BUFLEN];
getlfname(lf, lfname);
msg("%s%s %s beeps.", lfname, getpossessive(lfname),
noprefix(obname));
}
} else {
addflag(oo->flags, F_LOCKED, B_TRUE, 20, NA, NULL);
if (isplayer(lf)) {
msg("Your %s buzzes.", noprefix(obname));
} else if (cansee(player, lf)) {
char lfname[BUFLEN];
getlfname(lf, lfname);
msg("%s%s %s buzzes.", lfname, getpossessive(lfname),
noprefix(obname));
}
}
}
}
} else {
clearmsg();
return B_TRUE;
}
}
} else if (o->type->id == OT_PANPIPES) {
// announce
if (isplayer(lf)) {
msg("You play a few notes on your panpipes.");
} else {
noise(lf->cell, lf, NC_OTHER, 3, "the sound of panpipes.", "plays a tune on its panpipes.");
}
} else if (o->type->id == OT_PICKAXE) {
int ch,dir;
cell_t *c;
ch = askchar("Dig in which direction (- to cancel)", "yuhjklbn><-","-", B_FALSE);
if (ch == '-') {
// cancel
clearmsg();
return B_TRUE;
} else if (ch == '>') {
if (digdown(lf, o)) {
// failed
return B_TRUE;
}
} else if (ch == '<') {
if (digup(lf, o)) {
// failed
return B_TRUE;
}
} else {
dir = chartodir(ch);
c = getcellindir(lf->cell, dir);
if (digcell(lf, c, o)) {
// failed
return B_TRUE;
}
} // end if ch is a direction
} else if (o->type->id == OT_SPANNER) {
int donesomething = B_FALSE;
if (!where) {
if (isplayer(lf)) msg("There is nothing to use your spanner on there!");
} else {
object_t *o;
char ch;
flag_t *f;
for (o = where->obpile->first ; o ; o = o->next) {
int isopen;
if (isdoor(o, &isopen)) {
if (!isopen) { // ie. if closed.
f = hasflag(o->flags, F_JAMMED);
if (f) {
ch = askchar("The hinges seem jammed. Loosen them", "yn", "y", B_TRUE);
if (ch == 'y') {
char obname[BUFLEN];
getobname(o, obname, 1);
msg("You loosen the hinges on %s.", obname);
killflag(f);
taketime(lf, getactspeed(lf));
donesomething = B_TRUE;
}
} else {
char obname[BUFLEN];
getobname(o, obname, 1);
snprintf(buf, BUFLEN, "Tighten the hinges on %s",obname);
ch = askchar(buf, "yn", "y", B_TRUE);
if (ch == 'y') {
msg("You tighten the hinges on %s.", obname);
addflag(o->flags, F_JAMMED, rnd(1,10), NA, NA, NULL);
taketime(lf, getactspeed(lf));
donesomething = B_TRUE;
}
}
}
}
}
}
if (!donesomething) {
if (isplayer(lf)) msg("There is nothing to use your spanner on there!");
}
} else if (o->type->id == OT_TELEPAD) {
map_t *m;
cell_t *c,*dst = NULL;
int x,y;
int closest = 99999;
m = lf->cell->map;
// find closest pad
for (y = 0; y < m->h; y++) {
for (x = 0; x < m->w; x++) {
c = getcellat(m, x, y);
if (hasob(c->obpile, OT_TELEPAD)) {
int thisdist;
thisdist = getcelldist(lf->cell, c);
if (thisdist < closest) {
closest = thisdist;
dst = c;
}
}
}
}
if (dst) {
// teleport there
teleportto(lf, dst, B_TRUE);
} else {
// nothing happens
if (isplayer(lf)) {
nothinghappens();
}
}
} else if (o->type->id == OT_TOWEL) {
object_t *oo;
if (isplayer(lf)) {
msg("You dry yourself off with %s.", obname);
} else if (cansee(player, lf)) {
char lfname[BUFLEN];
getlfname(lf, lfname);
msg("%s dries itself off with %s.", lfname, obname);
}
// make objects dry
for (oo = lf->pack->first ;oo ; oo = oo->next) {
if (isequipped(oo)) {
killflagsofid(oo->flags, F_WET);
}
}
taketime(lf, getactspeed(lf));
} else if (o->type->id == OT_VENDINGMACHINE) {
if (isplayer(lf)) {
dovendingmachine(lf, o);
restoregamewindows();
} else {
if (cansee(player, lf)) {
char lfname[BUFLEN];
getlfname(lf, lfname);
msg("%s fiddles with %s.", lfname, obname);
}
}
taketime(lf, getactspeed(lf));
}
return B_FALSE;
}
int pilehasletter(obpile_t *op, char let) {
object_t *o;
int found = B_FALSE;
for (o = op->first ; o ; o = o->next) {
if (o->letter == let) {
found = B_TRUE;
break;
}
}
return found;
}
int pour(lifeform_t *lf, object_t *o) {
char buf[BUFLEN],obname[BUFLEN],lfname[BUFLEN],dstname[BUFLEN];
int playercansee;
char ch;
object_t *dst = NULL;
int doneask = B_FALSE;
getobname(o, obname, 1);
getlfname(lf, lfname);
if (isplayer(lf) || cansee(player, lf)) {
playercansee = B_TRUE;
} else {
playercansee = B_FALSE;
}
// adjacent to a closed door?
if (isplayer(lf)) {
int d;
for (d = DC_N; d <= DC_NW; d++) {
cell_t *c;
c = getcellindir(lf->cell, d);
if (c) {
object_t *door;
door = hasobwithflag(c->obpile, F_DOOR);
if (door) {
snprintf(buf, BUFLEN, "Pour %s onto the door to the %s", obname, getdirname(d));
ch = askchar(buf, "yn", "n", B_TRUE);
if (ch == 'y') {
// finished asking where to pour
doneask = B_TRUE;
dst = door;
}
}
}
}
}
if (!doneask) {
// tip onto what?
snprintf(buf, BUFLEN, "Pour %s onto the ground", obname);
ch = askchar(buf, "yn", "y", B_TRUE);
if (ch == 'y') {
dst = NULL;
} else {
snprintf(buf, BUFLEN, "Pour %s onto what", obname);
// tip onto another object
dst = askobject(lf->pack, buf, NULL, AO_NONE);
if (!dst) {
msg("Cancelled.");
return B_TRUE;
} else if (dst->type->obclass->id == OC_POTION) {
getobname(dst, buf, dst->amt);
msg("%s can't hold any more liquid!",buf);
return B_TRUE;
}
}
}
taketime(lf, SPEED_MOVE);
if (dst) {
cell_t *dstloc;
flag_t *refillflag;
dstloc = getoblocation(dst);
// pour 'o' onto 'dst'
getobname(dst, dstname, dst->amt);
// specal cases first...
refillflag = hasflag(dst->flags, F_REFILLWITH);
if (refillflag) {
flag_t *f;
if (refillflag->val[0] == o->type->id) {
// refill destination
f = hasflag(dst->flags, F_CHARGES);
if (f) {
f->val[0] = f->val[1];
if (isplayer(lf)) {
msg("You refill your %s.", noprefix(dstname));
// we now know what the potion was
if (!isknown(o)) makeknown(o->type->id);
} else if (cansee(player, lf)) {
msg("%s refills %s with %s.", lfname, dstname, obname);
// we now know what the potion was
if (!isknown(o)) makeknown(o->type->id);
}
}
} else {
// nothing happens
if (isplayer(lf)) {
msg("You refill your %s with %s. It doesn't seem to do much.", obname);
} else if (cansee(player, lf)) {
msg("%s refills %s with %s.", lfname, dstname, obname);
}
}
} else if ((o->type->id == OT_POT_WATER) && (o->blessed == B_BLESSED)) { // holy water!
if (isplayer(lf)) {
msg("You pour %s onto %s.", obname,dstname);
}
o->blessknown = B_TRUE;
// bless whatever we poured onto
blessob(dst);
// we now know that this is holy water
if (!isknown(o)) makeknown(o->type->id);
// god effects
if (isplayer(lf)) {
pleasegodmaybe(R_GODPURITY, 3);
angergodmaybe(R_GODDEATH, 15);
}
} else if ((o->type->id == OT_POT_WATER) && (o->blessed == B_CURSED)) { // unholy water
if (isplayer(lf)) {
msg("You pour %s onto %s.", obname,dstname);
}
o->blessknown = B_TRUE;
// curse whatever we poured onto
curseob(dst);
// we now know that this is holy water
if (!isknown(o)) makeknown(o->type->id);
// god effects
if (isplayer(lf)) {
pleasegodmaybe(R_GODDEATH, 3);
angergodmaybe(R_GODPURITY, 25);
}
} else if (o->type->id == OT_POT_INVULN) {
flag_t *f;
f = hasflag(dst->flags, F_DAMAGABLE);
if (f) {
if (isplayer(lf)) {
msg("Your %s looks invulnerable!",noprefix(dstname));
if (!isknown(o)) makeknown(o->type->id);
appendinscription(dst, "invuln");
}
killflag(f);
}
} else if (o->type->id == OT_POT_RESTORATION) {
flag_t *f, *nextf;
if (isplayer(lf)) {
msg("Your %s looks as good as new!",noprefix(dstname));
}
// restore orig material
if (dst->material != dst->type->material) {
changemat(dst, dst->type->material->id);
}
// remove blessings/curses
setblessed(dst, B_UNCURSED);
dst->blessknown = B_TRUE;
// remove bonuses
killflagsofid(dst->flags, F_BONUS);
// remove temporary flags, obmod flags and modify some others
for (f = dst->flags->first ; f ; f = nextf) {
nextf = f->next;
if (f->lifetime > 0) {
killflag(f);
} else if (f->lifetime == FROMOBMOD) {
killflag(f);
} else if (f->id == F_FROZEN) {
killflag(f);
} else if (f->id == F_ONFIRE) {
killflag(f);
} else if (f->id == F_POISONED) {
killflag(f);
} else if (f->id == F_OBHP) {
f->val[0] = f->val[1];
}
}
// we now know what the potion was
if (!isknown(o)) makeknown(o->type->id);
//if (!isknown(dst)) makeknown(dst->type->id);
} else if (o->type->id == OT_POT_ACID) {
// damage destinaiton
msg("You pour %s onto %s.", obname,dstname);
takedamage(dst, rnd(5,15), DT_ACID);
makeknown(o->type->id);
} else if (isdoor(dst, NULL)) {
msg("Your pour %s all over %s.", obname, dstname);
if (o->type->id == OT_POT_OIL) {
flag_t *f;
// unjam doors
f = hasflag(dst->flags, F_JAMMED);
if (f) {
killflag(f);
}
}
} else { // default
if (isplayer(lf)) {
msg("You pour %s onto %s.", obname,dstname);
if (!hasflag(dst->flags, F_CANGETWET)) {
msg("%s gets wet.", dstname);
// if it DOES have this flag, then we'll announce this
// during takedamage.
}
}
takedamage(dst, 0, DT_WATER);
}
} else {
flag_t *f;
// pour onto ground
if (isplayer(lf)) {
msg("You pour %s onto the ground.", obname);
} else if (haslos(player, lf->cell)) {
msg("%s pours %s onto the ground.", lfname, obname);
}
f = hasflag(o->flags, F_DIECONVERT);
if (f) {
addob(lf->cell->obpile, f->text);
} else {
if (haslos(player, lf->cell)) {
msg("The contents evaporate.");
}
}
}
// empty the flask
addemptyob(lf->pack, o);
// remove src
removeob(o, 1);
return B_FALSE;
}
void quaff(lifeform_t *lf, object_t *o) {
char buf[BUFLEN],obname[BUFLEN];
int willid = B_FALSE;
int playercansee;
int forcedrop = B_FALSE;
int seen;
int killobwhendone = B_TRUE;
flag_t *drinkflag;
enum OBTYPE realobid = OT_NONE;
getobname(o, obname, 1);
if (isplayer(lf) || cansee(player, lf)) {
playercansee = B_TRUE;
} else {
playercansee = B_FALSE;
}
taketime(lf, getactspeed(lf));
if (o->type->id == OT_FOUNTAIN) {
flag_t *f;
// ie if not already identified...
f = hasflag(o->flags, F_LINKOB);
realobid = f->val[0];
} else {
realobid = o->type->id;
}
maketried(realobid);
if (touch(lf, o)) {
return;
}
if (hasflag(o->flags, F_DEAD)) return;
if (o->material->id == MT_ICE) {
if (isplayer(lf)) {
msg("You can't drink this, it's frozen!");
}
return;
}
if (lf->controller != C_PLAYER) {
if (cansee(player, lf)) {
getlfname(lf, buf);
capitalise(buf);
msg("%s drinks %s!", buf, obname);
}
}
// figure out whether to id the object
willid = B_FALSE;
if (playercansee) {
if (o->type->id == OT_FOUNTAIN) {
flag_t *f;
f = hasflag(o->flags, F_LINKOB);
if (f->val[2] == B_TRUE) {
// fountain which is already identified
willid = B_FALSE;
}
// otherwise identify based on potion effects...
}
switch (realobid) {
case OT_NONE:
willid = B_FALSE;
break;
case OT_POT_HEALING:
case OT_POT_HEALINGMIN:
if (lf->hp < lf->maxhp) {
willid = B_TRUE;
}
break;
case OT_FOUNTAIN:
break;
default:
willid = B_TRUE;
break;
}
}
if (willid) {
makeknown(realobid);
if (o->type->id == OT_FOUNTAIN) {
// refresh fountain name
getobname(o, obname, 1);
if (isplayer(lf)) {
// tell the player
msg("This is %s!",obname);
more();
drawmsg();
}
} else if (!isknown(o)) {
real_getobname(o, obname, 1, B_FALSE, B_TRUE, B_FALSE, B_FALSE, B_FALSE); // don't adjust for blindness
if (isplayer(lf)) {
// tell the player
msg("This is %s!",obname);
more();
drawmsg();
}
}
}
if (o->type->obclass->id == OC_POTION) {
potioneffects(lf, o->type->id, o, o->blessed, &seen);
} else {
drinkflag = hasflag(o->flags, F_DRINKABLE);
if (drinkflag) {
// this is a drinkable thing which isn't a potion
flag_t *f;
f = hasflag(o->flags, F_LINKOB);
if (f) {
potioneffects(lf, f->val[0], o, o->blessed, NULL);
} else {
eat(lf, o);
}
// fountains sometimes dry up
if ((o->type->id == OT_FOUNTAIN) && onein(ONEIN_FOUNTAINDRYUP)) {
cell_t *loc;
// dry up (ie. remove DONTKILL property)
drinkflag->val[2] = NA;
loc = getoblocation(o);
if (haslos(player, loc)) {
msg("%s dries up.", obname);
}
}
if (drinkflag->val[2] == B_DONTKILL) {
killobwhendone = B_FALSE;
}
}
}
if (seen) {
o->blessknown = B_TRUE;
makeknown(o->type->id);
}
if (forcedrop) {
// try to add an empty container to the ground
addemptyob(lf->cell->obpile, o);
} else {
// try to add an empty container to our pack
addemptyob(lf->pack, o);
}
if (killobwhendone) {
// remove the potion (or whatever it is)
removeob(o, 1);
}
}
// o can be NULL if we're just doing potion EFFECTS, not actually drinking one.
void potioneffects(lifeform_t *lf, enum OBTYPE oid, object_t *o, enum BLESSTYPE potblessed, int *seen) {
char lfname[BUFLEN];
unsigned int dam;
int i;
int first,dir;
int amt;
int failed;
int seenbyplayer;
int hpheal,mpheal;
flag_t *f;
if (isplayer(lf)) {
seenbyplayer = B_TRUE;
} else if (cansee(player, lf)) {
seenbyplayer = B_TRUE;
} else {
seenbyplayer = B_FALSE;
}
if (seen) {
*seen = seenbyplayer;
}
getlfname(lf, lfname);
switch (oid) {
case OT_POT_ACID:
dam = rnd(5,10);
losehp(lf, dam, DT_ACID, NULL, "drinking acid");
if (isplayer(lf)) {
msg("Your suffer massive internal burning!");
} else if (cansee(player, lf)) {
msg("%s writhes in agony!", lfname);
}
break;
case OT_POT_ACROBATICS:
if (getmr(lf) && skillcheck(lf, SC_RESISTMAG, 30, 0)) {
if (isplayer(lf)) {
msg("You feel momentarily jumpy.");
}
break;
}
// how long for?
i = geteffecttime(5,10, potblessed);
if (lfhasflagval(lf, F_CANWILL, OT_A_JUMP, NA, NA, NULL)) {
nothinghappens();
seenbyplayer = B_FALSE;
if (seen) *seen = B_FALSE;
} else {
addtempflag(lf->flags, F_CANWILL, OT_A_JUMP, NA, NA, NULL, i);
}
break;
case OT_POT_AMBROSIA:
// fix hunger
i = gethungerlevel(gethungerval(lf));
if (i > 0) {
modhunger(lf, -i);
}
// fix hp
if (lf->hp < lf->maxhp) {
gainhp(lf, lf->maxhp); // ie. full hp
if (isplayer(lf)) {
msg("You feel completely healed!");
} else if (cansee(player, lf)) {
msg("%s looks completely healed!", lfname);
}
} else {
if (isplayer(lf)) {
msg("This makes you feel incredible!");
}
}
break;
case OT_POT_COFFEE:
if (isplayer(lf)) {
msg("This tastes like coffee.");
}
// sates hunger a tiny bit
modhunger(lf, -pctof(10, (float)HUNGERCONST));
// sobers you up
killtransitoryflags(lf->flags, F_DRUNK);
// no more sleeping for a while!
addtempflag(lf->flags, F_CAFFEINATED, B_TRUE, NA, NA, NULL,rnd(30,60));
break;
case OT_POT_COMPETENCE:
failed = B_TRUE;
if (getmr(lf) && skillcheck(lf, SC_RESISTMAG, 30, 0)) {
if (isplayer(lf)) {
msg("You feel momentarily %s.", (potblessed == B_CURSED) ? "incompetent" : "more competent");
}
break;
}
if (potblessed == B_CURSED) {
amt = -1;
} else {
amt = 1;
}
// select a random attribute
if (potblessed == B_BLESSED) {
// modify all attributes
for (i = 0; i < MAXATTS; i++) {
if (!modattr(lf, i, amt)) failed = B_FALSE;
}
} else {
enum ATTRIB a;
// modify just one attribute
a = rnd(0,MAXATTS);
if (!modattr(lf, a, amt)) failed = B_FALSE;
}
if (failed) {
if (isplayer(lf)) {
nothinghappens();
}
if (seen) *seen = B_FALSE;
} else {
if (seen) *seen = B_TRUE;
}
break;
case OT_POT_RUM:
// kill coffee flags
killtransitoryflags(lf->flags, F_CAFFEINATED);
if (lfhasflag(lf, F_CAFFEINATED)) {
// ie. conferred by something equipped etc
if (isplayer(lf)) {
msg("For some reason, the alcohol has no effect on you.");
}
} else {
// get drunk(er)
f = lfhasflag(lf, F_DRUNK);
if (f) {
if (isplayer(lf)) {
msg("You feel more tipsy.");
} else if (cansee(player, lf)) {
msg("%s looks more tipsy.", lfname);
}
f->lifetime += TM_DRUNKTIME;
} else {
addtempflag(lf->flags, F_DRUNK, 1, NA, NA, NULL, TM_DRUNKTIME);
}
}
break;
case OT_POT_ELEMENTIMMUNE:
if (getmr(lf) && skillcheck(lf, SC_RESISTMAG, 30, 0)) {
if (isplayer(lf)) {
msg("You feel momentarily immune to the elements.");
}
break;
}
// how long for?
i = geteffecttime(15,25,potblessed);
if (!isimmuneto(lf->flags, DT_FIRE)) {
addtempflag(lf->flags, F_DTIMMUNE, DT_FIRE, NA, NA, NULL, i);
}
if (!isimmuneto(lf->flags, DT_COLD)) {
addtempflag(lf->flags, F_DTIMMUNE, DT_COLD, NA, NA, NULL, i);
}
break;
case OT_POT_ETHEREALNESS:
dospelleffects(lf, OT_S_PASSWALL, (potblessed) ? 5 : 1, lf, NULL, lf->cell, potblessed, seen, B_TRUE);
break;
case OT_POT_EXPERIENCE:
// gain xp!
if (getmr(lf) && skillcheck(lf, SC_RESISTMAG, 30, 0)) {
if (isplayer(lf)) {
msg("You feel momentarily more experienced.");
}
break;
}
if (isplayer(lf)) {
msg("You feel more experienced!");
gainxp(lf, getxpforlev(lf->level+1) - lf->xp);
} else {
if (cansee(player, lf)) {
msg("%s looks more experienced!", lfname);
}
gainlevel(lf);
enhanceskills(lf);
}
break;
case OT_POT_GASEOUSFORM:
dospelleffects(lf, OT_S_GASEOUSFORM, (potblessed) ? 5 : 1, lf, NULL, lf->cell, potblessed, seen, B_TRUE);
break;
case OT_POT_HEALING:
dospelleffects(lf, OT_S_HEALING,potblessed ? 5 : 1, lf, NULL, lf->cell, potblessed, seen, B_TRUE);
break;
case OT_POT_HEALINGMIN:
dospelleffects(lf, OT_S_HEALINGMIN,potblessed ? 5 : 1, lf, NULL, lf->cell, potblessed, seen, B_TRUE);
break;
case OT_POT_HEALINGMAJ:
dospelleffects(lf, OT_S_HEALINGMAJ,potblessed ? 5 : 1, lf, NULL, lf->cell, potblessed, seen, B_TRUE);
break;
case OT_POT_INVIS:
dospelleffects(lf, OT_S_INVISIBILITY,potblessed ? 6 : 3, lf, NULL, lf->cell, potblessed, seen, B_TRUE);
break;
case OT_POT_INVULN:
if (getmr(lf) && skillcheck(lf, SC_RESISTMAG, 30, 0)) {
if (isplayer(lf)) {
msg("You feel momentarily invulnerable.");
}
break;
}
i = geteffecttime(5,15,potblessed);
if (!lfhasflagval(lf, F_INVULNERABLE, B_TRUE, NA, NA, NULL)) {
addtempflag(lf->flags, F_INVULNERABLE, B_TRUE, NA, NA, NULL, i);
}
break;
case OT_POT_LEVITATION:
i = rnd(5,20);
addtempflag(lf->flags, F_LEVITATING, B_TRUE, NA, NA, NULL, i);
break;
case OT_POT_MAGIC:
if (getmr(lf) && skillcheck(lf, SC_RESISTMAG, 30, -10)) {
if (isplayer(lf)) {
msg("You feel your magical energy temporarily pulse.");
}
break;
}
if (getmaxmp(lf) > 0) {
msg("Your magical energy is restored.");
lf->mp = getmaxmp(lf);
} else {
nothinghappens();
if (seen) *seen = B_FALSE;
}
break;
case OT_POT_OIL:
if (isplayer(lf)) {
char buf[BUFLEN];
switch (rnd(1,5)) {
case 1: strcpy(buf, "cooking"); break;
case 2: strcpy(buf, "olive"); break;
case 3: strcpy(buf, "peanut"); break;
case 4: strcpy(buf, "grapefruit"); break;
case 5: strcpy(buf, "vegetable"); break;
}
msg("Mmm, %s oil.", buf);
}
break;
case OT_POT_POISON:
poison(lf, rnd(10,20), P_FOOD, 1, "a potion of poison");
break;
case OT_POT_POLYMORPH:
if (potblessed == B_BLESSED) {
// controlled polymorph
dospelleffects(lf, OT_S_POLYMORPH, 5, lf, NULL, lf->cell, potblessed, NULL, B_TRUE);
} else {
// random polymorph
dospelleffects(lf, OT_S_POLYMORPH, 1, lf, NULL, lf->cell, potblessed, NULL, B_TRUE);
}
break;
case OT_POT_RESTORATION:
failed = B_TRUE;
if (getattr(lf,A_STR) < lf->baseatt[A_STR]) {
setattr(lf, A_STR, lf->baseatt[A_STR]);
failed = B_FALSE;
}
if (getattr(lf,A_DEX) < lf->baseatt[A_DEX]) {
setattr(lf, A_DEX, lf->baseatt[A_DEX]);
failed = B_FALSE;
}
if (getattr(lf,A_IQ) < lf->baseatt[A_IQ]) {
setattr(lf, A_IQ, lf->baseatt[A_IQ]);
failed = B_FALSE;
}
if (potblessed == B_BLESSED) {
hpheal = lf->maxhp;
mpheal = getmaxmp(lf);
} else if (potblessed == B_CURSED) {
hpheal = lf->maxhp / 3;
mpheal = getmaxmp(lf) / 3;
} else {
hpheal = lf->maxhp / 2;
mpheal = getmaxmp(lf) / 2;
}
// blessed restores hp/mp to full
if (lf->hp < hpheal) {
gainhp(lf, hpheal - lf->hp);
if (!isplayer(lf) && cansee(player, lf)) {
msg("%s%s health has been restored!", lfname, getpossessive(lfname));
}
failed = B_FALSE;
}
if (lf->mp < mpheal) {
gainmp(lf, mpheal - lf->mp);
failed = B_FALSE;
}
if (failed) {
if (isplayer(lf)) msg("You feel momentarily restored.");
} else {
if (isplayer(lf)) msg("You feel restored!");
}
break;
case OT_POT_SANCTUARY:
// how long for?
//i = gethealtime(lf); // TODO: change...
if (getmr(lf) && skillcheck(lf, SC_RESISTMAG, 30, 0)) {
if (isplayer(lf)) {
nothinghappens();
}
break;
}
i = 15;
first = B_TRUE;
// add holy barriers all around
for (dir = DC_N; dir <= DC_NW; dir++) {
cell_t *c;
c = getcellindir(lf->cell, dir);
if (c && isempty(c)) {
object_t *newob;
newob = addob(c->obpile, "magical barrier");
if (first && haslos(player, c)) {
msg("A magical barrier appears!");
first = B_FALSE;
}
// it will disappear eventually
addflag(newob->flags, F_OBHP, i, i, NA, NULL);
addflag(newob->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL);
addflag(newob->flags, F_OBHPDRAIN, 1, NA, NA, NULL);
}
}
break;
case OT_POT_SLEEP:
dospelleffects(lf, OT_S_SLEEP, 8, lf, NULL, lf->cell, B_UNCURSED, NULL, B_TRUE);
if (seen) *seen = B_TRUE;
break;
case OT_POT_SPEED:
if (potblessed == B_BLESSED) {
dospelleffects(lf, OT_S_HASTE, 5, lf, NULL, lf->cell, B_BLESSED, NULL, B_TRUE);
} else if (potblessed == B_CURSED) {
dospelleffects(lf, OT_S_SLOW, 5, lf, NULL, lf->cell, B_UNCURSED, NULL, B_TRUE);
} else { // uncursed
dospelleffects(lf, OT_S_HASTE, 5, lf, NULL, lf->cell, B_UNCURSED, NULL, B_TRUE);
}
if (seen) *seen = B_TRUE;
break;
case OT_POT_WATER:
switch (potblessed) {
case B_BLESSED:
if (hasflag(lf->flags, F_UNDEAD)) {
if (isplayer(lf)) {
msg("This tastes like water, but burns like acid!");
} else if (cansee(player, lf)) {
msg("%s writhes in agony!", lfname);
}
losehp(lf, rnd(5,15), DT_HOLY, NULL, "drinking holy water");
} else {
if (isplayer(lf)) msg("Mmm, holy water.");
}
break;
case B_UNCURSED:
if (isplayer(lf)) msg("Mmm, water.");
break;
case B_CURSED:
if (isplayer(lf)) msg("Yuck! Something is wrong with this water.");
break;
}
if (seen) {
if (isplayer(lf) || cansee(player, lf)) {
*seen = B_TRUE;
}
}
if (!isundead(lf)) {
modhunger(lf, -pctof(0.05, (float)HUNGERCONST));
}
break;
case OT_POT_BLOOD:
if (lf->race->id == R_VAMPIRE) {
int b = B_UNCURSED;
if (isplayer(lf)) msg("This blood is delicious!");
if (potblessed == B_BLESSED) {
b = B_CURSED;
} else if (potblessed == B_CURSED) {
b = B_BLESSED;
}
dospelleffects(lf, OT_S_HEALINGMAJ,b ? 5 : 1, lf, NULL, lf->cell, b, seen, B_TRUE);
modhunger(lf, -HUNGERCONST);
} else {
if (isplayer(lf)) msg("Yuck, this tastes like blood!");
}
break;
case OT_POT_BLOODC:
f = lfhasflag(lf, F_BEINGSTONED);
if (f) {
killflag(f);
} else {
if (isplayer(lf)) msg("Yuck, this tastes like oddly-flavoured blood!");
}
break;
case OT_POT_JUICE:
if (isplayer(lf)) {
switch (potblessed) {
case B_BLESSED:
msg("Mmm, fruit juice!");
break;
case B_UNCURSED:
msg("Mmm, fruit juice!");
break;
case B_CURSED:
msg("Yuck! This tastes like rotten fruit.");
break;
}
if (seen) *seen = B_TRUE;
}
if (potblessed != B_CURSED) {
modhunger(lf, -pctof(25, (float)HUNGERCONST));
}
break;
default: // nothing happens
break;
}
}
int readsomething(lifeform_t *lf, object_t *o) {
flag_t *f;
char buf[BUFLEN],obname[BUFLEN];
int playercansee;
int willid = B_FALSE;
int needsob = B_FALSE;
objecttype_t *linkspell;
int readtime;
if (!haslos(lf, lf->cell)) {
if (isplayer(lf)) {
msg("You can't read anything, since you can't see!");
}
return B_TRUE;
}
getobname(o, obname, 1);
if ((isplayer(lf)) || cansee(player, lf)) {
playercansee = B_TRUE;
} else {
playercansee = B_FALSE;
}
if (o->type->obclass->id == OC_BOOK) {
readtime = SPEED_READ * 2;
} else {
readtime = SPEED_READ;
}
taketime(lf, readtime);
maketried(o->type->id);
// some checks first...
if (touch(lf, o)) {
return B_TRUE;
}
if (hasflag(o->flags, F_DEAD)) {
return B_TRUE;
}
if (lf->controller != C_PLAYER) {
if (cansee(player, lf)) {
getlfname(lf, buf);
capitalise(buf);
msg("%s reads %s!", buf, obname);
}
}
// find linked spell
linkspell = getlinkspell(o);
// figure out whether to id the object
willid = B_FALSE;
if (playercansee) {
if (o->type->obclass->id == OC_BOOK) {
// is this a spellbook?
if (linkspell) {
// if so, always id it.
// note though that we can only actually LEARN
// the spell if we are skilled in that school.
willid = B_TRUE;
} else {
// ie. a manual
willid = B_TRUE;
}
} else {
switch (o->type->id) {
case OT_SCR_IDENTIFY:
case OT_SCR_MENDING:
if (isblessed(o)) {
willid = B_TRUE;
} else {
// only id if it does something
willid = B_FALSE;
}
case OT_SCR_ENCHANT:
case OT_SCR_CREATEMONSTER:
case OT_SCR_REMOVECURSE:
case OT_SCR_DETECTAURA:
// only id if it does something
willid = B_FALSE;
break;
default:
willid = B_TRUE;
break;
}
}
}
// ask for a target object of any type if scroll is unknown?
switch (o->type->id) {
case OT_SCR_IDENTIFY:
case OT_SCR_MENDING:
if (isblessed(o)) {
needsob = B_FALSE;
} else {
needsob = B_TRUE;
}
break;
case OT_SCR_ENCHANT:
needsob = B_TRUE;
break;
default:
needsob = B_FALSE;
break;
}
if (!isknown(o) && willid) {
// id the object
if (o->type->obclass->id == OC_BOOK) {
identify(o);
} else {
makeknown(o->type->id);
}
real_getobname(o, obname, 1, B_FALSE, B_TRUE, B_FALSE, B_FALSE, B_FALSE); // don't adjust for blindness
if (isplayer(lf)) {
// tell the player
msg("This is %s!",obname);
more();
drawmsg();
}
}
// special scrolls
if ((o->type->id == OT_SCR_IDENTIFY) && isblessed(o)) {
int seen = B_FALSE;
if (isplayer(lf)) {
object_t *oo;
// identify evertthing!
for (oo = lf->pack->first ; oo ; oo = oo->next) {
if (!isidentified(oo)) {
dospelleffects(lf, OT_S_IDENTIFY, 10, NULL, oo, NULL, o->blessed, &seen, B_FALSE);
}
}
}
if (seen) makeknown(o->type->id);
} else if ((o->type->id == OT_SCR_MENDING) && isblessed(o)) {
int seen = B_FALSE;
object_t *oo;
int power;
// mend everything!
power = getobspellpower(o, lf);
for (oo = lf->pack->first ; oo ; oo = oo->next) {
if (isdamaged(oo)) {
dospelleffects(lf, OT_S_MENDING, power, NULL, oo, NULL, o->blessed, &seen, B_FALSE);
}
}
if (seen) {
makeknown(o->type->id);
} else {
if (isplayer(lf) || cansee(player, lf)) nothinghappens();
}
if (isplayer(lf)) msg("The scroll crumbles to dust.");
removeob(o, 1);
} else if (o->type->obclass->id == OC_SCROLL) { // cast linked spell
object_t *targob = NULL;
f = hasflag(o->flags, F_LINKSPELL);
if (f) {
int seen = B_FALSE;
int power;
power = getobspellpower(o, lf);
// for unidentified scrolls which target an object,
// let player select ANY object (even if it won't
// work).
if (needsob && isplayer(lf) && !isknown(o)) {
flag_t *f2;
f2 = addflag(o->flags, F_BEINGUSED, B_TRUE, NA, NA, NULL);
targob = askobject(lf->pack, "Target which object", NULL, AO_NONE);
killflag(f2);
}
dospelleffects(lf, f->val[0], power, NULL, targob, NULL, o->blessed, &seen, B_FALSE);
if (seen) {
// id the scroll now
makeknown(o->type->id);
}
// removeob one of the object
if (isplayer(lf)) msg("The scroll crumbles to dust.");
removeob(o, 1);
} else if (o->type->id == OT_GRAPHPAPER) {
if (isplayer(lf)) {
msg("You study your hand-drawn map for a while.");
}
} else if (o->type->id == OT_MAP) {
if (isplayer(lf)) {
if (!getskill(lf, SK_CARTOGRAPHY)) {
msg("You can't comprehend this map.");
} else if (lf->cell->map->region->rtype->id == RG_WORLDMAP) {
int lfmx,lfmy,tmx,tmy;
int dist;
cell_t *c;
enum SKILLLEVEL slev;
f = hasflag(o->flags, F_MAPTO);
getmapcoords(lf->cell->map, &lfmx, &lfmy);
tmx = f->val[0];
tmy = f->val[1];
dist = abs(tmx - lfmx) + abs(tmy - lfmy);
slev = getskill(lf, SK_CARTOGRAPHY);
switch (slev) {
default:
msg("You can't comprehend this map.");
break;
case PR_NOVICE:
// here/not here
if (dist == 0) {
msg("%s is in this area!", f->text);
} else {
msg("%s isn't in this area.", f->text);
}
break;
case PR_BEGINNER:
// near/far dist to that map
if (dist == 0) {
msg("%s is in this area!", f->text);
} else if (dist == 1) {
msg("%s is very nearby.", f->text);
} else {
msg("%s isn't nearby.", f->text);
}
break;
case PR_ADEPT:
// x areas away
if (dist == 0) {
msg("%s is in this area!", f->text);
} else if (dist == 1) {
msg("%s is one area away.", f->text);
} else {
msg("%s is %d areas away.", f->text, dist);
}
break;
case PR_SKILLED:
// x areas away
// plus direction.
if (dist == 0) {
msg("%s is in this area!", f->text);
} else {
char dirbuf[BUFLEN];
if (dist == 1) {
snprintf(buf, BUFLEN, "%s is one area away to the ", f->text);
} else {
snprintf(buf, BUFLEN, "%s is %d areas away to the ", f->text, dist);
}
strcpy(dirbuf, "");
if (tmy < lfmy) {
strcpy(dirbuf, "north");
} else if (tmy > lfmy) {
strcpy(dirbuf, "south");
}
if (tmx > lfmx) {
strcat(dirbuf, "east");
} else if (tmx < lfmx) {
strcat(dirbuf, "west");
}
strcat(buf, dirbuf);
strcat(buf, ".");
msg("%s", buf);
}
break;
case PR_EXPERT:
// x areas away
// plus direction.
// plus distance within area.
if (dist == 0) {
int dist2;
char distbuf[BUFLEN];
c = findobinmap(lf->cell->map, f->val[2]);
dist2 = getcelldist(lf->cell, c);
if (dist2 >= 20) {
strcpy(distbuf, "(very far away)");
} else if (dist2 >= 10) {
strcpy(distbuf, "(far away)");
} else if (dist2 >= 5) {
strcpy(distbuf, "(nearby)");
} else {
strcpy(distbuf, "(very nearby)");
}
msg("%s is in this area %s!", f->text, distbuf);
} else {
char dirbuf[BUFLEN];
if (dist == 1) {
snprintf(buf, BUFLEN, "%s is one area away to the ", f->text);
} else {
snprintf(buf, BUFLEN, "%s is %d areas away to the ", f->text, dist);
}
strcpy(dirbuf, "");
if (tmy < lfmy) {
strcpy(dirbuf, "north");
} else if (tmy > lfmy) {
strcpy(dirbuf, "south");
}
if (tmx > lfmx) {
strcat(dirbuf, "east");
} else if (tmx < lfmx) {
strcat(dirbuf, "west");
}
strcat(buf, dirbuf);
strcat(buf, ".");
msg("%s", buf);
}
break;
case PR_MASTER:
// x,y coords.
// plus direction.
// plus show on map if in area.
if (dist == 0) {
msg("You have located %s in this area.", f->text);
c = findobinmap(lf->cell->map, f->val[2]);
setcellknownradius(c, slev, 5, DT_ORTH);
} else {
char dirbuf[BUFLEN];
char buf2[BUFLEN];
snprintf(buf, BUFLEN, "%s is at %d,%d",f->text, tmx,tmy);
if (dist == 1) {
snprintf(buf2, BUFLEN, " (one area away to the ");
} else {
snprintf(buf2, BUFLEN, " (%d areas away to the ", dist);
}
strcpy(dirbuf, "");
if (tmy < lfmy) {
strcpy(dirbuf, "north");
} else if (tmy > lfmy) {
strcpy(dirbuf, "south");
}
if (tmx > lfmx) {
strcat(dirbuf, "east");
} else if (tmx < lfmx) {
strcat(dirbuf, "west");
}
strcat(buf2, dirbuf);
strcat(buf2, ")");
msg("%s%s", buf, buf2);
}
break;
}
} else {
msg("You need to be outside to get your bearings first.");
}
}
} else if (o->type->id == OT_SCR_NOTHING) {
if (isplayer(lf)) {
msg("The scroll crumbles to dust.");
}
// removeob one of the object
removeob(o, 1);
} else if (o->type->id == OT_SCR_PERMENANCE) {
if (isplayer(lf)) {
targob = askobject(lf->pack, "Target which object", NULL, AO_NONE);
}
if (targob) {
flag_t *f;
for (f = targob->flags->first ; f ; f = f->next) {
f->lifetime = PERMENANT;
}
if (isplayer(lf)) {
char obname[BUFLEN];
getobname(targob, obname, targob->amt);
msg("Your %s emit%s a blinding burst of power!",noprefix(obname), (targob->amt == 1) ? "s" : "");
}
}
if (isplayer(lf)) {
msg("The scroll crumbles to dust.");
}
// removeob one of the object
removeob(o, 1);
} else if (o->type->id == OT_SCR_REMOVECURSE) {
int seen = B_FALSE;
object_t *oo;
// remove curses!
for (oo = lf->pack->first ; oo ; oo = oo->next) {
// if this object is cursed
if (iscursed(oo)) {
// blessed scrolls remove curse from everything you're holding.
// otherwise only equipped objects will be uncursed.
if (o->blessed || isequipped(oo)) {
uncurseob(oo, &seen);
}
}
}
if (seen) {
// id the scroll now
makeknown(o->type->id);
} else {
if (isplayer(lf)) {
nothinghappens();
}
}
if (isplayer(lf)) {
msg("The scroll crumbles to dust.");
}
// removeob one of the object
removeob(o, 1);
}
} else if (o->type->obclass->id == OC_BOOK) {
// is this a spellbook?
if (linkspell) {
// if so, can we read it?
if (getspellpower(lf, linkspell->id) > 0) {
if (lfhasflagval(lf, F_CANCAST, linkspell->id, NA, NA, NULL)) {
if (isplayer(lf)) msg("You already know how to cast this spell!");
} else {
enum SPELLSCHOOL school;
enum SKILLLEVEL slev;
school = getspellschool(linkspell->id);
slev = getspellskill(lf, linkspell->id);
// can we learn this?
if (slev) {
// try to learn it
int difficulty, mod;
difficulty = 15 + (getspelllevel(linkspell->id)*3);
mod = slev * 2;
if (skillcheck(lf, SC_LEARNMAGIC, difficulty, mod)) {
// learn it
addflag(lf->flags, F_CANCAST, linkspell->id, NA, NA, NULL);
} else {
msg("You fail to learn %s.",linkspell->name);
}
} else {
msg("You are not yet skilled in %s.",getschoolnameshort(school));
}
}
} else {
if (isplayer(lf)) msg("You cannot comprehend the contents of this book.");
}
} else {
// manuals
f = hasflag(o->flags, F_MANUALOF);
if (f) {
giveskill(lf, f->val[0]);
}
if (isplayer(lf)) {
msg("The book crumbles to dust.");
}
// removeob one of the object
removeob(o, 1);
}
}
return B_FALSE;
}
object_t *relinkob(object_t *src, obpile_t *dst) {
if (!obfits(src, dst)) return NULL;
if (src->pile->owner) {
// previous owner loses all flags conferred by this object
loseobflags(src->pile->owner, src, ALLCONFERRED);
}
// unweild
killflagsofid(src->flags, F_EQUIPPED);
// adjust letter...
// gold should always have letter '$'
if (src->type->obclass->id == OC_MONEY) {
src->letter = '$';
}
// adjust letter if going to player?
if (dst->owner && isplayer(dst->owner)) {
src->letter = getnextletter(dst, &src->letter);
}
// unlink this object from the current list
if (src->prev == NULL) {
// first
src->pile->first = src->next;
} else {
// not first
src->prev->next = src->next;
}
if (src->next == NULL) {
// last
src->pile->last = src->prev;
} else {
// not last
src->next->prev = src->prev;
}
// add this object to the end of the list for the new pile
if (dst->first == NULL) {
// first element in new list
dst->first = src;
src->prev = NULL;
} else {
object_t *aa;
// go to end of list
aa = dst->last;
// not first in new list
src->prev = aa;
aa->next = src;
}
dst->last = src;
src->pile = dst;
src->next = NULL;
if (src->pile->owner) {
// new owner gains "hold confer" flags conferred by this object
giveobflags(src->pile->owner, src, F_HOLDCONFER);
// new owner gains "activate confer" flags conferred by this object if it's active
if (isactivated(src)) {
giveobflags(src->pile->owner, src, F_ACTIVATECONFER);
}
}
if (obproduceslight(src)) {
calclight((getoblocation(src))->map);
if (gamemode == GM_GAMESTARTED) {
setlosdirty(player);
//precalclos(player);
}
drawscreen();
}
return src;
}
void removedeadobs(obpile_t *op) {
object_t *o, *nexto;
for (o = op->first ; o ; o = nexto) {
nexto = o->next;
if (hasflag(o->flags, F_DEAD)) {
obdie(o);
continue;
}
}
}
// returns the amount left
int removeob(object_t *o,int howmany) {
if (howmany == ALL) {
howmany = o->amt;
}
if (howmany >= o->amt) {
killob(o);
return 0;
} else {
o->amt -= howmany;
}
return o->amt;
}
void rrtorarity(enum RARITY r, int *minr, int *maxr) {
switch (r) {
case RR_UNIQUE:
case RR_NEVER:
if (minr) *minr = 0;
if (maxr) *maxr = 0;
break;
case RR_VERYRARE:
if (minr) *minr = 0;
if (maxr) *maxr = 49;
break;
case RR_RARE:
if (minr) *minr = 50;
if (maxr) *maxr = 64;
break;
case RR_UNCOMMON:
if (minr) *minr = 65;
if (maxr) *maxr = 79;
break;
case RR_COMMON:
if (minr) *minr = 80;
if (maxr) *maxr = 100;
break;
default:
if (minr) *minr = 0;
if (maxr) *maxr = 100; // ie. rarity can be anything
break;
}
}
void setblessed(object_t *o, enum BLESSTYPE wantbless) {
o->blessed = wantbless;
if (wantbless != B_BLESSED) {
flag_t *f,*nextf;
// remove glowing from blessings
for (f = o->flags->first ; f ; f = nextf) {
nextf = f->next;
if (f->lifetime == FROMBLESSING) {
killflag(f);
}
}
}
}
int sethiddenname(objecttype_t *ot, char *text) {
int n;
int gotcolour = B_FALSE;
// add knowledge for it
addknowledge(ot->id, text, B_UNKNOWN);
// some descriptions confer other effecst too...
if (strstr(text, "glowing")) {
addflag(ot->flags, F_PRODUCESLIGHT, 2, NA, NA, NULL);
} else if (strstr(text, "flourescent")) {
addflag(ot->flags, F_PRODUCESLIGHT, 1, NA, NA, NULL);
} else if (strstr(text, "luminous")) {
addflag(ot->flags, F_PRODUCESLIGHT, 1, NA, NA, NULL);
}
// set colour based on hiddenname
for (n = 0; strlen(colour[n].name); n++) {
if (strstr(text, colour[n].name)) {
flag_t *gf;
gf = hasflag(ot->flags, F_GLYPH);
if (gf) {
gf->val[0] = colour[n].col;
} else {
char buf[2];
buf[0] = ot->obclass->glyph.ch;
buf[1] = '\0';
addflag(ot->flags, F_GLYPH, colour[n].col, NA, NA, buf);
gotcolour = B_TRUE;
//dblog("assigning colour %s to %s (%s)",colour[n].name, text, ot->name);
break;
}
}
}
if (!gotcolour) {
for (n = 0; strlen(gemtype[n].name); n++) {
if (strstr(text, gemtype[n].name)) {
flag_t *gf;
gf = hasflag(ot->flags, F_GLYPH);
if (gf) {
gf->val[0] = gemtype[n].col;
} else {
char buf[2];
buf[0] = ot->obclass->glyph.ch;
buf[1] = '\0';
addflag(ot->flags, F_GLYPH, gemtype[n].col, NA, NA, buf);
break;
}
}
}
}
return B_FALSE;
}
void setinscription(object_t *o, char *text) {
if (o->inscription) {
free(o->inscription);
}
o->inscription = strdup(text);
}
void setobcreatedby(object_t *o, lifeform_t *lf) {
char lfname[BUFLEN];
if (!lf) {
return;
}
real_getlfnamea(lf, lfname, B_FALSE);
addflag(o->flags, F_CREATEDBY, lf->id, NA, NA, lfname);
}
// returns TRUE if it did shatter
int shatter(object_t *o, int hitlf, char *damstring, lifeform_t *fromlf) {
int shatterdam;
cell_t *where = NULL;
lifeform_t *target = NULL;
char buf[BUFLEN];
char obname[BUFLEN];
char targetname[BUFLEN];
int seen = B_FALSE;
if (hasflag(o->flags, F_NOSHATTER)) {
return B_FALSE;
}
getobname(o,obname,o->amt);
where = getoblocation(o);
if (hitlf) {
target = where->lf;
} else {
target = NULL;
}
if (target) {
getlfname(target, targetname);
}
// announce
if (haslos(player, where)) {
char prefix[BUFLEN];
if (o->pile->owner) {
char lfname[BUFLEN];
getlfname(o->pile->owner, lfname);
snprintf(prefix, BUFLEN, "%s%s ", lfname, getpossessive(lfname));
// ie. "the kobold's"
} else {
strcpy(prefix, "");
}
msg("%s%s shatter%s!",prefix, strlen(prefix) ? noprefix(obname) : obname,
(o->amt == 1) ? "s" : "");
seen = B_TRUE;
} else {
noise(where, NULL, NC_OTHER, 3, "shattering glass.", NULL);
}
if (target) {
shatterdam = getshatterdam(o);
if (shatterdam && !isdead(target)) {
// extra glass damage
if (seen) {
msg("%s %s showered in %s shards!", targetname, is(target),
o->material->name);
}
losehp(target, shatterdam, DT_SLASH, fromlf, damstring);
}
}
// place shards
if (o->material->id == MT_GLASS) {
int numshards;
numshards = getnumshards(o);
// place glass shards
snprintf(buf, BUFLEN, "%d pieces of broken glass",numshards);
addob(where->obpile, buf);
} else if (o->material->id == MT_ICE) {
int numshards;
numshards = getnumshards(o) / 15;
if (numshards < 1) numshards = 1;
// ice
snprintf(buf, BUFLEN, "%d chunks of ice",numshards);
addob(where->obpile, buf);
}
// potion effects (only if you hit)?
if (o->type->obclass->id == OC_POTION) {
// effects on lifeforms
if (hitlf && target) {
int observed;
// some potions have special effects...
switch (o->type->id) {
case OT_POT_ACID: // take acid damage
if (seen) {
makeknown(o->type->id);
}
if (target) {
if (seen) {
msg("%s %s splashed with acid!", targetname,
is(target));
}
losehp(target, rnd(1,5)*o->amt, DT_ACID, fromlf, "a splash of acid");
} else {
// announce
if (seen) {
msg("Acid splashes all over the floor!");
}
}
break;
case OT_POT_BLOOD:
if (seen) {
makeknown(o->type->id);
}
if (target) {
if (seen) {
msg("%s %s splashed with blood.", targetname,
is(target));
}
} else {
// announce
if (seen) {
msg("Blood splashes onto the floor.");
}
}
break;
case OT_POT_ELEMENTIMMUNE:
case OT_POT_ETHEREALNESS:
case OT_POT_GASEOUSFORM:
case OT_POT_LEVITATION:
case OT_POT_POISON:
case OT_POT_POLYMORPH:
case OT_POT_INVIS:
case OT_POT_SANCTUARY: // apply regular potion effects, and make them known
if (target) {
if (seen) {
makeknown(o->type->id);
}
potioneffects(target, o->type->id, o, o->blessed, &observed);
}
break;
case OT_POT_HEALING:
case OT_POT_HEALINGMIN: // only make them known if it had an effect
if (target) {
potioneffects(target, o->type->id, o, o->blessed, &observed);
if (observed) {
makeknown(o->type->id);
}
}
break;
case OT_POT_OIL:
if (seen) {
makeknown(o->type->id);
msg("%s %s covered with oil!", targetname, is(target));
}
// target is temporarily vulnerable to fire.
addtempflag(target->flags, F_DTVULN, DT_FIRE, NA, NA, "1d6", rnd(5,10));
break;
case OT_POT_WATER:
if (seen) makeknown(o->type->id);
if (target) {
if (seen) {
msg("%s %s splashed with water.", targetname,
is(target));
}
if (hasflag(target->flags, F_UNDEAD) && isblessed(o)) {
if (isplayer(target)) {
msg("The water burns like acid!");
} else if (cansee(player, target)) {
msg("%s writhes in agony!", targetname);
}
losehp(target, o->amt*rnd(5,10), DT_HOLY, NULL, "holy water");
if (seen) {
// we now know that it is blessed
o->blessknown = B_TRUE;
}
} else {
losehp(target, 0, DT_WATER, fromlf, "a splash of water");
}
} else {
// all objects take damage
object_t *oo,*nextoo;
// announce
if (seen) {
msg("Water splashes onto the floor.");
}
//TODO: holy water blesses everything?
// everything here takes water damage
for (oo = where->obpile->first ; oo ; oo = nextoo) {
nextoo = oo->next;
takedamage(oo, 0, DT_WATER);
}
}
break;
default:
break;
}
} else { // ie. you didn't hit anyone
switch (o->type->id) {
case OT_POT_OIL:
if (seen) {
makeknown(o->type->id);
msg("The floor is covered with oil!");
}
break;
case OT_POT_WATER:
if (seen) {
makeknown(o->type->id);
msg("The floor is covered with water!");
}
break;
default:
break;
}
}
}
// object is dead.
addflag(o->flags, F_DEAD, B_TRUE, NA, NA, NULL);
addflag(o->flags, F_NOOBDIETEXT, B_TRUE, NA, NA, NULL);
if (fromlf && isplayer(fromlf)) {
switch (o->type->id) {
case OT_POT_HEALING:
case OT_POT_HEALINGMIN:
case OT_POT_HEALINGMAJ:
case OT_POT_AMBROSIA:
angergodmaybe(R_GODMERCY, 25);
break;
default:
break;
}
}
return B_TRUE;
}
// randomizes hidden names
void shufflehiddennames(void) {
int i,n;
int total;
hiddenname_t *a, *temp;
int shuffleamt = 500;
total = 0;
for (a = firsthiddenname ; a ; a = a->next) {
total++;
}
if (total <= 1) {
return;
}
for (i = 0; i < shuffleamt; i++) {
int which;
// select random element (but never the first)
which = (rand() % (total-1))+1;
// go there
a = firsthiddenname;
for (n = 0; n < which; n++) {
if (a->next != NULL) a = a->next;
}
temp = a;
// remove from list
temp->prev->next = temp->next;
if (temp->next) {
temp->next->prev = temp->prev;
} else {
lasthiddenname = temp->prev;
}
// re-add this element to the start
temp->next = firsthiddenname;
temp->prev = NULL;
firsthiddenname->prev = temp;
firsthiddenname = temp;
}
}
object_t *splitob(object_t *o) {
object_t *newob;
// decrease count on original stack temporarily, in case we
// can't place the new object (at our weight limit?).
// doesn't matter if it goes down to zero, as we will put it back up soon.
o->amt--;
// give new object
newob = addobject(o->pile, NULL, B_NOSTACK, B_FALSE, o->type->id);
// restore count
o->amt++;
if (newob) {
copyobprops(newob, o);
killflagsofid(newob->flags, F_STACKABLE);
// remove old ob
removeob(o, 1);
}
return newob;
}
// returns amount of damage taken
int takedamage(object_t *o, unsigned int howmuch, int damtype) {
return real_takedamage(o, howmuch, damtype, B_TRUE);
}
// returns amount of damage taken
int real_takedamage(object_t *o, unsigned int howmuch, int damtype, int wantannounce) {
char predamname[BUFLEN],postdamname[BUFLEN];
char obname[BUFLEN];
flag_t *hpflag, *f;
int damtaken = 0;
// some checks need to happen before
// making sure the damage will happen.
// for example, even if an object is
// immune to water damage, water will
// still put out fire
// water puts out fire
if (damtype == DT_WATER) {
extinguish(o);
makewet(o, howmuch);
}
// catches on fire?
if (damtype == DT_FIRE) {
if ( ((o->type->id == OT_CANDLE) || (o->type->id == OT_TORCH) || (o->type->id == OT_CANDELABRUM)) &&
!isactivated(o)) {
cell_t *c;
c = getoblocation(o);
if (haslos(player, c)) {
char buf[BUFLEN];
getobname(o, buf, o->amt);
msg("%s %s lit.", buf, (o->amt == 1) ? "is" : "are");
}
turnon(NULL, o);
// reduce damage a tiny bit
howmuch--;
} else if (isflammable(o) && !hasflag(o->flags, F_ONFIRE)) {
ignite(o);
if (isdeadob(o)) {
return howmuch;
}
}
// actually take fire damage
// fire damage falls through to owner
if (o->pile->owner) {
flag_t *f;
lifeform_t *owner;
int lfdam = 0;
owner = o->pile->owner;
f = hasflag(o->flags, F_EQUIPPED);
if (f) {
// no damage from equipped _weapons_
if ((f->val[0] != BP_WEAPON) || (f->val[0] != BP_SECWEAPON)) {
} else {
// equipped clothes/armour? 1.5x damage.
lfdam = pctof(150,howmuch);
}
} else {
// otherwise normal.
lfdam = howmuch;
}
if (lfdam) {
// announce
getobname(o, obname, o->amt);
if (isplayer(owner)) {
msg("Your %s burn%s you!", noprefix(obname), (o->amt == 1) ? "s" : "");
} else if (cansee(player, owner)) {
char lfname[BUFLEN];
getlfname(owner, lfname);
msg("%s is burnt by %s!", lfname, obname);
}
// now use the REAL name
real_getobname(o, obname, o->amt, B_TRUE, B_FALSE, B_FALSE, B_FALSE, B_TRUE);
losehp_real(owner, howmuch , damtype, NULL, obname, B_TRUE, o, B_FALSE);
if (isdead(owner)) {
return howmuch;
}
}
}
} else if (damtype == DT_COLD) {
// cold will shatter glass
if (o->material->id == MT_GLASS) {
char buf[BUFLEN];
char buf2[BUFLEN];
getobname(o, buf2, 1);
snprintf(buf, BUFLEN, "a shattering %s", buf2);
shatter(o, B_TRUE, buf, B_FALSE);
return howmuch;
}
}
// damage type creates other objects?
f = hasflagval(o->flags, F_DTCREATEOB, damtype, NA, NA, NULL);
if (f) {
cell_t *loc;
int radius;
int dirtype;
objecttype_t *ot;
loc = getoblocation(o);
ot = findotn(f->text);
if (ot && !hasob(loc->obpile, ot->id)) {
if (f->val[1] == NA) {
radius = 0;
dirtype = NA;
} else {
radius = f->val[1];
dirtype = f->val[2];
}
addobburst(loc, radius, dirtype, f->text, NULL, LOF_WALLSTOP);
}
}
// damage type converts this into something else?
f = hasflagval(o->flags, F_DTCONVERT, damtype, NA, NA, NULL);
if (f && !hasflag(o->flags, F_NODTCONVERT)) {
object_t *newob;
newob = addob(o->pile, f->text);
newob->amt = o->amt;
// object dies, but don't announce it
addflag(o->flags, F_DEAD, B_TRUE, NA, NA, NULL);
addflag(o->flags, F_NOOBDIETEXT, B_TRUE, NA, NA, NULL);
return howmuch;
}
adjustdamob(o, &howmuch, damtype);
// effects which have to happen before damage is applied...
// explodes?
f = hasflag(o->flags, F_EXPLODEONDAM);
if (f) {
if (f->val[2] == B_IFACTIVATED) {
if (hasflag(o->flags, F_ACTIVATED)) {
if (hasflag(o->flags, F_EXPLODEONDEATH)) {
// object dies!
addflag(o->flags, F_DEAD, B_TRUE, NA, NA, NULL);
} else {
// explode
if ((f->val[0] == NA) || (f->val[0] == damtype)) {
explodeob(o, f, (f->val[1] == B_BIG) ? 1 : 0);
return howmuch;
}
}
}
} else {
if (hasflag(o->flags, F_EXPLODEONDEATH)) {
// object dies!
addflag(o->flags, F_DEAD, B_TRUE, NA, NA, NULL);
} else {
if ((f->val[0] == NA) || (f->val[0] == damtype)) {
// explode
explodeob(o, f, (f->val[1] == B_BIG) ? 1 : 0);
return howmuch;
}
}
}
}
// flashes?
f = hasflag(o->flags, F_FLASHONDAM);
if (f) {
if (f->val[2] == B_IFACTIVATED) {
if (hasflag(o->flags, F_ACTIVATED)) {
// flash, then object dies
brightflash(getoblocation(o),f->val[0], NULL);
addflag(o->flags, F_DEAD, B_TRUE, NA, NA, NULL);
}
} else {
// flash, then object dies
brightflash(getoblocation(o),f->val[0], NULL);
addflag(o->flags, F_DEAD, B_TRUE, NA, NA, NULL);
}
return howmuch;
}
if (howmuch <= 0) {
return 0;
}
// update lastdamtype
f = hasflag(o->flags, F_LASTDAMTYPE);
if (f) {
f->val[0] = damtype;
} else {
addflag(o->flags, F_LASTDAMTYPE, damtype, NA, NA, NULL);
}
real_getobname(o, obname, o->amt, B_FALSE, B_FALSE, B_TRUE, B_FALSE, B_FALSE);
getobconditionname(o, predamname);
hpflag = hasflag(o->flags, F_OBHP);
if (hpflag) {
damtaken = MAXOF(hpflag->val[0], howmuch);
// object loses hp
hpflag->val[0] -= howmuch;
}
if (!hpflag || (hpflag->val[0] <= 0)) {
// special cases....
if (damtype == DT_FIRE) {
if ((o->material->id == MT_FLESH) && onein(3)) { // fire sometimes roasts flesh
object_t *meat;
meat = addob(o->pile, "chunk of roast meat");
// purposely don't use getweight!
meat->weight = o->weight;
}
// fire turns things to ash
addob(o->pile, "pile of ash");
} else if (damtype == DT_BASH) {
if (o->material->id == MT_GLASS) { // bashing damage breaks glass
int nshards;
char buf[BUFLEN];
nshards = getnumshards(o);
snprintf(buf, BUFLEN, "%d pieces of broken glass", nshards);
addob(o->pile, buf);
} else if (o->material->id == MT_ICE) { // bashing breaks ice
int nshards;
char buf[BUFLEN];
nshards = getnumshards(o) / 15;
snprintf(buf, BUFLEN, "%d chunks of ice", nshards);
addob(o->pile, buf);
}
}
// object dies!
addflag(o->flags, F_DEAD, B_TRUE, NA, NA, NULL);
// if we didn't want this announced, don't say that it died either
if (!wantannounce) {
addflag(o->flags, F_NOOBDIETEXT, B_TRUE, NA, NA, NULL);
}
} else if (hpflag) {
// object was just damaged
getobconditionname(o, postdamname);
// was it enough to change the status
if (!hasflag(o->flags, F_NOOBDAMTEXT) && strcmp(predamname, postdamname)) {
// if it was melting, drop some water here
if (damtype == DT_MELT) {
if (hasflag(o->flags, F_EQUIPPED) ) {
addob(o->pile->owner->cell->obpile, "small puddle of water");
} else {
// melts into the ob pile
addob(o->pile, "small puddle of water");
}
}
if (o->pile->owner) {
if (wantannounce) {
if (isplayer(o->pile->owner)) {
msg("^wYour %s %s!",noprefix(obname), getobhurtname(o, damtype));
} else if (cansee(player, o->pile->owner)) {
// don't announce decay damage for object you aren't holding
if (damtype != DT_DECAY) {
char monname[BUFLEN];
getlfname(o->pile->owner, monname);
msg("%s's %s %s!",monname, noprefix(obname), getobhurtname(o, damtype));
}
}
}
} else if (haslos(player, o->pile->where)) {
if (wantannounce) {
// don't announce decay damage for object you aren't holding
if (damtype != DT_DECAY) {
msg("%s %s!", obname, getobhurtname(o, damtype));
}
}
// if you see a secret object get damaged, it's not secret anymore.
killflagsofid(o->flags, F_SECRET);
}
}
}
return damtaken;
}
// throw speed/2 is the damage multiplier
int fireat(lifeform_t *thrower, object_t *o, int amt, cell_t *where, int speed, object_t *firearm) {
char throwername[BUFLEN];
char throwernamea[BUFLEN];
char realthrowername[BUFLEN];
char realthrowernamea[BUFLEN];
char obname[BUFLEN];
char targetname[BUFLEN];
lifeform_t *target;
cell_t *srcloc;
int seen;
int shattered = B_FALSE;
char throwverbpast[BUFLEN];
char throwverbpres[BUFLEN];
int acc;
int youhit = B_FALSE;
int missiledam = 0;
object_t *newob = NULL;
cell_t *newloc;
int db = B_TRUE;
int willcatch = B_FALSE;
int announcedmiss = B_FALSE;
int outofammo = B_FALSE;
float multiplier;
obpile_t *op = NULL;
reason = E_OK;
// giving away money
if (isplayer(thrower) && (o->type->id == OT_GOLD)) {
flag_t *f;
f = lfhasflag(thrower, F_GAVEMONEY);
if (f) {
f->val[0] += o->amt;
} else {
addflag(thrower->flags, F_GAVEMONEY, o->amt, NA, NA, NULL);
}
}
// you can't throw with as much force while swimming.
if (isswimming(thrower) && !firearm) {
speed /= 2;
limit(&speed, 1, NA);
}
multiplier = speed / 2;
if (firearm) {
strcpy(throwverbpres, "fire");
strcpy(throwverbpast, "fired");
} else {
strcpy(throwverbpres, "throw");
strcpy(throwverbpast, "thrown");
}
if (isblind(player)) {
if (thrower && isplayer(thrower)) {
getobname(o, obname, amt);
} else {
strcpy(obname, "something");
}
} else {
getobname(o, obname, amt);
}
if (thrower) {
getlfname(thrower, throwername);
real_getlfname(thrower, realthrowername, B_FALSE);
if (isplayer(thrower)) {
strcpy(throwernamea, throwername);
} else {
if (isvowel(*(noprefix(throwername)))) {
strcpy(throwernamea, "an ");
} else {
strcpy(throwernamea, "a ");
}
strcat(throwernamea, noprefix(throwername));
if (isvowel(*(noprefix(realthrowername)))) {
strcpy(realthrowernamea, "an ");
} else {
strcpy(realthrowernamea, "a ");
}
strcat(realthrowernamea, noprefix(realthrowername));
}
} else {
strcat(throwernamea, "something");
strcat(realthrowernamea, "something");
}
if (firearm) {
srcloc = getoblocation(firearm);
} else {
srcloc = getoblocation(o);
}
// can't throw weilded cursed objects
if ((o->blessed == B_CURSED) && (!firearm)) {
// is object in thrower's pack? we need to check this
// because of things like telekenises which let us throw
// things we don't have.
if (thrower && (o->pile->owner == thrower)) {
// object equipped?
if (hasflag(o->flags, F_EQUIPPED)) {
// throw will fail!
if (isplayer(thrower)) {
msg("You can't release your %s - it %s cursed!", noprefix(obname),
isblessknown(o) ? "is" : "must be");
o->blessknown = B_TRUE;
} else if (cansee(player, thrower)) {
msg("%s tries to throw %s but can't!", throwername, obname);
o->blessknown = B_TRUE;
}
// take time anyway
//taketime(thrower, SPEED_THROW);
// fail.
reason = E_CURSED;
return B_TRUE;
}
}
// otherwise does player have haslos?
// identify as cursed!
}
if (haslos(player, where)) {
seen = B_TRUE;
} else {
seen = B_FALSE;
}
target = where->lf;
if (target && isdead(target)) {
target = NULL;
}
if (thrower && target && !isprone(target) && !lfhasflag(target, F_CASTINGSPELL)) {
if (areallies(thrower, target) && !firearm) {
willcatch = B_TRUE;
}
}
if (target) {
getlfname(target, targetname);
}
// touch effects
if (thrower) {
if (firearm) {
if (touch(thrower, firearm)) {
return B_TRUE;
}
} else {
if (o->pile == thrower->pack) {
if (touch(thrower, o)) {
return B_TRUE;
}
}
}
}
// announce it ("xx throws xx" "at yy")
if (thrower && isplayer(thrower)) {
// player is throwing something
if (target && !hasflag(o->flags, F_POWDER)) {
msg("You %s %s %s %s.", throwverbpres, obname, willcatch ? "to" : "at", targetname);
} else {
msg("You %s %s.",throwverbpres, obname);
}
} else if (thrower && haslos(player, srcloc) && (srcloc == thrower->cell)) {
char throwstring[BUFLEN];
// a monster is throwing something
snprintf(throwstring, BUFLEN, "%s %ss %s", throwername, throwverbpres,
obname);
if (target && haslos(player, where) && !hasflag(o->flags, F_POWDER)) {
strcat(throwstring, willcatch ? " to " : " at ");
strcat(throwstring, targetname);
}
strcat(throwstring, ".");
msg("%s", throwstring);
} else if (seen) {
char throwstring[BUFLEN];
// an object is moving on its own
/*
if (target) {
msg("Something %ss %s at %s.", throwverbpres, obname, targetname);
} else {
msg("Something %ss %s.",throwverbpres, obname);
}
*/
if (o->pile->owner && cansee(player, o->pile->owner)) {
char ownername[BUFLEN];
getlfname(o->pile->owner, ownername);
snprintf(throwstring, BUFLEN, "%s%s %s %s through the air", ownername, getpossessive(ownername),
noprefix(obname), (amt == 1) ? "flies" : "fly");
} else {
snprintf(throwstring, BUFLEN, "%s %s through the air", obname, (amt == 1) ? "flies" : "fly");
}
if (target && haslos(player, where)) {
strcat(throwstring, " toward ");
strcat(throwstring, targetname);
}
strcat(throwstring, ".");
msg("%s", throwstring);
}
// adjust destination location in case something is in the way.
haslof(srcloc, where, LOF_NEED, &newloc);
if (newloc) {
where = newloc;
target = where->lf;
if (target && isdead(target)) {
target = NULL;
}
if (target) {
getlfname(target, targetname);
}
}
//taketime(thrower, SPEED_THROW);
// some obejcts will die when thrown.
if (hasflag(o->flags, F_POWDER)) {
// special cases first
if (o->type->id == OT_ASHCONCEAL) {
int radius;
// make smoke
if (haslos(player, srcloc)) {
msg("%s dispers%s into a thick cloud of smoke!", obname,
(amt == 1) ? "es" : "e",
(amt == 1) ? "es" : "e" );
if (!isknown(o)) makeknown(o->type->id);
}
radius = o->amt * 2;
if (radius > 10) radius = 10;
addobsinradius(thrower->cell, radius, DT_COMPASS, "cloud of smoke", B_FALSE);
} else if (o->type->id == OT_ASHEXPLODE) {
char diebuf[BUFLEN];
// explosion!
snprintf(diebuf, BUFLEN, "%dd6",o->amt);
if (haslos(player, srcloc)) {
msg("%s dispers%s and explod%s!", obname,
(amt == 1) ? "es" : "e",
(amt == 1) ? "es" : "e" );
if (!isknown(o)) makeknown(o->type->id);
}
explodecells(thrower->cell, roll(diebuf), B_FALSE, o, 1, DT_COMPASS, B_FALSE);
} else if (o->type->id == OT_ASHSLEEP) {
int radius;
// make smoke
if (haslos(player, srcloc)) {
msg("%s dispers%s into a wispy mist!", obname,
(amt == 1) ? "es" : "e",
(amt == 1) ? "es" : "e" );
if (!isknown(o)) makeknown(o->type->id);
}
radius = o->amt * 2;
if (radius > 10) radius = 10;
spellcloud(srcloc, radius, '}', C_MAGENTA, OT_S_SLEEP, radius, B_TRUE);
} else {
if (haslos(player, srcloc)) {
msg("%s dispers%s into the air.", obname, (amt == 1) ? "es" : "e");
if (!isknown(o)) makeknown(o->type->id);
}
}
removeob(o, amt);
return B_FALSE;
}
if (thrower) {
// gravboost?
if (lfhasflag(thrower, F_GRAVBOOSTED) && (srcloc == thrower->cell)) {
if (isplayer(thrower) || haslos(player, srcloc)) {
msg("%s drops and sticks to the ground!", obname);
}
moveob(o, thrower->cell->obpile, amt);
return B_FALSE;
}
}
// do throw animation
if (seen) {
glyph_t *gl;
gl = getglyph(o);
anim(srcloc, where, gl->ch, gl->colour);
}
// find out your chances of hitting
if (target) {
if (thrower) {
if (willcatch) {
acc = 100;
} else {
acc = getmissileaccuracy(thrower, where, o, firearm, A_DEX);
}
} else {
// purely based on saving throw...
acc = 100;
}
// adjust for swimming
if (isswimming(thrower)) {
switch (getskill(thrower, SK_SWIMMING)) {
default:
case PR_INEPT: acc -= 40; break;
case PR_NOVICE: acc -= 30; break;
case PR_BEGINNER: acc -= 20; break;
case PR_ADEPT: acc -= 10; break;
case PR_SKILLED:
case PR_EXPERT:
case PR_MASTER:
break;
}
}
// roll for hit
youhit = B_FALSE;
// metal projectile versus magnetic shield?
if (target && lfhasflag(target, F_MAGSHIELD) && ismetal(o->material->id)) {
// announce
if (seen) {
msg("%s is repelled from %s!", obname, targetname);
announcedmiss = B_TRUE;
}
youhit = B_FALSE;
} else if (rnd(1,100) <= acc) {
youhit = B_TRUE;
}
if (youhit && target) {
flag_t *f;
object_t *shield;
// cyclone shield?
f = lfhasflag(target, F_WINDSHIELD);
if (f) {
if (speed <= f->val[0]) {
if (seen) {
msg("%s is repelled by air currents around %s!", obname, targetname);
announcedmiss = B_TRUE;
}
youhit = B_FALSE;
}
}
// an actual physical shield?
shield = getshield(target);
if (shield && !lfhasflag(target, F_CASTINGSPELL)) {
// block chance based on shield skill
// ie. AT_AVERAGE = speed3 = 18
// ie. gun = speed20 = 120 = impossible
if (skillcheck(target, SC_SHIELDBLOCK, speed*6, 0)) {
int throwdam,dam;
if (seen) {
char shname[BUFLEN];
real_getobname(shield, shname, 1, B_TRUE, B_FALSE, B_TRUE, B_FALSE, B_FALSE);
if (isplayer(target)) {
msg("You block %s with your %s.", obname, noprefix(shname));
} else {
msg("%s blocks %s with %s.", targetname, obname, shname);
}
announcedmiss = B_TRUE;
}
// damage shield
throwdam = getthrowdam(o);
dam = (int)((float)throwdam * multiplier);
takedamage(shield, dam, DT_PROJECTILE);
youhit = B_FALSE;
practice(target, SK_SHIELDS, 1);
missiledam += ((speed*2)+1);
}
}
}
// saving throws
if (youhit && !willcatch && !isprone(target)) {
// can the victim see the thrower?
if (thrower && cansee(target, thrower)) {
int catchmod,dodgemod;
enum LFSIZE sz;
sz = getobsize(o);
// smaller things are harder to catch, but easier to dodge
if (sz >= SZ_HUMAN) {
catchmod = 4;
dodgemod = -3;
} else if (sz == SZ_MEDIUM) {
catchmod = 4;
dodgemod = -1;
} else if (sz == SZ_SMALL) {
catchmod = 0;
dodgemod = 0;
} else if (sz == SZ_TINY) {
catchmod = -3;
dodgemod = 1;
} else if (sz <= SZ_MINI) {
catchmod = -6;
dodgemod = 2;
}
// first check to see if you can catch it
if (!lfhasflag(target, F_NOPACK) && hasbp(target, BP_HANDS) &&
lfhasflag(target, F_HUMANOID) &&
canpickup(target, o, o->amt) &&
!isimmobile(target) &&
skillcheck(target, SC_DEX, 15*speed, catchmod)) {
willcatch = B_TRUE;
} else if (!lfhasflag(target, F_CASTINGSPELL) && skillcheck(target, SC_DODGE, 10*speed, dodgemod)) {
// then check if we dodge it...
youhit = B_FALSE;
}
}
}
// doesn't matter wheter you hit or not...
if (lfhasflag(target, F_UNDEAD) && isblessed(o)) {
if (seen) {
msg("%s recoils in fear!", targetname);
}
o->blessknown = B_TRUE;
// ... but undead won't catch blessed things
willcatch = B_FALSE;
}
if (youhit && lfhasflag(target, F_NONCORPOREAL)) {
youhit = B_FALSE;
willcatch = B_FALSE;
if (seen) {
msg("%s passes straight through %s.", obname, targetname);
announcedmiss = B_TRUE;
}
}
// if someone is there, they take damage and the object might die
// this should be "if target && youhit"
if (youhit) {
if (willcatch) {
if (seen) {
msg("%s catch%s %s.", targetname, isplayer(target) ? "" : "es", obname);
}
moveob(o, target->pack, amt);
return B_FALSE;
} else {
int dam = 0;
char damstring[BUFLEN];
int reduceamt = 0;
int throwdam;
op = addobpile(NOOWNER, NOLOC, NULL);
// split off new object into a fake obpile
// so we don't modify the original stack with
// things like poison rubbing off.
o = real_moveob(o, op, amt, B_FALSE);
o->birthtime = -1;
throwdam = getthrowdam(o);
dam = (int)((float)throwdam * multiplier);
if (db) dblog("fireat(): dam = throwdam(%d) * speed(%d)/2 = %d",throwdam, speed, dam);
// special case
if (o->type->id == OT_RUBBERBULLET) {
dam = 1;
}
// deal extra cutting damage afterwards?
if (willshatter(o->material->id)) {
shattered = B_TRUE;
}
// announce
if (seen) {
char buf2[BUFLEN];
snprintf(buf2, BUFLEN, "%s hit%s %s.",obname,(amt == 1) ? "s" : "", targetname);
if (lfhasflag(player, F_EXTRAINFO)) {
char damstring[BUFLEN];
snprintf(damstring, BUFLEN, " [%d dmg]",dam);
strcat(buf2, damstring);
}
msg("%s", buf2);
}
snprintf(damstring, BUFLEN, "%s (%s by %s)",obname,throwverbpast, realthrowernamea);
reduceamt = getarmourdamreduction(target, o, dam, DT_PROJECTILE);
applyarmourdamreduction(target, o, reduceamt, &dam, DT_PROJECTILE);
if (dam > 0) {
lifeform_t *whogetsxp = NULL;
// TODO: at the moment you won't get experience if you telekenetically
// throw an object at something. is this okay?
if (thrower && (thrower->cell == srcloc)) {
whogetsxp = thrower;
}
losehp_real(target, dam, DT_PROJECTILE, whogetsxp, damstring, B_TRUE, o, B_TRUE);
}
if (reduceamt && (speed >= 3)) {
applyarmourdamage(target, o, reduceamt, DT_PROJECTILE);
}
wepeffects(o->flags, target->cell, hasflag(o->flags, F_DAM), dam);
missiledam += ((speed*2)+1);
if (thrower) {
if (firearm) {
practice(thrower, SK_THROWING, 1);
} else {
practice(thrower, SK_RANGED, 1);
}
}
}
} else { // ie. if !youhit
if (!announcedmiss) {
if (isplayer(thrower)) {
msg("Your %s misses %s.", noprefix(obname), targetname);
} else if (haslos(player, where)) {
msg("%s misses %s.", obname, targetname);
}
announcedmiss = B_TRUE;
}
}
} // end if target
// heavy ob?
if (youhit && target) {
if ((getobunitweight(o)*amt) >= getlfweight(target, B_NOOBS)) {
int dir;
dir = getdirtowards(srcloc, target->cell, target, B_FALSE, DT_COMPASS);
knockback(target, dir, 1, thrower, 0);
}
}
// move the object to the cell then take dam or kill it. don't stack.
newob = real_moveob(o, where->obpile, amt, B_FALSE);
// fake its birth time so that it can be damaged
newob->birthtime = -1;
// now we can get rid of the fake obpile, if we used it
if (op) killobpile(op);
// gun out of ammo?
if (firearm && !countobs(firearm->contents, B_FALSE)) {
outofammo = B_TRUE;
}
if (willshatter(newob->material->id)) {
char dambuf[BUFLEN];
snprintf(dambuf, BUFLEN, "%s (%s by %s)",obname,throwverbpast, realthrowernamea);
shatter(newob, youhit, dambuf, thrower);
} else {
// object only gets damaged if it hit someone/something
if (missiledam) {
// don't announce damage to the thrown object
real_takedamage(newob, missiledam, DT_BASH, B_FALSE);
}
}
if (firearm && outofammo && isplayer(thrower)) {
char buf[BUFLEN];
getobname(firearm, buf, 1);
msg("Your %s is now out of ammo.", noprefix(buf));
}
return B_FALSE;
}
void timeeffectsob(object_t *o) {
flag_t *f;
cell_t *location;
lifeform_t *owner;
object_t *sg;
char obname[BUFLEN],ownername[BUFLEN];
int i;
flag_t *retflag[MAXCANDIDATES];
int nretflags = 0;
if (hasflag(o->flags, F_DEAD)) return;
getobname(o, obname, o->amt);
location = getoblocation(o);
/*
if (o->pile->where) {
location = o->pile->where;
} else {
location = NULL;
}
*/
if (o->pile->owner) {
owner = o->pile->owner;
getlfname(owner, ownername);
} else {
owner = NULL;
}
// special case for trail flags
f = hasflag(o->flags, F_TRAIL);
if (f) {
if (f->lifetime > 0) {
f->lifetime--;
if (f->lifetime <= 0) {
// object dies.
killob(o);
return;
}
}
}
// expire flags
timeeffectsflags(o->flags);
// blessed weapons glow when held near undead
if (isblessed(o) && isweapon(o)) {
cell_t *ourcell;
flag_t *glowflag = NULL;
int nearundead = B_FALSE;
// are we glowing?
getflags(o->flags, retflag, &nretflags, F_PRODUCESLIGHT, F_NONE);
for (i = 0; i < nretflags; i++) {
f = retflag[i];
if ((f->id == F_PRODUCESLIGHT) && (f->lifetime == FROMBLESSING)) {
glowflag = f;
break;
}
}
if (isequipped(o)) {
// do we need to start/stop glowing?
ourcell = getoblocation(o);
if (ourcell) {
int x,y;
// check if we are near undead (ie. within 2 sq)
for (y = ourcell->y - 2; y <= ourcell->y + 2; y++) {
for (x = ourcell->x - 2; x <= ourcell->x + 2; x++) {
cell_t *c;
c = getcellat(ourcell->map, x, y);
if (c && haslf(c) && hasflag(c->lf->flags, F_UNDEAD)) {
nearundead = B_TRUE;
break;
}
}
}
if (nearundead) {
if (!glowflag) {
// start glowing
glowflag = addtempflag(o->flags, F_PRODUCESLIGHT, 2, NA, NA, NULL, FROMBLESSING);
/*
if (isplayer(o->pile->owner)) {
msg("Your %s start%s glowing!",noprefix(obname), (o->amt == 1) ? "s" : "");
if (!o->blessknown) o->blessknown = B_TRUE;
} else if (haslos(player, ourcell)) {
msg("%s start%s glowing!",obname, (o->amt == 1) ? "s" : "");
if (!o->blessknown) o->blessknown = B_TRUE;
}
*/
if (haslos(player, ourcell)) {
if (!o->blessknown) o->blessknown = B_TRUE;
}
calclight(ourcell->map);
setlosdirty(player);
//precalclos(player);
}
} else { // not near undead
if (glowflag) {
killflag(glowflag);
glowflag = NULL;
/*
if (isplayer(o->pile->owner)) {
msg("Your %s stop%s glowing.",noprefix(obname), (o->amt == 1) ? "s" : "");
if (!o->blessknown) o->blessknown = B_TRUE;
} else if (haslos(player, ourcell)) {
msg("%s stop%s glowing.",obname, (o->amt == 1) ? "s" : "");
if (!o->blessknown) o->blessknown = B_TRUE;
}
*/
}
}
}
} else { // not equipped
if (glowflag) { // if not equipped and glowing...
// stop glowing
killflag(glowflag);
glowflag = NULL;
}
}
}
// sacred ground?
sg = hasobwithflagval(location->obpile, F_REPELBLESSED, o->blessed, NA, NA, NULL);
if (sg) {
char sgname[BUFLEN];
cell_t *newc;
int canseeloc = B_FALSE;
if (haslos(player, location) && canseeob(player, sg)) {
getobname(sg, sgname, sg->amt);
canseeloc = B_TRUE;
msg("The %s pulses %s!", noprefix(sgname),
(o->blessed == B_CURSED) ? "white" : "black");
}
// object gets thrown away
newc = getrandomadjcell(location, WE_NOTWALL, B_ALLOWEXPAND);
if (newc) {
//flag_t *inv;
// make sure the object doesn't take damage
//inv = addflag(o->flags, F_INVULNERABLE, B_TRUE, NA, NA, NULL);
fireat(NULL, o, o->amt, newc, 1, NULL);
if (canseeloc) {
// player now knows that this is blessed
o->blessknown = B_TRUE;
}
// update location
//if (inv) killflag(inv);
location = newc;
} else {
// object can't go anywhere - it disintegrates.
if (owner && cansee(player, owner)) {
msg("%s%s vanish%s in a surge of %s power!", ownername, getpossessive(ownername),
obname, (o->amt == 1) ? "es" : "",
(o->blessed = B_CURSED) ? "holy" : "evil");
} else if (haslos(player, location)) {
msg("%s vanish%s in a surge of %s power!", obname, (o->amt == 1) ? "es" : "",
(o->blessed = B_CURSED) ? "holy" : "evil");
}
removeob(o, o->amt);
return;
}
}
if (location) {
// does object's material change cell type?
if (o->material->id == MT_FIRE) {
if (hasflag(location->type->material->flags, F_FLAMMABLE)) {
int changed = B_FALSE;
// burn by changing celltype...
switch (location->type->id) {
case CT_GRASS:
setcelltype(location, CT_DIRT);
break;
default:
break;
}
if (changed && haslos(player, location)) {
msg("The %s burns!", location->type->name);
needredraw = B_TRUE;
}
//setcelltype(location, CT_CORRIDOR);
addob(location->obpile, "pile of ash");
}
}
// checks based on object
if (o->type->id == OT_VINE) {
lifeform_t *creator;
int willvanish = B_FALSE;
// creator no longer has los?
f = hasflag(o->flags, F_CREATEDBY);
if (f) {
creator = findlf(NULL, f->val[0]);
if (!creator || !haslos(creator, location)) {
willvanish = B_TRUE;
}
// noone there?
if (!location->lf) {
willvanish = B_TRUE;
}
if (willvanish) {
// vanish.
if (haslos(player, location)) {
msg("%s vanish%s.", obname, (o->amt == 1) ? "es" : "");
}
killob(o);
return;
}
}
}
}
// check each flag for this object...
getflags(o->flags, retflag, &nretflags, F_ACTIVATED, F_EDIBLE, F_MATCONVERT, F_OBHPDRAIN, F_ONFIRE, F_RECHARGE, F_WALKDAM, F_WET, F_NONE);
for (i = 0; i < nretflags; i++) {
object_t *oo,*nextoo;
f = retflag[i];
// CHECKS FOR CURRENT OBJECT
if (f->id == F_ACTIVATED) {
if (o->type->id == OT_JETPACK) {
// activated jetpack on the ground?
if (location) {
if (haslos(player, location)) {
char obname[BUFLEN];
getobname(o, obname, 1);
msg("%s shoots up into the roof and explodes!",obname);
}
removeob(o, o->amt);
return;
} else {
int chargeleft;
// use up power
chargeleft = usecharge(o);
// out of power?
if (chargeleft <= 0) {
if (owner) {
// announce power loss
if (isplayer(owner)) {
msg("Your %s is out of power!",noprefix(obname));
// you know it's out
f = hasflag(o->flags, F_CHARGES);
f->known = B_TRUE;
}
}
turnoff(NULL, o);
if (owner) {
// user will fall to the ground if not flying in some
// other way
if (!lfhasflag(owner, F_FLYING)) {
if (cansee(player, owner)) {
char lfname[BUFLEN];
getlfname(owner, lfname);
msg("%s crash%s to the ground!",lfname,
isplayer(owner) ? "" : "es");
}
losehp(owner, rnd(1,4), DT_BASH, NULL, "falling");
}
}
} else if (chargeleft <= 10) { // about to run out of power?
if (isplayer(owner)) {
msg("Your %s splutters.", noprefix(obname));
}
// TODO: add smoke!
}
}
} else if (hasflag(o->flags, F_GRENADE)) {
flag_t *f2;
// countdown...
f2 = hasflag(o->flags, F_CHARGES);
if (f2) {
f2->val[0]--;
if (f2->val[0] <= 0) {
// blow up!
takedamage(o, 999, DT_DIRECT);
return;
}
}
}
if (hasflag(o->flags, F_LIGHTSOURCE)) {
flag_t *f2,*mf;
// countdown...
f2 = hasflag(o->flags, F_CHARGES);
if (f2) {
f2->val[0]--;
if (f2->val[0] <= 0) {
// turnoff
turnoff(NULL, o);
mf = hasflag(o->flags, F_CHARGEOUTMSG);
if (mf) obaction(o, mf->text);
needredraw = B_TRUE;
return;
} else if (f2->val[0] <= 50) {
if (onein(6)) {
mf = hasflag(o->flags, F_CHARGELOWMSG);
if (mf) obaction(o, mf->text);
}
}
}
}
}
if (f->id == F_OBHPDRAIN) {
enum DAMTYPE damtype;
//takedamage(o, f->val[0] * firstlftime, DT_DIRECT);
if (f->val[1] == NA) {
damtype = DT_DIRECT;
} else {
damtype = f->val[1];
}
takedamage(o, f->val[0], damtype);
if (hasflag(o->flags, F_DEAD)) return;
}
if ((f->id == F_EDIBLE) && (o->type->id == OT_STEW)) {
f->val[1] -= 20;
if (f->val[1] < 0) {
f->val[1] = 0;
addflag(o->flags, F_TAINTED, B_TRUE, NA, NA, NULL);
}
}
if (f->id == F_RECHARGE) {
flag_t *f2;
f2 = hasflag(o->flags, F_CHARGES);
if (f2 && (f2->val[0] < f2->val[1])) {
f2->val[0] += f->val[0];
if (f2->val[0] == f2->val[1]) {
if (isplayer(o->pile->owner)) {
char obname[BUFLEN];
getobname(o, obname, o->amt);
msg("Your %s is now fully charged.", noprefix(obname));
}
}
}
}
// damaging objects here will damage other objects
if (f->id == F_WALKDAM) {
// everything here takes damage
//damageallobs(o, o->pile, f->val[0] * timespent, f->val[1]);
damageallobs(o, o->pile, roll(f->text), f->val[0]);
//if (hasflag(o->flags, F_DEAD)) return;
}
// is object on fire?
if (f->id == F_ONFIRE) {
// water puts out fire
for (oo = o->pile->first ; oo ; oo = nextoo) {
nextoo = oo->next;
if ((oo != o) && (oo->material->id == MT_WATER)) {
extinguish(o);
continue;
}
}
// if it hasn't been extinguished, fire burns
takedamage(o, 2, DT_FIRE); // TODO: don't hardcode
if (hasflag(o->flags, F_DEAD)) return;
}
// will current object convert other obs to something else?
if ((f->id == F_MATCONVERT) && !hasflag(o->flags, F_NOMATCONVERT)) {
enum MATERIAL mat;
mat = f->val[0];
for (oo = o->pile->first ; oo ; oo = nextoo) {
flag_t *f2;
nextoo = oo->next;
if ((oo != o) && (oo->material->id == mat)) {
char buf[BUFLEN];
object_t *newob;
// TODO: remove the old object first
// in case the obpile doesn't have space
// to fit both the new and old ones.
// place item of this type here!
snprintf(buf, BUFLEN, "%d %s", o->amt, f->text);
newob = addob(o->pile, buf);
if (newob) {
int cansee;
// make the weight match.
newob->weight = o->weight;
// announce it?
cansee = B_FALSE;
if (location && haslos(player, location)) {
cansee = B_TRUE;
} else if (o->pile->owner == player) {
cansee = B_TRUE;
}
if (cansee) {
f2 = NULL;
if (o->amt > 1) {
f2 = hasflagval(o->flags, F_MATCONVERTTEXTPL, mat, NA, NA,NULL);
}
if (!f2) {
f2 = hasflagval(o->flags, F_MATCONVERTTEXT, mat, NA, NA, NULL);
}
if (f2) {
char *locbuf;
getobname(o, buf, o->amt);
locbuf = strdup(buf);
capitalise(locbuf);
if (o->pile->owner == player) {
// Remove prefix
locbuf = strrep(locbuf, "An ", "", NULL);
locbuf = strrep(locbuf, "A ", "", NULL);
}
msg("%s%s %s.", (o->pile->owner == player) ? "Your " : "", locbuf, f2->text);
free(locbuf);
}
}
// remove original object
removeob(o, o->amt);
return;
}
}
}
}
if (f->id == F_WET) {
if (isequipped(o) || !o->pile->owner) {
cell_t *ourcell;
object_t *splash;
ourcell = getoblocation(o);
// drip
if (!hasobwithflag(ourcell->obpile, F_DEEPWATER)) {
splash = addob(ourcell->obpile, "splash of water");
}
}
}
} // end for each object flag
}
// both trapob and oid are passed, because trapob might be NULL if
// coming from a door/chest trap.
void trapeffects(object_t *trapob, enum OBTYPE oid, cell_t *c) {
lifeform_t *lf = NULL;
char lfname[BUFLEN];
int avoided = B_FALSE;
enum CHECKTYPE ct;
objecttype_t *temp = NULL;
lf = c->lf;
if (lf) getlfname(lf, lfname);
temp = findot(oid);
// saving throw?
if (temp && lf) {
flag_t *f;
f = hasflag(temp->flags, F_TRAP);
if (f && (f->val[2] != NA)) {
if (isplayer(lf) && hasflag(temp->flags, F_SECRET)) {
avoided = B_FALSE;
} else {
int mod = 0;
switch (oid) {
case OT_TRAPTRIP: ct = SC_FALL; break;
default:
ct = SC_DODGE;
break;
}
// easier to avoid if you're sneaking
if (lfhasflag(lf, F_SNEAK)) mod += 5;
mod += getskill(lf, SK_TRAPS);
avoided = skillcheck(lf, ct, f->val[2], mod);
}
}
}
if (oid == OT_TRAPWIND) {
// can't be dodged
dospelleffects(NULL, OT_S_GUSTOFWIND, 10, NULL, NULL, c, B_UNCURSED, NULL, B_TRUE);
if (trapob) removeob(trapob, trapob->amt); // trap dies afterwards
} else if (oid == OT_TRAPNEEDLEP) {
if (lf) {
if (isplayer(lf)) {
msg("A needle shoots out %s", avoided ? "at you, but misses." : "and hits you!");
} else if (cansee(player, lf)) {
if (avoided) {
msg("A needle shoots out at %s, but misses.",lfname);
} else {
msg("A needle shoots out and hits %s!",lfname);
}
}
if (!avoided) {
poison(lf, rnd(10,20), P_VENOM, 1, "a needle trap");
}
} else {
if (haslos(player, c)) {
// TODO: "...shoots out of xxx". need to pass obfrom to this.
msg("A poisoned needle fires, then falls to the ground.");
addob(c->obpile, "poisoned needle");
}
}
if (trapob) removeob(trapob, trapob->amt); // trap dies afterwards
} else if (oid == OT_TRAPROCK) {
if (lf) {
if (haslos(player, c)) {
msg("A heavy rock drops onto %s%s", lfname,
avoided ? ", but misses." : "!");
}
if (!avoided) {
losehp(lf, roll("1d4"), DT_BASH, NULL, "a falling rock trap");
}
} else {
if (haslos(player, c)) {
msg("A heavy rock drops from the ceiling.");
}
}
addob(c->obpile, "stone");
} else if (oid == OT_TRAPTELEPORT) {
dospelleffects(NULL, OT_S_DISPERSAL, 10, NULL, NULL, c, B_UNCURSED, NULL, B_TRUE);
} else if (oid == OT_TRAPPIT) {
cell_t *escapeto = NULL;
addob(c->obpile, "hole in the ground");
if (trapob) removeob(trapob, trapob->amt); // trap dies afterwards
if (lf) {
if (avoided) {
escapeto = getrandomadjcell(lf->cell, WE_WALKABLE, B_NOEXPAND);
if (!escapeto) avoided = B_FALSE;
}
if (avoided) {
if (isplayer(lf)) {
msg("You leap away from the pit!");
} else if (cansee(player, lf)) {
msg("%s leaps away from a pit!", lfname);
}
movelf(lf, escapeto);
}
}
} else if (oid == OT_TRAPALARM) {
noise(c, NULL, NC_OTHER, 10, "a blaring siren!", NULL);
} else if ((oid == OT_TRAPARROW) || (oid == OT_TRAPARROWP)) {
int dir,bestdir = D_NONE;
cell_t *src = NULL;
int maxdist=-1;
// get furthest wall
for (dir = DC_N; dir <= DC_NW; dir++) {
cell_t *cc,*prevc;
int thisdist = 0;
prevc = NULL;
cc = c;
cc = getcellindir(cc, dir);
while (!cc->type->solid) {
thisdist++;
prevc = cc;
cc = getcellindir(cc, dir);
}
if (thisdist > maxdist) {
maxdist = thisdist;
bestdir = dir;
src = prevc;
}
}
if (src && (bestdir != D_NONE)) {
object_t *o;
if (oid == OT_TRAPARROWP) {
o = addob(src->obpile, "poisoned arrow");
} else {
o = addob(src->obpile, "arrow");
}
if (o) {
// dodge check will happen in fireat(). ignore results of the
// one above.
fireat(NULL, o, 1, c, 5, NULL);
} else {
msg("ERROR: arrow trap failed.");
dblog("ERROR: arrow trap failed.");
}
} else {
msg("ERROR: arrow trap failed (no dir).");
dblog("ERROR: arrow trap failed (no dir).");
}
} else if (oid == OT_TRAPEBLAST) {
if (haslos(player, c)) {
msg("A blast of energy comes out of nowhere!");
}
// can't be dodged
dospelleffects(NULL, OT_S_ENERGYBLAST, 1, NULL, NULL, c, B_UNCURSED, NULL, B_TRUE);
if (trapob) removeob(trapob, trapob->amt); // trap dies afterwards
} else if (oid == OT_TRAPFIRE) {
// can't be dodged
dospelleffects(NULL, OT_S_FLAMEPILLAR, 3, NULL, NULL, c, B_UNCURSED, NULL, B_TRUE);
if (trapob) removeob(trapob, trapob->amt); // trap dies afterwards
} else if (oid == OT_TRAPGAS) {
// can't be dodged
dospelleffects(NULL, OT_S_CLOUDKILL, 3, NULL, NULL, c, B_UNCURSED, NULL, B_TRUE);
if (trapob) removeob(trapob, trapob->amt); // trap dies afterwards
} else if (oid == OT_TRAPMINE) {
// can't be dodged
explodecells(c, roll("2d6"), B_FALSE, trapob, 1, DT_ORTH, B_TRUE);
if (trapob) removeob(trapob, trapob->amt); // trap dies afterwards
} else if (oid == OT_TRAPSUMMON) {
cell_t *cc;
// can't be dodged
cc = getrandomadjcell(c, WE_WALKABLE, B_ALLOWEXPAND);
if (cc) {
summonmonster(NULL, cc, R_SPECIFIED, "random", PERMENANT, B_FALSE);
}
if (trapob) removeob(trapob, trapob->amt); // trap dies afterwards
} else if (oid == OT_TRAPTRIP) {
if (lf) {
if (avoided) {
if (isplayer(lf)) {
msg("You retain your balance.");
} else if (cansee(player, lf)) {
msg("%s retains its balance.",lfname);
}
} else {
fall(lf, NULL, B_TRUE);
}
}
}
}
void turnoff(lifeform_t *lf, object_t *o) {
char obname[BUFLEN];
flag_t *f;
f = hasflag(o->flags, F_ACTIVATED);
if (!f) {
// already off
return;
}
// reset charges
if (hasflag(o->flags, F_RECHARGEWHENOFF)) {
f = hasflag(o->flags, F_CHARGES);
if (f) {
f->val[0] = f->val[1];
}
}
getobname(o, obname, 1);
if (lf) {
if (isplayer(lf)) {
msg("You deactivate your %s.",noprefix(obname));
} else if (cansee(player, lf)) {
char lfname[BUFLEN];
getlfname(lf, lfname);
msg("%s deactivates %s.",lfname, obname);
}
}
if (hasflag(o->flags, F_GRENADE)) {
object_t *stackob;
// make it stackable again
addflag(o->flags, F_STACKABLE, B_TRUE, NA, NA, NULL);
// other stacks to join?
stackob = canstackob(o->pile, o);
if (stackob) {
char stackname[BUFLEN];
// remove it, and inc amt on the stack
removeob(o, 1);
stackob->amt++;
getobname(stackob, stackname, stackob->amt);
msgnocap("%c - %s.",stackob->letter, stackname);
} else {
// just turn off
killflag(f);
}
} else {
killflag(f);
}
if (o->pile->owner) {
loseobflags(o->pile->owner, o, F_ACTIVATECONFER);
}
}
void turnon(lifeform_t *lf, object_t *o) {
char obname[BUFLEN];
flag_t *f;
int held = B_FALSE;
if (lf && (o->pile->owner == lf)) {
held = B_TRUE;
}
f = hasflag(o->flags, F_ACTIVATED);
if (f) {
// already on
if (lf && isplayer(lf)) {
if (held) {
msg("Your %s is already activated!\n", noprefix(obname));
} else {
msg("%s is already activated!\n", obname);
}
}
return;
}
// check charges
f = hasflag(o->flags, F_CHARGES);
if (f && (f->val[0] <= 0)) {
// out of power
if (lf && isplayer(lf)) {
nothinghappens();
}
return;
}
getobname(o, obname, 1);
if (lf) {
if (isplayer(lf)) {
msg("You activate%s %s.", held ? " your" : "",
held ? noprefix(obname) : obname);
} else if (cansee(player, lf)) {
char lfname[BUFLEN];
getlfname(lf, lfname);
msg("%s activates %s.",lfname, obname);
}
}
// for grenades, give a new object which is activated
if (hasflag(o->flags, F_GRENADE)) {
object_t *newob;
newob = splitob(o);
if (newob) {
char newobname[BUFLEN];
// announce new ob
addflag(newob->flags, F_ACTIVATED, B_TRUE, NA, NA, NULL);
getobname(newob, newobname, 1);
if (lf && isplayer(lf)) {
if (held) {
msgnocap("%c - %s [activated].",newob->letter, newobname);
} else {
msgnocap("You activate %s.",newob->letter, newobname);
}
}
} else {
if (isplayer(lf)) {
msg("You don't have room for an activated %s!",noprefix(obname));
}
}
} else {
addflag(o->flags, F_ACTIVATED, B_TRUE, NA, NA, NULL);
}
if (held) {
giveobflags(lf, o, F_ACTIVATECONFER);
}
}
int uncurseob(object_t *o, int *seen) {
lifeform_t *lf = NULL;
// default
if (seen) *seen = B_FALSE;
if (o->blessed != B_CURSED) {
return B_TRUE;
}
lf = o->pile->owner;
// announce
if (lf) {
if (cansee(player, lf)) {
char lfname[BUFLEN];
char obname[BUFLEN];
getlfname(lf, lfname);
getobname(o, obname,o->amt);
msg("A black aura breaks away from %s%s %s.",lfname,getpossessive(lfname),noprefix(obname));
if (seen) *seen = B_TRUE;
}
} else { // not held
cell_t *loc = NULL;
loc = getoblocation(o);
if (haslos(player, loc)) {
char obname[BUFLEN];
getobname(o, obname,o->amt);
msg("A black aura breaks away from %s.",obname);
if (seen) *seen = B_TRUE;
}
}
// uncurse it
o->blessed = B_UNCURSED;
o->blessknown = B_TRUE;
return B_FALSE;
}
// returns charges remaining, -1 if object doesn't have the flag
int usecharge(object_t *o) {
flag_t *f;
f = hasflag(o->flags, F_CHARGES);
if (f) {
f->val[0]--;
return f->val[0];
}
return -1;
}
int validateobs(void) {
objecttype_t *ot;
int foundspells = B_FALSE;
int goterror = B_FALSE;
flag_t *f;
for (ot = objecttype ; ot ; ot = ot->next) {
// fix up glyphs
f = hasflag(ot->flags, F_GLYPH);
if (f) {
if (f->val[0] == NA) {
f->val[0] = getmaterialcolour(ot->material->id);
}
}
if ((ot->obclass->id == OC_SPELL) || (ot->obclass->id == OC_ABILITY)) {
if (!foundspells) foundspells = B_TRUE;
if (!hasflag(ot->flags, F_SPELLSCHOOL)) {
printf("ERROR - spell %s doesn't have F_SPELLSCHOOL.\n", ot->name);
goterror = B_TRUE;
}
/*
if (!hasflag(ot->flags, F_SPELLLETTER)) {
printf("ERROR - spell %s doesn't have F_SPELLLETTER.\n", ot->name);
goterror = B_TRUE;
}
*/
if ((ot->obclass->id == OC_SPELL) && !hasflag(ot->flags, F_SPELLLEVEL)) {
printf("ERROR - spell %s doesn't have F_SPELLLEVEL.\n", ot->name);
goterror = B_TRUE;
}
f = hasflag(ot->flags, F_SPELLLEVEL);
if (f && (f->val[0] > MAXSPELLLEV)) {
printf("ERROR - spell %s level (%d) > MAXSPELLLEVEL (%d).\n", ot->name, f->val[0], MAXSPELLLEV);
goterror = B_TRUE;
}
} else if (ot->obclass->id == OC_SCROLL) {
if (foundspells) {
printf("ERROR in object '%s' - all Scrolls must be defined before Spells.\n", ot->name);
goterror = B_TRUE;
}
} else if (ot->obclass->id == OC_WEAPON) {
if (!hasflag(ot->flags, F_USESSKILL) && !hasflag(ot->flags, F_FIREARM)) {
if (ot->id != OT_ENERGYBLADE) {
printf("ERROR in object '%s' - weapon has no associated skill.\n", ot->name);
goterror = B_TRUE;
}
}
}
if (hasflagval(ot->flags, F_PICKLOCKS, NA, B_BLUNTONFAIL, NA, NULL) && hasflag(ot->flags, F_STACKABLE)) {
printf("ERROR in object '%s' - cannot have F_BLUNTONFAIL on stackable objects.\n", ot->name);
goterror = B_TRUE;
}
if (hasflag(ot->flags, F_FIREARM)) {
if (!hasflag(ot->flags, F_RANGE)) {
printf("ERROR in object '%s' - firearms need to have F_RANGE.\n", ot->name);
goterror = B_TRUE;
}
if (!hasflag(ot->flags, F_AMMOCAPACITY)) {
printf("ERROR in object '%s' - firearms need to have F_AMMOCAPACITY.\n", ot->name);
goterror = B_TRUE;
}
if (!hasflag(ot->flags, F_FIRETURNS)) {
printf("ERROR in object '%s' - firearms need to have F_AMMOCAPACITY.\n", ot->name);
goterror = B_TRUE;
}
if (!hasflag(ot->flags, F_RELOADTURNS)) {
printf("ERROR in object '%s' - firearms need to have F_AMMOCAPACITY.\n", ot->name);
goterror = B_TRUE;
}
}
f = hasflag(ot->flags, F_TECHLEVEL);
if (f && (f->val[0] != PR_INEPT)) {
if (!hasflag(ot->flags, F_HASHIDDENNAME)) {
printf("ERROR in object '%s' - has a techlevel but doesn't have a hidden name.\n", ot->name);
goterror = B_TRUE;
}
}
f = hasflag(ot->flags, F_MANUALOF);
if (f && !findskill(f->val[0])) {
printf("ERROR in object '%s' - teachs a skill which doesn't exist.\n", ot->name);
goterror = B_TRUE;
}
f = hasflag(ot->flags, F_DAM);
if (f) {
if (f->val[0] < 0) {
printf("ERROR in object '%s' - F_DAM does not specify damage type.\n", ot->name);
goterror = B_TRUE;
}
if (!strlen(f->text)) {
printf("ERROR in object '%s' - F_DAM does not have dice string.\n", ot->name);
goterror = B_TRUE;
}
}
f = hasflag(ot->flags, F_EXPLODEONDAM);
if (f && !strlen(f->text)) {
printf("ERROR in object '%s' - F_EXPLODEONDAM does not have damage string.\n", ot->name);
goterror = B_TRUE;
}
f = hasflag(ot->flags, F_EXPLODEONDEATH);
if (f && !strlen(f->text)) {
printf("ERROR in object '%s' - F_EXPLODEONDEATH does not have damage string.\n", ot->name);
goterror = B_TRUE;
}
if (hasflag(ot->flags, F_HITCONFER) && !hasflag(ot->flags, F_HITCONFERVALS)) {
printf("ERROR in object '%s' - has F_HITCONFER, but no HITCONFERVALS defined.\n", ot->name);
goterror = B_TRUE;
}
if (hasflag(ot->flags, F_OBDIETEXT) && hasflag(ot->flags, F_NOOBDIETEXT)) {
printf("ERROR in object '%s' - has both dietext & noobdietext.\n", ot->name);
goterror = B_TRUE;
}
f = hasflag(ot->flags, F_THEREISHERE);
if (f && !strlen(f->text)) {
printf("ERROR in object '%s' - has f_thereishere but no ->text.\n", ot->name);
goterror = B_TRUE;
}
f = hasflag(ot->flags, F_IMPASSABLE);
if (f && ((f->val[0] == NA) || (f->val[1] == NA)) ) {
printf("ERROR in object '%s' - f_impassable missing either min or max.\n", ot->name);
goterror = B_TRUE;
}
f = hasflag(ot->flags, F_DOOR);
if (f) {
flag_t *f2;
f2 = hasflag(ot->flags, F_IMPASSABLE);
if (f2) {
if ((f->val[0] != f2->val[0]) || (f->val[1] != f2->val[1])) {
printf("ERROR in object '%s' - f_door vals don't match f_impassable vals.\n", ot->name);
goterror = B_TRUE;
}
} else {
printf("ERROR in object '%s' - has f_door but not f_impassable.\n", ot->name);
goterror = B_TRUE;
}
}
}
/*
for (sk = firstskill ; sk ; sk = sk->next) {
int found = B_FALSE;
// make sure every skill have an object providing it
for (ot = objecttype ; ot ; ot = ot->next) {
if (hasflagval(ot->flags, F_MANUALOF, sk->id, NA, NA, NULL)) {
found = B_TRUE;
break;
}
}
if (!found) {
printf("ERROR - skill '%s' has no matching manual.\n", sk->name);
goterror = B_TRUE;
}
}
*/
return goterror;
}
int wepdullable(object_t *o) {
enum DAMTYPE dt;
if (!o) return B_FALSE;
dt = getdamtype(o);
switch (dt) {
case DT_PIERCE:
case DT_SLASH:
return B_TRUE;
default:
break;
}
return B_FALSE;
}
int willshatter(enum MATERIAL mat) {
switch (mat) {
case MT_GLASS:
case MT_ICE:
return B_TRUE;
default: break;
}
return B_FALSE;
}
int getcritchance(lifeform_t *lf, object_t *o, lifeform_t *victim) {
flag_t *f;
int chance = 0;
if (!o) return 0;
f = hasflag(o->flags, F_CRITCHANCE);
if (f) {
chance += f->val[0];
}
if (lf) {
enum SKILLLEVEL weplev = PR_INEPT;
skill_t *wepsk = NULL;
wepsk = getobskill(o);
if (wepsk) {
weplev = getskill(lf, wepsk->id);
if (weplev != PR_INEPT) {
chance += (weplev*5); // ie. up to 30% bonus
}
}
}
// double crit chance if victim is vulnerable to this weapon
if (victim && lfhasflagval(victim, F_MATVULN, o->material->id, NA, NA, NULL)) {
chance *= 2;
}
return chance;
}
// determine how long a conferred effect should last, based on its blessed/cursed status.
// blessed: always max
// uncursed: random number between min & max
// cursed: always min
int geteffecttime(int min, int max, enum BLESSTYPE isblessed) {
int howlong;
// how long for?
switch (isblessed) {
case B_BLESSED:
howlong = 15;
break;
case B_CURSED:
howlong = 5;
break;
default: // ie. B_UNCURSED
howlong = rnd(5,15);
break;
}
return howlong;
}
objecttype_t *getlinkspell(object_t *o) {
flag_t *f = NULL;
objecttype_t *spelltype = NULL;
f = hasflag(o->flags, F_LINKSPELL);
if (f) {
// find the linked spell
spelltype = findot(f->val[0]);
}
return spelltype;
}
enum COLOUR getmaterialcolour(enum MATERIAL mat) {
enum COLOUR col;
switch (mat) {
case MT_WOOD:
case MT_LEATHER:
col = C_BROWN;
break;
case MT_FIRE:
case MT_BLOOD:
col = C_RED;
break;
case MT_GLASS:
case MT_MAGIC:
col = C_CYAN;
break;
case MT_ICE:
col = C_WHITE;
break;
case MT_GOLD:
col = C_YELLOW;
break;
case MT_WATER:
col = C_BLUE;
break;
case MT_SLIME:
case MT_ACID:
col = C_GREEN;
break;
default:
col = C_GREY;
}
return col;
}
// is the given material solid or liquid?
enum MATSTATE getmaterialstate(enum MATERIAL mat) {
switch (mat) {
case MT_FIRE:
case MT_MAGIC:
case MT_NOTHING:
return MS_OTHER;
case MT_ACID:
case MT_BLOOD:
case MT_OIL:
case MT_WATER:
return MS_LIQUID;
case MT_GAS:
return MS_GAS;
default:
return MS_SOLID;
}
return MS_OTHER; // should never happen
}
int getmissileaccuracy(lifeform_t *thrower, cell_t *where, object_t *missile, object_t *firearm, enum ATTRIB whichatt) {
int acc,maxrange,howfar;
enum SKILLLEVEL slev;
// figure out if you miss or not, based on distance and
// dexterity
// base:
// if throwing, 40% + 10*sk_throwing
// if firing, gun accuracy modified by sk_ranged
// adjust for range:
// pointblank = +30%
// max = -30%
// then modify using dexterity/int/whatever
// then penalise for throwing non-missiles
// base accuracy
if (firearm) {
slev = getskill(thrower, SK_RANGED);
acc = getobaccuracy(firearm, thrower);
// ie. inept = -30%, adept = 0%, master = +30%
acc += ((slev - PR_ADEPT) * 10);
} else {
slev = getskill(thrower, SK_THROWING);
acc = 40;
// ie. inept = -30%, adept = 0%, master = +30%
acc += ((slev - PR_ADEPT) * 10);
// acc will now be 10 - 70
}
// adjust for range
if (firearm || missile) {
if (firearm) {
maxrange = getfirearmrange(firearm);
} else {
maxrange = getmaxthrowrange(thrower, missile);
}
} else {
maxrange = getvisrange(thrower, B_TRUE);
}
howfar = getcelldist(thrower->cell, where);
// ie. -30 to 30
if (firearm && (slev == PR_MASTER) ) {
} else {
int rangemod;
rangemod = 30 - ((int) (((float)howfar / (float)maxrange) * 60.0));
acc += rangemod;
}
/*
if (howfar == 1) {
acc += 30;
} else if (howfar == maxrange) {
if (slev != PR_MASTER) {
acc -= 30;
}
}
*/
// modify for dexterity
if (whichatt != A_NONE) {
acc += getstatmod(thrower, whichatt);
}
// penalty for throwing non-missiles
if (missile && !firearm && !isthrowmissile(missile)) {
acc -= 20;
}
// modify for prone throwers
if (isprone(thrower)) {
acc -= 50;
}
// modify for prone defenders
if (where->lf && isprone(where->lf)) {
acc -= 30;
}
limit(&acc, 0, NA);
return acc;
}