From e1576f40cfa7cba4bb6950c87d21fe5e79bb4243 Mon Sep 17 00:00:00 2001 From: Christian Heller <c.heller@plomlompom.de> Date: Mon, 9 Mar 2015 12:34:32 +0100 Subject: [PATCH] Remove C variant of server, redefine build system to match this change. --- all.do | 4 +- build/compiler_flags | 2 +- compile-server.sh | 2 - redo | 4 - roguelike | 3 + plomrogue-server.py => roguelike-server | 0 roguelike-server.do | 10 - roguelike_python | 12 - src/server/ai.c | 486 ---------------------- src/server/ai.h | 30 -- src/server/cleanup.c | 70 ---- src/server/cleanup.h | 39 -- src/server/field_of_view.c | 381 ----------------- src/server/field_of_view.h | 28 -- src/server/god_commands.c | 524 ------------------------ src/server/god_commands.h | 25 -- src/server/hardcoded_strings.c | 62 --- src/server/hardcoded_strings.h | 69 ---- src/server/init.c | 257 ------------ src/server/init.h | 46 --- src/server/io.c | 441 -------------------- src/server/io.h | 31 -- src/server/main.c | 49 --- src/server/map.c | 241 ----------- src/server/map.h | 47 --- src/server/rrand.c | 18 - src/server/rrand.h | 25 -- src/server/run.c | 467 --------------------- src/server/run.h | 46 --- src/server/thing_actions.c | 393 ------------------ src/server/thing_actions.h | 54 --- src/server/things.c | 411 ------------------- src/server/things.h | 136 ------ src/server/world.h | 46 --- start_server_client_union.sh | 5 - start_server_python_client_union.sh | 46 --- 36 files changed, 6 insertions(+), 4504 deletions(-) delete mode 100755 compile-server.sh rename plomrogue-server.py => roguelike-server (100%) delete mode 100644 roguelike-server.do delete mode 100755 roguelike_python delete mode 100644 src/server/ai.c delete mode 100644 src/server/ai.h delete mode 100644 src/server/cleanup.c delete mode 100644 src/server/cleanup.h delete mode 100644 src/server/field_of_view.c delete mode 100644 src/server/field_of_view.h delete mode 100644 src/server/god_commands.c delete mode 100644 src/server/god_commands.h delete mode 100644 src/server/hardcoded_strings.c delete mode 100644 src/server/hardcoded_strings.h delete mode 100644 src/server/init.c delete mode 100644 src/server/init.h delete mode 100644 src/server/io.c delete mode 100644 src/server/io.h delete mode 100644 src/server/main.c delete mode 100644 src/server/map.c delete mode 100644 src/server/map.h delete mode 100644 src/server/rrand.c delete mode 100644 src/server/rrand.h delete mode 100644 src/server/run.c delete mode 100644 src/server/run.h delete mode 100644 src/server/thing_actions.c delete mode 100644 src/server/thing_actions.h delete mode 100644 src/server/things.c delete mode 100644 src/server/things.h delete mode 100644 src/server/world.h delete mode 100755 start_server_python_client_union.sh diff --git a/all.do b/all.do index 96e8536..77be8b6 100644 --- a/all.do +++ b/all.do @@ -1,8 +1,8 @@ -# redo build file to build executables "roguelike-server", "roguelike-client". +# redo build file to build "roguelike-server", "libplomrogue.so". # This file is part of PlomRogue. PlomRogue is licensed under the GPL version 3 # or any later version. For details on its copyright, license, and warranties, # see the file NOTICE in the root directory of the PlomRogue source package. -redo-ifchange roguelike-server +redo-ifchange libplomrogue.so redo-ifchange roguelike-client diff --git a/build/compiler_flags b/build/compiler_flags index 59fcb18..198da87 100644 --- a/build/compiler_flags +++ b/build/compiler_flags @@ -2,4 +2,4 @@ # or any later version. For details on its copyright, license, and warranties, # see the file NOTICE in the root directory of the PlomRogue source package. -CFLAGS='-std=c11 -pedantic-errors -Wall -Werror -Wextra -Wformat-security -g' +CFLAGS='-std=c11 -pedantic-errors -Wall -Werror -Wextra -Wformat-security -O3' diff --git a/compile-server.sh b/compile-server.sh deleted file mode 100755 index 5fdc7b2..0000000 --- a/compile-server.sh +++ /dev/null @@ -1,2 +0,0 @@ -#!/bin/sh -gcc -shared -fPIC -std=c11 -pedantic-errors -Wall -Werror -Wextra -Wformat-security -O3 -o libplomrogue.so libplomrogue.c -lm diff --git a/redo b/redo index 8f459fb..4081117 100755 --- a/redo +++ b/redo @@ -18,9 +18,5 @@ # <https://github.com/plomlompom/plomrogue/issues/2#issuecomment-50972436> for a # workaround. -echo "non-redo stuff (preparing for future Python port sans redo needs):" -echo "Building library for server's Python variant with mere shell one-liner." -./compile-server.sh - export PATH=$PATH:$PWD/build/redo_scripts redo "$@" diff --git a/roguelike b/roguelike index a0be8cc..b002721 100755 --- a/roguelike +++ b/roguelike @@ -2,7 +2,10 @@ # Wrapper to the script so that its suppressed server messages get read on exit. ./start_server_client_union.sh "$@" + +# For some reason, mere sync won't ensure a log is written out, so wait a while. sync +sleep 0.5 if [ -e ./log ] then cat log diff --git a/plomrogue-server.py b/roguelike-server similarity index 100% rename from plomrogue-server.py rename to roguelike-server diff --git a/roguelike-server.do b/roguelike-server.do deleted file mode 100644 index ebe418d..0000000 --- a/roguelike-server.do +++ /dev/null @@ -1,10 +0,0 @@ -# redo build file to build the executable "roguelike-server". - -# This file is part of PlomRogue. PlomRogue is licensed under the GPL version 3 -# or any later version. For details on its copyright, license, and warranties, -# see the file NOTICE in the root directory of the PlomRogue source package. - -redo-ifchange build/build_template -TARGET=server -LIBRARY_LINKS=-lm -. ./build/build_template diff --git a/roguelike_python b/roguelike_python deleted file mode 100755 index 74f7f34..0000000 --- a/roguelike_python +++ /dev/null @@ -1,12 +0,0 @@ -#!/bin/sh - -# Wrapper to the script so that its suppressed server messages get read on exit. -./start_server_python_client_union.sh "$@" - -# For some reason, mere sync won't ensure a log is written out, so wait a while. -sync -sleep 0.5 -if [ -e ./log ] -then - cat log -fi diff --git a/src/server/ai.c b/src/server/ai.c deleted file mode 100644 index 749a385..0000000 --- a/src/server/ai.c +++ /dev/null @@ -1,486 +0,0 @@ -/* src/server/ai.c - * - * This file is part of PlomRogue. PlomRogue is licensed under the GPL version 3 - * or any later version. For details on its copyright, license, and warranties, - * see the file NOTICE in the root directory of the PlomRogue source package. - */ - -#include "ai.h" -#include <stdint.h> /* uint8_t, uint16_t, uint32_t, int16_t, UINT16_MAX */ -#include <stdlib.h> /* free() */ -#include "../common/try_malloc.h" /* try_malloc() */ -#include "hardcoded_strings.h" /* s */ -#include "rrand.h" /* rrand() */ -#include "thing_actions.h" /* get_thing_action_id_by_name() */ -#include "things.h" /* Thing, ThingType, ThingInMemory, get_thing_type() */ -#include "world.h" /* world */ - -#define N_DIRS 6 - - - -/* Return "score_map"["pos"] unless "check_inhabitant" and cell is inhabited. */ -static uint16_t set_neighbor_val(uint16_t * score_map, uint8_t check_inhabitant, - uint16_t kill_score, uint16_t pos); - -/* Write into "neighbors" scores of the N_DIRS immediate neighbors of the - * "score_map" cell at "pos_i" (array index), as found in the directions - * north-east, east, south-east etc. (clockwise order). Use "kill_score" for - * illegal neighborhoods (i.e. if direction would lead beyond the map's border, - * or, if "check_inhabitants" is non-zero, into animate-inhabited cell). - */ -static void get_neighbor_scores(uint16_t * score_map, uint16_t pos_i, - uint16_t kill_score, uint16_t * neighbors, - uint8_t check_inhabitants); - -/* Iterate over scored cells in "score_map" of world.map's geometry. Compare - * each cell's score against the score of its immediate neighbors in N_DIRS - * directions. If any neighbor's score is at least two points lower than the - * current cell's score, re-set it to 1 point higher than its lowest-scored - * neighbor. Repeat this whole process until all cells have settled on their - * final score. Ignore cells whose score is greater than "max_score". Expect - * "max_score" to be the maximum score for cells, marking them as unreachable. - */ -static void dijkstra_map(uint16_t * score_map, uint16_t max_score); - -/* Helpers to init_score_map(), realizing individual filters. */ -static uint8_t score_map_filter_attack(uint8_t filter, uint16_t * score_map, - struct Thing * t_eye); -static uint8_t score_map_filter_flee(uint8_t filter, uint16_t * score_map, - struct Thing * t_eye); -static uint8_t score_map_filter_consume(uint8_t filter, uint16_t * score_map, - struct Thing * t_eye); -static uint8_t score_map_filter_search(uint8_t filter, uint16_t * score_map, - struct Thing * t_eye); - -/* get_dir_to_nearest_target() helper: Prepare "score_map" for dijkstra_map(). */ -static void init_score_map(char filter, uint16_t * score_map, uint32_t map_size, - struct Thing * t_eye); - -/* From "targets" select random "cmp" match as directory by order in "dirs". */ -static char rand_target_dir(char * dirs, uint16_t cmp, uint16_t * targets); - -/* Helper to get_dir_to_nearest_target(). */ -static char get_dir_from_neighbors(char filter, struct Thing * t_eye, - uint16_t * score_map); - -/* Set (if possible) as "t_eye"'s command a move to the path to the path-wise - * nearest target that is not "t_eye" and fits criteria set by "filter". On - * success, return !0, else 0. Values for "filter": - * "a": thing in FOV is below a certain distance, animate, but of a type that is - * not "t_eye"'s, and starts out weaker than it is; build path as avoiding - * things of "t_eye"'s type - * "f": neighbor cell (not inhabited by any animate thing) further away from - * animate thing not further than x steps away and in FOV and of a type - * that is not "t_eye"'s, and starts out stronger or as strong as "t_eye" - * is currently; or (cornered), if no such flight cell, but thing of above - * criteria is too near, a cell closer to it, or, if less near, just wait - * "c": thing in memorized map is consumable - * "s": memory map cell with greatest-reachable degree of unexploredness - */ -static uint8_t get_dir_to_nearest_target(struct Thing * t_eye, char filter); - -/* Return 1 if any thing not "t_eye" is known and fulfills some criteria defined - * by "filter", else 0. Values for "filter": - * "a" or "f": thing in FOV is animate, but of type that not that of "t_eye", - * and starts out weaker ("a") / stronger ("f") than "t_eye" is - * "c" : thing in memorized map is consumable - */ -static uint8_t seeing_thing(struct Thing * t_eye, char filter); - -/* Return slot ID of strongest consumable in "t_owner"'s inventory, else -1. */ -static int16_t get_inventory_slot_to_consume(struct Thing * t_owner); - -/* Return 1 if "t_standing" is standing on a consumable, else 0. */ -static uint8_t standing_on_consumable(struct Thing * t_standing); - - - -static uint16_t set_neighbor_val(uint16_t * score_map, uint8_t check_inhabitant, - uint16_t kill_score, uint16_t pos) -{ - if (check_inhabitant) - { - struct Thing * t = world.things; - for (; t; t = t->next) - { - if (t->lifepoints && pos == t->pos.y * world.map.length + t->pos.x) - { - return kill_score; - } - } - } - return score_map[pos]; -} - - - -static void get_neighbor_scores(uint16_t * score_map, uint16_t pos_i, - uint16_t kill_score, uint16_t * neighbors, - uint8_t check_inhabitants) -{ - uint32_t map_size = world.map.length * world.map.length; - uint8_t open_north = pos_i >= world.map.length; - uint8_t open_east = pos_i + 1 % world.map.length; - uint8_t open_south = pos_i + world.map.length < map_size; - uint8_t open_west = pos_i % world.map.length; - uint8_t is_indented = (pos_i / world.map.length) % 2; - uint8_t open_diag_west = is_indented || open_west; - uint8_t open_diag_east = !is_indented || open_east; - neighbors[0] = !(open_north && open_diag_east) ? kill_score : - set_neighbor_val(score_map, check_inhabitants, kill_score, - pos_i - world.map.length + is_indented); - neighbors[1] = !(open_east) ? kill_score : - set_neighbor_val(score_map, check_inhabitants, kill_score, - pos_i + 1); - neighbors[2] = !(open_south && open_diag_east) ? kill_score : - set_neighbor_val(score_map, check_inhabitants, kill_score, - pos_i + world.map.length + is_indented); - neighbors[3] = !(open_south && open_diag_west) ? kill_score : - set_neighbor_val(score_map, check_inhabitants, kill_score, - pos_i + world.map.length - !is_indented); - neighbors[4] = !(open_west) ? kill_score : - set_neighbor_val(score_map, check_inhabitants, kill_score, - pos_i - 1); - neighbors[5] = !(open_north && open_diag_west) ? kill_score : - set_neighbor_val(score_map, check_inhabitants, kill_score, - pos_i - world.map.length - !is_indented); -} - - - -static void dijkstra_map(uint16_t * score_map, uint16_t max_score) -{ - uint32_t map_size = world.map.length * world.map.length; - uint32_t pos; - uint16_t i_scans, neighbors[N_DIRS], min_neighbor; - uint8_t scores_still_changing = 1; - uint8_t i_dirs; - for (i_scans = 0; scores_still_changing; i_scans++) - { - scores_still_changing = 0; - for (pos = 0; pos < map_size; pos++) - { - if (score_map[pos] <= max_score) - { - get_neighbor_scores(score_map, pos, max_score, neighbors, 0); - min_neighbor = max_score; - for (i_dirs = 0; i_dirs < N_DIRS; i_dirs++) - { - if (min_neighbor > neighbors[i_dirs]) - { - min_neighbor = neighbors[i_dirs]; - } - } - if (score_map[pos] > min_neighbor + 1) - { - score_map[pos] = min_neighbor + 1; - scores_still_changing = 1; - } - } - } - } -} - - - -static uint8_t score_map_filter_attack(uint8_t filter, uint16_t * score_map, - struct Thing * t_eye) -{ - if ('a' != filter) - { - return 0; - } - struct Thing * t = world.things; - for (; t; t = t->next) - { - if ( t != t_eye && t->lifepoints && t->type != t_eye->type - && 'v' == t_eye->fov_map[t->pos.y*world.map.length + t->pos.x] - && get_thing_type(t->type)->lifepoints < t_eye->lifepoints) - { - score_map[t->pos.y * world.map.length + t->pos.x] = 0; - } - else if (t->type == t_eye->type) - { - score_map[t->pos.y * world.map.length + t->pos.x] = UINT16_MAX; - } - } - return 1; -} - - - -static uint8_t score_map_filter_flee(uint8_t filter, uint16_t * score_map, - struct Thing * t_eye) -{ - if ('f' != filter) - { - return 0; - } - struct Thing * t = world.things; - for (; t; t = t->next) - { - if ( t->lifepoints && t->type != t_eye->type - && 'v' == t_eye->fov_map[t->pos.y*world.map.length + t->pos.x] - && get_thing_type(t->type)->lifepoints >= t_eye->lifepoints) - { - score_map[t->pos.y * world.map.length + t->pos.x] = 0; - } - } - return 1; -} - - - -static uint8_t score_map_filter_consume(uint8_t filter, uint16_t * score_map, - struct Thing * t_eye) -{ - if ('c' != filter) - { - return 0; - } - struct ThingInMemory * tm = t_eye->t_mem; - for (; tm; tm = tm->next) - { - if ( ' ' != t_eye->mem_map[tm->pos.y * world.map.length + tm->pos.x] - && get_thing_type(tm->type)->consumable) - { - score_map[tm->pos.y * world.map.length + tm->pos.x] = 0; - } - } - return 1; -} - - - -static uint8_t score_map_filter_search(uint8_t filter, uint16_t * score_map, - struct Thing * t_eye) -{ - if (!(('0' < filter && '9' >= filter) || ' ' == filter)) - { - return 0; - } - uint32_t i; - for (i = 0; i < (uint32_t) (world.map.length * world.map.length); i++) - { - score_map[i] = filter == t_eye->mem_depth_map[i] ? 0 : score_map[i]; - } - return 1; -} - - - -static void init_score_map(char filter, uint16_t * score_map, uint32_t map_size, - struct Thing * t_eye) -{ - uint32_t i; - for (i = 0; i < map_size; i++) - { - score_map[i] = UINT16_MAX; - if ('.' == t_eye->mem_map[i]) - { - score_map[i] = UINT16_MAX-1; - } - } - if ( score_map_filter_attack(filter, score_map, t_eye) - || score_map_filter_flee(filter, score_map, t_eye) - || score_map_filter_consume(filter, score_map, t_eye) - || score_map_filter_search(filter, score_map, t_eye)) - { - } -} - - -static char rand_target_dir(char * dirs, uint16_t cmp, uint16_t * targets) -{ - char candidates[N_DIRS]; - uint8_t n_candidates = 0; - uint8_t i; - for (i = 0; i < N_DIRS; i++) - { - if (cmp == targets[i]) - { - candidates[n_candidates] = dirs[i]; - n_candidates++; - } - } - return n_candidates ? candidates[rrand() % n_candidates] : 0; -} - - - -static char get_dir_from_neighbors(char filter, struct Thing * t_eye, - uint16_t * score_map) -{ - char dir_to_nearest_target = 0; - uint16_t pos_i = (t_eye->pos.y * world.map.length) + t_eye->pos.x; - char * dirs = "edcxsw"; /* get_neighbor_scores()'s clockwise dir order. */ - uint16_t neighbors[N_DIRS]; - get_neighbor_scores(score_map, pos_i, UINT16_MAX, neighbors, 'f'==filter); - uint16_t minmax_start = 'f' == filter ? 0 : UINT16_MAX-1; - uint16_t minmax_neighbor = minmax_start; - uint8_t i; - for (i = 0; i < N_DIRS; i++) - { - if ( ( 'f' == filter && score_map[pos_i] < neighbors[i] - && minmax_neighbor < neighbors[i] && UINT16_MAX != neighbors[i]) - || ('f' != filter && minmax_neighbor > neighbors[i])) - { - minmax_neighbor = neighbors[i]; - } - } - if (minmax_neighbor != minmax_start) - { - dir_to_nearest_target = rand_target_dir(dirs,minmax_neighbor,neighbors); - } - if ('f' == filter) - { - if (!dir_to_nearest_target) - { - if (1 == score_map[pos_i]) /* Attack if cornered too closely. */ - { - dir_to_nearest_target = rand_target_dir(dirs, 0, neighbors); - } - else if (3 >= score_map[pos_i]) /* If less closely, just wait. */ - { - t_eye->command = get_thing_action_id_by_name(s[S_CMD_WAIT]); - return 1; - } - } - else if (dir_to_nearest_target && 3 < score_map[pos_i]) /* Don't flee */ - { /* enemy of */ - dir_to_nearest_target = 0; /* a certain */ - } /* distance. */ - } - else if ('a' == filter && 10 <= score_map[pos_i]) - { - dir_to_nearest_target = 0; - } - return dir_to_nearest_target; -} - - - -static uint8_t get_dir_to_nearest_target(struct Thing * t_eye, char filter) -{ - char dir_to_nearest_target = 0; - uint8_t mem_depth_char = ' '; - uint8_t run_i = 's' == filter ? 9 /* max explored mem depth age */ + 1 : 1; - while ( run_i && !dir_to_nearest_target - && ('s' == filter || seeing_thing(t_eye, filter))) - { - run_i--; - uint32_t map_size = world.map.length * world.map.length; - uint16_t * score_map = try_malloc(map_size * sizeof(uint16_t),__func__); - init_score_map('s' == filter ? mem_depth_char : filter, - score_map, map_size, t_eye); - mem_depth_char = ' ' == mem_depth_char ? '9' : mem_depth_char - 1; - dijkstra_map(score_map, UINT16_MAX-1); - dir_to_nearest_target = get_dir_from_neighbors(filter,t_eye,score_map); - free(score_map); - if (dir_to_nearest_target && 1 != dir_to_nearest_target) - { - t_eye->command = get_thing_action_id_by_name(s[S_CMD_MOVE]); - t_eye->arg = dir_to_nearest_target; - } - } - return dir_to_nearest_target; -} - - - -static uint8_t seeing_thing(struct Thing * t_eye, char filter) -{ - if (t_eye->fov_map && ('a' == filter || 'f' == filter)) - { - struct Thing * t = world.things; - for (; t; t = t->next) - { - if ( t != t_eye && t->lifepoints && t->type != t_eye->type - && 'v' == t_eye->fov_map[t->pos.y*world.map.length + t->pos.x]) - { - struct ThingType * tt = get_thing_type(t->type); - if ( ('f' == filter && tt->lifepoints >= t_eye->lifepoints) - || ('a' == filter && tt->lifepoints < t_eye->lifepoints)) - { - return 1; - } - } - } - } - else if (t_eye->mem_map && 'c' == filter) - { - struct ThingInMemory * tm = t_eye->t_mem; - for (; tm; tm = tm->next) - { - if ( ' ' != t_eye->mem_map[tm->pos.y*world.map.length+tm->pos.x] - && get_thing_type(tm->type)->consumable) - { - return 1; - } - } - } - return 0; -} - - - -static int16_t get_inventory_slot_to_consume(struct Thing * t_owner) -{ - uint8_t compare_consumability = 0; - int16_t selection = -1; - struct Thing * t = t_owner->owns;; - uint8_t i; - for (i = 0; t; t = t->next, i++) - { - struct ThingType * tt = get_thing_type(t->type); - if (tt->consumable > compare_consumability) - { - compare_consumability = tt->consumable; - selection = i; - } - } - return selection; -} - - - -static uint8_t standing_on_consumable(struct Thing * t_standing) -{ - struct Thing * t = world.things; - for (; t; t = t->next) - { - if ( t != t_standing - && t->pos.y == t_standing->pos.y && t->pos.x == t_standing->pos.x - && get_thing_type(t->type)->consumable) - { - return 1; - } - } - return 0; -} - - - -extern void ai(struct Thing * t) -{ - t->command = get_thing_action_id_by_name(s[S_CMD_WAIT]); - if (!get_dir_to_nearest_target(t, 'f')) - { - int16_t sel = get_inventory_slot_to_consume(t); - if (-1 != sel) - { - t->command = get_thing_action_id_by_name(s[S_CMD_USE]); - t->arg = (uint8_t) sel; - } - else if (standing_on_consumable(t)) - { - t->command = get_thing_action_id_by_name(s[S_CMD_PICKUP]); - } - else if ( !get_dir_to_nearest_target(t, 'c') - && !get_dir_to_nearest_target(t, 'a')) - { - get_dir_to_nearest_target(t, 's'); - } - } -} diff --git a/src/server/ai.h b/src/server/ai.h deleted file mode 100644 index 966edd5..0000000 --- a/src/server/ai.h +++ /dev/null @@ -1,30 +0,0 @@ -/* src/server/ai.h - * - * This file is part of PlomRogue. PlomRogue is licensed under the GPL version 3 - * or any later version. For details on its copyright, license, and warranties, - * see the file NOTICE in the root directory of the PlomRogue source package. - * - * Pseudo AI for actor movement. - */ - -#ifndef AI_H -#define AI_H - -struct Thing; - - - -/* Determine next non-player actor command / arguments by the actor's AI. Actors - * will look for, and move towards, enemies (animate things not of their own - * type); if they see none, they will consume consumables in their inventory; if - * there are none, they will pick up any consumables they stand on; if they - * stand on none, they will move towards the next consumable they see or - * remember on the map; if they see or remember none, they'll explore parts of - * the map unseen since ever or for at least one turn; if there is nothing to - * explore, they will simply wait. - */ -extern void ai(struct Thing * t); - - - -#endif diff --git a/src/server/cleanup.c b/src/server/cleanup.c deleted file mode 100644 index ec8017d..0000000 --- a/src/server/cleanup.c +++ /dev/null @@ -1,70 +0,0 @@ -/* src/server/cleanup.c - * - * This file is part of PlomRogue. PlomRogue is licensed under the GPL version 3 - * or any later version. For details on its copyright, license, and warranties, - * see the file NOTICE in the root directory of the PlomRogue source package. - */ - -#include "cleanup.h" -#include <stdint.h> /* uint32_t */ -#include <stdlib.h> /* free() */ -#include <unistd.h> /* unlink() */ -#include "../common/readwrite.h" /* try_fclose() */ -#include "hardcoded_strings.h" /* s */ -#include "thing_actions.h" /* free_thing_actions() */ -#include "things.h" /* free_things(), free_thing_types() */ -#include "world.h" /* global world */ - - - - -/* The clean-up flags set by set_cleanup_flag(). */ -static uint32_t cleanup_flags = 0x0000; - - - -extern void cleanup() -{ - free(world.queue); - free(world.map.cells); - if (cleanup_flags & CLEANUP_WORLDSTATE) - { - unlink(s[S_PATH_WORLDSTATE]); - } - if (cleanup_flags & CLEANUP_THINGS) - { - free_things(world.things); - } - if (cleanup_flags & CLEANUP_THING_TYPES) - { - free_thing_types(world.thing_types); - } - if (cleanup_flags & CLEANUP_THING_ACTIONS) - { - free_thing_actions(world.thing_actions); - } - if (cleanup_flags & CLEANUP_IN) - { - try_fclose(world.file_in, __func__); - unlink(s[S_PATH_IN]); - } - if (cleanup_flags & CLEANUP_OUT) - { - try_fclose(world.file_out, __func__); - free(world.server_test); - unlink(s[S_PATH_OUT]); - } -} - - -extern void set_cleanup_flag(enum cleanup_flag flag) -{ - cleanup_flags = cleanup_flags | flag; -} - - - -extern void unset_cleanup_flag(enum cleanup_flag flag) -{ - cleanup_flags = cleanup_flags ^ flag; -} diff --git a/src/server/cleanup.h b/src/server/cleanup.h deleted file mode 100644 index 2047510..0000000 --- a/src/server/cleanup.h +++ /dev/null @@ -1,39 +0,0 @@ -/* src/server/cleanup.h - * - * This file is part of PlomRogue. PlomRogue is licensed under the GPL version 3 - * or any later version. For details on its copyright, license, and warranties, - * see the file NOTICE in the root directory of the PlomRogue source package. - * - * Stuff defining / performing the cleanup called by rexit.h's exit functions. - */ - -#ifndef CLEANUP_H -#define CLEANUP_H - - - -/* set_cleanup_flag() sets any of the flags defined in cleanup_flag to announce - * the resources that need cleaning up upon program exit. It is to be called at - * the earliest moment possible after resource creation / initialization. - */ -enum cleanup_flag -{ - CLEANUP_FIFO = 0x0001, - CLEANUP_WORLDSTATE = 0x0002, - CLEANUP_THING_TYPES = 0x0004, - CLEANUP_THINGS = 0x0008, - CLEANUP_THING_ACTIONS = 0x0010, - CLEANUP_IN = 0x0020, - CLEANUP_OUT = 0x0040 -}; - -/* In addition, unset_cleanup_flag() may be used to unset flags. */ -extern void set_cleanup_flag(enum cleanup_flag flag); -extern void unset_cleanup_flag(enum cleanup_flag flag); - -/* Frees memory and unlinks some files. */ -extern void cleanup(); - - - -#endif diff --git a/src/server/field_of_view.c b/src/server/field_of_view.c deleted file mode 100644 index 45c90e6..0000000 --- a/src/server/field_of_view.c +++ /dev/null @@ -1,381 +0,0 @@ -/* src/server/field_of_view.c - * - * This file is part of PlomRogue. PlomRogue is licensed under the GPL version 3 - * or any later version. For details on its copyright, license, and warranties, - * see the file NOTICE in the root directory of the PlomRogue source package. - */ - -#include "field_of_view.h" -#include <math.h> /* pow() */ -#include <stddef.h> /* NULL */ -#include <stdint.h> /* uint8_t, uint16_t, uint32_t, int32_t, UINT8_MAX */ -#include <stdlib.h> /* free() */ -#include <string.h> /* memset() */ -#include "../common/rexit.h" /* exit_trouble() */ -#include "../common/try_malloc.h" /* try_malloc() */ -#include "../common/yx_uint8.h" /* yx_uint8 */ -#include "map.h" /* mv_yx_in_dir_legal(), init_empty_map() */ -#include "rrand.h" /* rrand() */ -#include "things.h" /* Thing, ThingInMemory, add_thing_to_memory_map() */ -#include "world.h" /* world */ - - - -/* Number of degrees a circle is divided into. The greater it is, the greater - * the angle precision. But make it one whole zero larger and bizarre FOV bugs - * appear on large maps, probably due to value overflows (TODO: more research!). - */ -#define CIRCLE 3600000 - - - -/* Angle of a shadow. */ -struct shadow_angle -{ - struct shadow_angle * next; - uint32_t left_angle; - uint32_t right_angle; -}; - - - -/* Recalculate angle < 0 or > CIRCLE to a value between these two limits. */ -static uint32_t correct_angle(int32_t angle); - -/* Try merging the angle between "left_angle" and "right_angle" to "shadow" if - * it meets the shadow from the right or the left. Returns 1 on success, else 0. - */ -static uint8_t try_merge(struct shadow_angle * shadow, - uint32_t left_angle, uint32_t right_angle); - -/* Try merging the shadow angle between "left_angle" and "right_angle" into an - * existing shadow angle in "shadows". On success, see if this leads to any - * additional shadow angle overlaps and merge these accordingly. Return 1 on - * success, else 0. - */ -static uint8_t try_merging_angles(uint32_t left_angle, uint32_t right_angle, - struct shadow_angle ** shadows); - -/* Test whether angle between "left_angle" and "right_angle", or at least - * "middle_angle", is captured inside one of the shadow angles in "shadows". If - * so, set hex in "fov_map" indexed by "pos_in_map" to 'H'. If the whole angle - * and not just "middle_angle" is captured, return 1. Any other case: 0. - */ -static uint8_t shade_hex(uint32_t left_angle, uint32_t right_angle, - uint32_t middle_angle, struct shadow_angle ** shadows, - uint16_t pos_in_map, char * fov_map); - -/* To "shadows", add shadow defined by "left_angle" and "right_angle", either as - * new entry or as part of an existing shadow (swallowed whole or extending it). - */ -static void set_shadow(uint32_t left_angle, uint32_t right_angle, - struct shadow_angle ** shadows); - -/* Free shadow angles list "angles". */ -static void free_angles(struct shadow_angle * angles); - -/* Evaluate map position "test_pos" in distance "dist" to the view origin, and - * on the circle of that distance to the origin on hex "hex_i" (as counted from - * the circle's rightmost point), for setting shaded hexes in "fov_map" and - * potentially adding a new shadow to linked shadow angle list "shadows". - */ -static void eval_position(uint16_t dist, uint16_t hex_i, char * fov_map, - struct yx_uint8 * test_pos, - struct shadow_angle ** shadows); - -/* Update "t_eye"'s things-on-map memory by removing from its .t_mem all - * memorized thing in FOV, and adding inanimate things in FOV to it. - */ -static void add_things_to_map_memory(struct Thing * t_eye); - - - -static uint32_t correct_angle(int32_t angle) -{ - while (angle < 0) - { - angle = angle + CIRCLE; - } - while (angle > CIRCLE) - { - angle = angle - CIRCLE; - } - return angle; -} - - - -static uint8_t try_merge(struct shadow_angle * shadow, - uint32_t left_angle, uint32_t right_angle) -{ - if ( shadow->right_angle <= left_angle + 1 - && shadow->right_angle >= right_angle) - { - shadow->right_angle = right_angle; - } - else if ( shadow->left_angle + 1 >= right_angle - && shadow->left_angle <= left_angle) - { - shadow->left_angle = left_angle; - } - else - { - return 0; - } - return 1; -} - - - -static uint8_t try_merging_angles(uint32_t left_angle, uint32_t right_angle, - struct shadow_angle ** shadows) -{ - uint8_t angle_merge = 0; - struct shadow_angle * shadow; - for (shadow = *shadows; shadow; shadow = shadow->next) - { - if (try_merge(shadow, left_angle, right_angle)) - { - angle_merge = 1; - } - } - if (angle_merge) - { - struct shadow_angle * shadow1; - for (shadow1 = *shadows; shadow1; shadow1 = shadow1->next) - { - struct shadow_angle * last_shadow = NULL; - struct shadow_angle * shadow2; - for (shadow2 = *shadows; shadow2; shadow2 = shadow2->next) - { - if ( shadow1 != shadow2 - && try_merge(shadow1, shadow2->left_angle, - shadow2->right_angle)) - { - struct shadow_angle * to_free = shadow2; - if (last_shadow) - { - last_shadow->next = shadow2->next; - shadow2 = last_shadow; - } - else - { - *shadows = shadow2->next; - shadow2 = *shadows; - } - free(to_free); - } - last_shadow = shadow2; - } - } - } - return angle_merge; -} - - - -static uint8_t shade_hex(uint32_t left_angle, uint32_t right_angle, - uint32_t middle_angle, struct shadow_angle ** shadows, - uint16_t pos_in_map, char * fov_map) -{ - struct shadow_angle * shadow_i; - if (fov_map[pos_in_map] == 'v') - { - for (shadow_i = *shadows; shadow_i; shadow_i = shadow_i->next) - { - if ( left_angle <= shadow_i->left_angle - && right_angle >= shadow_i->right_angle) - { - fov_map[pos_in_map] = 'H'; - return 1; - } - if ( middle_angle < shadow_i->left_angle - && middle_angle > shadow_i->right_angle) - { - fov_map[pos_in_map] = 'H'; - } - } - } - return 0; -} - - - -static void set_shadow(uint32_t left_angle, uint32_t right_angle, - struct shadow_angle ** shadows) -{ - struct shadow_angle * shadow_i; - if (!try_merging_angles(left_angle, right_angle, shadows)) - { - struct shadow_angle * shadow; - shadow = try_malloc(sizeof(struct shadow_angle), __func__); - shadow->left_angle = left_angle; - shadow->right_angle = right_angle; - shadow->next = NULL; - if (*shadows) - { - for (shadow_i = *shadows; shadow_i; shadow_i = shadow_i->next) - { - if (!shadow_i->next) - { - shadow_i->next = shadow; - return; - } - } - } - *shadows = shadow; - } -} - - - -static void free_angles(struct shadow_angle * angles) -{ - if (angles->next) - { - free_angles(angles->next); - } - free(angles); -} - - - -static void eval_position(uint16_t dist, uint16_t hex_i, char * fov_map, - struct yx_uint8 * test_pos, - struct shadow_angle ** shadows) -{ - int32_t left_angle_uncorrected = ((CIRCLE / 12) / dist) - - (hex_i * (CIRCLE / 6) / dist); - int32_t right_angle_uncorrected = left_angle_uncorrected - - (CIRCLE / (6 * dist)); - uint32_t left_angle = correct_angle(left_angle_uncorrected); - uint32_t right_angle = correct_angle(right_angle_uncorrected); - uint32_t right_angle_1st = right_angle > left_angle ? 0 : right_angle; - uint32_t middle_angle = 0; - if (right_angle_1st) - { - middle_angle = right_angle + ((left_angle - right_angle) / 2); - } - uint16_t pos_in_map = test_pos->y * world.map.length + test_pos->x; - uint8_t all_shaded = shade_hex(left_angle, right_angle_1st, middle_angle, - shadows, pos_in_map, fov_map); - if (!all_shaded && 'X' == world.map.cells[pos_in_map]) - { - set_shadow(left_angle, right_angle_1st, shadows); - if (right_angle_1st != right_angle) - { - left_angle = CIRCLE; - set_shadow(left_angle, right_angle, shadows); - } - } -} - - - -static void add_things_to_map_memory(struct Thing * t_eye) -{ - struct ThingInMemory * tm = t_eye->t_mem; - struct ThingInMemory * tm_prev = NULL; - struct ThingInMemory * tm_next = NULL; - for (; tm; tm = tm_next) - { - tm_next = tm->next; - if ('v' == t_eye->fov_map[tm->pos.y * world.map.length + tm->pos.x]) - { - if (tm_prev) - { - tm_prev->next = tm->next; - } - else - { - t_eye->t_mem = tm->next; - } - free(tm); - continue; - } - tm_prev = tm; - } - struct Thing * t = world.things; - for (; t; t = t->next) - { - if ( !t->lifepoints - && 'v' == t_eye->fov_map[t->pos.y * world.map.length + t->pos.x]) - { - add_thing_to_memory_map(t_eye, t->type, t->pos.y, t->pos.x); - } - } -} - - - -extern void update_map_memory(struct Thing * t_eye, uint8_t age_map) -{ - if (!t_eye->mem_map) - { - init_empty_map(&(t_eye->mem_map)); - } - if (!t_eye->mem_depth_map) - { - init_empty_map(&(t_eye->mem_depth_map)); - } - uint32_t i; - for (i = 0; i < (uint32_t) (world.map.length * world.map.length); i++) - { - if ('v' == t_eye->fov_map[i]) - { - t_eye->mem_depth_map[i] = '0'; - if (' ' == t_eye->mem_map[i]) - { - t_eye->mem_map[i] = world.map.cells[i]; - } - continue; - } - if (age_map && - '0' <= t_eye->mem_depth_map[i] && '9' > t_eye->mem_depth_map[i] - && !(rrand() % (uint16_t) pow(2, t_eye->mem_depth_map[i] - 48))) - { - t_eye->mem_depth_map[i]++; - } - } - add_things_to_map_memory(t_eye); -} - - - -extern void build_fov_map(struct Thing * t) -{ - uint32_t map_size = world.map.length * world.map.length; - t->fov_map = t->fov_map ? t->fov_map : try_malloc(map_size, __func__); - memset(t->fov_map, 'v', map_size); - struct shadow_angle * shadows = NULL; - struct yx_uint8 test_pos = t->pos; - char * circledirs_string = "xswedc"; - uint16_t circle_i; - uint8_t circle_is_on_map; - for (circle_i = 1, circle_is_on_map = 1; circle_is_on_map; circle_i++) - { - circle_is_on_map = 0; - if (1 < circle_i) /* All circles but the 1st are */ - { /* moved into starting from a */ - mv_yx_in_dir_legal('c', &test_pos);/* previous circle's last hex, */ - } /* i.e. from the upper left. */ - char dir_char = 'd'; /* Circle's 1st hex is entered by rightward move.*/ - uint8_t dir_char_pos_in_circledirs_string = UINT8_MAX; - uint16_t dist_i, hex_i; - for (hex_i=0, dist_i=circle_i; hex_i < 6 * circle_i; dist_i++, hex_i++) - { - if (circle_i < dist_i) - { - dist_i = 1; - dir_char=circledirs_string[++dir_char_pos_in_circledirs_string]; - } - if (mv_yx_in_dir_legal(dir_char, &test_pos)) - { - eval_position(circle_i, hex_i, t->fov_map, &test_pos, &shadows); - circle_is_on_map = 1; - } - } - } - mv_yx_in_dir_legal(0, NULL); - free_angles(shadows); -} diff --git a/src/server/field_of_view.h b/src/server/field_of_view.h deleted file mode 100644 index be6324b..0000000 --- a/src/server/field_of_view.h +++ /dev/null @@ -1,28 +0,0 @@ -/* src/server/field_of_view.h - * - * This file is part of PlomRogue. PlomRogue is licensed under the GPL version 3 - * or any later version. For details on its copyright, license, and warranties, - * see the file NOTICE in the root directory of the PlomRogue source package. - * - * Generate field of view maps. - */ - -#ifndef FIELD_OF_VIEW_H -#define FIELD_OF_VIEW_H - -#include <stdint.h> /* uint8_t, uint32_t */ -struct Thing; - - - -/* Update "t_eye"'s .mem_map memory with what's in its current FOV, and update - * and age the .mem_depth_map. - */ -extern void update_map_memory(struct Thing * t_eye, uint8_t age_map); - -/* Build "t"'s field of view. */ -extern void build_fov_map(struct Thing * t); - - - -#endif diff --git a/src/server/god_commands.c b/src/server/god_commands.c deleted file mode 100644 index 0dbf1a3..0000000 --- a/src/server/god_commands.c +++ /dev/null @@ -1,524 +0,0 @@ -/* src/server/god_commands.c - * - * This file is part of PlomRogue. PlomRogue is licensed under the GPL version 3 - * or any later version. For details on its copyright, license, and warranties, - * see the file NOTICE in the root directory of the PlomRogue source package. - */ - -#include "god_commands.h" -#include <stddef.h> /* NULL */ -#include <stdint.h> /* uint8_t */ -#include <stdlib.h> /* atoi(), free() */ -#include <string.h> /* strcmp(), memset(), memcpy() */ -#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 "../common/try_malloc.h" /* try_malloc() */ -#include "cleanup.h" /* unset_cleanup_flag() */ -#include "field_of_view.h" /* build_fov_map(), update_map_memory() */ -#include "hardcoded_strings.h" /* s */ -#include "init.h" /* remake_world() */ -#include "map.h" /* init_empty_map(), 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(), add_thing_to_memory_map(),get_thing_type(), - * get_player() - */ -#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_1arg(char * tok0, char * tok1); - -/* Performs parse_world_active()'s world activation legality tests. */ -static uint8_t world_may_be_set_active(); - -/* Unlink worldstate file if it exists. */ -static void remove_worldstate_file(); - -/* 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); - - - -/* Thing, ThingType or ThingAction selected to be manipulated. */ -static struct Thing * t = NULL; -static struct ThingType * tt = NULL; -static struct ThingAction * ta = NULL; - - - -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]) - || !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."); - } - int16_t id; - if ( parse_val(tok0,tok1,s[S_CMD_TT_CONSUM],'u',(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_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)) - { - if (!get_thing_type(id)) - { - return err_line(1, "Corpse ID belongs to no known thing type."); - } - tt->corpse_id = id; - } - else if (parse_val(tok0, tok1, s[S_CMD_TT_ID], 'i', (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) -{ - if (!ta && - (!strcmp(tok0, s[S_CMD_TA_EFFORT]) || !strcmp(tok0, s[S_CMD_TA_NAME]))) - { - return err_line(1, "No thing action defined to manipulate yet."); - } - int16_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))) - { - return err_line(1, "Invalid action function name."); - } - if (world.exists) - { /* Legal worlds have at least one thing action for waiting. */ - world.exists = 0 != get_thing_action_id_by_name(s[S_CMD_WAIT]); - if (!world.exists) - { - remove_worldstate_file(); - } - } - } - else if (parse_val(tok0, tok1, s[S_CMD_TA_ID], '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; - } - if (world.exists && t->lifepoints) - { - build_fov_map(t); - if (t == get_player()) - { - update_map_memory(t, 1); - } - } - } - 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_1arg(char * tok0, char * tok1) -{ - 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]) - || !strcmp(tok0, s[S_CMD_T_SATIATION]))) - { - return err_line(1, "No thing defined to manipulate yet."); - } - int16_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_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)) - { - t = get_thing(world.things, id, 1); - char * err = "No thing type found to initialize new thing."; - if (!t && !err_line(!world.thing_types, err)) - { - t = add_thing(id, world.thing_types->id, 0, 0); - } - } - 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 void remove_worldstate_file() -{ - if (!access(s[S_PATH_WORLDSTATE], F_OK)) - { - int test = unlink(s[S_PATH_WORLDSTATE]); - exit_trouble(-1 == test, __func__, "unlink"); - } -} - - - -static uint8_t parse_world_active(char * tok0, char * tok1) -{ - if (!strcmp(tok0, s[S_CMD_WORLD_ACTIVE]) && !parsetest_int(tok1, '8')) - { - if (!parsetest_int(tok1, '8')) - { - uint8_t argument = atoi(tok1); - if (!argument) - { - remove_worldstate_file(); - 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) - { - build_fov_map(ti); - if (ti == get_player()) - { - update_map_memory(ti, 0); - } - } - } - 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) - { - return err_line(1, "Value must be >= 1 and <= 256."); - } - world.exists = 0; - remove_worldstate_file(); - 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_1arg(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; -} - - - -extern uint8_t parse_god_command_2arg(char * tok0, char * tok1, char * tok2) -{ - if (!t && ( !strcmp(tok0, s[S_CMD_T_MEMMAP]) - || !strcmp(tok0, s[S_CMD_T_MEMDEPTHMAP]))) - { - return err_line(1, "No thing defined to manipulate yet."); - } - if (!strcmp(tok0,s[S_CMD_T_MEMMAP]) || !strcmp(tok0,s[S_CMD_T_MEMDEPTHMAP])) - { - uint8_t y = atoi(tok1); - if (parsetest_int(tok1, '8') || y >= world.map.length) - { - return err_line(1, "Illegal value for map line number."); - } - if (strlen(tok2) != world.map.length) - { - return err_line(1, "Map line length is unequal map width."); - } - if (!strcmp(tok0,s[S_CMD_T_MEMMAP])) - { - if (!t->mem_map) - { - init_empty_map(&(t->mem_map)); - } - memcpy(t->mem_map + y * world.map.length, tok2, world.map.length); - } - else - { - if (!t->mem_depth_map) - { - init_empty_map(&(t->mem_depth_map)); - } - memcpy(t->mem_depth_map+y*world.map.length, tok2, world.map.length); - } - } - else - { - return 0; - } - return 1; -} - - - -extern uint8_t parse_god_command_3arg(char * tok0, char * tok1, char * tok2, - char * tok3) -{ - if (!t && !strcmp(tok0, s[S_CMD_T_MEMTHING])) - { - return err_line(1, "No thing defined to manipulate yet."); - } - if (!strcmp(tok0, s[S_CMD_T_MEMTHING])) - { - uint8_t id = atoi(tok1); - uint8_t y = atoi(tok2); - uint8_t x = atoi(tok3); - if ( parsetest_int(tok1, '8') || !get_thing_type(id) - || parsetest_int(tok2, '8') || y >= world.map.length - || parsetest_int(tok3, '8') || x >= world.map.length) - { - return err_line(1, "Illegal value for thing type or position."); - } - add_thing_to_memory_map(t, id, y, x); - } - else - { - return 0; - } - return 1; -} diff --git a/src/server/god_commands.h b/src/server/god_commands.h deleted file mode 100644 index bfe7454..0000000 --- a/src/server/god_commands.h +++ /dev/null @@ -1,25 +0,0 @@ -/* src/server/god_commands.h - * - * This file is part of PlomRogue. PlomRogue is licensed under the GPL version 3 - * or any later version. For details on its copyright, license, and warranties, - * see the file NOTICE in the root directory of the PlomRogue source package. - * - * 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", "tok2" etc. . */ -extern uint8_t parse_god_command_1arg(char * tok0, char * tok1); -extern uint8_t parse_god_command_2arg(char * tok0, char * tok1, char * tok2); -extern uint8_t parse_god_command_3arg(char * tok0, char * tok1, char * tok2, - char * tok3); - - - -#endif diff --git a/src/server/hardcoded_strings.c b/src/server/hardcoded_strings.c deleted file mode 100644 index dfb30e1..0000000 --- a/src/server/hardcoded_strings.c +++ /dev/null @@ -1,62 +0,0 @@ -/* hardcoded_strings.c * - * - * This file is part of PlomRogue. PlomRogue is licensed under the GPL version 3 - * or any later version. For details on its copyright, license, and warranties, - * see the file NOTICE in the root directory of the PlomRogue source package. - */ - -#include "hardcoded_strings.h" - - - -char * s[44]; - - - -extern void init_strings() -{ - s[S_PATH_CONFIG] = "confserver/world"; - s[S_PATH_WORLDSTATE] = "server/worldstate"; - s[S_PATH_OUT] = "server/out"; - s[S_PATH_IN] = "server/in"; - s[S_PATH_RECORD] = "record"; - s[S_PATH_SAVE] = "savefile"; - s[S_FCN_SPRINTF] = "sprintf"; - s[S_CMD_TA_ID] = "TA_ID"; - s[S_CMD_TA_EFFORT] = "TA_EFFORT"; - s[S_CMD_TA_NAME] = "TA_NAME"; - s[S_CMD_TT_ID] = "TT_ID"; - 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_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_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_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[S_CMD_T_MEMTHING] = "T_MEMTHING"; - s[S_CMD_AI] = "ai"; - 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_CMD_MAKE_WORLD] = "MAKE_WORLD"; - 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_MAPLENGTH] = "MAP_LENGTH"; - s[S_CMD_PLAYTYPE] = "PLAYER_TYPE"; -} diff --git a/src/server/hardcoded_strings.h b/src/server/hardcoded_strings.h deleted file mode 100644 index 4725bc2..0000000 --- a/src/server/hardcoded_strings.h +++ /dev/null @@ -1,69 +0,0 @@ -/* hardcoded_strings.h - * - * This file is part of PlomRogue. PlomRogue is licensed under the GPL version 3 - * or any later version. For details on its copyright, license, and warranties, - * see the file NOTICE in the root directory of the PlomRogue source package. - * - * For re-used hardcoded strings. - */ - -#ifndef STRINGS_H -#define STRINGS_H - - - -enum string_num -{ - S_PATH_CONFIG, - S_PATH_WORLDSTATE, - S_PATH_OUT, - S_PATH_IN, - S_PATH_RECORD, - S_PATH_SAVE, - S_FCN_SPRINTF, - S_CMD_TA_ID, - S_CMD_TA_EFFORT, - S_CMD_TA_NAME, - S_CMD_TT_ID, - 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_TT_PROL, - S_CMD_T_ID, - 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_SATIATION, - S_CMD_T_CARRIES, - S_CMD_T_MEMMAP, - S_CMD_T_MEMDEPTHMAP, - S_CMD_T_MEMTHING, - S_CMD_AI, - S_CMD_WAIT, - S_CMD_MOVE, - S_CMD_PICKUP, - S_CMD_DROP, - S_CMD_USE, - S_CMD_MAKE_WORLD, - S_CMD_WORLD_ACTIVE, - S_CMD_SEED_MAP, - S_CMD_SEED_RAND, - S_CMD_TURN, - S_CMD_MAPLENGTH, - S_CMD_PLAYTYPE -}; - -extern void init_strings(); - -extern char * s[44]; - - - -#endif diff --git a/src/server/init.c b/src/server/init.c deleted file mode 100644 index f44c504..0000000 --- a/src/server/init.c +++ /dev/null @@ -1,257 +0,0 @@ -/* src/server/init.c - * - * This file is part of PlomRogue. PlomRogue is licensed under the GPL version 3 - * or any later version. For details on its copyright, license, and warranties, - * see the file NOTICE in the root directory of the PlomRogue source package. - */ - -#define _POSIX_C_SOURCE 2 /* getopt(), optarg */ -#include "init.h" -#include <errno.h> /* global errno, EEXIST */ -#include <stddef.h> /* NULL */ -#include <stdint.h> /* uint32_t */ -#include <stdio.h> /* FILE, sprintf(), fflush() */ -#include <stdlib.h> /* exit(), free(), atoi() */ -#include <string.h> /* strlen() */ -#include <sys/stat.h> /* mkdir() */ -#include <sys/types.h> /* defines pid_t, time_t */ -#include <time.h> /* time() */ -#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() - */ -#include "../common/rexit.h" /* exit_err(), exit_trouble() */ -#include "../common/try_malloc.h" /* try_malloc() */ -#include "cleanup.h" /* set_cleanup_flag() */ -#include "field_of_view.h" /* update_map_memory() */ -#include "hardcoded_strings.h" /* s */ -#include "map.h" /* remake_map() */ -#include "things.h" /* Thing, ThingType, free_things(), add_things(), - * get_thing_id_action_id_by_name(), get_player() - */ -#include "run.h" /* obey_msg(), io_loop(), record(), send_to_outfile() */ -#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) -{ - FILE * file = try_fopen(path, "r", __func__); - uint32_t linemax = textfile_width(file); - char * line = try_malloc(linemax + 1, __func__); - while (try_fgets(line, linemax + 1, file, __func__)) - { - if (strlen(line)) - { - if (strcmp("\n", line)) - { - char * nl = strchr(line, '\n'); - if (nl) - { - *nl = '\0'; - } - obey_msg(line, record); - } - err_line_inc(); - } - } - free(line); - try_fclose(file, __func__); -} - - - -static void replay_game() -{ - exit_err(access(s[S_PATH_RECORD], F_OK), "No record found to replay."); - FILE * file = try_fopen(s[S_PATH_RECORD], "r", __func__); - uint32_t linemax = textfile_width(file); - char * line = try_malloc(linemax + 1, __func__); - while ( world.turn < world.replay - && try_fgets(line, linemax + 1, file, __func__)) - { - obey_msg(line, 0); - err_line_inc(); - } - uint8_t end = 0; - while (3 == io_loop(2)) - { - if (!end) - { - end = (NULL == try_fgets(line, linemax + 1, file, __func__)); - if (!end) - { - obey_msg(line, 0); - err_line_inc(); - } - } - } - free(line); - try_fclose(file, __func__); -} - - - -static uint8_t world_cannot_be_made() -{ - uint8_t player_will_be_generated = 0; - struct ThingType * tt; - for (tt = world.thing_types; 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; - while (-1 != (opt = getopt(argc, argv, "vs::"))) - { - if ('v' == opt) - { - world.is_verbose = 1; - } - else if ('s' == opt) - { - world.replay = 1; - if (optarg) - { - world.replay = atoi(optarg); - } - } - else - { - exit(EXIT_FAILURE); - } - } -} - - - -extern void setup_server_io() -{ - int test = mkdir("server", 0777); - exit_trouble(test && EEXIST != errno, __func__, "mkdir"); - world.file_out = try_fopen(s[S_PATH_OUT], "w", __func__); - world.server_test = try_malloc(10 + 1 + 10 + 1 + 1, __func__); - test = sprintf(world.server_test, "%d %d\n", getpid(), (int) time(0)); - exit_trouble(test < 0, __func__, s[S_FCN_SPRINTF]); - try_fwrite(world.server_test, strlen(world.server_test), 1, - world.file_out, __func__); - fflush(world.file_out); - set_cleanup_flag(CLEANUP_OUT); - char * path_in = s[S_PATH_IN]; - if (!access(path_in, F_OK)) /* This keeps out input from old input */ - { /* file streams of clients */ - unlink(path_in) ; /* communicating with server processes */ - } /* superseded by this current one. */ - world.file_in = try_fopen(path_in, "w", __func__); - try_fclose(world.file_in, __func__); - world.file_in = try_fopen(path_in, "r", __func__); - set_cleanup_flag(CLEANUP_IN); -} - - - -extern uint8_t remake_world() -{ - uint8_t test = world_cannot_be_made(); - if (test) - { - return test; - } - world.seed_map = world.seed; - free_things(world.things); - remake_map(); - world.exists = 1; - struct ThingType * tt; - for (tt = world.thing_types; tt; tt = tt->next) - { - if (world.player_type == tt->id) - { - add_things(tt->id, tt->start_n); - break; - } - } - update_map_memory(get_player(), 1); - for (tt = world.thing_types; tt; tt = tt->next) - { - if (world.player_type != tt->id) - { - add_things(tt->id, tt->start_n); - } - } - world.turn = 1; - send_to_outfile("NEW_WORLD\n", 1); - return 0; -} - - - -extern void 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; - } - if (!access(s[S_PATH_SAVE], F_OK)) - { - 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, __func__); - int test = sprintf(msg, "%s %d", command, (int) time(NULL)); - exit_trouble(test < 0, __func__, s[S_FCN_SPRINTF]); - obey_msg(msg, 1); - free(msg); - } - err_line_zero(); - io_loop(1); - record(NULL, 1); -} diff --git a/src/server/init.h b/src/server/init.h deleted file mode 100644 index 6161200..0000000 --- a/src/server/init.h +++ /dev/null @@ -1,46 +0,0 @@ -/* src/server/init.h - * - * This file is part of PlomRogue. PlomRogue is licensed under the GPL version 3 - * or any later version. For details on its copyright, license, and warranties, - * see the file NOTICE in the root directory of the PlomRogue source package. - * - * Server, world and game state initialization. - */ - -#ifndef INIT_H -#define INIT_H - -#include <stdint.h> /* uint8_t */ - - - -/* Parses command line arguments -v and -s into server configuration. */ -extern void obey_argv(int argc, char * argv[]); - -/* Start server in file and out file, latter with server process test string. */ -extern void setup_server_io(); - -/* Dissolves old game world if it exists, generates a new one from world.seed. - * 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 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 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(); - - - -#endif diff --git a/src/server/io.c b/src/server/io.c deleted file mode 100644 index 06ee838..0000000 --- a/src/server/io.c +++ /dev/null @@ -1,441 +0,0 @@ -/* src/server/io.c - * - * This file is part of PlomRogue. PlomRogue is licensed under the GPL version 3 - * or any later version. For details on its copyright, license, and warranties, - * see the file NOTICE in the root directory of the PlomRogue source package. - */ - -#define _POSIX_C_SOURCE 200112L /* snrpintf() */ -#include "io.h" -#include <errno.h> /* global errno */ -#include <limits.h> /* PIPE_BUF */ -#include <stddef.h> /* NULL */ -#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() */ -#include <sys/types.h> /* time_t */ -#include <time.h> /* time(), nanosleep() */ -#include "../common/readwrite.h" /* atomic_write_start(), atomic_write_finish(), - * get_message_from_queue(), try_fwrite(), - * read_file_into_queue(), try_fputc() - */ -#include "../common/rexit.h" /* exit_trouble() */ -#include "../common/try_malloc.h" /* try_malloc() */ -#include "cleanup.h" /* set_cleanup_flag() */ -#include "hardcoded_strings.h" /* s */ -#include "map.h" /* init_empty_map() */ -#include "run.h" /* send_to_outfile() */ -#include "things.h" /* Thing, ThingType, ThingInMemory, ThingAction, - * get_thing_type(), get_player() - */ -#include "world.h" /* global world */ - - - -/* Helpers to write lines of god commands to recreate thing "t". */ -static void write_key_space(FILE * file, char * key); -static void write_uvalue(FILE * file, uint32_t value); -static void write_string(FILE * file, char * string); -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 write_mem_map(FILE * file, char * map, char * command); - -/* Write to "file" \n-delimited line of "key" + space + "value" as string. */ -static void write_thing(FILE * file, struct Thing * t); - -/* Poll input file for world.queue input. Wait a few seconds until giving up; - * poll only every 0.03 seconds. Translate '\n' chars in input file into '\0'. - */ -static void try_growing_queue(); - -/* Write world state as visible to clients to its file. Write single dot line to - * server output file to satisfy client ping mechanisms. - */ -static void update_worldstate_file(); - -/* Write "value" to new \n-delimited line of "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); - -/* Return map cells sequence as visible to the "player", with invisible cells as - * whitespace. Super-impose over visible map cells things positioned there, - * with animate things overwriting inanimate things, and inanimate consumable - * things overwriting inanimate non-consumable things. - */ -static char * build_visible_map(struct Thing * player); - -/* Write to "file" game map as visible to "player" right now, as drawn by - * build_visible_map(), and thereafter game map as memorized by player in its - * .mem_map and .t_mem. Write one row per \n-delimited line. - */ -static void write_map(struct Thing * player, FILE * file); - - - -static void write_key_space(FILE * file, char * key) -{ - try_fwrite(key, strlen(key), 1, file, __func__); - try_fputc(' ', file, __func__); -} - - - -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]); - try_fwrite(line, strlen(line), 1, file, __func__); - free(line); -} - - - -static void write_string(FILE * file, char * string) -{ - try_fputc('\'', file, __func__); - try_fwrite(string, strlen(string), 1, file, __func__); - try_fputc('\'', file, __func__); -} - - - -static void write_key_space_uvalue(FILE * file, char * key, uint32_t value) -{ - write_key_space(file, key); - 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__); -} - - - -static void write_key_space_string(FILE * file, char * key, char * string) -{ - write_key_space(file, key); - write_string(file, string); - try_fputc('\n', file, __func__); -} - - - -static void write_mem_map(FILE * file, char * map, char * command) -{ - if (map) - { - uint32_t map_size = world.map.length * world.map.length;/* snprintf() */ - char * map_copy = try_malloc(map_size + 1, __func__); /* reads one */ - memcpy(map_copy, map, map_size); /* byte beyond map_size */ - map_copy[map_size] = '\0'; /* if string is not \0-terminated. */ - uint16_t y; - char string[UINT8_MAX + 1 + 1]; - for (y = 0; y < world.map.length; y++) - { - int test = snprintf(string, world.map.length + 1, "%s", - map_copy + (y * world.map.length)); - exit_trouble(test < 0, __func__, "snprintf()"); - write_key_space(file, command); - write_uvalue(file, y); - try_fputc(' ', file, __func__); - write_string(file, string); - try_fputc('\n', file, __func__); - } - free(map_copy); - } -} - - - -static void write_thing(FILE * file, struct Thing * t) -{ - struct Thing * o; - for (o = t->owns; o; o = o->next) - { - write_thing(file, o); - } - write_key_space_uvalue(file, s[S_CMD_T_ID], t->id); - struct ThingInMemory * tm = t->t_mem; - for (; tm; tm = tm->next) - { - write_key_space(file, s[S_CMD_T_MEMTHING]); - write_uvalue(file, tm->type); - try_fputc(' ', file, __func__); - write_uvalue(file, tm->pos.y); - try_fputc(' ', file, __func__); - write_uvalue(file, tm->pos.x); - try_fputc('\n', file, __func__); - } - write_key_space_uvalue(file, s[S_CMD_T_COMMAND], t->command); - write_key_space_uvalue(file, s[S_CMD_T_HP], t->lifepoints); - write_key_space_uvalue(file, s[S_CMD_T_TYPE], t->type); - write_key_space_uvalue(file, s[S_CMD_T_ARGUMENT], t->arg); - 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_PROGRESS], t->progress); - write_mem_map(file, t->mem_depth_map, s[S_CMD_T_MEMDEPTHMAP]); - write_key_space_svalue(file, s[S_CMD_T_SATIATION], t->satiation); - write_mem_map(file, t->mem_map, s[S_CMD_T_MEMMAP]); -} - - - -static void write_thing_carrying(FILE * file, struct Thing * t) -{ - if (t->owns) - { - write_key_space_uvalue(file, s[S_CMD_T_ID], t->id); - struct Thing * o; - for (o = t->owns; o; o = o->next) - { - write_key_space_uvalue(file, s[S_CMD_T_CARRIES], o->id); - } - } -} - - - -static void try_growing_queue() -{ - uint8_t wait_seconds = 5; - time_t now = time(0); - struct timespec dur; - dur.tv_sec = 0; - dur.tv_nsec = 33333333; - while (1) - { - if (read_file_into_queue(world.file_in, &world.queue)) - { - return; - } - nanosleep(&dur, NULL); - if (time(0) > now + wait_seconds) - { - return; - } - } -} - - - -static void update_worldstate_file() -{ - char * path_tmp; - FILE * file = atomic_write_start(s[S_PATH_WORLDSTATE], &path_tmp); - 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); - write_value_as_line(world.map.length, file); - write_map(player, file); - atomic_write_finish(file, s[S_PATH_WORLDSTATE], path_tmp); - set_cleanup_flag(CLEANUP_WORLDSTATE); - char * dot = ".\n"; - try_fwrite(dot, strlen(dot), 1, world.file_out, __func__); - fflush(world.file_out); -} - - - -static void write_value_as_line(int32_t value, FILE * file) -{ - 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__); -} - - - -static void write_inventory(struct Thing * player, FILE * file) -{ - struct Thing * owned = player->owns; - if (!owned) - { - char * empty = "(none)\n"; - try_fwrite(empty, strlen(empty), 1, file, __func__); - } - else - { - uint8_t q; - for (q = 0; owned; q++) - { - struct ThingType * tt = get_thing_type(owned->type); - try_fwrite(tt->name, strlen(tt->name), 1, file, __func__); - try_fputc('\n', file, __func__); - owned = owned->next; - } - } - try_fputc('%', file, __func__); - try_fputc('\n', file, __func__); -} - - - -static char * build_visible_map(struct Thing * player) -{ - char * visible_map; - init_empty_map(&visible_map); - if (player->fov_map) /* May fail if player thing was created / positioned */ - { /* by god command after turning off FOV building. */ - uint32_t pos_i = 0; - for (; pos_i < (uint32_t) world.map.length * world.map.length; pos_i++) - { - if (player->fov_map[pos_i] == 'v') - { - visible_map[pos_i] = world.map.cells[pos_i]; - } - } - struct Thing * t; - char c; - uint8_t i; - for (i = 0; i < 3; i++) - { - for (t = world.things; t != 0; t = t->next) - { - if ('v' == player->fov_map[t->pos.y*world.map.length+t->pos.x]) - { - struct ThingType * tt = get_thing_type(t->type); - if ( (0 == i && !t->lifepoints && !tt->consumable) - || (1 == i && !t->lifepoints && tt->consumable) - || (2 == i && t->lifepoints)) - { - c = tt->char_on_map; - visible_map[t->pos.y * world.map.length + t->pos.x] = c; - } - } - } - } - } - return visible_map; -} - - - -static void write_map(struct Thing * player, FILE * file) -{ - char * visible_map = build_visible_map(player); - uint16_t x, y; - for (y = 0; y < world.map.length; y++) - { - for (x = 0; x < world.map.length; x++) - { - try_fputc(visible_map[y * world.map.length + x], file, __func__); - } - try_fputc('\n', file, __func__); - } - free(visible_map); - uint32_t map_size = world.map.length * world.map.length; - char * mem_map = try_malloc(map_size, __func__); - memcpy(mem_map, player->mem_map, map_size); - uint8_t i; - struct ThingInMemory * tm; - for (i = 0; i < 2; i++) - { - for (tm = player->t_mem; tm; tm = tm->next) - { - if (' ' != player->mem_map[tm->pos.y*world.map.length+tm->pos.x]) - { - struct ThingType * tt = get_thing_type(tm->type); - if ( (0 == i && !tt->consumable) - || (1 == i && tt->consumable)) - { - char c = tt->char_on_map; - mem_map[tm->pos.y * world.map.length + tm->pos.x] = c; - } - } - } - } - for (y = 0; y < world.map.length; y++) - { - for (x = 0; x < world.map.length; x++) - { - try_fputc(mem_map[y * world.map.length + x], file, __func__); - } - try_fputc('\n', file, __func__); - } - free(mem_map); -} - - - -extern char * io_round() -{ - if (world.queue && strlen(world.queue)) - { - return get_message_from_queue(&world.queue); - } - if (world.do_update) - { - update_worldstate_file(); - send_to_outfile("WORLD_UPDATED\n", 1); - world.do_update = 0; - } - try_growing_queue(); - return get_message_from_queue(&world.queue); -} - - - -extern void save_world() -{ - char * path_tmp; - FILE * file = atomic_write_start(s[S_PATH_SAVE], &path_tmp); - write_key_space_uvalue(file, s[S_CMD_TURN], world.turn); - write_key_space_uvalue(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_SEED_MAP], world.seed_map); - struct ThingAction * ta; - for (ta = world.thing_actions; ta; ta = ta->next) - { - 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); - } - struct ThingType * tt; - for (tt = world.thing_types; tt; tt = tt->next) - { - 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); - 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_uvalue(file, s[S_CMD_TT_PROL], tt->proliferate); - write_key_space_uvalue(file, s[S_CMD_TT_HP], tt->lifepoints); - write_key_space_uvalue(file, s[S_CMD_TT_CONSUM], tt->consumable); - } - for (tt = world.thing_types; tt; tt = tt->next) - { - 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); - } - struct Thing * t; - for (t = world.things; t; t = t->next) - { - write_thing(file, t); - } - for (t = world.things; t; t = t->next) - { - write_thing_carrying(file, t); - } - write_key_space_uvalue(file, s[S_CMD_SEED_RAND], world.seed); - write_key_space_uvalue(file, s[S_CMD_WORLD_ACTIVE], 1); - atomic_write_finish(file, s[S_PATH_SAVE], path_tmp); -} diff --git a/src/server/io.h b/src/server/io.h deleted file mode 100644 index 7c9148d..0000000 --- a/src/server/io.h +++ /dev/null @@ -1,31 +0,0 @@ -/* io.h - * - * This file is part of PlomRogue. PlomRogue is licensed under the GPL version 3 - * or any later version. For details on its copyright, license, and warranties, - * see the file NOTICE in the root directory of the PlomRogue source package. - * - * Communication of the server with the outside world and its client via input, - * output and world state files. - */ - -#ifndef IO_H -#define IO_H - - - -/* Return single \0-terminated string read from input queue (world.queue); or, - * if queue is empty and world.do_update is set, update world state file (and - * unset world.do_update) and write a single dot line to server out file, then - * read server in file for the next load of bytes to put onto the input queue. - * (Queueing ensures only complete messages are interpreted.) - */ -extern char * io_round(); - -/* Write to savefile (atomically) god commands (one per line) to rebuild the - * current world state. - */ -extern void save_world(); - - - -#endif diff --git a/src/server/main.c b/src/server/main.c deleted file mode 100644 index 1ae00f1..0000000 --- a/src/server/main.c +++ /dev/null @@ -1,49 +0,0 @@ -/* src/server/main.c - * - * This file is part of PlomRogue. PlomRogue is licensed under the GPL version 3 - * or any later version. For details on its copyright, license, and warranties, - * see the file NOTICE in the root directory of the PlomRogue source package. - */ - -#include <stdio.h> /* printf() */ -#include <stdlib.h> /* exit() */ -#include "../common/rexit.h" /* exit_err, set_cleanup_func() */ -#include "cleanup.h" /* set_cleanup_flag(), cleanup() */ -#include "hardcoded_strings.h" /* s */ -#include "init.h" /* run_game(), obey_argv(), obey_argv(), setup_server_io() */ -#include "world.h" /* struct World */ - - - -struct World world; - - - -int main(int argc, char ** argv) -{ - /* So error exits also go through the server's cleanup() function. */ - set_cleanup_func(cleanup); - - /* Init settings from command line / hard-coded values. Print start info. */ - init_strings(); - obey_argv(argc, argv); - if (world.is_verbose) - { - char * printf_err = "Trouble in main() with printf()."; - int test = printf("Starting plomrogue-server.\n"); - exit_err(-1 == test, printf_err); - if (world.replay) - { - test = printf("Replay mode. Auto-replaying up to turn %d.\n", - world.replay); - exit_err(-1 == test, printf_err); - } - } - world.map.length = 64; /* Just a sane default value. */ - - /* Init server i/o, Enter play or replay mode loops, then leave properly. */ - setup_server_io(); - run_game(); - cleanup(); - exit(EXIT_SUCCESS); -} diff --git a/src/server/map.c b/src/server/map.c deleted file mode 100644 index 3a5a0a2..0000000 --- a/src/server/map.c +++ /dev/null @@ -1,241 +0,0 @@ -/* src/server/map.c - * - * This file is part of PlomRogue. PlomRogue is licensed under the GPL version 3 - * or any later version. For details on its copyright, license, and warranties, - * see the file NOTICE in the root directory of the PlomRogue source package. - */ - -#include "map.h" -#include <stdint.h> /* uint8_t, int8_t, uint16_t, uint32_t, (U)INT*_(MIN|MAX) */ -#include <stdlib.h> /* free() */ -#include <string.h> /* memset() */ -#include "../common/rexit.h" /* exit_err() */ -#include "../common/try_malloc.h" /* try_malloc() */ -#include "../common/yx_uint8.h" /* yx_uint8 */ -#include "rrand.h" /* rrand() */ -#include "world.h" /* global world */ - - - -/* Helper to mv_yx_in_dir_legal(). Move "yx" into hex direction "d". */ -static void mv_yx_in_dir(char d, struct yx_uint8 * yx); - -/* Call this too often with "init" of 0 and the game exits with an error message - * about reaching an iteration limit. An "init" of 1 sets the iteration counter - * to 0. Iteration limit is currently 256 * UINT16_MAX. - */ -static uint8_t iter_limit(uint8_t init); - -/* Return 1 if cell on "pos" is neighbor to a cell of "type", else return 0. */ -static uint8_t is_neighbor(struct yx_uint8 pos, char type); - -/* Fill map with '~' cells. */ -static void make_sea(); - -/* Put island of '.' cells inside map sea. */ -static void make_sea(); - -/* Put tree cells of 'X' on island. */ -static void make_trees(); - - - -static void mv_yx_in_dir(char d, struct yx_uint8 * yx) -{ - if (d == 'e') - { - yx->x = yx->x + (yx->y % 2); - yx->y--; - } - else if (d == 'd') - { - yx->x++; - } - else if (d == 'c') - { - yx->x = yx->x + (yx->y % 2); - yx->y++; - } - else if (d == 'x') - { - yx->x = yx->x - !(yx->y % 2); - yx->y++; - } - else if (d == 's') - { - yx->x--; - } - else if (d == 'w') - { - yx->x = yx->x - !(yx->y % 2); - yx->y--; - } -} - - - -static uint8_t iter_limit(uint8_t init) -{ - static uint32_t i = 0; - char * err = "Map generation reached iteration limit. Change map size?"; - if (init) - { - i = 0; - return 0; - } - i++; - exit_err(256 * UINT16_MAX == i, err); - return 1; -} - - - -static uint8_t is_neighbor(struct yx_uint8 pos, char type) -{ - uint8_t ind = pos.y % 2; - uint8_t diag_west = pos.x + ind > 0; - uint8_t diag_east = pos.x + ind <= world.map.length - 1; - uint16_t pos_i = (pos.y * world.map.length) + pos.x; - if ( ( pos.y > 0 && diag_east - && type == world.map.cells[pos_i - world.map.length + ind]) - || ( pos.x < world.map.length - 1 - && type == world.map.cells[pos_i + 1]) - || ( pos.y < world.map.length - 1 && diag_east - && type == world.map.cells[pos_i + world.map.length + ind]) - || ( pos.y > 0 && diag_west - && type == world.map.cells[pos_i - world.map.length - !ind]) - || ( pos.x > 0 - && type == world.map.cells[pos_i - 1]) - || ( pos.y < world.map.length - 1 && diag_west - && type == world.map.cells[pos_i + world.map.length - !ind])) - { - return 1; - } - return 0; -} - - - -static void make_sea() -{ - uint16_t y, x; - for (y = 0; y < world.map.length; y++) - { - for (x = 0; - x < world.map.length; - world.map.cells[(y * world.map.length) + x] = '~', x++); - } -} - - - -static void make_island() -{ - char type = '.'; - uint8_t add_half_width = !(world.map.length % 2) * (world.map.length / 2); - uint32_t size = world.map.length * world.map.length; - world.map.cells[(size / 2) + add_half_width] = type; - struct yx_uint8 pos; - iter_limit(1); - while (iter_limit(0)) - { - pos.y = rrand() % world.map.length; - pos.x = rrand() % world.map.length; - uint16_t pos_i = (pos.y * world.map.length) + pos.x; - if ('~' == world.map.cells[pos_i] && is_neighbor(pos, type)) - { - if ( pos.y == 0 || pos.y == world.map.length - 1 - || pos.x == 0 || pos.x == world.map.length - 1) - { - break; - } - world.map.cells[pos_i] = type; - } - } -} - - - -static void make_trees() -{ - char type = 'X'; - struct yx_uint8 pos; - uint16_t n_trees = (world.map.length * world.map.length) / 16; - uint16_t i_trees = 0; - iter_limit(1); - while (i_trees <= n_trees && iter_limit(0)) - { - uint8_t single_allowed = rrand() % 32; - pos.y = rrand() % world.map.length; - pos.x = rrand() % world.map.length; - uint16_t pos_i = (pos.y * world.map.length) + pos.x; - if ('.' == world.map.cells[pos_i] - && (!single_allowed || is_neighbor(pos, type))) - { - world.map.cells[pos_i] = type; - i_trees++; - } - } -} - - - -extern void remake_map() -{ - free(world.map.cells); - world.map.cells = try_malloc(world.map.length * world.map.length, __func__); - uint32_t store_seed = world.seed; - world.seed = world.seed_map; - make_sea(); - make_island(); - make_trees(); - world.seed = store_seed; -} - - - -extern uint8_t mv_yx_in_dir_legal(char dir, struct yx_uint8 * yx) -{ - static int8_t wrap_west_east = 0; - static int8_t wrap_north_south = 0; - if (!yx) - { - wrap_west_east = wrap_north_south = 0; - return 0; - } - char * err = "Too much wrapping in mv_yx_in_dir_legal()."; - exit_err( INT8_MIN == wrap_west_east || INT8_MIN == wrap_north_south - || INT8_MAX == wrap_west_east || INT8_MAX == wrap_north_south,err); - struct yx_uint8 original = *yx; - mv_yx_in_dir(dir, yx); - if (('e' == dir || 'd' == dir || 'c' == dir) && yx->x < original.x) - { - wrap_west_east++; - } - else if (('x' == dir || 's' == dir || 'w' == dir) && yx->x > original.x) - { - wrap_west_east--; - } - if (('w' == dir || 'e' == dir) && yx->y > original.y) - { - wrap_north_south--; - } - else if (('x' == dir || 'c' == dir) && yx->y < original.y) - { - wrap_north_south++; - } - if ( !wrap_west_east && !wrap_north_south - && yx->x < world.map.length && yx->y < world.map.length) - { - return 1; - } - return 0; -} - - - -extern void init_empty_map(char ** map) -{ - *map = try_malloc(world.map.length * world.map.length, __func__); - memset(*map, ' ', world.map.length * world.map.length); -} diff --git a/src/server/map.h b/src/server/map.h deleted file mode 100644 index d9ebf74..0000000 --- a/src/server/map.h +++ /dev/null @@ -1,47 +0,0 @@ -/* src/server/map.h - * - * This file is part of PlomRogue. PlomRogue is licensed under the GPL version 3 - * or any later version. For details on its copyright, license, and warranties, - * see the file NOTICE in the root directory of the PlomRogue source package. - * - * Routines to create and navigate game map. - */ - -#ifndef MAP_H_SERVER -#define MAP_H_SERVER - -#include <stdint.h> /* uint8_t */ -struct yx_uint8; - - - -/* (Re-)make island map "~" cells representing water and "." cells representing - * land. The island shape is built randomly from world.seed_map by starting with - * a sea of one land cell in the middle, then going into a cycle of repeatedly - * selecting a random sea cell and transforming it into land if it is neighbor - * to land; the cycle ends when a land cell is due to be created right at the - * border of the map. Lots of 'X' cells representing trees are put on the - * island. - */ -extern void remake_map(); - -/* Move "yx" into hex direction "dir". Available hex directions are: 'e' - * (north-east), 'd' (east), 'c' (south-east), 'x' (south-west), 's' (west), 'w' - * (north-west). Returns 1 if the move was legal, else 0. - * - * A move is legal if "yx" ends up in the confines of the map and the original - * wrap space. The latter is left to a neighbor wrap space if "yx" moves beyond - * the minimal (0) or maximal (UINT8_MAX) column or row of possible map space â - * in which case "yx".y or "yx".x will snap to the respective opposite side. The - * current wrapping state is kept between successive calls until a "yx" of NULL - * is passed, in which case the function does nothing but zero the wrap state. - * Successive wrapping may move "yx" several wrap spaces into either direction, - * or return it into the original wrap space. - */ -extern uint8_t mv_yx_in_dir_legal(char dir, struct yx_uint8 * yx); - -/* Initialize (empty) map array at "map". */ -extern void init_empty_map(char ** map); - - -#endif diff --git a/src/server/rrand.c b/src/server/rrand.c deleted file mode 100644 index 034b0e8..0000000 --- a/src/server/rrand.c +++ /dev/null @@ -1,18 +0,0 @@ -/* src/server/rrand.c - * - * This file is part of PlomRogue. PlomRogue is licensed under the GPL version 3 - * or any later version. For details on its copyright, license, and warranties, - * see the file NOTICE in the root directory of the PlomRogue source package. - */ - -#include "rrand.h" -#include <stdint.h> /* uint16_t */ -#include "world.h" /* global world */ - - - -extern uint16_t rrand() -{ /* Constants as recommended by POSIX.1-2001 (see man page rand(3)). */ - world.seed = ((world.seed * 1103515245) + 12345) % 4294967296; - return (world.seed >> 16); /* Ignore less random least significant bits. */ -} diff --git a/src/server/rrand.h b/src/server/rrand.h deleted file mode 100644 index 74f12fd..0000000 --- a/src/server/rrand.h +++ /dev/null @@ -1,25 +0,0 @@ -/* src/server/rrand.h - * - * This file is part of PlomRogue. PlomRogue is licensed under the GPL version 3 - * or any later version. For details on its copyright, license, and warranties, - * see the file NOTICE in the root directory of the PlomRogue source package. - * - * Provides deterministic pseudo-randomness. - */ - -#ifndef RRAND_H -#define RRAND_H - -#include <stdint.h> /* uint16_t */ - - - -/* Return 16-bit number pseudo-randomly generated via Linear Congruential - * Generator algorithm with some proven constants. Use instead of rand() to - * ensure portability of the same pseudo-randomness across systems. - */ -extern uint16_t rrand(); - - - -#endif diff --git a/src/server/run.c b/src/server/run.c deleted file mode 100644 index ad04f71..0000000 --- a/src/server/run.c +++ /dev/null @@ -1,467 +0,0 @@ -/* src/server/run.c - * - * This file is part of PlomRogue. PlomRogue is licensed under the GPL version 3 - * or any later version. For details on its copyright, license, and warranties, - * see the file NOTICE in the root directory of the PlomRogue source package. - */ - -#define _POSIX_C_SOURCE 200809L /* strdup() */ -#include "run.h" -#include <stddef.h> /* NULL */ -#include <stdint.h> /* uint8_t, uint16_t, uint32_t, int16_t */ -#include <stdio.h> /* FILE, printf(), fflush() */ -#include <stdlib.h> /* atoi(), free() */ -#include <string.h> /* strlen(), strcmp(), strncmp(), strdup() */ -#include <time.h> /* time_t, time() */ -#include <unistd.h> /* access() */ -#include "../common/parse_file.h" /* set_err_line_options(), token_from_line(), - * err_line(), err_line_inc(), parse_val(), - * parestest_int() - */ -#include "../common/readwrite.h" /* try_fopen(), try_fcose(), try_fwrite(), - * try_fgets(), textfile_width(), try_fputc(), - * atomic_write_finish(), build_temp_path() - */ -#include "../common/rexit.h" /* exit_trouble(), exit_err() */ -#include "../common/try_malloc.h" /* try_malloc() */ -#include "ai.h" /* ai() */ -#include "cleanup.h" /* unset_cleanup_flag() */ -#include "field_of_view.h" /* update_map_memory() */ -#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(), try_healing() */ -#include "things.h" /* Thing, ThingType, ThingInMemory, get_player(), - * get_thing_action_id_by_name(), try_thing_proliferation() - */ -#include "world.h" /* world */ - - - -/* 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); - -/* Return 1 on world.exists, else 0 and err_line() appropriate error message. */ -static uint8_t player_commands_allowed(); - -/* Parse player commands "tok0" with optional argument "tok1" to player action. - * Return 1 on success, 0 on failure. - */ -static uint8_t parse_player_command_0arg(char * tok0); -static uint8_t parse_player_command_1arg(char * tok0, char * tok1); - -/* Parse/apply (non-)meta command "tok0" (read further tokens as necessary). - * Return 0 on failure, 1 on success, 2 on QUIT meta command. - */ -static uint8_t parse_command_nonmeta(char * tok0); -static uint8_t parse_command_meta(char * tok0); - -/* Compare 1st line of server out file to world.server_test, abort if they don't - * match, but not before unsetting flags deleting files in the server directory, - * for in that case those must be assumed to belong to another server process. - */ -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 - * 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 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; - return 1; - } - return 0; -} - - - -static uint8_t player_commands_allowed() -{ - if (!world.exists) - { - return !err_line(1, "No world exists in which to run player commands."); - } - return 1; -} - - - -static uint8_t parse_player_command_0arg(char * tok0) -{ - struct Thing * player = get_player(); - if ( !strcmp(tok0, s[S_CMD_WAIT]) || !strcmp(tok0, s[S_CMD_PICKUP]) - || !strcmp(tok0, s[S_CMD_AI])) - { - if (player_commands_allowed()) - { - if (!strcmp(tok0, s[S_CMD_AI])) - { - ai(player); - } - else - { - player->command = get_thing_action_id_by_name(tok0); - } - turn_over(); - } - return 1; - } - return 0; -} - - - -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)) - && player_commands_allowed()) - { - player->command = get_thing_action_id_by_name(tok0); - turn_over(); - } - else if (!strcmp(tok0, s[S_CMD_MOVE]) && player_commands_allowed()) - { - char dir = '\0'; - if (!( set_char_by_string_comparison(tok1, "east", &dir, 'd') - || set_char_by_string_comparison(tok1, "south-east", &dir, 'c') - || set_char_by_string_comparison(tok1, "south-west", &dir, 'x') - || set_char_by_string_comparison(tok1, "west", &dir, 's') - || set_char_by_string_comparison(tok1, "north-west", &dir, 'w') - || set_char_by_string_comparison(tok1, "north-east", &dir, 'e'))) - { - return 0; - } - player->arg = dir; - player->command = get_thing_action_id_by_name(tok0); - turn_over(); - } - else - { - return 0; - } - return 1; -} - - - -static uint8_t parse_command_nonmeta(char * tok0) -{ - if (parse_player_command_0arg(tok0)) - { - return 1; - } - else - { - char * tok1 = token_from_line(NULL); - if (tok1 && ( parse_player_command_1arg(tok0, tok1) - || parse_god_command_1arg(tok0, tok1))) - { - return 1; - } - else - { - char * tok2 = token_from_line(NULL); - if (tok2 && parse_god_command_2arg(tok0, tok1, tok2)) - { - return 1; - } - else - { - char * tok3 = token_from_line(NULL); - if (tok2 && parse_god_command_3arg(tok0, tok1, tok2, tok3)) - { - return 1; - } - } - } - } - return 0; -} - - - -static uint8_t parse_command_meta(char * tok0) -{ - if (!strcmp("QUIT", tok0)) - { - return 2; - } - if (!strcmp("PING", tok0)) - { - send_to_outfile("PONG\n", 1); - return 1; - } - if (!strcmp("THINGS_HERE", tok0)) - { - char * tok1 = token_from_line(NULL); - char * tok2 = token_from_line(NULL); - if (tok1&&tok2 && !parsetest_int(tok1, '8')&&!parsetest_int(tok2, '8')) - { - if (!world.exists) - { - err_line(1, "Command only works on existing worlds."); - return 0; - } - send_to_outfile("THINGS_HERE START\n", 1); - struct Thing * player = get_player(); - if (player->fov_map && - 'v' == player->fov_map[atoi(tok1)*world.map.length+atoi(tok2)]) - { - struct Thing * t; - for (t = world.things; t; t = t->next) - { - if (t->pos.y == atoi(tok1) && t->pos.x == atoi(tok2)) - { - struct ThingType * tt = get_thing_type(t->type); - send_to_outfile(tt->name, 0); - send_to_outfile("\n", 1); - } - } - } - else - { - struct ThingInMemory * t_mem; - for (t_mem = player->t_mem; t_mem; t_mem = t_mem->next) - { - if (t_mem->pos.y == atoi(tok1) && t_mem->pos.x == atoi(tok2)) - { - struct ThingType * tt = get_thing_type(t_mem->type); - send_to_outfile(tt->name, 0); - send_to_outfile("\n", 1); - } - } - } - send_to_outfile("THINGS_HERE END\n", 1); - return 1; - } - } - return 0; -} - - - -static void server_test() -{ - char test[10 + 1 + 10 + 1 + 1]; - FILE * file = try_fopen(s[S_PATH_OUT], "r", __func__); - try_fgets(test, 10 + 10 + 1 + 1, file, __func__); - try_fclose(file, __func__); - if (strcmp(test, world.server_test)) - { - unset_cleanup_flag(CLEANUP_WORLDSTATE); - unset_cleanup_flag(CLEANUP_OUT); - unset_cleanup_flag(CLEANUP_IN); - char * msg = "Server test string in server output file does not match. " - "This indicates that the current server process has been " - "superseded by another one."; - exit_err(1, msg); - } -} - - - -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) -{ - uint16_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; - int16_t * whitelist = build_whitelist(); - while (0 < player->lifepoints) - { - if (!thing) - { - world.turn++; - thing = world.things; - free(whitelist); - whitelist = build_whitelist();/* The whitelist excludes things */ - } /* that appear only during the turn.*/ - if (thing_in_whitelist(thing->id, whitelist)) - { - if (0 < thing->lifepoints) - { - if (0 == thing->command) - { - update_map_memory(thing, 1); - if (thing == player) - { - break; - } - ai(thing); - } - try_healing(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; - } - hunger(thing); - } - try_thing_proliferation(thing); - } - thing = thing->next; - } - free(whitelist); -} - - - -extern void send_to_outfile(char * answer, uint8_t flush) -{ - try_fwrite(answer, strlen(answer), 1, world.file_out, __func__); - if (flush) - { - fflush(world.file_out); - } -} - - - -extern void record(char * msg, uint8_t force) -{ - static FILE * file_tmp = NULL; - static time_t save_wait = 0; - static char * path_tmp; - if (!file_tmp) - { - path_tmp = build_temp_path(s[S_PATH_RECORD]); - file_tmp = try_fopen(path_tmp, "w", __func__); - if (!access(s[S_PATH_RECORD], F_OK)) - { - FILE * file_read = try_fopen(s[S_PATH_RECORD], "r", __func__); - uint32_t linemax = textfile_width(file_read); - char * line = try_malloc(linemax + 1, __func__); - while (try_fgets(line, linemax + 1, file_read, __func__)) - { - try_fwrite(line, strlen(line), 1, file_tmp, __func__); - } - free(line); - try_fclose(file_read, __func__); - } - } - if (msg) - { - try_fwrite(msg, strlen(msg), 1, file_tmp, __func__); - try_fputc('\n', file_tmp, __func__); - } - if (force || time(NULL) > save_wait + 15) - { - save_wait = time(NULL); - save_world(); - atomic_write_finish(file_tmp, s[S_PATH_RECORD], path_tmp); - file_tmp = NULL; - } -} - - - -extern uint8_t obey_msg(char * msg, uint8_t obey_state) -{ - if (world.is_verbose) - { - exit_trouble(-1 == printf("Input: %s\n", msg), __func__, "printf"); - } - set_err_line_options("Trouble with message: ", msg, 0); - char * msg_copy = strdup(msg); - char * tok0 = token_from_line(msg_copy); - uint8_t ret = 0; - if (tok0) - { - ret = parse_command_meta(tok0); - if (ret || (obey_state < 2 && parse_command_nonmeta(tok0))) - { - if (!ret) - { - if (world.exists) - { - world.do_update = 1; - } - if (1 == obey_state) - { - record(msg, 0); - } - } - char * tokplus = token_from_line(NULL); - err_line(!(!tokplus), "Too many arguments, ignoring overflow."); - } - else if (world.replay) - { - ret = 3; - } - else if (!world.replay) - { - err_line(1, "Invalid command/argument or bad number of tokens."); - } - } - free(msg_copy); - return ret; -} - - - -extern uint8_t io_loop(uint8_t obey_state) -{ - while (1) - { - char * msg = io_round(); - server_test(); - if (msg) - { - uint8_t ret = obey_msg(msg, obey_state); - free(msg); - if ( (!world.replay && 2 == ret) - || ( world.replay && 2 <= ret)) - { - return ret; - } - } - } -} diff --git a/src/server/run.h b/src/server/run.h deleted file mode 100644 index 414df1b..0000000 --- a/src/server/run.h +++ /dev/null @@ -1,46 +0,0 @@ -/* src/server/run.h - * - * This file is part of PlomRogue. PlomRogue is licensed under the GPL version 3 - * or any later version. For details on its copyright, license, and warranties, - * see the file NOTICE in the root directory of the PlomRogue source package. - * - * Process commands and act on them. Stuff that furthers the state of the game. - */ - -#ifndef RUN_H -#define RUN_H - -#include <stdint.h> /* uint8_t */ - - - -/* Append "answer" to server output file, with instant fflush() if "flush". */ -extern void send_to_outfile(char * answer, uint8_t flush); - -/* Record save and record file data. Both are only written if "force" is set, or - * on the first run with unset "force", or if 15 seconds have passed since the - * last file writing. "msg" is appended to the record file if it is set. - */ -extern void record(char * msg, uint8_t force); - -/* Try parsing "msg" into a command to apply. Output "msg" if world.is_verbose. - * If "obey_state" is > 1 and world.replay is set, any non-meta command message - * is not executed, but merely returns 3. The QUIT meta command (if well-formed) - * always returns 2. Other meta commands and (with "obey_state" < 2) non-meta - * commands return 1 if well-formed. Malformed or empty command messages return - * 0. If "obey_state" is 1, "msg" is recorded via a non-forced record(). If a - * non-meta command is executed and world.exists, world.do_update is set. - */ -extern uint8_t obey_msg(char * msg, uint8_t obey_state); - -/* Loop to read commands via io_round() and call obey_msg() with "obey_state" - * set on them. If latter returns 2 and world.replay is not set, or returns > 1 - * and world.replay is set, abort loop to return that result. After io_round(), - * compares 1st line of the server out file is compared with world.server_test - * to ensure the server process hasn't been superseded by a new one. - */ -extern uint8_t io_loop(uint8_t obey_state); - - - -#endif diff --git a/src/server/thing_actions.c b/src/server/thing_actions.c deleted file mode 100644 index 6a8803d..0000000 --- a/src/server/thing_actions.c +++ /dev/null @@ -1,393 +0,0 @@ -/* src/server/thing_actions.c - * - * This file is part of PlomRogue. PlomRogue is licensed under the GPL version 3 - * or any later version. For details on its copyright, license, and warranties, - * see the file NOTICE in the root directory of the PlomRogue source package. - */ - -#include "thing_actions.h" -#include <stddef.h> /* NULL */ -#include <stdint.h> /* uint8_t, INT16_MIN, INT16_MAX */ -#include <stdio.h> /* sprintf() */ -#include <stdlib.h> /* free() */ -#include <string.h> /* strlen() */ -#include "../common/rexit.h" /* exit_err(), exit_trouble() */ -#include "../common/try_malloc.h" /* try_malloc() */ -#include "../common/yx_uint8.h" /* yx_uint8 */ -#include "field_of_view.h" /* build_fov_map() */ -#include "hardcoded_strings.h" /* s */ -#include "things.h" /* Thing, ThingType, get_player(), free_things_in_memory(), - * 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); - -/* 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 - * messages; _pick and _drop also decrement world.inventory_sel by 1 if >0. - * (match_dir() is just a little helper to playerbonus_move().) - */ -static void playerbonus_wait(); -static uint8_t match_dir(char d, char ** dsc_d, char match, char * dsc_match); -static void playerbonus_move(char d, uint8_t passable); -static void playerbonus_drop(uint8_t owns_none); -static void playerbonus_pick(uint8_t picked); -static void playerbonus_use(uint8_t no_thing, uint8_t wrong_thing); - - - -static void update_log(char * text) -{ - send_to_outfile("LOG ", 0); - send_to_outfile(text, 0); - send_to_outfile("\n", 1); -} - - - -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); - struct ThingType * tt_hitted = get_thing_type(hitted->type); - struct Thing * player = get_player(); - char * msg1 = "You"; - char * msg2 = "wound"; - char * msg3 = "you"; - if (player != hitter) - { - msg1 = tt_hitter->name; - msg2 = "wounds"; - } - if (player != hitted) - { - msg3 = tt_hitted->name; - } - uint8_t len = strlen(msg1) + 1 + strlen(msg2) + 1 + strlen(msg3) + 2; - char * msg = try_malloc(len, __func__); - int test = sprintf(msg, "%s %s %s.", msg1, msg2, msg3); - exit_trouble(test < 0, __func__, s[S_FCN_SPRINTF]); - update_log(msg); - free(msg); - decrement_lifepoints(hitted); -} - - - -static void playerbonus_wait() -{ - update_log("You wait."); -} - - - -static uint8_t match_dir(char d, char ** dsc_d, char match, char * dsc_match) -{ - if (d == match) - { - * dsc_d = dsc_match; - return 1; - } - return 0; -} - - - -static void playerbonus_move(char d, uint8_t passable) -{ - char * dsc_dir = "north-east"; - if ( match_dir(d, &dsc_dir, 'd', "east") - || match_dir(d, &dsc_dir, 'c', "south-east") - || match_dir(d, &dsc_dir, 'x', "south-west") - || match_dir(d, &dsc_dir, 's', "west") - || match_dir(d, &dsc_dir, 'w', "north-west")) - { - ; - } - char * dsc_move = "You move "; - if (0 == passable) - { - dsc_move = "You fail to move "; - } - char * msg = try_malloc(strlen(dsc_move) + strlen (dsc_dir) + 2, __func__); - int test = sprintf(msg, "%s%s.", dsc_move, dsc_dir); - exit_trouble(test < 0, __func__, s[S_FCN_SPRINTF]); - update_log(msg); - free(msg); -} - - - -static void playerbonus_drop(uint8_t owns_none) -{ - if (0 != owns_none) - { - update_log("You try to drop an object, but you own none."); - return; - } - update_log("You drop an object."); -} - - - -static void playerbonus_pick(uint8_t picked) -{ - if (picked) - { - update_log("You pick up an object."); - return; - } - update_log("You try to pick up an object, but there is none."); -} - - - -static void playerbonus_use(uint8_t no_thing, uint8_t wrong_thing) -{ - if (no_thing) - { - update_log("You try to use an object, but you own none."); - return; - } - else if (wrong_thing) - { - update_log("You try to use this object, but fail."); - return; - } - update_log("You consume this object."); -} - - - -extern void actor_wait(struct Thing * t) -{ - if (t == get_player()) - { - playerbonus_wait(); - } -} - - - -extern void actor_move(struct Thing * t) -{ - char d = t->arg; - struct Thing * other_t; - struct yx_uint8 target = t->pos; - uint8_t legal_move = mv_yx_in_dir_legal(d, &target); - mv_yx_in_dir_legal(0, NULL); - uint8_t passable = 0; - if (legal_move) - { - passable = '.' == world.map.cells[target.y*world.map.length + target.x]; - for (other_t = world.things; other_t != 0; other_t = other_t->next) - { - if (0 == other_t->lifepoints || other_t == t) - { - continue; - } - if (target.y == other_t->pos.y && target.x == other_t->pos.x) - { - actor_hits_actor(t, other_t); - return; - } - } - } - if (passable) - { - set_thing_position(t, target); - build_fov_map(t); - } - if (t == get_player()) - { - playerbonus_move(d, passable); - } -} - - - -extern void actor_drop(struct Thing * t) -{ - uint8_t owns_none = (!t->owns); - if (!owns_none) - { - uint8_t select = t->arg; - struct Thing * owned = t->owns; - uint8_t i = 0; - for (; i != select; i++, owned = owned->next); - own_thing(&world.things, &t->owns, owned->id); - } - if (t == get_player()) - { - playerbonus_drop(owns_none); - } -} - - - -extern void actor_pick(struct Thing * t) -{ - struct Thing * picked = NULL; - struct Thing * t_i; - uint8_t highest_id = 0; - for (t_i = world.things; t_i; t_i = t_i->next) - { - if (t_i != t && t_i->pos.y == t->pos.y && t_i->pos.x == t->pos.x) - { - if (t_i->id >= highest_id) /* With several Things to pick, */ - { /* pick the one with the highest ID. */ - highest_id = t_i->id; - picked = t_i; - } - } - } - if (picked) - { - own_thing(&t->owns, &world.things, picked->id); - set_thing_position(picked, t->pos); - } - if (t == get_player()) - { - playerbonus_pick(!(!picked)); - } -} - - - -extern void actor_use(struct Thing * t) -{ - uint8_t wrong_thing = 1; - uint8_t no_thing = (!t->owns); - if (!no_thing) - { - uint8_t select = t->arg; - uint8_t i = 0; - struct Thing * selected = t->owns; - for (; i != select; i++, selected = selected->next); - struct ThingType * tt = get_thing_type(selected->type); - if (tt->consumable) - { - wrong_thing = 0; - struct Thing * next = selected->next; - free(selected); - if (0 < select) - { - select--; - selected = t->owns; - for (i = 0; i != select; i++, selected = selected->next); - selected->next = next; - } - else - { - t->owns = next; - } - t->satiation = t->satiation + tt->consumable > INT16_MAX ? - INT16_MAX : t->satiation + tt->consumable; - } - } - if (t == get_player()) - { - playerbonus_use(no_thing, wrong_thing); - } -} - - - -extern void try_healing(struct Thing * t) -{ - struct ThingType * tt = get_thing_type(t->type); - if ( t->satiation > 0 && t->lifepoints < tt->lifepoints - && 0 == (rrand() % 31) - && get_thing_action_id_by_name(s[S_CMD_WAIT]) == t->command) - { - t->lifepoints++; - t->satiation = t->satiation - 32; - if (get_player() == t) - { - update_log("You heal."); - } - else - { - char * msg_part = " heals."; - 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); - } - } -} - - - -extern void hunger(struct Thing * t) -{ - if (t->satiation > INT16_MIN) - { - t->satiation--; - } - struct ThingType * tt = get_thing_type(t->type); - uint16_t testbase = t->satiation < 0 ? -(t->satiation) : t->satiation; - exit_err(!(tt->lifepoints), "A thing that should not hunger is hungering."); - uint16_t endurance = INT16_MAX / tt->lifepoints; - 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); - } -} diff --git a/src/server/thing_actions.h b/src/server/thing_actions.h deleted file mode 100644 index 97ab3cc..0000000 --- a/src/server/thing_actions.h +++ /dev/null @@ -1,54 +0,0 @@ -/* src/server/thing_actions.h - * - * This file is part of PlomRogue. PlomRogue is licensed under the GPL version 3 - * or any later version. For details on its copyright, license, and warranties, - * see the file NOTICE in the root directory of the PlomRogue source package. - * - * Actions that can be performed by living things / "actors". Note that apart - * from the consequences described below, each action may also trigger log - * messages and other minor stuff if the actor is equal to the player. - */ - -#ifndef THING_ACTIONS_H -#define THING_ACTIONS_H - -struct Thing; - - - -/* Actor "t" does nothing. */ -extern void actor_wait(struct Thing * t); - -/* Actor "t" tries to move one step in direction described by char t->arg (where - * north-east is 'e', east 'd' etc.) Move either succeeds, or another actor is - * encountered and hit (which leads ot its lifepoint decreasing by one and - * eventually death), or the move fails due to an impassable target square. On - * success, update thing's field of view map. - */ -extern void actor_move(struct Thing * t); - -/* Actor "t" tries to drop from inventory thing indexed by number t->args. */ -extern void actor_drop(struct Thing * t); - -/* Actor "t" tries to pick up topmost thing from ground into its inventory. */ -extern void actor_pick(struct Thing * t); - -/* Actor "t" tries to use thing in inventory indexed by number t->args. - * (Currently the only valid use is consuming items defined as consumable.) - */ -extern void actor_use(struct Thing * t); - -/* Increment "t"'s lifepoints to a 1/32 chance if its .satiation is positive, - * its lifepoints are below "t"'s type's .lifepoints, and "t"'s .command is the - * ID of the waiting action. On success, also decrement .satiation by by 32. - */ -extern void try_healing(struct Thing * t); - -/* Decrement "t"'s satiation and trigger a chance (dependent on over-/under- - * satiation value) of lifepoint decrement. - */ -extern void hunger(struct Thing * t); - - - -#endif diff --git a/src/server/things.c b/src/server/things.c deleted file mode 100644 index f114ea4..0000000 --- a/src/server/things.c +++ /dev/null @@ -1,411 +0,0 @@ -/* src/server/things.c - * - * This file is part of PlomRogue. PlomRogue is licensed under the GPL version 3 - * or any later version. For details on its copyright, license, and warranties, - * see the file NOTICE in the root directory of the PlomRogue source package. - */ - -#define _POSIX_C_SOURCE 200809L /* strdup() */ -#include "things.h" -#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(), 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 "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 */ - - - -/* Used to treat structs Thing, ThingType and ThingAction the same. */ -struct NextAndId -{ - struct NextAndId * next; - uint8_t id; -}; - - - -/* 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 lowest ID >= "start_id" and <= UINT8_MAX for new thing - * ("struct_id"=0), thing type ("struct_id"=1) or thing action ("struct_id"=2). - */ -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); - -/* Return 1 if cell at "test_pos" is proliferable by "t", i.e. it is passable, - * it is not inhabited by another thing of "t"'s type, and, if "t" is animate, - * neither by any other animate thing; else return 0. - */ -static uint8_t cell_is_proliferable(struct yx_uint8 test_pos, struct Thing * t); - - -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) -{ - struct NextAndId * nai = try_malloc(n_size, __func__); - memset(nai, 0, n_size); - if (start_id <= id && id <= UINT8_MAX) - { - nai->id = id; - } - else - { - while (1) - { - if ( (0 == struct_id && !get_thing(world.things, start_id, 1)) - || (1 == struct_id && !get_thing_type(start_id)) - || (2 == struct_id && !get_thing_action(start_id))) - { - nai->id = start_id; - break; - } - char * err = "No unused ID available to add to ID list."; - exit_err(start_id == UINT8_MAX, err); - start_id++; - } - } - struct NextAndId ** nai_ptr_ptr = start; - for (; * nai_ptr_ptr; nai_ptr_ptr = &(*nai_ptr_ptr)->next); - *nai_ptr_ptr = nai; - return nai; -} - - - -static uint8_t cell_is_proliferable(struct yx_uint8 test_pos, struct Thing * t) -{ - if ('.' == world.map.cells[test_pos.y * world.map.length + test_pos.x]) - { - struct Thing * t_test; - for (t_test = world.things; t_test; t_test = t_test->next) - { - if (t_test->pos.y == test_pos.y && t_test->pos.x == test_pos.x) - { - if (t_test->type == t->type) - { - return 0; - } - if (t_test->lifepoints && t->lifepoints) - { - return 0; - } - } - } - return 1; - } - return 0; -} - - - -extern struct ThingAction * add_thing_action(uint8_t id) -{ - struct ThingAction * ta; - ta = (struct ThingAction *) add_to_struct_list(sizeof(struct ThingAction), - 1, (int16_t) 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)"); - tt->corpse_id = tt->id; - 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; - if (t->lifepoints && world.exists) - { - build_fov_map(t); - } - return t; -} - - - -extern void add_thing_to_memory_map(struct Thing * t, uint8_t type, - uint8_t y, uint8_t x) -{ - struct ThingInMemory * tm=try_malloc(sizeof(struct ThingInMemory),__func__); - tm->type = type; - tm->pos.y = y; - tm->pos.x = x; - tm->next = t->t_mem; - t->t_mem = tm; -} - - - -extern void free_thing_actions(struct ThingAction * ta) -{ - if (!ta) - { - return; - } - free_thing_actions(ta->next); - free(ta->name); - free(ta); -} - - - -extern void free_thing_types(struct ThingType * tt) -{ - if (!tt) - { - return; - } - free_thing_types(tt->next); - free(tt->name); - free(tt); -} - - - -extern void free_things(struct Thing * t) -{ - if (!t) - { - return; - } - free_things(t->owns); - free_things(t->next); - free(t->fov_map); - free(t->mem_map); - free(t->mem_depth_map); - free_things_in_memory(t->t_mem); - 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 void free_things_in_memory(struct ThingInMemory * tm) -{ - if (!tm) - { - return; - } - free_things_in_memory(tm->next); - free(tm); -} - - - -extern struct ThingAction * get_thing_action(uint8_t id) -{ - struct ThingAction * ta = world.thing_actions; - for (; 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 (; 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 (ta) - { - if (0 == strcmp(ta->name, name)) - { - break; - } - 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 (!ptr || id == ptr->id) - { - return ptr; - } - if (deep) - { - struct Thing * owned_thing = get_thing(ptr->owns, id, 1); - if (owned_thing) - { - return ptr; - } - } - ptr = ptr->next; - } -} - - - -extern struct Thing * get_player() -{ - return get_thing(world.things, 0, 0); -} - - - -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] = "cxswed"; - struct yx_uint8 test = t->pos; - uint8_t i; - for (i = 0; i < strlen(dirs); i++) - { - if ( mv_yx_in_dir_legal(dirs[i], &test) - && cell_is_proliferable(test, t)) - { - candidates[n_candidates] = test; - 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; - for (i = 0; i < n; i++) - { - 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; - '.' != world.map.cells[pos.y * world.map.length + pos.x]; - 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 (0 != t->lifepoints && pos.y==t->pos.y && pos.x==t->pos.x) - { - clear = 0; - break; - } - } - if (1 == clear) - { - break; - } - } - add_thing(-1, type, pos.y, pos.x); - } -} - - - -extern void own_thing(struct Thing ** target, struct Thing ** source, - uint8_t id) -{ - struct Thing * t; - if (id == (*source)->id) - { - t = * source; - * source = t->next; - } - else - { - struct Thing * penult = * source; - while (1) - { - if (id == penult->next->id) - { - break; - } - penult = penult->next; - } - t = penult->next; - penult->next = t->next; - } - struct Thing ** t_ptr_ptr = target; - for (; * t_ptr_ptr; t_ptr_ptr = &(*t_ptr_ptr)->next); - * t_ptr_ptr = t; - t->next = NULL; -} - - - -extern void set_thing_position(struct Thing * t, struct yx_uint8 pos) -{ - t->pos = pos; - struct Thing * owned = t->owns; - for (; owned; set_thing_position(owned, pos), owned = owned->next); -} diff --git a/src/server/things.h b/src/server/things.h deleted file mode 100644 index 33a07db..0000000 --- a/src/server/things.h +++ /dev/null @@ -1,136 +0,0 @@ -/* src/server/things.h - * - * This file is part of PlomRogue. PlomRogue is licensed under the GPL version 3 - * or any later version. For details on its copyright, license, and warranties, - * see the file NOTICE in the root directory of the PlomRogue source package. - * - * 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, int16_t, uint16_t */ -#include "../common/yx_uint8.h" /* yx_uint8 */ - - - -struct Thing -{ - struct Thing * next; - uint8_t id; /* individual thing's unique identifier */ - struct Thing * owns; /* chain of things owned / in inventory */ - struct ThingInMemory * t_mem; /* chain of things remembered */ - struct yx_uint8 pos; /* coordinate on map */ - 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 arg; /* optional field for .command argument */ - uint8_t progress; /* turns already passed to realize .command */ -}; - -struct ThingInMemory -{ - struct ThingInMemory * next; - struct yx_uint8 pos; /* position on memorized */ - uint8_t type; /* thing type identifier */ -}; - -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 */ - uint16_t consumable; /* can be eaten if !0, for so much .satiation win */ - uint8_t corpse_id; /* type to change thing into upon destruction */ - uint8_t lifepoints; /* default start value for thing's .lifepoints */ - 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 * 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 */ -}; - - - -/* 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(uint8_t id); - -/* Add thing type of "id" to world.thing_types, with .corpse_id defaulting to - * the new thing type's .id, .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 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. 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); - -/* Add to thing memory of "t" thing of type id "type" and position "y"/"x". */ -extern void add_thing_to_memory_map(struct Thing * t, uint8_t type, - uint8_t y, uint8_t x); - -/* Free ThingAction / ThingType / Thing / ThingInMemory chain starting at "ta" / - * "tt" / "t" / "tm". - */ -extern void free_thing_actions(struct ThingAction * ta); -extern void free_thing_types(struct ThingType * tt); -extern void free_things(struct Thing * t); -extern void free_things_in_memory(struct ThingInMemory * tm); - -/* 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); - -/* 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(); - -/* 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. - */ -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); - - - -#endif diff --git a/src/server/world.h b/src/server/world.h deleted file mode 100644 index f6deb10..0000000 --- a/src/server/world.h +++ /dev/null @@ -1,46 +0,0 @@ -/* src/server/world.h - * - * This file is part of PlomRogue. PlomRogue is licensed under the GPL version 3 - * or any later version. For details on its copyright, license, and warranties, - * see the file NOTICE in the root directory of the PlomRogue source package. - * - * Contains the World struct holding all game data together. - */ - -#ifndef MAIN_H -#define MAIN_H - -#include <stdint.h> /* uint8_t, uint16_t, uint32_t */ -#include <stdio.h> /* define FILE */ -#include "../common/map.h" /* struct Map */ -struct ThingType; -struct ThingAction; -struct Thing; - - - -struct World -{ - FILE * file_in; /* Input stream on file at .path_in. */ - FILE * file_out; /* Output stream on file at .path_out. */ - struct Map map; /* Game map. */ - struct ThingType * thing_types; /* Thing type definitions. */ - struct ThingAction * thing_actions; /* Thing action definitions. */ - struct Thing * things; /* All physical things of the game world. */ - char * server_test; /* String uniquely identifying server process. */ - char * queue; /* Stores un-processed messages read from the input file. */ - uint32_t seed; /* Randomness seed. */ - 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. */ - 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? */ -}; - -extern struct World world; - - - -#endif diff --git a/start_server_client_union.sh b/start_server_client_union.sh index 69c959d..54a3386 100755 --- a/start_server_client_union.sh +++ b/start_server_client_union.sh @@ -10,11 +10,6 @@ then fi # Give helpful message to players that want to start without compiling first. -if [ ! -e ./roguelike-server ] -then - echo 'No ./roguelike-server file found to execute. Try "./redo" first?' - false -fi if [ ! -e ./roguelike-client ] then echo 'No ./roguelike-client file found to execute. Try "./redo" first?' diff --git a/start_server_python_client_union.sh b/start_server_python_client_union.sh deleted file mode 100755 index 5894947..0000000 --- a/start_server_python_client_union.sh +++ /dev/null @@ -1,46 +0,0 @@ -#!/bin/sh - -# Abort the script on error. -set -e - -# Don't let any log leftovers from before interfere. -if [ -e ./log ] -then - rm log -fi - -# Give helpful message to players that want to start without compiling first. -if [ ! -e ./roguelike-client ] -then - echo 'No ./roguelike-client file found to execute. Try "./redo" first?' - false -fi - -# Use shell script's arguments for server and pipe server output to log file. -# This script's wrapper script will read it out on exit. -python3 ./plomrogue-server.py "$@" > log 2>&1 & - -# Give server some time to start up and exit on error. -sleep 0.01 - -# The client should not start if the server is not running. (If the server was -# running in the foreground, any error exit of it so far would be caught by "set -# -e" above. But "set -e" is blind to error codes generated in the background.) -kill -0 $! 2> /dev/null - -# Give server some time (max. 10 seconds) to generate its worldstate file. -i=0 -while [ ! -e server/worldstate ] && [ $i -le 1000 ] -do - sleep 0.01 - i=`expr $i + 1` -done -if [ ! -e server/worldstate ] -then - echo "Server failed generating worldstate file within given time limit." - false -fi - -# Only start the interface when everything else went well. -kill -0 $! 2> /dev/null -./roguelike-client -- 2.30.2