Merge pull request #651 from ennorehling/develop

refactoring: race, locale, dict removal pt. 1
This commit is contained in:
Enno Rehling 2017-02-11 22:48:41 +01:00 committed by GitHub
commit 17fc2adcb5
43 changed files with 358 additions and 706 deletions

2
cmake

@ -1 +1 @@
Subproject commit d88983c7ff4bc3a4884a7c3f74e8190bac5eab23 Subproject commit f1fb3943ace59994d90d71a891b80033dc2700a2

View file

@ -1,19 +1,5 @@
-- Muschelplateau -- Muschelplateau
-- global exports (use item)
function use_seashell(u, amount)
-- Muschelplateau...
local visit = u.faction.objects:get("embassy_muschel")
if visit and u.region~= home then
local turns = get_turn() - visit
local msg = message.create('msg_event')
msg:set_string("string", u.name .. "(" .. itoa36(u.id) .. ") erzählt den Bewohnern von " .. u.region.name .. " von Muschelplateau, das die Partei " .. u.faction.name .. " vor " .. turns .. " Wochen besucht hat." )
msg:send_region(u.region)
return 0
end
return -4
end
if not config.embassy then return nil end if not config.embassy then return nil end
local embassy = {} local embassy = {}
@ -34,10 +20,10 @@ function embassy.update()
eressea.log.debug("updating embassies in " .. tostring(home)) eressea.log.debug("updating embassies in " .. tostring(home))
local u local u
for u in home.units do for u in home.units do
if u.faction.objects:get('embassy_muschel')==nil then if not u.faction:get_key('mupL') then
if (u.faction:add_item('seashell', 1)>0) then if (u.faction:add_item('seashell', 1)>0) then
eressea.log.debug("new seashell for " .. tostring(u.faction)) eressea.log.debug("new seashell for " .. tostring(u.faction))
u.faction.objects:set('embassy_muschel', get_turn()) u.faction:set_key('mupL', get_turn())
end end
end end
end end

View file

@ -7,3 +7,4 @@ if config.rules then
assert(0 == read_xml(confdir .. rules .. 'config.xml', confdir .. rules .. 'catalog.xml'), "could not load XML data, did you compile with LIBXML2 ?") assert(0 == read_xml(confdir .. rules .. 'config.xml', confdir .. rules .. 'catalog.xml'), "could not load XML data, did you compile with LIBXML2 ?")
assert(0 == eressea.config.read(rules .. 'config.json', confdir), "could not read JSON data") assert(0 == eressea.config.read(rules .. 'config.json', confdir), "could not read JSON data")
end end
eressea.game.reset()

View file

@ -330,17 +330,6 @@ function test_message()
return msg return msg
end end
function test_hashtable()
local f = faction.create("noreply1@eressea.de", "human", "de")
f.objects:set("enno", "smart guy")
f.objects:set("age", 10)
assert(f.objects:get("jesus") == nil)
assert(f.objects:get("enno") == "smart guy")
assert(f.objects:get("age") == 10)
f.objects:set("age", nil)
assert(f.objects:get("age") == nil)
end
function test_events() function test_events()
local fail = 1 local fail = 1
local function msg_handler(u, evt) local function msg_handler(u, evt)

View file

@ -46,23 +46,17 @@ function test_snowglobe()
local r2 = region.create(1, 0, "ocean") local r2 = region.create(1, 0, "ocean")
local f = faction.create("snowglobe2@eressea.de", "human", "de") local f = faction.create("snowglobe2@eressea.de", "human", "de")
local u = unit.create(f, r1, 1) local u = unit.create(f, r1, 1)
local have = 6
local fail = 0 local fail = 0
u:add_item("snowglobe", have) u:add_item("snowglobe", have)
local xform = { ocean = "glacier", glacier = "glacier", firewall = "volcano", volcano = "mountain", desert = "plain", plain = "plain" } local xform = { ocean = "glacier", glacier = "glacier", firewall = "volcano", desert = "plain", volcano = "mountain", plain = "plain" }
u:clear_orders()
u:add_order("BENUTZEN 1 Schneekugel Ost")
for k, v in pairs(xform) do for k, v in pairs(xform) do
r2.terrain = k r2.terrain = k
process_orders() use_snowglobe(u, 1, "Ost", nil)
assert_equal(v, r2.terrain) assert_equal(v, r2.terrain)
if k~=v then if k==v then
have=have - 1
else
fail = fail + 1 fail = fail + 1
assert_equal(fail, f:count_msg_type('target_region_invalid')) assert_equal(fail, f:count_msg_type('target_region_invalid'))
end end
assert_equal(have, u:get_item("snowglobe"))
end end
end end

View file

@ -148,7 +148,6 @@ set(SERVER_SRC
bind_locale.c bind_locale.c
bind_eressea.c bind_eressea.c
bind_faction.c bind_faction.c
bind_dict.c
bind_order.c bind_order.c
bindings.c bindings.c
bind_message.c bind_message.c

View file

@ -58,10 +58,6 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#include <storage.h> #include <storage.h>
attrib_type at_scare = { // monster scares peasants
"scare", NULL, NULL, NULL, a_writeint, a_readint
};
attrib_type at_unitdissolve = { attrib_type at_unitdissolve = {
"unitdissolve", NULL, NULL, NULL, a_writechars, a_readchars "unitdissolve", NULL, NULL, NULL, a_writechars, a_readchars
}; };
@ -78,7 +74,6 @@ static int read_ext(attrib * a, void *owner, gamedata *data)
void register_attributes(void) void register_attributes(void)
{ {
/* Alle speicherbaren Attribute müssen hier registriert werden */ /* Alle speicherbaren Attribute müssen hier registriert werden */
at_register(&at_scare);
at_register(&at_shiptrail); at_register(&at_shiptrail);
at_register(&at_familiar); at_register(&at_familiar);
at_register(&at_familiarmage); at_register(&at_familiarmage);

View file

@ -23,7 +23,6 @@ extern "C" {
#endif #endif
struct attrib_type; struct attrib_type;
extern struct attrib_type at_scare;
extern void register_attributes(void); extern void register_attributes(void);
#ifdef __cplusplus #ifdef __cplusplus

View file

@ -19,6 +19,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#include <platform.h> #include <platform.h>
#include <kernel/config.h> #include <kernel/config.h>
#include "dict.h" #include "dict.h"
#include "key.h"
/* kernel includes */ /* kernel includes */
#include <kernel/building.h> #include <kernel/building.h>
@ -29,6 +30,8 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
/* util includes */ /* util includes */
#include <util/attrib.h> #include <util/attrib.h>
#include <util/base36.h>
#include <util/log.h>
#include <util/gamedata.h> #include <util/gamedata.h>
#include <util/resolve.h> #include <util/resolve.h>
@ -54,46 +57,6 @@ typedef struct dict_data {
} data; } data;
} dict_data; } dict_data;
static void
dict_write(const attrib * a, const void *owner, struct storage *store)
{
const dict_data *data = (dict_data *)a->data.v;
int type = (int)data->type;
WRITE_TOK(store, data->name);
WRITE_INT(store, type);
switch (data->type) {
case TINTEGER:
WRITE_INT(store, data->data.i);
break;
case TREAL:
WRITE_FLT(store, (float)data->data.real);
break;
case TSTRING:
WRITE_STR(store, data->data.str);
break;
case TUNIT:
write_unit_reference(data->data.u, store);
break;
case TFACTION:
write_faction_reference(data->data.f, store);
break;
case TBUILDING:
write_building_reference(data->data.b, store);
break;
case TSHIP:
/* write_ship_reference(data->data.sh, store); */
assert(!"not implemented");
break;
case TREGION:
write_region_reference(data->data.r, store);
break;
case TNONE:
break;
default:
assert(!"illegal type in object-attribute");
}
}
static int dict_read(attrib * a, void *owner, gamedata *data) static int dict_read(attrib * a, void *owner, gamedata *data)
{ {
storage *store = data->store; storage *store = data->store;
@ -164,7 +127,7 @@ static int dict_read(attrib * a, void *owner, gamedata *data)
default: default:
return AT_READ_FAIL; return AT_READ_FAIL;
} }
return AT_READ_OK; return AT_READ_DEPR;
} }
static void dict_init(attrib * a) static void dict_init(attrib * a)
@ -184,100 +147,46 @@ static void dict_done(attrib * a)
free(a->data.v); free(a->data.v);
} }
static void dict_upgrade(attrib **alist, attrib *abegin) {
int n = 0, *keys = 0;
int i = 0, val[4];
attrib *a, *ak = a_find(*alist, &at_keys);
if (ak) {
keys = (int *)ak->data.v;
if (keys) n = keys[0];
}
for (a = abegin; a && a->type == abegin->type; a = a->next) {
dict_data *dd = (dict_data *)a->data.v;
if (dd->type != TINTEGER) {
log_error("dict conversion, bad type %d for %s", dd->type, dd->name);
}
else {
if (strcmp(dd->name, "embassy_muschel")==0) {
val[i++] = atoi36("mupL");
}
else {
log_error("dict conversion, bad entry %s", dd->name);
}
}
if (i == 4) {
keys = realloc(keys, sizeof(int) * (n + i + 1));
memcpy(keys + n + 1, val, sizeof(int)*i);
n += i;
i = 0;
}
}
if (i > 0) {
keys = realloc(keys, sizeof(int) * (n + i + 1));
memcpy(keys + n + 1, val, sizeof(int)*i);
if (!ak) {
ak = a_add(alist, a_new(&at_keys));
}
}
ak->data.v = keys;
keys[0] = n + i;
}
attrib_type at_dict = { attrib_type at_dict = {
"object", dict_init, dict_done, NULL, "object", dict_init, dict_done, NULL,
dict_write, dict_read NULL, dict_read, dict_upgrade
}; };
const char *dict_name(const attrib * a)
{
dict_data *data = (dict_data *)a->data.v;
return data->name;
}
struct attrib *dict_create(const char *name, dict_type type, variant value)
{
attrib *a = a_new(&at_dict);
dict_data *data = (dict_data *)a->data.v;
data->name = strdup(name);
dict_set(a, type, value);
return a;
}
void dict_set(attrib * a, dict_type type, variant value)
{
dict_data *data = (dict_data *)a->data.v;
if (data->type == TSTRING)
free(data->data.str);
data->type = type;
switch (type) {
case TSTRING:
data->data.str = value.v ? strdup(value.v) : NULL;
break;
case TINTEGER:
data->data.i = value.i;
break;
case TREAL:
data->data.real = value.f;
break;
case TREGION:
data->data.r = (region *)value.v;
break;
case TBUILDING:
data->data.b = (building *)value.v;
break;
case TFACTION:
data->data.f = (faction *)value.v;
break;
case TUNIT:
data->data.u = (unit *)value.v;
break;
case TSHIP:
data->data.sh = (ship *)value.v;
break;
case TNONE:
break;
default:
assert(!"invalid object-type");
break;
}
}
void dict_get(const struct attrib *a, dict_type * type, variant * value)
{
dict_data *data = (dict_data *)a->data.v;
*type = data->type;
switch (data->type) {
case TSTRING:
value->v = data->data.str;
break;
case TINTEGER:
value->i = data->data.i;
break;
case TREAL:
value->f = (float)data->data.real;
break;
case TREGION:
value->v = data->data.r;
break;
case TBUILDING:
value->v = data->data.b;
break;
case TFACTION:
value->v = data->data.f;
break;
case TUNIT:
value->v = data->data.u;
break;
case TSHIP:
value->v = data->data.sh;
break;
case TNONE:
break;
default:
assert(!"invalid object-type");
break;
}
}

View file

@ -26,13 +26,6 @@ extern "C" {
extern struct attrib_type at_dict; extern struct attrib_type at_dict;
struct attrib *dict_create(const char *name, dict_type type,
variant value);
void dict_get(const struct attrib *a, dict_type * type,
variant * value);
void dict_set(struct attrib *a, dict_type type, variant value);
const char *dict_name(const struct attrib *a);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

View file

@ -66,7 +66,7 @@ attrib_type at_keys = {
NULL NULL
}; };
void a_upgradekeys(attrib **alist, attrib *abegin) { static void a_upgradekeys(attrib **alist, attrib *abegin) {
int n = 0, *keys = 0; int n = 0, *keys = 0;
int i = 0, val[4]; int i = 0, val[4];
attrib *a, *ak = a_find(*alist, &at_keys); attrib *a, *ak = a_find(*alist, &at_keys);

View file

@ -760,10 +760,6 @@ bool missile)
if (is_riding(t) && (wtype == NULL || (fval(wtype, WTF_HORSEBONUS) if (is_riding(t) && (wtype == NULL || (fval(wtype, WTF_HORSEBONUS)
&& !fval(wtype, WTF_MISSILE)))) { && !fval(wtype, WTF_MISSILE)))) {
skill += CavalryBonus(tu, enemy, BONUS_SKILL); skill += CavalryBonus(tu, enemy, BONUS_SKILL);
if (wtype)
skill =
skillmod(u_race(tu)->attribs, tu, tu->region, wtype->skill, skill,
SMF_RIDING);
} }
if (t.index < tf->elvenhorses) { if (t.index < tf->elvenhorses) {

View file

@ -225,10 +225,10 @@ static void test_natural_armor(CuTest * tc)
set_level(u, SK_STAMINA, 2); set_level(u, SK_STAMINA, 2);
CuAssertIntEquals(tc, 0, rc_armor_bonus(rc)); CuAssertIntEquals(tc, 0, rc_armor_bonus(rc));
CuAssertIntEquals(tc, 0, natural_armor(u)); CuAssertIntEquals(tc, 0, natural_armor(u));
set_param(&rc->parameters, "armor.stamina", "1"); rc_set_param(rc, "armor.stamina", "1");
CuAssertIntEquals(tc, 1, rc_armor_bonus(rc)); CuAssertIntEquals(tc, 1, rc_armor_bonus(rc));
CuAssertIntEquals(tc, 2, natural_armor(u)); CuAssertIntEquals(tc, 2, natural_armor(u));
set_param(&rc->parameters, "armor.stamina", "2"); rc_set_param(rc, "armor.stamina", "2");
CuAssertIntEquals(tc, 2, rc_armor_bonus(rc)); CuAssertIntEquals(tc, 2, rc_armor_bonus(rc));
CuAssertIntEquals(tc, 1, natural_armor(u)); CuAssertIntEquals(tc, 1, natural_armor(u));
test_cleanup(); test_cleanup();

View file

@ -13,7 +13,6 @@ without prior permission by the authors of Eressea.
#include <platform.h> #include <platform.h>
#include "bind_building.h" #include "bind_building.h"
#include "bind_unit.h" #include "bind_unit.h"
#include "bind_dict.h"
#include <kernel/config.h> #include <kernel/config.h>
#include <kernel/unit.h> #include <kernel/unit.h>
@ -41,13 +40,6 @@ int tolua_buildinglist_next(lua_State * L)
return 0; /* no more values to return */ return 0; /* no more values to return */
} }
static int tolua_building_get_objects(lua_State * L)
{
building *self = (building *)tolua_tousertype(L, 1, 0);
tolua_pushusertype(L, (void *)&self->attribs, USERTYPE_DICT);
return 1;
}
static int tolua_building_set_working(lua_State * L) static int tolua_building_set_working(lua_State * L)
{ {
building *self = (building *)tolua_tousertype(L, 1, 0); building *self = (building *)tolua_tousertype(L, 1, 0);
@ -258,7 +250,6 @@ void tolua_building_open(lua_State * L)
tolua_variable(L, TOLUA_CAST "size", tolua_building_get_size, tolua_variable(L, TOLUA_CAST "size", tolua_building_get_size,
tolua_building_set_size); tolua_building_set_size);
tolua_function(L, TOLUA_CAST "get_typename", tolua_building_get_typename); tolua_function(L, TOLUA_CAST "get_typename", tolua_building_get_typename);
tolua_variable(L, TOLUA_CAST "objects", tolua_building_get_objects, 0);
tolua_variable(L, TOLUA_CAST "working", tolua_building_get_working, tolua_building_set_working); tolua_variable(L, TOLUA_CAST "working", tolua_building_get_working, tolua_building_set_working);
} }

View file

@ -20,9 +20,7 @@
#include "kernel/terrain.h" #include "kernel/terrain.h"
void config_reset(void) { void config_reset(void) {
default_locale = 0;
free_config(); free_config();
free_locales();
free_nrmesssages(); free_nrmesssages();
free_spells(); free_spells();
free_buildingtypes(); free_buildingtypes();
@ -37,7 +35,6 @@ int config_parse(const char *json)
if (conf) { if (conf) {
json_config(conf); json_config(conf);
cJSON_Delete(conf); cJSON_Delete(conf);
init_locales();
return 0; return 0;
} }
else { else {

View file

@ -1,185 +0,0 @@
/*
+-------------------+
| | Enno Rehling <enno@eressea.de>
| Eressea PBEM host | Christian Schlittchen <corwin@amber.kn-bremen.de>
| (c) 1998 - 2008 | Katja Zedel <katze@felidae.kn-bremen.de>
| | Henning Peters <faroul@beyond.kn-bremen.de>
+-------------------+
This program may not be used, modified or distributed
without prior permission by the authors of Eressea.
*/
#include <platform.h>
#include "bind_dict.h"
#include <kernel/building.h>
#include <kernel/unit.h>
#include <kernel/ship.h>
#include <kernel/region.h>
#include <attributes/dict.h>
#include <util/variant.h>
#include <util/attrib.h>
#include <tolua.h>
#include <lua.h>
#include <string.h>
#include <assert.h>
static int tolua_dict_get(lua_State * L)
{
dict self = (dict)tolua_tousertype(L, 1, 0);
const char *name = tolua_tostring(L, 2, 0);
attrib *a = a_find(*self, &at_dict);
for (; a && a->type == &at_dict; a = a->next) {
const char *obj_name = dict_name(a);
if (obj_name && name && strcmp(obj_name, name) == 0) {
variant val;
dict_type type;
dict_get(a, &type, &val);
switch (type) {
case TNONE:
lua_pushnil(L);
break;
case TINTEGER:
lua_pushinteger(L, val.i);
break;
case TREAL:
lua_pushnumber(L, (lua_Number)val.f);
break;
case TREGION:
tolua_pushusertype(L, val.v, TOLUA_CAST "region");
break;
case TBUILDING:
tolua_pushusertype(L, val.v, TOLUA_CAST "building");
break;
case TUNIT:
tolua_pushusertype(L, val.v, TOLUA_CAST "unit");
break;
case TSHIP:
tolua_pushusertype(L, val.v, TOLUA_CAST "ship");
break;
case TSTRING:
tolua_pushstring(L, (const char *)val.v);
break;
default:
assert(!"not implemented");
}
return 1;
}
}
lua_pushnil(L);
return 1;
}
static int tolua_dict_set_number(lua_State * L)
{
dict self = (dict)tolua_tousertype(L, 1, 0);
const char *name = tolua_tostring(L, 2, 0);
lua_Number value = tolua_tonumber(L, 3, 0);
attrib *a = a_find(*self, &at_dict);
variant val;
val.f = (float)value;
for (; a && a->type == &at_dict; a = a->next) {
if (strcmp(dict_name(a), name) == 0) {
dict_set(a, TREAL, val);
return 0;
}
}
a = a_add(self, dict_create(name, TREAL, val));
return 0;
}
static int tolua_dict_set_string(lua_State * L)
{
dict self = (dict)tolua_tousertype(L, 1, 0);
const char *name = tolua_tostring(L, 2, 0);
const char *value = tolua_tostring(L, 3, 0);
attrib *a = a_find(*self, &at_dict);
variant val;
val.v = strdup(value);
for (; a && a->type == &at_dict; a = a->next) {
if (strcmp(dict_name(a), name) == 0) {
dict_set(a, TSTRING, val);
return 0;
}
}
a = a_add(self, dict_create(name, TSTRING, val));
return 0;
}
static int tolua_dict_set_usertype(lua_State * L, int type)
{
dict self = (dict)tolua_tousertype(L, 1, 0);
const char *name = tolua_tostring(L, 2, 0);
unit *value = tolua_tousertype(L, 3, 0);
attrib *a = a_find(*self, &at_dict);
variant val;
val.v = value;
for (; a && a->type == &at_dict; a = a->next) {
if (strcmp(dict_name(a), name) == 0) {
dict_set(a, type, val);
return 0;
}
}
a = a_add(self, dict_create(name, type, val));
return 0;
}
static int tolua_dict_set(lua_State * L)
{
tolua_Error tolua_err;
if (tolua_isnumber(L, 3, 0, &tolua_err)) {
return tolua_dict_set_number(L);
}
else if (tolua_isusertype(L, 3, TOLUA_CAST "unit", 0, &tolua_err)) {
return tolua_dict_set_usertype(L, TUNIT);
}
else if (tolua_isusertype(L, 3, TOLUA_CAST "faction", 0, &tolua_err)) {
return tolua_dict_set_usertype(L, TFACTION);
}
else if (tolua_isusertype(L, 3, TOLUA_CAST "ship", 0, &tolua_err)) {
return tolua_dict_set_usertype(L, TSHIP);
}
else if (tolua_isusertype(L, 3, TOLUA_CAST "building", 0, &tolua_err)) {
return tolua_dict_set_usertype(L, TBUILDING);
}
else if (tolua_isusertype(L, 3, TOLUA_CAST "region", 0, &tolua_err)) {
return tolua_dict_set_usertype(L, TREGION);
}
return tolua_dict_set_string(L);
}
void tolua_dict_open(lua_State * L)
{
/* register user types */
tolua_usertype(L, USERTYPE_DICT);
tolua_module(L, NULL, 0);
tolua_beginmodule(L, NULL);
{
tolua_cclass(L, USERTYPE_DICT, USERTYPE_DICT,
TOLUA_CAST "", NULL);
tolua_beginmodule(L, USERTYPE_DICT);
{
tolua_function(L, TOLUA_CAST "get", tolua_dict_get);
tolua_function(L, TOLUA_CAST "set", tolua_dict_set);
}
tolua_endmodule(L);
}
tolua_endmodule(L);
}

View file

@ -1,26 +0,0 @@
/*
+-------------------+
| | Enno Rehling <enno@eressea.de>
| Eressea PBEM host | Christian Schlittchen <corwin@amber.kn-bremen.de>
| (c) 1998 - 2008 | Katja Zedel <katze@felidae.kn-bremen.de>
| | Henning Peters <faroul@beyond.kn-bremen.de>
+-------------------+
This program may not be used, modified or distributed
without prior permission by the authors of Eressea.
*/
#ifdef __cplusplus
extern "C" {
#endif
#define USERTYPE_DICT ((char *)"dict")
struct lua_State;
void tolua_dict_open(struct lua_State *L);
typedef struct attrib **dict;
#ifdef __cplusplus
}
#endif

View file

@ -9,6 +9,8 @@
#include <kernel/config.h> #include <kernel/config.h>
#include <kernel/save.h> #include <kernel/save.h>
#include <util/language.h>
#include <stream.h> #include <stream.h>
#include <filestream.h> #include <filestream.h>
@ -16,6 +18,7 @@
void eressea_free_game(void) { void eressea_free_game(void) {
free_gamedata(); free_gamedata();
init_resources(); init_resources();
init_locales();
} }
int eressea_read_game(const char * filename) { int eressea_read_game(const char * filename) {

View file

@ -13,7 +13,6 @@ without prior permission by the authors of Eressea.
#include <platform.h> #include <platform.h>
#include "bind_faction.h" #include "bind_faction.h"
#include "bind_unit.h" #include "bind_unit.h"
#include "bind_dict.h"
#include "bindings.h" #include "bindings.h"
#include "helpers.h" #include "helpers.h"
@ -27,7 +26,9 @@ without prior permission by the authors of Eressea.
#include <kernel/race.h> #include <kernel/race.h>
#include <kernel/region.h> #include <kernel/region.h>
#include <kernel/spellbook.h> #include <kernel/spellbook.h>
#include <attributes/key.h>
#include <util/base36.h>
#include <util/language.h> #include <util/language.h>
#include <util/log.h> #include <util/log.h>
#include <util/password.h> #include <util/password.h>
@ -241,6 +242,32 @@ static int tolua_faction_addnotice(lua_State * L)
return 0; return 0;
} }
static int tolua_faction_getkey(lua_State * L)
{
faction *self = (faction *)tolua_tousertype(L, 1, 0);
const char *name = tolua_tostring(L, 2, 0);
int flag = atoi36(name);
lua_pushboolean(L, key_get(self->attribs, flag));
return 1;
}
static int tolua_faction_setkey(lua_State * L)
{
faction *self = (faction *)tolua_tousertype(L, 1, 0);
const char *name = tolua_tostring(L, 2, 0);
int value = tolua_toboolean(L, 3, 0);
int flag = atoi36(name);
if (value) {
key_set(&self->attribs, flag);
}
else {
key_unset(&self->attribs, flag);
}
return 0;
}
static int tolua_faction_count_msg_type(lua_State *L) { static int tolua_faction_count_msg_type(lua_State *L) {
faction *self = (faction *)tolua_tousertype(L, 1, 0); faction *self = (faction *)tolua_tousertype(L, 1, 0);
const char *str = tolua_tostring(L, 2, 0); const char *str = tolua_tostring(L, 2, 0);
@ -258,13 +285,6 @@ static int tolua_faction_count_msg_type(lua_State *L) {
return 1; return 1;
} }
static int tolua_faction_get_objects(lua_State * L)
{
faction *self = (faction *)tolua_tousertype(L, 1, 0);
tolua_pushusertype(L, (void *)&self->attribs, USERTYPE_DICT);
return 1;
}
static int tolua_faction_get_policy(lua_State * L) static int tolua_faction_get_policy(lua_State * L)
{ {
faction *self = (faction *)tolua_tousertype(L, 1, 0); faction *self = (faction *)tolua_tousertype(L, 1, 0);
@ -618,8 +638,8 @@ void tolua_faction_open(lua_State * L)
/* tech debt hack, siehe https://paper.dropbox.com/doc/Weihnachten-2015-5tOx5r1xsgGDBpb0gILrv#:h=Probleme-mit-Tests-(Nachtrag-0 */ /* tech debt hack, siehe https://paper.dropbox.com/doc/Weihnachten-2015-5tOx5r1xsgGDBpb0gILrv#:h=Probleme-mit-Tests-(Nachtrag-0 */
tolua_function(L, TOLUA_CAST "count_msg_type", tolua_faction_count_msg_type); tolua_function(L, TOLUA_CAST "count_msg_type", tolua_faction_count_msg_type);
tolua_variable(L, TOLUA_CAST "objects", tolua_faction_get_objects, tolua_function(L, TOLUA_CAST "get_key", tolua_faction_getkey);
NULL); tolua_function(L, TOLUA_CAST "set_key", tolua_faction_setkey);
} }
tolua_endmodule(L); tolua_endmodule(L);
} }

View file

@ -14,7 +14,6 @@ without prior permission by the authors of Eressea.
#include "bind_region.h" #include "bind_region.h"
#include "bind_unit.h" #include "bind_unit.h"
#include "bind_ship.h" #include "bind_ship.h"
#include "bind_dict.h"
#include "bind_building.h" #include "bind_building.h"
#include "chaos.h" #include "chaos.h"
@ -36,10 +35,11 @@ without prior permission by the authors of Eressea.
#include <util/attrib.h> #include <util/attrib.h>
#include <util/base36.h> #include <util/base36.h>
#include <critbit.h>
#include <util/language.h> #include <util/language.h>
#include <util/log.h> #include <util/log.h>
#include <critbit.h>
#include <tolua.h> #include <tolua.h>
#include <assert.h> #include <assert.h>
@ -434,13 +434,6 @@ static int tolua_region_set_resource(lua_State * L)
return 0; return 0;
} }
static int tolua_region_get_objects(lua_State * L)
{
region *self = (region *)tolua_tousertype(L, 1, 0);
tolua_pushusertype(L, (void *)&self->attribs, USERTYPE_DICT);
return 1;
}
static int tolua_region_destroy(lua_State * L) static int tolua_region_destroy(lua_State * L)
{ {
region *self = (region *)tolua_tousertype(L, 1, 0); region *self = (region *)tolua_tousertype(L, 1, 0);
@ -733,8 +726,6 @@ void tolua_region_open(lua_State * L)
tolua_function(L, TOLUA_CAST "get_key", tolua_region_getkey); tolua_function(L, TOLUA_CAST "get_key", tolua_region_getkey);
tolua_function(L, TOLUA_CAST "set_key", tolua_region_setkey); tolua_function(L, TOLUA_CAST "set_key", tolua_region_setkey);
tolua_variable(L, TOLUA_CAST "objects", tolua_region_get_objects, 0);
} }
tolua_endmodule(L); tolua_endmodule(L);

View file

@ -13,7 +13,6 @@ without prior permission by the authors of Eressea.
#include <platform.h> #include <platform.h>
#include "bind_ship.h" #include "bind_ship.h"
#include "bind_unit.h" #include "bind_unit.h"
#include "bind_dict.h"
#include "move.h" #include "move.h"
@ -115,13 +114,6 @@ static int tolua_ship_get_units(lua_State * L)
return 1; return 1;
} }
static int tolua_ship_get_objects(lua_State * L)
{
ship *self = (ship *)tolua_tousertype(L, 1, 0);
tolua_pushusertype(L, (void *)&self->attribs, USERTYPE_DICT);
return 1;
}
static int tolua_ship_create(lua_State * L) static int tolua_ship_create(lua_State * L)
{ {
region *r = (region *)tolua_tousertype(L, 1, 0); region *r = (region *)tolua_tousertype(L, 1, 0);
@ -233,8 +225,6 @@ void tolua_ship_open(lua_State * L)
tolua_variable(L, TOLUA_CAST "type", tolua_ship_get_type, 0); tolua_variable(L, TOLUA_CAST "type", tolua_ship_get_type, 0);
tolua_variable(L, TOLUA_CAST "damage", tolua_ship_get_damage, tolua_variable(L, TOLUA_CAST "damage", tolua_ship_get_damage,
tolua_ship_set_damage); tolua_ship_set_damage);
tolua_variable(L, TOLUA_CAST "objects", tolua_ship_get_objects, 0);
tolua_function(L, TOLUA_CAST "create", tolua_ship_create); tolua_function(L, TOLUA_CAST "create", tolua_ship_create);
} }
tolua_endmodule(L); tolua_endmodule(L);

View file

@ -13,7 +13,6 @@ without prior permission by the authors of Eressea.
#include <platform.h> #include <platform.h>
#include "bind_unit.h" #include "bind_unit.h"
#include "bind_dict.h"
#include "alchemy.h" #include "alchemy.h"
#include "bindings.h" #include "bindings.h"
#include "move.h" #include "move.h"
@ -67,12 +66,6 @@ static int tolua_bufunit(lua_State * L) {
return 1; return 1;
} }
static int tolua_unit_get_objects(lua_State * L)
{
unit *self = (unit *)tolua_tousertype(L, 1, 0);
tolua_pushusertype(L, (void *)&self->attribs, USERTYPE_DICT);
return 1;
}
int tolua_unitlist_nextf(lua_State * L) int tolua_unitlist_nextf(lua_State * L)
{ {
@ -1013,7 +1006,6 @@ void tolua_unit_open(lua_State * L)
tolua_unit_set_race); tolua_unit_set_race);
tolua_variable(L, TOLUA_CAST "hp_max", &tolua_unit_get_hpmax, 0); tolua_variable(L, TOLUA_CAST "hp_max", &tolua_unit_get_hpmax, 0);
tolua_variable(L, TOLUA_CAST "objects", &tolua_unit_get_objects, 0);
tolua_function(L, TOLUA_CAST "show", &tolua_bufunit); tolua_function(L, TOLUA_CAST "show", &tolua_bufunit);
} }
tolua_endmodule(L); tolua_endmodule(L);

View file

@ -15,7 +15,6 @@ without prior permission by the authors of Eressea.
#include "bind_unit.h" #include "bind_unit.h"
#include "bind_storage.h" #include "bind_storage.h"
#include "bind_building.h" #include "bind_building.h"
#include "bind_dict.h"
#include "bind_message.h" #include "bind_message.h"
#include "bind_building.h" #include "bind_building.h"
#include "bind_faction.h" #include "bind_faction.h"
@ -517,7 +516,7 @@ static void reset_game(void)
for (f = factions; f; f = f->next) { for (f = factions; f; f = f->next) {
f->flags &= FFL_SAVEMASK; f->flags &= FFL_SAVEMASK;
} }
init_locales(); // init_locales();
} }
static int tolua_process_orders(lua_State * L) static int tolua_process_orders(lua_State * L)
@ -1143,7 +1142,6 @@ lua_State *lua_init(const dictionary *inifile) {
tolua_unit_open(L); tolua_unit_open(L);
tolua_message_open(L); tolua_message_open(L);
tolua_order_open(L); tolua_order_open(L);
tolua_dict_open(L);
#ifdef USE_CURSES #ifdef USE_CURSES
tolua_gmtool_open(L); tolua_gmtool_open(L);
#endif #endif

View file

@ -422,10 +422,7 @@ static void expandrecruit(region * r, request * recruitorders)
static int recruit_cost(const faction * f, const race * rc) static int recruit_cost(const faction * f, const race * rc)
{ {
if (is_monsters(f) || f->race == rc) { if (is_monsters(f) || valid_race(f, rc)) {
return rc->recruitcost;
}
else if (valid_race(f, rc)) {
return rc->recruitcost; return rc->recruitcost;
} }
return -1; return -1;

View file

@ -563,10 +563,7 @@ bool valid_race(const struct faction *f, const struct race *rc)
if (f->race == rc) if (f->race == rc)
return true; return true;
else { else {
const char *str = get_param(f->race->parameters, "other_race"); return rc_otherrace(f->race) == rc;
if (str)
return rc_find(str) == rc;
return false;
} }
} }

View file

@ -209,6 +209,22 @@ static void test_max_migrants(CuTest *tc) {
test_cleanup(); test_cleanup();
} }
static void test_valid_race(CuTest *tc) {
race * rc1, *rc2;
faction *f;
test_setup();
rc1 = test_create_race("human");
rc2 = test_create_race("elf");
f = test_create_faction(rc1);
CuAssertTrue(tc, valid_race(f, rc1));
CuAssertTrue(tc, !valid_race(f, rc2));
rc_set_param(rc1, "other_race", "elf");
CuAssertTrue(tc, valid_race(f, rc1));
CuAssertTrue(tc, valid_race(f, rc2));
test_cleanup();
}
CuSuite *get_faction_suite(void) CuSuite *get_faction_suite(void)
{ {
CuSuite *suite = CuSuiteNew(); CuSuite *suite = CuSuiteNew();
@ -222,5 +238,6 @@ CuSuite *get_faction_suite(void)
SUITE_ADD_TEST(suite, test_set_origin); SUITE_ADD_TEST(suite, test_set_origin);
SUITE_ADD_TEST(suite, test_set_origin_bug); SUITE_ADD_TEST(suite, test_set_origin_bug);
SUITE_ADD_TEST(suite, test_check_passwd); SUITE_ADD_TEST(suite, test_check_passwd);
SUITE_ADD_TEST(suite, test_valid_race);
return suite; return suite;
} }

View file

@ -44,6 +44,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#include <util/language.h> #include <util/language.h>
#include <util/log.h> #include <util/log.h>
#include <util/rng.h> #include <util/rng.h>
#include <util/variant.h>
#include <storage.h> #include <storage.h>
@ -77,6 +78,79 @@ static const char *racenames[MAXRACES] = {
"clone" "clone"
}; };
#define MAXOPTIONS 4
typedef struct rcoption {
unsigned char key[MAXOPTIONS];
variant value[MAXOPTIONS];
} rcoption;
enum {
RCO_NONE,
RCO_SCARE, // races that scare and eat peasants
RCO_OTHER, // may recruit from another race
RCO_STAMINA, // every n levels of stamina add +1 RC
RCO_HUNGER, // custom hunger.damage override (char *)
RCO_TRADELUX,
RCO_TRADEHERB,
};
static void rc_setoption(race *rc, int k, const char *value) {
unsigned char key = (unsigned char)k;
int i;
variant *v = NULL;
if (!rc->options) {
rc->options = malloc(sizeof(rcoption));
rc->options->key[0] = key;
rc->options->key[1] = RCO_NONE;
v = rc->options->value;
} else {
for (i=0;!v && i < MAXOPTIONS && rc->options->key[i]!=RCO_NONE;++i) {
if (rc->options->key[i]==key) {
v = rc->options->value+i;
}
}
if (!v) {
assert(i<MAXOPTIONS || !"MAXOPTIONS too small for race");
v = rc->options->value+i;
rc->options->key[i] = key;
if (i+1<MAXOPTIONS) {
rc->options->key[i+1]=RCO_NONE;
}
}
}
assert(v);
if (key == RCO_SCARE) {
v->i = atoi(value);
}
else if (key == RCO_STAMINA) {
v->i = atoi(value);
}
else if (key == RCO_OTHER) {
v->v = rc_get_or_create(value);
}
else if (key == RCO_HUNGER) {
v->v = strdup(value);
}
else if (key == RCO_TRADEHERB) {
v->i = atoi(value);
}
else if (key == RCO_TRADELUX) {
v->i = atoi(value);
}
}
static variant *rc_getoption(const race *rc, int key) {
if (rc->options) {
int i;
for (i=0;i!=MAXOPTIONS && rc->options->key[i]!=RCO_NONE;++i) {
if (rc->options->key[i]==key) {
return rc->options->value+i;
}
}
}
return NULL;
}
const struct race *findrace(const char *s, const struct locale *lang) const struct race *findrace(const char *s, const struct locale *lang)
{ {
void **tokens = get_translations(lang, UT_RACES); void **tokens = get_translations(lang, UT_RACES);
@ -184,12 +258,26 @@ void free_races(void) {
while (races) { while (races) {
int i; int i;
race * rc = races->next; race * rc = races->next;
rcoption * opt = races->options;
if (opt) {
for (i=0;i!=MAXOPTIONS && opt->key[i]!=RCO_NONE;++i) {
if (opt->key[i]==RCO_HUNGER) {
free(opt->value[i].v);
}
}
free(opt);
}
for (i = 0; races->attack[i].type!=AT_NONE; ++i) { for (i = 0; races->attack[i].type!=AT_NONE; ++i) {
spellref_free(races->attack[i].data.sp); att *at = races->attack + i;
if (at->type == AT_SPELL) {
spellref_free(at->data.sp);
}
else {
free(at->data.dice);
}
} }
spellref_free(races->precombatspell); spellref_free(races->precombatspell);
free_params(&races->parameters);
free(xrefs); free(xrefs);
xrefs = 0; xrefs = 0;
free(races->_name); free(races->_name);
@ -290,8 +378,46 @@ double rc_maxaura(const race *rc) {
return rc->maxaura / 100.0; return rc->maxaura / 100.0;
} }
int rc_armor_bonus(const race *rc) { const char * rc_hungerdamage(const race *rc)
return get_param_int(rc->parameters, "armor.stamina", 0); {
variant *v = rc_getoption(rc, RCO_HUNGER);
return v ? (const char *)v->v : NULL;
}
int rc_armor_bonus(const race *rc)
{
variant *v = rc_getoption(rc, RCO_STAMINA);
return v ? v->i : 0;
}
int rc_scare(const struct race *rc)
{
variant *v = rc_getoption(rc, RCO_SCARE);
return v ? v->i : 0;
}
int rc_luxury_trade(const struct race *rc)
{
if (rc) {
variant *v = rc_getoption(rc, RCO_TRADELUX);
if (v) return v->i;
}
return 1000;
}
int rc_herb_trade(const struct race *rc)
{
if (rc) {
variant *v = rc_getoption(rc, RCO_TRADEHERB);
if (v) return v->i;
}
return 500;
}
const race *rc_otherrace(const race *rc)
{
variant *v = rc_getoption(rc, RCO_OTHER);
return v ? (const race *)v->v : NULL;
} }
int rc_migrants_formula(const race *rc) int rc_migrants_formula(const race *rc)
@ -299,6 +425,38 @@ int rc_migrants_formula(const race *rc)
return (rc->flags&RCF_MIGRANTS) ? MIGRANTS_LOG10 : MIGRANTS_NONE; return (rc->flags&RCF_MIGRANTS) ? MIGRANTS_LOG10 : MIGRANTS_NONE;
} }
void rc_set_param(struct race *rc, const char *key, const char *value) {
if (strcmp(key, "recruit_multi") == 0) {
rc->recruit_multi = atof(value);
}
else if (strcmp(key, "migrants.formula") == 0) {
if (value[0] == '1') {
rc->flags |= RCF_MIGRANTS;
}
}
else if (strcmp(key, "other_race")==0) {
rc_setoption(rc, RCO_OTHER, value);
}
else if (strcmp(key, "ai.scare")==0) {
rc_setoption(rc, RCO_SCARE, value);
}
else if (strcmp(key, "hunger.damage")==0) {
rc_setoption(rc, RCO_HUNGER, value);
}
else if (strcmp(key, "armor.stamina")==0) {
rc_setoption(rc, RCO_STAMINA, value);
}
else if (strcmp(key, "luxury_trade")==0) {
rc_setoption(rc, RCO_TRADELUX, value);
}
else if (strcmp(key, "herb_trade")==0) {
rc_setoption(rc, RCO_TRADEHERB, value);
}
else {
log_error("unknown property for race %s: %s=%s", rc->_name, key, value);
}
}
const char* rc_name(const race * rc, name_t n, char *name, size_t size) { const char* rc_name(const race * rc, name_t n, char *name, size_t size) {
const char * postfix = 0; const char * postfix = 0;
if (!rc) { if (!rc) {

View file

@ -47,6 +47,7 @@ extern "C" {
struct spell; struct spell;
struct spellref; struct spellref;
struct locale; struct locale;
struct rcoption;
extern int num_races; extern int num_races;
@ -104,7 +105,7 @@ extern "C" {
typedef struct att { typedef struct att {
int type; int type;
union { union {
const char *dice; char *dice;
struct spellref *sp; struct spellref *sp;
} data; } data;
int flags; int flags;
@ -137,7 +138,6 @@ extern "C" {
int df_default; /* Verteidigungsskill Unbewaffnet (default: -2) */ int df_default; /* Verteidigungsskill Unbewaffnet (default: -2) */
int at_bonus; /* Ver<65>ndert den Angriffsskill (default: 0) */ int at_bonus; /* Ver<65>ndert den Angriffsskill (default: 0) */
int df_bonus; /* Ver<65>ndert den Verteidigungskill (default: 0) */ int df_bonus; /* Ver<65>ndert den Verteidigungskill (default: 0) */
struct param *parameters; // additional properties, for an example see natural_armor
struct spellref *precombatspell; struct spellref *precombatspell;
signed char *study_speed; /* study-speed-bonus in points/turn (0=30 Tage) */ signed char *study_speed; /* study-speed-bonus in points/turn (0=30 Tage) */
int flags; int flags;
@ -153,8 +153,9 @@ extern "C" {
struct item *(*itemdrop) (const struct race *, int size); struct item *(*itemdrop) (const struct race *, int size);
void(*init_familiar) (struct unit *); void(*init_familiar) (struct unit *);
struct rcoption *options; // rarely used properties
const struct race *familiars[MAXMAGIETYP]; const struct race *familiars[MAXMAGIETYP];
struct attrib *attribs;
struct race *next; struct race *next;
} race; } race;
@ -184,9 +185,16 @@ extern "C" {
const char * rc_name_s(const race *rc, name_t n); const char * rc_name_s(const race *rc, name_t n);
const char * rc_name(const race *rc, name_t n, char *name, size_t size); const char * rc_name(const race *rc, name_t n, char *name, size_t size);
void rc_set_param(struct race *rc, const char *key, const char *value);
int rc_luxury_trade(const struct race *rc);
int rc_herb_trade(const struct race *rc);
double rc_magres(const struct race *rc); double rc_magres(const struct race *rc);
double rc_maxaura(const struct race *rc); double rc_maxaura(const struct race *rc);
int rc_armor_bonus(const struct race *rc); int rc_armor_bonus(const struct race *rc);
int rc_scare(const struct race *rc);
const char * rc_hungerdamage(const race *rc);
const race *rc_otherrace(const race *rc);
#define MIGRANTS_NONE 0 #define MIGRANTS_NONE 0
#define MIGRANTS_LOG10 1 #define MIGRANTS_LOG10 1

View file

@ -84,6 +84,23 @@ static void test_old_race(CuTest *tc)
test_cleanup(); test_cleanup();
} }
static void test_rc_set_param(CuTest *tc) {
race *rc;
test_setup();
rc = test_create_race("human");
CuAssertPtrEquals(tc, NULL, rc->options);
rc_set_param(rc, "recruit_multi", "0.5");
CuAssertDblEquals(tc, 0.5, rc->recruit_multi, 0.0);
rc_set_param(rc, "migrants.formula", "1");
CuAssertIntEquals(tc, RCF_MIGRANTS, rc->flags&RCF_MIGRANTS);
CuAssertIntEquals(tc, MIGRANTS_LOG10, rc_migrants_formula(rc));
rc_set_param(rc, "ai.scare", "400");
CuAssertIntEquals(tc, 400, rc_scare(rc));
rc_set_param(rc, "hunger.damage", "1d10+12");
CuAssertStrEquals(tc, "1d10+12", rc_hungerdamage(rc));
test_cleanup();
}
CuSuite *get_race_suite(void) CuSuite *get_race_suite(void)
{ {
CuSuite *suite = CuSuiteNew(); CuSuite *suite = CuSuiteNew();
@ -92,6 +109,7 @@ CuSuite *get_race_suite(void)
SUITE_ADD_TEST(suite, test_rc_name); SUITE_ADD_TEST(suite, test_rc_name);
SUITE_ADD_TEST(suite, test_rc_defaults); SUITE_ADD_TEST(suite, test_rc_defaults);
SUITE_ADD_TEST(suite, test_rc_find); SUITE_ADD_TEST(suite, test_rc_find);
SUITE_ADD_TEST(suite, test_rc_set_param);
return suite; return suite;
} }

View file

@ -1470,7 +1470,6 @@ int readgame(const char *filename)
FILE *F; FILE *F;
size_t sz; size_t sz;
init_locales();
log_debug("- reading game data from %s", filename); log_debug("- reading game data from %s", filename);
join_path(datapath(), filename, path, sizeof(path)); join_path(datapath(), filename, path, sizeof(path));

View file

@ -358,16 +358,12 @@ static int parse_calendar(xmlDocPtr doc)
xmlXPathContextPtr xpath = xmlXPathNewContext(doc); xmlXPathContextPtr xpath = xmlXPathNewContext(doc);
xmlXPathObjectPtr xpathCalendars; xmlXPathObjectPtr xpathCalendars;
xmlNodeSetPtr nsetCalendars; xmlNodeSetPtr nsetCalendars;
int c, rv = 0;
/* reading eressea/buildings/building */
xpathCalendars = xmlXPathEvalExpression(BAD_CAST "/eressea/calendar", xpath); xpathCalendars = xmlXPathEvalExpression(BAD_CAST "/eressea/calendar", xpath);
nsetCalendars = xpathCalendars->nodesetval; nsetCalendars = xpathCalendars->nodesetval;
months_per_year = 0; months_per_year = 0;
if (nsetCalendars == NULL || nsetCalendars->nodeNr == 0) { if (nsetCalendars != NULL && nsetCalendars->nodeNr != 0) {
rv = -1; int c;
}
else
for (c = 0; c != nsetCalendars->nodeNr; ++c) { for (c = 0; c != nsetCalendars->nodeNr; ++c) {
xmlNodePtr calendar = nsetCalendars->nodeTab[c]; xmlNodePtr calendar = nsetCalendars->nodeTab[c];
xmlXPathObjectPtr xpathWeeks, xpathMonths, xpathSeasons; xmlXPathObjectPtr xpathWeeks, xpathMonths, xpathSeasons;
@ -377,7 +373,7 @@ static int parse_calendar(xmlDocPtr doc)
xmlChar *start; xmlChar *start;
start = xmlGetProp(calendar, BAD_CAST "start"); start = xmlGetProp(calendar, BAD_CAST "start");
if (start && config_get("game.start")==NULL) { if (start && config_get("game.start") == NULL) {
config_set("game.start", (const char *)start); config_set("game.start", (const char *)start);
xmlFree(start); xmlFree(start);
} }
@ -477,10 +473,11 @@ static int parse_calendar(xmlDocPtr doc)
xmlFree(newyear); xmlFree(newyear);
newyear = NULL; newyear = NULL;
} }
}
xmlXPathFreeObject(xpathCalendars); xmlXPathFreeObject(xpathCalendars);
xmlXPathFreeContext(xpath); xmlXPathFreeContext(xpath);
return rv; return 0;
} }
static int parse_ships(xmlDocPtr doc) static int parse_ships(xmlDocPtr doc)
@ -1575,13 +1572,12 @@ static int parse_spells(xmlDocPtr doc)
static void parse_ai(race * rc, xmlNodePtr node) static void parse_ai(race * rc, xmlNodePtr node)
{ {
int n; xmlChar *propValue;
n = xml_ivalue(node, "scare", 0); propValue = xmlGetProp(node, BAD_CAST "scare");
if (n>0) { if (propValue) {
attrib *a = a_new(&at_scare); rc_set_param(rc, "ai.scare", (const char *)propValue);
a->data.i = n; xmlFree(propValue);
a_add(&rc->attribs, a);
} }
rc->splitsize = xml_ivalue(node, "splitsize", 0); rc->splitsize = xml_ivalue(node, "splitsize", 0);
rc->aggression = (float)xml_fvalue(node, "aggression", 0.04); rc->aggression = (float)xml_fvalue(node, "aggression", 0.04);
@ -1734,22 +1730,11 @@ static int parse_races(xmlDocPtr doc)
else if (strcmp((const char *)child->name, "param") == 0) { else if (strcmp((const char *)child->name, "param") == 0) {
xmlChar *propName = xmlGetProp(child, BAD_CAST "name"); xmlChar *propName = xmlGetProp(child, BAD_CAST "name");
xmlChar *propValue = xmlGetProp(child, BAD_CAST "value"); xmlChar *propValue = xmlGetProp(child, BAD_CAST "value");
if (strcmp((const char *)propName, "recruit_multi")==0) { rc_set_param(rc, (const char *)propName, (const char *)propValue);
rc->recruit_multi = atof((const char *)propValue);
}
else if (strcmp((const char *)propName, "migrants.formula") == 0) {
if (propValue[0] == '1') {
rc->flags |= RCF_MIGRANTS;
}
}
else {
set_param(&rc->parameters, (const char *)propName, (const char *)propValue);
}
xmlFree(propName); xmlFree(propName);
xmlFree(propValue); xmlFree(propValue);
} }
} }
rc->recruit_multi = get_param_flt(rc->parameters, "recruit_multi", 1.0);
/* reading eressea/races/race/skill */ /* reading eressea/races/race/skill */
xpath->node = node; xpath->node = node;

View file

@ -2,6 +2,7 @@
#include "magic.h" #include "magic.h"
#include "teleport.h" #include "teleport.h"
#include "give.h"
#include <kernel/config.h> #include <kernel/config.h>
#include <kernel/race.h> #include <kernel/race.h>
@ -448,6 +449,24 @@ static void test_max_spellpoints(CuTest *tc) {
test_cleanup(); test_cleanup();
} }
static void test_familiar_mage(CuTest *tc) {
unit *um, *uf, *ut;
test_setup();
um = test_create_unit(test_create_faction(0), test_create_region(0, 0, 0));
uf = test_create_unit(um->faction, um->region);
ut = test_create_unit(um->faction, um->region);
set_number(ut, 0);
CuAssertTrue(tc, create_newfamiliar(um, uf));
CuAssertTrue(tc, is_familiar(uf));
CuAssertTrue(tc, !is_familiar(um));
CuAssertPtrEquals(tc, um, get_familiar_mage(uf));
CuAssertPtrEquals(tc, uf, get_familiar(um));
CuAssertPtrEquals(tc, NULL, give_men(1, um, ut, NULL));
CuAssertPtrEquals(tc, ut, get_familiar_mage(uf));
test_cleanup();
}
CuSuite *get_magic_suite(void) CuSuite *get_magic_suite(void)
{ {
CuSuite *suite = CuSuiteNew(); CuSuite *suite = CuSuiteNew();
@ -465,5 +484,6 @@ CuSuite *get_magic_suite(void)
SUITE_ADD_TEST(suite, test_hasspell); SUITE_ADD_TEST(suite, test_hasspell);
SUITE_ADD_TEST(suite, test_magic_resistance); SUITE_ADD_TEST(suite, test_magic_resistance);
SUITE_ADD_TEST(suite, test_max_spellpoints); SUITE_ADD_TEST(suite, test_max_spellpoints);
DISABLE_TEST(suite, test_familiar_mage);
return suite; return suite;
} }

View file

@ -66,22 +66,6 @@ attrib_type at_market = {
NULL, NULL, NULL, ATF_UNIQUE NULL, NULL, NULL, ATF_UNIQUE
}; };
int rc_luxury_trade(const struct race *rc)
{
if (rc) {
return get_param_int(rc->parameters, "luxury_trade", 1000);
}
return 1000;
}
int rc_herb_trade(const struct race *rc)
{
if (rc) {
return get_param_int(rc->parameters, "herb_trade", 500);
}
return 500;
}
#define MAX_MARKETS 128 #define MAX_MARKETS 128
#define MIN_PEASANTS 50 /* if there are at least this many peasants, you will get 1 good */ #define MIN_PEASANTS 50 /* if there are at least this many peasants, you will get 1 good */

View file

@ -86,8 +86,8 @@ static void test_rc_trade(CuTest *tc) {
rc = test_create_race("human"); rc = test_create_race("human");
CuAssertIntEquals(tc, 1000, rc_luxury_trade(rc)); CuAssertIntEquals(tc, 1000, rc_luxury_trade(rc));
CuAssertIntEquals(tc, 500, rc_herb_trade(rc)); CuAssertIntEquals(tc, 500, rc_herb_trade(rc));
set_param(&rc->parameters, "luxury_trade", "100"); rc_set_param(rc, "luxury_trade", "100");
set_param(&rc->parameters, "herb_trade", "50"); rc_set_param(rc, "herb_trade", "50");
CuAssertIntEquals(tc, 100, rc_luxury_trade(rc)); CuAssertIntEquals(tc, 100, rc_luxury_trade(rc));
CuAssertIntEquals(tc, 50, rc_herb_trade(rc)); CuAssertIntEquals(tc, 50, rc_herb_trade(rc));
test_cleanup(); test_cleanup();

View file

@ -31,7 +31,6 @@
#include "study.h" #include "study.h"
/* attributes includes */ /* attributes includes */
#include <attributes/attributes.h>
#include <attributes/targetregion.h> #include <attributes/targetregion.h>
#include <attributes/hate.h> #include <attributes/hate.h>
@ -1013,11 +1012,11 @@ static void eaten_by_monster(unit * u)
int horse = -1; int horse = -1;
const resource_type *rhorse = get_resourcetype(R_HORSE); const resource_type *rhorse = get_resourcetype(R_HORSE);
const race *rc = u_race(u); const race *rc = u_race(u);
attrib *a; int scare;
a = a_find(rc->attribs, &at_scare); scare = rc_scare(rc);
if (a) { if (scare>0) {
n = rng_int() & a->data.i * u->number; n = rng_int() % scare * u->number;
} else { } else {
n = rng_int() % (u->number / 20 + 1); n = rng_int() % (u->number / 20 + 1);
horse = 0; horse = 0;
@ -1093,10 +1092,11 @@ static void scared_by_monster(unit * u)
{ {
int n; int n;
const race *rc = u_race(u); const race *rc = u_race(u);
attrib *a; int scare;
a = a_find(rc->attribs, &at_scare);
if (a) { scare = rc_scare(rc);
n = rng_int() & a->data.i * u->number; if (scare>0) {
n = rng_int() % scare * u->number;
} else { } else {
n = rng_int() % (u->number / 4 + 1); n = rng_int() % (u->number / 4 + 1);
} }

View file

@ -31,10 +31,9 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#include <assert.h> #include <assert.h>
static double rc_popularity(const struct race *rc) static double popularity(void)
{ {
int pop = get_param_int(rc->parameters, "morale", MORALE_AVERAGE); return 1.0 / (MORALE_AVERAGE - MORALE_COOLDOWN); /* 10 turns average */
return 1.0 / (pop - MORALE_COOLDOWN); /* 10 turns average */
} }
void morale_update(region *r) { void morale_update(region *r) {
@ -52,7 +51,7 @@ void morale_update(region *r) {
if (morale < maxmorale) { if (morale < maxmorale) {
if (stability > MORALE_COOLDOWN && r->land->ownership->owner if (stability > MORALE_COOLDOWN && r->land->ownership->owner
&& morale < MORALE_MAX) { && morale < MORALE_MAX) {
double ch = rc_popularity(r->land->ownership->owner->race); double ch = popularity();
if (is_cursed(r->attribs, C_GENEROUS, 0)) { if (is_cursed(r->attribs, C_GENEROUS, 0)) {
ch *= 1.2; /* 20% improvement */ ch *= 1.2; /* 20% improvement */
} }

View file

@ -95,7 +95,6 @@
#include <triggers/createunit.h> #include <triggers/createunit.h>
#include <triggers/killunit.h> #include <triggers/killunit.h>
#include <triggers/timeout.h> #include <triggers/timeout.h>
#include <triggers/unitmessage.h>
/* attributes includes */ /* attributes includes */
#include <attributes/targetregion.h> #include <attributes/targetregion.h>

View file

@ -11,7 +11,6 @@ killunit.c
shock.c shock.c
timeout.c timeout.c
triggers.c triggers.c
unitmessage.c
) )
FOREACH(_FILE ${_FILES}) FOREACH(_FILE ${_FILES})
LIST(APPEND _SOURCES ${PROJECT_NAME}/${_FILE}) LIST(APPEND _SOURCES ${PROJECT_NAME}/${_FILE})

View file

@ -28,7 +28,6 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#include <triggers/killunit.h> #include <triggers/killunit.h>
#include <triggers/shock.h> #include <triggers/shock.h>
#include <triggers/timeout.h> #include <triggers/timeout.h>
#include <triggers/unitmessage.h>
#include <triggers/clonedied.h> #include <triggers/clonedied.h>
/* util includes */ /* util includes */
@ -47,7 +46,6 @@ void register_triggers(void)
tt_register(&tt_giveitem); tt_register(&tt_giveitem);
tt_register(&tt_killunit); tt_register(&tt_killunit);
tt_register(&tt_shock); tt_register(&tt_shock);
tt_register(&tt_unitmessage);
tt_register(&tt_timeout); tt_register(&tt_timeout);
tt_register(&tt_clonedied); tt_register(&tt_clonedied);
} }

View file

@ -1,124 +0,0 @@
/*
+-------------------+ Enno Rehling <enno@eressea.de>
| Eressea PBEM host | Christian Schlittchen <corwin@amber.kn-bremen.de>
| (c) 1998 - 2008 | Katja Zedel <katze@felidae.kn-bremen.de>
+-------------------+
This program may not be used, modified or distributed
without prior permission by the authors of Eressea.
*/
#include <platform.h>
#include "unitmessage.h"
/* kernel includes */
#include <kernel/unit.h>
#include <kernel/faction.h>
#include <kernel/messages.h>
/* util includes */
#include <util/attrib.h>
#include <util/base36.h>
#include <util/event.h>
#include <util/gamedata.h>
#include <util/goodies.h>
#include <util/language.h>
#include <util/log.h>
#include <util/resolve.h>
#include <storage.h>
/* ansi includes */
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <assert.h>
/***
** give an item to someone
**/
typedef struct unitmessage_data {
struct unit *target;
char *string;
int type;
int level;
} unitmessage_data;
static void unitmessage_init(trigger * t)
{
t->data.v = calloc(sizeof(unitmessage_data), 1);
}
static void unitmessage_free(trigger * t)
{
unitmessage_data *sd = (unitmessage_data *)t->data.v;
free(sd->string);
free(t->data.v);
}
static int unitmessage_handle(trigger * t, void *data)
{
/* call an event handler on unitmessage.
* data.v -> ( variant event, int timer )
*/
unitmessage_data *td = (unitmessage_data *)t->data.v;
if (td->target && td->target->no) {
struct faction *f = td->target->faction;
const char * str = LOC(f->locale, td->string);
/* bug found in turn 733: sometimes, alps have f*cked up messages */
if (td->string && td->string[0]) {
addmessage(td->target->region, f, str, td->type,
td->level);
}
}
UNUSED_ARG(data);
return 0;
}
static void unitmessage_write(const trigger * t, struct storage *store)
{
unitmessage_data *td = (unitmessage_data *)t->data.v;
write_unit_reference(td->target, store);
WRITE_TOK(store, td->string);
WRITE_INT(store, td->type);
WRITE_INT(store, td->level);
}
static int unitmessage_read(trigger * t, gamedata *data)
{
unitmessage_data *td = (unitmessage_data *)t->data.v;
char zText[256];
int result = read_reference(&td->target, data, read_unit_reference,
resolve_unit);
READ_TOK(data->store, zText, sizeof(zText));
td->string = strdup(zText);
READ_INT(data->store, &td->type);
READ_INT(data->store, &td->level);
if (result == 0 && td->target == NULL) {
return AT_READ_FAIL;
}
return AT_READ_OK;
}
trigger_type tt_unitmessage = {
"unitmessage",
unitmessage_init,
unitmessage_free,
unitmessage_handle,
unitmessage_write,
unitmessage_read
};
trigger *trigger_unitmessage(unit * target, const char *string, int type,
int level)
{
trigger *t = t_new(&tt_unitmessage);
unitmessage_data *td = (unitmessage_data *)t->data.v;
td->target = target;
td->string = strdup(string);
td->type = type;
td->level = level;
return t;
}

View file

@ -1,37 +0,0 @@
/*
Copyright (c) 1998-2015, Enno Rehling <enno@eressea.de>
Katja Zedel <katze@felidae.kn-bremen.de
Christian Schlittchen <corwin@amber.kn-bremen.de>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
**/
#ifndef UNITMESSAGE_H
#define UNITMESSAGE_H
#ifdef __cplusplus
extern "C" {
#endif
/* all types we use are defined here to reduce dependencies */
struct trigger_type;
struct trigger;
struct unit;
extern struct trigger_type tt_unitmessage;
extern struct trigger *trigger_unitmessage(struct unit *target,
const char *string, int type, int level);
#ifdef __cplusplus
}
#endif
#endif

View file

@ -59,7 +59,7 @@ static void help_feed(unit * donor, unit * u, int *need_p)
} }
static const char *hunger_damage(const race *rc) { static const char *hunger_damage(const race *rc) {
const char * damage = rc->parameters ? get_param(rc->parameters, "hunger.damage") : NULL; const char * damage = rc_hungerdamage(rc);
if (!damage) { if (!damage) {
damage = config_get("hunger.damage"); damage = config_get("hunger.damage");
} }
@ -98,11 +98,11 @@ static bool hunger(int number, unit * u)
deathcounts(r, dead); deathcounts(r, dead);
} }
if (hpsub > 0) { if (hpsub > 0) {
/* Jetzt die Schäden der nicht gestorbenen abziehen. */ /* Jetzt die Sch<EFBFBD>den der nicht gestorbenen abziehen. */
u->hp -= hpsub; u->hp -= hpsub;
/* Meldung nur, wenn noch keine für Tote generiert. */ /* Meldung nur, wenn noch keine f<EFBFBD>r Tote generiert. */
if (dead == 0) { if (dead == 0) {
/* Durch unzureichende Ernährung wird %s geschwächt */ /* Durch unzureichende Ern<EFBFBD>hrung wird %s geschw<68>cht */
ADDMSG(&u->faction->msgs, msg_message("malnourish", "unit region", u, r)); ADDMSG(&u->faction->msgs, msg_message("malnourish", "unit region", u, r));
} }
} }
@ -125,13 +125,13 @@ void get_food(region * r)
return; return;
} }
/* 1. Versorgung von eigenen Einheiten. Das vorhandene Silber /* 1. Versorgung von eigenen Einheiten. Das vorhandene Silber
* wird zunächst so auf die Einheiten aufgeteilt, dass idealerweise * wird zun<EFBFBD>chst so auf die Einheiten aufgeteilt, dass idealerweise
* jede Einheit genug Silber für ihren Unterhalt hat. */ * jede Einheit genug Silber f<EFBFBD>r ihren Unterhalt hat. */
for (u = r->units; u; u = u->next) { for (u = r->units; u; u = u->next) {
int need = lifestyle(u); int need = lifestyle(u);
/* Erstmal zurücksetzen */ /* Erstmal zur<EFBFBD>cksetzen */
freset(u, UFL_HUNGER); freset(u, UFL_HUNGER);
if (u->ship && (u->ship->flags & SF_FISHING)) { if (u->ship && (u->ship->flags & SF_FISHING)) {
@ -230,7 +230,7 @@ void get_food(region * r)
} }
/* 3. bestimmen, wie viele Bauern gefressen werden. /* 3. bestimmen, wie viele Bauern gefressen werden.
* bei fehlenden Bauern den Dämon hungern lassen * bei fehlenden Bauern den D<EFBFBD>mon hungern lassen
*/ */
for (u = r->units; u; u = u->next) { for (u = r->units; u; u = u->next) {
if (u_race(u) == rc_demon) { if (u_race(u) == rc_demon) {
@ -293,7 +293,7 @@ void get_food(region * r)
} }
rsetpeasants(r, peasantfood / 10); rsetpeasants(r, peasantfood / 10);
/* 3. Von den überlebenden das Geld abziehen: */ /* 3. Von den <EFBFBD>berlebenden das Geld abziehen: */
for (u = r->units; u; u = u->next) { for (u = r->units; u; u = u->next) {
int need = MIN(get_money(u), lifestyle(u)); int need = MIN(get_money(u), lifestyle(u));
change_money(u, -need); change_money(u, -need);

View file

@ -300,6 +300,9 @@ void init_translations(const struct locale *lang, int ut, const char * (*string_
struct critbit_tree ** cb = (struct critbit_tree **)tokens; struct critbit_tree ** cb = (struct critbit_tree **)tokens;
add_translation(cb, key, i); add_translation(cb, key, i);
} }
else {
log_warning("no translation for %s in locale %s", s, lang->name);
}
} }
} }
} }