forked from github/server
Merge branch 'develop' of github.com:eressea/server into develop
This commit is contained in:
commit
b8302b1f15
39 changed files with 549 additions and 519 deletions
|
@ -3819,10 +3819,6 @@
|
||||||
<text locale="de">Meteorregen</text>
|
<text locale="de">Meteorregen</text>
|
||||||
<text locale="en">Meteor Shower</text>
|
<text locale="en">Meteor Shower</text>
|
||||||
</string>
|
</string>
|
||||||
<string name="shadowcall">
|
|
||||||
<text locale="de">Schattenruf</text>
|
|
||||||
<text locale="en">Shadow Call</text>
|
|
||||||
</string>
|
|
||||||
<string name="create_ror">
|
<string name="create_ror">
|
||||||
<text locale="de">Erschaffe einen Ring der Regeneration</text>
|
<text locale="de">Erschaffe einen Ring der Regeneration</text>
|
||||||
<text locale="en">Create A Ring of Regeneration</text>
|
<text locale="en">Create A Ring of Regeneration</text>
|
||||||
|
@ -4503,10 +4499,6 @@
|
||||||
<text locale="de">Verletzt alle Gegner.</text>
|
<text locale="de">Verletzt alle Gegner.</text>
|
||||||
<text locale="en">Injures all enemies.</text>
|
<text locale="en">Injures all enemies.</text>
|
||||||
</string>
|
</string>
|
||||||
<string name="shadowcall">
|
|
||||||
<text locale="de">Ruft Schattenwesen.</text>
|
|
||||||
<text locale="en">Calls beings from shadow.</text>
|
|
||||||
</string>
|
|
||||||
<string name="aura_of_fear">
|
<string name="aura_of_fear">
|
||||||
<text locale="de">Panik.</text>
|
<text locale="de">Panik.</text>
|
||||||
<text locale="en">Panic.</text>
|
<text locale="en">Panic.</text>
|
||||||
|
|
|
@ -7521,16 +7521,6 @@
|
||||||
<text locale="en">"$unit($mage) casts $spell($spell). $int($amount) fighters are temporarily losing some of their memories."</text>
|
<text locale="en">"$unit($mage) casts $spell($spell). $int($amount) fighters are temporarily losing some of their memories."</text>
|
||||||
</message>
|
</message>
|
||||||
|
|
||||||
<message name="sp_shadowcall_effect" section="magic">
|
|
||||||
<type>
|
|
||||||
<arg name="mage" type="unit"/>
|
|
||||||
<arg name="amount" type="int"/>
|
|
||||||
<arg name="race" type="race"/>
|
|
||||||
</type>
|
|
||||||
<text locale="de">"$unit($mage) ruft $int($amount) $race($race, 0) zu Hilfe."</text>
|
|
||||||
<text locale="en">"$unit($mage) calls upon the help of $int($amount) $race($race, 0)."</text>
|
|
||||||
</message>
|
|
||||||
|
|
||||||
<message name="battle::killed" section="battle">
|
<message name="battle::killed" section="battle">
|
||||||
<type>
|
<type>
|
||||||
<arg name="unit" type="unit"/>
|
<arg name="unit" type="unit"/>
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
|
|
||||||
<xi:include href="config://default/buildings/castle-2.xml" />
|
<xi:include href="config://default/buildings/castle-2.xml" />
|
||||||
|
|
||||||
<building name="watch" capacity="1" fort="yes">
|
<building name="watch" maxsize="10" capacity="1" fort="yes">
|
||||||
<function name="name" value="fort_name"/>
|
<function name="name" value="fort_name"/>
|
||||||
<function name="protection" value="building_protection"/>
|
<function name="protection" value="building_protection"/>
|
||||||
<function name="taxes" value="lua_building_taxes"/>
|
<function name="taxes" value="lua_building_taxes"/>
|
||||||
|
|
|
@ -885,35 +885,4 @@
|
||||||
<attack type="8" damage="1d10"/>
|
<attack type="8" damage="1d10"/>
|
||||||
</race>
|
</race>
|
||||||
|
|
||||||
<!-- for the shadowcall spell -->
|
|
||||||
<race name="shadowbat" magres="80" maxaura="0.000000" regaura="0.000000" weight="500" capacity="540" speed="1.0" hp="1" ac="4" damage="2d4" unarmedattack="0" unarmeddefense="0" attackmodifier="3" defensemodifier="3" scarepeasants="yes" fly="yes" walk="yes" teach="no" getitem="yes">
|
|
||||||
<ai splitsize="5000" killpeasants="yes"/>
|
|
||||||
<function name="name" value="namegeneric"/>
|
|
||||||
<attack type="4" damage="1d6"/>
|
|
||||||
<attack type="3" damage="1d1"/>
|
|
||||||
</race>
|
|
||||||
|
|
||||||
<!-- for the shadowcall spell -->
|
|
||||||
<race name="nightmare" magres="50" maxaura="0.000000" regaura="0.000000" weight="100" capacity="540" speed="1.0" hp="80" ac="10" damage="2d4" unarmedattack="0" unarmeddefense="0" attackmodifier="3" defensemodifier="3" scarepeasants="yes" fly="yes" walk="yes" teach="no" getitem="yes" invinciblenonmagic="yes">
|
|
||||||
<ai splitsize="500" killpeasants="yes"/>
|
|
||||||
<function name="name" value="namegeneric"/>
|
|
||||||
<attack type="4" damage="1d4"/>
|
|
||||||
<attack type="4" damage="1d4"/>
|
|
||||||
<attack type="4" damage="1d4"/>
|
|
||||||
<attack type="3" damage="1d4"/>
|
|
||||||
<attack type="2" damage="1d10"/>
|
|
||||||
</race>
|
|
||||||
|
|
||||||
<!-- for the shadowcall spell -->
|
|
||||||
<race name="vampunicorn" magres="1.0" maxaura="0.000000" regaura="0.000000" weight="5000" capacity="2000" speed="1.0" hp="30" ac="4" damage="2d4" unarmedattack="0" unarmeddefense="0" attackmodifier="3" defensemodifier="3" scarepeasants="yes" walk="yes" teach="no" getitem="yes">
|
|
||||||
<ai splitsize="5000" killpeasants="yes"/>
|
|
||||||
<function name="name" value="namegeneric"/>
|
|
||||||
<attack type="4" damage="2d10"/>
|
|
||||||
<attack type="3" damage="1d4"/>
|
|
||||||
<attack type="3" damage="1d4"/>
|
|
||||||
<attack type="3" damage="1d4"/>
|
|
||||||
<attack type="3" damage="1d4"/>
|
|
||||||
<attack type="2" damage="2d60"/>
|
|
||||||
</race>
|
|
||||||
|
|
||||||
</races>
|
</races>
|
||||||
|
|
|
@ -107,7 +107,6 @@
|
||||||
<entry spell="rustweapon" level="3" />
|
<entry spell="rustweapon" level="3" />
|
||||||
<entry spell="sacrifice_strength" level="15" />
|
<entry spell="sacrifice_strength" level="15" />
|
||||||
<entry spell="seduction" level="6" />
|
<entry spell="seduction" level="6" />
|
||||||
<entry spell="shadowcall" level="12" />
|
|
||||||
<entry spell="shadowknights" level="1" />
|
<entry spell="shadowknights" level="1" />
|
||||||
<entry spell="shapeshift" level="3" />
|
<entry spell="shapeshift" level="3" />
|
||||||
<entry spell="shockwave" level="5" />
|
<entry spell="shockwave" level="5" />
|
||||||
|
|
|
@ -665,9 +665,6 @@
|
||||||
<spell name="aura_of_fear" rank="5" index="175" combat="2">
|
<spell name="aura_of_fear" rank="5" index="175" combat="2">
|
||||||
<resource name="aura" amount="12" cost="fixed"/>
|
<resource name="aura" amount="12" cost="fixed"/>
|
||||||
</spell>
|
</spell>
|
||||||
<spell name="shadowcall" rank="5" index="176" combat="1">
|
|
||||||
<resource name="aura" amount="24" cost="fixed"/>
|
|
||||||
</spell>
|
|
||||||
<spell name="immolation" rank="5" index="180" combat="2">
|
<spell name="immolation" rank="5" index="180" combat="2">
|
||||||
<resource name="aura" amount="24" cost="fixed"/>
|
<resource name="aura" amount="24" cost="fixed"/>
|
||||||
</spell>
|
</spell>
|
||||||
|
|
|
@ -1283,31 +1283,5 @@
|
||||||
<attack type="4" damage="5d30"/>
|
<attack type="4" damage="5d30"/>
|
||||||
<attack type="6" spell="drain_skills" level="12"/>
|
<attack type="6" spell="drain_skills" level="12"/>
|
||||||
<attack type="6" spell="aura_of_fear" level="12"/>
|
<attack type="6" spell="aura_of_fear" level="12"/>
|
||||||
<precombatspell spell="shadowcall"/>
|
|
||||||
</race>
|
|
||||||
<race name="shadowbat" magres="80" maxaura="0.000000" regaura="0.000000" weight="500" capacity="540" speed="1.000000" hp="1" ac="4" damage="2d4" unarmedattack="0" unarmeddefense="0" attackmodifier="3" defensemodifier="3" scarepeasants="yes" fly="yes" walk="yes" teach="no" getitem="yes">
|
|
||||||
<ai splitsize="5000" killpeasants="yes"/>
|
|
||||||
<function name="name" value="namegeneric"/>
|
|
||||||
<attack type="4" damage="1d6"/>
|
|
||||||
<attack type="3" damage="1d1"/>
|
|
||||||
</race>
|
|
||||||
<race name="nightmare" magres="50" maxaura="0.000000" regaura="0.000000" weight="100" capacity="540" speed="1.000000" hp="80" ac="10" damage="2d4" unarmedattack="0" unarmeddefense="0" attackmodifier="3" defensemodifier="3" scarepeasants="yes" fly="yes" walk="yes" teach="no" getitem="yes" invinciblenonmagic="yes">
|
|
||||||
<ai splitsize="500" killpeasants="yes"/>
|
|
||||||
<function name="name" value="namegeneric"/>
|
|
||||||
<attack type="4" damage="1d4"/>
|
|
||||||
<attack type="4" damage="1d4"/>
|
|
||||||
<attack type="4" damage="1d4"/>
|
|
||||||
<attack type="3" damage="1d4"/>
|
|
||||||
<attack type="2" damage="1d10"/>
|
|
||||||
</race>
|
|
||||||
<race name="vampunicorn" magres="100" maxaura="0.000000" regaura="0.000000" weight="5000" capacity="2000" speed="1.000000" hp="30" ac="4" damage="2d4" unarmedattack="0" unarmeddefense="0" attackmodifier="3" defensemodifier="3" scarepeasants="yes" walk="yes" teach="no" getitem="yes">
|
|
||||||
<ai splitsize="5000" killpeasants="yes"/>
|
|
||||||
<function name="name" value="namegeneric"/>
|
|
||||||
<attack type="4" damage="2d10"/>
|
|
||||||
<attack type="3" damage="1d4"/>
|
|
||||||
<attack type="3" damage="1d4"/>
|
|
||||||
<attack type="3" damage="1d4"/>
|
|
||||||
<attack type="3" damage="1d4"/>
|
|
||||||
<attack type="2" damage="2d60"/>
|
|
||||||
</race>
|
</race>
|
||||||
</races>
|
</races>
|
||||||
|
|
|
@ -123,7 +123,6 @@
|
||||||
<entry spell="rustweapon" level="3" />
|
<entry spell="rustweapon" level="3" />
|
||||||
<entry spell="sacrifice_strength" level="15" />
|
<entry spell="sacrifice_strength" level="15" />
|
||||||
<entry spell="seduction" level="6" />
|
<entry spell="seduction" level="6" />
|
||||||
<entry spell="shadowcall" level="12" />
|
|
||||||
<entry spell="shadowknights" level="1" />
|
<entry spell="shadowknights" level="1" />
|
||||||
<entry spell="shapeshift" level="3" />
|
<entry spell="shapeshift" level="3" />
|
||||||
<entry spell="shockwave" level="5" />
|
<entry spell="shockwave" level="5" />
|
||||||
|
|
|
@ -471,9 +471,6 @@
|
||||||
<spell name="aura_of_fear" rank="5" index="175" combat="2">
|
<spell name="aura_of_fear" rank="5" index="175" combat="2">
|
||||||
<resource name="aura" amount="12" cost="fixed"/>
|
<resource name="aura" amount="12" cost="fixed"/>
|
||||||
</spell>
|
</spell>
|
||||||
<spell name="shadowcall" rank="5" index="176" combat="1">
|
|
||||||
<resource name="aura" amount="24" cost="fixed"/>
|
|
||||||
</spell>
|
|
||||||
<spell name="mallorntreegrow" rank="5" index="177" far="true" variable="true">
|
<spell name="mallorntreegrow" rank="5" index="177" far="true" variable="true">
|
||||||
<resource name="aura" amount="6" cost="level"/>
|
<resource name="aura" amount="6" cost="level"/>
|
||||||
<resource name="mallorn" amount="1" cost="level"/>
|
<resource name="mallorn" amount="1" cost="level"/>
|
||||||
|
|
|
@ -5,6 +5,20 @@ if not config.embassy then return nil end
|
||||||
local embassy = {}
|
local embassy = {}
|
||||||
local home = nil
|
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()
|
function embassy.init()
|
||||||
home = get_region(165,30)
|
home = get_region(165,30)
|
||||||
if home==nil then
|
if home==nil then
|
||||||
|
@ -20,7 +34,7 @@ function embassy.update()
|
||||||
eressea.log.debug("updating embassies in " .. tostring(home))
|
eressea.log.debug("updating embassies in " .. tostring(home))
|
||||||
local u
|
local u
|
||||||
for u in home.units do
|
for u in home.units do
|
||||||
if not u.faction:get_key('mupL') then
|
if u.faction:get_key('mupL')==0 then
|
||||||
if (u.faction:add_item('seashell', 1)>0) then
|
if (u.faction:add_item('seashell', 1)>0) then
|
||||||
eressea.log.debug("new seashell for " .. tostring(u.faction))
|
eressea.log.debug("new seashell for " .. tostring(u.faction))
|
||||||
u.faction:set_key('mupL', get_turn())
|
u.faction:set_key('mupL', get_turn())
|
||||||
|
|
|
@ -11,13 +11,45 @@ function teardown()
|
||||||
eressea.settings.set("rules.food.flags", "0")
|
eressea.settings.set("rules.food.flags", "0")
|
||||||
end
|
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()
|
function test_small_castles()
|
||||||
local r = region.create(0, 0, "plain")
|
local r = region.create(0, 0, "plain")
|
||||||
local f1 = faction.create("noreply@eressea.de", "human", "de")
|
local f1 = faction.create("noreply@eressea.de", "human", "de")
|
||||||
local u1 = unit.create(f1, r, 1)
|
local u1 = unit.create(f1, r, 1)
|
||||||
local f2 = faction.create("noreply@eressea.de", "halfling", "de")
|
local f2 = faction.create("noreply@eressea.de", "halfling", "de")
|
||||||
local u2 = unit.create(f2, r, 1)
|
local u2 = unit.create(f2, r, 1)
|
||||||
u1:add_item("money", 10000)
|
|
||||||
|
|
||||||
local b = building.create(r, "castle")
|
local b = building.create(r, "castle")
|
||||||
u2.building = b
|
u2.building = b
|
||||||
|
|
|
@ -42,6 +42,10 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
TNONE = 0, TINTEGER = 1, TREAL = 2
|
||||||
|
} dict_type;
|
||||||
|
|
||||||
typedef struct dict_data {
|
typedef struct dict_data {
|
||||||
dict_type type;
|
dict_type type;
|
||||||
char *name;
|
char *name;
|
||||||
|
@ -62,69 +66,22 @@ static int dict_read(attrib * a, void *owner, gamedata *data)
|
||||||
storage *store = data->store;
|
storage *store = data->store;
|
||||||
char name[NAMESIZE];
|
char name[NAMESIZE];
|
||||||
dict_data *dd = (dict_data *)a->data.v;
|
dict_data *dd = (dict_data *)a->data.v;
|
||||||
int result, n;
|
int n;
|
||||||
float flt;
|
|
||||||
|
|
||||||
READ_STR(store, name, sizeof(name));
|
READ_STR(store, name, sizeof(name));
|
||||||
dd->name = strdup(name);
|
dd->name = strdup(name);
|
||||||
READ_INT(store, &n);
|
READ_INT(store, &n);
|
||||||
dd->type = (dict_type)n;
|
dd->type = (dict_type)n;
|
||||||
switch (dd->type) {
|
if (dd->type == TINTEGER) {
|
||||||
case TINTEGER:
|
|
||||||
READ_INT(store, &dd->data.i);
|
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 {
|
else if (dd->type == TREAL) {
|
||||||
|
float flt;
|
||||||
|
READ_FLT(store, &flt);
|
||||||
dd->data.real = flt;
|
dd->data.real = flt;
|
||||||
}
|
}
|
||||||
break;
|
else {
|
||||||
case TSTRING:
|
log_error("read dict, invalid type %d", n);
|
||||||
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:
|
|
||||||
return AT_READ_FAIL;
|
return AT_READ_FAIL;
|
||||||
}
|
}
|
||||||
return AT_READ_DEPR;
|
return AT_READ_DEPR;
|
||||||
|
@ -132,24 +89,32 @@ static int dict_read(attrib * a, void *owner, gamedata *data)
|
||||||
|
|
||||||
static void dict_init(attrib * a)
|
static void dict_init(attrib * a)
|
||||||
{
|
{
|
||||||
dict_data *data;
|
dict_data *dd;
|
||||||
a->data.v = malloc(sizeof(dict_data));
|
a->data.v = malloc(sizeof(dict_data));
|
||||||
data = (dict_data *)a->data.v;
|
dd = (dict_data *)a->data.v;
|
||||||
data->type = TNONE;
|
dd->type = TNONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void dict_done(attrib * a)
|
static void dict_done(attrib * a)
|
||||||
{
|
{
|
||||||
dict_data *data = (dict_data *)a->data.v;
|
dict_data *dd = (dict_data *)a->data.v;
|
||||||
if (data->type == TSTRING)
|
free(dd->name);
|
||||||
free(data->data.str);
|
|
||||||
free(data->name);
|
|
||||||
free(a->data.v);
|
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) {
|
static void dict_upgrade(attrib **alist, attrib *abegin) {
|
||||||
int n = 0, *keys = 0;
|
int n = 0, *keys = 0;
|
||||||
int i = 0, val[4];
|
int i = 0, val[8];
|
||||||
attrib *a, *ak = a_find(*alist, &at_keys);
|
attrib *a, *ak = a_find(*alist, &at_keys);
|
||||||
if (ak) {
|
if (ak) {
|
||||||
keys = (int *)ak->data.v;
|
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) {
|
for (a = abegin; a && a->type == abegin->type; a = a->next) {
|
||||||
dict_data *dd = (dict_data *)a->data.v;
|
dict_data *dd = (dict_data *)a->data.v;
|
||||||
if (dd->type != TINTEGER) {
|
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 {
|
||||||
log_error("dict conversion, bad type %d for %s", dd->type, dd->name);
|
log_error("dict conversion, bad type %d for %s", dd->type, dd->name);
|
||||||
}
|
assert(!"invalid input");
|
||||||
else {
|
|
||||||
if (strcmp(dd->name, "embassy_muschel")==0) {
|
|
||||||
val[i++] = atoi36("mupL");
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
log_error("dict conversion, bad entry %s", dd->name);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (i == 4) {
|
if (i == 4) {
|
||||||
keys = realloc(keys, sizeof(int) * (n + i + 1));
|
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;
|
n += i;
|
||||||
i = 0;
|
i = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (i > 0) {
|
if (i > 0) {
|
||||||
keys = realloc(keys, sizeof(int) * (n + i + 1));
|
keys = realloc(keys, sizeof(int) * (2 * (n + i) + 1));
|
||||||
memcpy(keys + n + 1, val, sizeof(int)*i);
|
memcpy(keys + n*2 + 1, val, sizeof(int)*i*2);
|
||||||
if (!ak) {
|
if (!ak) {
|
||||||
ak = a_add(alist, a_new(&at_keys));
|
ak = a_add(alist, a_new(&at_keys));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (ak) {
|
||||||
ak->data.v = keys;
|
ak->data.v = keys;
|
||||||
|
if (keys) {
|
||||||
keys[0] = n + i;
|
keys[0] = n + i;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
attrib_type at_dict = {
|
attrib_type at_dict = {
|
||||||
"object", dict_init, dict_done, NULL,
|
"object", dict_init, dict_done, NULL,
|
||||||
NULL, dict_read, dict_upgrade
|
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;
|
||||||
|
}
|
||||||
|
|
|
@ -13,18 +13,16 @@
|
||||||
#ifndef H_ATTRIBUTE_OBJECT
|
#ifndef H_ATTRIBUTE_OBJECT
|
||||||
#define H_ATTRIBUTE_OBJECT
|
#define H_ATTRIBUTE_OBJECT
|
||||||
|
|
||||||
#include <util/variant.h>
|
struct attrib_type;
|
||||||
|
struct attrib;
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
typedef enum {
|
extern struct attrib_type at_dict; // DEPRECATED: at_dict has been replaced with at_keys
|
||||||
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;
|
void dict_set(struct attrib * a, const char * name, int value);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|
|
@ -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) {
|
static void a_writekeys(const attrib *a, const void *o, storage *store) {
|
||||||
int i, *keys = (int *)a->data.v;
|
int i, *keys = (int *)a->data.v;
|
||||||
for (i = 0; i <= keys[0]; ++i) {
|
WRITE_INT(store, keys[0]);
|
||||||
WRITE_INT(store, keys[i]);
|
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) {
|
if (i == 0) {
|
||||||
return AT_READ_FAIL;
|
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;
|
*p++ = i;
|
||||||
while (i--) {
|
while (i--) {
|
||||||
READ_INT(data->store, p++);
|
READ_INT(data->store, p++);
|
||||||
|
if (data->version >= KEYVAL_VERSION) {
|
||||||
|
READ_INT(data->store, p++);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
*p++ = 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return AT_READ_OK;
|
return AT_READ_OK;
|
||||||
}
|
}
|
||||||
|
@ -71,31 +79,36 @@ attrib_type at_keys = {
|
||||||
|
|
||||||
static void a_upgradekeys(attrib **alist, attrib *abegin) {
|
static void a_upgradekeys(attrib **alist, attrib *abegin) {
|
||||||
int n = 0, *keys = 0;
|
int n = 0, *keys = 0;
|
||||||
int i = 0, val[4];
|
int i = 0, val[8];
|
||||||
attrib *a, *ak = a_find(*alist, &at_keys);
|
attrib *a, *ak = a_find(*alist, &at_keys);
|
||||||
if (ak) {
|
if (ak) {
|
||||||
keys = (int *)ak->data.v;
|
keys = (int *)ak->data.v;
|
||||||
if (keys) n = keys[0];
|
if (keys) n = keys[0];
|
||||||
}
|
}
|
||||||
for (a = abegin; a && a->type == abegin->type; a = a->next) {
|
for (a = abegin; a && a->type == abegin->type; a = a->next) {
|
||||||
val[i++] = a->data.i;
|
val[i * 2] = a->data.i;
|
||||||
if (i == 4) {
|
val[i * 2 + 1] = 1;
|
||||||
keys = realloc(keys, sizeof(int) * (n + i + 1));
|
if (++i == 4) {
|
||||||
memcpy(keys + n + 1, val, sizeof(int)*i);
|
keys = realloc(keys, sizeof(int) * (2 * (n + i) + 1));
|
||||||
|
memcpy(keys + 2 * n + 1, val, sizeof(val));
|
||||||
n += i;
|
n += i;
|
||||||
i = 0;
|
i = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (i > 0) {
|
if (i > 0) {
|
||||||
keys = realloc(keys, sizeof(int) * (n + i + 1));
|
keys = realloc(keys, sizeof(int) * (2 * (n + i) + 1));
|
||||||
memcpy(keys + n + 1, val, sizeof(int)*i);
|
memcpy(keys + 2 * n + 1, val, sizeof(int)*i*2);
|
||||||
if (!ak) {
|
if (!ak) {
|
||||||
ak = a_add(alist, a_new(&at_keys));
|
ak = a_add(alist, a_new(&at_keys));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (ak) {
|
||||||
ak->data.v = keys;
|
ak->data.v = keys;
|
||||||
|
if (keys) {
|
||||||
keys[0] = n + i;
|
keys[0] = n + i;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
attrib_type at_key = {
|
attrib_type at_key = {
|
||||||
"key",
|
"key",
|
||||||
|
@ -107,9 +120,9 @@ attrib_type at_key = {
|
||||||
a_upgradekeys
|
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;
|
attrib *a;
|
||||||
assert(key != 0);
|
assert(key != 0);
|
||||||
a = a_find(*alist, &at_keys);
|
a = a_find(*alist, &at_keys);
|
||||||
|
@ -118,12 +131,13 @@ void key_set(attrib ** alist, int key)
|
||||||
}
|
}
|
||||||
keys = (int *)a->data.v;
|
keys = (int *)a->data.v;
|
||||||
if (keys) {
|
if (keys) {
|
||||||
n = keys[0] + 1;
|
n = keys[0];
|
||||||
}
|
}
|
||||||
keys = realloc(keys, sizeof(int) *(n + 1));
|
keys = realloc(keys, sizeof(int) *(2 * n + 3));
|
||||||
// TODO: does insertion sort pay off here?
|
// TODO: does insertion sort pay off here? prob. not.
|
||||||
keys[0] = n;
|
keys[0] = n + 1;
|
||||||
keys[n] = key;
|
keys[2 * n + 1] = key;
|
||||||
|
keys[2 * n + 2] = val;
|
||||||
a->data.v = keys;
|
a->data.v = keys;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -135,29 +149,31 @@ void key_unset(attrib ** alist, int key)
|
||||||
if (a) {
|
if (a) {
|
||||||
int i, *keys = (int *)a->data.v;
|
int i, *keys = (int *)a->data.v;
|
||||||
if (keys) {
|
if (keys) {
|
||||||
for (i = 1; i <= keys[0]; ++i) {
|
int n = keys[0];
|
||||||
if (keys[i] == key) {
|
for (i = 0; i != n; ++i) {
|
||||||
keys[i] = keys[keys[0]];
|
if (keys[2 * i + 1] == key) {
|
||||||
|
memmove(keys + 2 * i + 1, keys + 2 * n - 1, 2 * sizeof(int));
|
||||||
keys[0]--;
|
keys[0]--;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool key_get(attrib *alist, int key) {
|
int key_get(attrib *alist, int key) {
|
||||||
attrib *a;
|
attrib *a;
|
||||||
assert(key != 0);
|
assert(key != 0);
|
||||||
a = a_find(alist, &at_keys);
|
a = a_find(alist, &at_keys);
|
||||||
if (a) {
|
if (a) {
|
||||||
int i, *keys = (int *)a->data.v;
|
int i, *keys = (int *)a->data.v;
|
||||||
if (keys) {
|
if (keys) {
|
||||||
for (i = 1; i <= keys[0]; ++i) {
|
for (i = 0; i != keys[0]; ++i) {
|
||||||
if (keys[i] == key) {
|
if (keys[i*2+1] == key) {
|
||||||
return true;
|
return keys[i * 2 + 2];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,12 +26,12 @@ extern "C" {
|
||||||
#endif
|
#endif
|
||||||
struct attrib;
|
struct attrib;
|
||||||
struct attrib_type;
|
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;
|
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);
|
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
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,22 +1,24 @@
|
||||||
#include <platform.h>
|
#include <platform.h>
|
||||||
#include "key.h"
|
#include "key.h"
|
||||||
|
#include "dict.h"
|
||||||
|
|
||||||
#include <util/attrib.h>
|
#include <util/attrib.h>
|
||||||
|
#include <util/base36.h>
|
||||||
#include <CuTest.h>
|
#include <CuTest.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
static void test_get_set_keys(CuTest *tc) {
|
static void test_get_set_keys(CuTest *tc) {
|
||||||
attrib *a = 0;
|
attrib *a = 0;
|
||||||
key_set(&a, 42);
|
key_set(&a, 42, 1);
|
||||||
key_set(&a, 43);
|
key_set(&a, 43, 2);
|
||||||
key_set(&a, 44);
|
key_set(&a, 44, 3);
|
||||||
CuAssertTrue(tc, key_get(a, 42));
|
CuAssertIntEquals(tc, 1, key_get(a, 42));
|
||||||
CuAssertTrue(tc, key_get(a, 43));
|
CuAssertIntEquals(tc, 2, key_get(a, 43));
|
||||||
CuAssertTrue(tc, key_get(a, 44));
|
CuAssertIntEquals(tc, 3, key_get(a, 44));
|
||||||
key_unset(&a, 42);
|
key_unset(&a, 42);
|
||||||
CuAssertTrue(tc, !key_get(a, 42));
|
CuAssertIntEquals(tc, 0, key_get(a, 42));
|
||||||
CuAssertTrue(tc, key_get(a, 43));
|
CuAssertIntEquals(tc, 2, key_get(a, 43));
|
||||||
CuAssertTrue(tc, key_get(a, 44));
|
CuAssertIntEquals(tc, 3, key_get(a, 44));
|
||||||
a_removeall(&a, NULL);
|
a_removeall(&a, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -26,7 +28,7 @@ static attrib *key_set_orig(attrib **alist, int key) {
|
||||||
return a;
|
return a;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void test_upgrade(CuTest *tc) {
|
static void test_upgrade_key(CuTest *tc) {
|
||||||
attrib *alist = 0;
|
attrib *alist = 0;
|
||||||
key_set_orig(&alist, 40);
|
key_set_orig(&alist, 40);
|
||||||
key_set_orig(&alist, 41);
|
key_set_orig(&alist, 41);
|
||||||
|
@ -35,18 +37,31 @@ static void test_upgrade(CuTest *tc) {
|
||||||
key_set_orig(&alist, 44);
|
key_set_orig(&alist, 44);
|
||||||
CuAssertPtrNotNull(tc, alist->type->upgrade);
|
CuAssertPtrNotNull(tc, alist->type->upgrade);
|
||||||
alist->type->upgrade(&alist, alist);
|
alist->type->upgrade(&alist, alist);
|
||||||
CuAssertTrue(tc, key_get(alist, 40));
|
CuAssertIntEquals(tc, 1, key_get(alist, 40));
|
||||||
CuAssertTrue(tc, key_get(alist, 41));
|
CuAssertIntEquals(tc, 1, key_get(alist, 41));
|
||||||
CuAssertTrue(tc, key_get(alist, 42));
|
CuAssertIntEquals(tc, 1, key_get(alist, 42));
|
||||||
CuAssertTrue(tc, key_get(alist, 43));
|
CuAssertIntEquals(tc, 1, key_get(alist, 43));
|
||||||
CuAssertTrue(tc, key_get(alist, 44));
|
CuAssertIntEquals(tc, 1, key_get(alist, 44));
|
||||||
a_removeall(&alist, NULL);
|
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 *get_key_suite(void)
|
||||||
{
|
{
|
||||||
CuSuite *suite = CuSuiteNew();
|
CuSuite *suite = CuSuiteNew();
|
||||||
SUITE_ADD_TEST(suite, test_get_set_keys);
|
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;
|
return suite;
|
||||||
}
|
}
|
||||||
|
|
|
@ -248,7 +248,7 @@ static int tolua_faction_getkey(lua_State * L)
|
||||||
const char *name = tolua_tostring(L, 2, 0);
|
const char *name = tolua_tostring(L, 2, 0);
|
||||||
int flag = atoi36(name);
|
int flag = atoi36(name);
|
||||||
|
|
||||||
lua_pushboolean(L, key_get(self->attribs, flag));
|
lua_pushinteger(L, key_get(self->attribs, flag));
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -256,11 +256,11 @@ static int tolua_faction_setkey(lua_State * L)
|
||||||
{
|
{
|
||||||
faction *self = (faction *)tolua_tousertype(L, 1, 0);
|
faction *self = (faction *)tolua_tousertype(L, 1, 0);
|
||||||
const char *name = tolua_tostring(L, 2, 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);
|
int flag = atoi36(name);
|
||||||
|
|
||||||
if (value) {
|
if (value) {
|
||||||
key_set(&self->attribs, flag);
|
key_set(&self->attribs, flag, value);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
key_unset(&self->attribs, flag);
|
key_unset(&self->attribs, flag);
|
||||||
|
|
|
@ -544,11 +544,11 @@ static int tolua_region_setkey(lua_State * L)
|
||||||
{
|
{
|
||||||
region *self = (region *)tolua_tousertype(L, 1, 0);
|
region *self = (region *)tolua_tousertype(L, 1, 0);
|
||||||
const char *name = tolua_tostring(L, 2, 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);
|
int flag = atoi36(name);
|
||||||
|
|
||||||
if (value) {
|
if (value) {
|
||||||
key_set(&self->attribs, flag);
|
key_set(&self->attribs, flag, value);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
key_unset(&self->attribs, flag);
|
key_unset(&self->attribs, flag);
|
||||||
|
|
|
@ -786,7 +786,7 @@ static int tolua_unit_set_flag(lua_State * L)
|
||||||
int value = (int)tolua_tonumber(L, 3, 0);
|
int value = (int)tolua_tonumber(L, 3, 0);
|
||||||
int flag = atoi36(name);
|
int flag = atoi36(name);
|
||||||
if (value) {
|
if (value) {
|
||||||
key_set(&self->attribs, flag);
|
key_set(&self->attribs, flag, value);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
key_unset(&self->attribs, flag);
|
key_unset(&self->attribs, flag);
|
||||||
|
|
|
@ -206,10 +206,10 @@ static int tolua_translate(lua_State * L)
|
||||||
static int tolua_setkey(lua_State * L)
|
static int tolua_setkey(lua_State * L)
|
||||||
{
|
{
|
||||||
const char *name = tolua_tostring(L, 1, 0);
|
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);
|
int flag = atoi36(name);
|
||||||
if (value) {
|
if (value) {
|
||||||
key_set(&global.attribs, flag);
|
key_set(&global.attribs, flag, value);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
key_unset(&global.attribs, flag);
|
key_unset(&global.attribs, flag);
|
||||||
|
|
256
src/economy.c
256
src/economy.c
|
@ -534,7 +534,7 @@ static void recruit(unit * u, struct order *ord, request ** recruitorders)
|
||||||
}
|
}
|
||||||
if (has_skill(u, SK_MAGIC)) {
|
if (has_skill(u, SK_MAGIC)) {
|
||||||
/* error158;de;{unit} in {region}: '{command}' - Magier arbeiten
|
/* error158;de;{unit} in {region}: '{command}' - Magier arbeiten
|
||||||
* grundsätzlich nur alleine! */
|
* grunds<EFBFBD>tzlich nur alleine! */
|
||||||
cmistake(u, ord, 158, MSG_EVENT);
|
cmistake(u, ord, 158, MSG_EVENT);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -863,7 +863,7 @@ static void manufacture(unit * u, const item_type * itype, int want)
|
||||||
typedef struct allocation {
|
typedef struct allocation {
|
||||||
struct allocation *next;
|
struct allocation *next;
|
||||||
int want, get;
|
int want, get;
|
||||||
double save;
|
variant save;
|
||||||
unsigned int flags;
|
unsigned int flags;
|
||||||
unit *unit;
|
unit *unit;
|
||||||
} allocation;
|
} allocation;
|
||||||
|
@ -883,6 +883,37 @@ enum {
|
||||||
AFL_LOWSKILL = 1 << 1
|
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)
|
static void allocate_resource(unit * u, const resource_type * rtype, int want)
|
||||||
{
|
{
|
||||||
const item_type *itype = resource2item(rtype);
|
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);
|
attrib *a = a_find(rtype->attribs, &at_resourcelimit);
|
||||||
resource_limit *rdata = (resource_limit *)a->data.v;
|
resource_limit *rdata = (resource_limit *)a->data.v;
|
||||||
const resource_type *rring;
|
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<EFBFBD>r
|
||||||
* Materialverbrauch hat: */
|
* Materialverbrauch hat: */
|
||||||
assert(itype != NULL && (itype->construction == NULL
|
assert(itype != NULL && (itype->construction == NULL
|
||||||
|| itype->construction->materials == NULL));
|
|| itype->construction->materials == NULL));
|
||||||
|
@ -915,21 +947,19 @@ static void allocate_resource(unit * u, const resource_type * rtype, int want)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rdata->modifiers) {
|
if (rdata->modifiers) {
|
||||||
resource_mod *mod = rdata->modifiers;
|
message *msg = get_modifiers(u, rdata->modifiers, &save_mod, &skill_mod);
|
||||||
for (; mod->flags != 0; ++mod) {
|
if (msg) {
|
||||||
if (mod->flags & RMF_REQUIREDBUILDING) {
|
ADDMSG(&u->faction->msgs, msg);
|
||||||
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;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
else {
|
||||||
|
save_mod.sa[0] = 1;
|
||||||
|
save_mod.sa[1] = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Bergwächter können Abbau von Eisen/Laen durch Bewachen verhindern.
|
/* Bergw<EFBFBD>chter k<>nnen Abbau von Eisen/Laen durch Bewachen verhindern.
|
||||||
* Als magische Wesen 'sehen' Bergwächter alles und werden durch
|
* Als magische Wesen 'sehen' Bergw<EFBFBD>chter alles und werden durch
|
||||||
* Belagerung nicht aufgehalten. (Ansonsten wie oben bei Elfen anpassen).
|
* Belagerung nicht aufgehalten. (Ansonsten wie oben bei Elfen anpassen).
|
||||||
*/
|
*/
|
||||||
if (itype->rtype && (itype->rtype == get_resourcetype(R_IRON) || itype->rtype == rt_find("laen"))) {
|
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));
|
itype->rtype));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
else {
|
skill += skill_mod;
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
amount = skill * u->number;
|
amount = skill * u->number;
|
||||||
/* nun ist amount die Gesamtproduktion der Einheit (in punkten) */
|
/* 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 = new_allocation();
|
||||||
al->want = amount;
|
al->want = amount;
|
||||||
al->save = 1.0;
|
al->save = save_mod;
|
||||||
al->next = alist->data;
|
al->next = alist->data;
|
||||||
al->unit = u;
|
al->unit = u;
|
||||||
alist->data = al;
|
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);
|
int req = (int)(want * save.sa[0] / save.sa[1]);
|
||||||
if (req < want * save)
|
int r = want * save.sa[0] % save.sa[1];
|
||||||
++req;
|
if (r>0) ++req;
|
||||||
return req;
|
return req;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1095,14 +1093,14 @@ leveled_allocation(const resource_type * rtype, region * r, allocation * alist)
|
||||||
if (avail > 0) {
|
if (avail > 0) {
|
||||||
int want = required(al->want - al->get, al->save);
|
int want = required(al->want - al->get, al->save);
|
||||||
int x = avail * want / nreq;
|
int x = avail * want / nreq;
|
||||||
/* Wenn Rest, dann würfeln, ob ich was bekomme: */
|
int r = (avail * want) % nreq;
|
||||||
if (rng_int() % nreq < (avail * want) % nreq)
|
/* Wenn Rest, dann wuerfeln, ob ich etwas bekomme: */
|
||||||
++x;
|
if (r > 0 && rng_int() % nreq < r) ++x;
|
||||||
avail -= x;
|
avail -= x;
|
||||||
use += x;
|
use += x;
|
||||||
nreq -= want;
|
nreq -= want;
|
||||||
need -= x;
|
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) {
|
if (use) {
|
||||||
|
@ -1140,12 +1138,13 @@ attrib_allocation(const resource_type * rtype, region * r, allocation * alist)
|
||||||
if (avail > 0) {
|
if (avail > 0) {
|
||||||
int want = required(al->want, al->save);
|
int want = required(al->want, al->save);
|
||||||
int x = avail * want / nreq;
|
int x = avail * want / nreq;
|
||||||
/* Wenn Rest, dann würfeln, ob ich was bekomme: */
|
int rx = (avail * want) % nreq;
|
||||||
if (rng_int() % nreq < (avail * want) % nreq)
|
/* Wenn Rest, dann wuerfeln, ob ich was bekomme: */
|
||||||
++x;
|
if (rx>0 && rng_int() % nreq < rx) ++x;
|
||||||
avail -= x;
|
avail -= x;
|
||||||
nreq -= want;
|
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) {
|
if (rdata->produce) {
|
||||||
int use = required(al->get, al->save);
|
int use = required(al->get, al->save);
|
||||||
if (use)
|
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 (itype->construction && fval(itype->rtype, RTF_LIMITED)) {
|
||||||
#if GUARD_DISABLES_PRODUCTION == 1
|
#if GUARD_DISABLES_PRODUCTION == 1
|
||||||
|
@ -1402,7 +1401,7 @@ int make_cmd(unit * u, struct order *ord)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (itype != NULL) {
|
else if (itype != NULL) {
|
||||||
create_item(u, itype, m);
|
make_item(u, itype, m);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "error_cannotmake", ""));
|
ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "error_cannotmake", ""));
|
||||||
|
@ -1453,15 +1452,15 @@ static void expandbuying(region * r, request * buyorders)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/* Initialisation. multiplier ist der Multiplikator auf den
|
/* Initialisation. multiplier ist der Multiplikator auf den
|
||||||
* Verkaufspreis. Für max_products Produkte kauft man das Produkt zum
|
* Verkaufspreis. F<EFBFBD>r max_products Produkte kauft man das Produkt zum
|
||||||
* einfachen Verkaufspreis, danach erhöht sich der Multiplikator um 1.
|
* einfachen Verkaufspreis, danach erh<EFBFBD>ht sich der Multiplikator um 1.
|
||||||
* counter ist ein Zähler, der die gekauften Produkte zählt. money
|
* counter ist ein Z<EFBFBD>hler, der die gekauften Produkte z<EFBFBD>hlt. money
|
||||||
* wird für die debug message gebraucht. */
|
* wird f<EFBFBD>r die debug message gebraucht. */
|
||||||
|
|
||||||
max_products = rpeasants(r) / TRADE_FRACTION;
|
max_products = rpeasants(r) / TRADE_FRACTION;
|
||||||
|
|
||||||
/* Kauf - auch so programmiert, daß er leicht erweiterbar auf mehrere
|
/* Kauf - auch so programmiert, da<EFBFBD> er leicht erweiterbar auf mehrere
|
||||||
* Güter pro Monat ist. j sind die Befehle, i der Index des
|
* G<EFBFBD>ter pro Monat ist. j sind die Befehle, i der Index des
|
||||||
* gehandelten Produktes. */
|
* gehandelten Produktes. */
|
||||||
if (max_products > 0) {
|
if (max_products > 0) {
|
||||||
unsigned int j;
|
unsigned int j;
|
||||||
|
@ -1483,10 +1482,10 @@ static void expandbuying(region * r, request * buyorders)
|
||||||
unit *u = g_requests[j].unit;
|
unit *u = g_requests[j].unit;
|
||||||
item *items;
|
item *items;
|
||||||
|
|
||||||
/* litems zählt die Güter, die verkauft wurden, u->n das Geld, das
|
/* litems z<EFBFBD>hlt die G<>ter, die verkauft wurden, u->n das Geld, das
|
||||||
* verdient wurde. Dies muß gemacht werden, weil der Preis ständig sinkt,
|
* verdient wurde. Dies mu<EFBFBD> gemacht werden, weil der Preis st<EFBFBD>ndig sinkt,
|
||||||
* man sich also das verdiente Geld und die verkauften Produkte separat
|
* man sich also das verdiente Geld und die verkauften Produkte separat
|
||||||
* merken muß. */
|
* merken mu<EFBFBD>. */
|
||||||
attrib *a = a_find(u->attribs, &at_luxuries);
|
attrib *a = a_find(u->attribs, &at_luxuries);
|
||||||
if (a == NULL)
|
if (a == NULL)
|
||||||
a = a_add(&u->attribs, a_new(&at_luxuries));
|
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);
|
rsetmoney(r, rmoney(r) + price);
|
||||||
|
|
||||||
/* Falls mehr als max_products Bauern ein Produkt verkauft haben, steigt
|
/* 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<EFBFBD>r das Produkt um den Faktor 1. Der Z<EFBFBD>hler
|
||||||
* wird wieder auf 0 gesetzt. */
|
* wird wieder auf 0 gesetzt. */
|
||||||
if (++trade->number == max_products) {
|
if (++trade->number == max_products) {
|
||||||
trade->number = 0;
|
trade->number = 0;
|
||||||
|
@ -1563,7 +1562,7 @@ static void buy(unit * u, request ** buyorders, struct order *ord)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
/* Im Augenblick kann man nur 1 Produkt kaufen. expandbuying ist aber
|
/* Im Augenblick kann man nur 1 Produkt kaufen. expandbuying ist aber
|
||||||
* schon dafür ausgerüstet, mehrere Produkte zu kaufen. */
|
* schon daf<EFBFBD>r ausger<EFBFBD>stet, mehrere Produkte zu kaufen. */
|
||||||
|
|
||||||
kwd = init_order(ord);
|
kwd = init_order(ord);
|
||||||
assert(kwd == K_BUY);
|
assert(kwd == K_BUY);
|
||||||
|
@ -1573,7 +1572,7 @@ static void buy(unit * u, request ** buyorders, struct order *ord)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (besieged(u)) {
|
if (besieged(u)) {
|
||||||
/* Belagerte Einheiten können nichts kaufen. */
|
/* Belagerte Einheiten k<EFBFBD>nnen nichts kaufen. */
|
||||||
cmistake(u, ord, 60, MSG_COMMERCE);
|
cmistake(u, ord, 60, MSG_COMMERCE);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -1587,7 +1586,7 @@ static void buy(unit * u, request ** buyorders, struct order *ord)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
/* ...oder in der Region muß es eine Burg geben. */
|
/* ...oder in der Region mu<EFBFBD> es eine Burg geben. */
|
||||||
building *b = 0;
|
building *b = 0;
|
||||||
if (r->buildings) {
|
if (r->buildings) {
|
||||||
static int cache;
|
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<EFBFBD>ndler kann nur 10 G<>ter pro Talentpunkt handeln. */
|
||||||
k = u->number * 10 * effskill(u, SK_TRADE, 0);
|
k = u->number * 10 * effskill(u, SK_TRADE, 0);
|
||||||
|
|
||||||
/* hat der Händler bereits gehandelt, muss die Menge der bereits
|
/* hat der H<EFBFBD>ndler bereits gehandelt, muss die Menge der bereits
|
||||||
* verkauften/gekauften Güter abgezogen werden */
|
* verkauften/gekauften G<EFBFBD>ter abgezogen werden */
|
||||||
a = a_find(u->attribs, &at_trades);
|
a = a_find(u->attribs, &at_trades);
|
||||||
if (!a) {
|
if (!a) {
|
||||||
a = a_add(&u->attribs, a_new(&at_trades));
|
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);
|
assert(n >= 0);
|
||||||
/* die Menge der verkauften Güter merken */
|
/* die Menge der verkauften G<EFBFBD>ter merken */
|
||||||
a->data.i += n;
|
a->data.i += n;
|
||||||
|
|
||||||
s = gettoken(token, sizeof(token));
|
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));
|
"unit region mode wanted amount", u, u->region, type, want, qty));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Steuersätze in % bei Burggröße */
|
/* Steuers<EFBFBD>tze in % bei Burggr<67><72>e */
|
||||||
static int tax_per_size[7] = { 0, 6, 12, 18, 24, 30, 36 };
|
static int tax_per_size[7] = { 0, 6, 12, 18, 24, 30, 36 };
|
||||||
|
|
||||||
static void expandselling(region * r, request * sellorders, int limit)
|
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);
|
memset(counter, 0, sizeof(int) * ncounter);
|
||||||
|
|
||||||
if (!sellorders) { /* NEIN, denn Insekten können in || !r->buildings) */
|
if (!sellorders) { /* NEIN, denn Insekten k<EFBFBD>nnen in || !r->buildings) */
|
||||||
return; /* Sümpfen und Wüsten auch so handeln */
|
return; /* S<EFBFBD>mpfen und W<>sten auch so handeln */
|
||||||
}
|
}
|
||||||
/* Stelle Eigentümer der größten Burg fest. Bekommt Steuern aus jedem
|
/* Stelle Eigent<EFBFBD>mer der gr<67><72>ten Burg fest. Bekommt Steuern aus jedem
|
||||||
* Verkauf. Wenn zwei Burgen gleicher Größe bekommt gar keiner etwas. */
|
* Verkauf. Wenn zwei Burgen gleicher Gr<EFBFBD><EFBFBD>e bekommt gar keiner etwas. */
|
||||||
for (b = rbuildings(r); b; b = b->next) {
|
for (b = rbuildings(r); b; b = b->next) {
|
||||||
if (b->size > maxsize && building_owner(b) != NULL
|
if (b->size > maxsize && building_owner(b) != NULL
|
||||||
&& b->type == castle_bt) {
|
&& b->type == castle_bt) {
|
||||||
|
@ -1724,13 +1723,13 @@ static void expandselling(region * r, request * sellorders, int limit)
|
||||||
maxowner = (unit *)NULL;
|
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<EFBFBD>nnen. */
|
||||||
|
|
||||||
money = rmoney(r);
|
money = rmoney(r);
|
||||||
|
|
||||||
/* max_products sind 1/100 der Bevölkerung, falls soviele Produkte
|
/* max_products sind 1/100 der Bev<EFBFBD>lkerung, falls soviele Produkte
|
||||||
* verkauft werden - counter[] - sinkt die Nachfrage um 1 Punkt.
|
* verkauft werden - counter[] - sinkt die Nachfrage um 1 Punkt.
|
||||||
* multiplier speichert r->demand für die debug message ab. */
|
* multiplier speichert r->demand f<EFBFBD>r die debug message ab. */
|
||||||
|
|
||||||
max_products = rpeasants(r) / TRADE_FRACTION;
|
max_products = rpeasants(r) / TRADE_FRACTION;
|
||||||
if (max_products <= 0)
|
if (max_products <= 0)
|
||||||
|
@ -1798,11 +1797,11 @@ static void expandselling(region * r, request * sellorders, int limit)
|
||||||
change_money(u, price);
|
change_money(u, price);
|
||||||
fset(u, UFL_LONGACTION | UFL_NOTMOVING);
|
fset(u, UFL_LONGACTION | UFL_NOTMOVING);
|
||||||
|
|
||||||
/* r->money -= price; --- dies wird eben nicht ausgeführt, denn die
|
/* r->money -= price; --- dies wird eben nicht ausgef<EFBFBD>hrt, denn die
|
||||||
* Produkte können auch als Steuern eingetrieben werden. In der Region
|
* Produkte k<EFBFBD>nnen auch als Steuern eingetrieben werden. In der Region
|
||||||
* wurden Silberstücke gegen Luxusgüter des selben Wertes eingetauscht!
|
* wurden Silberst<EFBFBD>cke gegen Luxusg<EFBFBD>ter des selben Wertes eingetauscht!
|
||||||
* Falls mehr als max_products Kunden ein Produkt gekauft haben, sinkt
|
* 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<EFBFBD>r das Produkt um 1. Der Z<EFBFBD>hler wird wieder auf 0
|
||||||
* gesetzt. */
|
* gesetzt. */
|
||||||
|
|
||||||
if (++counter[i] > max_products) {
|
if (++counter[i] > max_products) {
|
||||||
|
@ -1819,7 +1818,7 @@ static void expandselling(region * r, request * sellorders, int limit)
|
||||||
}
|
}
|
||||||
free(g_requests);
|
free(g_requests);
|
||||||
|
|
||||||
/* Steuern. Hier werden die Steuern dem Besitzer der größten Burg gegeben. */
|
/* Steuern. Hier werden die Steuern dem Besitzer der gr<EFBFBD><EFBFBD>ten Burg gegeben. */
|
||||||
if (maxowner) {
|
if (maxowner) {
|
||||||
if (taxcollected > 0) {
|
if (taxcollected > 0) {
|
||||||
change_money(maxowner, (int)taxcollected);
|
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);
|
cmistake(u, ord, 69, MSG_INCOME);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
/* sellorders sind KEIN array, weil für alle items DIE SELBE resource
|
/* sellorders sind KEIN array, weil f<EFBFBD>r alle items DIE SELBE resource
|
||||||
* (das geld der region) aufgebraucht wird. */
|
* (das geld der region) aufgebraucht wird. */
|
||||||
|
|
||||||
kwd = init_order(ord);
|
kwd = init_order(ord);
|
||||||
|
@ -1901,13 +1900,13 @@ static bool sell(unit * u, request ** sellorders, struct order *ord)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* Belagerte Einheiten können nichts verkaufen. */
|
/* Belagerte Einheiten k<EFBFBD>nnen nichts verkaufen. */
|
||||||
|
|
||||||
if (besieged(u)) {
|
if (besieged(u)) {
|
||||||
ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "error60", ""));
|
ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "error60", ""));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
/* In der Region muß es eine Burg geben. */
|
/* In der Region mu<EFBFBD> es eine Burg geben. */
|
||||||
|
|
||||||
if (u_race(u) == get_race(RC_INSECT)) {
|
if (u_race(u) == get_race(RC_INSECT)) {
|
||||||
if (r->terrain != newterrain(T_SWAMP) && r->terrain != newterrain(T_DESERT)
|
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 {
|
else {
|
||||||
/* ...oder in der Region muß es eine Burg geben. */
|
/* ...oder in der Region mu<EFBFBD> es eine Burg geben. */
|
||||||
building *b = 0;
|
building *b = 0;
|
||||||
if (r->buildings) {
|
if (r->buildings) {
|
||||||
for (b = r->buildings; b; b = b->next) {
|
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<EFBFBD>ndler kann nur 10 G<>ter pro Talentpunkt verkaufen. */
|
||||||
|
|
||||||
n = MIN(n, u->number * 10 * effskill(u, SK_TRADE, 0));
|
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);
|
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<EFBFBD> ihr Zeug abgezogen
|
||||||
* werden damit es nicht zweimal verkauft wird: */
|
* werden damit es nicht zweimal verkauft wird: */
|
||||||
for (o = *sellorders; o; o = o->next) {
|
for (o = *sellorders; o; o = o->next) {
|
||||||
if (o->type.ltype == ltype && o->unit->faction == u->faction) {
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
/* Hier wird request->type verwendet, weil die obere limit durch
|
/* 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<EFBFBD>r alle
|
||||||
* (!) produkte als summe gilt, als nicht wie bei der
|
* (!) produkte als summe gilt, als nicht wie bei der
|
||||||
* produktion, wo für jedes produkt einzeln eine obere limite
|
* produktion, wo f<EFBFBD>r jedes produkt einzeln eine obere limite
|
||||||
* existiert, so dass man arrays von orders machen kann. */
|
* existiert, so dass man arrays von orders machen kann. */
|
||||||
|
|
||||||
/* Ein Händler kann nur 10 Güter pro Talentpunkt handeln. */
|
/* Ein H<EFBFBD>ndler kann nur 10 G<>ter pro Talentpunkt handeln. */
|
||||||
k = u->number * 10 * effskill(u, SK_TRADE, 0);
|
k = u->number * 10 * effskill(u, SK_TRADE, 0);
|
||||||
|
|
||||||
/* hat der Händler bereits gehandelt, muss die Menge der bereits
|
/* hat der H<EFBFBD>ndler bereits gehandelt, muss die Menge der bereits
|
||||||
* verkauften/gekauften Güter abgezogen werden */
|
* verkauften/gekauften G<EFBFBD>ter abgezogen werden */
|
||||||
a = a_find(u->attribs, &at_trades);
|
a = a_find(u->attribs, &at_trades);
|
||||||
if (!a) {
|
if (!a) {
|
||||||
a = a_add(&u->attribs, a_new(&at_trades));
|
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);
|
n = MIN(n, k);
|
||||||
assert(n >= 0);
|
assert(n >= 0);
|
||||||
/* die Menge der verkauften Güter merken */
|
/* die Menge der verkauften G<EFBFBD>ter merken */
|
||||||
a->data.i += n;
|
a->data.i += n;
|
||||||
o = (request *)calloc(1, sizeof(request));
|
o = (request *)calloc(1, sizeof(request));
|
||||||
o->unit = u;
|
o->unit = u;
|
||||||
|
@ -2017,8 +2016,8 @@ static void expandstealing(region * r, request * stealorders)
|
||||||
expandorders(r, stealorders);
|
expandorders(r, stealorders);
|
||||||
if (!norders) return;
|
if (!norders) return;
|
||||||
|
|
||||||
/* Für jede unit in der Region wird Geld geklaut, wenn sie Opfer eines
|
/* F<EFBFBD>r jede unit in der Region wird Geld geklaut, wenn sie Opfer eines
|
||||||
* Beklauen-Orders ist. Jedes Opfer muß einzeln behandelt werden.
|
* Beklauen-Orders ist. Jedes Opfer mu<EFBFBD> einzeln behandelt werden.
|
||||||
*
|
*
|
||||||
* u ist die beklaute unit. oa.unit ist die klauende unit.
|
* u ist die beklaute unit. oa.unit ist die klauende unit.
|
||||||
*/
|
*/
|
||||||
|
@ -2079,7 +2078,7 @@ static void plant(unit * u, int raw)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Skill prüfen */
|
/* Skill pr<EFBFBD>fen */
|
||||||
skill = effskill(u, SK_HERBALISM, 0);
|
skill = effskill(u, SK_HERBALISM, 0);
|
||||||
if (skill < 6) {
|
if (skill < 6) {
|
||||||
ADDMSG(&u->faction->msgs,
|
ADDMSG(&u->faction->msgs,
|
||||||
|
@ -2087,14 +2086,14 @@ static void plant(unit * u, int raw)
|
||||||
"skill minskill product", SK_HERBALISM, 6, itype->rtype, 1));
|
"skill minskill product", SK_HERBALISM, 6, itype->rtype, 1));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
/* Wasser des Lebens prüfen */
|
/* Wasser des Lebens pr<EFBFBD>fen */
|
||||||
if (get_pooled(u, rt_water, GET_DEFAULT, 1) == 0) {
|
if (get_pooled(u, rt_water, GET_DEFAULT, 1) == 0) {
|
||||||
ADDMSG(&u->faction->msgs,
|
ADDMSG(&u->faction->msgs,
|
||||||
msg_feedback(u, u->thisorder, "resource_missing", "missing", rt_water));
|
msg_feedback(u, u->thisorder, "resource_missing", "missing", rt_water));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
n = get_pooled(u, itype->rtype, GET_DEFAULT, skill * u->number);
|
n = get_pooled(u, itype->rtype, GET_DEFAULT, skill * u->number);
|
||||||
/* Kräuter prüfen */
|
/* Kr<EFBFBD>uter pr<70>fen */
|
||||||
if (n == 0) {
|
if (n == 0) {
|
||||||
ADDMSG(&u->faction->msgs,
|
ADDMSG(&u->faction->msgs,
|
||||||
msg_feedback(u, u->thisorder, "resource_missing", "missing",
|
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(skill * u->number, n);
|
||||||
n = MIN(raw, n);
|
n = MIN(raw, n);
|
||||||
/* Für jedes Kraut Talent*10% Erfolgschance. */
|
/* F<EFBFBD>r jedes Kraut Talent*10% Erfolgschance. */
|
||||||
for (i = n; i > 0; i--) {
|
for (i = n; i > 0; i--) {
|
||||||
if (rng_int() % 10 < skill)
|
if (rng_int() % 10 < skill)
|
||||||
planted++;
|
planted++;
|
||||||
|
@ -2129,10 +2128,10 @@ static void planttrees(unit * u, int raw)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Mallornbäume kann man nur in Mallornregionen züchten */
|
/* Mallornb<EFBFBD>ume kann man nur in Mallornregionen z<>chten */
|
||||||
rtype = get_resourcetype(fval(r, RF_MALLORN) ? R_MALLORNSEED : R_SEED);
|
rtype = get_resourcetype(fval(r, RF_MALLORN) ? R_MALLORNSEED : R_SEED);
|
||||||
|
|
||||||
/* Skill prüfen */
|
/* Skill pr<EFBFBD>fen */
|
||||||
skill = effskill(u, SK_HERBALISM, 0);
|
skill = effskill(u, SK_HERBALISM, 0);
|
||||||
if (skill < 6) {
|
if (skill < 6) {
|
||||||
ADDMSG(&u->faction->msgs,
|
ADDMSG(&u->faction->msgs,
|
||||||
|
@ -2157,7 +2156,7 @@ static void planttrees(unit * u, int raw)
|
||||||
}
|
}
|
||||||
n = MIN(raw, n);
|
n = MIN(raw, n);
|
||||||
|
|
||||||
/* Für jeden Samen Talent*10% Erfolgschance. */
|
/* F<EFBFBD>r jeden Samen Talent*10% Erfolgschance. */
|
||||||
for (i = n; i > 0; i--) {
|
for (i = n; i > 0; i--) {
|
||||||
if (rng_int() % 10 < skill)
|
if (rng_int() % 10 < skill)
|
||||||
planted++;
|
planted++;
|
||||||
|
@ -2172,7 +2171,7 @@ static void planttrees(unit * u, int raw)
|
||||||
"unit region amount herb", u, r, planted, rtype));
|
"unit region amount herb", u, r, planted, rtype));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* züchte bäume */
|
/* z<EFBFBD>chte b<>ume */
|
||||||
static void breedtrees(unit * u, int raw)
|
static void breedtrees(unit * u, int raw)
|
||||||
{
|
{
|
||||||
int n, i, skill, planted = 0;
|
int n, i, skill, planted = 0;
|
||||||
|
@ -2184,7 +2183,7 @@ static void breedtrees(unit * u, int raw)
|
||||||
get_gamedate(turn, &date);
|
get_gamedate(turn, &date);
|
||||||
current_season = date.season;
|
current_season = date.season;
|
||||||
|
|
||||||
/* Bäume züchten geht nur im Frühling */
|
/* B<EFBFBD>ume z<>chten geht nur im Fr<46>hling */
|
||||||
if (current_season != SEASON_SPRING) {
|
if (current_season != SEASON_SPRING) {
|
||||||
planttrees(u, raw);
|
planttrees(u, raw);
|
||||||
return;
|
return;
|
||||||
|
@ -2194,10 +2193,10 @@ static void breedtrees(unit * u, int raw)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Mallornbäume kann man nur in Mallornregionen züchten */
|
/* Mallornb<EFBFBD>ume kann man nur in Mallornregionen z<>chten */
|
||||||
rtype = get_resourcetype(fval(r, RF_MALLORN) ? R_MALLORNSEED : R_SEED);
|
rtype = get_resourcetype(fval(r, RF_MALLORN) ? R_MALLORNSEED : R_SEED);
|
||||||
|
|
||||||
/* Skill prüfen */
|
/* Skill pr<EFBFBD>fen */
|
||||||
skill = effskill(u, SK_HERBALISM, 0);
|
skill = effskill(u, SK_HERBALISM, 0);
|
||||||
if (skill < 12) {
|
if (skill < 12) {
|
||||||
planttrees(u, raw);
|
planttrees(u, raw);
|
||||||
|
@ -2207,7 +2206,7 @@ static void breedtrees(unit * u, int raw)
|
||||||
/* wenn eine Anzahl angegeben wurde, nur soviel verbrauchen */
|
/* wenn eine Anzahl angegeben wurde, nur soviel verbrauchen */
|
||||||
raw = MIN(skill * u->number, raw);
|
raw = MIN(skill * u->number, raw);
|
||||||
n = get_pooled(u, rtype, GET_DEFAULT, raw);
|
n = get_pooled(u, rtype, GET_DEFAULT, raw);
|
||||||
/* Samen prüfen */
|
/* Samen pr<EFBFBD>fen */
|
||||||
if (n == 0) {
|
if (n == 0) {
|
||||||
ADDMSG(&u->faction->msgs,
|
ADDMSG(&u->faction->msgs,
|
||||||
msg_feedback(u, u->thisorder, "resource_missing", "missing", rtype));
|
msg_feedback(u, u->thisorder, "resource_missing", "missing", rtype));
|
||||||
|
@ -2215,7 +2214,7 @@ static void breedtrees(unit * u, int raw)
|
||||||
}
|
}
|
||||||
n = MIN(raw, n);
|
n = MIN(raw, n);
|
||||||
|
|
||||||
/* Für jeden Samen Talent*5% Erfolgschance. */
|
/* F<EFBFBD>r jeden Samen Talent*5% Erfolgschance. */
|
||||||
for (i = n; i > 0; i--) {
|
for (i = n; i > 0; i--) {
|
||||||
if (rng_int() % 100 < skill * 5)
|
if (rng_int() % 100 < skill * 5)
|
||||||
planted++;
|
planted++;
|
||||||
|
@ -2230,7 +2229,7 @@ static void breedtrees(unit * u, int raw)
|
||||||
"unit region amount herb", u, r, planted, rtype));
|
"unit region amount herb", u, r, planted, rtype));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* züchte pferde */
|
/* z<EFBFBD>chte pferde */
|
||||||
static void breedhorses(unit * u)
|
static void breedhorses(unit * u)
|
||||||
{
|
{
|
||||||
int n, c, breed = 0;
|
int n, c, breed = 0;
|
||||||
|
@ -2283,7 +2282,7 @@ static void breed_cmd(unit * u, struct order *ord)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* züchte [<anzahl>] <parameter> */
|
/* z<EFBFBD>chte [<anzahl>] <parameter> */
|
||||||
(void)init_order(ord);
|
(void)init_order(ord);
|
||||||
s = gettoken(token, sizeof(token));
|
s = gettoken(token, sizeof(token));
|
||||||
|
|
||||||
|
@ -2549,7 +2548,7 @@ static void expandentertainment(region * r)
|
||||||
m -= u->n;
|
m -= u->n;
|
||||||
entertaining -= o->qty;
|
entertaining -= o->qty;
|
||||||
|
|
||||||
/* Nur soviel PRODUCEEXP wie auch tatsächlich gemacht wurde */
|
/* Nur soviel PRODUCEEXP wie auch tats<EFBFBD>chlich gemacht wurde */
|
||||||
produceexp(u, SK_ENTERTAINMENT, MIN(u->n, u->number));
|
produceexp(u, SK_ENTERTAINMENT, MIN(u->n, u->number));
|
||||||
add_income(u, IC_ENTERTAIN, o->qty, u->n);
|
add_income(u, IC_ENTERTAIN, o->qty, u->n);
|
||||||
fset(u, UFL_LONGACTION | UFL_NOTMOVING);
|
fset(u, UFL_LONGACTION | UFL_NOTMOVING);
|
||||||
|
@ -2633,8 +2632,9 @@ expandwork(region * r, request * work_begin, request * work_end, int maxwork)
|
||||||
if (jobs >= working)
|
if (jobs >= working)
|
||||||
workers = u->number;
|
workers = u->number;
|
||||||
else {
|
else {
|
||||||
|
int r = (u->number * jobs) % working;
|
||||||
workers = 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++;
|
workers++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2707,7 +2707,7 @@ static void expandloot(region * r, request * lootorders)
|
||||||
{
|
{
|
||||||
unit *u;
|
unit *u;
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
int looted = 0;
|
int m, looted = 0;
|
||||||
int startmoney = rmoney(r);
|
int startmoney = rmoney(r);
|
||||||
|
|
||||||
expandorders(r, lootorders);
|
expandorders(r, lootorders);
|
||||||
|
@ -2724,9 +2724,9 @@ static void expandloot(region * r, request * lootorders)
|
||||||
free(g_requests);
|
free(g_requests);
|
||||||
|
|
||||||
/* Lowering morale by 1 depending on the looted money (+20%) */
|
/* Lowering morale by 1 depending on the looted money (+20%) */
|
||||||
|
m = region_get_morale(r);
|
||||||
|
if (m && startmoney>0) {
|
||||||
if (rng_int() % 100 < 20 + (looted * 80) / startmoney) {
|
if (rng_int() % 100 < 20 + (looted * 80) / startmoney) {
|
||||||
int m = region_get_morale(r);
|
|
||||||
if (m) {
|
|
||||||
/*Nur Moral -1, turns is not changed, so the first time nothing happens if the morale is good*/
|
/*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);
|
region_set_morale(r, m - 1, -1);
|
||||||
}
|
}
|
||||||
|
@ -3121,7 +3121,7 @@ void produce(struct region *r)
|
||||||
|
|
||||||
/* Entertainment (expandentertainment) und Besteuerung (expandtax) vor den
|
/* Entertainment (expandentertainment) und Besteuerung (expandtax) vor den
|
||||||
* Befehlen, die den Bauern mehr Geld geben, damit man aus den Zahlen der
|
* 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<EFBFBD>r Unterhaltung
|
||||||
* auszugeben bereit sind. */
|
* auszugeben bereit sind. */
|
||||||
if (entertaining)
|
if (entertaining)
|
||||||
expandentertainment(r);
|
expandentertainment(r);
|
||||||
|
@ -3136,7 +3136,7 @@ void produce(struct region *r)
|
||||||
|
|
||||||
/* An erster Stelle Kaufen (expandbuying), die Bauern so Geld bekommen, um
|
/* An erster Stelle Kaufen (expandbuying), die Bauern so Geld bekommen, um
|
||||||
* nachher zu beim Verkaufen (expandselling) den Spielern abkaufen zu
|
* nachher zu beim Verkaufen (expandselling) den Spielern abkaufen zu
|
||||||
* können. */
|
* k<EFBFBD>nnen. */
|
||||||
|
|
||||||
if (buyorders)
|
if (buyorders)
|
||||||
expandbuying(r, buyorders);
|
expandbuying(r, buyorders);
|
||||||
|
|
|
@ -56,6 +56,7 @@ extern "C" {
|
||||||
|
|
||||||
enum { IC_WORK, IC_ENTERTAIN, IC_TAX, IC_TRADE, IC_TRADETAX, IC_STEAL, IC_MAGIC, IC_LOOT };
|
enum { IC_WORK, IC_ENTERTAIN, IC_TAX, IC_TRADE, IC_TRADETAX, IC_STEAL, IC_MAGIC, IC_LOOT };
|
||||||
void maintain_buildings(struct region *r);
|
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);
|
int make_cmd(struct unit *u, struct order *ord);
|
||||||
void split_allocations(struct region *r);
|
void split_allocations(struct region *r);
|
||||||
int give_control_cmd(struct unit *u, struct order *ord);
|
int give_control_cmd(struct unit *u, struct order *ord);
|
||||||
|
|
|
@ -11,10 +11,12 @@
|
||||||
#include <kernel/pool.h>
|
#include <kernel/pool.h>
|
||||||
#include <kernel/race.h>
|
#include <kernel/race.h>
|
||||||
#include <kernel/region.h>
|
#include <kernel/region.h>
|
||||||
|
#include <kernel/resources.h>
|
||||||
#include <kernel/ship.h>
|
#include <kernel/ship.h>
|
||||||
#include <kernel/terrain.h>
|
#include <kernel/terrain.h>
|
||||||
#include <kernel/unit.h>
|
#include <kernel/unit.h>
|
||||||
|
|
||||||
|
#include <util/attrib.h>
|
||||||
#include <util/language.h>
|
#include <util/language.h>
|
||||||
|
|
||||||
#include <CuTest.h>
|
#include <CuTest.h>
|
||||||
|
@ -341,12 +343,89 @@ static void test_income(CuTest *tc)
|
||||||
test_cleanup();
|
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 *get_economy_suite(void)
|
||||||
{
|
{
|
||||||
CuSuite *suite = CuSuiteNew();
|
CuSuite *suite = CuSuiteNew();
|
||||||
SUITE_ADD_TEST(suite, test_give_control_building);
|
SUITE_ADD_TEST(suite, test_give_control_building);
|
||||||
SUITE_ADD_TEST(suite, test_give_control_ship);
|
SUITE_ADD_TEST(suite, test_give_control_ship);
|
||||||
SUITE_ADD_TEST(suite, test_income);
|
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_okay);
|
||||||
SUITE_ADD_TEST(suite, test_steal_ocean);
|
SUITE_ADD_TEST(suite, test_steal_ocean);
|
||||||
SUITE_ADD_TEST(suite, test_steal_nosteal);
|
SUITE_ADD_TEST(suite, test_steal_nosteal);
|
||||||
|
|
|
@ -397,7 +397,7 @@ static int required(int size, int msize, int maxneed)
|
||||||
* braucht man required von maxneed resourcen */
|
* braucht man required von maxneed resourcen */
|
||||||
{
|
{
|
||||||
int used;
|
int used;
|
||||||
|
assert(msize > 0);
|
||||||
used = size * maxneed / msize;
|
used = size * maxneed / msize;
|
||||||
if (size * maxneed % msize)
|
if (size * maxneed % msize)
|
||||||
++used;
|
++used;
|
||||||
|
@ -428,6 +428,76 @@ int roqf_factor(void)
|
||||||
return value;
|
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.
|
/** Use up resources for building an object.
|
||||||
* Build up to 'size' points of 'type', where 'completed'
|
* Build up to 'size' points of 'type', where 'completed'
|
||||||
* of the first object have already been finished. return the
|
* 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;) {
|
for (; want > 0 && skills > 0;) {
|
||||||
int c, n;
|
int err, n;
|
||||||
|
|
||||||
/* skip over everything that's already been done:
|
/* skip over everything that's already been done:
|
||||||
* type->improvement==NULL means no more improvements, but no size limits
|
* type->improvement==NULL means no more improvements, but no size limits
|
||||||
|
@ -559,66 +629,16 @@ int build(unit * u, const construction * ctype, int completed, int want)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (type->materials)
|
n = count_materials(u, type, n, completed);
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (n <= 0) {
|
if (n <= 0) {
|
||||||
if (made == 0)
|
if (made == 0)
|
||||||
return ENOMATERIALS;
|
return ENOMATERIALS;
|
||||||
else
|
else
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (type->materials)
|
err = use_materials(u, type, n, completed);
|
||||||
for (c = 0; type->materials[c].number; c++) {
|
if (err < 0) {
|
||||||
const struct resource_type *rtype = type->materials[c].rtype;
|
return err;
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
made += n;
|
made += n;
|
||||||
skills -= n * type->minskill;
|
skills -= n * type->minskill;
|
||||||
|
|
|
@ -84,7 +84,7 @@ static void test_group_readwrite(CuTest * tc)
|
||||||
f = test_create_faction(0);
|
f = test_create_faction(0);
|
||||||
new_group(f, "NW", 42);
|
new_group(f, "NW", 42);
|
||||||
g = new_group(f, "Egoisten", 43);
|
g = new_group(f, "Egoisten", 43);
|
||||||
key_set(&g->attribs, 44);
|
key_set(&g->attribs, 44, 44);
|
||||||
al = ally_add(&g->allies, f);
|
al = ally_add(&g->allies, f);
|
||||||
al->status = HELP_GIVE;
|
al->status = HELP_GIVE;
|
||||||
write_groups(&store, f);
|
write_groups(&store, f);
|
||||||
|
@ -108,7 +108,7 @@ static void test_group_readwrite(CuTest * tc)
|
||||||
CuAssertStrEquals(tc, "Egoisten", f->groups->next->name);
|
CuAssertStrEquals(tc, "Egoisten", f->groups->next->name);
|
||||||
CuAssertPtrEquals(tc, 0, f->groups->allies);
|
CuAssertPtrEquals(tc, 0, f->groups->allies);
|
||||||
g = f->groups->next;
|
g = f->groups->next;
|
||||||
CuAssertTrue(tc, key_get(g->attribs, 44));
|
CuAssertIntEquals(tc, 44, key_get(g->attribs, 44));
|
||||||
CuAssertPtrNotNull(tc, g->allies);
|
CuAssertPtrNotNull(tc, g->allies);
|
||||||
CuAssertPtrEquals(tc, 0, g->allies->next);
|
CuAssertPtrEquals(tc, 0, g->allies->next);
|
||||||
CuAssertPtrEquals(tc, f, g->allies->faction);
|
CuAssertPtrEquals(tc, f, g->allies->faction);
|
||||||
|
|
|
@ -939,7 +939,7 @@ struct order *ord)
|
||||||
use_pooled(user, itype->rtype, GET_SLACK | GET_RESERVE | GET_POOLED_SLACK,
|
use_pooled(user, itype->rtype, GET_SLACK | GET_RESERVE | GET_POOLED_SLACK,
|
||||||
user->number);
|
user->number);
|
||||||
|
|
||||||
key_set(&f->attribs, atoi36("mbst"));
|
key_set(&f->attribs, atoi36("mbst"), turn);
|
||||||
set_level(user, SK_MAGIC, 3);
|
set_level(user, SK_MAGIC, 3);
|
||||||
|
|
||||||
ADDMSG(&user->faction->msgs, msg_message("use_item",
|
ADDMSG(&user->faction->msgs, msg_message("use_item",
|
||||||
|
|
|
@ -70,7 +70,7 @@ extern "C" {
|
||||||
typedef char *(*rtype_name) (const struct resource_type * rtype, int flags);
|
typedef char *(*rtype_name) (const struct resource_type * rtype, int flags);
|
||||||
typedef struct resource_type {
|
typedef struct resource_type {
|
||||||
/* --- constants --- */
|
/* --- constants --- */
|
||||||
char *_name; /* wie es heißt */
|
char *_name; /* wie es hei<EFBFBD>t */
|
||||||
unsigned int flags;
|
unsigned int flags;
|
||||||
/* --- functions --- */
|
/* --- functions --- */
|
||||||
rtype_uchange uchange;
|
rtype_uchange uchange;
|
||||||
|
@ -91,8 +91,7 @@ extern "C" {
|
||||||
|
|
||||||
/* resource-limits for regions */
|
/* resource-limits for regions */
|
||||||
#define RMF_SKILL 0x01 /* int, bonus on resource production skill */
|
#define RMF_SKILL 0x01 /* int, bonus on resource production skill */
|
||||||
#define RMF_SAVEMATERIAL 0x02 /* float, multiplier on resource usage */
|
#define RMF_SAVEMATERIAL 0x02 /* fraction (sa[0]/sa[1]), multiplier on resource usage */
|
||||||
#define RMF_SAVERESOURCE 0x03 /* int, bonus on resource production skill */
|
|
||||||
#define RMF_REQUIREDBUILDING 0x04 /* building, required to build */
|
#define RMF_REQUIREDBUILDING 0x04 /* building, required to build */
|
||||||
|
|
||||||
typedef struct resource_mod {
|
typedef struct resource_mod {
|
||||||
|
@ -136,7 +135,7 @@ extern "C" {
|
||||||
int weight;
|
int weight;
|
||||||
int capacity;
|
int capacity;
|
||||||
struct construction *construction;
|
struct construction *construction;
|
||||||
char *_appearance[2]; /* wie es für andere aussieht */
|
char *_appearance[2]; /* wie es f<EFBFBD>r andere aussieht */
|
||||||
/* --- functions --- */
|
/* --- functions --- */
|
||||||
bool(*canuse) (const struct unit * user,
|
bool(*canuse) (const struct unit * user,
|
||||||
const struct item_type * itype);
|
const struct item_type * itype);
|
||||||
|
@ -311,6 +310,8 @@ extern "C" {
|
||||||
extern const struct potion_type *oldpotiontype[];
|
extern const struct potion_type *oldpotiontype[];
|
||||||
const struct resource_type *get_resourcetype(resource_t rt);
|
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 get_money(const struct unit *);
|
||||||
int set_money(struct unit *, int);
|
int set_money(struct unit *, int);
|
||||||
int change_money(struct unit *, int);
|
int change_money(struct unit *, int);
|
||||||
|
|
|
@ -270,8 +270,6 @@ void syntax_error(const struct unit *u, struct order *ord)
|
||||||
ADDMSG(&u->faction->msgs, result);
|
ADDMSG(&u->faction->msgs, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
extern unsigned int new_hashstring(const char *s);
|
|
||||||
|
|
||||||
void free_messagelist(mlist *msgs)
|
void free_messagelist(mlist *msgs)
|
||||||
{
|
{
|
||||||
struct mlist **mlistptr;
|
struct mlist **mlistptr;
|
||||||
|
|
|
@ -277,7 +277,6 @@ void free_races(void) {
|
||||||
free(at->data.dice);
|
free(at->data.dice);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
spellref_free(races->precombatspell);
|
|
||||||
free(xrefs);
|
free(xrefs);
|
||||||
xrefs = 0;
|
xrefs = 0;
|
||||||
free(races->_name);
|
free(races->_name);
|
||||||
|
@ -337,7 +336,6 @@ race *rc_create(const char *zName)
|
||||||
assert(strchr(zName, ' ') == NULL);
|
assert(strchr(zName, ' ') == NULL);
|
||||||
}
|
}
|
||||||
rc->_name = strdup(zName);
|
rc->_name = strdup(zName);
|
||||||
rc->precombatspell = NULL;
|
|
||||||
|
|
||||||
rc->attack[0].type = AT_COMBATSPELL;
|
rc->attack[0].type = AT_COMBATSPELL;
|
||||||
for (i = 1; i < RACE_ATTACKS; ++i)
|
for (i = 1; i < RACE_ATTACKS; ++i)
|
||||||
|
|
|
@ -138,7 +138,6 @@ extern "C" {
|
||||||
int df_default; /* Verteidigungsskill Unbewaffnet (default: -2) */
|
int df_default; /* Verteidigungsskill Unbewaffnet (default: -2) */
|
||||||
int at_bonus; /* Ver<65>ndert den Angriffsskill (default: 0) */
|
int at_bonus; /* Ver<65>ndert den Angriffsskill (default: 0) */
|
||||||
int df_bonus; /* Ver<65>ndert den Verteidigungskill (default: 0) */
|
int df_bonus; /* Ver<65>ndert den Verteidigungskill (default: 0) */
|
||||||
struct spellref *precombatspell;
|
|
||||||
signed char *study_speed; /* study-speed-bonus in points/turn (0=30 Tage) */
|
signed char *study_speed; /* study-speed-bonus in points/turn (0=30 Tage) */
|
||||||
int flags;
|
int flags;
|
||||||
int battle_flags;
|
int battle_flags;
|
||||||
|
|
|
@ -55,18 +55,16 @@ extern "C" {
|
||||||
|
|
||||||
extern struct rawmaterial_type *rawmaterialtypes;
|
extern struct rawmaterial_type *rawmaterialtypes;
|
||||||
|
|
||||||
extern void update_resources(struct region *r);
|
void update_resources(struct region *r);
|
||||||
extern void terraform_resources(struct region *r);
|
void terraform_resources(struct region *r);
|
||||||
extern void read_resources(struct region *r);
|
struct rawmaterial *rm_get(struct region *,
|
||||||
extern void write_resources(struct region *r);
|
|
||||||
extern struct rawmaterial *rm_get(struct region *,
|
|
||||||
const struct resource_type *);
|
const struct resource_type *);
|
||||||
extern struct rawmaterial_type *rmt_find(const char *str);
|
struct rawmaterial_type *rmt_find(const char *str);
|
||||||
extern struct rawmaterial_type *rmt_get(const struct resource_type *);
|
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);
|
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);
|
const char *name);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
|
|
@ -211,8 +211,8 @@ static void test_readwrite_attrib(CuTest *tc) {
|
||||||
attrib *a = NULL;
|
attrib *a = NULL;
|
||||||
|
|
||||||
test_setup();
|
test_setup();
|
||||||
key_set(&a, 41);
|
key_set(&a, 41, 42);
|
||||||
key_set(&a, 42);
|
key_set(&a, 42, 43);
|
||||||
mstream_init(&data.strm);
|
mstream_init(&data.strm);
|
||||||
gamedata_init(&data, &store, RELEASE_VERSION);
|
gamedata_init(&data, &store, RELEASE_VERSION);
|
||||||
write_attribs(data.store, a, NULL);
|
write_attribs(data.store, a, NULL);
|
||||||
|
@ -223,8 +223,8 @@ static void test_readwrite_attrib(CuTest *tc) {
|
||||||
read_attribs(&data, &a, NULL);
|
read_attribs(&data, &a, NULL);
|
||||||
mstream_done(&data.strm);
|
mstream_done(&data.strm);
|
||||||
gamedata_done(&data);
|
gamedata_done(&data);
|
||||||
CuAssertTrue(tc, key_get(a, 41));
|
CuAssertIntEquals(tc, 42, key_get(a, 41));
|
||||||
CuAssertTrue(tc, key_get(a, 42));
|
CuAssertIntEquals(tc, 43, key_get(a, 42));
|
||||||
a_removeall(&a, NULL);
|
a_removeall(&a, NULL);
|
||||||
|
|
||||||
test_cleanup();
|
test_cleanup();
|
||||||
|
|
|
@ -11,8 +11,9 @@
|
||||||
const char *eressea_version(void) {
|
const char *eressea_version(void) {
|
||||||
#ifdef ERESSEA_BUILDNO
|
#ifdef ERESSEA_BUILDNO
|
||||||
return ERESSEA_VERSION "-" ERESSEA_BUILDNO;
|
return ERESSEA_VERSION "-" ERESSEA_BUILDNO;
|
||||||
#endif
|
#else
|
||||||
return ERESSEA_VERSION;
|
return ERESSEA_VERSION;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
int version_no(const char *str) {
|
int version_no(const char *str) {
|
||||||
|
|
|
@ -905,6 +905,22 @@ static int parse_rules(xmlDocPtr doc)
|
||||||
return 0;
|
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)
|
static int parse_resources(xmlDocPtr doc)
|
||||||
{
|
{
|
||||||
xmlXPathContextPtr xpath = xmlXPathNewContext(doc);
|
xmlXPathContextPtr xpath = xmlXPathNewContext(doc);
|
||||||
|
@ -1025,13 +1041,17 @@ static int parse_resources(xmlDocPtr doc)
|
||||||
rdata->modifiers[k].flags = RMF_SKILL;
|
rdata->modifiers[k].flags = RMF_SKILL;
|
||||||
}
|
}
|
||||||
else if (strcmp((const char *)propValue, "material") == 0) {
|
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;
|
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) {
|
else if (strcmp((const char *)propValue, "require") == 0) {
|
||||||
xmlChar *propBldg = xmlGetProp(node, BAD_CAST "building");
|
xmlChar *propBldg = xmlGetProp(node, BAD_CAST "building");
|
||||||
if (propBldg != NULL) {
|
if (propBldg != NULL) {
|
||||||
|
@ -1829,17 +1849,6 @@ static int parse_races(xmlDocPtr doc)
|
||||||
}
|
}
|
||||||
xmlXPathFreeObject(result);
|
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 */
|
/* reading eressea/races/race/attack */
|
||||||
xpath->node = node;
|
xpath->node = node;
|
||||||
result = xmlXPathEvalExpression(BAD_CAST "attack", xpath);
|
result = xmlXPathEvalExpression(BAD_CAST "attack", xpath);
|
||||||
|
|
|
@ -561,13 +561,6 @@ const spell *get_combatspell(const unit * u, int nr)
|
||||||
if (m) {
|
if (m) {
|
||||||
return m->combatspells[nr].sp;
|
return m->combatspells[nr].sp;
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
const race * rc = u_race(u);
|
|
||||||
if (rc->precombatspell) {
|
|
||||||
return spellref_get(rc->precombatspell);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6596,7 +6596,6 @@ static spelldata spell_functions[] = {
|
||||||
{ "powerful_dragonbreath", sp_dragonodem, 0 },
|
{ "powerful_dragonbreath", sp_dragonodem, 0 },
|
||||||
{ "drain_skills", sp_dragonodem, 0 },
|
{ "drain_skills", sp_dragonodem, 0 },
|
||||||
{ "aura_of_fear", sp_flee, 0 },
|
{ "aura_of_fear", sp_flee, 0 },
|
||||||
{ "shadowcall", sp_shadowcall, 0 },
|
|
||||||
{ "immolation", sp_immolation, 0 },
|
{ "immolation", sp_immolation, 0 },
|
||||||
{ "firestorm", sp_immolation, 0 },
|
{ "firestorm", sp_immolation, 0 },
|
||||||
{ "coldfront", sp_immolation, 0 },
|
{ "coldfront", sp_immolation, 0 },
|
||||||
|
|
|
@ -815,42 +815,6 @@ int sp_drainodem(fighter * fi, int level, double power, spell * sp)
|
||||||
/* ------------------------------------------------------------- */
|
/* ------------------------------------------------------------- */
|
||||||
/* PRECOMBAT */
|
/* 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) {
|
static fighter *summon_allies(const fighter *fi, const race *rc, int number) {
|
||||||
attrib *a;
|
attrib *a;
|
||||||
unit *mage = fi->unit;
|
unit *mage = fi->unit;
|
||||||
|
|
|
@ -49,7 +49,6 @@ extern "C" {
|
||||||
int sp_armorshield(struct castorder * co);
|
int sp_armorshield(struct castorder * co);
|
||||||
int sp_stun(struct castorder * co);
|
int sp_stun(struct castorder * co);
|
||||||
int sp_undeadhero(struct castorder * co);
|
int sp_undeadhero(struct castorder * co);
|
||||||
int sp_shadowcall(struct castorder * co);
|
|
||||||
int sp_immolation(struct castorder * co);
|
int sp_immolation(struct castorder * co);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
|
|
@ -32,10 +32,11 @@
|
||||||
#define NOCRYPT_VERSION 352 /* passwords are plaintext again */
|
#define NOCRYPT_VERSION 352 /* passwords are plaintext again */
|
||||||
#define ATHASH_VERSION 353 /* attribute-type hash, not name */
|
#define ATHASH_VERSION 353 /* attribute-type hash, not name */
|
||||||
#define NOWATCH_VERSION 354 /* plane->watchers is gone */
|
#define NOWATCH_VERSION 354 /* plane->watchers is gone */
|
||||||
|
#define KEYVAL_VERSION 355 /* at_keys has values */
|
||||||
/* unfinished: */
|
/* unfinished: */
|
||||||
#define CRYPT_VERSION 400 /* passwords are encrypted */
|
#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 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 */
|
#define MAX_VERSION RELEASE_VERSION /* change this if we can need to read the future datafile, and we can do so */
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue