aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFranklin Wei <git@fwei.tk>2016-03-31 17:05:37 -0400
committerFranklin Wei <git@fwei.tk>2016-03-31 17:05:37 -0400
commit207850187986568b17ea9b2d9c29510cb00bf9da (patch)
treeaee87cf74280e8f9dd29aca88d12a638f37b2493
parentb3699dd5df18db3c060bb88a74c1b05e37154c76 (diff)
downloadnetcosm-207850187986568b17ea9b2d9c29510cb00bf9da.zip
netcosm-207850187986568b17ea9b2d9c29510cb00bf9da.tar.gz
netcosm-207850187986568b17ea9b2d9c29510cb00bf9da.tar.bz2
netcosm-207850187986568b17ea9b2d9c29510cb00bf9da.tar.xz
lots of things
-rw-r--r--README.md12
-rw-r--r--src/auth.c5
-rw-r--r--src/auth.h6
-rw-r--r--src/client.c64
-rw-r--r--src/client_reqs.c6
-rw-r--r--src/globals.h7
-rw-r--r--src/obj.c6
-rw-r--r--src/obj.h2
-rw-r--r--src/server.c50
-rw-r--r--src/server_reqs.c62
-rw-r--r--src/server_reqs.h5
-rw-r--r--src/userdb.c2
-rw-r--r--src/util.c87
-rw-r--r--src/util.h3
-rw-r--r--src/world.c30
-rwxr-xr-x[-rw-r--r--]tests/all.sh0
-rwxr-xr-x[-rw-r--r--]tests/gen_data.sh0
-rw-r--r--worlds/test.c162
18 files changed, 353 insertions, 156 deletions
diff --git a/README.md b/README.md
index f7144b8..f459f72 100644
--- a/README.md
+++ b/README.md
@@ -100,7 +100,7 @@ number.
#### 0.4.0 (skipped)
-* Object support [DONE, needs testing]
+* Object support [DONE]
* User inventory support [DONE]
@@ -110,7 +110,15 @@ number.
* Verb support [DONE]
-* World hooks/scripting [PARTIAL]
+* World hooks/scripting [DONE]
+
+##### 0.5.1
+
+* Work on dunnet clone
+
+* API enhancements
+
+* Many bugfixes
#### 0.6.0
diff --git a/src/auth.c b/src/auth.c
index 069e9fe..c7b53d3 100644
--- a/src/auth.c
+++ b/src/auth.c
@@ -193,11 +193,12 @@ struct userdata_t *auth_check(const char *name2, const char *pass2)
{
debugf("auth module: user %s found\n", name2);
- /* hashes are in HEX to avoid the Trucha bug */
+ /* hashes are in lowercase hex to avoid the Trucha bug
+ * but still allow comparison with strcmp() */
char *new_hash_hex = hash_pass_hex(pass, salt);
bool success = true;
- /* constant-time comparison to a timing attack */
+ /* constant-time comparison to hopefully prevent a timing attack */
for(int i = 0; i < AUTH_HASHLEN; ++i)
{
if(new_hash_hex[i] != hash[i])
diff --git a/src/auth.h b/src/auth.h
index ba24595..c5c9dc1 100644
--- a/src/auth.h
+++ b/src/auth.h
@@ -26,12 +26,6 @@
//#define HASH_ITERS 500000
#define HASH_ITERS 1
-struct authinfo_t {
- bool success;
- const char *user;
- int authlevel;
-};
-
/* makes admin account */
void first_run_setup(void);
diff --git a/src/client.c b/src/client.c
index 3117b63..d66836e 100644
--- a/src/client.c
+++ b/src/client.c
@@ -46,9 +46,9 @@ void out_raw(const void *buf, size_t len)
error("out() called from master");
if(!len)
return;
-
+
try_again:
-
+
while(output_locked);
/* something weird happened and the value changed between the loop and here */
@@ -103,8 +103,8 @@ void __attribute__((format(printf,1,2))) out(const char *fmt, ...)
if(is_newline)
++ptr; /* skip the newline */
- /* skip following spaces */
- while(*ptr == ' ')
+ /* skip following spaces */
+ while(*ptr == ' ')
++ptr;
last_space = 0;
pos = 0;
@@ -208,7 +208,10 @@ int user_cb(char **save)
{
char *what = strtok_r(NULL, WSPACE, save);
if(!what)
+ {
+ out("Usage: USER <ADD|DEL|MODIFY|LIST> <ARGS>\n");
return CMD_OK;
+ }
all_upper(what);
@@ -308,7 +311,7 @@ int client_cb(char **save)
char *pid_s = strtok_r(NULL, WSPACE, save);
if(pid_s)
{
- all_upper(pid_s);
+ all_upper(pid_s);
if(!strcmp(pid_s, "ALL"))
{
const char *msg = "Kicking everyone...\n";
@@ -338,7 +341,7 @@ int client_cb(char **save)
debugf("Success.\n");
}
else
- out("Usage: CLIENT KICK <PID>\n");
+ out("Usage: CLIENT KICK <PID|ALL>\n");
}
return CMD_OK;
}
@@ -427,9 +430,53 @@ int drop_cb(char **save)
{
char *what = strtok_r(NULL, "", save);
if(what)
- client_drop(what);
+ client_drop(what);
else
- out("You must supply an object.\n");
+ out("You must supply an object.\n");
+ return CMD_OK;
+}
+
+int chpass_cb(char **save)
+{
+ out("Enter current password: ");
+ char *current = client_read_password();
+
+ struct userdata_t *current_data = auth_check(current_user, current);
+
+ memset(current, 0, strlen(current));
+ free(current);
+
+ if(!current_data)
+ {
+ out("Password mismatch.\n");
+ return CMD_OK;
+ }
+
+ out("Enter new password: ");
+ char *pass1 = client_read_password();
+
+ out("Retype new password: ");
+
+ char *pass2 = client_read_password();
+
+ if(strcmp(pass1, pass2))
+ {
+ memset(pass1, 0, strlen(pass1));
+ memset(pass2, 0, strlen(pass2));
+ free(pass1);
+ free(pass2);
+
+ out("Passwords do not match.\n");
+ return CMD_OK;
+ }
+
+ memset(pass2, 0, strlen(pass2));
+ free(pass2);
+
+ auth_user_add(current_user, pass1, current_data->priv);
+
+ memset(pass1, 0, strlen(pass1));
+
return CMD_OK;
}
@@ -451,6 +498,7 @@ static const struct client_cmd {
{ "WAIT", wait_cb, true },
{ "GO", go_cb, false },
{ "DROP", drop_cb, false },
+ { "CHPASS", chpass_cb, false },
};
static void *cmd_map = NULL;
diff --git a/src/client_reqs.c b/src/client_reqs.c
index 36f341c..21174c4 100644
--- a/src/client_reqs.c
+++ b/src/client_reqs.c
@@ -267,11 +267,11 @@ void client_take(char *obj)
{
if(obj)
{
- all_lower(obj);
- send_master(REQ_TAKE, obj, strlen(obj) + 1);
+ all_lower(obj);
+ send_master(REQ_TAKE, obj, strlen(obj) + 1);
}
else
- out("You must supply an object.\n");
+ out("You must supply an object.\n");
}
void client_inventory(void)
diff --git a/src/globals.h b/src/globals.h
index 0177b8a..5a164ba 100644
--- a/src/globals.h
+++ b/src/globals.h
@@ -21,17 +21,18 @@
#define _GNU_SOURCE
-#include <libev/ev.h>
+#include <ev.h>
+
#include <openssl/sha.h>
#include <openssl/opensslv.h>
#include <arpa/inet.h>
#include <arpa/telnet.h>
#include <assert.h>
-//#include <bsd/string.h> // for strlcat
#include <ctype.h>
#include <errno.h>
#include <fcntl.h>
+#include <inttypes.h>
#include <limits.h>
#include <netdb.h>
#include <netinet/in.h>
@@ -66,7 +67,7 @@
#define WORLD_MAGIC 0x31415926
#define USERDB_MAGIC 0x27182818
#define MAX_FAILURES 3
-#define NETCOSM_VERSION "0.5.0"
+#define NETCOSM_VERSION "0.5.1"
/* username length */
#define MAX_NAME_LEN 32
diff --git a/src/obj.c b/src/obj.c
index deeb30d..296fbb5 100644
--- a/src/obj.c
+++ b/src/obj.c
@@ -144,7 +144,7 @@ struct object_t *obj_copy(struct object_t *obj)
struct object_t *obj_dup(struct object_t *obj)
{
- debugf("Adding an object reference to #%lu.\n", obj->id);
+ debugf("Adding an object reference to #%" PRI_OBJID ".\n", obj->id);
++obj->refcount;
return obj;
}
@@ -154,11 +154,11 @@ void obj_free(void *ptr)
struct object_t *obj = ptr;
--obj->refcount;
- debugf("Freeing an object reference for #%lu (%s, %d).\n", obj->id, obj->name, obj->refcount);
+ debugf("Freeing an object reference for #%" PRI_OBJID" (%s, %d).\n", obj->id, obj->name, obj->refcount);
if(!obj->refcount)
{
- debugf("Freeing object #%lu\n", obj->id);
+ debugf("Freeing object #%"PRI_OBJID"\n", obj->id);
if(obj->class->hook_destroy)
obj->class->hook_destroy(obj);
diff --git a/src/obj.h b/src/obj.h
index 37dbfd9..3858d78 100644
--- a/src/obj.h
+++ b/src/obj.h
@@ -54,6 +54,8 @@ struct obj_class_t {
typedef uint64_t obj_id;
+#define PRI_OBJID PRId64
+
struct obj_alias_t {
char *alias;
struct obj_alias_t *next;
diff --git a/src/server.c b/src/server.c
index 6e8dba2..6d90c61 100644
--- a/src/server.c
+++ b/src/server.c
@@ -255,10 +255,34 @@ static void new_connection_cb(EV_P_ ev_io *w, int revents)
int readpipe[2]; /* child->parent */
int outpipe [2]; /* parent->child */
- if(socketpair(AF_UNIX, SOCK_SEQPACKET, 0, readpipe) < 0)
- error("error creating pipe, need linux kernel >= 3.4");
- if(socketpair(AF_UNIX, SOCK_SEQPACKET, 0, outpipe) < 0)
- error("error creating pipe, need linux kernel >= 3.4");
+ /* try several methods to create a packet pipe between the child and master: */
+
+ /* first try creating a pipe in "packet mode": see pipe(2) */
+ if(pipe2(readpipe, O_DIRECT) < 0)
+ {
+ /* then try a SOCK_SEQPACKET socket pair: see unix(7) */
+ if(socketpair(AF_UNIX, SOCK_SEQPACKET, 0, readpipe) < 0)
+ {
+ /* if that failed, try a SOCK_DGRAM socket as a last resort */
+ if(socketpair(AF_UNIX, SOCK_DGRAM, 0, readpipe) < 0)
+ error("couldn't create child-master communication pipe");
+ else
+ debugf("WARNING: Using a SOCK_DGRAM socket pair for IPC, performance may be degraded.\n");
+ }
+ else
+ debugf("Using a SOCK_SEQPACKET socket pair for IPC.\n");
+ }
+ else
+ debugf("Using a packet-mode pipe for IPC.\n");
+
+ if(pipe2(outpipe, O_DIRECT) < 0)
+ {
+ if(socketpair(AF_UNIX, SOCK_SEQPACKET, 0, outpipe) < 0)
+ {
+ if(socketpair(AF_UNIX, SOCK_DGRAM, 0, outpipe) < 0)
+ error("error creating pipe, need linux kernel >= 3.4");
+ }
+ }
pid_t pid = fork();
if(pid < 0)
@@ -329,6 +353,7 @@ static void init_signals(void)
{
struct sigaction sa;
+ /* SIGINT and SIGTERM cause graceful shutdown */
sigemptyset(&sa.sa_mask);
sigaddset(&sa.sa_mask, SIGINT);
sa.sa_handler = sigint_handler;
@@ -338,6 +363,7 @@ static void init_signals(void)
if(sigaction(SIGTERM, &sa, NULL) < 0)
error("sigaction");
+ /* ignore SIGPIPE */
sigemptyset(&sa.sa_mask);
sa.sa_handler = SIG_IGN;
sa.sa_flags = 0;
@@ -345,7 +371,7 @@ static void init_signals(void)
error("sigaction");
/* libev's default SIGCHLD handler exhibits some really strange
- * behavior, which we don't like, so we use our own ;) */
+ * behavior, which we don't like, so we use our own */
sigemptyset(&sa.sa_mask);
sigaddset(&sa.sa_mask, SIGCHLD);
sa.sa_handler = sigchld_handler;
@@ -367,7 +393,7 @@ static void parse_args(int argc, char *argv[])
switch(c)
{
case 'h': /* help */
- debugf("FIXME: usage message");
+ debugf("Usage: %s [-d PREFIX] [-a <username> <password>]\n", argv[0]);
exit(0);
case 'a': /* automatic first-run config */
autoconfig = true;
@@ -393,7 +419,7 @@ static SIMP_EQUAL(pid_t, pid_equal);
static void check_libs(void)
{
- debugf("*** Starting NetCosm %s (libev %d.%d, %s) ***\n",
+ debugf("*** NetCosm %s (libev %d.%d, %s) ***\n",
NETCOSM_VERSION, EV_VERSION_MAJOR, EV_VERSION_MINOR, OPENSSL_VERSION_TEXT);
assert(ev_version_major() == EV_VERSION_MAJOR &&
ev_version_minor() >= EV_VERSION_MINOR);
@@ -405,11 +431,9 @@ int server_main(int argc, char *argv[])
parse_args(argc, argv);
- server_socket = server_bind();
-
userdb_init(USERFILE);
-
- /* also perform first-time setup */
+
+ /* also performs first-time setup: */
check_userfile();
load_worldfile();
@@ -427,10 +451,12 @@ int server_main(int argc, char *argv[])
debugf("Listening on port %d\n", port);
+ server_socket = server_bind();
+
struct ev_loop *loop = ev_default_loop(0);
/* we initialize signals after creating the default event loop
- * because libev grabs SIGCHLD */
+ * because libev grabs SIGCHLD in the process */
init_signals();
ev_io server_watcher;
diff --git a/src/server_reqs.c b/src/server_reqs.c
index 676403d..21787f4 100644
--- a/src/server_reqs.c
+++ b/src/server_reqs.c
@@ -150,7 +150,7 @@ static void req_send_desc(unsigned char *data, size_t datalen, struct child_data
send_packet(sender, REQ_BCASTMSG, (void*)room->data.desc, strlen(room->data.desc));
send_packet(sender, REQ_PRINTNEWLINE, NULL, 0);
-
+
/* list objects */
char buf[MSG_MAX];
buf[0] = 0;
@@ -189,7 +189,7 @@ static void req_send_desc(unsigned char *data, size_t datalen, struct child_data
{
strlcat(buf, "There are ", sizeof(buf));
char n[32];
- snprintf(n, sizeof(n), "%lu ", n_objs);
+ snprintf(n, sizeof(n), "%zu ", n_objs);
strlcat(buf, n, sizeof(buf));
strlcat(buf, name, sizeof(buf));
strlcat(buf, "s here.\n", sizeof(buf));
@@ -238,25 +238,25 @@ static void req_move_room(unsigned char *data, size_t datalen, struct child_data
/* TODO: bounds checking on `dir' */
room_id new = current->adjacent[dir];
-
+
if(new == ROOM_NONE)
{
- send_msg(sender, "You cannot go that way.\n");
+ send_msg(sender, "You cannot go that way.\n");
}
else
{
- struct room_t *new_room = room_get(new);
-
- if((!new_room->data.hook_enter ||
- (new_room->data.hook_enter && new_room->data.hook_enter(new, sender))) &&
- (!current->data.hook_leave ||
- (current->data.hook_leave && current->data.hook_leave(sender->room, sender))))
- {
- room_user_del(sender->room, sender);
-
- child_set_room(sender, new);
- status = 1;
- }
+ struct room_t *new_room = room_get(new);
+
+ if((!new_room->data.hook_enter ||
+ (new_room->data.hook_enter && new_room->data.hook_enter(new, sender))) &&
+ (!current->data.hook_leave ||
+ (current->data.hook_leave && current->data.hook_leave(sender->room, sender))))
+ {
+ room_user_del(sender->room, sender);
+
+ child_set_room(sender, new);
+ status = 1;
+ }
}
send_packet(sender, REQ_MOVE, &status, sizeof(status));
@@ -419,34 +419,8 @@ static void req_inventory(unsigned char *data, size_t datalen, struct child_data
struct object_t *obj = iter->val;
if(!strcmp(name, obj->name))
{
- if(n_objs == 1)
- {
- if(obj->default_article)
- {
- char *article = (is_vowel(name[0])?"An":"A");
- strlcat(buf, article, sizeof(buf));
- strlcat(buf, " ", sizeof(buf));
- strlcat(buf, name, sizeof(buf));
- }
- else
- {
- char tmp[2];
- tmp[0] = toupper(name[0]);
- tmp[1] = '\0';
- strlcat(buf, tmp, sizeof(buf));
- strlcat(buf, name + 1, sizeof(buf));
- }
- strlcat(buf, "\n", sizeof(buf));
- }
- else
- {
- char n[32];
- snprintf(n, sizeof(n), "%lu", n_objs);
- strlcat(buf, n, sizeof(buf));
- strlcat(buf, " ", sizeof(buf));
- strlcat(buf, name, sizeof(buf));
- strlcat(buf, "s\n", sizeof(buf));
- }
+ format_noun(buf, sizeof(buf), name, n_objs, obj->default_article, true);
+ strlcat(buf, "\n", sizeof(buf));
send_packet(sender, REQ_BCASTMSG, buf, strlen(buf));
}
diff --git a/src/server_reqs.h b/src/server_reqs.h
index 68ba74a..10c1755 100644
--- a/src/server_reqs.h
+++ b/src/server_reqs.h
@@ -23,7 +23,7 @@
#include "server.h"
/* child<->master commands */
-/* children might not implement all of these */
+/* not all of these are implemented by both parties */
/* meanings might be different for the server and child, see comments */
#define REQ_NOP 0 /* server, child: do nothing (used for acknowledgement) */
#define REQ_BCASTMSG 1 /* server: broadcast text; child: print following text */
@@ -32,7 +32,7 @@
#define REQ_CHANGEUSER 4 /* server: change child login name */
#define REQ_HANG 5 /* <UNIMP> server: loop forever */
#define REQ_KICK 6 /* server: kick PID with message; child: print message, quit */
-#define REQ_WAIT 7 /* server: sleep 10s */
+#define REQ_WAIT 7 /* <DEBUG> server: sleep 10s */
#define REQ_GETROOMDESC 8 /* server: send child room description */
#define REQ_SETROOM 9 /* server: set child room */
#define REQ_MOVE 10 /* server: move child based on direction; child: success or failure */
@@ -50,6 +50,7 @@
#define REQ_DROP 22 /* server: drop user object if allowed */
#define REQ_LISTUSERS 23 /* server: list users in USERFILE */
#define REQ_EXECVERB 24 /* server: execute a verb with its arguments */
+#define REQ_RAWMODE 25 /* child: toggle the child's processing of commands and instead sending input directly to master */
/* child states, sent as an int to the master */
#define STATE_INIT 0 /* initial state */
diff --git a/src/userdb.c b/src/userdb.c
index 54dd19e..0a13319 100644
--- a/src/userdb.c
+++ b/src/userdb.c
@@ -232,7 +232,7 @@ void userdb_dump(void)
while(iter)
{
struct object_t *obj = iter->val;
- debugf(" - Obj #%lu class %s: name %s\n", obj->id, obj->class->class_name, obj->name);
+ debugf(" - Obj #%"PRI_OBJID" class %s: name %s\n", obj->id, obj->class->class_name, obj->name);
iter = iter->next;
}
}
diff --git a/src/util.c b/src/util.c
index 9776c31..9c4b447 100644
--- a/src/util.c
+++ b/src/util.c
@@ -188,9 +188,9 @@ bool is_vowel(char c)
}
}
-/* $NetBSD: strlcat.c,v 1.4 2005/05/16 06:55:48 lukem Exp $ */
-/* from NetBSD: strlcat.c,v 1.16 2003/10/27 00:12:42 lukem Exp */
-/* from OpenBSD: strlcat.c,v 1.10 2003/04/12 21:56:39 millert Exp */
+/* $NetBSD: strlcat.c,v 1.4 2005/05/16 06:55:48 lukem Exp $ */
+/* from NetBSD: strlcat.c,v 1.16 2003/10/27 00:12:42 lukem Exp */
+/* from OpenBSD: strlcat.c,v 1.10 2003/04/12 21:56:39 millert Exp */
/*
* Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
@@ -218,27 +218,62 @@ bool is_vowel(char c)
size_t
strlcat(char *dst, const char *src, size_t siz)
{
- char *d = dst;
- const char *s = src;
- size_t n = siz;
- size_t dlen;
-
- /* Find the end of dst and adjust bytes left but don't go past end */
- while (n-- != 0 && *d != '\0')
- d++;
- dlen = d - dst;
- n = siz - dlen;
-
- if (n == 0)
- return(dlen + strlen(s));
- while (*s != '\0') {
- if (n != 1) {
- *d++ = *s;
- n--;
- }
- s++;
- }
- *d = '\0';
-
- return(dlen + (s - src)); /* count does not include NUL */
+ char *d = dst;
+ const char *s = src;
+ size_t n = siz;
+ size_t dlen;
+
+ /* Find the end of dst and adjust bytes left but don't go past end */
+ while (n-- != 0 && *d != '\0')
+ d++;
+ dlen = d - dst;
+ n = siz - dlen;
+
+ if (n == 0)
+ return(dlen + strlen(s));
+ while (*s != '\0') {
+ if (n != 1) {
+ *d++ = *s;
+ n--;
+ }
+ s++;
+ }
+ *d = '\0';
+
+ return(dlen + (s - src)); /* count does not include NUL */
+}
+
+char *format_noun(char *buf, size_t len, const char *name, size_t count, bool default_article, bool capitalize)
+{
+ assert(len > 1);
+ buf[0] = '\0';
+ if(count == 1)
+ {
+ if(default_article)
+ {
+ char *article = capitalize?(is_vowel(name[0])? "An" : "A"):(is_vowel(name[0])? "an" : "a");
+ strlcat(buf, article, len);
+ strlcat(buf, " ", len);
+ strlcat(buf, name, len);
+ }
+ else
+ {
+ char tmp[2];
+ tmp[0] = toupper(name[0]);
+ tmp[1] = '\0';
+ strlcat(buf, tmp, len);
+ strlcat(buf, name + 1, len);
+ }
+ }
+ else
+ {
+ char n[32];
+ snprintf(n, sizeof(n), "%zu", count);
+ strlcat(buf, n, len);
+ strlcat(buf, " ", len);
+ strlcat(buf, name, len);
+ strlcat(buf, "s", len);
+ }
+
+ return buf;
}
diff --git a/src/util.h b/src/util.h
index 407836a..8007ec8 100644
--- a/src/util.h
+++ b/src/util.h
@@ -51,3 +51,6 @@ size_t read_size(int fd);
bool is_vowel(char c);
size_t strlcat(char *dst, const char *src, size_t siz);
+
+/* formats a noun's name */
+char *format_noun(char *buf, size_t len, const char *name, size_t count, bool default_article, bool capitalize);
diff --git a/src/world.c b/src/world.c
index a06b08e..8c25d7d 100644
--- a/src/world.c
+++ b/src/world.c
@@ -134,13 +134,13 @@ void world_save(const char *fname)
void *ptr = world_map, *save;
for(unsigned int i = 0; i < world_sz; ++i)
{
- void *key;
- struct room_t *room = hash_iterate(ptr, &save, &key);
- if(!room)
- break;
- ptr = NULL;
- write_string(fd, key);
- write_roomid(fd, &room->id);
+ void *key;
+ struct room_t *room = hash_iterate(ptr, &save, &key);
+ if(!room)
+ break;
+ ptr = NULL;
+ write_string(fd, key);
+ write_roomid(fd, &room->id);
}
close(fd);
@@ -250,13 +250,13 @@ bool world_load(const char *fname, const struct roomdata_t *data, size_t data_sz
/* read in the room name -> room map */
world_map = hash_init(world_sz * 2, hash_djb, compare_strings);
-
+
for(unsigned int i = 0; i < world_sz; ++i)
{
- const char *key = read_string(fd);
- room_id id = read_roomid(fd);
- debugf("'%s' -> %d\n", key, id);
- hash_insert(world_map, key, world + id);
+ const char *key = read_string(fd);
+ room_id id = read_roomid(fd);
+ debugf("'%s' -> %d\n", key, id);
+ hash_insert(world_map, key, world + id);
}
close(fd);
@@ -269,7 +269,7 @@ static SIMP_EQUAL(enum direction_t, dir_equal);
/* loads room data (supplied by the world module) into our internal format */
void world_init(const struct roomdata_t *data, size_t sz, const char *name)
{
- debugf("Loading world with %lu rooms.\n", sz);
+ debugf("Loading world with %zu rooms.\n", sz);
world = calloc(sz, sizeof(struct room_t));
world_sz = 0;
world_name = strdup(name);
@@ -400,7 +400,7 @@ room_id room_get_id(const char *uniq_id)
{
struct room_t *room = hash_lookup(world_map, uniq_id);
if(!room)
- return ROOM_NONE;
+ return ROOM_NONE;
else
- return room->id;
+ return room->id;
}
diff --git a/tests/all.sh b/tests/all.sh
index 68603d0..68603d0 100644..100755
--- a/tests/all.sh
+++ b/tests/all.sh
diff --git a/tests/gen_data.sh b/tests/gen_data.sh
index bba3964..bba3964 100644..100755
--- a/tests/gen_data.sh
+++ b/tests/gen_data.sh
diff --git a/worlds/test.c b/worlds/test.c
index 7425d81..f662c1f 100644
--- a/worlds/test.c
+++ b/worlds/test.c
@@ -9,13 +9,20 @@ 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.");
+
room_obj_add(id, new);
-#if 0
- new = obj_copy(new);
+ new = obj_new("/generic/notake");
+ new->name = strdup("trees");
+ new->userdata = strdup("They are palm trees with a bountiful supply of coconuts in them.");
+ new->hidden = true;
+
room_obj_add(id, new);
-#endif
+ room_obj_add_alias(id, new, "tree");
+ room_obj_add_alias(id, new, "palm");
+ room_obj_add_alias(id, new, "palm tree");
+ /* add global verbs */
struct verb_t *verb = verb_new("dig");
verb->name = strdup("dig");
world_verb_add(verb);
@@ -24,6 +31,13 @@ static void deadend_init(room_id id)
verb->name = strdup("put");
world_verb_add(verb);
+ verb = verb_new("eat");
+ verb->name = strdup("eat");
+ world_verb_add(verb);
+
+ verb = verb_new("shake");
+ verb->name = strdup("shake");
+ world_verb_add(verb);
}
static void ew_road_init(room_id id)
@@ -93,6 +107,7 @@ static void hidden_init(room_id id)
static bool building_enter(room_id id, user_t *user)
{
+ (void) id;
if(multimap_lookup(userdb_lookup(user->user)->objects, "shiny brass key", NULL))
return true;
else
@@ -107,7 +122,7 @@ static void mailroom_init(room_id id)
struct object_t *new = obj_new("/generic/notake");
new->name = strdup("bins");
new->hidden = true;
-
+
/* insert IAC NOP to prevent the extra whitespace from being dropped */
new->userdata = strdup("All of the bins are empty. Looking closely you can see that there are names written at the bottom of each bin, but most of them are faded away so that you cannot read them. You can only make out three names:\n\377\361 Jeffrey Collier\n\377\361 Robert Toukmond\n\377\361 Thomas Stock\n");
room_obj_add(id, new);
@@ -261,13 +276,13 @@ const struct roomdata_t netcosm_world[] = {
{
"computer_room",
"Computer room",
- "You are in a computer room. It seems like most of the equipment has been removed. There is a VAX 11/780 in front of you, however, with one of the cabinets wide open. A sign on the front of the machine says: This VAX is named 'pokey'. To type on the console, use the 'type' command. The exit is to the east.\nThe panel lights are steady and motionless.",
+ "You are in a computer room. It seems like most of the equipment has been removed. There is a VAX 11/780 in front of you, however, with one of the cabinets wide open. A sign on the front of the machine says: This VAX is named 'pokey'. To type on the console, use the 'type' command. The exit is to the east.\nThe panel lights are steady and motionless.",
{ NONE_N, NONE_NE, "building_hallway", NONE_SE, NONE_S, NONE_SW, NONE_W, NONE_NW, NONE_UP, NONE_DN, NONE_IN, NONE_OT },
computer_room_init,
NULL,
NULL,
bool_ser,
- bool_deser,
+ bool_deser,
bool_destroy,
},
};
@@ -406,7 +421,7 @@ static void dig_exec(struct verb_t *verb, char *args, user_t *user)
}
}
else
- send_msg(user, "Digging here reveals nothing.\n");
+ send_msg(user, "Digging here reveals nothing.\n");
return;
@@ -416,43 +431,45 @@ nothing:
static void put_exec(struct verb_t *verb, char *args, user_t *user)
{
+ (void) verb;
char *save;
const char *obj_name = strtok_r(args, WSPACE, &save);
if(!obj_name)
{
- send_msg(user, "You must supply an object\n");
- return;
+ send_msg(user, "You must supply an object\n");
+ return;
}
args = NULL;
const struct multimap_list *list = multimap_lookup(userdb_lookup(user->user)->objects,
- obj_name, NULL);
+ obj_name, NULL);
if(!list)
{
- send_msg(user, "You don't have that.\n");
- return;
+ send_msg(user, "You don't have that.\n");
+ return;
}
-
+
struct object_t *obj = list->val;
/* original dunnet ignores the preposition */
const char *prep = strtok_r(args, WSPACE, &save);
+ (void) prep;
const char *ind_obj_name = strtok_r(args, WSPACE, &save);
if(!ind_obj_name)
{
- send_msg(user, "You must supply an indirect object.\n");
- return;
+ send_msg(user, "You must supply an indirect object.\n");
+ return;
}
list = room_obj_get(user->room, ind_obj_name);
-
+
if(!list)
{
- send_msg(user, "I don't know what that indirect object is.\n");
- return;
+ send_msg(user, "I don't know what that indirect object is.\n");
+ return;
}
struct object_t *ind_obj = list->val;
@@ -460,33 +477,120 @@ static void put_exec(struct verb_t *verb, char *args, user_t *user)
/* now execute the verb */
if(!strcmp(obj->name, "CPU card") && !strcmp(ind_obj->name, "computer") && user->room == room_get_id("computer_room"))
{
- userdb_del_obj_by_ptr(user->user, obj);
- send_msg(user, "As you put the CPU board in the computer, it immediately springs to life. The lights start flashing, and the fans seem to startup.\n");
- bool *b = room_get(user->room)->userdata;
- *b = true;
+ userdb_del_obj_by_ptr(user->user, obj);
+ send_msg(user, "As you put the CPU board in the computer, it immediately springs to life. The lights start flashing, and the fans seem to startup.\n");
+ bool *b = room_get(user->room)->userdata;
+ *b = true;
+
+ room_get(user->room)->data.desc = strdup("You are in a computer room. It seems like most of the equipment has been removed. There is a VAX 11/780 in front of you, however, with one of the cabinets wide open. A sign on the front of the machine says: This VAX is named 'pokey'. To type on the console, use the 'type' command. The exit is to the east.\nThe panel lights are flashing in a seemingly organized pattern.");
+ }
+ else
+ {
+ send_msg(user, "I don't know how to combine those objects. Perhaps you should just try dropping it.\n");
+ }
+}
+
+static void eat_exec(struct verb_t *verb, char *args, user_t *user)
+{
+ (void) verb;
+ char *save;
+ char *obj_name = strtok_r(args, WSPACE, &save);
+ if(!obj_name)
+ {
+ send_msg(user, "You must supply an object.\n");
+ return;
+ }
+
+ size_t n_objs;
+ const struct multimap_list *list = multimap_lookup(userdb_lookup(user->user)->objects, obj_name, &n_objs);
+
+ if(!list)
+ {
+ if(!room_obj_get(user->room, obj_name))
+ send_msg(user, "I don't know what that is.\n");
+ else
+ send_msg(user, "You don't have that.\n");
+ return;
+ }
+
+ struct object_t *obj = list->val;
- room_get(user->room)->data.desc = strdup("You are in a computer room. It seems like most of the equipment has been removed. There is a VAX 11/780 in front of you, however, with one of the cabinets wide open. A sign on the front of the machine says: This VAX is named 'pokey'. To type on the console, use the 'type' command. The exit is to the east.\nThe panel lights are flashing in a seemingly organized pattern.");
+ if(!strcmp(obj->name, "some food"))
+ {
+ send_msg(user, "That tasted horrible.\n");
}
else
{
- send_msg(user, "I don't know how to combine those objects. Perhaps you should just try dropping it.\n");
+ char buf[MSG_MAX];
+ send_msg(user, "You forcibly shove %s down your throat, and start choking.\n",
+ format_noun(buf, sizeof(buf), obj->name, n_objs, obj->default_article, false));
+
+ /* TODO: kill player */
+ }
+
+ userdb_del_obj(user->user, obj_name);
+}
+
+static void shake_exec(struct verb_t *verb, char *args, user_t *user)
+{
+ (void) verb;
+ char *save;
+ char *obj_name = strtok_r(args, WSPACE, &save);
+
+ if(!obj_name)
+ {
+ send_msg(user, "You must supply an object.\n");
+ return;
+ }
+
+ size_t n_objs_room, n_objs_inv;
+ const struct multimap_list *list_room = room_obj_get_size(user->room, obj_name, &n_objs_room);
+
+ const struct multimap_list *list_inv = multimap_lookup(userdb_lookup(user->user)->objects, obj_name, &n_objs_inv);
+
+ if(!list_room && !list_inv)
+ {
+ send_msg(user, "I don't know what that is.\n");
+ return;
+ }
+
+ if(list_room)
+ {
+ struct object_t *obj = list_room->val;
+ if(!strcmp(obj->name, "trees"))
+ send_msg(user, "You begin to shake a tree, and notice a coconut begin to fall from the air. As you try to get your hand up to block it, you feel the impact as it lands on your head.\n");
+ else
+ send_msg(user, "You don't have that.\n");
+ }
+ else if(list_inv)
+ {
+ struct object_t *obj = list_inv->val;
+ char buf[MSG_MAX];
+ send_msg(user, "Shaking %s seems to have no effect.\n",
+ format_noun(buf, sizeof(buf), obj->name,
+ n_objs_room, obj->default_article,
+ false));
}
}
-/* global verbs */
+/* verb classes */
const struct verb_class_t netcosm_verb_classes[] = {
{ "dig",
dig_exec },
{ "put",
- put_exec },
- /*
+ put_exec },
+ { "eat",
+ eat_exec },
{ "shake",
shake_exec },
+ /*
+ { "type",
+ type_exec },
{ "climb",
climb_exec },
- { "eat",
- eat_exec },
+ */
+ /*
{ "feed",
feed_exec },
*/