370 lines · 5.4 KB · C
RawDownload
#include <u.h>#include <libc.h>#include <thread.h>#include <draw.h>#include <bio.h>#include <ndb.h> #include "map.h"#include "bt.h" #include "dat.h" enum{	ITEMNAME	= 0,	ITEMTILE,	ITEMTYPE,	ITEMCOST,	ITEMWEIGHT,	ITEMATK,	ITEMAC,	ITEMHEAL,	ITEMSTACKS,}; static char *itemdbcmd[] = {[ITEMNAME]		"item",[ITEMTILE]		"tile",[ITEMTYPE]		"type",[ITEMCOST]		"cost",[ITEMWEIGHT]		"weight",[ITEMATK]		"atk",[ITEMAC]		"ac",[ITEMHEAL]		"heal",[ITEMSTACKS]	"stacks", }; static char *itemtype[] = {[IWEAPON]	"weapon",[IHELMET]	"helmet",[ICLOAK]	"cloak",[ISHIELD]	"shield",[IARMOR]	"armor",[IGLOVES]	"gloves",[IBOOTS]	"boots",[ICONSUME]	"consumable",}; char*itypetoname(int type){	if(type < 0 || type > nelem(itemtype)-1)		return nil;	return itemtype[type];} static Ndb *itemdb; static intifmt(Fmt *f){	char *name, extra[64];	Item *i; 	extra[0] = 0;	i = va_arg(f->args, Item*); 	if(i->name != nil)		name = i->name;	else		name = i->id->name; 	switch(i->id->type){	case IWEAPON:		snprint(extra, sizeof(extra), " (%dd%d)", i->id->rolls, i->id->atk);		break;	case IHELMET:	case ICLOAK:	case ISHIELD:	case IARMOR:	case IGLOVES:	case IBOOTS:		snprint(extra, sizeof(extra), " (ac %d)", i->id->ac);		break;	case ICONSUME:		snprint(extra, sizeof(extra), " (heal %d)", i->id->heal);		break;	} 	if(f->flags & FmtSharp)		return fmtprint(f, "%s%s", name, extra); 	if(i->count != 1)		return fmtprint(f, "%d %ss%s", i->count, name, extra);	return fmtprint(f, "a %s%s", name, extra);} intitemdbopen(char *file){	fmtinstall('i', ifmt); 	itemdb = ndbopen(file);	if(itemdb == nil)		return 0;	return 1;} typedef struct idcache idcache;struct idcache{	ItemData *id;	idcache *next;}; static idcache *itemcache = nil; /* TODO: sanity checks */static intidaddattr(ItemData *id, int attr, char *val){	int i; 	switch(attr){	case ITEMNAME:		strncpy(id->name, val, sizeof(id->name)-1);		id->name[sizeof(id->name)-1] = 0;		break;	case ITEMTILE:		id->tile = atoi(val);		break;	case ITEMTYPE:		for(i = 0; i < nelem(itemtype); i++){			if(strcmp(val, itemtype[i]) == 0){				id->type = i;				return 1;			}		}		werrstr("unknown item type '%s'", val);		return 0;		break;	case ITEMCOST:		id->cost = atoi(val);		break;	case ITEMWEIGHT:		id->weight = atoi(val);		break;	case ITEMATK:		if(!parseroll(val, &id->rolls, &id->atk)){			werrstr("bad roll '%s'", val);			return 0;		}		break;	case ITEMAC:		id->ac = atoi(val);		break;	case ITEMHEAL:		id->heal = atoi(val);		break;	case ITEMSTACKS:		id->flags |= IFSTACKS;		break;	default:		return 0;	} 	return 1;} /* resolve a list name into a random item on that list * or inner list if recursive */static ItemData*idbylistname(char *list){	int i, cnt, pick;	Ndbtuple *t, *nt;	Ndbs search;	ItemData *id; 	t = ndbsearch(itemdb, &search, "itemlist", list);	if(t == nil)		return nil; 	/* count items */	cnt = 0;	for(nt = t; nt != nil; nt = nt->entry){		if(strcmp(nt->attr, "items") == 0)			cnt++;	} 	if(cnt == 0)		sysfatal("no items in itemlist '%s'", list); 	/* pick random item */	pick = nrand(cnt); 	/* walk this many forward */	i = 0;	id = nil;	for(nt = t; nt != nil; nt = nt->entry){		if(strcmp(nt->attr, "items") == 0 && i++ == pick){			id = idbyname(nt->val);			break;		}	} 	ndbfree(t); 	return id;} ItemData*idbyname(char *item){	int i;	Ndbtuple *t, *nt;	Ndbs search;	ItemData *id;	idcache *idc; 	/* cached? */	for(idc = itemcache; idc != nil; idc = idc->next){		if(strcmp(item, idc->id->name) == 0){			return idc->id;		}	} 	t = ndbsearch(itemdb, &search, "item", item); 	/*	 * if there is no item by this name, lookup an	 * item list by that name. if that exits, pick a	 * random item from the list.	 */	if(t == nil)		return idbylistname(item); 	id = emalloc(sizeof(ItemData)); 	for(nt = t; nt != nil; nt = nt->entry){		for(i = 0; i < nelem(itemdbcmd); i++){			if(strcmp(nt->attr, itemdbcmd[i]) == 0){				if(!idaddattr(id, i, nt->val))					sysfatal("bad item value '%s=%s': %r", nt->attr, nt->val);				goto okattr;			}		}		sysfatal("unknown item attribute '%s'", nt->attr);okattr:		continue;	} 	ndbfree(t); 	idc = emalloc(sizeof(idcache)); 	if(itemcache == nil){		itemcache = idc;		itemcache->id = id;	} else {		idc->id = id;		idc->next = itemcache;		itemcache = idc;	} 	return id;} Item*ibyname(char *item){	ItemData *id;	Item *i; 	id = idbyname(item);	if(id == nil)		goto missing; 	i = mallocz(sizeof(Item), 1);	assert(i != nil); 	i->count = 1;	i->id = id; 	incref(&i->ref); 	return i;missing:	werrstr("missing data for item '%s'", item);	return nil; } voidifree(Item *i){	if(i == nil)		return; 	if(decref(&i->ref) != 0)		return; 	free(i);} voidilfree(ItemList *il){	Item *i, *next;	for(i = il->head; i != nil; i = next){		next = i->next;		ifree(i);	}} /* take n'th item out of il. */Item*iltakenth(ItemList *il, int n){	int j;	Item *i, *prev; 	i = il->head;	prev = nil;		for(j = 0; j < n && i != nil; j++){		prev = i;		i = i->next;	} 	if(i == nil)		return nil; 	if(n != 0)		prev->next = i->next;	else		il->head = il->head->next; 	il->count--; 	return i;} Item*ilnth(ItemList *il, int n){	int j;	Item *i; 	i = il->head;		for(j = 0; j < n && i != nil; j++){		i = i->next;	} 	if(i == nil)		return nil; 	return i;} voidiladd(ItemList *il, Item *i){	i->next = il->head;	il->head = i;	il->count++;}