From 3ea12be5642c130fd40a13c7e765e0c66927e14d Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Mon, 13 Feb 2017 18:48:38 +0100 Subject: [PATCH 01/21] BENUTZE Muschel repariert. at_keys hat jetzt auch zu jedem key ein value, und Funktionen zum Update altee Daten. --- scripts/eressea/embassy.lua | 16 +++++- src/attributes/dict.c | 98 +++++++++++-------------------------- src/attributes/dict.h | 10 ++-- src/attributes/key.c | 62 +++++++++++++---------- src/attributes/key.h | 6 +-- src/attributes/key.test.c | 47 ++++++++++++------ src/bind_faction.c | 6 +-- src/bind_region.c | 4 +- src/bind_unit.c | 2 +- src/bindings.c | 4 +- src/kernel/group.test.c | 4 +- src/kernel/item.c | 2 +- src/kernel/save.test.c | 8 +-- src/util/gamedata.h | 3 +- 14 files changed, 135 insertions(+), 137 deletions(-) diff --git a/scripts/eressea/embassy.lua b/scripts/eressea/embassy.lua index 704581c6f..93ff66d7c 100644 --- a/scripts/eressea/embassy.lua +++ b/scripts/eressea/embassy.lua @@ -5,6 +5,20 @@ if not config.embassy then return nil end local embassy = {} local home = nil +-- global exports (use item) +function use_seashell(u, amount) +-- Muschelplateau... + local visit = u.faction:get_key('mupL') + 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 + function embassy.init() home = get_region(165,30) if home==nil then @@ -20,7 +34,7 @@ function embassy.update() eressea.log.debug("updating embassies in " .. tostring(home)) local u for u in home.units do - if not u.faction:get_key('mupL') then + if u.faction:get_key('mupL')==0 then if (u.faction:add_item('seashell', 1)>0) then eressea.log.debug("new seashell for " .. tostring(u.faction)) u.faction:set_key('mupL', get_turn()) diff --git a/src/attributes/dict.c b/src/attributes/dict.c index 6d4b3ed3c..ad66e3676 100644 --- a/src/attributes/dict.c +++ b/src/attributes/dict.c @@ -42,6 +42,10 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include #include +typedef enum { + TNONE = 0, TINTEGER = 1 +} dict_type; + typedef struct dict_data { dict_type type; char *name; @@ -62,94 +66,38 @@ static int dict_read(attrib * a, void *owner, gamedata *data) storage *store = data->store; char name[NAMESIZE]; dict_data *dd = (dict_data *)a->data.v; - int result, n; - float flt; + int n; READ_STR(store, name, sizeof(name)); dd->name = strdup(name); READ_INT(store, &n); dd->type = (dict_type)n; - switch (dd->type) { - case TINTEGER: - READ_INT(store, &dd->data.i); - break; - case TREAL: - READ_FLT(store, &flt); - if ((int)flt == flt) { - dd->type = TINTEGER; - dd->data.i = (int)flt; - } - else { - dd->data.real = flt; - } - break; - case TSTRING: - READ_STR(store, name, sizeof(name)); - dd->data.str = strdup(name); - break; - case TBUILDING: - result = - read_reference(&dd->data.b, data, read_building_reference, - resolve_building); - if (result == 0 && !dd->data.b) { - return AT_READ_FAIL; - } - break; - case TUNIT: - result = - read_reference(&dd->data.u, data, read_unit_reference, resolve_unit); - if (result == 0 && !dd->data.u) { - return AT_READ_FAIL; - } - break; - case TFACTION: - result = - read_reference(&dd->data.f, data, read_faction_reference, - resolve_faction); - if (result == 0 && !dd->data.f) { - return AT_READ_FAIL; - } - break; - case TREGION: - result = - read_reference(&dd->data.r, data, read_region_reference, - RESOLVE_REGION(data->version)); - if (result == 0 && !dd->data.r) { - return AT_READ_FAIL; - } - break; - case TSHIP: - /* return read_ship_reference(&data->data.sh, store); */ - assert(!"not implemented"); - break; - case TNONE: - break; - default: + if (dd->type != TINTEGER) { + log_error("read dict, invalid type %d", n); return AT_READ_FAIL; } + READ_INT(store, &dd->data.i); return AT_READ_DEPR; } static void dict_init(attrib * a) { - dict_data *data; + dict_data *dd; a->data.v = malloc(sizeof(dict_data)); - data = (dict_data *)a->data.v; - data->type = TNONE; + dd = (dict_data *)a->data.v; + dd->type = TNONE; } static void dict_done(attrib * a) { - dict_data *data = (dict_data *)a->data.v; - if (data->type == TSTRING) - free(data->data.str); - free(data->name); + dict_data *dd = (dict_data *)a->data.v; + free(dd->name); free(a->data.v); } static void dict_upgrade(attrib **alist, attrib *abegin) { int n = 0, *keys = 0; - int i = 0, val[4]; + int i = 0, val[8]; attrib *a, *ak = a_find(*alist, &at_keys); if (ak) { keys = (int *)ak->data.v; @@ -162,7 +110,9 @@ static void dict_upgrade(attrib **alist, attrib *abegin) { } else { if (strcmp(dd->name, "embassy_muschel")==0) { - val[i++] = atoi36("mupL"); + val[i * 2] = atoi36("mupL"); + val[i * 2 + 1] = dd->data.i; + ++i; } else { log_error("dict conversion, bad entry %s", dd->name); @@ -170,14 +120,14 @@ static void dict_upgrade(attrib **alist, attrib *abegin) { } if (i == 4) { keys = realloc(keys, sizeof(int) * (n + i + 1)); - memcpy(keys + n + 1, val, sizeof(int)*i); + memcpy(keys + n + 1, val, sizeof(val)); n += i; i = 0; } } if (i > 0) { - keys = realloc(keys, sizeof(int) * (n + i + 1)); - memcpy(keys + n + 1, val, sizeof(int)*i); + keys = realloc(keys, sizeof(int) * (2 * (n + i) + 1)); + memcpy(keys + n*2 + 1, val, sizeof(int)*i*2); if (!ak) { ak = a_add(alist, a_new(&at_keys)); } @@ -190,3 +140,11 @@ attrib_type at_dict = { "object", dict_init, dict_done, NULL, NULL, dict_read, dict_upgrade }; + +void dict_set(attrib * a, const char * name, int value) +{ + dict_data *dd = (dict_data *)a->data.v; + dd->name = strdup(name); + dd->type = TINTEGER; + dd->data.i = value; +} diff --git a/src/attributes/dict.h b/src/attributes/dict.h index 7b028fa00..cc700bb9f 100644 --- a/src/attributes/dict.h +++ b/src/attributes/dict.h @@ -13,18 +13,16 @@ #ifndef H_ATTRIBUTE_OBJECT #define H_ATTRIBUTE_OBJECT -#include +struct attrib_type; +struct attrib; #ifdef __cplusplus extern "C" { #endif - typedef enum { - TNONE = 0, TINTEGER = 1, TREAL = 2, TSTRING = 3, - TUNIT = 10, TFACTION = 11, TREGION = 12, TBUILDING = 13, TSHIP = 14 - } dict_type; + extern struct attrib_type at_dict; // DEPRECATED: at_dict has been replaced with at_keys - extern struct attrib_type at_dict; + void dict_set(struct attrib * a, const char * name, int value); #ifdef __cplusplus } diff --git a/src/attributes/key.c b/src/attributes/key.c index 84bbf7c04..904df32be 100644 --- a/src/attributes/key.c +++ b/src/attributes/key.c @@ -30,8 +30,10 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. static void a_writekeys(const attrib *a, const void *o, storage *store) { int i, *keys = (int *)a->data.v; - for (i = 0; i <= keys[0]; ++i) { - WRITE_INT(store, keys[i]); + WRITE_INT(store, keys[0]); + for (i = 0; i < keys[0]; ++i) { + WRITE_INT(store, keys[i * 2 + 1]); + WRITE_INT(store, keys[i * 2 + 2]); } } @@ -42,10 +44,16 @@ static int a_readkeys(attrib * a, void *owner, gamedata *data) { if (i == 0) { return AT_READ_FAIL; } - a->data.v = p = malloc(sizeof(int)*(i + 1)); + a->data.v = p = malloc(sizeof(int)*(i*2 + 1)); *p++ = i; while (i--) { READ_INT(data->store, p++); + if (data->version >= KEYVAL_VERSION) { + READ_INT(data->store, p++); + } + else { + *p++ = 1; + } } return AT_READ_OK; } @@ -71,24 +79,25 @@ attrib_type at_keys = { static void a_upgradekeys(attrib **alist, attrib *abegin) { int n = 0, *keys = 0; - int i = 0, val[4]; + int i = 0, val[8]; 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) { - val[i++] = a->data.i; - if (i == 4) { - keys = realloc(keys, sizeof(int) * (n + i + 1)); - memcpy(keys + n + 1, val, sizeof(int)*i); + val[i * 2] = a->data.i; + val[i * 2 + 1] = 1; + if (++i == 4) { + keys = realloc(keys, sizeof(int) * (2 * (n + i) + 1)); + memcpy(keys + 2 * n + 1, val, sizeof(val)); n += i; i = 0; } } if (i > 0) { - keys = realloc(keys, sizeof(int) * (n + i + 1)); - memcpy(keys + n + 1, val, sizeof(int)*i); + keys = realloc(keys, sizeof(int) * (2 * (n + i) + 1)); + memcpy(keys + 2 * n + 1, val, sizeof(int)*i*2); if (!ak) { ak = a_add(alist, a_new(&at_keys)); } @@ -107,9 +116,9 @@ attrib_type at_key = { a_upgradekeys }; -void key_set(attrib ** alist, int key) +void key_set(attrib ** alist, int key, int val) { - int *keys, n = 1; + int *keys, n = 0; attrib *a; assert(key != 0); a = a_find(*alist, &at_keys); @@ -118,12 +127,13 @@ void key_set(attrib ** alist, int key) } keys = (int *)a->data.v; if (keys) { - n = keys[0] + 1; + n = keys[0]; } - keys = realloc(keys, sizeof(int) *(n + 1)); - // TODO: does insertion sort pay off here? - keys[0] = n; - keys[n] = key; + keys = realloc(keys, sizeof(int) *(2 * n + 3)); + // TODO: does insertion sort pay off here? prob. not. + keys[0] = n + 1; + keys[2 * n + 1] = key; + keys[2 * n + 2] = val; a->data.v = keys; } @@ -135,29 +145,31 @@ void key_unset(attrib ** alist, int key) if (a) { int i, *keys = (int *)a->data.v; if (keys) { - for (i = 1; i <= keys[0]; ++i) { - if (keys[i] == key) { - keys[i] = keys[keys[0]]; + int n = keys[0]; + for (i = 0; i != n; ++i) { + if (keys[2 * i + 1] == key) { + memmove(keys + 2 * i + 1, keys + 2 * n - 1, 2 * sizeof(int)); keys[0]--; + break; } } } } } -bool key_get(attrib *alist, int key) { +int key_get(attrib *alist, int key) { attrib *a; assert(key != 0); a = a_find(alist, &at_keys); if (a) { int i, *keys = (int *)a->data.v; if (keys) { - for (i = 1; i <= keys[0]; ++i) { - if (keys[i] == key) { - return true; + for (i = 0; i != keys[0]; ++i) { + if (keys[i*2+1] == key) { + return keys[i * 2 + 2]; } } } } - return false; + return 0; } diff --git a/src/attributes/key.h b/src/attributes/key.h index d2cea1ff0..81511d248 100644 --- a/src/attributes/key.h +++ b/src/attributes/key.h @@ -26,12 +26,12 @@ extern "C" { #endif struct attrib; struct attrib_type; - extern struct attrib_type at_key; + extern struct attrib_type at_key; // DEPRECATED: at_key has been replaced with at_keys extern struct attrib_type at_keys; - void key_set(struct attrib **alist, int key); + void key_set(struct attrib **alist, int key, int value); void key_unset(struct attrib **alist, int key); - bool key_get(struct attrib *alist, int key); + int key_get(struct attrib *alist, int key); #ifdef __cplusplus } diff --git a/src/attributes/key.test.c b/src/attributes/key.test.c index 2b7632917..b816e1d86 100644 --- a/src/attributes/key.test.c +++ b/src/attributes/key.test.c @@ -1,22 +1,24 @@ #include #include "key.h" +#include "dict.h" #include +#include #include #include static void test_get_set_keys(CuTest *tc) { attrib *a = 0; - key_set(&a, 42); - key_set(&a, 43); - key_set(&a, 44); - CuAssertTrue(tc, key_get(a, 42)); - CuAssertTrue(tc, key_get(a, 43)); - CuAssertTrue(tc, key_get(a, 44)); + key_set(&a, 42, 1); + key_set(&a, 43, 2); + key_set(&a, 44, 3); + CuAssertIntEquals(tc, 1, key_get(a, 42)); + CuAssertIntEquals(tc, 2, key_get(a, 43)); + CuAssertIntEquals(tc, 3, key_get(a, 44)); key_unset(&a, 42); - CuAssertTrue(tc, !key_get(a, 42)); - CuAssertTrue(tc, key_get(a, 43)); - CuAssertTrue(tc, key_get(a, 44)); + CuAssertIntEquals(tc, 0, key_get(a, 42)); + CuAssertIntEquals(tc, 2, key_get(a, 43)); + CuAssertIntEquals(tc, 3, key_get(a, 44)); a_removeall(&a, NULL); } @@ -26,7 +28,7 @@ static attrib *key_set_orig(attrib **alist, int key) { return a; } -static void test_upgrade(CuTest *tc) { +static void test_upgrade_key(CuTest *tc) { attrib *alist = 0; key_set_orig(&alist, 40); key_set_orig(&alist, 41); @@ -35,18 +37,31 @@ static void test_upgrade(CuTest *tc) { key_set_orig(&alist, 44); CuAssertPtrNotNull(tc, alist->type->upgrade); alist->type->upgrade(&alist, alist); - CuAssertTrue(tc, key_get(alist, 40)); - CuAssertTrue(tc, key_get(alist, 41)); - CuAssertTrue(tc, key_get(alist, 42)); - CuAssertTrue(tc, key_get(alist, 43)); - CuAssertTrue(tc, key_get(alist, 44)); + CuAssertIntEquals(tc, 1, key_get(alist, 40)); + CuAssertIntEquals(tc, 1, key_get(alist, 41)); + CuAssertIntEquals(tc, 1, key_get(alist, 42)); + CuAssertIntEquals(tc, 1, key_get(alist, 43)); + CuAssertIntEquals(tc, 1, key_get(alist, 44)); a_removeall(&alist, NULL); } +static void test_upgrade_dict(CuTest *tc) { + attrib *a; + + a = a_new(&at_dict); + + dict_set(a, "embassy_muschel", 42); + CuAssertPtrNotNull(tc, a->type->upgrade); + a->type->upgrade(&a, a); + CuAssertIntEquals(tc, 42, key_get(a, atoi36("mupL"))); + a_removeall(&a, NULL); +} + CuSuite *get_key_suite(void) { CuSuite *suite = CuSuiteNew(); SUITE_ADD_TEST(suite, test_get_set_keys); - SUITE_ADD_TEST(suite, test_upgrade); + SUITE_ADD_TEST(suite, test_upgrade_key); + SUITE_ADD_TEST(suite, test_upgrade_dict); return suite; } diff --git a/src/bind_faction.c b/src/bind_faction.c index 749bb65f6..371481fcb 100644 --- a/src/bind_faction.c +++ b/src/bind_faction.c @@ -248,7 +248,7 @@ static int tolua_faction_getkey(lua_State * L) const char *name = tolua_tostring(L, 2, 0); int flag = atoi36(name); - lua_pushboolean(L, key_get(self->attribs, flag)); + lua_pushinteger(L, key_get(self->attribs, flag)); return 1; } @@ -256,11 +256,11 @@ 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 value = (int)tolua_tonumber(L, 3, 0); int flag = atoi36(name); if (value) { - key_set(&self->attribs, flag); + key_set(&self->attribs, flag, value); } else { key_unset(&self->attribs, flag); diff --git a/src/bind_region.c b/src/bind_region.c index d9956c8b6..51a5bedd4 100644 --- a/src/bind_region.c +++ b/src/bind_region.c @@ -544,11 +544,11 @@ static int tolua_region_setkey(lua_State * L) { region *self = (region *)tolua_tousertype(L, 1, 0); const char *name = tolua_tostring(L, 2, 0); - int value = tolua_toboolean(L, 3, 0); + int value = (int)tolua_tonumber(L, 3, 0); int flag = atoi36(name); if (value) { - key_set(&self->attribs, flag); + key_set(&self->attribs, flag, value); } else { key_unset(&self->attribs, flag); diff --git a/src/bind_unit.c b/src/bind_unit.c index c0939b5cf..a9d413bf0 100755 --- a/src/bind_unit.c +++ b/src/bind_unit.c @@ -786,7 +786,7 @@ static int tolua_unit_set_flag(lua_State * L) int value = (int)tolua_tonumber(L, 3, 0); int flag = atoi36(name); if (value) { - key_set(&self->attribs, flag); + key_set(&self->attribs, flag, value); } else { key_unset(&self->attribs, flag); diff --git a/src/bindings.c b/src/bindings.c index 21f2aad58..531b68618 100755 --- a/src/bindings.c +++ b/src/bindings.c @@ -206,10 +206,10 @@ static int tolua_translate(lua_State * L) static int tolua_setkey(lua_State * L) { const char *name = tolua_tostring(L, 1, 0); - int value = tolua_toboolean(L, 2, 0); + int value = (int)tolua_tonumber(L, 3, 0); int flag = atoi36(name); if (value) { - key_set(&global.attribs, flag); + key_set(&global.attribs, flag, value); } else { key_unset(&global.attribs, flag); diff --git a/src/kernel/group.test.c b/src/kernel/group.test.c index 78ee6b24f..e95458114 100644 --- a/src/kernel/group.test.c +++ b/src/kernel/group.test.c @@ -84,7 +84,7 @@ static void test_group_readwrite(CuTest * tc) f = test_create_faction(0); new_group(f, "NW", 42); g = new_group(f, "Egoisten", 43); - key_set(&g->attribs, 44); + key_set(&g->attribs, 44, 44); al = ally_add(&g->allies, f); al->status = HELP_GIVE; write_groups(&store, f); @@ -108,7 +108,7 @@ static void test_group_readwrite(CuTest * tc) CuAssertStrEquals(tc, "Egoisten", f->groups->next->name); CuAssertPtrEquals(tc, 0, f->groups->allies); g = f->groups->next; - CuAssertTrue(tc, key_get(g->attribs, 44)); + CuAssertIntEquals(tc, 44, key_get(g->attribs, 44)); CuAssertPtrNotNull(tc, g->allies); CuAssertPtrEquals(tc, 0, g->allies->next); CuAssertPtrEquals(tc, f, g->allies->faction); diff --git a/src/kernel/item.c b/src/kernel/item.c index 34a0e1875..9327700cd 100644 --- a/src/kernel/item.c +++ b/src/kernel/item.c @@ -939,7 +939,7 @@ struct order *ord) use_pooled(user, itype->rtype, GET_SLACK | GET_RESERVE | GET_POOLED_SLACK, user->number); - key_set(&f->attribs, atoi36("mbst")); + key_set(&f->attribs, atoi36("mbst"), turn); set_level(user, SK_MAGIC, 3); ADDMSG(&user->faction->msgs, msg_message("use_item", diff --git a/src/kernel/save.test.c b/src/kernel/save.test.c index c05ce4455..70bcb2e65 100644 --- a/src/kernel/save.test.c +++ b/src/kernel/save.test.c @@ -211,8 +211,8 @@ static void test_readwrite_attrib(CuTest *tc) { attrib *a = NULL; test_setup(); - key_set(&a, 41); - key_set(&a, 42); + key_set(&a, 41, 42); + key_set(&a, 42, 43); mstream_init(&data.strm); gamedata_init(&data, &store, RELEASE_VERSION); write_attribs(data.store, a, NULL); @@ -223,8 +223,8 @@ static void test_readwrite_attrib(CuTest *tc) { read_attribs(&data, &a, NULL); mstream_done(&data.strm); gamedata_done(&data); - CuAssertTrue(tc, key_get(a, 41)); - CuAssertTrue(tc, key_get(a, 42)); + CuAssertIntEquals(tc, 42, key_get(a, 41)); + CuAssertIntEquals(tc, 43, key_get(a, 42)); a_removeall(&a, NULL); test_cleanup(); diff --git a/src/util/gamedata.h b/src/util/gamedata.h index bb1632838..75a750452 100644 --- a/src/util/gamedata.h +++ b/src/util/gamedata.h @@ -32,10 +32,11 @@ #define NOCRYPT_VERSION 352 /* passwords are plaintext again */ #define ATHASH_VERSION 353 /* attribute-type hash, not name */ #define NOWATCH_VERSION 354 /* plane->watchers is gone */ +#define KEYVAL_VERSION 355 /* at_keys has values */ /* unfinished: */ #define CRYPT_VERSION 400 /* passwords are encrypted */ -#define RELEASE_VERSION NOWATCH_VERSION /* current datafile */ +#define RELEASE_VERSION KEYVAL_VERSION /* current datafile */ #define MIN_VERSION INTPAK_VERSION /* minimal datafile we support */ #define MAX_VERSION RELEASE_VERSION /* change this if we can need to read the future datafile, and we can do so */ From aa230cc191b85dbcf40051bb0093e09046b5b6f4 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Tue, 14 Feb 2017 12:15:36 +0100 Subject: [PATCH 02/21] fix coverity warnings --- src/attributes/key.c | 8 ++++++-- src/kernel/version.c | 3 ++- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/src/attributes/key.c b/src/attributes/key.c index 904df32be..8b09fdd1c 100644 --- a/src/attributes/key.c +++ b/src/attributes/key.c @@ -102,8 +102,12 @@ static void a_upgradekeys(attrib **alist, attrib *abegin) { ak = a_add(alist, a_new(&at_keys)); } } - ak->data.v = keys; - keys[0] = n + i; + if (ak) { + ak->data.v = keys; + if (keys) { + keys[0] = n + i; + } + } } attrib_type at_key = { diff --git a/src/kernel/version.c b/src/kernel/version.c index 7e8ed01d7..8cf6a372e 100644 --- a/src/kernel/version.c +++ b/src/kernel/version.c @@ -11,8 +11,9 @@ const char *eressea_version(void) { #ifdef ERESSEA_BUILDNO return ERESSEA_VERSION "-" ERESSEA_BUILDNO; -#endif +#else return ERESSEA_VERSION; +#endif } int version_no(const char *str) { From 08e14f3095c6feb62821dd3101d4b13bf6f503c9 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Tue, 14 Feb 2017 16:23:40 +0100 Subject: [PATCH 03/21] coverity warnings --- src/attributes/dict.c | 8 ++++++-- src/economy.c | 8 ++++---- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/src/attributes/dict.c b/src/attributes/dict.c index ad66e3676..36d017b2c 100644 --- a/src/attributes/dict.c +++ b/src/attributes/dict.c @@ -132,8 +132,12 @@ static void dict_upgrade(attrib **alist, attrib *abegin) { ak = a_add(alist, a_new(&at_keys)); } } - ak->data.v = keys; - keys[0] = n + i; + if (ak) { + ak->data.v = keys; + if (keys) { + keys[0] = n + i; + } + } } attrib_type at_dict = { diff --git a/src/economy.c b/src/economy.c index dcbc7431e..dec4517a4 100644 --- a/src/economy.c +++ b/src/economy.c @@ -2707,7 +2707,7 @@ static void expandloot(region * r, request * lootorders) { unit *u; unsigned int i; - int looted = 0; + int m, looted = 0; int startmoney = rmoney(r); expandorders(r, lootorders); @@ -2724,9 +2724,9 @@ static void expandloot(region * r, request * lootorders) free(g_requests); /* Lowering morale by 1 depending on the looted money (+20%) */ - if (rng_int() % 100 < 20 + (looted * 80) / startmoney) { - int m = region_get_morale(r); - if (m) { + m = region_get_morale(r); + if (m && startmoney>0) { + if (rng_int() % 100 < 20 + (looted * 80) / startmoney) { /*Nur Moral -1, turns is not changed, so the first time nothing happens if the morale is good*/ region_set_morale(r, m - 1, -1); } From 623137e872f3bec0f824ff40cdb51914681074bd Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Tue, 14 Feb 2017 19:57:31 +0100 Subject: [PATCH 04/21] test guardhouse level limits. --- scripts/tests/e3/castles.lua | 52 +++++++++++++++++++++--------------- 1 file changed, 31 insertions(+), 21 deletions(-) diff --git a/scripts/tests/e3/castles.lua b/scripts/tests/e3/castles.lua index df395ed3d..eafc58b51 100644 --- a/scripts/tests/e3/castles.lua +++ b/scripts/tests/e3/castles.lua @@ -11,30 +11,40 @@ function teardown() eressea.settings.set("rules.food.flags", "0") end +function test_watch() + local r = region.create(0, 0, "plain") + local b = building.create(r, "watch") + + assert_equal("scaffolding", b:get_typename(1)) + assert_equal("scaffolding", b:get_typename(4)) + assert_equal("guardhouse", b:get_typename(5)) + assert_equal("guardhouse", b:get_typename(9)) + assert_equal("guardtower", b:get_typename(10)) +end + function test_small_castles() - local r = region.create(0, 0, "plain") - local f1 = faction.create("noreply@eressea.de", "human", "de") - local u1 = unit.create(f1, r, 1) - local f2 = faction.create("noreply@eressea.de", "halfling", "de") - local u2 = unit.create(f2, r, 1) - u1:add_item("money", 10000) + local r = region.create(0, 0, "plain") + local f1 = faction.create("noreply@eressea.de", "human", "de") + local u1 = unit.create(f1, r, 1) + local f2 = faction.create("noreply@eressea.de", "halfling", "de") + local u2 = unit.create(f2, r, 1) - local b = building.create(r, "castle") - u2.building = b - u1.building = b + local b = building.create(r, "castle") + u2.building = b + u1.building = b - b.owner = u2 - assert_equal("site", b:get_typename(7)) - assert_equal("fortification", b:get_typename(8)) - b.owner = u1 - assert_equal("site", b:get_typename(9)) - assert_equal("fortification", b:get_typename(10)) + b.owner = u2 + assert_equal("site", b:get_typename(7)) + assert_equal("fortification", b:get_typename(8)) + b.owner = u1 + assert_equal("site", b:get_typename(9)) + assert_equal("fortification", b:get_typename(10)) end function test_build_normal() - local r = region.create(0, 0, "plain") - local f = faction.create("noreply@eressea.de", "human", "de") - local u = unit.create(f, r, 1) + local r = region.create(0, 0, "plain") + local f = faction.create("noreply@eressea.de", "human", "de") + local u = unit.create(f, r, 1) u:clear_orders() u:add_item("stone", 10) u:set_skill("building", 10) @@ -45,9 +55,9 @@ function test_build_normal() end function test_build_packice() - local r = region.create(0, 0, "packice") - local f = faction.create("packice@eressea.de", "human", "de") - local u = unit.create(f, r, 1) + local r = region.create(0, 0, "packice") + local f = faction.create("packice@eressea.de", "human", "de") + local u = unit.create(f, r, 1) u:clear_orders() u:add_item("stone", 10) u:set_skill("building", 10) From 1dcb21b08cffe1be5170c0ac4fa77747dfaa686e Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Tue, 14 Feb 2017 20:30:24 +0100 Subject: [PATCH 05/21] bug 2281: add a failing test https://bugs.eressea.de/view.php?id=2281 --- scripts/tests/e3/castles.lua | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/scripts/tests/e3/castles.lua b/scripts/tests/e3/castles.lua index eafc58b51..b16019159 100644 --- a/scripts/tests/e3/castles.lua +++ b/scripts/tests/e3/castles.lua @@ -11,6 +11,28 @@ function teardown() eressea.settings.set("rules.food.flags", "0") end +function test_build_watch() + local r = region.create(0, 0, "plain") + local f = faction.create("e3build@eressea.de", "human", "de") + local u = unit.create(f, r, 1) + + u.number = 20 + u:add_item("log", 20) + u.id = 42 + + u:set_skill("building", 1) + u:add_order("MACHE Wache") + process_orders() + assert_not_nil(u.building) + assert_equal(5, u.building.size) + + u:set_skill("building", 2) + u:add_order("MACHE Wache " .. itoa36(u.building.id)) + process_orders() + assert_not_nil(u.building) + assert_equal(10, u.building.size) +end + function test_watch() local r = region.create(0, 0, "plain") local b = building.create(r, "watch") From 4ce415be5099ef93f20c9634d1c396a7effa8e5e Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Tue, 14 Feb 2017 20:51:03 +0100 Subject: [PATCH 06/21] BUG 2281: fix maxsize of guard towers. --- res/e3a/buildings.xml | 2 +- src/kernel/build.c | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/res/e3a/buildings.xml b/res/e3a/buildings.xml index c1edbcc0b..f65654e2f 100644 --- a/res/e3a/buildings.xml +++ b/res/e3a/buildings.xml @@ -3,7 +3,7 @@ - + diff --git a/src/kernel/build.c b/src/kernel/build.c index dff51cf6c..6b23723e8 100644 --- a/src/kernel/build.c +++ b/src/kernel/build.c @@ -595,7 +595,7 @@ int build(unit * u, const construction * ctype, int completed, int want) else break; } - if (type->materials) + if (type->materials) { for (c = 0; type->materials[c].number; c++) { const struct resource_type *rtype = type->materials[c].rtype; int prebuilt = @@ -620,6 +620,7 @@ int build(unit * u, const construction * ctype, int completed, int want) use_pooled(u, rtype, GET_DEFAULT, (need - prebuilt + multi - 1) / multi); } + } made += n; skills -= n * type->minskill; want -= n; From 794710189940fec22b1a02ccef5a36681f56cdfd Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Tue, 14 Feb 2017 21:01:22 +0100 Subject: [PATCH 07/21] factor out some function to make future debugging easier. --- src/kernel/build.c | 131 ++++++++++++++++++++++++++------------------- 1 file changed, 75 insertions(+), 56 deletions(-) diff --git a/src/kernel/build.c b/src/kernel/build.c index 6b23723e8..78bcd6b8f 100644 --- a/src/kernel/build.c +++ b/src/kernel/build.c @@ -428,6 +428,76 @@ int roqf_factor(void) return value; } +static int use_materials(unit *u, const construction *type, int n, int completed) { + if (type->materials) { + int c; + for (c = 0; type->materials[c].number; c++) { + const struct resource_type *rtype = type->materials[c].rtype; + int prebuilt = + required(completed, type->reqsize, type->materials[c].number); + int need = + required(completed + n, type->reqsize, type->materials[c].number); + int multi = 1; + int canuse = 100; /* normalization */ + if (building_is_active(u->building) && inside_building(u)) { + canuse = matmod(u->building->type->attribs, u, rtype, canuse); + } + if (canuse < 0) { + return canuse; /* pass errors to caller */ + } + canuse = matmod(type->attribs, u, rtype, canuse); + + assert(canuse % 100 == 0 + || !"only constant multipliers are implemented in build()"); + multi = canuse / 100; + if (canuse < 0) { + return canuse; /* pass errors to caller */ + } + use_pooled(u, rtype, GET_DEFAULT, + (need - prebuilt + multi - 1) / multi); + } + } + return 0; +} + +static int count_materials(unit *u, const construction *type, int n, int completed) +{ + if (type->materials) { + int c; + for (c = 0; n > 0 && type->materials[c].number; c++) { + const struct resource_type *rtype = type->materials[c].rtype; + int need, prebuilt; + int canuse = get_pooled(u, rtype, GET_DEFAULT, INT_MAX); + + if (building_is_active(u->building) && inside_building(u)) { + canuse = matmod(u->building->type->attribs, u, rtype, canuse); + } + + if (canuse < 0) + return canuse; /* pass errors to caller */ + canuse = matmod(type->attribs, u, rtype, canuse); + if (type->reqsize > 1) { + prebuilt = + required(completed, type->reqsize, type->materials[c].number); + for (; n;) { + need = + required(completed + n, type->reqsize, type->materials[c].number); + if (need - prebuilt <= canuse) + break; + --n; /* TODO: optimieren? */ + } + } + else { + int maxn = canuse / type->materials[c].number; + if (maxn < n) { + n = maxn; + } + } + } + } + return n; +} + /** Use up resources for building an object. * Build up to 'size' points of 'type', where 'completed' * of the first object have already been finished. return the @@ -492,7 +562,7 @@ int build(unit * u, const construction * ctype, int completed, int want) } } for (; want > 0 && skills > 0;) { - int c, n; + int err, n; /* skip over everything that's already been done: * type->improvement==NULL means no more improvements, but no size limits @@ -559,67 +629,16 @@ int build(unit * u, const construction * ctype, int completed, int want) } } - if (type->materials) - for (c = 0; n > 0 && type->materials[c].number; c++) { - const struct resource_type *rtype = type->materials[c].rtype; - int need, prebuilt; - int canuse = get_pooled(u, rtype, GET_DEFAULT, INT_MAX); - - if (building_is_active(u->building) && inside_building(u)) { - canuse = matmod(u->building->type->attribs, u, rtype, canuse); - } - - if (canuse < 0) - return canuse; /* pass errors to caller */ - canuse = matmod(type->attribs, u, rtype, canuse); - if (type->reqsize > 1) { - prebuilt = - required(completed, type->reqsize, type->materials[c].number); - for (; n;) { - need = - required(completed + n, type->reqsize, type->materials[c].number); - if (need - prebuilt <= canuse) - break; - --n; /* TODO: optimieren? */ - } - } - else { - int maxn = canuse / type->materials[c].number; - if (maxn < n) - n = maxn; - } - } + n = count_materials(u, type, n, completed); if (n <= 0) { if (made == 0) return ENOMATERIALS; else break; } - if (type->materials) { - for (c = 0; type->materials[c].number; c++) { - const struct resource_type *rtype = type->materials[c].rtype; - int prebuilt = - required(completed, type->reqsize, type->materials[c].number); - int need = - required(completed + n, type->reqsize, type->materials[c].number); - int multi = 1; - int canuse = 100; /* normalization */ - if (building_is_active(u->building) && inside_building(u)) { - canuse = matmod(u->building->type->attribs, u, rtype, canuse); - } - if (canuse < 0) - return canuse; /* pass errors to caller */ - canuse = matmod(type->attribs, u, rtype, canuse); - - assert(canuse % 100 == 0 - || !"only constant multipliers are implemented in build()"); - multi = canuse / 100; - if (canuse < 0) - return canuse; /* pass errors to caller */ - - use_pooled(u, rtype, GET_DEFAULT, - (need - prebuilt + multi - 1) / multi); - } + err = use_materials(u, type, n, completed); + if (err < 0) { + return err; } made += n; skills -= n * type->minskill; From 5680057e7f0c27cf90eeb81588bd5659d5be8874 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Wed, 15 Feb 2017 17:09:23 +0100 Subject: [PATCH 08/21] adding simple test for MAKE --- src/economy.c | 140 ++++++++++++++++++++++----------------------- src/economy.h | 1 + src/economy.test.c | 31 ++++++++++ src/kernel/build.c | 2 +- src/kernel/item.h | 6 +- 5 files changed, 107 insertions(+), 73 deletions(-) diff --git a/src/economy.c b/src/economy.c index dec4517a4..711a80d82 100644 --- a/src/economy.c +++ b/src/economy.c @@ -534,7 +534,7 @@ static void recruit(unit * u, struct order *ord, request ** recruitorders) } if (has_skill(u, SK_MAGIC)) { /* error158;de;{unit} in {region}: '{command}' - Magier arbeiten - * grundsätzlich nur alleine! */ + * grunds�tzlich nur alleine! */ cmistake(u, ord, 158, MSG_EVENT); return; } @@ -895,7 +895,7 @@ static void allocate_resource(unit * u, const resource_type * rtype, int want) const resource_type *rring; int amount, skill; - /* momentan kann man keine ressourcen abbauen, wenn man dafür + /* momentan kann man keine ressourcen abbauen, wenn man daf�r * Materialverbrauch hat: */ assert(itype != NULL && (itype->construction == NULL || itype->construction->materials == NULL)); @@ -928,8 +928,8 @@ static void allocate_resource(unit * u, const resource_type * rtype, int want) } } - /* Bergwächter können Abbau von Eisen/Laen durch Bewachen verhindern. - * Als magische Wesen 'sehen' Bergwächter alles und werden durch + /* Bergw�chter k�nnen Abbau von Eisen/Laen durch Bewachen verhindern. + * Als magische Wesen 'sehen' Bergw�chter alles und werden durch * Belagerung nicht aufgehalten. (Ansonsten wie oben bei Elfen anpassen). */ if (itype->rtype && (itype->rtype == get_resourcetype(R_IRON) || itype->rtype == rt_find("laen"))) { @@ -1095,7 +1095,7 @@ leveled_allocation(const resource_type * rtype, region * r, allocation * alist) if (avail > 0) { int want = required(al->want - al->get, al->save); int x = avail * want / nreq; - /* Wenn Rest, dann würfeln, ob ich was bekomme: */ + /* Wenn Rest, dann w�rfeln, ob ich was bekomme: */ if (rng_int() % nreq < (avail * want) % nreq) ++x; avail -= x; @@ -1140,7 +1140,7 @@ attrib_allocation(const resource_type * rtype, region * r, allocation * alist) if (avail > 0) { int want = required(al->want, al->save); int x = avail * want / nreq; - /* Wenn Rest, dann würfeln, ob ich was bekomme: */ + /* Wenn Rest, dann w�rfeln, ob ich was bekomme: */ if (rng_int() % nreq < (avail * want) % nreq) ++x; avail -= x; @@ -1248,7 +1248,7 @@ static void create_potion(unit * u, const potion_type * ptype, int want) } } -static void create_item(unit * u, const item_type * itype, int want) +void make_item(unit * u, const item_type * itype, int want) { if (itype->construction && fval(itype->rtype, RTF_LIMITED)) { #if GUARD_DISABLES_PRODUCTION == 1 @@ -1402,7 +1402,7 @@ int make_cmd(unit * u, struct order *ord) } } else if (itype != NULL) { - create_item(u, itype, m); + make_item(u, itype, m); } else { ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "error_cannotmake", "")); @@ -1453,15 +1453,15 @@ static void expandbuying(region * r, request * buyorders) return; /* Initialisation. multiplier ist der Multiplikator auf den - * Verkaufspreis. Für max_products Produkte kauft man das Produkt zum - * einfachen Verkaufspreis, danach erhöht sich der Multiplikator um 1. - * counter ist ein Zähler, der die gekauften Produkte zählt. money - * wird für die debug message gebraucht. */ + * Verkaufspreis. F�r max_products Produkte kauft man das Produkt zum + * einfachen Verkaufspreis, danach erh�ht sich der Multiplikator um 1. + * counter ist ein Z�hler, der die gekauften Produkte z�hlt. money + * wird f�r die debug message gebraucht. */ max_products = rpeasants(r) / TRADE_FRACTION; - /* Kauf - auch so programmiert, daß er leicht erweiterbar auf mehrere - * Güter pro Monat ist. j sind die Befehle, i der Index des + /* Kauf - auch so programmiert, da� er leicht erweiterbar auf mehrere + * G�ter pro Monat ist. j sind die Befehle, i der Index des * gehandelten Produktes. */ if (max_products > 0) { unsigned int j; @@ -1483,10 +1483,10 @@ static void expandbuying(region * r, request * buyorders) unit *u = g_requests[j].unit; item *items; - /* litems zählt die Güter, die verkauft wurden, u->n das Geld, das - * verdient wurde. Dies muß gemacht werden, weil der Preis ständig sinkt, + /* litems z�hlt die G�ter, die verkauft wurden, u->n das Geld, das + * verdient wurde. Dies mu� gemacht werden, weil der Preis st�ndig sinkt, * man sich also das verdiente Geld und die verkauften Produkte separat - * merken muß. */ + * merken mu�. */ attrib *a = a_find(u->attribs, &at_luxuries); if (a == NULL) a = a_add(&u->attribs, a_new(&at_luxuries)); @@ -1503,7 +1503,7 @@ static void expandbuying(region * r, request * buyorders) rsetmoney(r, rmoney(r) + price); /* Falls mehr als max_products Bauern ein Produkt verkauft haben, steigt - * der Preis Multiplikator für das Produkt um den Faktor 1. Der Zähler + * der Preis Multiplikator f�r das Produkt um den Faktor 1. Der Z�hler * wird wieder auf 0 gesetzt. */ if (++trade->number == max_products) { trade->number = 0; @@ -1563,7 +1563,7 @@ static void buy(unit * u, request ** buyorders, struct order *ord) return; } /* Im Augenblick kann man nur 1 Produkt kaufen. expandbuying ist aber - * schon dafür ausgerüstet, mehrere Produkte zu kaufen. */ + * schon daf�r ausger�stet, mehrere Produkte zu kaufen. */ kwd = init_order(ord); assert(kwd == K_BUY); @@ -1573,7 +1573,7 @@ static void buy(unit * u, request ** buyorders, struct order *ord) return; } if (besieged(u)) { - /* Belagerte Einheiten können nichts kaufen. */ + /* Belagerte Einheiten k�nnen nichts kaufen. */ cmistake(u, ord, 60, MSG_COMMERCE); return; } @@ -1587,7 +1587,7 @@ static void buy(unit * u, request ** buyorders, struct order *ord) } } else { - /* ...oder in der Region muß es eine Burg geben. */ + /* ...oder in der Region mu� es eine Burg geben. */ building *b = 0; if (r->buildings) { static int cache; @@ -1608,11 +1608,11 @@ static void buy(unit * u, request ** buyorders, struct order *ord) } } - /* Ein Händler kann nur 10 Güter pro Talentpunkt handeln. */ + /* Ein H�ndler kann nur 10 G�ter pro Talentpunkt handeln. */ k = u->number * 10 * effskill(u, SK_TRADE, 0); - /* hat der Händler bereits gehandelt, muss die Menge der bereits - * verkauften/gekauften Güter abgezogen werden */ + /* hat der H�ndler bereits gehandelt, muss die Menge der bereits + * verkauften/gekauften G�ter abgezogen werden */ a = a_find(u->attribs, &at_trades); if (!a) { a = a_add(&u->attribs, a_new(&at_trades)); @@ -1629,7 +1629,7 @@ static void buy(unit * u, request ** buyorders, struct order *ord) } assert(n >= 0); - /* die Menge der verkauften Güter merken */ + /* die Menge der verkauften G�ter merken */ a->data.i += n; s = gettoken(token, sizeof(token)); @@ -1662,7 +1662,7 @@ static void add_income(unit * u, int type, int want, int qty) "unit region mode wanted amount", u, u->region, type, want, qty)); } -/* Steuersätze in % bei Burggröße */ +/* Steuers�tze in % bei Burggr��e */ static int tax_per_size[7] = { 0, 6, 12, 18, 24, 30, 36 }; static void expandselling(region * r, request * sellorders, int limit) @@ -1697,11 +1697,11 @@ static void expandselling(region * r, request * sellorders, int limit) } memset(counter, 0, sizeof(int) * ncounter); - if (!sellorders) { /* NEIN, denn Insekten können in || !r->buildings) */ - return; /* Sümpfen und Wüsten auch so handeln */ + if (!sellorders) { /* NEIN, denn Insekten k�nnen in || !r->buildings) */ + return; /* S�mpfen und W�sten auch so handeln */ } - /* Stelle Eigentümer der größten Burg fest. Bekommt Steuern aus jedem - * Verkauf. Wenn zwei Burgen gleicher Größe bekommt gar keiner etwas. */ + /* Stelle Eigent�mer der gr��ten Burg fest. Bekommt Steuern aus jedem + * Verkauf. Wenn zwei Burgen gleicher Gr��e bekommt gar keiner etwas. */ for (b = rbuildings(r); b; b = b->next) { if (b->size > maxsize && building_owner(b) != NULL && b->type == castle_bt) { @@ -1724,13 +1724,13 @@ static void expandselling(region * r, request * sellorders, int limit) maxowner = (unit *)NULL; } } - /* Die Region muss genug Geld haben, um die Produkte kaufen zu können. */ + /* Die Region muss genug Geld haben, um die Produkte kaufen zu k�nnen. */ money = rmoney(r); - /* max_products sind 1/100 der Bevölkerung, falls soviele Produkte + /* max_products sind 1/100 der Bev�lkerung, falls soviele Produkte * verkauft werden - counter[] - sinkt die Nachfrage um 1 Punkt. - * multiplier speichert r->demand für die debug message ab. */ + * multiplier speichert r->demand f�r die debug message ab. */ max_products = rpeasants(r) / TRADE_FRACTION; if (max_products <= 0) @@ -1798,11 +1798,11 @@ static void expandselling(region * r, request * sellorders, int limit) change_money(u, price); fset(u, UFL_LONGACTION | UFL_NOTMOVING); - /* r->money -= price; --- dies wird eben nicht ausgeführt, denn die - * Produkte können auch als Steuern eingetrieben werden. In der Region - * wurden Silberstücke gegen Luxusgüter des selben Wertes eingetauscht! + /* r->money -= price; --- dies wird eben nicht ausgef�hrt, denn die + * Produkte k�nnen auch als Steuern eingetrieben werden. In der Region + * wurden Silberst�cke gegen Luxusg�ter des selben Wertes eingetauscht! * Falls mehr als max_products Kunden ein Produkt gekauft haben, sinkt - * die Nachfrage für das Produkt um 1. Der Zähler wird wieder auf 0 + * die Nachfrage f�r das Produkt um 1. Der Z�hler wird wieder auf 0 * gesetzt. */ if (++counter[i] > max_products) { @@ -1819,7 +1819,7 @@ static void expandselling(region * r, request * sellorders, int limit) } free(g_requests); - /* Steuern. Hier werden die Steuern dem Besitzer der größten Burg gegeben. */ + /* Steuern. Hier werden die Steuern dem Besitzer der gr��ten Burg gegeben. */ if (maxowner) { if (taxcollected > 0) { change_money(maxowner, (int)taxcollected); @@ -1876,7 +1876,7 @@ static bool sell(unit * u, request ** sellorders, struct order *ord) cmistake(u, ord, 69, MSG_INCOME); return false; } - /* sellorders sind KEIN array, weil für alle items DIE SELBE resource + /* sellorders sind KEIN array, weil f�r alle items DIE SELBE resource * (das geld der region) aufgebraucht wird. */ kwd = init_order(ord); @@ -1901,13 +1901,13 @@ static bool sell(unit * u, request ** sellorders, struct order *ord) return false; } } - /* Belagerte Einheiten können nichts verkaufen. */ + /* Belagerte Einheiten k�nnen nichts verkaufen. */ if (besieged(u)) { ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "error60", "")); return false; } - /* In der Region muß es eine Burg geben. */ + /* In der Region mu� es eine Burg geben. */ if (u_race(u) == get_race(RC_INSECT)) { if (r->terrain != newterrain(T_SWAMP) && r->terrain != newterrain(T_DESERT) @@ -1917,7 +1917,7 @@ static bool sell(unit * u, request ** sellorders, struct order *ord) } } else { - /* ...oder in der Region muß es eine Burg geben. */ + /* ...oder in der Region mu� es eine Burg geben. */ building *b = 0; if (r->buildings) { for (b = r->buildings; b; b = b->next) { @@ -1930,7 +1930,7 @@ static bool sell(unit * u, request ** sellorders, struct order *ord) } } - /* Ein Händler kann nur 10 Güter pro Talentpunkt verkaufen. */ + /* Ein H�ndler kann nur 10 G�ter pro Talentpunkt verkaufen. */ n = MIN(n, u->number * 10 * effskill(u, SK_TRADE, 0)); @@ -1956,7 +1956,7 @@ static bool sell(unit * u, request ** sellorders, struct order *ord) } available = get_pooled(u, itype->rtype, GET_DEFAULT, INT_MAX); - /* Wenn andere Einheiten das selbe verkaufen, muß ihr Zeug abgezogen + /* Wenn andere Einheiten das selbe verkaufen, mu� ihr Zeug abgezogen * werden damit es nicht zweimal verkauft wird: */ for (o = *sellorders; o; o = o->next) { if (o->type.ltype == ltype && o->unit->faction == u->faction) { @@ -1973,16 +1973,16 @@ static bool sell(unit * u, request ** sellorders, struct order *ord) return false; } /* Hier wird request->type verwendet, weil die obere limit durch - * das silber gegeben wird (region->money), welches für alle + * das silber gegeben wird (region->money), welches f�r alle * (!) produkte als summe gilt, als nicht wie bei der - * produktion, wo für jedes produkt einzeln eine obere limite + * produktion, wo f�r jedes produkt einzeln eine obere limite * existiert, so dass man arrays von orders machen kann. */ - /* Ein Händler kann nur 10 Güter pro Talentpunkt handeln. */ + /* Ein H�ndler kann nur 10 G�ter pro Talentpunkt handeln. */ k = u->number * 10 * effskill(u, SK_TRADE, 0); - /* hat der Händler bereits gehandelt, muss die Menge der bereits - * verkauften/gekauften Güter abgezogen werden */ + /* hat der H�ndler bereits gehandelt, muss die Menge der bereits + * verkauften/gekauften G�ter abgezogen werden */ a = a_find(u->attribs, &at_trades); if (!a) { a = a_add(&u->attribs, a_new(&at_trades)); @@ -1993,7 +1993,7 @@ static bool sell(unit * u, request ** sellorders, struct order *ord) n = MIN(n, k); assert(n >= 0); - /* die Menge der verkauften Güter merken */ + /* die Menge der verkauften G�ter merken */ a->data.i += n; o = (request *)calloc(1, sizeof(request)); o->unit = u; @@ -2017,8 +2017,8 @@ static void expandstealing(region * r, request * stealorders) expandorders(r, stealorders); if (!norders) return; - /* Für jede unit in der Region wird Geld geklaut, wenn sie Opfer eines - * Beklauen-Orders ist. Jedes Opfer muß einzeln behandelt werden. + /* F�r jede unit in der Region wird Geld geklaut, wenn sie Opfer eines + * Beklauen-Orders ist. Jedes Opfer mu� einzeln behandelt werden. * * u ist die beklaute unit. oa.unit ist die klauende unit. */ @@ -2079,7 +2079,7 @@ static void plant(unit * u, int raw) return; } - /* Skill prüfen */ + /* Skill pr�fen */ skill = effskill(u, SK_HERBALISM, 0); if (skill < 6) { ADDMSG(&u->faction->msgs, @@ -2087,14 +2087,14 @@ static void plant(unit * u, int raw) "skill minskill product", SK_HERBALISM, 6, itype->rtype, 1)); return; } - /* Wasser des Lebens prüfen */ + /* Wasser des Lebens pr�fen */ if (get_pooled(u, rt_water, GET_DEFAULT, 1) == 0) { ADDMSG(&u->faction->msgs, msg_feedback(u, u->thisorder, "resource_missing", "missing", rt_water)); return; } n = get_pooled(u, itype->rtype, GET_DEFAULT, skill * u->number); - /* Kräuter prüfen */ + /* Kr�uter pr�fen */ if (n == 0) { ADDMSG(&u->faction->msgs, msg_feedback(u, u->thisorder, "resource_missing", "missing", @@ -2104,7 +2104,7 @@ static void plant(unit * u, int raw) n = MIN(skill * u->number, n); n = MIN(raw, n); - /* Für jedes Kraut Talent*10% Erfolgschance. */ + /* F�r jedes Kraut Talent*10% Erfolgschance. */ for (i = n; i > 0; i--) { if (rng_int() % 10 < skill) planted++; @@ -2129,10 +2129,10 @@ static void planttrees(unit * u, int raw) return; } - /* Mallornbäume kann man nur in Mallornregionen züchten */ + /* Mallornb�ume kann man nur in Mallornregionen z�chten */ rtype = get_resourcetype(fval(r, RF_MALLORN) ? R_MALLORNSEED : R_SEED); - /* Skill prüfen */ + /* Skill pr�fen */ skill = effskill(u, SK_HERBALISM, 0); if (skill < 6) { ADDMSG(&u->faction->msgs, @@ -2157,7 +2157,7 @@ static void planttrees(unit * u, int raw) } n = MIN(raw, n); - /* Für jeden Samen Talent*10% Erfolgschance. */ + /* F�r jeden Samen Talent*10% Erfolgschance. */ for (i = n; i > 0; i--) { if (rng_int() % 10 < skill) planted++; @@ -2172,7 +2172,7 @@ static void planttrees(unit * u, int raw) "unit region amount herb", u, r, planted, rtype)); } -/* züchte bäume */ +/* z�chte b�ume */ static void breedtrees(unit * u, int raw) { int n, i, skill, planted = 0; @@ -2184,7 +2184,7 @@ static void breedtrees(unit * u, int raw) get_gamedate(turn, &date); current_season = date.season; - /* Bäume züchten geht nur im Frühling */ + /* B�ume z�chten geht nur im Fr�hling */ if (current_season != SEASON_SPRING) { planttrees(u, raw); return; @@ -2194,10 +2194,10 @@ static void breedtrees(unit * u, int raw) return; } - /* Mallornbäume kann man nur in Mallornregionen züchten */ + /* Mallornb�ume kann man nur in Mallornregionen z�chten */ rtype = get_resourcetype(fval(r, RF_MALLORN) ? R_MALLORNSEED : R_SEED); - /* Skill prüfen */ + /* Skill pr�fen */ skill = effskill(u, SK_HERBALISM, 0); if (skill < 12) { planttrees(u, raw); @@ -2207,7 +2207,7 @@ static void breedtrees(unit * u, int raw) /* wenn eine Anzahl angegeben wurde, nur soviel verbrauchen */ raw = MIN(skill * u->number, raw); n = get_pooled(u, rtype, GET_DEFAULT, raw); - /* Samen prüfen */ + /* Samen pr�fen */ if (n == 0) { ADDMSG(&u->faction->msgs, msg_feedback(u, u->thisorder, "resource_missing", "missing", rtype)); @@ -2215,7 +2215,7 @@ static void breedtrees(unit * u, int raw) } n = MIN(raw, n); - /* Für jeden Samen Talent*5% Erfolgschance. */ + /* F�r jeden Samen Talent*5% Erfolgschance. */ for (i = n; i > 0; i--) { if (rng_int() % 100 < skill * 5) planted++; @@ -2230,7 +2230,7 @@ static void breedtrees(unit * u, int raw) "unit region amount herb", u, r, planted, rtype)); } -/* züchte pferde */ +/* z�chte pferde */ static void breedhorses(unit * u) { int n, c, breed = 0; @@ -2283,7 +2283,7 @@ static void breed_cmd(unit * u, struct order *ord) return; } - /* züchte [] */ + /* z�chte [] */ (void)init_order(ord); s = gettoken(token, sizeof(token)); @@ -2549,7 +2549,7 @@ static void expandentertainment(region * r) m -= u->n; entertaining -= o->qty; - /* Nur soviel PRODUCEEXP wie auch tatsächlich gemacht wurde */ + /* Nur soviel PRODUCEEXP wie auch tats�chlich gemacht wurde */ produceexp(u, SK_ENTERTAINMENT, MIN(u->n, u->number)); add_income(u, IC_ENTERTAIN, o->qty, u->n); fset(u, UFL_LONGACTION | UFL_NOTMOVING); @@ -3121,7 +3121,7 @@ void produce(struct region *r) /* Entertainment (expandentertainment) und Besteuerung (expandtax) vor den * Befehlen, die den Bauern mehr Geld geben, damit man aus den Zahlen der - * letzten Runde berechnen kann, wieviel die Bauern für Unterhaltung + * letzten Runde berechnen kann, wieviel die Bauern f�r Unterhaltung * auszugeben bereit sind. */ if (entertaining) expandentertainment(r); @@ -3136,7 +3136,7 @@ void produce(struct region *r) /* An erster Stelle Kaufen (expandbuying), die Bauern so Geld bekommen, um * nachher zu beim Verkaufen (expandselling) den Spielern abkaufen zu - * können. */ + * k�nnen. */ if (buyorders) expandbuying(r, buyorders); diff --git a/src/economy.h b/src/economy.h index 5549e13cb..7b0eed8c9 100644 --- a/src/economy.h +++ b/src/economy.h @@ -56,6 +56,7 @@ extern "C" { enum { IC_WORK, IC_ENTERTAIN, IC_TAX, IC_TRADE, IC_TRADETAX, IC_STEAL, IC_MAGIC, IC_LOOT }; void maintain_buildings(struct region *r); + void make_item(struct unit * u, const struct item_type * itype, int want); int make_cmd(struct unit *u, struct order *ord); void split_allocations(struct region *r); int give_control_cmd(struct unit *u, struct order *ord); diff --git a/src/economy.test.c b/src/economy.test.c index 3c4a5f257..bee074714 100644 --- a/src/economy.test.c +++ b/src/economy.test.c @@ -341,12 +341,43 @@ static void test_income(CuTest *tc) test_cleanup(); } +static void test_make_item(CuTest *tc) { + unit *u; + struct item_type *itype; + const struct resource_type *rt_silver; + + test_setup(); + init_resources(); + rt_silver = get_resourcetype(R_SILVER); + itype = test_create_itemtype("log"); + u = test_create_unit(test_create_faction(0), test_create_region(0,0,0)); + make_item(u, itype, 1); + CuAssertPtrNotNull(tc, test_find_messagetype(u->faction->msgs, "error_cannotmake")); + CuAssertIntEquals(tc, 0, get_item(u, itype)); + test_clear_messages(u->faction); + itype->construction = calloc(1, sizeof(construction)); + itype->construction->skill = SK_ALCHEMY; + itype->construction->minskill = 1; + itype->construction->maxsize = 1; + itype->construction->reqsize = 1; + itype->construction->materials = calloc(2, sizeof(requirement)); + itype->construction->materials[0].rtype = rt_silver; + itype->construction->materials[0].number = 1; + set_level(u, SK_ALCHEMY, 1); + set_item(u, rt_silver->itype, 1); + make_item(u, itype, 1); + CuAssertIntEquals(tc, 1, get_item(u, itype)); + CuAssertIntEquals(tc, 0, get_item(u, rt_silver->itype)); + test_cleanup(); +} + CuSuite *get_economy_suite(void) { CuSuite *suite = CuSuiteNew(); SUITE_ADD_TEST(suite, test_give_control_building); SUITE_ADD_TEST(suite, test_give_control_ship); SUITE_ADD_TEST(suite, test_income); + SUITE_ADD_TEST(suite, test_make_item); SUITE_ADD_TEST(suite, test_steal_okay); SUITE_ADD_TEST(suite, test_steal_ocean); SUITE_ADD_TEST(suite, test_steal_nosteal); diff --git a/src/kernel/build.c b/src/kernel/build.c index 78bcd6b8f..88ab35fd2 100644 --- a/src/kernel/build.c +++ b/src/kernel/build.c @@ -397,7 +397,7 @@ static int required(int size, int msize, int maxneed) * braucht man required von maxneed resourcen */ { int used; - + assert(msize > 0); used = size * maxneed / msize; if (size * maxneed % msize) ++used; diff --git a/src/kernel/item.h b/src/kernel/item.h index c32f38057..39a2d0687 100644 --- a/src/kernel/item.h +++ b/src/kernel/item.h @@ -70,7 +70,7 @@ extern "C" { typedef char *(*rtype_name) (const struct resource_type * rtype, int flags); typedef struct resource_type { /* --- constants --- */ - char *_name; /* wie es heißt */ + char *_name; /* wie es hei�t */ unsigned int flags; /* --- functions --- */ rtype_uchange uchange; @@ -136,7 +136,7 @@ extern "C" { int weight; int capacity; struct construction *construction; - char *_appearance[2]; /* wie es für andere aussieht */ + char *_appearance[2]; /* wie es f�r andere aussieht */ /* --- functions --- */ bool(*canuse) (const struct unit * user, const struct item_type * itype); @@ -311,6 +311,8 @@ extern "C" { extern const struct potion_type *oldpotiontype[]; const struct resource_type *get_resourcetype(resource_t rt); + int get_item(const struct unit * u, const struct item_type *itype); + int set_item(struct unit * u, const struct item_type *itype, int value); int get_money(const struct unit *); int set_money(struct unit *, int); int change_money(struct unit *, int); From 5902a6922f06eae2d42591a71ff76b670cd146de Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Wed, 15 Feb 2017 20:50:45 +0100 Subject: [PATCH 09/21] BUG 2279: add a failing unit test. --- src/economy.test.c | 36 +++++++++++++++++++++++++++++++++++- src/kernel/resources.h | 16 +++++++--------- 2 files changed, 42 insertions(+), 10 deletions(-) diff --git a/src/economy.test.c b/src/economy.test.c index bee074714..ddb0cafbc 100644 --- a/src/economy.test.c +++ b/src/economy.test.c @@ -11,10 +11,12 @@ #include #include #include +#include #include #include #include +#include #include #include @@ -345,11 +347,17 @@ static void test_make_item(CuTest *tc) { unit *u; struct item_type *itype; const struct resource_type *rt_silver; + resource_type *rtype; + attrib *a; + resource_limit *rdata; test_setup(); init_resources(); + + /* make items from other items (turn silver to stone) */ rt_silver = get_resourcetype(R_SILVER); - itype = test_create_itemtype("log"); + itype = test_create_itemtype("stone"); + rtype = itype->rtype; u = test_create_unit(test_create_faction(0), test_create_region(0,0,0)); make_item(u, itype, 1); CuAssertPtrNotNull(tc, test_find_messagetype(u->faction->msgs, "error_cannotmake")); @@ -368,6 +376,32 @@ static void test_make_item(CuTest *tc) { make_item(u, itype, 1); CuAssertIntEquals(tc, 1, get_item(u, itype)); CuAssertIntEquals(tc, 0, get_item(u, rt_silver->itype)); + + /* make level-based raw materials, no materials used in construction */ + free(itype->construction->materials); + itype->construction->materials = 0; + rtype->flags |= RTF_LIMITED; + a = a_add(&rtype->attribs, a_new(&at_resourcelimit)); + rdata = (resource_limit *)a->data.v; + rdata->value = 0; + rmt_create(rtype, "stone"); + add_resource(u->region, 1, 300, 150, rtype); + u->region->resources->amount = 300; /* there are 300 stones at level 1 */ + set_level(u, SK_ALCHEMY, 10); + + make_item(u, itype, 10); + split_allocations(u->region); + CuAssertIntEquals(tc, 11, get_item(u, itype)); + CuAssertIntEquals(tc, 290, u->region->resources->amount); /* used 10 stones to make 10 stones */ + + rdata->modifiers = calloc(2, sizeof(resource_mod)); + rdata->modifiers[0].flags = RMF_SAVEMATERIAL; + rdata->modifiers[0].race = u->_race; + rdata->modifiers[0].value.f = (float)0.6; + make_item(u, itype, 10); + split_allocations(u->region); + CuAssertIntEquals(tc, 21, get_item(u, itype)); + CuAssertIntEquals(tc, 284, u->region->resources->amount); /* 60% saving = 6 stones make 10 stones */ test_cleanup(); } diff --git a/src/kernel/resources.h b/src/kernel/resources.h index 32c69036c..a1a7abd40 100644 --- a/src/kernel/resources.h +++ b/src/kernel/resources.h @@ -55,18 +55,16 @@ extern "C" { extern struct rawmaterial_type *rawmaterialtypes; - extern void update_resources(struct region *r); - extern void terraform_resources(struct region *r); - extern void read_resources(struct region *r); - extern void write_resources(struct region *r); - extern struct rawmaterial *rm_get(struct region *, + void update_resources(struct region *r); + void terraform_resources(struct region *r); + struct rawmaterial *rm_get(struct region *, const struct resource_type *); - extern struct rawmaterial_type *rmt_find(const char *str); - extern struct rawmaterial_type *rmt_get(const struct resource_type *); + struct rawmaterial_type *rmt_find(const char *str); + struct rawmaterial_type *rmt_get(const struct resource_type *); - extern void add_resource(struct region *r, int level, int base, int divisor, + void add_resource(struct region *r, int level, int base, int divisor, const struct resource_type *rtype); - extern struct rawmaterial_type *rmt_create(const struct resource_type *rtype, + struct rawmaterial_type *rmt_create(const struct resource_type *rtype, const char *name); #ifdef __cplusplus From 50083fc668641d6c232ce6b3958e16240c91a31d Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Wed, 15 Feb 2017 21:16:54 +0100 Subject: [PATCH 10/21] BUG 2279: too many resources used. diddling the resource-save formula until test passes. --- src/economy.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/economy.c b/src/economy.c index 711a80d82..b38244ca8 100644 --- a/src/economy.c +++ b/src/economy.c @@ -1038,8 +1038,6 @@ static void allocate_resource(unit * u, const resource_type * rtype, int want) static int required(int want, double save) { int req = (int)(want * save); - if (req < want * save) - ++req; return req; } @@ -1095,14 +1093,14 @@ leveled_allocation(const resource_type * rtype, region * r, allocation * alist) if (avail > 0) { int want = required(al->want - al->get, al->save); int x = avail * want / nreq; - /* Wenn Rest, dann w�rfeln, ob ich was bekomme: */ - if (rng_int() % nreq < (avail * want) % nreq) - ++x; + int r = (avail * want) % nreq; + /* Wenn Rest, dann wuerfeln, ob ich etwas bekomme: */ + if (r > 0 && rng_int() % nreq < r) ++x; avail -= x; use += x; nreq -= want; need -= x; - al->get = MIN(al->want, al->get + (int)(x / al->save)); + al->get = MIN(al->want, al->get + (int)(1 + x / al->save)); } } if (use) { From 20ff8981df584330e1cc9d3f29811903dcba961b Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Wed, 15 Feb 2017 09:30:36 +0100 Subject: [PATCH 11/21] trying to extract allocation modifiers into a separate function --- src/economy.c | 80 ++++++++++++++++++++++----------------------------- 1 file changed, 35 insertions(+), 45 deletions(-) diff --git a/src/economy.c b/src/economy.c index b38244ca8..abbf28a02 100644 --- a/src/economy.c +++ b/src/economy.c @@ -883,6 +883,32 @@ enum { AFL_LOWSKILL = 1 << 1 }; +struct message * get_modifiers(unit *u, const resource_mod *mod, double *savep, int *skillp) { + struct building *b = inside_building(u); + const struct building_type *btype = building_is_active(b) ? b->type : NULL; + double save = 1.0; + int skill = 0; + + for (; mod->flags != 0; ++mod) { + if (mod->btype == NULL || mod->btype == btype) { + if (mod->flags & RMF_REQUIREDBUILDING) { + return msg_error(u, u->thisorder, 104);; + } + if (mod->race == NULL || mod->race == u_race(u)) { + if (mod->flags & RMF_SAVEMATERIAL) { + save *= mod->value.f; + } + if (mod->flags & RMF_SKILL) { + skill += mod->value.i; + } + } + } + } + *skillp = skill; + *savep = save; + return NULL; +} + static void allocate_resource(unit * u, const resource_type * rtype, int want) { const item_type *itype = resource2item(rtype); @@ -893,7 +919,8 @@ static void allocate_resource(unit * u, const resource_type * rtype, int want) attrib *a = a_find(rtype->attribs, &at_resourcelimit); resource_limit *rdata = (resource_limit *)a->data.v; const resource_type *rring; - int amount, skill; + int amount, skill, skill_mod; + double save_mod; /* momentan kann man keine ressourcen abbauen, wenn man daf�r * Materialverbrauch hat: */ @@ -915,16 +942,11 @@ static void allocate_resource(unit * u, const resource_type * rtype, int want) } if (rdata->modifiers) { - resource_mod *mod = rdata->modifiers; - for (; mod->flags != 0; ++mod) { - if (mod->flags & RMF_REQUIREDBUILDING) { - struct building *b = inside_building(u); - const struct building_type *btype = building_is_active(b) ? b->type : NULL; - if (mod->btype && mod->btype != btype) { - cmistake(u, u->thisorder, 104, MSG_PRODUCE); - return; - } - } + message *msg = get_modifiers(u, rdata->modifiers, &save_mod, &skill_mod); + if (msg) { + ADDMSG(&u->faction->msgs, msg); + msg_release(msg); + return; } } @@ -962,23 +984,7 @@ static void allocate_resource(unit * u, const resource_type * rtype, int want) itype->rtype)); return; } - else { - struct building *b = inside_building(u); - const struct building_type *btype = building_is_active(b) ? b->type : NULL; - - if (rdata->modifiers) { - resource_mod *mod = rdata->modifiers; - for (; mod->flags != 0; ++mod) { - if (mod->flags & RMF_SKILL) { - if (mod->btype == NULL || mod->btype == btype) { - if (mod->race == NULL || mod->race == u_race(u)) { - skill += mod->value.i; - } - } - } - } - } - } + skill += skill_mod; amount = skill * u->number; /* nun ist amount die Gesamtproduktion der Einheit (in punkten) */ @@ -1013,26 +1019,10 @@ static void allocate_resource(unit * u, const resource_type * rtype, int want) } al = new_allocation(); al->want = amount; - al->save = 1.0; + al->save = save_mod; al->next = alist->data; al->unit = u; alist->data = al; - - if (rdata->modifiers) { - struct building *b = inside_building(u); - const struct building_type *btype = building_is_active(b) ? b->type : NULL; - - resource_mod *mod = rdata->modifiers; - for (; mod->flags != 0; ++mod) { - if (mod->flags & RMF_SAVEMATERIAL) { - if (mod->btype == NULL || mod->btype == btype) { - if (mod->race == NULL || mod->race == u_race(u)) { - al->save *= mod->value.f; - } - } - } - } - } } static int required(int want, double save) From a5dfe12d48cc147f8ecbbc6e7087c231581fd6dd Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Thu, 16 Feb 2017 19:38:09 +0100 Subject: [PATCH 12/21] initialize variable --- src/economy.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/economy.c b/src/economy.c index abbf28a02..df01f3b45 100644 --- a/src/economy.c +++ b/src/economy.c @@ -919,8 +919,8 @@ static void allocate_resource(unit * u, const resource_type * rtype, int want) attrib *a = a_find(rtype->attribs, &at_resourcelimit); resource_limit *rdata = (resource_limit *)a->data.v; const resource_type *rring; - int amount, skill, skill_mod; - double save_mod; + int amount, skill, skill_mod = 0; + double save_mod = 1.0; /* momentan kann man keine ressourcen abbauen, wenn man daf�r * Materialverbrauch hat: */ From a624915a0634ef1ac731c6c12e99242e25609a3d Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Thu, 16 Feb 2017 20:26:34 +0100 Subject: [PATCH 13/21] error message if building is required. was broken in recent commit. also fix reference counts. --- src/economy.c | 6 ++---- src/economy.test.c | 7 +++++++ src/kernel/messages.c | 2 -- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/src/economy.c b/src/economy.c index df01f3b45..4c54cb5da 100644 --- a/src/economy.c +++ b/src/economy.c @@ -891,9 +891,6 @@ struct message * get_modifiers(unit *u, const resource_mod *mod, double *savep, for (; mod->flags != 0; ++mod) { if (mod->btype == NULL || mod->btype == btype) { - if (mod->flags & RMF_REQUIREDBUILDING) { - return msg_error(u, u->thisorder, 104);; - } if (mod->race == NULL || mod->race == u_race(u)) { if (mod->flags & RMF_SAVEMATERIAL) { save *= mod->value.f; @@ -902,6 +899,8 @@ struct message * get_modifiers(unit *u, const resource_mod *mod, double *savep, skill += mod->value.i; } } + } else if (mod->flags & RMF_REQUIREDBUILDING) { + return msg_error(u, u->thisorder, 104); } } *skillp = skill; @@ -945,7 +944,6 @@ static void allocate_resource(unit * u, const resource_type * rtype, int want) message *msg = get_modifiers(u, rdata->modifiers, &save_mod, &skill_mod); if (msg) { ADDMSG(&u->faction->msgs, msg); - msg_release(msg); return; } } diff --git a/src/economy.test.c b/src/economy.test.c index ddb0cafbc..7101d859a 100644 --- a/src/economy.test.c +++ b/src/economy.test.c @@ -402,6 +402,13 @@ static void test_make_item(CuTest *tc) { split_allocations(u->region); CuAssertIntEquals(tc, 21, get_item(u, itype)); CuAssertIntEquals(tc, 284, u->region->resources->amount); /* 60% saving = 6 stones make 10 stones */ + + rdata->modifiers[0].flags = RMF_REQUIREDBUILDING; + rdata->modifiers[0].race = NULL; + rdata->modifiers[0].btype = bt_get_or_create("mine"); + make_item(u, itype, 10); + CuAssertPtrNotNull(tc, test_find_messagetype(u->faction->msgs, "error104")); + test_cleanup(); } diff --git a/src/kernel/messages.c b/src/kernel/messages.c index cb859df96..f74e9c0d7 100644 --- a/src/kernel/messages.c +++ b/src/kernel/messages.c @@ -270,8 +270,6 @@ void syntax_error(const struct unit *u, struct order *ord) ADDMSG(&u->faction->msgs, result); } -extern unsigned int new_hashstring(const char *s); - void free_messagelist(mlist *msgs) { struct mlist **mlistptr; From 2328975dc226c735f5652918482e8e995345c52b Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Fri, 17 Feb 2017 21:45:10 +0100 Subject: [PATCH 14/21] do not use floats for material-save. abusing variants for storing short fractions. remove unused RMF_SAVERESOURCE. --- src/economy.c | 40 ++++++++++++++++++++++++++-------------- src/economy.test.c | 4 +++- src/kernel/item.h | 3 +-- src/kernel/xmlreader.c | 7 ++----- 4 files changed, 32 insertions(+), 22 deletions(-) diff --git a/src/economy.c b/src/economy.c index 4c54cb5da..70b48e9ce 100644 --- a/src/economy.c +++ b/src/economy.c @@ -863,7 +863,7 @@ static void manufacture(unit * u, const item_type * itype, int want) typedef struct allocation { struct allocation *next; int want, get; - double save; + variant save; unsigned int flags; unit *unit; } allocation; @@ -883,17 +883,18 @@ enum { AFL_LOWSKILL = 1 << 1 }; -struct message * get_modifiers(unit *u, const resource_mod *mod, double *savep, int *skillp) { +struct message * get_modifiers(unit *u, const resource_mod *mod, variant *savep, int *skillp) { struct building *b = inside_building(u); const struct building_type *btype = building_is_active(b) ? b->type : NULL; - double save = 1.0; + int save_n = 1, save_d = 1; int skill = 0; for (; mod->flags != 0; ++mod) { if (mod->btype == NULL || mod->btype == btype) { if (mod->race == NULL || mod->race == u_race(u)) { if (mod->flags & RMF_SAVEMATERIAL) { - save *= mod->value.f; + save_n *= mod->value.sa[0]; + save_d *= mod->value.sa[1]; } if (mod->flags & RMF_SKILL) { skill += mod->value.i; @@ -904,7 +905,12 @@ struct message * get_modifiers(unit *u, const resource_mod *mod, double *savep, } } *skillp = skill; - *savep = save; + assert(save_n < SHRT_MAX); + assert(save_n > SHRT_MIN); + assert(save_d < SHRT_MAX); + assert(save_d > SHRT_MIN); + savep->sa[0] = (short)save_n; + savep->sa[1] = (short)save_d; return NULL; } @@ -919,7 +925,7 @@ static void allocate_resource(unit * u, const resource_type * rtype, int want) resource_limit *rdata = (resource_limit *)a->data.v; const resource_type *rring; int amount, skill, skill_mod = 0; - double save_mod = 1.0; + variant save_mod; /* momentan kann man keine ressourcen abbauen, wenn man daf�r * Materialverbrauch hat: */ @@ -947,6 +953,10 @@ static void allocate_resource(unit * u, const resource_type * rtype, int want) return; } } + else { + save_mod.sa[0] = 1; + save_mod.sa[1] = 1; + } /* Bergw�chter k�nnen Abbau von Eisen/Laen durch Bewachen verhindern. * Als magische Wesen 'sehen' Bergw�chter alles und werden durch @@ -1023,9 +1033,9 @@ static void allocate_resource(unit * u, const resource_type * rtype, int want) alist->data = al; } -static int required(int want, double save) +static int required(int want, variant save) { - int req = (int)(want * save); + int req = (int)(want * save.sa[0] / save.sa[1]); return req; } @@ -1088,7 +1098,7 @@ leveled_allocation(const resource_type * rtype, region * r, allocation * alist) use += x; nreq -= want; need -= x; - al->get = MIN(al->want, al->get + (int)(1 + x / al->save)); + al->get = MIN(al->want, al->get + x * al->save.sa[1] / al->save.sa[0]); } } if (use) { @@ -1126,12 +1136,13 @@ attrib_allocation(const resource_type * rtype, region * r, allocation * alist) if (avail > 0) { int want = required(al->want, al->save); int x = avail * want / nreq; - /* Wenn Rest, dann w�rfeln, ob ich was bekomme: */ - if (rng_int() % nreq < (avail * want) % nreq) - ++x; + int rx = (avail * want) % nreq; + /* Wenn Rest, dann wuerfeln, ob ich was bekomme: */ + if (rx>0 && rng_int() % nreq < rx) ++x; avail -= x; nreq -= want; - al->get = MIN(al->want, (int)(x / al->save)); + al->get = x * al->save.sa[0] / al->save.sa[1]; + al->get = MIN(al->want, al->get); if (rdata->produce) { int use = required(al->get, al->save); if (use) @@ -2619,8 +2630,9 @@ expandwork(region * r, request * work_begin, request * work_end, int maxwork) if (jobs >= working) workers = u->number; else { + int r = (u->number * jobs) % working; workers = u->number * jobs / working; - if (rng_int() % working < (u->number * jobs) % working) + if (r > 0 && rng_int() % working < r) workers++; } diff --git a/src/economy.test.c b/src/economy.test.c index 7101d859a..d9f9b82e8 100644 --- a/src/economy.test.c +++ b/src/economy.test.c @@ -350,6 +350,7 @@ static void test_make_item(CuTest *tc) { resource_type *rtype; attrib *a; resource_limit *rdata; + double d = 0.6; test_setup(); init_resources(); @@ -397,7 +398,8 @@ static void test_make_item(CuTest *tc) { rdata->modifiers = calloc(2, sizeof(resource_mod)); rdata->modifiers[0].flags = RMF_SAVEMATERIAL; rdata->modifiers[0].race = u->_race; - rdata->modifiers[0].value.f = (float)0.6; + rdata->modifiers[0].value.sa[0] = (short)(0.5+100*d); + rdata->modifiers[0].value.sa[1] = 100; make_item(u, itype, 10); split_allocations(u->region); CuAssertIntEquals(tc, 21, get_item(u, itype)); diff --git a/src/kernel/item.h b/src/kernel/item.h index 39a2d0687..e6301c314 100644 --- a/src/kernel/item.h +++ b/src/kernel/item.h @@ -91,8 +91,7 @@ extern "C" { /* resource-limits for regions */ #define RMF_SKILL 0x01 /* int, bonus on resource production skill */ -#define RMF_SAVEMATERIAL 0x02 /* float, multiplier on resource usage */ -#define RMF_SAVERESOURCE 0x03 /* int, bonus on resource production skill */ +#define RMF_SAVEMATERIAL 0x02 /* fraction (sa[0]/sa[1]), multiplier on resource usage */ #define RMF_REQUIREDBUILDING 0x04 /* building, required to build */ typedef struct resource_mod { diff --git a/src/kernel/xmlreader.c b/src/kernel/xmlreader.c index 5ce6800ef..5cecc4fdb 100644 --- a/src/kernel/xmlreader.c +++ b/src/kernel/xmlreader.c @@ -1025,13 +1025,10 @@ static int parse_resources(xmlDocPtr doc) rdata->modifiers[k].flags = RMF_SKILL; } else if (strcmp((const char *)propValue, "material") == 0) { - rdata->modifiers[k].value.f = (float)xml_fvalue(node, "value", 0); + rdata->modifiers[k].value.sa[0] = (short)(0.5+100*xml_fvalue(node, "value", 0)); + rdata->modifiers[k].value.sa[1] = 100; rdata->modifiers[k].flags = RMF_SAVEMATERIAL; } - else if (strcmp((const char *)propValue, "resource") == 0) { - rdata->modifiers[k].value.f = (float)xml_fvalue(node, "value", 0); - rdata->modifiers[k].flags = RMF_SAVERESOURCE; - } else if (strcmp((const char *)propValue, "require") == 0) { xmlChar *propBldg = xmlGetProp(node, BAD_CAST "building"); if (propBldg != NULL) { From 0a3e3de5a33405b0de1e93e5734266c48a94e126 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Fri, 17 Feb 2017 22:01:51 +0100 Subject: [PATCH 15/21] refactor fractions a little bit. --- src/kernel/xmlreader.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/kernel/xmlreader.c b/src/kernel/xmlreader.c index 5cecc4fdb..36f003e80 100644 --- a/src/kernel/xmlreader.c +++ b/src/kernel/xmlreader.c @@ -1025,8 +1025,17 @@ static int parse_resources(xmlDocPtr doc) rdata->modifiers[k].flags = RMF_SKILL; } else if (strcmp((const char *)propValue, "material") == 0) { - rdata->modifiers[k].value.sa[0] = (short)(0.5+100*xml_fvalue(node, "value", 0)); - rdata->modifiers[k].value.sa[1] = 100; + int num, den = 100; + double fval = xml_fvalue(node, "value", 0); + // TODO: extract into a function for reading fractions? + num = (int)(fval * den + 0.5); + if (num % 10 == 0) { + // TODO: calculating a GCD would be better than this + num /= 10; + den /= 10; + } + rdata->modifiers[k].value.sa[0] = (short)num; + rdata->modifiers[k].value.sa[1] = (short)den; rdata->modifiers[k].flags = RMF_SAVEMATERIAL; } else if (strcmp((const char *)propValue, "require") == 0) { From aee68fbd0fb0bc5ec2c159ce4812ef7749dd1fc2 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sat, 18 Feb 2017 11:19:42 +0100 Subject: [PATCH 16/21] github issue #658 MACHE 1 EISEN use 1 iron even with savings. --- src/economy.c | 2 ++ src/economy.test.c | 5 +++++ 2 files changed, 7 insertions(+) diff --git a/src/economy.c b/src/economy.c index 70b48e9ce..ab1875eed 100644 --- a/src/economy.c +++ b/src/economy.c @@ -1036,6 +1036,8 @@ static void allocate_resource(unit * u, const resource_type * rtype, int want) static int required(int want, variant save) { int req = (int)(want * save.sa[0] / save.sa[1]); + int r = want * save.sa[0] % save.sa[1]; + if (r>0) ++req; return req; } diff --git a/src/economy.test.c b/src/economy.test.c index d9f9b82e8..fdc218844 100644 --- a/src/economy.test.c +++ b/src/economy.test.c @@ -405,6 +405,11 @@ static void test_make_item(CuTest *tc) { CuAssertIntEquals(tc, 21, get_item(u, itype)); CuAssertIntEquals(tc, 284, u->region->resources->amount); /* 60% saving = 6 stones make 10 stones */ + make_item(u, itype, 1); + split_allocations(u->region); + CuAssertIntEquals(tc, 22, get_item(u, itype)); + CuAssertIntEquals(tc, 283, u->region->resources->amount); /* no free lunches */ + rdata->modifiers[0].flags = RMF_REQUIREDBUILDING; rdata->modifiers[0].race = NULL; rdata->modifiers[0].btype = bt_get_or_create("mine"); From 9682d6b48c751a236844d7a3c3d8dff2bf0be74e Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sat, 18 Feb 2017 15:45:57 +0100 Subject: [PATCH 17/21] implement quick-and-dirty gcd --- src/kernel/xmlreader.c | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/src/kernel/xmlreader.c b/src/kernel/xmlreader.c index 36f003e80..3a4b351dd 100644 --- a/src/kernel/xmlreader.c +++ b/src/kernel/xmlreader.c @@ -905,6 +905,22 @@ static int parse_rules(xmlDocPtr doc) return 0; } +static int gcd(int num, int den) { + const int primes[] = { 3, 5, 7, 11, 0 }; + int i=0, g = 1, p = 2; + while (p && p<=den && p<=num) { + if (num % p == 0 && den % p == 0) { + num /= p; + den /= p; + g *= p; + } + else { + p = primes[i++]; + } + } + return g; +} + static int parse_resources(xmlDocPtr doc) { xmlXPathContextPtr xpath = xmlXPathNewContext(doc); @@ -1025,15 +1041,13 @@ static int parse_resources(xmlDocPtr doc) rdata->modifiers[k].flags = RMF_SKILL; } else if (strcmp((const char *)propValue, "material") == 0) { - int num, den = 100; + int g, num, den = 100; double fval = xml_fvalue(node, "value", 0); // TODO: extract into a function for reading fractions? num = (int)(fval * den + 0.5); - if (num % 10 == 0) { - // TODO: calculating a GCD would be better than this - num /= 10; - den /= 10; - } + g = gcd(num, den); + num /= g; + den /= g; rdata->modifiers[k].value.sa[0] = (short)num; rdata->modifiers[k].value.sa[1] = (short)den; rdata->modifiers[k].flags = RMF_SAVEMATERIAL; From a754975ef9d957b79f7e142244ff27301081f7ec Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sat, 18 Feb 2017 17:52:25 +0100 Subject: [PATCH 18/21] fix loading data where embassy uses floats. --- src/attributes/dict.c | 42 +++++++++++++++++++++++++++++------------- 1 file changed, 29 insertions(+), 13 deletions(-) diff --git a/src/attributes/dict.c b/src/attributes/dict.c index 36d017b2c..f95555734 100644 --- a/src/attributes/dict.c +++ b/src/attributes/dict.c @@ -43,7 +43,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include typedef enum { - TNONE = 0, TINTEGER = 1 + TNONE = 0, TINTEGER = 1, TREAL = 2 } dict_type; typedef struct dict_data { @@ -72,11 +72,18 @@ static int dict_read(attrib * a, void *owner, gamedata *data) dd->name = strdup(name); READ_INT(store, &n); dd->type = (dict_type)n; - if (dd->type != TINTEGER) { + if (dd->type == TINTEGER) { + READ_INT(store, &dd->data.i); + } + else if (dd->type == TREAL) { + float flt; + READ_FLT(store, &flt); + dd->data.real = flt; + } + else { log_error("read dict, invalid type %d", n); return AT_READ_FAIL; } - READ_INT(store, &dd->data.i); return AT_READ_DEPR; } @@ -95,6 +102,16 @@ static void dict_done(attrib * a) free(a->data.v); } +static void upgrade_keyval(const dict_data *dd, int keyval[], int v) { + if (strcmp(dd->name, "embassy_muschel") == 0) { + keyval[0] = atoi36("mupL"); + keyval[1] = v; + } + else { + log_error("dict conversion, bad entry %s", dd->name); + } +} + static void dict_upgrade(attrib **alist, attrib *abegin) { int n = 0, *keys = 0; int i = 0, val[8]; @@ -105,18 +122,17 @@ static void dict_upgrade(attrib **alist, attrib *abegin) { } 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); + if (dd->type == TINTEGER) { + upgrade_keyval(dd, val + i * 2, dd->data.i); + ++i; + } + else if (dd->type == TREAL) { + upgrade_keyval(dd, val + i * 2, (int)dd->data.real); + ++i; } else { - if (strcmp(dd->name, "embassy_muschel")==0) { - val[i * 2] = atoi36("mupL"); - val[i * 2 + 1] = dd->data.i; - ++i; - } - else { - log_error("dict conversion, bad entry %s", dd->name); - } + log_error("dict conversion, bad type %d for %s", dd->type, dd->name); + assert(!"invalid input"); } if (i == 4) { keys = realloc(keys, sizeof(int) * (n + i + 1)); From daa75543610ea410b3ade74d670224a86001ff12 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sat, 18 Feb 2017 18:14:18 +0100 Subject: [PATCH 19/21] remove race.precombatspell --- res/eressea/races.xml | 1 - src/kernel/race.c | 2 -- src/kernel/race.h | 1 - src/kernel/xmlreader.c | 11 ----------- src/magic.c | 7 ------- 5 files changed, 22 deletions(-) diff --git a/res/eressea/races.xml b/res/eressea/races.xml index e4e22d0c3..de5a26325 100644 --- a/res/eressea/races.xml +++ b/res/eressea/races.xml @@ -1283,7 +1283,6 @@ - diff --git a/src/kernel/race.c b/src/kernel/race.c index a4a11c15d..683d37d63 100644 --- a/src/kernel/race.c +++ b/src/kernel/race.c @@ -277,7 +277,6 @@ void free_races(void) { free(at->data.dice); } } - spellref_free(races->precombatspell); free(xrefs); xrefs = 0; free(races->_name); @@ -337,7 +336,6 @@ race *rc_create(const char *zName) assert(strchr(zName, ' ') == NULL); } rc->_name = strdup(zName); - rc->precombatspell = NULL; rc->attack[0].type = AT_COMBATSPELL; for (i = 1; i < RACE_ATTACKS; ++i) diff --git a/src/kernel/race.h b/src/kernel/race.h index c58bad701..8fc6d5989 100644 --- a/src/kernel/race.h +++ b/src/kernel/race.h @@ -138,7 +138,6 @@ extern "C" { int df_default; /* Verteidigungsskill Unbewaffnet (default: -2) */ int at_bonus; /* Ver�ndert den Angriffsskill (default: 0) */ int df_bonus; /* Ver�ndert den Verteidigungskill (default: 0) */ - struct spellref *precombatspell; signed char *study_speed; /* study-speed-bonus in points/turn (0=30 Tage) */ int flags; int battle_flags; diff --git a/src/kernel/xmlreader.c b/src/kernel/xmlreader.c index 3a4b351dd..1ac5583ec 100644 --- a/src/kernel/xmlreader.c +++ b/src/kernel/xmlreader.c @@ -1849,17 +1849,6 @@ static int parse_races(xmlDocPtr doc) } xmlXPathFreeObject(result); - /* reading eressea/races/race/precombatspell */ - xpath->node = node; - result = xmlXPathEvalExpression(BAD_CAST "precombatspell", xpath); - assert(rc->precombatspell == NULL - || !"precombatspell is already initialized"); - for (k = 0; k != result->nodesetval->nodeNr; ++k) { - xmlNodePtr node = result->nodesetval->nodeTab[k]; - rc->precombatspell = xml_spellref(node, "spell"); - } - xmlXPathFreeObject(result); - /* reading eressea/races/race/attack */ xpath->node = node; result = xmlXPathEvalExpression(BAD_CAST "attack", xpath); diff --git a/src/magic.c b/src/magic.c index 89774e96a..19890ec0e 100644 --- a/src/magic.c +++ b/src/magic.c @@ -561,13 +561,6 @@ const spell *get_combatspell(const unit * u, int nr) if (m) { return m->combatspells[nr].sp; } - else { - const race * rc = u_race(u); - if (rc->precombatspell) { - return spellref_get(rc->precombatspell); - } - } - return NULL; } From 7d5586635ea4523a056def5656a81867b1660d8a Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sat, 18 Feb 2017 18:24:44 +0100 Subject: [PATCH 20/21] remove shadowcall spell --- res/core/de/strings.xml | 8 -------- res/core/messages.xml | 10 ---------- res/e3a/races.xml | 31 ------------------------------- res/e3a/spellbooks/gray.xml | 1 - res/e3a/spells.xml | 3 --- res/eressea/races.xml | 25 ------------------------- res/eressea/spellbooks/gray.xml | 1 - res/eressea/spells.xml | 3 --- 8 files changed, 82 deletions(-) diff --git a/res/core/de/strings.xml b/res/core/de/strings.xml index bccfdd165..3aa71393d 100644 --- a/res/core/de/strings.xml +++ b/res/core/de/strings.xml @@ -3819,10 +3819,6 @@ Meteorregen Meteor Shower - - Schattenruf - Shadow Call - Erschaffe einen Ring der Regeneration Create A Ring of Regeneration @@ -4503,10 +4499,6 @@ Verletzt alle Gegner. Injures all enemies. - - Ruft Schattenwesen. - Calls beings from shadow. - Panik. Panic. diff --git a/res/core/messages.xml b/res/core/messages.xml index c28670d65..3fae49eb3 100644 --- a/res/core/messages.xml +++ b/res/core/messages.xml @@ -7521,16 +7521,6 @@ "$unit($mage) casts $spell($spell). $int($amount) fighters are temporarily losing some of their memories." - - - - - - - "$unit($mage) ruft $int($amount) $race($race, 0) zu Hilfe." - "$unit($mage) calls upon the help of $int($amount) $race($race, 0)." - - diff --git a/res/e3a/races.xml b/res/e3a/races.xml index 7e75f3fd4..5060604a3 100644 --- a/res/e3a/races.xml +++ b/res/e3a/races.xml @@ -885,35 +885,4 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/res/e3a/spellbooks/gray.xml b/res/e3a/spellbooks/gray.xml index 5967d6265..9c0035e78 100644 --- a/res/e3a/spellbooks/gray.xml +++ b/res/e3a/spellbooks/gray.xml @@ -107,7 +107,6 @@ - diff --git a/res/e3a/spells.xml b/res/e3a/spells.xml index ec656c18f..74eb89146 100644 --- a/res/e3a/spells.xml +++ b/res/e3a/spells.xml @@ -665,9 +665,6 @@ - - - diff --git a/res/eressea/races.xml b/res/eressea/races.xml index de5a26325..26607a297 100644 --- a/res/eressea/races.xml +++ b/res/eressea/races.xml @@ -1284,29 +1284,4 @@ - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/res/eressea/spellbooks/gray.xml b/res/eressea/spellbooks/gray.xml index a7f718f2a..ae7a1f611 100644 --- a/res/eressea/spellbooks/gray.xml +++ b/res/eressea/spellbooks/gray.xml @@ -123,7 +123,6 @@ - diff --git a/res/eressea/spells.xml b/res/eressea/spells.xml index 5af11913e..1d762f4bd 100644 --- a/res/eressea/spells.xml +++ b/res/eressea/spells.xml @@ -471,9 +471,6 @@ - - - From a553b2258a0509bd7fa04e10262f8ef7a074246f Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sat, 18 Feb 2017 18:25:58 +0100 Subject: [PATCH 21/21] remove code for shadowcall, too --- src/spells.c | 1 - src/spells/combatspells.c | 36 ------------------------------------ src/spells/combatspells.h | 1 - 3 files changed, 38 deletions(-) diff --git a/src/spells.c b/src/spells.c index b40192016..66f5325c9 100644 --- a/src/spells.c +++ b/src/spells.c @@ -6596,7 +6596,6 @@ static spelldata spell_functions[] = { { "powerful_dragonbreath", sp_dragonodem, 0 }, { "drain_skills", sp_dragonodem, 0 }, { "aura_of_fear", sp_flee, 0 }, - { "shadowcall", sp_shadowcall, 0 }, { "immolation", sp_immolation, 0 }, { "firestorm", sp_immolation, 0 }, { "coldfront", sp_immolation, 0 }, diff --git a/src/spells/combatspells.c b/src/spells/combatspells.c index 76fd605ff..939433617 100644 --- a/src/spells/combatspells.c +++ b/src/spells/combatspells.c @@ -815,42 +815,6 @@ int sp_drainodem(fighter * fi, int level, double power, spell * sp) /* ------------------------------------------------------------- */ /* PRECOMBAT */ -int sp_shadowcall(struct castorder * co) -{ - fighter * fi = co->magician.fig; - int level = co->level; - double power = co->force; - battle *b = fi->side->battle; - region *r = b->region; - unit *mage = fi->unit; - attrib *a; - int force = (int)(get_force(power, 3) / 2); - unit *u; - const char *rcnames[3] = { "shadowbat", "nightmare", "vampunicorn" }; - const race *rc = rc_find(rcnames[rng_int() % 3]); - message *msg; - - u = create_unit(r, mage->faction, force, rc, 0, NULL, mage); - setstatus(u, ST_FIGHT); - - set_level(u, SK_WEAPONLESS, (int)(power / 2)); - set_level(u, SK_STAMINA, (int)(power / 2)); - u->hp = u->number * unit_max_hp(u); - - a = a_new(&at_unitdissolve); - a->data.ca[0] = 0; - a->data.ca[1] = 100; - a_add(&u->attribs, a); - - make_fighter(b, u, fi->side, is_attacker(fi)); - msg = - msg_message("sp_shadowcall_effect", "mage amount race", mage, u->number, - u_race(u)); - message_all(b, msg); - msg_release(msg); - return level; -} - static fighter *summon_allies(const fighter *fi, const race *rc, int number) { attrib *a; unit *mage = fi->unit; diff --git a/src/spells/combatspells.h b/src/spells/combatspells.h index 4e3173a66..cf07c2a89 100644 --- a/src/spells/combatspells.h +++ b/src/spells/combatspells.h @@ -49,7 +49,6 @@ extern "C" { int sp_armorshield(struct castorder * co); int sp_stun(struct castorder * co); int sp_undeadhero(struct castorder * co); - int sp_shadowcall(struct castorder * co); int sp_immolation(struct castorder * co); #ifdef __cplusplus