T_LIFEPOINTS [0 to 255]
Set selected thing's lifepoints to argument.
+T_SATIATION [-32768 to 32767]
+Set selected thing's satiation score.
+
T_CARRIES [0 to 255]
Add thing of ID in argument to inventory of selected thing, if said thing is
available for carrying and not the selected thing.
thing of the selected type to emit an offspring to a random neighbor cell if one
is available that is passable and not inhabited by a thing of the same same type
or, if the proliferating thing is animate, any other animate thing.
+
+TT_STOMACH [0-32767]
+Set degree to which things of the selected type suffer from hunger or
+over-satiation: If 0, not at all. Else, each turn a thing of the given type may
+suffer a lifepoint decrement to the chance of the rounded down quotient of the
+satiation score's absolute value by the given value, then again divided by the
+latter. This means that the chance is always zero when the absolute value of the
+satiation score is lower than the given value.
TT_SYMBOL @
TT_NAME HUMAN
TT_CONSUMABLE 0
+TT_STOMACH 2048
TT_ID 1
TT_START_NUMBER 27
TT_SYMBOL a
TT_NAME ANT
TT_CONSUMABLE 0
+TT_STOMACH 4096
TT_ID 2
TT_START_NUMBER 9
TT_SYMBOL z
TT_NAME ZOMBIE
TT_CONSUMABLE 0
+TT_STOMACH 1024
TT_ID 3
TT_START_NUMBER 3
TT_SYMBOL S
TT_NAME SHOGGOTH
TT_CONSUMABLE 0
+TT_STOMACH 512
TT_ID 4
TT_START_NUMBER 9
{
char * dsc_turn = "Turn: ";
char * dsc_hitpoints = "\nHitpoints: ";
- uint16_t maxl = strlen(dsc_turn) + 5 + strlen(dsc_hitpoints) + 3;
+ char * dsc_satiation = "\nSatiation: ";
+ uint16_t maxl = strlen(dsc_turn) + 5 + strlen(dsc_hitpoints)
+ + strlen(dsc_satiation) + 6 + 3;
char * text = try_malloc(maxl + 1, __func__);
- int test = sprintf(text, "%s%d%s%d", dsc_turn, world.turn, dsc_hitpoints,
- world.player_lifepoints);
+ int test = sprintf(text, "%s%d%s%d%s%d", dsc_turn, world.turn, dsc_hitpoints,
+ world.player_lifepoints, dsc_satiation,
+ world.player_satiation);
exit_trouble(test < 0, __func__, "sprintf");
add_text_with_linebreaks(win, text);
free(text);
/* Return value seen by atoi() in next line of "file" when passed to try_fgets()
* with the given arguments.
*/
-static uint16_t read_value_from_line(char * read_buf, uint32_t linemax,
- FILE * file);
+static int32_t read_value_from_line(char* read_buf,int32_t linemax,FILE* file);
/* If the server's worldstate file has changed since the last read_worldstate(),
* return a pointer to its file descriptor; else, return NULL.
-static uint16_t read_value_from_line(char * read_buf, uint32_t linemax,
- FILE * file)
+static int32_t read_value_from_line(char * read_buf,int32_t linemax,FILE * file)
{
try_fgets(read_buf, linemax + 1, file, __func__);
return atoi(read_buf);
}
uint32_t linemax = textfile_width(file);
char * read_buf = try_malloc(linemax + 1, __func__);
- world.turn = read_value_from_line(read_buf, linemax, file);
- world.player_lifepoints = read_value_from_line(read_buf, linemax, file);
+ world.turn = (uint16_t) read_value_from_line(read_buf, linemax, file);
+ world.player_lifepoints = (uint16_t) read_value_from_line(read_buf, linemax,
+ file);
+ world.player_satiation = (int16_t) read_value_from_line(read_buf, linemax,
+ file);
read_inventory(read_buf, linemax, file);
- world.player_pos.y = read_value_from_line(read_buf, linemax, file);
- world.player_pos.x = read_value_from_line(read_buf, linemax, file);
- world.map.length = read_value_from_line(read_buf, linemax, file);
+ world.player_pos.y = (uint8_t) read_value_from_line(read_buf,linemax,file);
+ world.player_pos.x = (uint8_t) read_value_from_line(read_buf,linemax,file);
+ world.map.length = (uint16_t) read_value_from_line(read_buf, linemax, file);
read_map_cells(file, &world.map.cells);
read_map_cells(file, &world.mem_map);
free(read_buf);
struct yx_uint8 player_pos; /* coordinates of player on map */
struct yx_uint8 look_pos; /* coordinates of look cursor */
uint16_t turn; /* world/game turn */
+ int16_t player_satiation; /* player's belly fullness */
uint8_t player_inventory_select; /* index of selected item in inventory */
uint8_t player_lifepoints; /* how alive the player is */
uint8_t winch; /* if set, SIGWINCH was registered; trigger reset_windows()*/
|| 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));
+ || parse_val(tok0,tok1,s[S_CMD_TT_STOMACH], 'u', (char *) &tt->stomach)
+ || 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))
( !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])))
+ || !strcmp(tok0, s[S_CMD_T_HP]) || !strcmp(tok0, s[S_CMD_T_COMMAND])
+ || !strcmp(tok0, s[S_CMD_T_SATIATION])))
{
return err_line(1, "No thing defined to manipulate yet.");
}
|| 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_val(tok0,tok1, s[S_CMD_T_SATIATION], 'i',(char *)&t->satiation)
|| parse_position(tok0, tok1, t)
|| parse_carry(tok0, tok1, t));
else if (parse_val(tok0, tok1, s[S_CMD_T_ID], 'i', (char *) &id))
-char * s[43];
+char * s[45];
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_TT_STOMACH] = "TT_STOMACH";
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_ARGUMENT] = "T_ARGUMENT";
s[S_CMD_T_PROGRESS] = "T_PROGRESS";
s[S_CMD_T_HP] = "T_LIFEPOINTS";
+ s[S_CMD_T_SATIATION] = "T_SATIATION";
s[S_CMD_T_CARRIES] = "T_CARRIES";
s[S_CMD_T_MEMMAP] = "T_MEMMAP";
s[S_CMD_T_MEMDEPTHMAP] = "T_MEMDEPTHMAP";
S_CMD_TT_NAME,
S_CMD_TT_CORPS,
S_CMD_TT_PROL,
+ S_CMD_TT_STOMACH,
S_CMD_T_ID,
S_CMD_T_TYPE,
S_CMD_T_POSY,
S_CMD_T_ARGUMENT,
S_CMD_T_PROGRESS,
S_CMD_T_HP,
+ S_CMD_T_SATIATION,
S_CMD_T_CARRIES,
S_CMD_T_MEMMAP,
S_CMD_T_MEMDEPTHMAP,
extern void init_strings();
-extern char * s[43];
+extern char * s[45];
#include <errno.h> /* global errno */
#include <limits.h> /* PIPE_BUF */
#include <stddef.h> /* NULL */
-#include <stdint.h> /* uint8_t, uint16_t, uint32_t, UINT8_MAX */
+#include <stdint.h> /* uint8_t, uint16_t, uint32_t, int32_t, UINT8_MAX */
#include <stdio.h> /* defines FILE, sprintf(), fprintf() */
#include <stdlib.h> /* free() */
#include <string.h> /* strlen(), snprintf(), memcpy(), strchr() */
/* Helpers to write lines of god commands to recreate thing "t". */
static void write_key_space(FILE * file, char * key);
-static void write_value(FILE * file, uint32_t value);
+static void write_uvalue(FILE * file, uint32_t value);
static void write_string(FILE * file, char * string);
-static void write_key_space_value(FILE * file, char * key, uint32_t value);
+static void write_key_space_uvalue(FILE * file, char * key, uint32_t value);
+static void write_key_space_svalue(FILE * file, char * key, int32_t value);
static void write_key_space_string(FILE * file, char * key, char * string);
/* Write to "file" game-map-sized "map" in "command"-prefixed numbered lines. */
static void update_worldstate_file();
/* Write "value" to new \n-delimited line of "file". */
-static void write_value_as_line(uint32_t value, FILE * file);
+static void write_value_as_line(int32_t value, FILE * file);
/* Write to "file" player's inventory, one item name per line. End in "%\n". */
static void write_inventory(struct Thing * player, FILE * file);
-static void write_value(FILE * file, uint32_t value)
+static void write_uvalue(FILE * file, uint32_t value)
{
char * line = try_malloc(11, __func__);
exit_trouble(-1 == sprintf(line, "%u", value), __func__, s[S_FCN_SPRINTF]);
-static void write_key_space_value(FILE * file, char * key, uint32_t value)
+static void write_key_space_uvalue(FILE * file, char * key, uint32_t value)
{
write_key_space(file, key);
- write_value(file, value);
+ write_uvalue(file, value);
+ try_fputc('\n', file, __func__);
+}
+
+
+
+static void write_key_space_svalue(FILE * file, char * key, int32_t value)
+{
+ write_key_space(file, key);
+ char * line = try_malloc(11, __func__);
+ exit_trouble(-1 == sprintf(line, "%d", value), __func__, s[S_FCN_SPRINTF]);
+ try_fwrite(line, strlen(line), 1, file, __func__);
+ free(line);
try_fputc('\n', file, __func__);
}
map_copy + (y * world.map.length));
exit_trouble(test < 0, __func__, "snprintf()");
write_key_space(file, command);
- write_value(file, y);
+ write_uvalue(file, y);
try_fputc(' ', file, __func__);
write_string(file, string);
try_fputc('\n', file, __func__);
{
write_thing(file, o);
}
- write_key_space_value(file, s[S_CMD_T_ID], t->id);
- write_key_space_value(file, s[S_CMD_T_TYPE], t->type);
- write_key_space_value(file, s[S_CMD_T_POSY], t->pos.y);
- write_key_space_value(file, s[S_CMD_T_POSX], t->pos.x);
- write_key_space_value(file, s[S_CMD_T_COMMAND], t->command);
- write_key_space_value(file, s[S_CMD_T_ARGUMENT], t->arg);
- write_key_space_value(file, s[S_CMD_T_PROGRESS], t->progress);
- write_key_space_value(file, s[S_CMD_T_HP], t->lifepoints);
+ write_key_space_uvalue(file, s[S_CMD_T_ID], t->id);
+ write_key_space_uvalue(file, s[S_CMD_T_TYPE], t->type);
+ write_key_space_uvalue(file, s[S_CMD_T_POSY], t->pos.y);
+ write_key_space_uvalue(file, s[S_CMD_T_POSX], t->pos.x);
+ write_key_space_uvalue(file, s[S_CMD_T_COMMAND], t->command);
+ write_key_space_uvalue(file, s[S_CMD_T_ARGUMENT], t->arg);
+ write_key_space_uvalue(file, s[S_CMD_T_PROGRESS], t->progress);
+ write_key_space_uvalue(file, s[S_CMD_T_HP], t->lifepoints);
+ write_key_space_svalue(file, s[S_CMD_T_SATIATION], t->satiation);
for (o = t->owns; o; o = o->next)
{
- write_key_space_value(file, s[S_CMD_T_CARRIES], o->id);
+ write_key_space_uvalue(file, s[S_CMD_T_CARRIES], o->id);
}
write_mem_map(file, t->mem_depth_map, s[S_CMD_T_MEMDEPTHMAP]);
write_mem_map(file, t->mem_map, s[S_CMD_T_MEMMAP]);
for (; tm; tm = tm->next)
{
write_key_space(file, s[S_CMD_T_MEMTHING]);
- write_value(file, tm->type);
+ write_uvalue(file, tm->type);
try_fputc(' ', file, __func__);
- write_value(file, tm->pos.y);
+ write_uvalue(file, tm->pos.y);
try_fputc(' ', file, __func__);
- write_value(file, tm->pos.x);
+ write_uvalue(file, tm->pos.x);
try_fputc('\n', file, __func__);
}
try_fputc('\n', file, __func__);
struct Thing * player = get_player();
write_value_as_line(world.turn, file);
write_value_as_line(player->lifepoints, file);
+ write_value_as_line(player->satiation, file);
write_inventory(player, file);
write_value_as_line(player->pos.y, file);
write_value_as_line(player->pos.x, file);
-static void write_value_as_line(uint32_t value, FILE * file)
+static void write_value_as_line(int32_t value, FILE * file)
{
- char write_buf[12]; /* Holds 10 digits of uint32_t maximum + \n + \0. */
+ char write_buf[13]; /* Hold "+"/"-" + 10 digits of int32_t max + \n + \0. */
exit_trouble(sprintf(write_buf,"%u\n",value) < 0,__func__,s[S_FCN_SPRINTF]);
try_fwrite(write_buf, strlen(write_buf), 1, file, __func__);
}
{
char * path_tmp;
FILE * file = atomic_write_start(s[S_PATH_SAVE], &path_tmp);
- write_key_space_value(file, s[S_CMD_MAPLENGTH], world.map.length);
- write_key_space_value(file, s[S_CMD_PLAYTYPE], world.player_type);
+ write_key_space_uvalue(file, s[S_CMD_MAPLENGTH], world.map.length);
+ write_key_space_uvalue(file, s[S_CMD_PLAYTYPE], world.player_type);
try_fputc('\n', file, __func__);
struct ThingAction * ta;
for (ta = world.thing_actions; ta; ta = ta->next)
{
- write_key_space_value(file, s[S_CMD_TA_ID], ta->id);
- write_key_space_value(file, s[S_CMD_TA_EFFORT], ta->effort);
+ write_key_space_uvalue(file, s[S_CMD_TA_ID], ta->id);
+ write_key_space_uvalue(file, s[S_CMD_TA_EFFORT], ta->effort);
write_key_space_string(file, s[S_CMD_TA_NAME], ta->name);
try_fputc('\n', file, __func__);
}
struct ThingType * tt;
for (tt = world.thing_types; tt; tt = tt->next)
{
- write_key_space_value(file, s[S_CMD_TT_ID], tt->id);
- write_key_space_value(file, s[S_CMD_TT_STARTN], tt->start_n);
- write_key_space_value(file, s[S_CMD_TT_HP], tt->lifepoints);
+ write_key_space_uvalue(file, s[S_CMD_TT_ID], tt->id);
+ write_key_space_uvalue(file, s[S_CMD_TT_STARTN], tt->start_n);
+ write_key_space_uvalue(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, __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);
+ write_key_space_uvalue(file, s[S_CMD_TT_CONSUM], tt->consumable);
+ write_key_space_uvalue(file, s[S_CMD_TT_PROL], tt->proliferate);
+ write_key_space_uvalue(file, s[S_CMD_TT_STOMACH], tt->stomach);
try_fputc('\n', file, __func__);
}
for (tt = world.thing_types; tt; tt = tt->next)
{
- write_key_space_value(file, s[S_CMD_TT_ID], tt->id);
- write_key_space_value(file, s[S_CMD_TT_CORPS], tt->corpse_id);
+ write_key_space_uvalue(file, s[S_CMD_TT_ID], tt->id);
+ write_key_space_uvalue(file, s[S_CMD_TT_CORPS], tt->corpse_id);
}
try_fputc('\n', file, __func__);
- write_key_space_value(file, s[S_CMD_SEED_MAP], world.seed_map);
- write_key_space_value(file, s[S_CMD_SEED_RAND], world.seed);
- write_key_space_value(file, s[S_CMD_TURN], world.turn);
+ write_key_space_uvalue(file, s[S_CMD_SEED_MAP], world.seed_map);
+ write_key_space_uvalue(file, s[S_CMD_SEED_RAND], world.seed);
+ write_key_space_uvalue(file, s[S_CMD_TURN], world.turn);
try_fputc('\n', file, __func__);
struct Thing * t;
for (t = world.things; t; t = t->next)
{
write_thing(file, t);
}
- write_key_space_value(file, s[S_CMD_WORLD_ACTIVE], 1);
+ write_key_space_uvalue(file, s[S_CMD_WORLD_ACTIVE], 1);
atomic_write_finish(file, s[S_PATH_SAVE], path_tmp);
}
#include "god_commands.h" /* parse_god_command_(1|2|3)arg() */
#include "hardcoded_strings.h" /* s */
#include "io.h" /* io_round(), save_world() */
+#include "thing_actions.h" /* hunger() */
#include "things.h" /* Thing, ThingType, ThingInMemory, get_player(),
* get_thing_action_id_by_name(), try_thing_proliferation()
*/
thing->command = 0;
thing->progress = 0;
}
+ hunger(thing);
}
try_thing_proliferation(thing);
}
#include "thing_actions.h"
#include <stddef.h> /* NULL */
-#include <stdint.h> /* uint8_t */
+#include <stdint.h> /* uint8_t, INT16_MIN */
#include <stdio.h> /* sprintf() */
#include <stdlib.h> /* free() */
#include <string.h> /* strlen() */
* own_thing(), set_thing_position(), get_thing_type(),
*/
#include "map.h" /* mv_yx_in_dir_legal() */
+#include "rrand.h" /* rrand() */
#include "run.h" /* send_to_outfile() */
#include "world.h" /* global world */
/* Send "text" as log message to server out file. */
static void update_log(char * text);
-/* One actor "wounds" another actor, decrementing his lifepoints and, if they
- * reach zero in the process, killing it. Generates appropriate log message.
- */
+/* Decrement "t"'s lifepoints, and if to zero, kill it with log update. */
+static void decrement_lifepoints(struct Thing * t);
+
+/* One actor "wounds" another actor, decrementing his lifepoints. */
static void actor_hits_actor(struct Thing * hitter, struct Thing * hitted);
/* Bonus stuff to actor_*() to happen if actor==player. Mostly writing of log
+static void decrement_lifepoints(struct Thing * t)
+{
+ struct Thing * player = get_player();
+ t->lifepoints--;
+ if (0 == t->lifepoints)
+ {
+ t->type = get_thing_type(t->type)->corpse_id;
+ if (player == t)
+ {
+ update_log("You die.");
+ memset(t->fov_map, ' ', world.map.length * world.map.length);
+ return;
+ }
+ else
+ {
+ free(t->fov_map);
+ t->fov_map = NULL;
+ free(t->mem_map);
+ t->mem_map = NULL;
+ free(t->mem_depth_map);
+ t->mem_depth_map = NULL;
+ free_things_in_memory(t->t_mem);
+ t->t_mem = NULL;
+ }
+ update_log("It dies.");
+ }
+}
+
+
+
static void actor_hits_actor(struct Thing * hitter, struct Thing * hitted)
{
struct ThingType * tt_hitter = get_thing_type(hitter->type);
exit_trouble(test < 0, __func__, s[S_FCN_SPRINTF]);
update_log(msg);
free(msg);
- hitted->lifepoints--;
- if (0 == hitted->lifepoints)
- {
- hitted->type = tt_hitted->corpse_id;
- if (player == hitted)
- {
- update_log("You die.");
- memset(hitted->fov_map, ' ', world.map.length * world.map.length);
- return;
- }
- else
- {
- free(hitted->fov_map);
- hitted->fov_map = NULL;
- free(hitted->mem_map);
- hitted->mem_map = NULL;
- free(hitted->mem_depth_map);
- hitted->mem_depth_map = NULL;
- free_things_in_memory(hitted->t_mem);
- hitted->t_mem = NULL;
- }
- update_log("It dies.");
- }
+ decrement_lifepoints(hitted);
}
playerbonus_use(no_thing, wrong_thing);
}
}
+
+
+
+extern void hunger(struct Thing * t)
+{
+ struct ThingType * tt = get_thing_type(t->type);
+ if (!(tt->stomach))
+ {
+ return;
+ }
+ if (t->satiation > INT16_MIN)
+ {
+ t->satiation--;
+ }
+ uint16_t testbase = t->satiation < 0 ? -(t->satiation) : t->satiation;
+ uint16_t endurance = tt->stomach;
+ if ((testbase / endurance) / ((rrand() % endurance) + 1))
+ {
+ if (get_player() == t)
+ {
+ update_log("You suffer from hunger.");
+ }
+ else
+ {
+ char * msg_part = " suffers from hunger.";
+ uint8_t len = strlen(tt->name) + strlen(msg_part) + 1;
+ char * msg = try_malloc(len, __func__);
+ int test = sprintf(msg, "%s%s", tt->name, msg_part);
+ exit_trouble(test < 0, __func__, s[S_FCN_SPRINTF]);
+ update_log(msg);
+ free(msg);
+ }
+ decrement_lifepoints(t);
+ }
+}
*/
extern void actor_use(struct Thing * t);
+/* Decrement "t"'s satiation and trigger a chance (dependent on over-/under-
+ * satiation value) of lifepoint decrement, when its type's .stomach is >0.
+ */
+extern void hunger(struct Thing * t);
+
#endif
#ifndef THINGS_H
#define THINGS_H
-#include <stdint.h> /* uint8_t, int16_t */
+#include <stdint.h> /* uint8_t, int16_t, uint16_t */
#include "../common/yx_uint8.h" /* yx_uint8 */
char * fov_map; /* thing's FOV map; 'v':visible, 'H':hidden */
char * mem_map; /* map knowledge of thing by FOV and memory */
char * mem_depth_map; /* map of map memory up-to-dateness */
+ int16_t satiation; /* negative: hungry; positive: over-fed */
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 */
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 */
+ uint16_t stomach; /* if >0, defines onset & chance of hunger suffering */
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 */