/* $Header: /belch_a/users/rearl/tinymuck/src/RCS/property.c,v 1.5 90/09/16 04:42:47 rearl Exp $ */
/*
* $Log: property.c,v $
* Revision 1.5 90/09/16 04:42:47 rearl
* Preparation code added for disk-based MUCK.
*
* Revision 1.4 90/09/15 22:27:45 rearl
* Fixed dangerous COMPRESS-related bug.
*
* Revision 1.3 90/09/10 02:19:49 rearl
* Introduced string compression of properties, for the
* COMPRESS compiler option.
*
* Revision 1.2 90/08/02 18:50:00 rearl
* Fixed NULL pointer problem in get_property_class().
*
* Revision 1.1 90/07/19 23:04:03 casie
* Initial revision
*
*
*/
#include "copyright.h"
#include "config.h"
#include "params.h"
#include "db.h"
#include "externs.h"
/* property.c
A whole new lachesis mod.
Adds property manipulation routines to TinyMUCK. */
/* IN ALL CASES, the argument "value" is referred to only when "class" is
a NULL string. */
/* modify a property list */
void insert_prop(struct plist *start, const char *type, const char *class)
{
struct plist *curr, *prev;
int diff;
for(curr = start; curr; curr = curr -> next)
{
diff = string_compare(type, curr -> type);
if(diff < 0)
{
prev -> next = new_prop();
prev = prev -> next;
prev -> type = alloc_string(type);
prev -> class = alloc_compressed(class);
prev -> next = curr;
return;
}
if(diff == 0)
{
if(curr -> class)
free((void *) curr -> class);
curr -> class = alloc_compressed(class);
return;
}
prev = curr;
}
prev -> next = new_prop();
prev = prev -> next;
prev -> type = alloc_string(type);
prev -> class = alloc_compressed(class);
}
/* adds a new property to an object */
void
add_property(dbref player, const char *type, const char *class)
{
struct plist *p, *new;
if (!type || !*type || index(type, PROP_DELIMITER)) return;
/* stick properties at the end because most frequently used ones
will be put in front. */
if(*type == PROP_WIZARD)
p = DBFETCH(player) -> attributes;
else
p = DBFETCH(player) -> properties;
if(p) {
if(string_compare(type, p -> type) >= 0) {
insert_prop(p, type, class);
return;
}
}
if(*type == PROP_WIZARD) {
DBSTORE(player, attributes, new_prop());
new = DBFETCH(player)->attributes;
}
else {
DBSTORE(player, properties, new_prop());
new = DBFETCH(player)->properties;
}
new -> type = alloc_string(type);
new -> class = alloc_compressed(class);
new -> next = p;
}
void add_attr(dbref player, const char *type, const char *class)
{
char *attribute = (char *) calloc(strlen(type) + 2, sizeof(char));
*attribute = PROP_WIZARD;
strcat(attribute, type);
if(class && *class)
add_property(player, attribute, class);
free((void *) attribute);
}
void delete_prop(struct plist *start, const char *type)
{
struct plist *curr, *prev;
int diff = 0;
prev = start;
for(curr = prev -> next; curr && (diff >= 0); curr = curr -> next)
{
diff = string_compare(type, curr -> type);
if(diff == 0)
{
prev -> next = curr -> next;
free_prop(curr);
return;
}
prev = curr;
}
}
/* removes property list --- if it's not there then ignore */
void
remove_property(dbref player, const char *type)
{
struct plist *p;
if(*type == PROP_WIZARD)
p = DBFETCH(player) -> attributes;
else
p = DBFETCH(player) -> properties;
if(p) {
if(string_compare(type, p -> type)) {
delete_prop(p, type);
}
else {
if(*type == PROP_WIZARD) {
DBSTORE(player, attributes, p -> next);
}
else {
DBSTORE(player, properties, p -> next);
}
free_prop(p);
}
}
}
/* checks if object has property, returning 1 if it or any of it's contents has
the property stated */
int
has_property(dbref player, const char *type, const char *class)
{
dbref things;
if (has_property_strict(player, type, class))
return 1;
for (things = DBFETCH(player)->contents;
things != NOTHING;
things = DBFETCH(things)->next)
if (has_property_strict(things, type, class))
return 1;
return 0;
}
struct plist * find_prop(struct plist *start, const char *type)
{
struct plist *p;
int diff = 0;
for(p = start; p && (diff >= 0); p = p -> next)
{
diff = string_compare(type, p -> type);
if(diff == 0)
return p;
}
return (struct plist *) 0;
}
/* checks if object has property, returning 1 if it has the property asked for */
int
has_property_strict(dbref player, const char *type, const char *class)
{
struct plist *p;
const char *str;
str = get_compress(DoNull(class));
if(*type == PROP_WIZARD)
p = find_prop(DBFETCH(player)->attributes, type);
else
p = find_prop(DBFETCH(player)->properties, type);
if(p)
return (!string_compare(str, p -> class));
return 0;
}
/* return class of property */
char *
get_property_class(dbref player, const char *type)
{
struct plist *p;
if(*type == PROP_WIZARD)
p = find_prop(DBFETCH(player)->attributes, type);
else
p = find_prop(DBFETCH(player)->properties, type);
if(p)
return((char *) get_uncompress(p -> class));
return((char *) 0);
}
char *
get_attr(dbref player, const char *type)
{
char *result;
char *attribute = (char *) calloc(strlen(type) + 2, sizeof(char));
*attribute = PROP_WIZARD;
strcat(attribute, type);
result = (char *) get_property_class(player, attribute);
free((void *) attribute);
return result;
}
/* copies properties */
struct plist *
copy_prop(dbref old)
{
struct plist *p;
struct plist *new = 0, *first = 0;
for (p = DBFETCH(old)->properties; p; p = p -> next)
{
if (!first) first = new = new_prop();
else new -> next = new_prop();
if (new -> next)
new = new -> next;
new -> type = alloc_string(p -> type);
new -> class = alloc_compressed(p -> class);
}
return first;
}
/* copies attributes */
struct plist *
copy_attr(dbref old)
{
struct plist *p;
struct plist *new = 0, *first = 0;
for (p = DBFETCH(old)->attributes; p; p = p -> next)
{
if (!first) first = new = new_prop();
else new -> next = new_prop();
if (new -> next)
new = new -> next;
new -> type = alloc_string(p -> type);
new -> class = alloc_compressed(p -> class);
}
return first;
}
/* return old gender values for pronoun substitution code */
int
genderof(dbref player)
{
char gender[5];
sprintf(gender, "%c%s", PROP_WIZARD, "sex");
if (has_property_strict(player, gender, "male"))
return GENDER_MALE;
else if (has_property_strict(player, gender, "female"))
return GENDER_FEMALE;
else if (has_property_strict(player, gender, "neuter"))
return GENDER_NEUTER;
else
return GENDER_UNASSIGNED;
}