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/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/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 e4e22d0c3..26607a297 100644
--- a/res/eressea/races.xml
+++ b/res/eressea/races.xml
@@ -1283,31 +1283,5 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
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 @@
-
-
-
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/scripts/tests/e3/castles.lua b/scripts/tests/e3/castles.lua
index df395ed3d..b16019159 100644
--- a/scripts/tests/e3/castles.lua
+++ b/scripts/tests/e3/castles.lua
@@ -11,30 +11,62 @@ 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")
+
+ 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 +77,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)
diff --git a/src/attributes/dict.c b/src/attributes/dict.c
index 6d4b3ed3c..f95555734 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, TREAL = 2
+} dict_type;
+
typedef struct dict_data {
dict_type type;
char *name;
@@ -62,69 +66,22 @@ 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:
+ if (dd->type == TINTEGER) {
READ_INT(store, &dd->data.i);
- break;
- case TREAL:
+ }
+ else if (dd->type == TREAL) {
+ float flt;
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:
+ dd->data.real = flt;
+ }
+ else {
+ log_error("read dict, invalid type %d", n);
return AT_READ_FAIL;
}
return AT_READ_DEPR;
@@ -132,24 +89,32 @@ static int dict_read(attrib * a, void *owner, gamedata *data)
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 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[4];
+ int i = 0, val[8];
attrib *a, *ak = a_find(*alist, &at_keys);
if (ak) {
keys = (int *)ak->data.v;
@@ -157,36 +122,49 @@ 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++] = atoi36("mupL");
- }
- 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));
- 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));
}
}
- ak->data.v = keys;
- keys[0] = n + i;
+ if (ak) {
+ ak->data.v = keys;
+ if (keys) {
+ keys[0] = n + i;
+ }
+ }
}
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..8b09fdd1c 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,30 +79,35 @@ 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));
}
}
- ak->data.v = keys;
- keys[0] = n + i;
+ if (ak) {
+ ak->data.v = keys;
+ if (keys) {
+ keys[0] = n + i;
+ }
+ }
}
attrib_type at_key = {
@@ -107,9 +120,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 +131,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 +149,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/economy.c b/src/economy.c
index dcbc7431e..ab1875eed 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;
}
@@ -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,6 +883,37 @@ enum {
AFL_LOWSKILL = 1 << 1
};
+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;
+ 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_n *= mod->value.sa[0];
+ save_d *= mod->value.sa[1];
+ }
+ if (mod->flags & RMF_SKILL) {
+ skill += mod->value.i;
+ }
+ }
+ } else if (mod->flags & RMF_REQUIREDBUILDING) {
+ return msg_error(u, u->thisorder, 104);
+ }
+ }
+ *skillp = skill;
+ 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;
+}
+
static void allocate_resource(unit * u, const resource_type * rtype, int want)
{
const item_type *itype = resource2item(rtype);
@@ -893,9 +924,10 @@ 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 = 0;
+ variant save_mod;
- /* 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));
@@ -915,21 +947,19 @@ 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);
+ 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
+ /* 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"))) {
@@ -962,23 +992,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,33 +1027,17 @@ 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)
+static int required(int want, variant save)
{
- int req = (int)(want * save);
- if (req < want * save)
- ++req;
+ 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;
}
@@ -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 + x * al->save.sa[1] / al->save.sa[0]);
}
}
if (use) {
@@ -1140,12 +1138,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)
@@ -1248,7 +1247,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 +1401,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 +1452,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 +1482,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 +1502,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 +1562,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 +1572,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 +1586,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 +1607,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 +1628,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 +1661,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 +1696,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 +1723,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 +1797,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 +1818,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 +1875,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 +1900,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 +1916,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 +1929,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 +1955,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 +1972,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 +1992,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 +2016,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 +2078,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 +2086,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 +2103,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 +2128,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 +2156,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 +2171,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 +2183,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 +2193,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 +2206,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 +2214,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 +2229,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 +2282,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 +2548,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);
@@ -2633,8 +2632,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++;
}
@@ -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);
}
@@ -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..fdc218844 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
@@ -341,12 +343,89 @@ 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;
+ resource_type *rtype;
+ attrib *a;
+ resource_limit *rdata;
+ double d = 0.6;
+
+ test_setup();
+ init_resources();
+
+ /* make items from other items (turn silver to stone) */
+ rt_silver = get_resourcetype(R_SILVER);
+ 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"));
+ 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));
+
+ /* 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.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));
+ 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");
+ make_item(u, itype, 10);
+ CuAssertPtrNotNull(tc, test_find_messagetype(u->faction->msgs, "error104"));
+
+ 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 dff51cf6c..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;
@@ -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,17 @@ 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;
want -= n;
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/item.h b/src/kernel/item.h
index c32f38057..e6301c314 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;
@@ -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 {
@@ -136,7 +135,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 +310,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);
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;
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/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
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/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) {
diff --git a/src/kernel/xmlreader.c b/src/kernel/xmlreader.c
index 5ce6800ef..1ac5583ec 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,13 +1041,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.f = (float)xml_fvalue(node, "value", 0);
+ 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);
+ 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;
}
- 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) {
@@ -1829,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 478848488..ace6c5a8a 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;
}
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
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 */