home · contact · privacy
Server: New command TT_PROLIFERATE sets chance for thing proliferation.
authorChristian Heller <c.heller@plomlompom.de>
Wed, 15 Oct 2014 01:14:50 +0000 (03:14 +0200)
committerChristian Heller <c.heller@plomlompom.de>
Wed, 15 Oct 2014 01:14:50 +0000 (03:14 +0200)
README
SERVER_COMMANDS
confserver/world
src/server/god_commands.c
src/server/hardcoded_strings.c
src/server/hardcoded_strings.h
src/server/io.c
src/server/run.c
src/server/things.c
src/server/things.h

diff --git a/README b/README
index d50abd9910e4b35250277ebb641ba957855c1a65..15fc87f41e72cd35db5e9729f67135609ce5f6c5 100644 (file)
--- a/README
+++ b/README
@@ -8,7 +8,8 @@ You can move around a player on an island and meet different enemies. You have 5
 hitpoints to lose before death. Enemies start with different amounts of
 hitpoints, depending on their species. Dead enemies become dirt, skeletons or
 "magic meat" -- such objects can be collected, and "magic meat" can be consumed
 hitpoints to lose before death. Enemies start with different amounts of
 hitpoints, depending on their species. Dead enemies become dirt, skeletons or
 "magic meat" -- such objects can be collected, and "magic meat" can be consumed
-to gain hitpoints. Note that different kinds of movements/actions take different
+to gain hitpoints (if allowed to lie on the ground for a while it may even
+multiply ...). Note that different kinds of movements/actions take different
 numbers of turns to finish.
 
 Enemies' AI is very dumb so far: Each turn, they try to move towards their
 numbers of turns to finish.
 
 Enemies' AI is very dumb so far: Each turn, they try to move towards their
index 8af195fbdc5283a6e396666e669ff3dcf6716533..0a85cd381588c6379ded56b8a324be45ddfb467a 100644 (file)
@@ -126,7 +126,7 @@ T_ID [-32768 to 32767]
 Select thing to manipulate by argument as ID. If argument is <0 or >255, change
 it to the lowest unused thing ID. If thing of ID does not exist yet, create it
 with default position of y=0/x=0, the first thing type's ID, and that type's
 Select thing to manipulate by argument as ID. If argument is <0 or >255, change
 it to the lowest unused thing ID. If thing of ID does not exist yet, create it
 with default position of y=0/x=0, the first thing type's ID, and that type's
-lifepoints value. If world is active and the thing is animate, build its field
+lifepoints value; if world is active and the thing is animate, build its field
 of view.
 
 T_TYPE [0 to 255]
 of view.
 
 T_TYPE [0 to 255]
@@ -197,3 +197,9 @@ game log and the inventory.
 TT_CORPSE_ID [0-255]
 Set to argument the ID of the thing type that things of the selected type
 transform into when their state changes from animate to inanimate.
 TT_CORPSE_ID [0-255]
 Set to argument the ID of the thing type that things of the selected type
 transform into when their state changes from animate to inanimate.
+
+TT_PROLIFERATE [0-255]
+If non-zero, there is a chance of 1 divided by the given value each turn for any
+thing of the selected type to emit an offspring to a random neighbor cell if one
+passable is available (and, if the thing is of an animate type, not inhabited by
+another animate thing).
index 0c26815e93d4f4cb8ac11acc307a2e2fbf4f7184..c967a1955ff041ab0329269982df7d41634f644d 100644 (file)
@@ -69,6 +69,7 @@ TT_LIFEPOINTS 0
 TT_SYMBOL m
 TT_NAME 'MAGIC MEAT'
 TT_CONSUMABLE 3
 TT_SYMBOL m
 TT_NAME 'MAGIC MEAT'
 TT_CONSUMABLE 3
+TT_PROLIFERATE 255
 
 TT_ID 0
 TT_CORPSE_ID 5
 
 TT_ID 0
 TT_CORPSE_ID 5
index ebe0d5f91be8955f6f81435c02a9a985efe025a9..06abcfec87626d6677daa9586db3bf0e35dc8042 100644 (file)
@@ -88,7 +88,8 @@ static uint8_t parse_thingtype_manipulation(char * tok0, char * tok1)
     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])
     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])))
+         || !strcmp(tok0, s[S_CMD_TT_CORPS])  || !strcmp(tok0, s[S_CMD_TT_HP])
+         || !strcmp(tok0, s[S_CMD_TT_PROL])))
     {
         return err_line(1, "No thing type defined to manipulate yet.");
     }
     {
         return err_line(1, "No thing type defined to manipulate yet.");
     }
@@ -97,6 +98,7 @@ static uint8_t parse_thingtype_manipulation(char * tok0, char * tok1)
         || 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_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_PROL],'8',(char *) &tt->proliferate)
         || 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))
     {
         || 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))
     {
@@ -304,10 +306,6 @@ static uint8_t parse_thing_manipulation_1arg(char * tok0, char * tok1)
         if (!t && !err_line(!world.thing_types, err))
         {
             t = add_thing(id, world.thing_types->id, 0, 0);
         if (!t && !err_line(!world.thing_types, err))
         {
             t = add_thing(id, world.thing_types->id, 0, 0);
-            if (world.exists && t->lifepoints)
-            {
-                build_fov_map(t);
-            }
         }
     }
     else
         }
     }
     else
index d3560f65fa1b3d81d90eab44cff28c6adfe8bfbf..a0a21735683d4a96c8338aed534c4e74b629e455 100644 (file)
@@ -9,7 +9,7 @@
 
 
 
 
 
 
-char * s[41];
+char * s[42];
 
 
 
 
 
 
@@ -32,6 +32,7 @@ extern void init_strings()
     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_TT_SYMB] = "TT_SYMBOL";
     s[S_CMD_TT_NAME] = "TT_NAME";
     s[S_CMD_TT_CORPS] = "TT_CORPSE_ID";
+    s[S_CMD_TT_PROL] = "TT_PROLIFERATE";
     s[S_CMD_T_ID] = "T_ID";
     s[S_CMD_T_TYPE] = "T_TYPE";
     s[S_CMD_T_POSY] = "T_POSY";
     s[S_CMD_T_ID] = "T_ID";
     s[S_CMD_T_TYPE] = "T_TYPE";
     s[S_CMD_T_POSY] = "T_POSY";
index 70d29c678ff49ba674c258c9ab8266637db7b2cf..d11082779a4bb3a8b6029753e69f8859ef282891 100644 (file)
@@ -31,6 +31,7 @@ enum string_num
     S_CMD_TT_SYMB,
     S_CMD_TT_NAME,
     S_CMD_TT_CORPS,
     S_CMD_TT_SYMB,
     S_CMD_TT_NAME,
     S_CMD_TT_CORPS,
+    S_CMD_TT_PROL,
     S_CMD_T_ID,
     S_CMD_T_TYPE,
     S_CMD_T_POSY,
     S_CMD_T_ID,
     S_CMD_T_TYPE,
     S_CMD_T_POSY,
@@ -59,7 +60,7 @@ enum string_num
 
 extern void init_strings();
 
 
 extern void init_strings();
 
-extern char * s[41];
+extern char * s[42];
 
 
 
 
 
 
index eb54799c5dc052d6245717ddb21f44afec2118fe..0f7c3a8bd60367e5a338db65b6e2648227309b7e 100644 (file)
@@ -455,6 +455,7 @@ extern void save_world()
         exit_trouble(test < 0, __func__, "fprintf");
         write_key_space_string(file, s[S_CMD_TT_NAME], tt->name);
         write_key_space_value(file, s[S_CMD_TT_CONSUM], tt->consumable);
         exit_trouble(test < 0, __func__, "fprintf");
         write_key_space_string(file, s[S_CMD_TT_NAME], tt->name);
         write_key_space_value(file, s[S_CMD_TT_CONSUM], tt->consumable);
+        write_key_space_value(file, s[S_CMD_TT_PROL], tt->proliferate);
         try_fputc('\n', file, __func__);
     }
     for (tt = world.thing_types; tt; tt = tt->next)
         try_fputc('\n', file, __func__);
     }
     for (tt = world.thing_types; tt; tt = tt->next)
index b715ca4e74329617085f9dc4317e4f4202d060b2..334fe410fcf9200713725ee2f8adcc81b22f2c53 100644 (file)
@@ -8,7 +8,7 @@
 #define _POSIX_C_SOURCE 200809L
 #include "run.h"
 #include <stddef.h> /* NULL */
 #define _POSIX_C_SOURCE 200809L
 #include "run.h"
 #include <stddef.h> /* NULL */
-#include <stdint.h> /* uint8_t, uint16_t, uint32_t */
+#include <stdint.h> /* uint8_t, uint16_t, uint32_t, int16_t */
 #include <stdio.h> /* FILE, printf(), fflush() */
 #include <stdlib.h> /* free() */
 #include <string.h> /* strlen(), strcmp(), strncmp(), strdup() */
 #include <stdio.h> /* FILE, printf(), fflush() */
 #include <stdlib.h> /* free() */
 #include <string.h> /* strlen(), strcmp(), strncmp(), strdup() */
@@ -28,7 +28,9 @@
 #include "god_commands.h" /* parse_god_command_(1|2|3)arg() */
 #include "hardcoded_strings.h" /* s */
 #include "io.h" /* io_round(), save_world() */
 #include "god_commands.h" /* parse_god_command_(1|2|3)arg() */
 #include "hardcoded_strings.h" /* s */
 #include "io.h" /* io_round(), save_world() */
-#include "things.h" /* Thing, get_thing_action_id_by_name(), get_player() */
+#include "things.h" /* Thing, get_thing_action_id_by_name(), get_player(),
+                      * try_thing_proliferation()
+                      */
 #include "world.h" /* world */
 
 
 #include "world.h" /* world */
 
 
@@ -56,8 +58,16 @@ static uint8_t parse_command(char * tok0);
  */
 static void server_test();
 
  */
 static void server_test();
 
+/* Return array of IDs of non-owned things in game world, ended by non-ID -1. */
+static int16_t * build_whitelist();
+
+/* Return 1 if value of "id" appears in "whitelist", else 0. */
+static uint8_t thing_in_whitelist(uint8_t id, int16_t * whitelist);
+
 /* Run the game world and its inhabitants (and their actions) until the player
 /* Run the game world and its inhabitants (and their actions) until the player
- * avatar is free to receive new commands (or is dead).
+ * avatar is free to receive new commands (or is dead). Only actions and
+ * proliferations for non-owned things are performed that exist at the start of
+ * the turn jumped into, or started anew by the cycle.
  */
 static void turn_over();
 
  */
 static void turn_over();
 
@@ -204,40 +214,77 @@ static void server_test()
 
 
 
 
 
 
+static int16_t * build_whitelist()
+{
+    uint16_t i_things = NULL != world.things;
+    struct Thing * t = world.things;
+    for (; t; t = t->next, i_things++);
+    int16_t * whitelist = try_malloc(i_things * sizeof(int16_t), __func__);
+    for (i_things = 0, t = world.things; t;
+         whitelist[i_things] = t->id, t = t->next, i_things++)
+    whitelist[i_things] = -1;
+    return whitelist;
+}
+
+
+
+static uint8_t thing_in_whitelist(uint8_t id, int16_t * whitelist)
+{
+    int16_t i;
+    for (i = 0; -1 < whitelist[i]; i++)
+    {
+        if ((int16_t) id == whitelist[i])
+        {
+            return 1;
+        }
+    }
+    return 0;
+}
+
+
+
 static void turn_over()
 {
     struct Thing * player = get_player();
     struct Thing * thing = player;
     uint16_t start_turn = world.turn;
 static void turn_over()
 {
     struct Thing * player = get_player();
     struct Thing * thing = player;
     uint16_t start_turn = world.turn;
+    int16_t * whitelist = build_whitelist();
     while (    0 < player->lifepoints
            || (0 == player->lifepoints && start_turn == world.turn))
     while (    0 < player->lifepoints
            || (0 == player->lifepoints && start_turn == world.turn))
-    {
+    {             /* TODO: check meaning and refactorability of 2nd condition */
         if (!thing)
         {
             world.turn++;
             thing = world.things;
         if (!thing)
         {
             world.turn++;
             thing = world.things;
+            free(whitelist);
+            whitelist = build_whitelist();
         }
         }
-        if (0 < thing->lifepoints)
+        if (thing_in_whitelist(thing->id, whitelist))
         {
         {
-            if (0 == thing->command)
+            if (0 < thing->lifepoints)
             {
             {
-                if (thing == player)
+                if (0 == thing->command)
                 {
                 {
-                    break;
+                    if (thing == player)
+                    {
+                        break;
+                    }
+                    ai(thing);
+                }
+                thing->progress++;
+                struct ThingAction * ta = get_thing_action(thing->command);
+                if (thing->progress == ta->effort)
+                {
+                    ta->func(thing);
+                    thing->command = 0;
+                    thing->progress = 0;
                 }
                 }
-                ai(thing);
-            }
-            thing->progress++;
-            struct ThingAction * ta = get_thing_action(thing->command);
-            if (thing->progress == ta->effort)
-            {
-                ta->func(thing);
-                thing->command = 0;
-                thing->progress = 0;
             }
             }
+            try_thing_proliferation(thing);
         }
         thing = thing->next;
     }
         }
         thing = thing->next;
     }
+    free(whitelist);
 }
 
 
 }
 
 
index 5a866bb2f35a7f6395b4b7d005b8dcece45507da..eaeeb9ee8b9b09d9a5e511e6a082504e2a8b830d 100644 (file)
 #include <stddef.h> /* NULL, size_t */
 #include <stdint.h> /* uint8_t, uint16_t, int16_t, UINT8_MAX, UINT16_MAX */
 #include <stdlib.h> /* free() */
 #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(), strcmp(), strdup() */
+#include <string.h> /* memset(), strcmp(), strdup(), strlen() */
 #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 "../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 "field_of_view.h" /* build_fov_map() */
+#include "map.h" /* mv_yx_in_dir_legal() */
 #include "rrand.h" /* rrand() */
 #include "thing_actions.h" /* actor_wait */
 #include "world.h" /* world */
 #include "rrand.h" /* rrand() */
 #include "thing_actions.h" /* actor_wait */
 #include "world.h" /* world */
@@ -119,6 +121,10 @@ extern struct Thing * add_thing(int16_t id, uint8_t type, uint8_t y, uint8_t x)
     t->lifepoints = tt->lifepoints;
     t->pos.y      = y;
     t->pos.x      = x;
     t->lifepoints = tt->lifepoints;
     t->pos.y      = y;
     t->pos.x      = x;
+    if (t->lifepoints && world.exists)
+    {
+        build_fov_map(t);
+    }
     return t;
 }
 
     return t;
 }
 
@@ -262,6 +268,54 @@ extern struct Thing * get_player()
 
 
 
 
 
 
+extern void try_thing_proliferation(struct Thing * t)
+{
+    struct ThingType * tt = get_thing_type(t->type);
+    if (tt->proliferate)
+    {
+        if (1 == tt->proliferate || 1 == (rrand() % tt->proliferate))
+        {
+            struct yx_uint8 candidates[6];
+            uint8_t n_candidates = 0;
+            char dirs[7] = "dxswed";
+            struct yx_uint8 start = t->pos;
+            uint8_t i;
+            for (i = 0; i < strlen(dirs); i++)
+            {
+                if (   mv_yx_in_dir_legal(dirs[i], &start)
+                    && '.' == world.map.cells[start.y*world.map.length+start.x])
+                {
+                    uint8_t drop = 0;
+                    if (tt->lifepoints)
+                    {
+                        for (t = world.things; t; t = t->next)
+                        {
+                            if (   t->lifepoints
+                                && start.y == t->pos.y && start.x == t->pos.x)
+                            {
+                                drop = 1;
+                            }
+                        }
+                    }
+                    if (!drop)
+                    {
+                        candidates[n_candidates] = start;
+                        n_candidates++;
+                    }
+                }
+            }
+            if (!n_candidates)
+            {
+                return;
+            }
+            i = rrand() % n_candidates;
+            add_thing(-1, tt->id, candidates[i].y, candidates[i].x);
+        }
+    }
+}
+
+
+
 extern void add_things(uint8_t type, uint8_t n)
 {
     uint8_t i;
 extern void add_things(uint8_t type, uint8_t n)
 {
     uint8_t i;
index 940d108ab2f2b44d613737d08ce39fd3586e65a2..0f20fd90b8a14031b42fc4e3deb3791cd079028e 100644 (file)
@@ -42,13 +42,14 @@ struct ThingInMemory
 struct ThingType
 {
     struct ThingType * next;
 struct ThingType
 {
     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 */
-    uint8_t lifepoints; /* default start value for thing's .lifepoints */
-    uint8_t consumable; /* can be eaten if !0, for so much hitpoint win */
-    uint8_t start_n;    /* how many of these does the map start with? */
+    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 */
+    uint8_t lifepoints;  /* default start value for thing's .lifepoints */
+    uint8_t consumable;  /* can be eaten if !0, for so much hitpoint win */
+    uint8_t start_n;     /* how many of these does the map start with? */
+    uint8_t proliferate; /* if >0: inverse of chance to proliferate */
 };
 
 struct ThingAction
 };
 
 struct ThingAction
@@ -75,7 +76,8 @@ extern struct ThingAction * add_thing_action(uint8_t id);
 extern struct ThingType * add_thing_type(int16_t id);
 
 /* Add thing of "id" and "type" on position of "y"/x" to world.things. If "id"
 extern struct ThingType * add_thing_type(int16_t id);
 
 /* 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.
+ * is not >= 0 and <= UINT8_MAX, use lowest unused id. Build .fov_map if
+ * world.exists is non-zero. Return thing.
  */
 extern struct Thing * add_thing(int16_t id, uint8_t type, uint8_t y, uint8_t x);
 
  */
 extern struct Thing * add_thing(int16_t id, uint8_t type, uint8_t y, uint8_t x);
 
@@ -108,6 +110,12 @@ extern struct Thing * get_thing(struct Thing * ptr, uint8_t id, uint8_t deep);
  */
 extern struct Thing * get_player();
 
  */
 extern struct Thing * get_player();
 
+/* Try to create "t" offspring on random passable neighbor cell if available (and,
+ * if "t" is of animate thing type, not inhabited by animate thing) and "t"'s
+ * type's .proliferation is >0, with a chance of 1/.proliferation.
+ */
+extern void try_thing_proliferation(struct Thing * t);
+
 /* 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.
 /* 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.