forked from github/server
Merge pull request #651 from ennorehling/develop
refactoring: race, locale, dict removal pt. 1
This commit is contained in:
commit
17fc2adcb5
43 changed files with 358 additions and 706 deletions
2
cmake
2
cmake
|
@ -1 +1 @@
|
|||
Subproject commit d88983c7ff4bc3a4884a7c3f74e8190bac5eab23
|
||||
Subproject commit f1fb3943ace59994d90d71a891b80033dc2700a2
|
|
@ -1,19 +1,5 @@
|
|||
-- 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
|
||||
|
||||
local embassy = {}
|
||||
|
@ -34,10 +20,10 @@ function embassy.update()
|
|||
eressea.log.debug("updating embassies in " .. tostring(home))
|
||||
local u
|
||||
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
|
||||
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
|
||||
|
|
|
@ -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 == eressea.config.read(rules .. 'config.json', confdir), "could not read JSON data")
|
||||
end
|
||||
eressea.game.reset()
|
||||
|
|
|
@ -330,17 +330,6 @@ function test_message()
|
|||
return msg
|
||||
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()
|
||||
local fail = 1
|
||||
local function msg_handler(u, evt)
|
||||
|
|
|
@ -46,23 +46,17 @@ function test_snowglobe()
|
|||
local r2 = region.create(1, 0, "ocean")
|
||||
local f = faction.create("snowglobe2@eressea.de", "human", "de")
|
||||
local u = unit.create(f, r1, 1)
|
||||
local have = 6
|
||||
local fail = 0
|
||||
u:add_item("snowglobe", have)
|
||||
local xform = { ocean = "glacier", glacier = "glacier", firewall = "volcano", volcano = "mountain", desert = "plain", plain = "plain" }
|
||||
u:clear_orders()
|
||||
u:add_order("BENUTZEN 1 Schneekugel Ost")
|
||||
local xform = { ocean = "glacier", glacier = "glacier", firewall = "volcano", desert = "plain", volcano = "mountain", plain = "plain" }
|
||||
for k, v in pairs(xform) do
|
||||
r2.terrain = k
|
||||
process_orders()
|
||||
use_snowglobe(u, 1, "Ost", nil)
|
||||
assert_equal(v, r2.terrain)
|
||||
if k~=v then
|
||||
have=have - 1
|
||||
else
|
||||
if k==v then
|
||||
fail = fail + 1
|
||||
assert_equal(fail, f:count_msg_type('target_region_invalid'))
|
||||
end
|
||||
assert_equal(have, u:get_item("snowglobe"))
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -148,7 +148,6 @@ set(SERVER_SRC
|
|||
bind_locale.c
|
||||
bind_eressea.c
|
||||
bind_faction.c
|
||||
bind_dict.c
|
||||
bind_order.c
|
||||
bindings.c
|
||||
bind_message.c
|
||||
|
|
|
@ -58,10 +58,6 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|||
|
||||
#include <storage.h>
|
||||
|
||||
attrib_type at_scare = { // monster scares peasants
|
||||
"scare", NULL, NULL, NULL, a_writeint, a_readint
|
||||
};
|
||||
|
||||
attrib_type at_unitdissolve = {
|
||||
"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)
|
||||
{
|
||||
/* Alle speicherbaren Attribute müssen hier registriert werden */
|
||||
at_register(&at_scare);
|
||||
at_register(&at_shiptrail);
|
||||
at_register(&at_familiar);
|
||||
at_register(&at_familiarmage);
|
||||
|
|
|
@ -23,7 +23,6 @@ extern "C" {
|
|||
#endif
|
||||
|
||||
struct attrib_type;
|
||||
extern struct attrib_type at_scare;
|
||||
extern void register_attributes(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
|
|
@ -19,6 +19,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|||
#include <platform.h>
|
||||
#include <kernel/config.h>
|
||||
#include "dict.h"
|
||||
#include "key.h"
|
||||
|
||||
/* kernel includes */
|
||||
#include <kernel/building.h>
|
||||
|
@ -29,6 +30,8 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|||
|
||||
/* util includes */
|
||||
#include <util/attrib.h>
|
||||
#include <util/base36.h>
|
||||
#include <util/log.h>
|
||||
#include <util/gamedata.h>
|
||||
#include <util/resolve.h>
|
||||
|
||||
|
@ -54,46 +57,6 @@ typedef struct dict_data {
|
|||
} 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)
|
||||
{
|
||||
storage *store = data->store;
|
||||
|
@ -164,7 +127,7 @@ static int dict_read(attrib * a, void *owner, gamedata *data)
|
|||
default:
|
||||
return AT_READ_FAIL;
|
||||
}
|
||||
return AT_READ_OK;
|
||||
return AT_READ_DEPR;
|
||||
}
|
||||
|
||||
static void dict_init(attrib * a)
|
||||
|
@ -184,100 +147,46 @@ static void dict_done(attrib * a)
|
|||
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 = {
|
||||
"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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,13 +26,6 @@ extern "C" {
|
|||
|
||||
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
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -66,7 +66,7 @@ attrib_type at_keys = {
|
|||
NULL
|
||||
};
|
||||
|
||||
void a_upgradekeys(attrib **alist, attrib *abegin) {
|
||||
static void a_upgradekeys(attrib **alist, attrib *abegin) {
|
||||
int n = 0, *keys = 0;
|
||||
int i = 0, val[4];
|
||||
attrib *a, *ak = a_find(*alist, &at_keys);
|
||||
|
|
|
@ -760,10 +760,6 @@ bool missile)
|
|||
if (is_riding(t) && (wtype == NULL || (fval(wtype, WTF_HORSEBONUS)
|
||||
&& !fval(wtype, WTF_MISSILE)))) {
|
||||
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) {
|
||||
|
|
|
@ -225,10 +225,10 @@ static void test_natural_armor(CuTest * tc)
|
|||
set_level(u, SK_STAMINA, 2);
|
||||
CuAssertIntEquals(tc, 0, rc_armor_bonus(rc));
|
||||
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, 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, 1, natural_armor(u));
|
||||
test_cleanup();
|
||||
|
|
|
@ -13,7 +13,6 @@ without prior permission by the authors of Eressea.
|
|||
#include <platform.h>
|
||||
#include "bind_building.h"
|
||||
#include "bind_unit.h"
|
||||
#include "bind_dict.h"
|
||||
|
||||
#include <kernel/config.h>
|
||||
#include <kernel/unit.h>
|
||||
|
@ -41,13 +40,6 @@ int tolua_buildinglist_next(lua_State * L)
|
|||
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)
|
||||
{
|
||||
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_building_set_size);
|
||||
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);
|
||||
|
||||
}
|
||||
|
|
|
@ -20,9 +20,7 @@
|
|||
#include "kernel/terrain.h"
|
||||
|
||||
void config_reset(void) {
|
||||
default_locale = 0;
|
||||
free_config();
|
||||
free_locales();
|
||||
free_nrmesssages();
|
||||
free_spells();
|
||||
free_buildingtypes();
|
||||
|
@ -37,7 +35,6 @@ int config_parse(const char *json)
|
|||
if (conf) {
|
||||
json_config(conf);
|
||||
cJSON_Delete(conf);
|
||||
init_locales();
|
||||
return 0;
|
||||
}
|
||||
else {
|
||||
|
|
185
src/bind_dict.c
185
src/bind_dict.c
|
@ -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);
|
||||
}
|
|
@ -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
|
|
@ -9,6 +9,8 @@
|
|||
#include <kernel/config.h>
|
||||
#include <kernel/save.h>
|
||||
|
||||
#include <util/language.h>
|
||||
|
||||
#include <stream.h>
|
||||
#include <filestream.h>
|
||||
|
||||
|
@ -16,6 +18,7 @@
|
|||
void eressea_free_game(void) {
|
||||
free_gamedata();
|
||||
init_resources();
|
||||
init_locales();
|
||||
}
|
||||
|
||||
int eressea_read_game(const char * filename) {
|
||||
|
|
|
@ -13,7 +13,6 @@ without prior permission by the authors of Eressea.
|
|||
#include <platform.h>
|
||||
#include "bind_faction.h"
|
||||
#include "bind_unit.h"
|
||||
#include "bind_dict.h"
|
||||
#include "bindings.h"
|
||||
#include "helpers.h"
|
||||
|
||||
|
@ -27,7 +26,9 @@ without prior permission by the authors of Eressea.
|
|||
#include <kernel/race.h>
|
||||
#include <kernel/region.h>
|
||||
#include <kernel/spellbook.h>
|
||||
#include <attributes/key.h>
|
||||
|
||||
#include <util/base36.h>
|
||||
#include <util/language.h>
|
||||
#include <util/log.h>
|
||||
#include <util/password.h>
|
||||
|
@ -241,6 +242,32 @@ static int tolua_faction_addnotice(lua_State * L)
|
|||
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) {
|
||||
faction *self = (faction *)tolua_tousertype(L, 1, 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;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
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 */
|
||||
tolua_function(L, TOLUA_CAST "count_msg_type", tolua_faction_count_msg_type);
|
||||
|
||||
tolua_variable(L, TOLUA_CAST "objects", tolua_faction_get_objects,
|
||||
NULL);
|
||||
tolua_function(L, TOLUA_CAST "get_key", tolua_faction_getkey);
|
||||
tolua_function(L, TOLUA_CAST "set_key", tolua_faction_setkey);
|
||||
}
|
||||
tolua_endmodule(L);
|
||||
}
|
||||
|
|
|
@ -14,7 +14,6 @@ without prior permission by the authors of Eressea.
|
|||
#include "bind_region.h"
|
||||
#include "bind_unit.h"
|
||||
#include "bind_ship.h"
|
||||
#include "bind_dict.h"
|
||||
#include "bind_building.h"
|
||||
|
||||
#include "chaos.h"
|
||||
|
@ -36,10 +35,11 @@ without prior permission by the authors of Eressea.
|
|||
|
||||
#include <util/attrib.h>
|
||||
#include <util/base36.h>
|
||||
#include <critbit.h>
|
||||
#include <util/language.h>
|
||||
#include <util/log.h>
|
||||
|
||||
#include <critbit.h>
|
||||
|
||||
#include <tolua.h>
|
||||
|
||||
#include <assert.h>
|
||||
|
@ -434,13 +434,6 @@ static int tolua_region_set_resource(lua_State * L)
|
|||
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)
|
||||
{
|
||||
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 "set_key", tolua_region_setkey);
|
||||
|
||||
tolua_variable(L, TOLUA_CAST "objects", tolua_region_get_objects, 0);
|
||||
}
|
||||
tolua_endmodule(L);
|
||||
|
||||
|
|
|
@ -13,7 +13,6 @@ without prior permission by the authors of Eressea.
|
|||
#include <platform.h>
|
||||
#include "bind_ship.h"
|
||||
#include "bind_unit.h"
|
||||
#include "bind_dict.h"
|
||||
|
||||
#include "move.h"
|
||||
|
||||
|
@ -115,13 +114,6 @@ static int tolua_ship_get_units(lua_State * L)
|
|||
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)
|
||||
{
|
||||
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 "damage", tolua_ship_get_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_endmodule(L);
|
||||
|
|
|
@ -13,7 +13,6 @@ without prior permission by the authors of Eressea.
|
|||
#include <platform.h>
|
||||
|
||||
#include "bind_unit.h"
|
||||
#include "bind_dict.h"
|
||||
#include "alchemy.h"
|
||||
#include "bindings.h"
|
||||
#include "move.h"
|
||||
|
@ -67,12 +66,6 @@ static int tolua_bufunit(lua_State * L) {
|
|||
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)
|
||||
{
|
||||
|
@ -1013,7 +1006,6 @@ void tolua_unit_open(lua_State * L)
|
|||
tolua_unit_set_race);
|
||||
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_endmodule(L);
|
||||
|
|
|
@ -15,7 +15,6 @@ without prior permission by the authors of Eressea.
|
|||
#include "bind_unit.h"
|
||||
#include "bind_storage.h"
|
||||
#include "bind_building.h"
|
||||
#include "bind_dict.h"
|
||||
#include "bind_message.h"
|
||||
#include "bind_building.h"
|
||||
#include "bind_faction.h"
|
||||
|
@ -517,7 +516,7 @@ static void reset_game(void)
|
|||
for (f = factions; f; f = f->next) {
|
||||
f->flags &= FFL_SAVEMASK;
|
||||
}
|
||||
init_locales();
|
||||
// init_locales();
|
||||
}
|
||||
|
||||
static int tolua_process_orders(lua_State * L)
|
||||
|
@ -1143,7 +1142,6 @@ lua_State *lua_init(const dictionary *inifile) {
|
|||
tolua_unit_open(L);
|
||||
tolua_message_open(L);
|
||||
tolua_order_open(L);
|
||||
tolua_dict_open(L);
|
||||
#ifdef USE_CURSES
|
||||
tolua_gmtool_open(L);
|
||||
#endif
|
||||
|
|
|
@ -422,10 +422,7 @@ static void expandrecruit(region * r, request * recruitorders)
|
|||
|
||||
static int recruit_cost(const faction * f, const race * rc)
|
||||
{
|
||||
if (is_monsters(f) || f->race == rc) {
|
||||
return rc->recruitcost;
|
||||
}
|
||||
else if (valid_race(f, rc)) {
|
||||
if (is_monsters(f) || valid_race(f, rc)) {
|
||||
return rc->recruitcost;
|
||||
}
|
||||
return -1;
|
||||
|
|
|
@ -563,10 +563,7 @@ bool valid_race(const struct faction *f, const struct race *rc)
|
|||
if (f->race == rc)
|
||||
return true;
|
||||
else {
|
||||
const char *str = get_param(f->race->parameters, "other_race");
|
||||
if (str)
|
||||
return rc_find(str) == rc;
|
||||
return false;
|
||||
return rc_otherrace(f->race) == rc;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -209,6 +209,22 @@ static void test_max_migrants(CuTest *tc) {
|
|||
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 *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_bug);
|
||||
SUITE_ADD_TEST(suite, test_check_passwd);
|
||||
SUITE_ADD_TEST(suite, test_valid_race);
|
||||
return suite;
|
||||
}
|
||||
|
|
|
@ -44,6 +44,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|||
#include <util/language.h>
|
||||
#include <util/log.h>
|
||||
#include <util/rng.h>
|
||||
#include <util/variant.h>
|
||||
|
||||
#include <storage.h>
|
||||
|
||||
|
@ -77,6 +78,79 @@ static const char *racenames[MAXRACES] = {
|
|||
"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)
|
||||
{
|
||||
void **tokens = get_translations(lang, UT_RACES);
|
||||
|
@ -184,12 +258,26 @@ void free_races(void) {
|
|||
while (races) {
|
||||
int i;
|
||||
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) {
|
||||
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);
|
||||
free_params(&races->parameters);
|
||||
free(xrefs);
|
||||
xrefs = 0;
|
||||
free(races->_name);
|
||||
|
@ -290,8 +378,46 @@ double rc_maxaura(const race *rc) {
|
|||
return rc->maxaura / 100.0;
|
||||
}
|
||||
|
||||
int rc_armor_bonus(const race *rc) {
|
||||
return get_param_int(rc->parameters, "armor.stamina", 0);
|
||||
const char * rc_hungerdamage(const race *rc)
|
||||
{
|
||||
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)
|
||||
|
@ -299,6 +425,38 @@ int rc_migrants_formula(const race *rc)
|
|||
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 * postfix = 0;
|
||||
if (!rc) {
|
||||
|
|
|
@ -47,6 +47,7 @@ extern "C" {
|
|||
struct spell;
|
||||
struct spellref;
|
||||
struct locale;
|
||||
struct rcoption;
|
||||
|
||||
extern int num_races;
|
||||
|
||||
|
@ -104,7 +105,7 @@ extern "C" {
|
|||
typedef struct att {
|
||||
int type;
|
||||
union {
|
||||
const char *dice;
|
||||
char *dice;
|
||||
struct spellref *sp;
|
||||
} data;
|
||||
int flags;
|
||||
|
@ -137,7 +138,6 @@ extern "C" {
|
|||
int df_default; /* Verteidigungsskill Unbewaffnet (default: -2) */
|
||||
int at_bonus; /* Ver<65>ndert den Angriffsskill (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;
|
||||
signed char *study_speed; /* study-speed-bonus in points/turn (0=30 Tage) */
|
||||
int flags;
|
||||
|
@ -153,8 +153,9 @@ extern "C" {
|
|||
struct item *(*itemdrop) (const struct race *, int size);
|
||||
void(*init_familiar) (struct unit *);
|
||||
|
||||
struct rcoption *options; // rarely used properties
|
||||
|
||||
const struct race *familiars[MAXMAGIETYP];
|
||||
struct attrib *attribs;
|
||||
struct race *next;
|
||||
} race;
|
||||
|
||||
|
@ -184,9 +185,16 @@ extern "C" {
|
|||
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);
|
||||
|
||||
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_maxaura(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_LOG10 1
|
||||
|
|
|
@ -84,6 +84,23 @@ static void test_old_race(CuTest *tc)
|
|||
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 *suite = CuSuiteNew();
|
||||
|
@ -92,6 +109,7 @@ CuSuite *get_race_suite(void)
|
|||
SUITE_ADD_TEST(suite, test_rc_name);
|
||||
SUITE_ADD_TEST(suite, test_rc_defaults);
|
||||
SUITE_ADD_TEST(suite, test_rc_find);
|
||||
SUITE_ADD_TEST(suite, test_rc_set_param);
|
||||
return suite;
|
||||
}
|
||||
|
||||
|
|
|
@ -1470,7 +1470,6 @@ int readgame(const char *filename)
|
|||
FILE *F;
|
||||
size_t sz;
|
||||
|
||||
init_locales();
|
||||
log_debug("- reading game data from %s", filename);
|
||||
join_path(datapath(), filename, path, sizeof(path));
|
||||
|
||||
|
|
|
@ -358,16 +358,12 @@ static int parse_calendar(xmlDocPtr doc)
|
|||
xmlXPathContextPtr xpath = xmlXPathNewContext(doc);
|
||||
xmlXPathObjectPtr xpathCalendars;
|
||||
xmlNodeSetPtr nsetCalendars;
|
||||
int c, rv = 0;
|
||||
|
||||
/* reading eressea/buildings/building */
|
||||
xpathCalendars = xmlXPathEvalExpression(BAD_CAST "/eressea/calendar", xpath);
|
||||
nsetCalendars = xpathCalendars->nodesetval;
|
||||
months_per_year = 0;
|
||||
if (nsetCalendars == NULL || nsetCalendars->nodeNr == 0) {
|
||||
rv = -1;
|
||||
}
|
||||
else
|
||||
if (nsetCalendars != NULL && nsetCalendars->nodeNr != 0) {
|
||||
int c;
|
||||
for (c = 0; c != nsetCalendars->nodeNr; ++c) {
|
||||
xmlNodePtr calendar = nsetCalendars->nodeTab[c];
|
||||
xmlXPathObjectPtr xpathWeeks, xpathMonths, xpathSeasons;
|
||||
|
@ -377,7 +373,7 @@ static int parse_calendar(xmlDocPtr doc)
|
|||
xmlChar *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);
|
||||
xmlFree(start);
|
||||
}
|
||||
|
@ -477,10 +473,11 @@ static int parse_calendar(xmlDocPtr doc)
|
|||
xmlFree(newyear);
|
||||
newyear = NULL;
|
||||
}
|
||||
}
|
||||
xmlXPathFreeObject(xpathCalendars);
|
||||
xmlXPathFreeContext(xpath);
|
||||
|
||||
return rv;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int parse_ships(xmlDocPtr doc)
|
||||
|
@ -1575,13 +1572,12 @@ static int parse_spells(xmlDocPtr doc)
|
|||
|
||||
static void parse_ai(race * rc, xmlNodePtr node)
|
||||
{
|
||||
int n;
|
||||
xmlChar *propValue;
|
||||
|
||||
n = xml_ivalue(node, "scare", 0);
|
||||
if (n>0) {
|
||||
attrib *a = a_new(&at_scare);
|
||||
a->data.i = n;
|
||||
a_add(&rc->attribs, a);
|
||||
propValue = xmlGetProp(node, BAD_CAST "scare");
|
||||
if (propValue) {
|
||||
rc_set_param(rc, "ai.scare", (const char *)propValue);
|
||||
xmlFree(propValue);
|
||||
}
|
||||
rc->splitsize = xml_ivalue(node, "splitsize", 0);
|
||||
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) {
|
||||
xmlChar *propName = xmlGetProp(child, BAD_CAST "name");
|
||||
xmlChar *propValue = xmlGetProp(child, BAD_CAST "value");
|
||||
if (strcmp((const char *)propName, "recruit_multi")==0) {
|
||||
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);
|
||||
}
|
||||
rc_set_param(rc, (const char *)propName, (const char *)propValue);
|
||||
xmlFree(propName);
|
||||
xmlFree(propValue);
|
||||
}
|
||||
}
|
||||
rc->recruit_multi = get_param_flt(rc->parameters, "recruit_multi", 1.0);
|
||||
|
||||
/* reading eressea/races/race/skill */
|
||||
xpath->node = node;
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
#include "magic.h"
|
||||
#include "teleport.h"
|
||||
#include "give.h"
|
||||
|
||||
#include <kernel/config.h>
|
||||
#include <kernel/race.h>
|
||||
|
@ -448,6 +449,24 @@ static void test_max_spellpoints(CuTest *tc) {
|
|||
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 *suite = CuSuiteNew();
|
||||
|
@ -465,5 +484,6 @@ CuSuite *get_magic_suite(void)
|
|||
SUITE_ADD_TEST(suite, test_hasspell);
|
||||
SUITE_ADD_TEST(suite, test_magic_resistance);
|
||||
SUITE_ADD_TEST(suite, test_max_spellpoints);
|
||||
DISABLE_TEST(suite, test_familiar_mage);
|
||||
return suite;
|
||||
}
|
||||
|
|
16
src/market.c
16
src/market.c
|
@ -66,22 +66,6 @@ attrib_type at_market = {
|
|||
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 MIN_PEASANTS 50 /* if there are at least this many peasants, you will get 1 good */
|
||||
|
||||
|
|
|
@ -86,8 +86,8 @@ static void test_rc_trade(CuTest *tc) {
|
|||
rc = test_create_race("human");
|
||||
CuAssertIntEquals(tc, 1000, rc_luxury_trade(rc));
|
||||
CuAssertIntEquals(tc, 500, rc_herb_trade(rc));
|
||||
set_param(&rc->parameters, "luxury_trade", "100");
|
||||
set_param(&rc->parameters, "herb_trade", "50");
|
||||
rc_set_param(rc, "luxury_trade", "100");
|
||||
rc_set_param(rc, "herb_trade", "50");
|
||||
CuAssertIntEquals(tc, 100, rc_luxury_trade(rc));
|
||||
CuAssertIntEquals(tc, 50, rc_herb_trade(rc));
|
||||
test_cleanup();
|
||||
|
|
|
@ -31,7 +31,6 @@
|
|||
#include "study.h"
|
||||
|
||||
/* attributes includes */
|
||||
#include <attributes/attributes.h>
|
||||
#include <attributes/targetregion.h>
|
||||
#include <attributes/hate.h>
|
||||
|
||||
|
@ -1013,11 +1012,11 @@ static void eaten_by_monster(unit * u)
|
|||
int horse = -1;
|
||||
const resource_type *rhorse = get_resourcetype(R_HORSE);
|
||||
const race *rc = u_race(u);
|
||||
attrib *a;
|
||||
int scare;
|
||||
|
||||
a = a_find(rc->attribs, &at_scare);
|
||||
if (a) {
|
||||
n = rng_int() & a->data.i * u->number;
|
||||
scare = rc_scare(rc);
|
||||
if (scare>0) {
|
||||
n = rng_int() % scare * u->number;
|
||||
} else {
|
||||
n = rng_int() % (u->number / 20 + 1);
|
||||
horse = 0;
|
||||
|
@ -1093,10 +1092,11 @@ static void scared_by_monster(unit * u)
|
|||
{
|
||||
int n;
|
||||
const race *rc = u_race(u);
|
||||
attrib *a;
|
||||
a = a_find(rc->attribs, &at_scare);
|
||||
if (a) {
|
||||
n = rng_int() & a->data.i * u->number;
|
||||
int scare;
|
||||
|
||||
scare = rc_scare(rc);
|
||||
if (scare>0) {
|
||||
n = rng_int() % scare * u->number;
|
||||
} else {
|
||||
n = rng_int() % (u->number / 4 + 1);
|
||||
}
|
||||
|
|
|
@ -31,10 +31,9 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|||
|
||||
#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 / (pop - MORALE_COOLDOWN); /* 10 turns average */
|
||||
return 1.0 / (MORALE_AVERAGE - MORALE_COOLDOWN); /* 10 turns average */
|
||||
}
|
||||
|
||||
void morale_update(region *r) {
|
||||
|
@ -52,7 +51,7 @@ void morale_update(region *r) {
|
|||
if (morale < maxmorale) {
|
||||
if (stability > MORALE_COOLDOWN && r->land->ownership->owner
|
||||
&& morale < MORALE_MAX) {
|
||||
double ch = rc_popularity(r->land->ownership->owner->race);
|
||||
double ch = popularity();
|
||||
if (is_cursed(r->attribs, C_GENEROUS, 0)) {
|
||||
ch *= 1.2; /* 20% improvement */
|
||||
}
|
||||
|
|
|
@ -95,7 +95,6 @@
|
|||
#include <triggers/createunit.h>
|
||||
#include <triggers/killunit.h>
|
||||
#include <triggers/timeout.h>
|
||||
#include <triggers/unitmessage.h>
|
||||
|
||||
/* attributes includes */
|
||||
#include <attributes/targetregion.h>
|
||||
|
|
|
@ -11,7 +11,6 @@ killunit.c
|
|||
shock.c
|
||||
timeout.c
|
||||
triggers.c
|
||||
unitmessage.c
|
||||
)
|
||||
FOREACH(_FILE ${_FILES})
|
||||
LIST(APPEND _SOURCES ${PROJECT_NAME}/${_FILE})
|
||||
|
|
|
@ -28,7 +28,6 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|||
#include <triggers/killunit.h>
|
||||
#include <triggers/shock.h>
|
||||
#include <triggers/timeout.h>
|
||||
#include <triggers/unitmessage.h>
|
||||
#include <triggers/clonedied.h>
|
||||
|
||||
/* util includes */
|
||||
|
@ -47,7 +46,6 @@ void register_triggers(void)
|
|||
tt_register(&tt_giveitem);
|
||||
tt_register(&tt_killunit);
|
||||
tt_register(&tt_shock);
|
||||
tt_register(&tt_unitmessage);
|
||||
tt_register(&tt_timeout);
|
||||
tt_register(&tt_clonedied);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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
|
18
src/upkeep.c
18
src/upkeep.c
|
@ -59,7 +59,7 @@ static void help_feed(unit * donor, unit * u, int *need_p)
|
|||
}
|
||||
|
||||
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) {
|
||||
damage = config_get("hunger.damage");
|
||||
}
|
||||
|
@ -98,11 +98,11 @@ static bool hunger(int number, unit * u)
|
|||
deathcounts(r, dead);
|
||||
}
|
||||
if (hpsub > 0) {
|
||||
/* Jetzt die Schäden der nicht gestorbenen abziehen. */
|
||||
/* Jetzt die Sch<EFBFBD>den der nicht gestorbenen abziehen. */
|
||||
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) {
|
||||
/* 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));
|
||||
}
|
||||
}
|
||||
|
@ -125,13 +125,13 @@ void get_food(region * r)
|
|||
return;
|
||||
}
|
||||
/* 1. Versorgung von eigenen Einheiten. Das vorhandene Silber
|
||||
* wird zunächst so auf die Einheiten aufgeteilt, dass idealerweise
|
||||
* jede Einheit genug Silber für ihren Unterhalt hat. */
|
||||
* wird zun<EFBFBD>chst so auf die Einheiten aufgeteilt, dass idealerweise
|
||||
* jede Einheit genug Silber f<EFBFBD>r ihren Unterhalt hat. */
|
||||
|
||||
for (u = r->units; u; u = u->next) {
|
||||
int need = lifestyle(u);
|
||||
|
||||
/* Erstmal zurücksetzen */
|
||||
/* Erstmal zur<EFBFBD>cksetzen */
|
||||
freset(u, UFL_HUNGER);
|
||||
|
||||
if (u->ship && (u->ship->flags & SF_FISHING)) {
|
||||
|
@ -230,7 +230,7 @@ void get_food(region * r)
|
|||
}
|
||||
|
||||
/* 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) {
|
||||
if (u_race(u) == rc_demon) {
|
||||
|
@ -293,7 +293,7 @@ void get_food(region * r)
|
|||
}
|
||||
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) {
|
||||
int need = MIN(get_money(u), lifestyle(u));
|
||||
change_money(u, -need);
|
||||
|
|
|
@ -300,6 +300,9 @@ void init_translations(const struct locale *lang, int ut, const char * (*string_
|
|||
struct critbit_tree ** cb = (struct critbit_tree **)tokens;
|
||||
add_translation(cb, key, i);
|
||||
}
|
||||
else {
|
||||
log_warning("no translation for %s in locale %s", s, lang->name);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue