home · contact · privacy
Server: Read in former "config" data as normal server god commands.
authorChristian Heller <c.heller@plomlompom.de>
Sun, 13 Jul 2014 21:49:13 +0000 (23:49 +0200)
committerChristian Heller <c.heller@plomlompom.de>
Sun, 13 Jul 2014 21:49:13 +0000 (23:49 +0200)
Re-wrote and re-factored lots of stuff to facilitate this.

25 files changed:
confserver/world
src/client/command_db.c
src/client/control.c
src/client/interface_conf.c
src/client/parse.c [new file with mode: 0644]
src/client/parse.h [new file with mode: 0644]
src/common/parse_file.c
src/common/parse_file.h
src/server/configfile.c [deleted file]
src/server/configfile.h [deleted file]
src/server/god_commands.c [new file with mode: 0644]
src/server/god_commands.h [new file with mode: 0644]
src/server/hardcoded_strings.c
src/server/hardcoded_strings.h
src/server/init.c
src/server/init.h
src/server/io.c
src/server/main.c
src/server/run.c
src/server/run.h
src/server/thing_actions.c
src/server/thing_actions.h
src/server/things.c
src/server/things.h
src/server/world.h

index 1bbb10c06fc588c6b8aea412451685be0170cf5f..a399aeeffd578181dc882c8c82e46f166997e2e9 100644 (file)
@@ -1,78 +1,86 @@
 MAP_LENGTH 64
 PLAYER_TYPE 0
 
-ACTION 1
-NAME wait
-EFFORT 1
+THING_ACTION 1
+TA_EFFORT 1
+TA_NAME wait
 
-ACTION 2
-NAME move
-EFFORT 5
+THING_ACTION 2
+TA_EFFORT 5
+TA_NAME move
 
-ACTION 3
-NAME pick_up
-EFFORT 15
+THING_ACTION 3
+TA_EFFORT 15
+TA_NAME pick_up
 
-ACTION 4
-NAME drop
-EFFORT 5
+THING_ACTION 4
+TA_EFFORT 5
+TA_NAME drop
 
-ACTION 5
-NAME use
-EFFORT 45
+THING_ACTION 5
+TA_EFFORT 45
+TA_NAME use
 
-THINGTYPE 0
-NAME HUMAN
-SYMBOL @
-LIFEPOINTS 5
-CORPSE_ID 5
-CONSUMABLE 0
-START_NUMBER 1
+THING_TYPE 0
+TT_START_NUMBER 1
+TT_LIFEPOINTS 5
+TT_SYMBOL @
+TT_NAME HUMAN
+TT_CONSUMABLE 0
 
-THINGTYPE 1
-NAME ANT
-SYMBOL a
-LIFEPOINTS 1
-CORPSE_ID 4
-CONSUMABLE 0
-START_NUMBER 27
+THING_TYPE 1
+TT_START_NUMBER 27
+TT_LIFEPOINTS 1
+TT_SYMBOL a
+TT_NAME ANT
+TT_CONSUMABLE 0
 
-THINGTYPE 2
-NAME ZOMBIE
-SYMBOL z
-LIFEPOINTS 3
-CORPSE_ID 5
-CONSUMABLE 0
-START_NUMBER 9
+THING_TYPE 2
+TT_START_NUMBER 9
+TT_LIFEPOINTS 3
+TT_SYMBOL z
+TT_NAME ZOMBIE
+TT_CONSUMABLE 0
 
-THINGTYPE 3
-NAME SHOGGOTH
-SYMBOL S
-LIFEPOINTS 9
-CORPSE_ID 6
-CONSUMABLE 0
-START_NUMBER 3
+THING_TYPE 3
+TT_START_NUMBER 3
+TT_LIFEPOINTS 9
+TT_SYMBOL S
+TT_NAME SHOGGOTH
+TT_CONSUMABLE 0
 
-THINGTYPE 4
-NAME DIRT
-SYMBOL #
-LIFEPOINTS 0
-CORPSE_ID 4
-CONSUMABLE 0
-START_NUMBER 9
+THING_TYPE 4
+TT_START_NUMBER 9
+TT_LIFEPOINTS 0
+TT_SYMBOL #
+TT_NAME DIRT
+TT_CONSUMABLE 0
 
-THINGTYPE 5
-NAME SKELETON
-SYMBOL %
-LIFEPOINTS 0
-CORPSE_ID 4
-CONSUMABLE 0
-START_NUMBER 9
+THING_TYPE 5
+TT_START_NUMBER 9
+TT_LIFEPOINTS 0
+TT_SYMBOL %
+TT_NAME SKELETON
+TT_CONSUMABLE 0
 
-THINGTYPE 6
-NAME 'MAGIC MEAT'
-SYMBOL m
-LIFEPOINTS 0
-CORPSE_ID 4
-CONSUMABLE 3
-START_NUMBER 1
+THING_TYPE 6
+TT_START_NUMBER 1
+TT_LIFEPOINTS 0
+TT_SYMBOL m
+TT_NAME 'MAGIC MEAT'
+TT_CONSUMABLE 3
+
+THING_TYPE 0
+TT_CORPSE_ID 5
+THING_TYPE 1
+TT_CORPSE_ID 4
+THING_TYPE 2
+TT_CORPSE_ID 5
+THING_TYPE 3
+TT_CORPSE_ID 6
+THING_TYPE 4
+TT_CORPSE_ID 4
+THING_TYPE 5
+TT_CORPSE_ID 4
+THING_TYPE 6
+TT_CORPSE_ID 4
index b9d10a6234c92560bbeb1994d4ec0de5ccb52f10..a7523b79a1a40b2863eac2dbc3dc45cf60fd3527 100644 (file)
@@ -6,13 +6,12 @@
 #include <stdint.h> /* uint8_t */
 #include <stdlib.h> /* free() */
 #include <string.h> /* strcmp(), strdup() */
-#include "../common/parse_file.h" /* EDIT_STARTED,parse_init_entry(),
-                                   * parse_id_uniq(), parse_unknown_arg(),
-                                   * parsetest_too_many_values(), parse_file(),
-                                   * parse_and_reduce_to_readyflag(),
-                                   * parse_flagval()
-                                   */
 #include "array_append.h" /* array_append() */
+#include "parse.h" /* EDIT_STARTED, parse_init_entry(), parse_id_uniq(),
+                    * parse_unknown_arg(), parsetest_too_many_values(),
+                    * parse_file(), parse_and_reduce_to_readyflag(),
+                    * parse_flagval()
+                    */
 #include "world.h" /* global world */
 #include "cleanup.h" /* set_cleanup_flag() */
 
index 04f0c94825d234edefd67a2488acb41967d2b7c0..17a76320e48c7ad70c3535ef5f754c26156829d6 100644 (file)
@@ -181,8 +181,8 @@ static char * build_server_message_with_argument(struct Command * cmd)
 {
     char * f_name = "build_server_message_with_argument()";
     uint8_t command_size = strlen(cmd->server_msg);
-    char * arg_str;
-    uint8_t arg_size;
+    char * arg_str = "";
+    uint8_t arg_size = 0;
     if ('i' == cmd->arg)
     {
         arg_size = 3;
index 853fdaae66ef132b50ed340078e39a52e497f11b..aba5e3bf5927f3be950a26d6d190e661804707e4 100644 (file)
@@ -9,13 +9,7 @@
 #include <stdio.h> /* FILE, sprintf() */
 #include <string.h> /* strchr(), strcmp(), strdup(), strlen() */
 #include <unistd.h> /* optarg, getopt() */
-#include "../common/parse_file.h" /* EDIT_STARTED, parse_file(),parse_flagval(),
-                                   * token_from_line(), parsetest_singlechar(),
-                                   * parse_and_reduce_to_readyflag(),
-                                   * parsetest_defcontext(),parse_unknown_arg(),
-                                   * parsetest_too_many_values(),
-                                   * parse_id_uniq(), parse_init_entry()
-                                   */
+#include "../common/parse_file.h" /* token_from_line(),parsetset_singlechar() */
 #include "../common/readwrite.h" /* atomic_write_start(), atomic_write_finish(),
                                   * detect_atomic_leftover(), try_fwrite()
                                   */
 #include "command_db.h" /* get_command() */
 #include "keybindings.h" /* KeyBinding, KeyBindingDB, get_command_to_keycode()*/
 #include "map.h" /* map_center() */
+#include "parse.h" /* EDIT_STARTED, parse_file(), parse_flagval(),
+                    * parse_and_reduce_to_readyflag(), parse_id_uniq()
+                    * parsetest_defcontext(), parse_unknown_arg(),
+                    * parsetest_too_many_values(), parse_init_entry()
+                    */
 #include "wincontrol.h" /* toggle_window() */
 #include "windows.h" /* Win, free_winDB(), make_v_screen_and_init_win_sizes() */
 #include "world.h" /* global world */
diff --git a/src/client/parse.c b/src/client/parse.c
new file mode 100644 (file)
index 0000000..2767c46
--- /dev/null
@@ -0,0 +1,120 @@
+/* src/client/parse.c */
+
+#define _POSIX_C_SOURCE 200809L /* strdup() */
+#include "parse.h"
+#include <stddef.h> /* size_t, NULL */
+#include <stdio.h> /* FILE, snprintf() */
+#include <stdint.h> /* uint8_t, uint32_t */
+#include <stdlib.h> /* free() */
+#include <string.h> /* strdup(), strlen() */
+#include <unistd.h> /* access(), F_OK */
+#include "../common/parse_file.h" /* set_err_line_options(), err_line_inc(),
+                                   * err_line_zero(), token_from_line()
+                                   */
+#include "../common/readwrite.h" /* try_fopen(),try_fclose(),textfile_width() */
+#include "../common/rexit.h" /* exit_err(), exit_trouble() */
+#include "../common/try_malloc.h" /* try_malloc() */
+
+
+
+extern void parse_file(char * path, void (* token_to_entry) (char *, char *))
+{
+    char * f_name = "read_new_config_file()";
+    char * prefix = "Failed reading config file: \"";
+    char * affix = "\". ";
+    size_t size = strlen(prefix) + strlen(path) + strlen(affix) + 1;
+    char * errline_intro = try_malloc(size, f_name);
+    int test = snprintf(errline_intro, size, "%s%s%s", prefix, path, affix);
+    exit_trouble(test < 0, f_name, "snprintf()");
+    exit_err(access(path, F_OK), errline_intro);
+    FILE * file = try_fopen(path, "r", f_name);
+    uint32_t linemax = textfile_width(file);
+    char * errline_line = try_malloc(linemax + 1, f_name);
+    set_err_line_options(errline_intro, errline_line, 1);
+    err_line_zero();
+    err_line(0 == linemax, "File is empty.");
+    char * token0 = NULL; /* For final token_to_entry() if while() stagnates. */
+    char * token1 = NULL;
+    char * err_val = "No value given.";
+    while (try_fgets(errline_line, linemax + 1, file, f_name))
+    {
+        err_line_inc();
+        // err_line(UINT32_MAX == err_line_count, "Line reaches max lines limit.");
+        char * line_copy = strdup(errline_line);
+        token0 = token_from_line(line_copy);
+        if (token0)
+        {
+            err_line(0 == (token1 = token_from_line(NULL)), err_val);
+            token_to_entry(token0, token1);
+            token0 = NULL;
+        }
+        free(line_copy);
+    }
+    token_to_entry(token0, token1);
+    try_fclose(file, f_name);
+    free(errline_line);
+    free(errline_intro);
+}
+
+
+
+extern void parsetest_defcontext(uint8_t flags)
+{
+    err_line(!(flags & EDIT_STARTED),"Outside appropriate definition context.");
+}
+
+
+
+extern void parsetest_too_many_values()
+{
+    err_line(NULL != token_from_line(NULL), "Too many values.");
+}
+
+
+
+extern void parse_id_uniq(int test)
+{
+    err_line(0 != test, "Declaration of ID already used.");
+}
+
+
+
+extern void parse_unknown_arg()
+{
+    err_line(1, "Unknown argument.");
+}
+
+
+
+extern char * parse_init_entry(uint8_t * flags, size_t size)
+{
+    char * f_name = "parse_init_entry()";
+    *flags = EDIT_STARTED;
+    char * p = try_malloc(size, f_name);
+    memset(p, 0, size);
+    return p;
+}
+
+
+
+extern uint8_t parse_flagval(char * token0, char * token1, char * comparand,
+                             uint8_t * flags, uint8_t set_flag, char type,
+                             char * element)
+{
+    if (parse_val(token0, token1, comparand, type, element))
+    {
+        parsetest_defcontext(*flags);
+        *flags = *flags | set_flag;
+        return 1;
+    }
+    return 0;
+}
+
+
+
+extern void parse_and_reduce_to_readyflag(uint8_t * flags, uint8_t ready_flag)
+{
+    char * err_fin = "Last definition block not finished yet.";
+    err_line((*flags & ready_flag) ^ ready_flag, err_fin);
+    *flags = ready_flag;
+}
diff --git a/src/client/parse.h b/src/client/parse.h
new file mode 100644 (file)
index 0000000..33a9687
--- /dev/null
@@ -0,0 +1,55 @@
+/* src/client/parse.h
+ *
+ * Routines for file parsing.
+ */
+
+#ifndef PARSE_H
+#define PARSE_H
+
+#include <stddef.h> /* size_t */
+#include <stdint.h> /* uint8_t */
+
+
+
+enum parse_flags
+{
+    EDIT_STARTED  = 0x01
+};
+
+
+
+/* Parse file at "path" by passing each line's first two tokens to
+ * "token_to_entry". Ignore empty lines. Non-empty lines must feature at least
+ * two tokens as delimited either be whitespace or single quotes (to allow for
+ * tokens featuring whitespaces). When EOF is reached, token_to_entry() is
+ * called a last time with a first token of NULL.
+ */
+extern void parse_file(char * path, void ( *token_to_entry) (char *, char *));
+
+/* Calls err_line() with fitting message if EDIT_STARTED not set in "flags". */
+extern void parsetest_defcontext(uint8_t flags);
+
+/* Ensure token_from_line() does not find any more tokens on the line. */
+extern void parsetest_too_many_values();
+
+/* Trigger err_line() with "Unknown argument" message. */
+extern void parse_unknown_arg();
+
+/* If "test"!=0 call err_line() with "Declaration of ID already used" message.*/
+extern void parse_id_uniq(int test);
+
+/* Set "flags"=EDIT_STARTED and return pointer to new zeroed array of "size". */
+extern char * parse_init_entry(uint8_t * flags, size_t size);
+
+/* Wrapper to parse_val() that sets "flags" to "flags"|"set_flag" on success. */
+extern uint8_t parse_flagval(char * token0, char * token1, char * comparand,
+                             uint8_t * flags, uint8_t set_flag, char type,
+                             char * element);
+
+/* Check "ready_flag" is set in "flags", re-set "flags" to "ready_flag" only. */
+extern void parse_and_reduce_to_readyflag(uint8_t * flags, uint8_t ready_flag);
+
+
+
+#endif
+
index 8ce20ad55db79c7369225134e73d2f09a5d2b42a..82ba4e389bdbbe34d930df6eb7af71a08a5ab485 100644 (file)
@@ -7,8 +7,6 @@
 #include <stdint.h> /* int16_t,uint8_t,uint32_t, INT16_MIN, UINT{8,16,32}_MAX */
 #include <stdlib.h> /* atoi(), free() */
 #include <string.h> /* strchr, strcmp(), strdup(), strlen() */
-#include <unistd.h> /* access(), F_OK */
-#include "readwrite.h" /* try_fopen(), try_fclose(), textfile_width() */
 #include "rexit.h" /* exit_err(), exit_trouble() */
 #include "try_malloc.h" /* try_malloc() */
 
@@ -49,53 +47,26 @@ static void set_token_end(char ** start, char ** limit_char)
 
 
 
-extern void parse_file(char * path, void (* token_to_entry) (char *, char *))
+extern void set_err_line_options(char * intro, char * line, uint8_t exit)
 {
-    char * f_name = "read_new_config_file()";
-    char * prefix = "Failed reading config file: \"";
-    char * affix = "\". ";
-    size_t size = strlen(prefix) + strlen(path) + strlen(affix) + 1;
-    char * errline_intro = try_malloc(size, f_name);
-    int test = snprintf(errline_intro, size, "%s%s%s", prefix, path, affix);
-    exit_trouble(test < 0, f_name, "snprintf()");
-    exit_err(access(path, F_OK), errline_intro);
-    FILE * file = try_fopen(path, "r", f_name);
-    uint32_t linemax = textfile_width(file);
-    char * errline_line = try_malloc(linemax + 1, f_name);
-    set_err_line_options(errline_intro, errline_line, 0, 1);
-    err_line(0 == linemax, "File is empty.");
-    char * token0 = NULL; /* For final token_to_entry() if while() stagnates. */
-    char * token1 = NULL;
-    char * err_val = "No value given.";
-    while (try_fgets(errline_line, linemax + 1, file, f_name))
-    {
-        err_line_count++;
-        err_line(UINT32_MAX == err_line_count, "Line reaches max lines limit.");
-        char * line_copy = strdup(errline_line);
-        token0 = token_from_line(line_copy);
-        if (token0)
-        {
-            err_line(0 == (token1 = token_from_line(NULL)), err_val);
-            token_to_entry(token0, token1);
-            token0 = NULL;
-        }
-        free(line_copy);
-    }
-    token_to_entry(token0, token1);
-    try_fclose(file, f_name);
-    free(errline_line);
-    free(errline_intro);
+    err_line_line = line;
+    err_line_intro = intro;
+    err_line_exit = exit;
 }
 
 
 
-extern void set_err_line_options(char * intro, char * line, uint32_t count,
-                                 uint8_t exit)
+extern void err_line_inc()
 {
-    err_line_count = count;
-    err_line_line = line;
-    err_line_intro = intro;
-    err_line_exit = exit;
+    err_line_count++;
+    err_line(UINT32_MAX == err_line_count, "Line reaches max lines limit.");
+}
+
+
+
+extern void err_line_zero()
+{
+    err_line_count = 0;
 }
 
 
@@ -108,7 +79,7 @@ extern uint8_t err_line(uint8_t test, char * msg)
     }
     char * f_name = "err_line()";
     char * prefix = " Offending line ";
-    char * affix = ":\n";
+    char * affix = ": ";
     size_t size =   strlen(err_line_intro) + strlen(msg) + strlen(prefix)
                   + 10                 /* strlen for uint32_t representations */
                   + strlen(affix) + strlen(err_line_line) + 1;
@@ -208,13 +179,6 @@ extern uint8_t parsetest_int(char * string, char type)
 
 
 
-extern void parsetest_defcontext(uint8_t flags)
-{
-    err_line(!(flags & EDIT_STARTED),"Outside appropriate definition context.");
-}
-
-
-
 extern uint8_t parsetest_singlechar(char * string)
 {
     return err_line(1 !=strlen(string),"Value must be single ASCII character.");
@@ -222,38 +186,6 @@ extern uint8_t parsetest_singlechar(char * string)
 
 
 
-extern void parsetest_too_many_values()
-{
-    err_line(NULL != token_from_line(NULL), "Too many values.");
-}
-
-
-
-extern void parse_id_uniq(int test)
-{
-    err_line(0 != test, "Declaration of ID already used.");
-}
-
-
-
-extern void parse_unknown_arg()
-{
-    err_line(1, "Unknown argument.");
-}
-
-
-
-extern char * parse_init_entry(uint8_t * flags, size_t size)
-{
-    char * f_name = "parse_init_entry()";
-    *flags = EDIT_STARTED;
-    char * p = try_malloc(size, f_name);
-    memset(p, 0, size);
-    return p;
-}
-
-
-
 extern uint8_t parse_val(char * token0, char * token1, char * comparand,
                          char type, char * element)
 {
@@ -261,11 +193,15 @@ extern uint8_t parse_val(char * token0, char * token1, char * comparand,
     {
         if      ('s' == type)
         {
+            free(* (char **) element);
             * (char **) element = strdup(token1);
         }
-        else if ('c' == type && !parsetest_singlechar(token1))
+        else if ('c' == type)
         {
-            *element = (token1)[0];
+            if (!parsetest_singlechar(token1))
+            {
+                *element = (token1)[0];
+            }
         }
         else if (!parsetest_int(token1, type))
         {
@@ -290,27 +226,3 @@ extern uint8_t parse_val(char * token0, char * token1, char * comparand,
     }
     return 0;
 }
-
-
-
-extern uint8_t parse_flagval(char * token0, char * token1, char * comparand,
-                             uint8_t * flags, uint8_t set_flag, char type,
-                             char * element)
-{
-    if (parse_val(token0, token1, comparand, type, element))
-    {
-        parsetest_defcontext(*flags);
-        *flags = *flags | set_flag;
-        return 1;
-    }
-    return 0;
-}
-
-
-
-extern void parse_and_reduce_to_readyflag(uint8_t * flags, uint8_t ready_flag)
-{
-    char * err_fin = "Last definition block not finished yet.";
-    err_line((*flags & ready_flag) ^ ready_flag, err_fin);
-    *flags = ready_flag;
-}
index 4192dac046ee7190a8976e3253fe5b5b2f25f6fc..7d7cfbda195ebab3b31436f82edf74db90575f56 100644 (file)
@@ -1,36 +1,23 @@
 /* src/common/parse_file.h
  *
- * Tools for parsing config files.
+ * Tools for parsing files.
  */
 
 #ifndef PARSE_FILE_H
 #define PARSE_FILE_H
 
-#include <stddef.h> /* size_t */
 #include <stdint.h> /* uint8_t */
 
 
 
-enum parse_flags
-{
-    EDIT_STARTED  = 0x01
-};
-
-
-
-/* Parse file at "path" by passing each line's first two tokens to
- * "token_to_entry". Ignore empty lines. Non-empty lines must feature at least
- * two tokens as delimited either be whitespace or single quotes (to allow for
- * tokens featuring whitespaces). When EOF is reached, token_to_entry() is
- * called a last time with a first token of NULL.
- */
-extern void parse_file(char * path, void ( *token_to_entry) (char *, char *));
-
 /* Set err_line() options: "intro" message, char array used to store analyzed
- * lines ("line"), line start "count", whether to "exit" on error message.
+ * lines ("line"), and whether to "exit" on error message.
  */
-extern void set_err_line_options(char * intro, char * line, uint32_t count,
-                                 uint8_t exit);
+extern void set_err_line_options(char * intro, char * line, uint8_t exit);
+
+/* Increment and reset (to zero) err_line() line counter. */
+extern void err_line_inc();
+extern void err_line_zero();
 
 /* If "test", output "msg", faulty line, its number and exit if so defined by
  * set_err_line_options(), else return 1 on "test" and 0 if "test" is 0.
@@ -56,21 +43,6 @@ extern uint8_t parsetest_int(char * string, char type);
 /* Test for "string" to be of length 1 (excluding "\0"). Return 1 on failure. */
 extern uint8_t parsetest_singlechar(char * string);
 
-/* Calls err_line() with fitting message if EDIT_STARTED not set in "flags". */
-extern void parsetest_defcontext(uint8_t flags);
-
-/* Ensure token_from_line() does not find any more tokens on the line. */
-extern void parsetest_too_many_values();
-
-/* Trigger err_line() with "Unknown argument" message. */
-extern void parse_unknown_arg();
-
-/* If "test"!=0 call err_line() with "Declaration of ID already used" message.*/
-extern void parse_id_uniq(int test);
-
-/* Set "flags"=EDIT_STARTED and return pointer to new zeroed array of "size". */
-extern char * parse_init_entry(uint8_t * flags, size_t size);
-
 /* If "token0" fits "comparand", set "element" to value read from "token1" as
  * string (type: "s"), char ("c") uint8 ("8"), uint16 ("u"), uint32 ("U") or
  * int16 ("i"), and return 1; else 0.
@@ -78,14 +50,6 @@ extern char * parse_init_entry(uint8_t * flags, size_t size);
 extern uint8_t parse_val(char * token0, char * token1, char * comparand,
                          char type, char * element);
 
-/* Wrapper to parse_val() that sets "flags" to "flags"|"set_flag" on success. */
-extern uint8_t parse_flagval(char * token0, char * token1, char * comparand,
-                             uint8_t * flags, uint8_t set_flag, char type,
-                             char * element);
-
-/* Check "ready_flag" is set in "flags", re-set "flags" to "ready_flag" only. */
-extern void parse_and_reduce_to_readyflag(uint8_t * flags, uint8_t ready_flag);
-
 
 
 #endif
diff --git a/src/server/configfile.c b/src/server/configfile.c
deleted file mode 100644 (file)
index ca1b07f..0000000
+++ /dev/null
@@ -1,322 +0,0 @@
-/* src/server/configfile.c */
-
-#include <stddef.h> /* size_t, NULL */
-#include <stdio.h> /* snprintf() */
-#include <stdint.h> /* uint8_t */
-#include <stdlib.h> /* atoi(), free() */
-#include <string.h> /* strcmp() */
-#include "../common/parse_file.h" /* EDIT_STARTED, parsetest_int(),parse_file(),
-                                   * parsetest_too_many_values(),parse_id_uniq()
-                                   * parse_unknown_arg(), parse_init_entry(),
-                                   * parse_and_reduce_to_readyflag(),
-                                   * parse_flagval()
-                                   */
-#include "../common/rexit.h" /* exit_err(), exit_trouble() */
-#include "../common/try_malloc.h" /* try_malloc() */
-#include "cleanup.h" /* set_cleanup_flag(), CLEANUP_THING_TYPES,
-                      * CLEANUP_THING_ACTIONS
-                      */
-#include "hardcoded_strings.h" /* s */
-#include "thing_actions.h" /* ThingAction */
-#include "things.h" /* Thing, ThingType */
-#include "world.h" /* world global */
-
-
-
-/* Flags defining state of thing type and action entry reading ((un-)finished /
- * ready for starting the reading of a new definition etc.)
- */
-enum flag
-{
-    HEIGHT_SET     = 0x02,
-    WIDTH_SET      = 0x04,
-    NAME_SET       = 0x02,
-    EFFORT_SET     = 0x04,
-    CORPSE_ID_SET  = 0x04,
-    SYMBOL_SET     = 0x08,
-    LIFEPOINTS_SET = 0x10,
-    CONSUMABLE_SET = 0x20,
-    START_N_SET    = 0x40,
-    READY_ACTION   = NAME_SET | EFFORT_SET,
-    READY_THING    = NAME_SET | CORPSE_ID_SET | SYMBOL_SET | LIFEPOINTS_SET
-                     | CONSUMABLE_SET | START_N_SET
-};
-
-
-
-/* What ThingType and ThingAction structs have in common at their top. Use this
- * to allow same functions run over structs of both types.
- */
-struct EntryHead
-{
-    uint8_t id;
-    struct EntryHead * next;
-};
-
-
-
-/* Interpret "token0" and "token1" as data to write into the ThingAction /
- * ThingType DB.
- *
- * Individual ThingType / ThingAction DB entries are put together line by line
- * before being written. Writing only happens after all necessary members of an
- * entry have been assembled, and when additionally a) a new entry is started by
- * a "token0" of "ACTION" or "THINGTYPE"; or b) "token0" is NULL.
- *
- * Also check against the line parse_file() read tokens from having more tokens.
- */
-static void tokens_into_entries(char * token0, char * token1);
-
-/* Start reading a new DB entry of "size" from tokens if "token0" matches
- * "comparand". Set EDIT_STARTED in "flags" to mark beginning of new entry
- * reading. Check that "token1" id of new entry has not already been used in DB
- * starting at "entry_cmp".
- */
-static uint8_t start_entry(char * token0, char * token1, char * comparand,
-                         uint8_t * flags, size_t size,
-                         struct EntryHead ** entry,
-                         struct EntryHead * entry_cmp);
-
-/* Write DB entry pointed to by "entry" to its appropriate location. */
-static void write_if_entry(struct EntryHead ** entry,
-                           struct EntryHead *** entry_p_p_p);
-
-/* Ensure that all .corpse_id members in the ThingType DB fit .id members of
- * ThingType DB entries.
- */
-static void test_corpse_ids();
-
-/* If "token0" matches "comparand", set world.player_type to int in "token1". */
-static uint8_t set_player_type(char * token0, char * comparand, char * token1);
-
-/* If "token0" matches "comparand", set world.map.length to int in "token1". */
-static uint8_t set_map_length(char * token0, char * comparand, char * token1);
-
-/* Try to read tokens as members for the definition currently edited, which may
- * be "tt" or "ta". What member of which of the two is set depends on which of
- * the flags has EDIT_STARTED set and on the key name in "token0". Return 1 if
- * interpretation succeeds, else 0.
- *
- * Note that ThingAction entries' .name also determines their .func.
- */
-static uint8_t set_members(char * token0, char * token1,
-                           uint8_t * thing_flags, uint8_t * action_flags,
-                           struct ThingType * tt, struct ThingAction * ta);
-
-/* If "name" fits "ta"->name, set "ta"->func to "func". (Derives ThingAction
- * .func from .name for set_members().
- */
-static uint8_t try_func_name(struct ThingAction * ta,
-                             char * name, void (* func) (struct Thing *));
-
-
-
-static void tokens_into_entries(char * token0, char * token1)
-{
-    char * str_action = "ACTION";
-    char * str_thing = "THINGTYPE";
-    char * str_player = "PLAYER_TYPE";
-    char * str_map_length = "MAP_LENGTH";
-    static struct ThingAction ** ta_p_p = &world.thing_actions;
-    static struct ThingType ** tt_p_p = &world.thing_types;
-    static uint8_t action_flags = READY_ACTION;
-    static uint8_t thing_flags = READY_THING;
-    static struct EntryHead * ta = NULL;
-    static struct EntryHead * tt = NULL;
-    if (!token0 || !strcmp(token0, str_action) || !strcmp(token0, str_thing)
-                || !strcmp(token0, str_player))
-    {
-        parse_and_reduce_to_readyflag(&action_flags, READY_ACTION);
-        parse_and_reduce_to_readyflag(&thing_flags, READY_THING);
-        write_if_entry(&ta, (struct EntryHead ***) &ta_p_p);
-        write_if_entry(&tt, (struct EntryHead ***) &tt_p_p);
-    }
-    if (token0)
-    {
-        parsetest_too_many_values();
-        if (start_entry(token0, token1, str_action, &action_flags,
-                        sizeof(struct ThingAction), (struct EntryHead**) &ta,
-                        (struct EntryHead *) world.thing_actions))
-        {
-            err_line(0 == atoi(token1), "Value must not be 0.");
-        }
-        else if (!(   start_entry(token0, token1, str_thing, &thing_flags,
-                                  sizeof(struct ThingType),
-                                  (struct EntryHead**) &tt,
-                                  (struct EntryHead *) world.thing_types)
-                   || set_player_type(token0, str_player, token1)
-                   || set_map_length(token0, str_map_length, token1)
-                   || set_members(token0, token1, &thing_flags, &action_flags,
-                                  (struct ThingType *) tt,
-                                  (struct ThingAction *) ta)))
-        {
-            parse_unknown_arg();
-        }
-    }
-}
-
-
-
-static uint8_t start_entry(char * token0, char * token1, char * comparand,
-                           uint8_t * flags, size_t size,
-                           struct EntryHead ** entry,
-                           struct EntryHead * entry_cmp)
-{
-    if (strcmp(token0, comparand))
-    {
-        return 0;
-    }
-    *entry = (struct EntryHead *) parse_init_entry(flags, size);
-    parsetest_int(token1, '8');
-    (*entry)-> id = atoi(token1);
-    for (; NULL != entry_cmp; entry_cmp = entry_cmp->next)
-    {
-        parse_id_uniq((*entry)->id == entry_cmp->id);
-    }
-    return 1;
-}
-
-
-
-static void write_if_entry(struct EntryHead ** entry,
-                           struct EntryHead *** entry_p_p_p)
-{
-    if (*entry)
-    {
-        (*entry)->next = NULL;
-        **entry_p_p_p = *entry;
-        *entry_p_p_p = &((*entry)->next);
-        *entry = NULL;   /* So later runs of this don't re-append same entry. */
-    }
-}
-
-
-
-static void test_corpse_ids()
-{
-    char * f_name = "test_corpse_ids()";
-    char * prefix = "In the thing types DB, one thing corpse ID does not "
-                    "reference any known thing type in the DB. ID of "
-                    "responsible thing type: ";
-    size_t size = strlen(prefix) + 3 + 1; /* 3: uint8_t representation strlen */
-    char * err_corpse = try_malloc(size, f_name);
-    struct ThingType * test_entry_0 = world.thing_types;
-    for (; test_entry_0; test_entry_0 = test_entry_0->next)
-    {
-        uint8_t corpse_id_found = 0;
-        struct ThingType * test_entry_1 = world.thing_types;
-        for (; test_entry_1; test_entry_1 = test_entry_1->next)
-        {
-            if (test_entry_0->corpse_id == test_entry_1->id)
-            {
-                corpse_id_found = 1;
-            }
-        }
-        int test = snprintf(err_corpse, size, "%s%d", prefix, test_entry_0->id);
-        exit_trouble(test < 0, f_name, "snprintf()");
-        exit_err(!corpse_id_found, err_corpse);
-    }
-    free(err_corpse);
-}
-
-
-
-static uint8_t set_player_type(char * token0, char * comparand, char * token1)
-{
-    if (strcmp(token0, comparand))
-    {
-        return 0;
-    }
-    parsetest_int(token1, '8');
-    world.player_type = atoi(token1);
-    return 1;
-}
-
-
-
-static uint8_t set_map_length(char * token0, char * comparand, char * token1)
-{
-    if (strcmp(token0, comparand))
-    {
-        return 0;
-    }
-    parsetest_int(token1, 'i');
-    int test = atoi(token1) > 256 || atoi(token1) < 1;
-    err_line(test, "Value must be >= 1 and <= 256.");
-    world.map.length = atoi(token1);
-    return 1;
-}
-
-
-
-static uint8_t set_members(char * token0, char * token1, uint8_t * thing_flags,
-                           uint8_t * action_flags,
-                           struct ThingType * tt, struct ThingAction * ta)
-{
-    if (   *action_flags & EDIT_STARTED
-        && parse_flagval(token0, token1, "NAME", action_flags,
-                         NAME_SET, 's', (char *) &ta->name))
-    {
-        if (!(   try_func_name(ta, s[S_CMD_MOVE], actor_move)
-              || try_func_name(ta, s[S_CMD_PICKUP], actor_pick)
-              || try_func_name(ta, s[S_CMD_DROP], actor_drop)
-              || try_func_name(ta, s[S_CMD_USE], actor_use)))
-        {
-            ta->func = actor_wait;
-        }
-        *action_flags = *action_flags | NAME_SET;
-        return 1;
-    }
-    else if (   parse_flagval(token0, token1, "NAME", thing_flags,
-                              NAME_SET, 's', (char *) &tt->name)
-             || parse_flagval(token0, token1, "SYMBOL", thing_flags,
-                              SYMBOL_SET, 'c', (char *) &tt->char_on_map)
-             || parse_flagval(token0, token1, "EFFORT", action_flags,
-                              EFFORT_SET, '8', (char *) &ta->effort)
-             || parse_flagval(token0, token1, "START_NUMBER", thing_flags,
-                              START_N_SET, '8', (char *) &tt->start_n)
-             || parse_flagval(token0, token1, "LIFEPOINTS", thing_flags,
-                              LIFEPOINTS_SET, '8', (char *) &tt->lifepoints)
-             || parse_flagval(token0, token1, "CONSUMABLE", thing_flags,
-                              CONSUMABLE_SET, '8', (char *) &tt->consumable)
-             || parse_flagval(token0, token1, "CORPSE_ID", thing_flags,
-                              CORPSE_ID_SET, '8', (char *) &tt->corpse_id))
-    {
-        return 1;
-    }
-    return 0;
-}
-
-
-
-static uint8_t try_func_name(struct ThingAction * ta, char * name,
-                             void (* func) (struct Thing *))
-{
-    if (0 == strcmp(ta->name, name))
-    {
-        ta->func = func;
-        return 1;
-    }
-    return 0;
-}
-
-
-
-extern void read_config_file()
-{
-    parse_file(s[S_PATH_CONFIG], tokens_into_entries);
-    exit_err(!world.map.length, "Map size not defined in config file.");
-    uint8_t player_type_is_valid = 0;
-    struct ThingType * tt;
-    for (tt = world.thing_types; NULL != tt; tt = tt->next)
-    {
-        if (world.player_type == tt->id)
-        {
-            player_type_is_valid = 1;
-            break;
-        }
-    }
-    exit_err(!player_type_is_valid, "No valid thing type set for player.");
-    set_cleanup_flag(CLEANUP_THING_ACTIONS | CLEANUP_THING_TYPES);
-    test_corpse_ids();
-}
diff --git a/src/server/configfile.h b/src/server/configfile.h
deleted file mode 100644 (file)
index d80a2ba..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-/* src/server/configfile.h
- *
- * Reading in the config file of thing types and thing actions.
- */
-
-#ifndef CONFIGFILE_H
-#define CONFIGFILE_H
-
-
-
-/* Parse thing type / action definitons file nto thing type and thing action
- * definitions at world.thing_types and world.thing_actions.
- */
-extern void read_config_file();
-
-
-
-#endif
diff --git a/src/server/god_commands.c b/src/server/god_commands.c
new file mode 100644 (file)
index 0000000..efb607d
--- /dev/null
@@ -0,0 +1,426 @@
+/* src/server/god_commands.c */
+
+#include "god_commands.h"
+#include <stddef.h> /* NULL */
+#include <stdint.h> /* uint8_t */
+#include <stdlib.h> /* atoi(), free() */
+#include <string.h> /* strcmp() */
+#include <unistd.h> /* F_OK, access(), unlink() */
+#include "../common/parse_file.h" /* err_line(), parse_val(), parsetest_int() */
+#include "../common/rexit.h" /* exit_trouble() */
+#include "cleanup.h" /* unset_cleanup_flag() */
+#include "field_of_view.h" /* build_fov_map() */
+#include "hardcoded_strings.h" /* s */
+#include "init.h" /* remake_world() */
+#include "map.h" /* remake_map() */
+#include "thing_actions.h" /* ThingAction, actor_wait(), actor_move(),
+                            * actor_use(), actor_pickup(), actor_drop()
+                            */
+#include "things.h" /* Thing, ThingType, add_thing(), get_thing(), own_thing(),
+                     * free_things()
+                     */
+#include "world.h" /* world */
+
+
+
+/* Parse/apply god command in "tok0"/tok1" to manipulate a ThingType*/
+static uint8_t parse_thingtype_manipulation(char * tok0, char * tok1);
+
+/* If "name" fits "ta"->name, set "ta"->func to "func". (Derives ThingAction
+ * .func from .name for set_members().
+ */
+static uint8_t try_func_name(struct ThingAction * ta, char * name,
+                             void (* func) (struct Thing *));
+
+/* Parse/apply god command in "tok0"/"tok1" to manipulate a ThingAction. */
+static uint8_t parse_thingaction_manipulation(char * tok0, char * tok1);
+
+/* Parse/apply god command in "tok0"/"tok1" oo setting "t"'s thing type. */
+static uint8_t parse_thing_type(char * tok0, char * tok1, struct Thing * t);
+
+/* Parse/apply god command in "tok0"/"tok1" on setting up thing "t". */
+static uint8_t parse_thing_command(char * tok0, char * tok1, struct Thing * t);
+
+/* Parse/apply god command in "tok0"/"tok1" on positioning a thing "t". */
+static uint8_t parse_position(char* tok0, char * tok1, struct Thing * t);
+
+/* Parse/apply god command in "tok0"/"tok1" on "t" owning another thing. */
+static uint8_t parse_carry(char * tok0, char * tok1, struct Thing * t);
+
+/* Parse/apply god command in "tok0"/"tok1" to manipulate a Thing. */
+static uint8_t parse_thing_manipulation(char * tok0, char * tok1);
+
+/* Performs parse_world_active()'s world activation legality tests. */
+static uint8_t world_may_be_set_active();
+
+/* Parse/apply god command in "tok0"/"tok1" on toggling world.exists. Unset if
+ * argument is 0 and unlink worldstate file, but only set it on positive
+ * argument if it is not already set and a thing action of name S_CMD_WAIT, a
+ * player thing and a map are defined. On setting it, rebuild all FOVs.
+ */
+static uint8_t parse_world_active(char * tok0, char * tok1);
+
+/* Parse/apply god command in "tok0"/"tok1" to reset world.map.length. On
+ * re-set, set world.exists to 0, remove all things and free world.map.cells
+ */
+static uint8_t set_map_length(char * tok0, char * tok1);
+
+
+
+static uint8_t parse_thingtype_manipulation(char * tok0, char * tok1)
+{
+    static struct ThingType * tt = NULL;
+    if (!tt &&
+        (   !strcmp(tok0, s[S_CMD_TT_CONSUM]) || !strcmp(tok0, s[S_CMD_TT_SYMB])
+         || !strcmp(tok0, s[S_CMD_TT_STARTN]) || !strcmp(tok0, s[S_CMD_TT_NAME])
+         || !strcmp(tok0, s[S_CMD_TT_CORPS]) || !strcmp(tok0, s[S_CMD_TT_HP])))
+    {
+        err_line(1, "No thing type defined to manipulate yet.");
+        return 1;
+    }
+    uint8_t id;
+    if (   parse_val(tok0,tok1,s[S_CMD_TT_CONSUM],'8',(char *) &tt->consumable)
+        || parse_val(tok0,tok1,s[S_CMD_TT_HP],'8',(char *) &tt->lifepoints)
+        || parse_val(tok0,tok1,s[S_CMD_TT_STARTN],'8',(char *) &tt->start_n)
+        || parse_val(tok0,tok1,s[S_CMD_TT_SYMB],'c',(char *) &tt->char_on_map)
+        || parse_val(tok0,tok1,s[S_CMD_TT_NAME],'s',(char *) &tt->name));
+    else if (parse_val(tok0, tok1, s[S_CMD_TT_CORPS],'8',(char *)&id))
+    {
+        if (!get_thing_type(id))
+        {
+            err_line(1, "Corpse ID belongs to no known thing type.");
+            return 1;
+        }
+        tt->corpse_id = id;
+    }
+    else if (parse_val(tok0, tok1, s[S_CMD_THINGTYPE], '8', (char *) &id))
+    {
+        tt = get_thing_type(id);
+        if (!tt)
+        {
+            tt = add_thing_type(id);
+        }
+    }
+    else
+    {
+        return 0;
+    }
+    return 1;
+}
+
+
+
+static uint8_t try_func_name(struct ThingAction * ta, char * name,
+                             void (* func) (struct Thing *))
+{
+    if (0 == strcmp(ta->name, name))
+    {
+        ta->func = func;
+        return 1;
+    }
+    return 0;
+}
+
+
+
+static uint8_t parse_thingaction_manipulation(char * tok0, char * tok1)
+{
+    static struct ThingAction * ta = NULL;
+    if (!ta &&
+        (!strcmp(tok0, s[S_CMD_TA_EFFORT]) || !strcmp(tok0, s[S_CMD_TA_NAME])))
+    {
+        err_line(1, "No thing action defined to manipulate yet.");
+        return 1;
+    }
+    uint8_t id;
+    if      (parse_val(tok0, tok1, s[S_CMD_TA_EFFORT],'8',(char *) &ta->effort));
+    else if (parse_val(tok0, tok1, s[S_CMD_TA_NAME], 's', (char *) &ta->name))
+    {
+        if (!(   try_func_name(ta, s[S_CMD_MOVE], actor_move)
+              || try_func_name(ta, s[S_CMD_PICKUP], actor_pick)
+              || try_func_name(ta, s[S_CMD_WAIT], actor_wait)
+              || try_func_name(ta, s[S_CMD_DROP], actor_drop)
+              || try_func_name(ta, s[S_CMD_USE], actor_use)))
+        {
+            err_line(1, "Invalid action function name.");
+            return 1;
+        }         /* Legal worlds have at least one thing action for waiting. */
+        if (world.exists)
+        {
+            world.exists = 0 != get_thing_action_id_by_name(s[S_CMD_WAIT]);
+        }
+    }
+    else if (parse_val(tok0, tok1, s[S_CMD_THINGACTION], '8', (char *) &id))
+    {
+        ta = get_thing_action(id);
+        if (!ta)
+        {
+            ta = add_thing_action(id);
+        }
+    }
+    else
+    {
+        return 0;
+    }
+    return 1;
+}
+
+
+
+static uint8_t parse_thing_type(char * tok0, char * tok1, struct Thing * t)
+{
+    uint8_t type;
+    if (parse_val(tok0, tok1, s[S_CMD_T_TYPE], '8', (char *) &type))
+    {
+        struct ThingType * tt = get_thing_type(type);
+        if (!err_line(!tt, "Thing type does not exist."))
+        {
+            t->type = type;
+        }
+        return 1;
+    }
+    return 0;
+}
+
+
+
+static uint8_t parse_thing_command(char * tok0, char * tok1, struct Thing * t)
+{
+    uint8_t command;
+    if (parse_val(tok0, tok1, s[S_CMD_T_COMMAND], '8', (char *) &command))
+    {
+        if (!command)
+        {
+            t->command = command;
+            return 1;
+        }
+        struct ThingAction * ta = world.thing_actions;
+        for (; ta && command != ta->id; ta = ta->next);
+        if (!err_line(!ta, "Thing action does not exist."))
+        {
+            t->command = command;
+        }
+        return 1;
+    }
+    return 0;
+}
+
+
+
+static uint8_t parse_position(char* tok0, char * tok1, struct Thing * t)
+{
+    char axis = 0;
+    if      (!strcmp(tok0, s[S_CMD_T_POSY]))
+    {
+        axis = 'y';
+    }
+    else if (!strcmp(tok0, s[S_CMD_T_POSX]))
+    {
+        axis = 'x';
+    }
+    if (axis && !parsetest_int(tok1, '8'))
+    {
+        uint8_t length = atoi(tok1);
+        char * err = "Position is outside of map.";
+        if (!err_line(length >= world.map.length, err))
+        {
+            if      ('y' == axis)
+            {
+                t->pos.y = length;
+            }
+            else if ('x' == axis)
+            {
+                t->pos.x = length;
+            }
+            free(t->fov_map);
+            if (world.exists && t->lifepoints)
+            {
+                t->fov_map = build_fov_map(t);
+            }
+        }
+        return 1;
+    }
+    return 0;
+}
+
+
+
+static uint8_t parse_carry(char * tok0, char * tok1, struct Thing * t)
+{
+    uint8_t id;
+    if (parse_val(tok0, tok1, s[S_CMD_T_CARRIES], '8', (char *) &id))
+    {
+        if (!err_line(id == t->id, "Thing cannot carry itself."))
+        {
+            struct Thing * o = get_thing(world.things, id, 0);
+            if (!err_line(!o, "Thing not available for carrying."))
+            {
+                own_thing(&(t->owns), &world.things, id);
+                o->pos = t->pos;
+            }
+        }
+        return 1;
+    }
+    return 0;
+}
+
+
+
+static uint8_t parse_thing_manipulation(char * tok0, char * tok1)
+{
+    static struct Thing * t = NULL;
+    if (!t &&
+        (   !strcmp(tok0, s[S_CMD_T_PROGRESS]) || !strcmp(tok0, s[S_CMD_T_TYPE])
+         || !strcmp(tok0, s[S_CMD_T_CARRIES]) || !strcmp(tok0, s[S_CMD_T_POSY])
+         || !strcmp(tok0, s[S_CMD_T_POSY]) || !strcmp(tok0, s[S_CMD_T_ARGUMENT])
+         || !strcmp(tok0, s[S_CMD_T_HP]) || !strcmp(tok0, s[S_CMD_T_COMMAND])))
+    {
+        err_line(1, "No thing defined to manipulate yet.");
+        return 1;
+    }
+    uint8_t id;
+    if (    parse_thing_type(tok0, tok1, t)
+        || parse_thing_command(tok0, tok1, t)
+        || parse_val(tok0,tok1, s[S_CMD_T_ARGUMENT], '8', (char *)&t->arg)
+        || parse_val(tok0,tok1, s[S_CMD_T_PROGRESS], '8', (char *)&t->progress)
+        || parse_val(tok0,tok1, s[S_CMD_T_HP], '8', (char *) &t->lifepoints)
+        || parse_position(tok0, tok1, t)
+        || parse_carry(tok0, tok1, t));
+    else if (parse_val(tok0, tok1, s[S_CMD_THING], 'i', (char *) &id))
+    {
+        t = get_thing(world.things, id, 1);
+        char * err = "No thing type found to initialize new thing.";
+        if (!t && !err_line(NULL == world.thing_types, err))
+        {
+            t = add_thing(id, world.thing_types->id, 0, 0);
+            if (world.exists && t->lifepoints)
+            {
+                t->fov_map = build_fov_map(t);
+            }
+        }
+    }
+    else
+    {
+        return 0;
+    }
+    return 1;
+}
+
+
+
+static uint8_t world_may_be_set_active()
+{
+    if (!get_thing_action_id_by_name(s[S_CMD_WAIT]))
+    {
+        err_line(1, "No thing action of name 'wait' found.");
+        return 0;
+    }
+    if (!get_player())
+    {
+        err_line(1, "No un-owned player thing (of id=0) found.");
+        return 0;
+    }
+    if (!world.map.cells)
+    {
+        err_line(1, "No map found.");
+        return 0;
+    }
+    return 1;
+}
+
+
+
+static uint8_t parse_world_active(char * tok0, char * tok1)
+{
+    char * f_name = "parse_world_active()";
+    if (!strcmp(tok0, s[S_CMD_WORLD_ACTIVE]) && !parsetest_int(tok1, '8'))
+    {
+        if (!parsetest_int(tok1, '8'))
+        {
+            uint8_t argument = atoi(tok1);
+            if (!argument)
+            {
+                if (!access(s[S_PATH_WORLDSTATE], F_OK))
+                {
+                    int test = unlink(s[S_PATH_WORLDSTATE]);
+                    exit_trouble(-1 == test, f_name, "unlink()");
+                }
+                world.exists = 0;
+            }
+            else if (world.exists)
+            {
+                err_line(1, "World already active.");
+            }
+            else if (world_may_be_set_active())
+            {
+                struct Thing * ti;
+                for (ti = world.things; ti; ti = ti->next)
+                {
+                    if (ti->lifepoints)
+                    {
+                        if (ti->fov_map)
+                        {
+                            free(ti->fov_map);
+                        }
+                        ti->fov_map = build_fov_map(ti);
+                    }
+                }
+                world.exists = 1;
+            }
+            return 1;
+        }
+    }
+    return 0;
+}
+
+
+
+static uint8_t set_map_length(char * tok0, char * tok1)
+{
+    if (!strcmp(tok0, s[S_CMD_MAPLENGTH]) && !parsetest_int(tok1, 'u'))
+    {
+        uint16_t argument = atoi(tok1);
+        if (argument < 1 || argument > 256)
+        {
+            err_line(1, "Value must be >= 1 and <= 256.");
+            return 1;
+        }
+        world.exists = 0;
+        free_things(world.things);
+        free(world.map.cells);
+        world.map.cells = NULL;    /* Since remake_map() runs free() on this. */
+        world.map.length = argument;
+        return 1;
+    }
+    return 0;
+}
+
+
+
+extern uint8_t parse_god_command_1arg(char * tok0, char * tok1)
+{
+    if (   parse_thingtype_manipulation(tok0, tok1)
+        || parse_thingaction_manipulation(tok0, tok1)
+        || parse_thing_manipulation(tok0, tok1)
+        || set_map_length(tok0,tok1)
+        || parse_val(tok0,tok1,s[S_CMD_SEED_RAND],'U', (char *)&world.seed)
+        || parse_val(tok0,tok1,s[S_CMD_TURN],'u',(char *)&world.turn)
+        || parse_val(tok0,tok1,s[S_CMD_PLAYTYPE],'8',(char *)&world.player_type)
+        || parse_world_active(tok0, tok1));
+    else if (parse_val(tok0,tok1,s[S_CMD_SEED_MAP],'U',(char *)&world.seed_map))
+
+    {
+        remake_map();
+    }
+    else if (parse_val(tok0, tok1, s[S_CMD_MAKE_WORLD],'U',(char *)&world.seed))
+    {
+        uint8_t test = remake_world();
+        err_line(1 == test, "No player type with start number of >0 defined.");
+        err_line(2 == test, "No thing action with name 'wait' defined.");
+    }
+    else
+    {
+        return 0;
+    }
+    return 1;
+}
diff --git a/src/server/god_commands.h b/src/server/god_commands.h
new file mode 100644 (file)
index 0000000..87af27e
--- /dev/null
@@ -0,0 +1,19 @@
+/* src/server/god_commands.h
+ *
+ * God commands and their interpretation by the server.
+ */
+
+
+
+#ifndef GOD_COMMANDS_H
+#define GOD_COMMANDS_H
+
+#include <stdint.h> /* uint8_t */
+
+
+/* Parse/apply god command "tok0" with argument "tok1". */
+extern uint8_t parse_god_command_1arg(char * tok1, char * tok2);
+
+
+
+#endif
index e26264a89b8f6aff2bc41ab9149f17caf7b369ec..4094478af8aea017f6204e326effb317cef05377 100644 (file)
@@ -4,7 +4,7 @@
 
 
 
-char * s[26];
+char * s[38];
 
 
 
@@ -17,23 +17,35 @@ extern void init_strings()
     s[S_PATH_RECORD] = "record";
     s[S_PATH_SAVE] = "savefile";
     s[S_CMD_MAKE_WORLD] = "MAKE_WORLD";
-    s[S_CMD_DO_FOV] = "BUILD_FOVS";
+    s[S_CMD_WORLD_ACTIVE] = "WORLD_ACTIVE";
     s[S_CMD_SEED_MAP] = "SEED_MAP";
     s[S_CMD_SEED_RAND] = "SEED_RANDOMNESS";
     s[S_CMD_TURN] = "TURN";
     s[S_CMD_THING] = "THING";
-    s[S_CMD_TYPE] = "TYPE";
-    s[S_CMD_POS_Y] = "POS_Y";
-    s[S_CMD_POS_X] = "POS_X";
-    s[S_CMD_COMMAND] =  "COMMAND";
-    s[S_CMD_ARGUMENT] = "ARGUMENT";
-    s[S_CMD_PROGRESS] = "PROGRESS";
-    s[S_CMD_LIFEPOINTS] = "LIFEPOINTS";
-    s[S_CMD_CARRIES] = "CARRIES";
+    s[S_CMD_T_TYPE] = "T_TYPE";
+    s[S_CMD_T_POSY] = "T_POSY";
+    s[S_CMD_T_POSX] = "T_POSX";
+    s[S_CMD_T_COMMAND] =  "T_COMMAND";
+    s[S_CMD_T_ARGUMENT] = "T_ARGUMENT";
+    s[S_CMD_T_PROGRESS] = "T_PROGRESS";
+    s[S_CMD_T_HP] = "T_LIFEPOINTS";
+    s[S_CMD_T_CARRIES] = "T_CARRIES";
     s[S_CMD_WAIT] = "wait";
     s[S_CMD_MOVE] = "move";
     s[S_CMD_PICKUP] = "pick_up";
     s[S_CMD_DROP] = "drop";
     s[S_CMD_USE] = "use";
     s[S_FCN_SPRINTF] = "sprintf()";
+    s[S_CMD_THINGTYPE] = "THING_TYPE";
+    s[S_CMD_TT_CONSUM] = "TT_CONSUMABLE";
+    s[S_CMD_TT_STARTN] = "TT_START_NUMBER";
+    s[S_CMD_TT_HP] = "TT_LIFEPOINTS";
+    s[S_CMD_TT_SYMB] = "TT_SYMBOL";
+    s[S_CMD_TT_NAME] = "TT_NAME";
+    s[S_CMD_TT_CORPS] = "TT_CORPSE_ID";
+    s[S_CMD_THINGACTION] = "THING_ACTION";
+    s[S_CMD_TA_EFFORT] = "TA_EFFORT";
+    s[S_CMD_TA_NAME] = "TA_NAME";
+    s[S_CMD_MAPLENGTH] = "MAP_LENGTH";
+    s[S_CMD_PLAYTYPE] = "PLAYER_TYPE";
 }
index db4be5ac54389a779e0984e65255619230e02504..fd9ceb80853f1922a61cbaa08e16d3c1c8aca9b6 100644 (file)
@@ -17,30 +17,42 @@ enum string_num
     S_PATH_RECORD,
     S_PATH_SAVE,
     S_CMD_MAKE_WORLD,
-    S_CMD_DO_FOV,
+    S_CMD_WORLD_ACTIVE,
     S_CMD_SEED_MAP,
     S_CMD_SEED_RAND,
     S_CMD_TURN,
     S_CMD_THING,
-    S_CMD_TYPE,
-    S_CMD_POS_Y,
-    S_CMD_POS_X,
-    S_CMD_COMMAND,
-    S_CMD_ARGUMENT,
-    S_CMD_PROGRESS,
-    S_CMD_LIFEPOINTS,
-    S_CMD_CARRIES,
+    S_CMD_T_TYPE,
+    S_CMD_T_POSY,
+    S_CMD_T_POSX,
+    S_CMD_T_COMMAND,
+    S_CMD_T_ARGUMENT,
+    S_CMD_T_PROGRESS,
+    S_CMD_T_HP,
+    S_CMD_T_CARRIES,
     S_CMD_WAIT,
     S_CMD_MOVE,
     S_CMD_PICKUP,
     S_CMD_DROP,
     S_CMD_USE,
-    S_FCN_SPRINTF
+    S_FCN_SPRINTF,
+    S_CMD_THINGTYPE,
+    S_CMD_TT_CONSUM,
+    S_CMD_TT_STARTN,
+    S_CMD_TT_HP,
+    S_CMD_TT_SYMB,
+    S_CMD_TT_NAME,
+    S_CMD_TT_CORPS,
+    S_CMD_THINGACTION,
+    S_CMD_TA_EFFORT,
+    S_CMD_TA_NAME,
+    S_CMD_MAPLENGTH,
+    S_CMD_PLAYTYPE
 };
 
 extern void init_strings();
 
-extern char * s[26];
+extern char * s[38];
 
 
 
index dd6ee15408a70a83b37a76b338e76878d475888c..16ab4dfb42ffe2728803a40a8750233c5e2f4b15 100644 (file)
@@ -11,7 +11,8 @@
 #include <sys/stat.h> /* mkdir() */
 #include <sys/types.h> /* defines pid_t, time_t */
 #include <time.h> /* time() */
-#include <unistd.h> /* optarg, getopt(), access(), unlink(), getpid() */
+#include <unistd.h> /* optarg, getopt(), access(), getpid() */
+#include "../common/parse_file.h" /* err_line_zero(), err_line_inc() */
 #include "../common/readwrite.h" /* try_fopen(), try_fclose(), textfile_width(),
                                   * try_fgets(), try_fwrite(),
                                   * detect_atomic_leftover()
@@ -23,7 +24,7 @@
 #include "hardcoded_strings.h" /* s */
 #include "map.h" /* remake_map() */
 #include "things.h" /* Thing, ThingType, free_things(), add_things(),
-                     * get_player()
+                     * get_thing_id_action_id_by_name()
                      */
 #include "run.h" /* obey_msg(), io_loop() */
 #include "world.h" /* global world */
 
 
 
+/* Pass to obey_msg() lines from file at "path", on "record" write to same. Do
+ * not pass lines that consist only of a newline character. Transform newline
+ * in the line passed to \0.
+ */
+static void obey_lines_from_file(char * path, uint8_t record);
+
 /* Replay game from record file up to the turn named in world.replay, then turn
  * over to manual replay via io_loop().
  */
 static void replay_game();
 
+/* Return 1 if the type defined by world.player_type has a .start_n of 0.
+ * Return 2 if no thing action with .name of s[S_CMD_WAIT] is defined.
+ * Else, return 0.
+ */
+static uint8_t world_cannot_be_made();
+
+
+static void obey_lines_from_file(char * path, uint8_t record)
+{
+    char * f_name = "obey_lines_from_file()";
+    FILE * file = try_fopen(path, "r", f_name);
+    uint32_t linemax = textfile_width(file);
+    char * line = try_malloc(linemax + 1, f_name);
+    while (NULL != try_fgets(line, linemax + 1, file, f_name))
+    {
+        if (strlen(line))
+        {
+            if (strcmp("\n", line))
+            {
+                char * nl = strchr(line, '\n');
+                if (nl)
+                {
+                    *nl = '\0';
+                }
+                obey_msg(line, record, 1);
+            }
+            err_line_inc();
+        }
+    }
+    free(line);
+    try_fclose(file, f_name);
+}
+
 
 
 static void replay_game()
@@ -48,7 +88,8 @@ static void replay_game()
     while (   world.turn < world.replay
            && NULL != try_fgets(line, linemax + 1, file, f_name))
     {
-        obey_msg(line, 0);
+        obey_msg(line, 0, 1);
+        err_line_inc();
     }
     uint8_t end = 0;
     while (!io_loop())
@@ -58,7 +99,8 @@ static void replay_game()
             end = (NULL == try_fgets(line, linemax + 1, file, f_name));
             if (!end)
             {
-                obey_msg(line, 0);
+                obey_msg(line, 0, 1);
+                err_line_inc();
             }
         }
     }
@@ -68,6 +110,31 @@ static void replay_game()
 
 
 
+static uint8_t world_cannot_be_made()
+{
+    uint8_t player_will_be_generated = 0;
+    struct ThingType * tt;
+    for (tt = world.thing_types; NULL != tt; tt = tt->next)
+    {
+        if (world.player_type == tt->id)
+        {
+            player_will_be_generated = 0 < tt->start_n;
+            break;
+        }
+    }
+    if (!player_will_be_generated)
+    {
+        return 1;
+    }
+    if (!get_thing_action_id_by_name(s[S_CMD_WAIT]))
+    {
+        return 2;
+    }
+    return 0;
+}
+
+
+
 extern void obey_argv(int argc, char * argv[])
 {
     int opt;
@@ -120,14 +187,17 @@ extern void setup_server_io()
 
 
 
-extern void remake_world()
+extern uint8_t remake_world()
 {
-    char * f_name = "remake_world()";
+    uint8_t test = world_cannot_be_made();
+    if (test)
+    {
+        return test;
+    }
     free(world.log);
     world.log = NULL;      /* thing_actions.c's update_log() checks for this. */
     world.seed_map = world.seed;
     free_things(world.things);
-    world.do_update = 1;
     remake_map();
     struct ThingType * tt;
     for (tt = world.thing_types; NULL != tt; tt = tt->next)
@@ -145,17 +215,15 @@ extern void remake_world()
             add_things(tt->id, tt->start_n);
         }
     }
-    set_cleanup_flag(CLEANUP_THINGS);
     struct Thing * t;
     for (t = world.things; NULL != t; t = t->next)
     {
         t->fov_map = t->lifepoints ? build_fov_map(t) : NULL;
     }
-    if (!world.replay && !access(s[S_PATH_RECORD], F_OK))
-    {
-        exit_trouble(unlink(s[S_PATH_RECORD]), f_name, "unlink()");
-    }
     world.turn = 1;
+    world.do_update = 1;
+    world.exists = 1;
+    return 0;
 }
 
 
@@ -165,35 +233,29 @@ extern void run_game()
     char * f_name = "run_game()";
     detect_atomic_leftover(s[S_PATH_SAVE]);
     detect_atomic_leftover(s[S_PATH_RECORD]);
+    err_line_zero();
     if (world.replay)
     {
         replay_game();
         return;
     }
-    char * path_savefile = s[S_PATH_SAVE];
-    if (!access(path_savefile, F_OK))
+    if (!access(s[S_PATH_SAVE], F_OK))
     {
-        FILE * file = try_fopen(path_savefile, "r", f_name);
-        uint32_t linemax = textfile_width(file);
-        char * line = try_malloc(linemax + 1, f_name);
-        while (NULL != try_fgets(line, linemax + 1, file, f_name))
-        {
-            if (strlen(line) && strcmp("\n", line))
-            {
-                obey_msg(line, 0);
-            }
-        }
-        free(line);
-        try_fclose(file, f_name);
+        obey_lines_from_file(s[S_PATH_SAVE], 0);
     }
     else
     {
+        char * err = "No world config file from which to start a new world.";
+        exit_err(access(s[S_PATH_CONFIG], F_OK), err);
+        obey_lines_from_file(s[S_PATH_CONFIG], 1);
+        err_line_zero();
         char * command = s[S_CMD_MAKE_WORLD];
         char * msg = try_malloc(strlen(command) + 1 + 11 + 1, f_name);
         int test = sprintf(msg, "%s %d", command, (int) time(NULL));
         exit_trouble(test < 0, f_name, s[S_FCN_SPRINTF]);
-        obey_msg(msg, 1);
+        obey_msg(msg, 1, 1);
         free(msg);
     }
+    err_line_zero();
     io_loop();
 }
index cadacf3ad27cac50695e3bc159b3b1490ee57d75..e18b3bd46edf01ef4beaf63052728dca577eea86 100644 (file)
@@ -6,7 +6,7 @@
 #ifndef INIT_H
 #define INIT_H
 
-#include <stdint.h> /* uint32_t */
+#include <stdint.h> /* uint8_t */
 
 
 
@@ -17,22 +17,23 @@ extern void obey_argv(int argc, char * argv[]);
 extern void setup_server_io();
 
 /* Dissolves old game world if it exists, generates a new one from world.seed.
- * Unlinks any pre-existing record file.
- *
- * Thing (action) definitions read in from server config directory are not
- * affected. The map is populated accordingly. world.turn is set to 1, as is
- * world.do_update, so that io_round() is told to update the worldstate file.
+ * The map is populated according to world.thing_types start numbers. world.turn
+ * is set to 1, as is .exists and .do_update, so that io_round() is told to
+ * update the worldstate file. Returns 0 on success, and if the world cannot be
+ * generated 1 since there is no player type or it has .n_start of 0, 2 if no
+ * "wait" thing action is defined.
  */
-extern void remake_world();
+extern uint8_t remake_world();
 
 /* Create a game world state, then enter play or replay mode.
  *
  * If replay mode is called for, try for the record file and follow its commands
  + up to the turn specified by the user, then enter manual replay. Otherwise,
  * start into play mode after having either recreated a game world state from
- * the savefile, or, if none exists, having created a new world with the
- * MAKE_WORLD command. Manual replay as well as play mode take place inside
- * io_loop().
+ * the savefile, or, if none exists, having created a new world with first
+ * following the commands from the world config file, then running the
+ * MAKE_WORLD command. Manual replay as well as manual play mode take place
+ * inside io_loop().
  */
 extern void run_game();
 
index 00afb3cc28fa16d09cd053b38dd5bd4333bf37e0..317c088b1148bb0475e71b32b1599ef0d128f90b 100644 (file)
@@ -6,9 +6,9 @@
 #include <limits.h> /* PIPE_BUF */
 #include <stddef.h> /* size_t, NULL */
 #include <stdint.h> /* uint8_t, uint16_t, uint32_t */
-#include <stdio.h> /* defines EOF, FILE, sprintf() */
+#include <stdio.h> /* defines EOF, FILE, sprintf(), fprintf() */
 #include <stdlib.h> /* free() */
-#include <string.h> /* strlen(), memcpy(), memset() */
+#include <string.h> /* strlen(), memcpy(), memset(), strchr() */
 #include <sys/types.h> /* time_t */
 #include <time.h> /* time(), nanosleep() */
 #include "../common/readwrite.h" /* atomic_write_start(), atomic_write_finish(),
 #include "field_of_view.h" /* VISIBLE */
 #include "hardcoded_strings.h" /* s */
 #include "map.h" /* yx_to_map_pos() */
-#include "things.h" /* Thing, ThingType, get_thing_type(), get_player() */
+#include "things.h" /* Thing, ThingType, ThingAction, get_thing_type(),
+                     * get_player()
+                     */
 #include "world.h" /* global world  */
 
 
 
 /* Write to "file" god commands (one per line) to recreate thing "t". */
 static void write_key_value(FILE * file, char * key, uint32_t value);
+static void write_key_string(FILE * file, char * key, char * string);
 
 /* Write to "file" \n-delimited line of "key" + space + "value" as string. */
 static void write_thing(FILE * file, struct Thing * t);
@@ -80,6 +83,26 @@ static void write_key_value(FILE * file, char * key, uint32_t value)
 
 
 
+static void write_key_string(FILE * file, char * key, char * string)
+{
+    char * f_name = "write_key_string()";
+    try_fwrite(key, strlen(key), 1, file, f_name);
+    try_fputc(' ', file, f_name);
+    uint8_t contains_space = NULL != strchr(string, ' ');
+    if (contains_space)
+    {
+        try_fputc('\'', file, f_name);
+    }
+    try_fwrite(string, strlen(string), 1, file, f_name);
+    if (contains_space)
+    {
+        try_fputc('\'', file, f_name);
+    }
+    try_fputc('\n', file, f_name);
+}
+
+
+
 static void write_thing(FILE * file, struct Thing * t)
 {
     char * f_name = "write_thing()";
@@ -89,16 +112,16 @@ static void write_thing(FILE * file, struct Thing * t)
         write_thing(file, o);
     }
     write_key_value(file, s[S_CMD_THING], t->id);
-    write_key_value(file, s[S_CMD_TYPE], t->type);
-    write_key_value(file, s[S_CMD_POS_Y], t->pos.y);
-    write_key_value(file, s[S_CMD_POS_X], t->pos.x);
-    write_key_value(file, s[S_CMD_COMMAND], t->command);
-    write_key_value(file, s[S_CMD_ARGUMENT], t->arg);
-    write_key_value(file, s[S_CMD_PROGRESS], t->progress);
-    write_key_value(file, s[S_CMD_LIFEPOINTS], t->lifepoints);
+    write_key_value(file, s[S_CMD_T_TYPE], t->type);
+    write_key_value(file, s[S_CMD_T_POSY], t->pos.y);
+    write_key_value(file, s[S_CMD_T_POSX], t->pos.x);
+    write_key_value(file, s[S_CMD_T_COMMAND], t->command);
+    write_key_value(file, s[S_CMD_T_ARGUMENT], t->arg);
+    write_key_value(file, s[S_CMD_T_PROGRESS], t->progress);
+    write_key_value(file, s[S_CMD_T_HP], t->lifepoints);
     for (o = t->owns; o; o = o->next)
     {
-        write_key_value(file, s[S_CMD_CARRIES], o->id);
+        write_key_value(file, s[S_CMD_T_CARRIES], o->id);
     }
     try_fputc('\n', file, f_name);
 }
@@ -196,7 +219,7 @@ static void update_worldstate_file()
     }
     atomic_write_finish(file, s[S_PATH_WORLDSTATE], path_tmp);
     set_cleanup_flag(CLEANUP_WORLDSTATE);
-    char * dot = ".\n";;
+    char * dot = ".\n";
     try_fwrite(dot, strlen(dot), 1, world.file_out, f_name);
     fflush(world.file_out);
 }
@@ -329,7 +352,34 @@ extern void save_world()
     char * f_name = "save_world()";
     char * path_tmp;
     FILE * file = atomic_write_start(s[S_PATH_SAVE], &path_tmp);
-    write_key_value(file, s[S_CMD_DO_FOV], 0);
+    write_key_value(file, s[S_CMD_MAPLENGTH], world.map.length);
+    write_key_value(file, s[S_CMD_PLAYTYPE], world.player_type);
+    try_fputc('\n', file, f_name);
+    struct ThingAction * ta;
+    for (ta = world.thing_actions; ta; ta = ta->next)
+    {
+        write_key_value(file, s[S_CMD_THINGACTION], ta->id);
+        write_key_value(file, s[S_CMD_TA_EFFORT], ta->effort);
+        write_key_string(file, s[S_CMD_TA_NAME], ta->name);
+        try_fputc('\n', file, f_name);
+    }
+    struct ThingType * tt;
+    for (tt = world.thing_types; tt; tt = tt->next)
+    {
+        write_key_value(file, s[S_CMD_THINGTYPE], tt->id);
+        write_key_value(file, s[S_CMD_TT_STARTN], tt->start_n);
+        write_key_value(file, s[S_CMD_TT_HP], tt->lifepoints);
+        int test = fprintf(file, "%s %c\n", s[S_CMD_TT_SYMB], tt->char_on_map);
+        exit_trouble(test < 0, f_name, "fprintf()");
+        write_key_string(file, s[S_CMD_TT_NAME], tt->name);
+        write_key_value(file, s[S_CMD_TT_CONSUM], tt->consumable);
+        try_fputc('\n', file, f_name);
+    }
+    for (tt = world.thing_types; tt; tt = tt->next)
+    {
+        write_key_value(file, s[S_CMD_THINGTYPE], tt->id);
+        write_key_value(file, s[S_CMD_TT_CORPS], tt->corpse_id);
+    }
     try_fputc('\n', file, f_name);
     write_key_value(file, s[S_CMD_SEED_MAP], world.seed_map);
     write_key_value(file, s[S_CMD_SEED_RAND], world.seed);
@@ -340,6 +390,6 @@ extern void save_world()
     {
         write_thing(file, t);
     }
-    write_key_value(file, s[S_CMD_DO_FOV], 1);
+    write_key_value(file, s[S_CMD_WORLD_ACTIVE], 1);
     atomic_write_finish(file, s[S_PATH_SAVE], path_tmp);
 }
index 33e539102beded5802016eadea339ea40f2cc77e..c8ca499293999f32067b2c5a0afcc54dc34c8526 100644 (file)
@@ -4,7 +4,6 @@
 #include <stdlib.h> /* exit() */
 #include "../common/rexit.h" /* exit_err, set_cleanup_func() */
 #include "cleanup.h" /* set_cleanup_flag(), cleanup() */
-#include "configfile.h" /* read_config_file() */
 #include "hardcoded_strings.h" /* s */
 #include "init.h" /* run_game(), obey_argv(), obey_argv(), setup_server_io() */
 #include "world.h" /* struct World */
@@ -31,16 +30,14 @@ int main(int argc, char ** argv)
         if (world.replay)
         {
             test = printf("Replay mode. Auto-replaying up to turn %d.\n",
-                         world.replay);
+                          world.replay);
             exit_err(-1 == test, printf_err);
         }
     }
+    world.map.length = 64;                      /* Just a sane default value. */
 
-    /* Init config file and server i/o files. */
-    read_config_file();
+    /* Init server i/o, Enter play or replay mode loops, then leave properly. */
     setup_server_io();
-
-    /* Enter play or replay mode loops, then leave properly. */
     run_game();
     cleanup();
     exit(EXIT_SUCCESS);
index 394081c74d7190f3a3b3c4546384a8f92e231cb8..8251d06118e7ddb071bfd21841c7fab9c1c68379 100644 (file)
@@ -5,11 +5,11 @@
 #include <stddef.h> /* NULL */
 #include <stdint.h> /* uint8_t, uint16_t, uint32_t */
 #include <stdio.h> /* FILE, printf(), fflush() */
-#include <stdlib.h> /* free(), atoi() */
-#include <string.h> /* strlen(), strcmp() strncmp(), strdup() */
+#include <stdlib.h> /* free() */
+#include <string.h> /* strlen(), strcmp(), strncmp(), strdup() */
 #include <unistd.h> /* access() */
 #include "../common/parse_file.h" /* set_err_line_options(), token_from_line(),
-                                   * err_line()
+                                   * err_line(), err_line_inc(), parse_val()
                                    */
 #include "../common/readwrite.h" /* try_fopen(), try_fcose(), try_fwrite(),
                                   * try_fgets(), textfile_width(), try_fputc()
 #include "../common/rexit.h" /* exit_trouble(), exit_err() */
 #include "../common/try_malloc.h" /* try_malloc() */
 #include "ai.h" /* ai() */
-#include "cleanup.h" /* set_cleanup_flag(), unset_cleanup_flag() */
-#include "field_of_view.h" /* build_fov_map() */
+#include "cleanup.h" /* unset_cleanup_flag() */
+#include "god_commands.h" /* parse_god_command_1arg() */
 #include "hardcoded_strings.h" /* s */
-#include "init.h" /* remake_world() */
 #include "io.h" /* io_round(), save_world() */
-#include "map.h" /* remake_map() */
-#include "thing_actions.h" /* ThingAction */
-#include "things.h" /* Thing, get_thing(), own_thing(), add_thing(),
-                     * get_thing_action_id_by_name(), get_player()
-                     */
+#include "things.h" /* Thing, get_thing_action_id_by_name(), get_player() */
 #include "world.h" /* world */
 
 
 
-/* Parse/apply god command in "tok0"/"tok1" on "t" owning another thing. */
-static uint8_t parse_carry(char * tok0, char * tok1, struct Thing * t);
-
-/* Parse/apply god commansd in "tok0"/"tok1" on positioning a thing "t". */
-static uint8_t parse_position(char* tok0, char * tok1, struct Thing * t);
-
-/* Parse/apply god command in "tok0"/"tok1" oo setting "t"'s thing type. */
-static uint8_t parse_thing_type(char * tok0, char * tok1, struct Thing * t);
-
-/* Parse/apply god command in "tok0"/"tok1" on setting up thing "t". */
-static uint8_t parse_thing_command(char * tok0, char * tok1, struct Thing * t);
-
-/* Parse/apply god command on enabling/disabling generation of fields of view on
- * god commands that may affect them, via static global "do_fov". On enabling,
- * (re-)generate all animate things' fields of view.
- */
-static uint8_t parse_do_fov(char * tok0, char * tok1);
+/* If "string" and "comparand" match in string, set "c_to_set" to value."  */
+static uint8_t set_char_by_string_comparison(char * string, char * comparand,
+                                             char * c_to_set, char value);
 
-/* Parse/apply god command in "tok0"/"tok1" manipulating a thing's state. */
-static uint8_t parse_thing_manipulation(char * tok0, char * tok1);
+/* Return 1 on world.exists, else 0 and err_line() appropriate error message. */
+static uint8_t player_commands_allowed();
 
 /* Parse player command "tok0" with no argument to player action, comment on
  * invalidity of non-zero "tok1" (but do not abort in that case).
  */
 static uint8_t parse_player_command_0arg(char * tok0, char * tok1);
 
-/* If "string" and "comparand" match in string, set "c_to_set" to value."  */
-static uint8_t set_char_by_string_comparison(char * string, char * comparand,
-                                             char * c_to_set, char value);
-
 /* Parse player command "tok0" with one argument "tok1" to player action. */
 static uint8_t parse_player_command_1arg(char * tok0, char * tok1);
 
-/* Parse/apply commadn "tok0" with argument "tok1" and test the line for further
- * tokens, commenting on their invalidity (but don't abort on findingthem).
+/* Parse/apply command "tok0" with argument "tok1" and test the line for further
+ * tokens, commenting on their invalidity (but don't abort on finding them).
  */
 static uint8_t parse_command_1arg(char * tok0, char * tok1);
 
@@ -84,120 +61,13 @@ static void turn_over();
 
 
 
-/* Do god commands to create / position things generate their fields of view? */
-static uint8_t do_fov = 0;
-
-
-
-static uint8_t parse_carry(char * tok0, char * tok1, struct Thing * t)
-{
-    uint8_t id;
-    if (parse_val(tok0, tok1, s[S_CMD_CARRIES], '8', (char *) &id))
-    {
-        if (!err_line(id == t->id, "Thing cannot carry itself."))
-        {
-            struct Thing * o = get_thing(world.things, id, 0);
-            if (!err_line(!o, "Thing cannot carry thing that does not exist."))
-            {
-                own_thing(&(t->owns), &world.things, id);
-                o->pos = t->pos;
-            }
-        }
-        return 1;
-    }
-    return 0;
-}
-
-
-
-static uint8_t parse_position(char* tok0, char * tok1, struct Thing * t)
-{
-    char axis = 0;
-    if      (!strcmp(tok0, s[S_CMD_POS_Y]))
-    {
-        axis = 'y';
-    }
-    else if (!strcmp(tok0, s[S_CMD_POS_X]))
-    {
-        axis = 'x';
-    }
-    if (axis && !parsetest_int(tok1, '8'))
-    {
-        uint8_t length = atoi(tok1);
-        char * err = "Position is outside of map.";
-        if (!err_line(length >= world.map.length, err))
-        {
-            if      ('y' == axis)
-            {
-                t->pos.y = length;
-            }
-            else if ('x' == axis)
-            {
-                t->pos.x = length;
-            }
-            free(t->fov_map);
-            t->fov_map= do_fov && t->lifepoints ? build_fov_map(t) : t->fov_map;
-        }
-        return 1;
-    }
-    return 0;
-}
-
-
-
-static uint8_t parse_thing_type(char * tok0, char * tok1, struct Thing * t)
-{
-    uint8_t type;
-    if (parse_val(tok0, tok1, s[S_CMD_TYPE], '8', (char *) &type))
-    {
-        struct ThingType * tt = world.thing_types;
-        for (; NULL != tt && type != tt->id; tt = tt->next);
-        if (!err_line(!tt, "Thing type does not exist."))
-        {
-            t->type = type;
-        }
-        return 1;
-    }
-    return 0;
-}
-
-
 
-static uint8_t parse_thing_command(char * tok0, char * tok1, struct Thing * t)
-{
-    uint8_t command;
-    if (parse_val(tok0, tok1, s[S_CMD_COMMAND], '8', (char *) &command))
-    {
-        if (!command)
-        {
-            t->command = command;
-            return 1;
-        }
-        struct ThingAction * ta = world.thing_actions;
-        for (; NULL != ta && command != ta->id; ta = ta->next);
-        if (!err_line(!ta, "Thing action does not exist."))
-        {
-            t->command = command;
-        }
-        return 1;
-    }
-    return 0;
-}
-
-
-
-static uint8_t parse_do_fov(char * tok0, char * tok1)
+static uint8_t set_char_by_string_comparison(char * string, char * comparand,
+                                             char * c_to_set, char value)
 {
-    if (parse_val(tok0, tok1, s[S_CMD_DO_FOV], '8', (char *) &do_fov))
+    if (!strcmp(string, comparand))
     {
-        if (do_fov)
-        {
-            struct Thing * ti;
-            for (ti = world.things; ti; ti = ti->next)
-            {
-                ti->fov_map = ti->lifepoints ? build_fov_map(ti) : ti->fov_map;
-            }
-        }
+        * c_to_set = value;
         return 1;
     }
     return 0;
@@ -205,30 +75,11 @@ static uint8_t parse_do_fov(char * tok0, char * tok1)
 
 
 
-static uint8_t parse_thing_manipulation(char * tok0, char * tok1)
+static uint8_t player_commands_allowed()
 {
-    uint8_t id;
-    static struct Thing * t = NULL;
-    if (t && (   parse_thing_type(tok0, tok1, t)
-              || parse_thing_command(tok0, tok1, t)
-              || parse_val(tok0, tok1, s[S_CMD_ARGUMENT], '8', (char *)&t->arg)
-              || parse_val(tok0,tok1,s[S_CMD_PROGRESS],'8',(char *)&t->progress)
-              || parse_val(tok0, tok1, s[S_CMD_LIFEPOINTS], '8',
-                                                        (char *) &t->lifepoints)
-              || parse_position(tok0, tok1, t)
-              || parse_carry(tok0, tok1, t)));
-    else if (parse_val(tok0, tok1, s[S_CMD_THING], '8', (char *) &id))
-    {
-        t = get_thing(world.things, id, 1);
-        if (!t)
-        {
-            t = add_thing(id, 0, 0);
-            set_cleanup_flag(CLEANUP_THINGS);
-            t->fov_map= do_fov && t->lifepoints ? build_fov_map(t) : t->fov_map;
-        }
-    }
-    else
+    if (!world.exists)
     {
+        err_line(1, "No world exists in which to run player commands.");
         return 0;
     }
     return 1;
@@ -241,23 +92,13 @@ static uint8_t parse_player_command_0arg(char * tok0, char * tok1)
     struct Thing * player = get_player();
     if (!strcmp(tok0, s[S_CMD_WAIT]) || !strcmp(tok0, s[S_CMD_PICKUP]))
     {
-        player->command = get_thing_action_id_by_name(tok0);
-        player->arg = 0;
-        turn_over();
-        err_line (NULL != tok1, "No arguments expected, ignoring arguments.");
-        return 1;
-    }
-    return 0;
-}
-
-
-
-static uint8_t set_char_by_string_comparison(char * string, char * comparand,
-                                             char * c_to_set, char value)
-{
-    if (!strcmp(string, comparand))
-    {
-        * c_to_set = value;
+        if (player_commands_allowed())
+        {
+            player->command = get_thing_action_id_by_name(tok0);
+            player->arg = 0;
+            turn_over();
+            err_line (NULL != tok1, "No arguments expected, ignoring them.");
+        }
         return 1;
     }
     return 0;
@@ -268,14 +109,14 @@ static uint8_t set_char_by_string_comparison(char * string, char * comparand,
 static uint8_t parse_player_command_1arg(char * tok0, char * tok1)
 {
     struct Thing * player = get_player();
-    if (
-           parse_val(tok0, tok1, s[S_CMD_DROP], '8', (char *) &player->arg)
-        || parse_val(tok0, tok1, s[S_CMD_USE], '8', (char *) &player->arg))
+    if (   (   parse_val(tok0, tok1, s[S_CMD_DROP], '8', (char *) &player->arg)
+            || parse_val(tok0, tok1, s[S_CMD_USE], '8', (char *) &player->arg))
+        && player_commands_allowed())
     {
         player->command = get_thing_action_id_by_name(tok0);
         turn_over();
     }
-    else if (!strcmp(tok0, s[S_CMD_MOVE]))
+    else if (!strcmp(tok0, s[S_CMD_MOVE]) && player_commands_allowed())
     {
         char dir = '\0';
         if (!(   set_char_by_string_comparison(tok1, "east",       &dir, 'd')
@@ -303,20 +144,8 @@ static uint8_t parse_player_command_1arg(char * tok0, char * tok1)
 static uint8_t parse_command_1arg(char * tok0, char * tok1)
 {
     char * tok2 = token_from_line(NULL);
-    if (   parse_thing_manipulation(tok0, tok1)
-        || parse_player_command_1arg(tok0, tok1)
-        || parse_val(tok0, tok1, s[S_CMD_SEED_RAND], 'U', (char *) &world.seed)
-        || parse_val(tok0, tok1, s[S_CMD_TURN], 'u', (char *) &world.turn)
-        || parse_do_fov(tok0, tok1));
-    else if (parse_val(tok0,tok1,s[S_CMD_SEED_MAP],'U',(char *)&world.seed_map))
-
-    {
-        remake_map();
-    }
-    else if (parse_val(tok0, tok1, s[S_CMD_MAKE_WORLD],'U',(char *)&world.seed))
-    {
-        remake_world();
-    }
+    if (   parse_player_command_1arg(tok0, tok1)
+        || parse_god_command_1arg(tok0, tok1));
     else
     {
         return 0;
@@ -373,11 +202,8 @@ static void turn_over()
                 ai(thing);
             }
             thing->progress++;
-            struct ThingAction * ta = world.thing_actions;
-            while (ta->id != thing->command)
-            {
-                ta = ta->next;
-            }
+
+            struct ThingAction * ta = get_thing_action(thing->command);
             if (thing->progress == ta->effort)
             {
                 ta->func(thing);
@@ -415,10 +241,20 @@ static void record_msg(char * msg)
 
 
 
-extern void obey_msg(char * msg, uint8_t do_record)
+extern void obey_msg(char * msg, uint8_t do_record, uint8_t do_verbose)
 {
-    set_err_line_options("Trouble with message: ", msg, 0, 0);
+    char * f_name = "obey_msg()";
+    if (world.is_verbose && do_verbose)
+    {
+        exit_trouble(-1 == printf("Input: %s\n", msg), f_name, "printf()");
+    }
+    set_err_line_options("Trouble with message: ", msg, 0);
     char * msg_copy = strdup(msg);
+    if (msg[0] == 'm')
+    {
+        int a = 5;
+        a = a;
+    }
     char * tok0 = token_from_line(msg_copy);
     if (NULL != tok0)
     {
@@ -426,7 +262,10 @@ extern void obey_msg(char * msg, uint8_t do_record)
         if (    parse_player_command_0arg(tok0, tok1)
             || (tok1 && parse_command_1arg(tok0, tok1)))
         {
-            world.do_update = 1;
+            if (world.exists)
+            {
+                world.do_update = 1;
+            }
             if (do_record)
             {
                 save_world();
@@ -436,7 +275,7 @@ extern void obey_msg(char * msg, uint8_t do_record)
             return;
         }
     }
-    err_line(1, "Unknown command or bad number of tokens.");
+    err_line(1, "Unknown command/argument or bad number of tokens.");
     free(msg_copy);
 }
 
@@ -475,7 +314,7 @@ extern uint8_t io_loop()
             free(msg);
             return 0;
         }
-        obey_msg(msg, 1);
+        obey_msg(msg, 1, 0);
         free(msg);
     }
 }
index 07ca9029f24655a0b66a87466dc1ac512da0f4c3..400f0799b38379af51d63b31e26edd1618a3debf 100644 (file)
 
 
 /* Try parsing "msg" into a command to apply, and apply it. Record commands to
- * the file at world.path_record if "do_record" is set.
+ * the file at world.path_record if "do_record" is set, and output them to
+ * stdout if "do_verbose" and world.is_verbose are set.
  */
-extern void obey_msg(char * msg, uint8_t do_record);
+extern void obey_msg(char * msg, uint8_t do_record, uint8_t do_verbose);
 
 /* Loop for receiving commands via io_round() and acting on them. Exits with 1
  * on "QUIT" command. In replay mode, exits with 0 on each non-"QUIT" command.
index b153ff868ef749fc92497e955a75cc849c725674..e91f576aa3ebfd5ed84fbb296c2ba100f0f4d574 100644 (file)
@@ -5,13 +5,13 @@
 #include <stdint.h> /* uint8_t, uint16_t */
 #include <stdio.h> /* sprintf() */
 #include <stdlib.h> /* free() */
-#include <string.h> /* strlen(), strcmp(), memcpy(), strncmp() */
-#include "../common/rexit.h" /* exit_err(), exit_trouble() */
+#include <string.h> /* strlen(), memcpy(), strncmp() */
+#include "../common/rexit.h" /* exit_trouble() */
 #include "../common/try_malloc.h" /* try_malloc() */
 #include "../common/yx_uint8.h" /* struct yx_uint8 */
 #include "field_of_view.h" /* build_fov_map() */
 #include "hardcoded_strings.h" /* s */
-#include "things.h" /* structs Thing, ThingType, get_player(), own_thing(),
+#include "things.h" /* Thing, ThingType, get_player(), own_thing(),
                      * set_thing_position(), get_thing_type()
                      */
 #include "map.h" /* is_passable() */
@@ -238,36 +238,6 @@ static void playerbonus_use(uint8_t no_thing, uint8_t wrong_thing)
 
 
 
-extern void free_thing_actions(struct ThingAction * ta)
-{
-    if (NULL == ta)
-    {
-        return;
-    }
-    free(ta->name);
-    free_thing_actions(ta->next);
-    free(ta);
-}
-
-
-
-extern uint8_t get_thing_action_id_by_name(char * name)
-{
-    struct ThingAction * ta = world.thing_actions;
-    while (NULL != ta)
-    {
-        if (0 == strcmp(ta->name, name))
-        {
-            break;
-        }
-        ta = ta->next;
-    }
-    exit_err(NULL == ta, "get_thing_action_id_by_name() did not find action.");
-    return ta->id;
-}
-
-
-
 extern void actor_wait(struct Thing * t)
 {
     if (t == get_player())
index 861f5c233ab351cbc26d1230d9ba1d3b649492c2..28857e773cd135a678ccb1da0cfabb90426de828 100644 (file)
@@ -8,28 +8,10 @@
 #ifndef THING_ACTIONS_H
 #define THING_ACTIONS_H
 
-#include <stdint.h> /* uint8_t */
 struct Thing;
 
 
 
-struct ThingAction
-{
-    uint8_t id; /* identifies action in Thing.command; therefore must be >0 */
-    struct ThingAction * next;
-    void (* func) (struct Thing *); /* function called after .effort turns */
-    char * name; /* human-readable identifier */
-    uint8_t effort; /* how many turns the action takes */
-};
-
-
-
-/* Free ThingAction * chain starting at "ta". */
-extern void free_thing_actions(struct ThingAction * ta);
-
-/* Return world.thing_actions ThingAction.id for "name". */
-extern uint8_t get_thing_action_id_by_name(char * name);
-
 /* Actor "t" does nothing. */
 extern void actor_wait(struct Thing * t);
 
index 9425f9cc3c315c5362733f93d13d9dbc984ce7a5..6df9b18efe5fe32ab5bd441ac6e2232032540fcf 100644 (file)
 /* src/server/things.c */
 
+#define _POSIX_C_SOURCE 200809L /* strdup() */
 #include "things.h"
-#include <stddef.h> /* NULL */
-#include <stdint.h> /* uint8_t, uint16_t, UINT8_MAX, UINT16_MAX */
+#include <stddef.h> /* NULL, size_t */
+#include <stdint.h> /* uint8_t, uint16_t, int16_t, UINT8_MAX, UINT16_MAX */
 #include <stdlib.h> /* free() */
-#include <string.h> /* memset(), strlen() */
-#include "../common/rexit.h" /* exit_err(), exit_trouble() */
+#include <string.h> /* memset(), strcmp(), strdup() */
+#include "../common/rexit.h" /* exit_err() */
 #include "../common/try_malloc.h" /* try_malloc() */
 #include "../common/yx_uint8.h" /* yx_uint8 */
+#include "cleanup.h" /* set_cleanup_flag() */
 #include "hardcoded_strings.h" /* s */
 #include "map.h" /* is_passable() */
 #include "rrand.h" /* rrand() */
-#include "world.h" /* global world */
+#include "thing_actions.h" /* actor_wait */
+#include "world.h" /* world */
 #include "yx_uint8.h" /* yx_uint8_cmp() */
 
 
 
+/* Used to treat structs Thing, ThingType and ThingAction the same. */
+struct NextAndId
+{
+    struct NextAndId * next;
+    uint8_t id;
+};
+
+
 
-/* Return lowest unused id for new thing. */
-static uint8_t get_lowest_unused_id();
+/* Return lowest unused id for new thing ("sel"==0), thing type ("sel"==1) or
+ * thing action ("sel"==2).
+ */
+static uint8_t get_unused_id(uint8_t sel);
 
+/* To linked list of NextAndId structs (or rather structs whose start region is
+ * compatible to it) starting at "start", add newly allocated element of
+ * "n_size" and an ID that is either "id" or, if "id" is <= UINT8_MAX and >=
+ * "id_start", get ID from get_unused_id("struct_id").
+ */
+static struct NextAndId * add_to_struct_list(size_t n_size, uint8_t start_id,
+                                             int16_t id, uint8_t struct_id,
+                                             struct NextAndId ** start);
 
 
-static uint8_t get_lowest_unused_id()
+
+static uint8_t get_unused_id(uint8_t sel)
 {
     uint8_t i = 0;
     while (1)
     {
-        if (!get_thing(world.things, i, 1))
+        if (   (0 == sel && !get_thing(world.things, i, 1))
+            || (1 == sel && !get_thing_type(i))
+            || (2 == sel && !get_thing_action(i)))
         {
             return i;
         }
-        exit_err(i == UINT8_MAX, "No unused ID available to add new thing.");
+        exit_err(i == UINT8_MAX, "No unused ID available to add to ID list.");
         i++;
     }
 }
 
 
 
-extern struct Thing * get_thing(struct Thing * ptr, uint8_t id, uint8_t deep)
+static struct NextAndId * add_to_struct_list(size_t n_size, uint8_t start_id,
+                                             int16_t id, uint8_t struct_id,
+                                             struct NextAndId ** start)
 {
-    while (1)
+    char * f_name = "add_to_struct_list()";
+    struct NextAndId * nai  = try_malloc(n_size, f_name);
+    memset(nai, 0, n_size);
+    nai->id = (start_id<=id && id<=UINT8_MAX) ? id : get_unused_id(struct_id);
+    struct NextAndId ** nai_ptr_ptr = start;
+    for (; NULL != * nai_ptr_ptr; nai_ptr_ptr = &(*nai_ptr_ptr)->next);
+    *nai_ptr_ptr = nai;
+    return nai;
+}
+
+
+
+extern struct ThingAction * add_thing_action(int16_t id)
+{
+    struct ThingAction * ta;
+    ta = (struct ThingAction *) add_to_struct_list(sizeof(struct ThingAction),
+                                                   1, id, 2,
+                                                   (struct NextAndId **)
+                                                   &world.thing_actions);
+    set_cleanup_flag(CLEANUP_THING_ACTIONS);
+    ta->name = strdup(s[S_CMD_WAIT]);
+    ta->effort = 1;
+    ta->func = actor_wait;
+    return ta;
+}
+
+
+
+extern struct ThingType * add_thing_type(int16_t id)
+{
+    struct ThingType * tt;
+    tt = (struct ThingType *) add_to_struct_list(sizeof(struct ThingType),
+                                                 0, id, 1,
+                                                 (struct NextAndId **)
+                                                 &world.thing_types);
+    set_cleanup_flag(CLEANUP_THING_TYPES);
+    tt->name = strdup("(none)");
+    return tt;
+}
+
+
+
+extern struct Thing * add_thing(int16_t id, uint8_t type, uint8_t y, uint8_t x)
+{
+    struct Thing * t;
+    t = (struct Thing *) add_to_struct_list(sizeof(struct Thing), 0, id, 0,
+                                            (struct NextAndId **) &world.things);
+    struct ThingType * tt = get_thing_type(type);
+    set_cleanup_flag(CLEANUP_THINGS);
+    t->type       = tt->id;
+    t->lifepoints = tt->lifepoints;
+    t->pos.y      = y;
+    t->pos.x      = x;
+    return t;
+}
+
+
+
+extern void free_thing_actions(struct ThingAction * ta)
+{
+    if (NULL == ta)
     {
-        if (NULL == ptr || id == ptr->id)
-        {
-            return ptr;
-        }
-        if (deep)
-        {
-            struct Thing * owned_thing = get_thing(ptr->owns, id, 1);
-            if (NULL != owned_thing)
-            {
-                return ptr;
-            }
-        }
-        ptr = ptr->next;
+        return;
     }
+    free_thing_actions(ta->next);
+    free(ta->name);
+    free(ta);
 }
 
 
 
-extern void free_thing_types(struct ThingType * tt_start)
+extern void free_thing_types(struct ThingType * tt)
 {
-    if (NULL == tt_start)
+    if (NULL == tt)
     {
         return;
     }
-    free_thing_types(tt_start->next);
-    free(tt_start->name);
-    free(tt_start);
+    free_thing_types(tt->next);
+    free(tt->name);
+    free(tt);
 }
 
 
 
-extern struct Thing * add_thing(int16_t id, uint8_t type, uint8_t find_pos)
+extern void free_things(struct Thing * t)
 {
-    char * f_name = "add_thing()";
-    struct ThingType * tt = get_thing_type(type);
-    struct Thing *     t  = try_malloc(sizeof(struct Thing), f_name);
-    memset(t, 0, sizeof(struct Thing));
-    t->id = (0 <= id && id <= UINT8_MAX) ? id : get_lowest_unused_id();
-    t->type       = tt->id;
-    t->lifepoints = tt->lifepoints;
-    char * err = "Space to put thing on too hard to find. Map too small?";
-    uint16_t i = 0;
-    memset(&(t->pos), 0, sizeof(struct yx_uint8));
-    while (find_pos)
+    if (NULL == t)
     {
-        struct yx_uint8 pos;
-        for (pos.y = pos.x = 0; 0 == is_passable(pos); i++)
+        return;
+    }
+    free_things(t->owns);
+    free_things(t->next);
+    free(t->fov_map);
+    free(t);
+    if (t == world.things)         /* So add_things()' NULL-delimited thing   */
+    {                              /* iteration loop does not iterate over    */
+        world.things = NULL;       /* freed memory when called the first time */
+    }                              /* after world re-seeding.                 */
+}
+
+
+
+extern struct ThingAction * get_thing_action(uint8_t id)
+{
+    struct ThingAction * ta = world.thing_actions;
+    for (; NULL != ta && id != ta->id; ta = ta->next);
+    return ta;
+}
+
+
+
+extern struct ThingType * get_thing_type(uint8_t id)
+{
+    struct ThingType * tt = world.thing_types;
+    for (; NULL != tt && id != tt->id; tt = tt->next);
+    return tt;
+}
+
+
+
+extern uint8_t get_thing_action_id_by_name(char * name)
+{
+    struct ThingAction * ta = world.thing_actions;
+    while (NULL != ta)
+    {
+        if (0 == strcmp(ta->name, name))
         {
-            exit_err(UINT16_MAX == i, err);
-            pos.y = rrand() % world.map.length;
-            pos.x = rrand() % world.map.length;
+            break;
         }
-        struct Thing * t_ptr;
-        uint8_t clear = 1;
-        for (t_ptr = world.things; t_ptr != NULL; t_ptr = t_ptr->next)
+        ta = ta->next;
+    }
+    if (!ta)
+    {
+        return 0;
+    }
+    return ta->id;
+}
+
+
+
+extern struct Thing * get_thing(struct Thing * ptr, uint8_t id, uint8_t deep)
+{
+    while (1)
+    {
+        if (NULL == ptr || id == ptr->id)
         {
-            if (yx_uint8_cmp(&pos, &t_ptr->pos) && 0 != t_ptr->lifepoints)
-            {
-                clear = 0;
-                break;
-            }
+            return ptr;
         }
-        if (1 == clear)
+        if (deep)
         {
-            t->pos = pos;
-            break;
+            struct Thing * owned_thing = get_thing(ptr->owns, id, 1);
+            if (NULL != owned_thing)
+            {
+                return ptr;
+            }
         }
+        ptr = ptr->next;
     }
-    struct Thing ** t_ptr_ptr = &world.things;
-    for (; NULL != * t_ptr_ptr; t_ptr_ptr = &(*t_ptr_ptr)->next);
-    * t_ptr_ptr = t;
-    return t;
 }
 
 
 
-extern void add_things(uint8_t type, uint8_t n)
+extern struct Thing * get_player()
 {
-    uint8_t i;
-    for (i = 0; i < n; i++)
-    {
-        add_thing(-1, type, 1);
-    }
+    return get_thing(world.things, 0, 0);
 }
 
 
 
-extern void free_things(struct Thing * t_start)
+extern void add_things(uint8_t type, uint8_t n)
 {
-    if (NULL == t_start)
+    uint8_t i;
+    for (i = 0; i < n; i++)
     {
-        return;
+        struct yx_uint8 pos;
+        while (1)
+        {
+            char * err = "Space to put thing on too hard to find."
+                         "Map too small?";
+            uint16_t i_pos = 0;
+            for (pos.y = pos.x = 0; 0 == is_passable(pos); i_pos++)
+            {
+                exit_err(UINT16_MAX == i_pos, err);
+                pos.y = rrand() % world.map.length;
+                pos.x = rrand() % world.map.length;
+            }
+            struct Thing * t;
+            uint8_t clear = 1;
+            for (t = world.things; t; t = t->next)
+            {
+                if (yx_uint8_cmp(&pos, &t->pos) && 0 != t->lifepoints)
+                {
+                    clear = 0;
+                    break;
+                }
+            }
+            if (1 == clear)
+            {
+                break;
+            }
+        }
+        add_thing(-1, type, pos.y, pos.x);
     }
-    free_things(t_start->owns);
-    free_things(t_start->next);
-    free(t_start->fov_map);
-    free(t_start);
-    if (t_start == world.things)   /* So add_things()' NULL-delimited thing   */
-    {                              /* iteration loop does not iterate over    */
-        world.things = NULL;       /* freed memory when called the first time */
-    }                              /* after world re-seeding.                 */
 }
 
 
@@ -178,29 +304,6 @@ extern void own_thing(struct Thing ** target, struct Thing ** source,
 
 
 
-extern struct Thing * get_player()
-{
-    return get_thing(world.things, 0, 1);
-}
-
-
-
-extern struct ThingType * get_thing_type(uint8_t id)
-{
-    char * f_name = "get_thing_type()";
-    struct ThingType * tt = world.thing_types;
-    for (; NULL != tt && id != tt->id; tt = tt->next);
-    char * err_intro = "Requested thing type of unused ID ";
-    uint16_t size = strlen(err_intro) + 3 + 1 + 1;
-    char * err = try_malloc(size, f_name);
-    exit_trouble(sprintf(err,"%s%d.",err_intro,id) < 0,f_name,s[S_FCN_SPRINTF]);
-    exit_err(NULL == tt, err);
-    free(err);
-    return tt;
-}
-
-
-
 extern void set_thing_position(struct Thing * t, struct yx_uint8 pos)
 {
     t->pos = pos;
index 889374a80d5e3fabc36647459f145902f66fdbf2..6f7d124bc414e3af0e04701b5cc675bcd97944c3 100644 (file)
@@ -1,24 +1,24 @@
 /* src/server/things.h
  *
- * Structs for things and their type definitions, and routines to initialize
- * these and load and save them from/to files.
+ * Structs for things and their type and action definitions, and routines to
+ * initialize these.
  */
 
 #ifndef THINGS_H
 #define THINGS_H
 
-#include <stdint.h> /* uint8_t */
+#include <stdint.h> /* uint8_t, int16_t */
 #include "../common/yx_uint8.h" /* yx_uint8 structs */
 
 
 
 struct Thing
 {
-    struct Thing * next;         /* pointer to next one in things chain */
+    struct Thing * next;
+    uint8_t id;                  /* individual thing's unique identifier */
     struct Thing * owns;         /* chain of things owned / in inventory */
     struct yx_uint8 pos;         /* coordinate on map */
     uint8_t * fov_map;           /* map of the thing's field of view */
-    uint8_t id;                  /* individual thing's unique identifier */
     uint8_t type;                /* ID of appropriate thing definition */
     uint8_t lifepoints;          /* 0: thing is inanimate; >0: hitpoints */
     uint8_t command;             /* thing's current action; 0 if none */
@@ -28,8 +28,8 @@ struct Thing
 
 struct ThingType
 {
-    uint8_t id;         /* thing type identifier / sets .type */
     struct ThingType * next;
+    uint8_t id;         /* thing type identifier / sets .type */
     char char_on_map;   /* thing symbol to appear on map */
     char * name;        /* string to describe thing in game log */
     uint8_t corpse_id;  /* type to change thing into upon destruction */
@@ -38,37 +38,65 @@ struct ThingType
     uint8_t start_n;    /* how many of these does the map start with? */
 };
 
+struct ThingAction
+{
+    struct ThingAction * next;
+    uint8_t id;   /* identifies action in Thing.command; therefore must be >0 */
+    void (* func) (struct Thing *);    /* function called after .effort turns */
+    char * name;                       /* human-readable identifier */
+    uint8_t effort;                    /* how many turns the action takes */
+};
 
 
-/* Return thing of "id" in chain at "ptr", search inventories too if "deep". */
-extern struct Thing * get_thing(struct Thing * ptr, uint8_t id, uint8_t deep);
 
-/* Free thing types chain starting at "tt_start". */
-extern void free_thing_types(struct ThingType * tt_start);
+/* Add thing action of "id" to world.thing_actions, with .name defaulting to
+ * s[S_CMD_WAIT], .func to actor_wait() and .effort to 1. If "id" is not >= 1
+ * and <= UINT8_MAX, use lowest unused id. Return thing action.
+ */
+extern struct ThingAction * add_thing_action(int16_t id);
 
-/* Add thing of "id" and "type" to map on random passable position (positions
- * which contain an actor are not deemed passable) if "find_pos", else on y=0,
- * x=0. If "id" is >= 0 and <= UINT8_MAX, use lowest unused id. Return thing.
+/* Add thing type of "id", with .corpse_id defaulting to "id" to
+ * world.thing_types, .name to "(none)" and the remaining values to 0. If "id"
+ * is not >= 0 and <= UINT8_MAX, use lowest unused id. Return thing type.
  */
-extern struct Thing * add_thing(int16_t id, uint8_t type, uint8_t find_pos);
+extern struct ThingType * add_thing_type(int16_t id);
 
-/* Add thing(s) ("n": how many?) of "type" to map on random position(s). New
- * animate things are never placed in the same square with other animate ones.
+/* Add thing of "id" and "type" on position of "y"/x" to world.things.If "id" is
+ * not >= 0 and <= UINT8_MAX, use lowest unused id. Return thing.
  */
-extern void add_things(uint8_t type, uint8_t n);
+extern struct Thing * add_thing(int16_t id, uint8_t type, uint8_t y, uint8_t x);
 
-/* Free things in things chain starting at "t_start. */
-extern void free_things(struct Thing * t_start);
+/* Free ThingAction/ThingType/Thing * chain starting at "ta"/"tt"/"t". */
+extern void free_thing_actions(struct ThingAction * ta);
+extern void free_thing_types(struct ThingType * tt);
+extern void free_things(struct Thing * t);
 
-/* Move thing of "id" from "source" inventory to "target" inventory. */
-extern void own_thing(struct Thing ** target, struct Thing ** source,
-                      uint8_t id);
+/* Return pointer to ThingAction/ThingType of "id", or NULL if none found. */
+extern struct ThingAction * get_thing_action(uint8_t id);
+extern struct ThingType * get_thing_type(uint8_t id);
 
-/* Get pointer to the Thing struct that represents the player. */
+/* Return world.thing_actions ThingAction.id for "name" or 0 if none found. */
+extern uint8_t get_thing_action_id_by_name(char * name);
+
+/* Return thing of "id" in chain at "ptr", search inventories too if "deep".
+ * Return NULL if nothing found.
+ */
+extern struct Thing * get_thing(struct Thing * ptr, uint8_t id, uint8_t deep);
+
+/* Get pointer to the non-owend Thing struct that represents the player, or NULL
+ * if none found.
+ */
 extern struct Thing * get_player();
 
-/* Get pointer to the thing type of identifier "def_id". */
-extern struct ThingType * get_thing_type(uint8_t id);
+/* Add thing(s) ("n": how many?) of "type" to map on random passable
+ * position(s). New animate things are never placed in the same square with
+ * other animate ones.
+ */
+extern void add_things(uint8_t type, uint8_t n);
+
+/* Move thing of "id" from "source" inventory to "target" inventory. */
+extern void own_thing(struct Thing ** target, struct Thing ** source,
+                      uint8_t id);
 
 /* Move not only "t" to "pos", but also all things owned by it. */
 extern void set_thing_position(struct Thing * t, struct yx_uint8 pos);
index 22af12c618a48288ebcaba517cec6ab132ea09e4..6e941e60cbbe199284decf3dd54134957bf33b36 100644 (file)
@@ -31,7 +31,8 @@ struct World
     uint32_t seed_map; /* Map seed. */
     uint16_t replay; /* Turn up to which to replay game. No replay if zero. */
     uint16_t turn; /* Current game turn. */
-    uint16_t do_update; /* Update worldstate file if !0. */
+    uint8_t do_update; /* Update worldstate file if !0. */
+    uint8_t exists; /* If !0, remake_world() has been run successfully. */
     uint8_t player_type; /* Thing type that player will start as. */
     uint8_t is_verbose; /* Should server send debugging info to stdout? */
 };