diff options
| -rw-r--r-- | src/globals.h | 1 | ||||
| -rw-r--r-- | src/hash.c | 4 | ||||
| -rw-r--r-- | src/main.c | 2 | ||||
| -rw-r--r-- | src/multimap.c | 14 | ||||
| -rw-r--r-- | src/obj.c | 8 | ||||
| -rw-r--r-- | src/obj.h | 28 | ||||
| -rw-r--r-- | src/room.c | 25 | ||||
| -rw-r--r-- | src/room.h | 13 | ||||
| -rw-r--r-- | src/server.c | 19 | ||||
| -rw-r--r-- | src/server.h | 22 | ||||
| -rw-r--r-- | src/server_reqs.c | 79 | ||||
| -rw-r--r-- | src/server_reqs.h | 6 | ||||
| -rw-r--r-- | src/userdb.c | 37 | ||||
| -rw-r--r-- | src/userdb.h | 4 | ||||
| -rw-r--r-- | src/verb.h | 3 | ||||
| -rw-r--r-- | src/world.c | 7 | ||||
| -rw-r--r-- | worlds/test.c | 119 |
17 files changed, 299 insertions, 92 deletions
diff --git a/src/globals.h b/src/globals.h index d26dc15..987d382 100644 --- a/src/globals.h +++ b/src/globals.h @@ -88,6 +88,7 @@ #include "util.h" #define MSG_MAX PIPE_BUF + #ifndef NDEBUG #define debugf(fmt,...) debugf_real(__func__, __LINE__, __FILE__, fmt, ##__VA_ARGS__) #else @@ -308,12 +308,16 @@ bool hash_remove(void *ptr, const void *key) last->next = iter->next; else map->table[hash] = iter->next; + if(map->free_key) map->free_key((void*)iter->key); if(map->free_data) map->free_data((void*)iter->data); + --map->n_entries; + free(iter); + return true; } last = iter; @@ -5,4 +5,6 @@ int main(int argc, char *argv[]) { server_main(argc, argv); + + error("weird"); } diff --git a/src/multimap.c b/src/multimap.c index b958db0..033b511 100644 --- a/src/multimap.c +++ b/src/multimap.c @@ -193,11 +193,12 @@ size_t multimap_delete(void *ptr, const void *key, const void *val) struct multimap_node *node = hash_lookup(map->hash_tab, key); if(!node) - return false; + return 0; + /* iterate over the node's pairs and delete */ size_t deleted = 0; - struct multimap_list *last = NULL, *iter = node->list, *next;; + struct multimap_list *last = NULL, *iter = node->list, *next; while(iter) { next = iter->next; @@ -209,9 +210,10 @@ size_t multimap_delete(void *ptr, const void *key, const void *val) map->free_key((void*)iter->key); if(last) - last->next = iter->next; + last->next = next; else - node->list = iter->next; + node->list = next; + free(iter); ++deleted; @@ -251,7 +253,9 @@ size_t multimap_delete_all(void *ptr, const void *key) return ret; } - /* fall through */ + + /* fall through on failure */ + } return 0; } @@ -67,7 +67,7 @@ struct object_t *obj_new(const char *class_name) obj->id = idcounter++; obj->refcount = 1; - obj->list = true; + obj->hidden = false; obj->default_article = true; return obj; @@ -80,7 +80,7 @@ void obj_write(int fd, struct object_t *obj) write_uint64(fd, obj->id); write_string(fd, obj->name); - write_bool(fd, obj->list); + write_bool(fd, obj->hidden); write_bool(fd, obj->default_article); struct obj_alias_t *iter = obj->alias_list; @@ -104,7 +104,7 @@ struct object_t *obj_read(int fd) obj->id = read_uint64(fd); obj->name = read_string(fd); - obj->list = read_bool(fd); + obj->hidden = read_bool(fd); obj->default_article = read_bool(fd); /* aliases */ @@ -136,7 +136,7 @@ struct object_t *obj_copy(struct object_t *obj) { struct object_t *ret = obj_new(obj->class->class_name); ret->name = strdup(obj->name); - ret->list = obj->list; + ret->hidden = obj->hidden; if(obj->class->hook_dupdata) ret->userdata = obj->class->hook_dupdata(obj); return ret; @@ -27,9 +27,9 @@ * internally. */ -struct object_t; +typedef struct child_data user_t; -typedef struct child_data user_t; // see server.h for the definition +struct object_t; struct obj_class_t { const char *class_name; @@ -46,11 +46,6 @@ struct obj_class_t { * no function (NULL) = can take */ bool (*hook_take)(struct object_t*, user_t *user); - /* called when dropping an object; - * true: can drop - * false: can't drop - * NULL: can drop - */ bool (*hook_drop)(struct object_t*, user_t *user); void (*hook_destroy)(struct object_t*); // free resources const char* (*hook_desc)(struct object_t*, user_t*); // get object description @@ -65,8 +60,9 @@ struct obj_alias_t { struct obj_alias_t *next; }; -/* world modules should not instantiate this directly, use obj_new() instead */ -/* also, members marked with 'protected' should not be modified by the world module */ +/* world modules should not instantiate this directly, use obj_new() + * instead also, fields marked with 'protected' should not be modified + * by the world module */ struct object_t { obj_id id; // protected @@ -75,17 +71,17 @@ struct object_t { * room */ char *name; - struct obj_class_t *class; + struct obj_class_t *class; // protected size_t n_alias; - struct obj_alias_t *alias_list; + struct obj_alias_t *alias_list; // protected - bool list; /* whether to list in room view */ + bool hidden; /* whether to list in room description */ bool default_article; /* whether or not to use 'a' or 'an' when describing this */ void *userdata; - unsigned refcount; // private + unsigned refcount; // protected }; /* returns a new object of class 'c' */ @@ -100,10 +96,12 @@ struct object_t *obj_read(int fd); /* this adds a reference to an object, DOES NOT COPY */ struct object_t *obj_dup(struct object_t *obj); -/* makes a new object with a new ID, but same data fields as the original */ +/* makes a new object with a new ID, but with the same data fields as + * the original */ struct object_t *obj_copy(struct object_t *obj); -/* this only frees the object if its reference count is zero */ +/* decrements an object's reference count; frees the object if there + * are no more references to it */ void obj_free(void*); /* shut down the obj_* module */ @@ -80,9 +80,15 @@ void room_free(struct room_t *room) bool room_obj_add(room_id room, struct object_t *obj) { + debugf("ADDING OBJECT %s to ROOM %d\n", obj->name, room); + bool status = true; if(!multimap_insert(room_get(room)->objects, obj->name, obj)) + { + debugf("FAILED TO ADD OBJECT.\n"); status = false; + } + struct obj_alias_t *iter = obj->alias_list; while(iter) { @@ -94,6 +100,9 @@ bool room_obj_add(room_id room, struct object_t *obj) } iter = iter->next; } + + debugf("ROOM %d now has %d objects\n", room, multimap_size(room_get(room)->objects)); + return status; } @@ -116,16 +125,22 @@ bool room_obj_add_alias(room_id room, struct object_t *obj, char *alias) iter = iter->next; } + debugf("adding alias '%s' for object '%s'\n", alias, obj->name); + + debugf("ROOM %d now has %d total object names\n", room, multimap_size(room_get(room)->objects)); + struct obj_alias_t *new = calloc(1, sizeof(struct obj_alias_t)); - new->alias = alias; + new->alias = strdup(alias); new->next = obj->alias_list; obj->alias_list = new; ++obj->n_alias; - return multimap_insert(room_get(room)->objects, alias, obj_dup(obj)); + bool status = multimap_insert(room_get(room)->objects, alias, obj_dup(obj)); + + return status; } const struct multimap_list *room_obj_iterate(room_id room, void **save, size_t *n_pairs) @@ -160,6 +175,7 @@ size_t room_obj_count_noalias(room_id id) bool room_obj_del_by_ptr(room_id room, struct object_t *obj) { + debugf("room_obj_del_by_ptr: deleting object %s\n", obj->name); struct obj_alias_t *iter = obj->alias_list; struct object_t tmp; @@ -167,14 +183,17 @@ bool room_obj_del_by_ptr(room_id room, struct object_t *obj) while(iter) { + debugf(" deleting alias %s\n", iter->alias); multimap_delete(room_get(room)->objects, iter->alias, &tmp); iter = iter->next; } + debugf("After deleting aliases of object: %s:\n", obj->name); + return multimap_delete(room_get(room)->objects, obj->name, &tmp); } -/* delete all the objects with a matching name, and all their aliases, +/* delete all the objects with a matching name, and all their aliases * from a room */ bool room_obj_del(room_id room, const char *name) @@ -28,9 +28,9 @@ are added by hooks in rooms, which are provided by the world module. */ -typedef enum room_id { ROOM_NONE = -1 } room_id; +typedef struct child_data user_t; // definition of child_data in server.h -typedef struct child_data user_t; +typedef enum room_id { ROOM_NONE = -1 } room_id; enum direction_t { DIR_N = 0, DIR_NE, DIR_E, DIR_SE, DIR_S, DIR_SW, DIR_W, DIR_NW, DIR_UP, DIR_DN, DIR_IN, DIR_OT, NUM_DIRECTIONS }; @@ -46,8 +46,12 @@ struct roomdata_t { const char * const adjacent[NUM_DIRECTIONS]; void (* const hook_init)(room_id id); - void (* const hook_enter)(room_id room, user_t *user); - void (* const hook_leave)(room_id room, user_t *user); + + /* return values indicate permission to enter/leave, + * setting to NULL defaults to true. + */ + bool (* const hook_enter)(room_id room, user_t *user); + bool (* const hook_leave)(room_id room, user_t *user); void (* const hook_serialize)(room_id room, int fd); void (* const hook_deserialize)(room_id room, int fd); void (* const hook_destroy)(room_id room); @@ -88,6 +92,7 @@ bool room_obj_add_alias(room_id room, struct object_t *obj, char *alias); bool room_obj_del(room_id room, const char *name); bool room_obj_del_alias(room_id room, struct object_t *obj, const char *alias); +bool room_obj_del_by_ptr(room_id room, struct object_t *obj); const struct multimap_list *room_obj_get(room_id room, const char *obj); const struct multimap_list *room_obj_get_size(room_id room, const char *name, size_t *n_objs); diff --git a/src/server.c b/src/server.c index 9e2e465..e42483c 100644 --- a/src/server.c +++ b/src/server.c @@ -45,12 +45,15 @@ static int server_socket; /* saves state periodically */ void server_save_state(bool force) { - static int n = 0; - n = (n + 1) % SAVE_INTERVAL; - if(!n || force) + if(!are_child) { - world_save(WORLDFILE); - userdb_write(USERFILE); + static int n = 0; + n = (n + 1) % SAVE_INTERVAL; + if(!n || force) + { + world_save(WORLDFILE); + userdb_write(USERFILE); + } } } @@ -119,6 +122,10 @@ static void __attribute__((noreturn)) server_cleanup(void) close(server_socket); + /* save state */ + if(!are_child) + server_save_state(true); + /* shut down modules */ client_shutdown(); obj_shutdown(); @@ -152,7 +159,7 @@ static void __attribute__((noreturn)) sigint_handler(int s) } static bool autoconfig = false; -const char *autouser, *autopass; +static const char *autouser, *autopass; static void check_userfile(void) { diff --git a/src/server.h b/src/server.h index af7e9fc..95e537a 100644 --- a/src/server.h +++ b/src/server.h @@ -26,21 +26,29 @@ #include "server_reqs.h" #include "room.h" +/* everything the server needs to manage its children */ struct child_data { - pid_t pid; - int readpipe[2]; - int outpipe[2]; + pid_t pid; - int state; - room_id room; - char *user; + /* pipes, packet mode */ + int readpipe[2]; + int outpipe[2]; - ev_io *io_watcher; + /* user state */ + int state; + room_id room; + char *user; + + /* libev watchers */ + ev_io *io_watcher; ev_child *sigchld_watcher; + /* remote IP */ struct in_addr addr; }; +typedef struct child_data user_t; + extern volatile int num_clients; extern void *child_map; extern bool are_child; diff --git a/src/server_reqs.c b/src/server_reqs.c index 167331d..fffdee1 100644 --- a/src/server_reqs.c +++ b/src/server_reqs.c @@ -157,42 +157,53 @@ static void req_send_desc(unsigned char *data, size_t datalen, struct child_data room_id id = sender->room; while(1) { - debugf("Iterating over object name...\n"); size_t n_objs; - const struct multimap_list *iter= room_obj_iterate(id, &save, &n_objs); + const struct multimap_list *iter = room_obj_iterate(id, &save, &n_objs); id = ROOM_NONE; if(!iter) break; const char *name = iter->key; struct object_t *obj = iter->val; - if(!strcmp(name, obj->name)) + + debugf("*** ITERATING OVER OBJECT IN ROOM ***\n"); + debugf("hidden: %d\n", obj->hidden); + debugf("compare: %s %s\n", obj->name, name); + + buf[0] = '\0'; + + if(!obj->hidden) { - if(n_objs == 1) + if(!strcmp(name, obj->name)) { - char *article = (is_vowel(name[0])?"an":"a"); - strlcat(buf, "There is ", sizeof(buf)); - if(obj->default_article) + if(n_objs == 1) { - strlcat(buf, article, sizeof(buf)); - strlcat(buf, " ", sizeof(buf)); + char *article = (is_vowel(name[0])?"an":"a"); + strlcat(buf, "There is ", sizeof(buf)); + if(obj->default_article) + { + strlcat(buf, article, sizeof(buf)); + strlcat(buf, " ", sizeof(buf)); + } + strlcat(buf, name, sizeof(buf)); + strlcat(buf, " here.\n", sizeof(buf)); + } + else + { + strlcat(buf, "There are ", sizeof(buf)); + char n[32]; + snprintf(n, sizeof(n), "%lu ", n_objs); + strlcat(buf, n, sizeof(buf)); + strlcat(buf, name, sizeof(buf)); + strlcat(buf, "s here.\n", sizeof(buf)); } - strlcat(buf, name, sizeof(buf)); - strlcat(buf, " here.\n", sizeof(buf)); - } - else - { - strlcat(buf, "There are ", sizeof(buf)); - char n[32]; - snprintf(n, sizeof(n), "%lu ", n_objs); - strlcat(buf, n, sizeof(buf)); - strlcat(buf, name, sizeof(buf)); - strlcat(buf, "s here.\n", sizeof(buf)); } + + send_msg(sender, "%s", buf); } + else + debugf("OBJECT IS HIDDEN\n"); } - - send_packet(sender, REQ_BCASTMSG, buf, strlen(buf)); } static void req_send_roomname(unsigned char *data, size_t datalen, struct child_data *sender) @@ -333,7 +344,7 @@ static void req_look_at(unsigned char *data, size_t datalen, struct child_data * if(inv_list) { send_msg(sender, "In inventory:\n"); - idx = print_objlist(sender, inv_list, idx, n_objs); + print_objlist(sender, inv_list, idx, n_objs); } if(!room_list && !inv_list) @@ -355,10 +366,12 @@ static void req_take(unsigned char *data, size_t datalen, struct child_data *sen if(obj->class->hook_take && !obj->class->hook_take(obj, sender)) { send_msg(sender, "You can't take that.\n"); - return; + iter = next; + continue; } userdb_add_obj(sender->user, obj); + room_obj_del_by_ptr(sender->room, obj); send_msg(sender, "Taken.\n"); } @@ -367,8 +380,6 @@ static void req_take(unsigned char *data, size_t datalen, struct child_data *sen iter = next; } - room_obj_del(sender->room, (const char*)data); - server_save_state(false); } else @@ -452,17 +463,21 @@ static void req_drop(unsigned char *data, size_t datalen, struct child_data *sen while(iter) { + const struct multimap_list *next = iter->next; struct object_t *obj = iter->val; - struct object_t *dup = obj_dup(obj); - room_obj_add(sender->room, dup); + if(!obj->class->hook_drop || (obj->class->hook_drop && obj->class->hook_drop(obj, sender))) + { + send_msg(sender, "Dropped.\n"); + room_obj_add(sender->room, obj_dup(obj)); + userdb_del_obj_by_ptr(sender->user, obj); + } + else + send_msg(sender, "You cannot drop that.\n"); - send_msg(sender, "Dropped.\n"); - iter = iter->next; + iter = next; } - multimap_delete_all(user->objects, (const char*)data); - server_save_state(false); } diff --git a/src/server_reqs.h b/src/server_reqs.h index 5137f9d..c77c53a 100644 --- a/src/server_reqs.h +++ b/src/server_reqs.h @@ -16,6 +16,12 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ +#pragma once + +#include "globals.h" + +typedef struct child_data user_t; + /* child<->master commands */ /* children might not implement all of these */ /* meanings might be different for the server and child, see comments */ diff --git a/src/userdb.c b/src/userdb.c index dde2693..101b6d0 100644 --- a/src/userdb.c +++ b/src/userdb.c @@ -183,7 +183,6 @@ bool userdb_remove(const char *key) bool userdb_add(struct userdata_t *data) { - userdb_dump(); struct userdata_t *new = calloc(1, sizeof(*new)); /* only in C! */ memcpy(new, data, sizeof(*new)); @@ -239,9 +238,6 @@ void userdb_dump(void) void userdb_shutdown(void) { - if(map && db_file && !are_child) - userdb_write(db_file); - if(map) { hash_free(map); @@ -283,6 +279,39 @@ bool userdb_add_obj(const char *name, struct object_t *obj) return multimap_insert(user->objects, obj->name, obj_dup(obj)); } +bool userdb_del_obj_by_ptr(const char *username, struct object_t *obj) +{ + struct userdata_t *user = userdb_lookup(username); + + struct obj_alias_t *iter = obj->alias_list; + + struct object_t tmp; + tmp.id = obj->id; + + while(iter) + { + multimap_delete(user->objects, iter->alias, &tmp); + iter = iter->next; + } + + return multimap_delete(user->objects, obj->name, &tmp); +} + +bool userdb_del_obj(const char *username, const char *obj_name) +{ + struct userdata_t *user = userdb_lookup(username); + const struct multimap_list *iter = multimap_lookup(user->objects, obj_name, NULL); + while(iter) + { + const struct multimap_list *next = iter->next; + struct object_t *obj = iter->val; + userdb_del_obj_by_ptr(username, obj); + iter = next; + } + + return true; +} + /*** child request wrappers ***/ /* NOTE: these also work from the master, but it's better to use the * userdb_* funcs instead */ diff --git a/src/userdb.h b/src/userdb.h index 52ade12..25bdc7b 100644 --- a/src/userdb.h +++ b/src/userdb.h @@ -66,7 +66,9 @@ bool userdb_write(const char*); /* *save should be set to NULL on the first run */ struct userdata_t *userdb_iterate(void **save); -bool userdb_add_obj(const char *name, struct object_t *obj); +bool userdb_add_obj(const char *username, struct object_t *obj); +bool userdb_del_obj(const char *username, const char *obj_name); +bool userdb_del_obj_by_ptr(const char *username, struct object_t *obj); /*** child-only functions ***/ struct userdata_t *userdb_request_lookup(const char *name); @@ -30,6 +30,9 @@ * callbacks. */ +struct child_data; +typedef struct child_data user_t; + struct verb_t; struct verb_class_t { const char *class_name; diff --git a/src/world.c b/src/world.c index 1516b4c..a854e49 100644 --- a/src/world.c +++ b/src/world.c @@ -80,6 +80,8 @@ void world_save(const char *fname) size_t n_objects = room_obj_count_noalias(i); write(fd, &n_objects, sizeof(n_objects)); + debugf("Room %d has %d objects.\n", i, n_objects); + room_id id = i; void *save; while(1) @@ -95,7 +97,10 @@ void world_save(const char *fname) break; const char *name = iter->key; if(!strcmp(name, obj->name)) - obj_write(fd, obj); + { + debugf("writing object '%s' in room %d\n", obj->name, i); + obj_write(fd, obj); + } iter = iter->next; } } diff --git a/worlds/test.c b/worlds/test.c index cdcaba9..37a058e 100644 --- a/worlds/test.c +++ b/worlds/test.c @@ -7,10 +7,12 @@ static void deadend_init(room_id id) struct object_t *new = obj_new("/generic"); new->name = strdup("shovel"); new->userdata = strdup("It is a normal shovel with a price tag attached that says $19.99."); - new->list = true; room_obj_add(id, new); + +#if 0 new = obj_copy(new); room_obj_add(id, new); +#endif } static void ew_road_init(room_id id) @@ -18,8 +20,9 @@ static void ew_road_init(room_id id) struct object_t *new = obj_new("/generic/notake"); new->name = strdup("large boulder"); new->userdata = strdup("It is just a boulder. It cannot be moved."); - new->list = true; room_obj_add(id, new); + room_obj_add_alias(id, new, "boulder"); + room_obj_add_alias(id, new, "rock"); } static void fork_init(room_id id) @@ -54,12 +57,31 @@ static void fork_destroy(room_id id) static void senw_init(room_id id) { - struct object_t *new = obj_new("/generic"); + struct object_t *new = obj_new("/generic/dunnet/food"); new->name = strdup("some food"); new->userdata = strdup("It looks like some kind of meat. Smells pretty bad."); new->default_article = false; room_obj_add(id, new); - room_obj_add_alias(id, new, strdup("food")); + room_obj_add_alias(id, new, "food"); + room_obj_add_alias(id, new, "meat"); +} + +static void hangout_init(room_id id) +{ + struct object_t *new = obj_new("/generic/notake"); + new->name = strdup("ferocious bear"); + new->userdata = strdup("It looks like a grizzly to me."); + room_obj_add(id, new); + room_obj_add_alias(id, new, "bear"); +} + +static void hidden_init(room_id id) +{ + struct object_t *new = obj_new("/generic"); + new->name = strdup("emerald bracelet"); + new->userdata = strdup("I see nothing special about that."); + room_obj_add(id, new); + room_obj_add_alias(id, new, "bracelet"); } const struct roomdata_t netcosm_world[] = { @@ -106,7 +128,7 @@ const struct roomdata_t netcosm_world[] = { "senw_road", "SE/NW road", "You are on a southeast/northwest road.", - { NONE_N, NONE_NE, NONE_E, NONE_SE, NONE_S, NONE_SW, NONE_W, "fork", NONE_UP, NONE_DN, NONE_IN, NONE_OT }, + { NONE_N, NONE_NE, NONE_E, "bear_hangout", NONE_S, NONE_SW, NONE_W, "fork", NONE_UP, NONE_DN, NONE_IN, NONE_OT }, senw_init, NULL, NULL, @@ -116,10 +138,49 @@ const struct roomdata_t netcosm_world[] = { }, { + "bear_hangout", + "Bear Hangout", + "You are standing at the end of a road. A passage leads back to the northwest.", + { NONE_N, NONE_NE, NONE_E, NONE_SE, NONE_S, "hidden_area", NONE_W, "senw_road", NONE_UP, NONE_DN, NONE_IN, NONE_OT }, + hangout_init, + NULL, + NULL, + NULL, + NULL, + NULL, + }, + + { + "hidden_area", + "Hidden Area", + "You are in a well-hidden area off to the side of a road. Back to the northeast through the brush you can see the bear hangout.", + { NONE_N, "bear_hangout", NONE_E, NONE_SE, NONE_S, NONE_SW, NONE_W, NONE_NW, NONE_UP, NONE_DN, NONE_IN, NONE_OT }, + hidden_init, + NULL, + NULL, + NULL, + NULL, + NULL, + }, + + { "nesw_road", "NE/SW road", "You are on a northeast/southwest road.", - { NONE_N, NONE_NE, NONE_E, NONE_SE, NONE_S, "fork", NONE_W, NONE_NW, NONE_UP, NONE_DN, NONE_IN, NONE_OT }, + { NONE_N, "building_front", NONE_E, NONE_SE, NONE_S, "fork", NONE_W, NONE_NW, NONE_UP, NONE_DN, NONE_IN, NONE_OT }, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + }, + + { + "building_front", + "Building Front", + "You are at the end of the road. There is a building in front of you to the northeast, and the road leads back to the southwest.", + { NONE_N, NONE_NE, NONE_E, NONE_SE, NONE_S, "nesw_road", NONE_W, NONE_NW, NONE_UP, NONE_DN, NONE_IN, NONE_OT }, NULL, NULL, NULL, @@ -166,8 +227,32 @@ static bool no_take(struct object_t *obj, user_t *user) return false; } +static bool food_drop(struct object_t *obj, user_t *user) +{ + if(room_obj_get(user->room, "bear")) + { + send_msg(user, "The bear takes the food and runs away with it. He left something behind.\n"); + + struct object_t *new = obj_new("/generic"); + + debugf("ADDING OBJECT.\n"); + + new->name = strdup("shiny brass key"); + new->userdata = strdup("I see nothing special about that."); + + room_obj_add(user->room, new); + room_obj_add_alias(user->room, new, "key"); + room_obj_add_alias(user->room, new, "shiny key"); + room_obj_add_alias(user->room, new, "brass key"); + + room_obj_del(user->room, "ferocious bear"); + } + + return true; +} + const struct obj_class_t netcosm_obj_classes[] = { - /* a generic, takable object class with userdata as its description */ + /* a generic, takeable object class with userdata pointing to its description */ { "/generic", generic_ser, @@ -179,7 +264,7 @@ const struct obj_class_t netcosm_obj_classes[] = { generic_dup, }, - /* a generic, non-takable object class */ + /* a generic, non-takeable object class, inherits /generic */ { "/generic/notake", generic_ser, @@ -189,7 +274,19 @@ const struct obj_class_t netcosm_obj_classes[] = { generic_destroy, generic_desc, generic_dup, - } + }, + + /* a specialized "food" object for dunnet, inherits /generic */ + { + "/generic/dunnet/food", + generic_ser, + generic_deser, + NULL, + food_drop, + generic_destroy, + generic_desc, + generic_dup, + }, }; const size_t netcosm_obj_classes_sz = ARRAYLEN(netcosm_obj_classes); @@ -215,8 +312,10 @@ static void dig_exec(struct verb_t *verb, char *args, user_t *user) struct object_t *new = obj_new("/generic"); new->name = strdup("CPU card"); new->userdata = strdup("The CPU board has a VAX chip on it. It seems to have 2 Megabytes of RAM onboard."); - new->list = true; room_obj_add(user->room, new); + room_obj_add_alias(user->room, new, "cpu"); + room_obj_add_alias(user->room, new, "chip"); + room_obj_add_alias(user->room, new, "card"); send_msg(user, "I think you found something.\n"); } else |