Merge remote-tracking branch 'upstream/develop' into develop

This commit is contained in:
Enno Rehling 2015-12-05 18:34:59 +01:00
commit f747b4ee05
27 changed files with 412 additions and 109 deletions

View file

@ -61,7 +61,7 @@
"desert": { "desert": {
"size": 400, "size": 400,
"seed": 2, "seed": 2,
"road": 75, "road": 100,
"flags": [ "cavalry", "land", "walk", "sail", "fly" ], "flags": [ "cavalry", "land", "walk", "sail", "fly" ],
"herbs": [ "h9", "h11" ], "herbs": [ "h9", "h11" ],
"production": { "production": {

@ -1 +1 @@
Subproject commit 934c2dd94d41da19637a76a1a8b3dfeb7aa8524d Subproject commit dfe57a077222c6b572da61a79dc0687f81c10055

View file

@ -30,5 +30,5 @@ fi
echo "backup turn $TURN, game $GAME, files: $files" echo "backup turn $TURN, game $GAME, files: $files"
tar cjf backup/$TURN.tar.bz2 $files tar cjf backup/$TURN.tar.bz2 $files
echo "uploading game-$GAME/$TURN.tar.bz2" echo "uploading game-$GAME/$TURN.tar.bz2"
curl -n -T backup/$TURN.tar.bz2 https://dav.box.com/dav/Eressea/game-$GAME/$TURN.tar.bz2 curl -s -n -T backup/$TURN.tar.bz2 https://dav.box.com/dav/Eressea/game-$GAME/$TURN.tar.bz2
curl -n -T eressea.db https://dav.box.com/dav/Eressea/eressea.db curl -s -n -T eressea.db https://dav.box.com/dav/Eressea/eressea.db

@ -1 +1 @@
Subproject commit 612a1d06b772bbd1c9b247afbda88a6aadfc5792 Subproject commit f837dd31e5fcf13c706db1ac2c86b7de3e706578

View file

@ -585,7 +585,7 @@
<!-- Schutzzauber --> <!-- Schutzzauber -->
<resource name="aura" amount="5" cost="level"/> <resource name="aura" amount="5" cost="level"/>
</spell> </spell>
<spell name="protective_runes" rank="2" index="99" parameters="kc" ship="true"> <spell name="protective_runes" rank="2" index="99" parameters="kc" regiontarget="false" unittarget="false" buildingtarget="true" shiptarget="true" ship="true">
<resource name="aura" amount="20" cost="fixed"/> <resource name="aura" amount="20" cost="fixed"/>
</spell> </spell>
<spell name="analyze_magic" rank="5" index="102" parameters="kc?" los="true" ship="true" variable="true"> <spell name="analyze_magic" rank="5" index="102" parameters="kc?" los="true" ship="true" variable="true">

View file

@ -313,7 +313,7 @@
<spell name="keeploot" rank="5" index="98" variable="true" combat="3"> <spell name="keeploot" rank="5" index="98" variable="true" combat="3">
<resource name="aura" amount="1" cost="level"/> <resource name="aura" amount="1" cost="level"/>
</spell> </spell>
<spell name="protective_runes" rank="2" index="99" parameters="kc" ship="true"> <spell name="protective_runes" rank="2" index="99" parameters="kc" regiontarget="false" unittarget="false" buildingtarget="true" shiptarget="true" ship="true">
<resource name="aura" amount="20" cost="fixed"/> <resource name="aura" amount="20" cost="fixed"/>
</spell> </spell>
<spell name="song_resist_magic" rank="2" index="100" far="true" variable="true"> <spell name="song_resist_magic" rank="2" index="100" far="true" variable="true">
@ -332,7 +332,7 @@
<resource name="aura" amount="10" cost="fixed"/> <resource name="aura" amount="10" cost="fixed"/>
</spell> </spell>
<spell name="analyse_object" rank="5" index="105" parameters="kc+" ship="true" variable="true"> <spell name="analyse_object" rank="5" index="105" parameters="kc+" ship="true" variable="true">
<resource name="aura" amount="3" cost="level"/> <resource name="aura" amount="3" cost="level" regiontarget="true" unittarget="false" buildingtarget="true" shiptarget="true"/>
</spell> </spell>
<spell name="destroy_magic" rank="2" index="106" parameters="kc+" los="true" ship="true" far="true" variable="true"> <spell name="destroy_magic" rank="2" index="106" parameters="kc+" los="true" ship="true" far="true" variable="true">
<resource name="aura" amount="4" cost="level"/> <resource name="aura" amount="4" cost="level"/>

View file

@ -7,6 +7,10 @@ function setup()
eressea.settings.set("rules.food.flags", "4") eressea.settings.set("rules.food.flags", "4")
end end
function teardown()
eressea.settings.set("rules.food.flags", "0")
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")

View file

@ -4,12 +4,17 @@ module("tests.e3.morale", package.seeall, lunit.testcase )
function setup() function setup()
eressea.game.reset() eressea.game.reset()
eressea.settings.set("rules.food.flags", "4") -- food is free
end end
function test_when_owner_returns_morale_drops_only_2() function teardown()
eressea.settings.set("rules.food.flags", "0")
end
function test_when_owner_returns_morale_stays()
local r = region.create(0, 0, "plain") local r = region.create(0, 0, "plain")
assert_equal(1, r.morale) assert_equal(1, r.morale)
local f1 = faction.create("noreply@eressea.de", "human", "de") local f1 = faction.create("owner_returns@eressea.de", "human", "de")
local u1 = unit.create(f1, r, 1) local u1 = unit.create(f1, r, 1)
u1:add_item("money", 10000) u1:add_item("money", 10000)
local b = building.create(r, "castle") local b = building.create(r, "castle")
@ -25,21 +30,21 @@ function test_when_owner_returns_morale_drops_only_2()
assert_equal(5, r.morale) -- no owner, fall by 1 assert_equal(5, r.morale) -- no owner, fall by 1
u1.building = b u1.building = b
update_owners() update_owners()
set_key("test", 42)
process_orders() process_orders()
assert_equal(3, r.morale) -- new owner, fall by 2 assert_equal(5, r.morale) -- old owner returns, no reduction
assert_false(r.is_mourning)
end end
function test_morale_alliance() function test_morale_alliance()
local r = region.create(0, 0, "plain") local r = region.create(0, 0, "plain")
assert_equal(1, r.morale) assert_equal(1, r.morale)
local f1 = faction.create("noreply@eressea.de", "human", "de") local f1 = faction.create("ma1@eressea.de", "human", "de")
local u1 = unit.create(f1, r, 1) local u1 = unit.create(f1, r, 1)
u1:add_item("money", 10000) u1:add_item("money", 10000)
local f2 = faction.create("noreply@eressea.de", "human", "de") local f2 = faction.create("ma2@eressea.de", "human", "de")
local u2 = unit.create(f2, r, 1) local u2 = unit.create(f2, r, 1)
u2:add_item("money", 10000) u2:add_item("money", 10000)
local f3 = faction.create("noreply@eressea.de", "human", "de") local f3 = faction.create("ma3@eressea.de", "human", "de")
local u3 = unit.create(f3, r, 1) local u3 = unit.create(f3, r, 1)
u3:add_item("money", 10000) u3:add_item("money", 10000)
@ -65,27 +70,68 @@ function test_morale_alliance()
-- just checking everything's okay after setup. -- just checking everything's okay after setup.
run_a_turn() run_a_turn()
assert_equal(6, r.morale) assert_equal(6, r.morale)
assert_false(r.is_mourning)
-- change owner, new owner is in the same alliance -- change owner, new owner is in the same alliance
u1.building = nil u1.building = nil
run_a_turn() run_a_turn()
assert_equal(4, r.morale) assert_equal(4, r.morale)
assert_true(r.is_mourning)
run_a_turn()
assert_false(r.is_mourning) -- mourning recovers
-- change owner, new owner is not in the same alliance -- change owner, new owner is not in the same alliance
u2.building = nil u2.building = nil
run_a_turn() run_a_turn()
assert_equal(0, r.morale) assert_equal(0, r.morale)
assert_true(r.is_mourning)
run_a_turn()
assert_false(r.is_mourning) -- mourning recovers
end
function test_bigger_castle_empty()
local r = region.create(0, 0, "plain")
assert_equal(1, r.morale)
local f1 = faction.create("small1@eressea.de", "human", "de")
local u1 = unit.create(f1, r, 1)
local f2 = faction.create("small2@eressea.de", "human", "de")
local u2 = unit.create(f2, r, 1)
u1:add_item("money", 10000)
local big = building.create(r, "castle")
big.size = 20
u1.building = big
local small = building.create(r, "castle")
small.size = 10
u2.building = small
local function run_a_turn()
process_orders()
f1.lastturn=get_turn()
end
update_owners()
assert_equal(r.owner, u1.faction)
u1.building = nil
update_owners()
assert_equal(r.owner, u2.faction)
assert_equal(0, r.morale)
assert_true(r.is_mourning)
run_a_turn()
assert_false(r.is_mourning) -- mourning recovers
end end
function test_morale_change() function test_morale_change()
local r = region.create(0, 0, "plain") local r = region.create(0, 0, "plain")
assert_equal(1, r.morale) assert_equal(1, r.morale)
local f1 = faction.create("noreply@eressea.de", "human", "de") local f1 = faction.create("mchange@eressea.de", "human", "de")
local u1 = unit.create(f1, r, 1) local u1 = unit.create(f1, r, 1)
u1:add_item("money", 10000) u1:add_item("money", 10000)
local f2 = faction.create("noreply@eressea.de", "human", "de")
local u2 = unit.create(f2, r, 1)
u2:add_item("money", 10000)
local AVG_STEP = 6 local AVG_STEP = 6
local b = building.create(r, "castle") local b = building.create(r, "castle")
@ -95,38 +141,44 @@ function test_morale_change()
local function run_a_turn() local function run_a_turn()
process_orders() process_orders()
f1.lastturn=get_turn() f1.lastturn=get_turn()
f2.lastturn=get_turn()
end end
-- reinhardt-regel: nach 2*AVG_STEP ist moral mindestens einmal gestiegen. -- reinhardt-regel: nach 2*AVG_STEP ist moral mindestens einmal gestiegen.
update_owners() update_owners()
assert_not_equal(r.owner, nil) assert_not_equal(r.owner, nil)
assert_false(r.is_mourning)
for i=1,AVG_STEP*2 do for i=1,AVG_STEP*2 do
run_a_turn() run_a_turn()
assert_not_equal(r.owner, nil) assert_not_equal(r.owner, nil)
end end
assert_not_equal(1, r.morale) assert_not_equal(1, r.morale)
assert_false(r.is_mourning)
-- regel: moral ist nie hoeher als 2 punkte ueber burgen-max. -- regel: moral ist nie hoeher als 2 punkte ueber burgen-max.
for i=1,AVG_STEP*4 do for i=1,AVG_STEP*4 do
run_a_turn() run_a_turn()
end end
assert_equal(4, r.morale) assert_equal(4, r.morale)
assert_false(r.is_mourning)
-- auch mit herrscher faellt moral um 1 pro woche, wenn moral > burgstufe -- auch mit herrscher faellt moral um 1 pro woche, wenn moral > burgstufe
r.morale = 6 r.morale = 6
run_a_turn() run_a_turn()
assert_equal(5, r.morale) assert_equal(5, r.morale)
assert_false(r.is_mourning)
run_a_turn() run_a_turn()
assert_equal(4, r.morale) assert_equal(4, r.morale)
run_a_turn() run_a_turn()
assert_equal(4, r.morale) assert_equal(4, r.morale)
-- regel: ohne herrscher fällt die moral jede woche um 1 punkt, bis sie 1 erreicht -- regel: ohne herrscher fällt die moral jede woche um 1 punkt, bis sie 1 erreicht
assert_false(r.is_mourning)
u1.building = nil u1.building = nil
update_owners() update_owners()
assert_false(r.is_mourning)
run_a_turn() run_a_turn()
assert_equal(3, r.morale) assert_equal(3, r.morale)
assert_false(r.is_mourning)
run_a_turn() run_a_turn()
assert_equal(2, r.morale) assert_equal(2, r.morale)
run_a_turn() run_a_turn()
@ -140,12 +192,12 @@ function test_morale_change()
assert_equal(0, r.morale) assert_equal(0, r.morale)
end end
function test_morale_old() function test_morale_give_command()
local r = region.create(0, 0, "plain") local r = region.create(0, 0, "plain")
assert_equal(1, r.morale) assert_equal(1, r.morale)
local f1 = faction.create("first@eressea.de", "human", "de") local f1 = faction.create("mold1@eressea.de", "human", "de")
local u1 = unit.create(f1, r, 1) local u1 = unit.create(f1, r, 1)
local f2 = faction.create("second@eressea.de", "human", "de") local f2 = faction.create("mold2@eressea.de", "human", "de")
local u2 = unit.create(f2, r, 1) local u2 = unit.create(f2, r, 1)
local b = building.create(r, "castle") local b = building.create(r, "castle")
@ -154,25 +206,20 @@ function test_morale_old()
u2.building = b u2.building = b
update_owners() update_owners()
assert_equal(1, r.morale) assert_equal(1, r.morale)
assert_false(r.is_mourning)
r.morale = 5 r.morale = 5
assert_equal(r.owner, u1.faction) assert_equal(r.owner, u1.faction)
u1:clear_orders() u1:clear_orders()
u1:add_order("GIB " .. itoa36(u2.id) .. " KOMMANDO") u1:add_order("GIB " .. itoa36(u2.id) .. " KOMMANDO")
process_orders() process_orders()
u1:clear_orders()
assert_equal(u2.faction, r.owner) assert_equal(u2.faction, r.owner)
assert_equal(3, r.morale) -- 5-MORALE_TRANSFER assert_equal(3, r.morale) -- 5 - MORALE_TRANSFER
for u in r.units do assert_true(r.is_mourning)
if u.faction.id==u2.faction.id then
u.building = nil u1:clear_orders()
end
end process_orders()
update_owners() assert_false(r.is_mourning) -- mourning recovers
assert_equal(r.owner, u1.faction)
assert_equal(0, r.morale)
end end
function test_no_uruk()
local f1 = faction.create("noreply@eressea.de", "uruk", "de")
assert_equal(f1.race, "orc")
end

View file

@ -929,7 +929,6 @@ function test_volcanooutbreak_message()
assert_not_equal("", msg:render("en")) assert_not_equal("", msg:render("en"))
end end
function test_bug2083() function test_bug2083()
local herb_multi = 500 -- from rc_herb_trade() local herb_multi = 500 -- from rc_herb_trade()
local r = region.create(0,0,"plain") local r = region.create(0,0,"plain")
@ -961,3 +960,8 @@ function test_bug2083()
assert_equal(0, u:get_item("balm")) assert_equal(0, u:get_item("balm"))
end end
function test_no_uruk()
local f1 = faction.create("noreply@eressea.de", "uruk", "de")
assert_equal(f1.race, "orc")
end

View file

@ -1175,7 +1175,7 @@ terminate(troop dt, troop at, int type, const char *damage, bool missile)
const weapon_type *dwtype = NULL; const weapon_type *dwtype = NULL;
const weapon_type *awtype = NULL; const weapon_type *awtype = NULL;
const weapon *weapon; const weapon *weapon;
double res = 0.0; double res = 1.0;
int rda, sk = 0, sd; int rda, sk = 0, sd;
bool magic = false; bool magic = false;
@ -3946,7 +3946,7 @@ static bool start_battle(region * r, battle ** bp)
continue; continue;
} }
if ((u_race(u)->battle_flags & BF_CANATTACK) == 0) { if (u_race(u)->battle_flags & BF_NO_ATTACK) {
ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "race_no_attack", ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "race_no_attack",
"race", u_race(u))); "race", u_race(u)));
continue; continue;

View file

@ -266,6 +266,7 @@ static void test_calculate_armor(CuTest * tc)
i_change(&du->items, ishield, 1); i_change(&du->items, ishield, 1);
i_change(&du->items, ichain, 1); i_change(&du->items, ichain, 1);
dt.fighter = setup_fighter(&b, du); dt.fighter = setup_fighter(&b, du);
rc->battle_flags &= ~BF_EQUIPMENT;
CuAssertIntEquals_Msg(tc, "require BF_EQUIPMENT", 1, calculate_armor(dt, 0, 0, 0)); CuAssertIntEquals_Msg(tc, "require BF_EQUIPMENT", 1, calculate_armor(dt, 0, 0, 0));
free_battle(b); free_battle(b);
@ -292,6 +293,67 @@ static void test_calculate_armor(CuTest * tc)
test_cleanup(); test_cleanup();
} }
static void test_magic_resistance(CuTest *tc)
{
troop dt;
battle *b;
region *r;
unit *du;
armor_type *ashield, *achain;
item_type *ishield, *ichain;
race *rc;
double magres = 0.0;
test_cleanup();
r = test_create_region(0, 0, 0);
ishield = it_get_or_create(rt_get_or_create("shield"));
ashield = new_armortype(ishield, 0.0, 0.5, 1, ATF_SHIELD);
ichain = it_get_or_create(rt_get_or_create("chainmail"));
achain = new_armortype(ichain, 0.0, 0.5, 3, ATF_NONE);
rc = test_create_race("human");
du = test_create_unit(test_create_faction(rc), r);
dt.index = 0;
dt.fighter = setup_fighter(&b, du);
calculate_armor(dt, 0, 0, &magres);
CuAssertDblEquals_Msg(tc, "magres unmodified", 0.0, magres, 0.01);
magres = 1.0;
calculate_armor(dt, 0, 0, &magres);
CuAssertDblEquals_Msg(tc, "no magres bonus", 0.0, magic_resistance(du), 0.01);
CuAssertDblEquals_Msg(tc, "no magres bonus", 1.0, magres, 0.01);
ashield->flags |= ATF_LAEN;
ashield->magres = 0.1;
magres = 1.0;
calculate_armor(dt, 0, 0, &magres);
free_battle(b);
i_change(&du->items, ishield, 1);
i_change(&du->items, ichain, 1);
achain->flags |= ATF_LAEN;
achain->magres = 0.1;
ashield->flags |= ATF_LAEN;
ashield->magres = 0.1;
dt.fighter = setup_fighter(&b, du);
magres = 1.0;
calculate_armor(dt, 0, 0, &magres);
CuAssertDblEquals_Msg(tc, "laen bonus", 0.81, magres, 0.01);
free_battle(b);
i_change(&du->items, ishield, -1);
i_change(&du->items, ichain, -1);
set_level(du, SK_MAGIC, 2);
dt.fighter = setup_fighter(&b, du);
magres = 1.0;
calculate_armor(dt, 0, 0, &magres);
CuAssertDblEquals_Msg(tc, "magic bonus", 0.1, magic_resistance(du), 0.01);
CuAssertDblEquals_Msg(tc, "magic bonus", 0.7, magres, 0.01);
free_battle(b);
test_cleanup();
}
static void test_projectile_armor(CuTest * tc) static void test_projectile_armor(CuTest * tc)
{ {
troop dt; troop dt;
@ -340,6 +402,7 @@ CuSuite *get_battle_suite(void)
SUITE_ADD_TEST(suite, test_building_defence_bonus); SUITE_ADD_TEST(suite, test_building_defence_bonus);
SUITE_ADD_TEST(suite, test_calculate_armor); SUITE_ADD_TEST(suite, test_calculate_armor);
SUITE_ADD_TEST(suite, test_natural_armor); SUITE_ADD_TEST(suite, test_natural_armor);
SUITE_ADD_TEST(suite, test_magic_resistance);
SUITE_ADD_TEST(suite, test_projectile_armor); SUITE_ADD_TEST(suite, test_projectile_armor);
return suite; return suite;
} }

View file

@ -210,6 +210,14 @@ static int tolua_region_set_morale(lua_State * L)
return 0; return 0;
} }
/* region mourning this turn */
static int tolua_region_get_is_mourning(lua_State * L)
{
region *r = (region *)tolua_tousertype(L, 1, 0);
lua_pushboolean(L, is_mourning(r, turn+1));
return 1;
}
static int tolua_region_get_adj(lua_State * L) static int tolua_region_get_adj(lua_State * L)
{ {
region *r = (region *)tolua_tousertype(L, 1, 0); region *r = (region *)tolua_tousertype(L, 1, 0);
@ -691,6 +699,7 @@ void tolua_region_open(lua_State * L)
tolua_region_set_name); tolua_region_set_name);
tolua_variable(L, TOLUA_CAST "morale", tolua_region_get_morale, tolua_variable(L, TOLUA_CAST "morale", tolua_region_get_morale,
tolua_region_set_morale); tolua_region_set_morale);
tolua_variable(L, TOLUA_CAST "is_mourning", tolua_region_get_is_mourning, NULL);
tolua_variable(L, TOLUA_CAST "info", tolua_region_get_info, tolua_variable(L, TOLUA_CAST "info", tolua_region_get_info,
tolua_region_set_info); tolua_region_set_info);
tolua_variable(L, TOLUA_CAST "units", tolua_region_get_units, NULL); tolua_variable(L, TOLUA_CAST "units", tolua_region_get_units, NULL);

View file

@ -183,7 +183,7 @@ race *rc_get_or_create(const char *zName)
rc->recruit_multi = 1.0F; rc->recruit_multi = 1.0F;
rc->regaura = 1.0F; rc->regaura = 1.0F;
rc->speed = 1.0F; rc->speed = 1.0F;
rc->battle_flags = BF_CANATTACK; rc->battle_flags = 0;
if (strchr(zName, ' ') != NULL) { if (strchr(zName, ' ') != NULL) {
log_error("race '%s' has an invalid name. remove spaces\n", zName); log_error("race '%s' has an invalid name. remove spaces\n", zName);
assert(strchr(zName, ' ') == NULL); assert(strchr(zName, ' ') == NULL);

View file

@ -232,7 +232,7 @@ extern "C" {
#define BF_RES_CUT (1<<3) /* Halber Schaden durch CUT */ #define BF_RES_CUT (1<<3) /* Halber Schaden durch CUT */
#define BF_RES_BASH (1<<4) /* Halber Schaden durch BASH */ #define BF_RES_BASH (1<<4) /* Halber Schaden durch BASH */
#define BF_INV_NONMAGIC (1<<5) /* Immun gegen nichtmagischen Schaden */ #define BF_INV_NONMAGIC (1<<5) /* Immun gegen nichtmagischen Schaden */
#define BF_CANATTACK (1<<6) /* Kann keine ATTACKIERE Befehle ausfuehren */ #define BF_NO_ATTACK (1<<6) /* Kann keine ATTACKIERE Befehle ausfuehren */
int unit_old_max_hp(struct unit *u); int unit_old_max_hp(struct unit *u);
const char *racename(const struct locale *lang, const struct unit *u, const char *racename(const struct locale *lang, const struct unit *u,

View file

@ -36,6 +36,7 @@ static void test_rc_defaults(CuTest *tc) {
CuAssertIntEquals(tc, 0, rc->armor); CuAssertIntEquals(tc, 0, rc->armor);
CuAssertIntEquals(tc, 0, rc->at_bonus); CuAssertIntEquals(tc, 0, rc->at_bonus);
CuAssertIntEquals(tc, 0, rc->df_bonus); CuAssertIntEquals(tc, 0, rc->df_bonus);
CuAssertIntEquals(tc, 0, rc->battle_flags);
CuAssertIntEquals(tc, PERSON_WEIGHT, rc->weight); CuAssertIntEquals(tc, PERSON_WEIGHT, rc->weight);
test_cleanup(); test_cleanup();
} }

View file

@ -1261,12 +1261,21 @@ struct faction *region_get_owner(const struct region *r)
return NULL; return NULL;
} }
struct faction *region_get_last_owner(const struct region *r)
{
assert(rule_region_owners());
if (r->land && r->land->ownership) {
return r->land->ownership->last_owner;
}
return NULL;
}
struct alliance *region_get_alliance(const struct region *r) struct alliance *region_get_alliance(const struct region *r)
{ {
assert(rule_region_owners()); assert(rule_region_owners());
if (r->land && r->land->ownership) { if (r->land && r->land->ownership) {
region_owner *own = r->land->ownership; region_owner *own = r->land->ownership;
return own->owner ? own->owner->alliance : own->alliance; return own->owner ? own->owner->alliance : (own->last_owner? own->last_owner->alliance : NULL);
} }
return NULL; return NULL;
} }
@ -1279,16 +1288,14 @@ void region_set_owner(struct region *r, struct faction *owner, int turn)
r->land->ownership = malloc(sizeof(region_owner)); r->land->ownership = malloc(sizeof(region_owner));
assert(region_get_morale(r) == MORALE_DEFAULT); assert(region_get_morale(r) == MORALE_DEFAULT);
r->land->ownership->owner = NULL; r->land->ownership->owner = NULL;
r->land->ownership->alliance = NULL; r->land->ownership->last_owner = NULL;
r->land->ownership->flags = 0; r->land->ownership->flags = 0;
} }
r->land->ownership->since_turn = turn; r->land->ownership->since_turn = turn;
r->land->ownership->morale_turn = turn; r->land->ownership->morale_turn = turn;
assert(r->land->ownership->owner != owner); assert(r->land->ownership->owner != owner);
r->land->ownership->last_owner = r->land->ownership->owner;
r->land->ownership->owner = owner; r->land->ownership->owner = owner;
if (owner) {
r->land->ownership->alliance = owner->alliance;
}
} }
} }
@ -1302,40 +1309,35 @@ faction *update_owners(region * r)
if (blargest) { if (blargest) {
if (!bowner || bowner->size < blargest->size) { if (!bowner || bowner->size < blargest->size) {
/* region owners update? */ /* region owners update? */
unit *u = building_owner(blargest); unit *new_owner = building_owner(blargest);
f = region_get_owner(r); f = region_get_owner(r);
if (u == NULL) { if (new_owner == NULL) {
if (f) { if (f) {
region_set_owner(r, NULL, turn); region_set_owner(r, NULL, turn);
r->land->ownership->flags |= OWNER_MOURNING;
f = NULL; f = NULL;
} }
} }
else if (u->faction != f) { else if (new_owner->faction != f) {
if (!r->land->ownership) { if (!r->land->ownership) {
/* there has never been a prior owner */ /* there has never been a prior owner */
region_set_morale(r, MORALE_DEFAULT, turn); region_set_morale(r, MORALE_DEFAULT, turn);
} }
else { else if (f || new_owner->faction != region_get_last_owner(r)) {
alliance *al = region_get_alliance(r); alliance *al = region_get_alliance(r);
if (al && u->faction->alliance == al) { if (al && new_owner->faction->alliance == al) {
int morale = _max(0, r->land->morale - MORALE_TRANSFER); int morale = _max(0, r->land->morale - MORALE_TRANSFER);
region_set_morale(r, morale, turn); region_set_morale(r, morale, turn);
} }
else { else {
region_set_morale(r, MORALE_TAKEOVER, turn); region_set_morale(r, MORALE_TAKEOVER, turn);
if (f) {
r->land->ownership->flags |= OWNER_MOURNING;
}
} }
} }
region_set_owner(r, u->faction, turn); region_set_owner(r, new_owner->faction, turn);
f = u->faction; f = new_owner->faction;
} }
} }
} }
else if (r->land->ownership && r->land->ownership->owner) { else if (r->land->ownership && r->land->ownership->owner) {
r->land->ownership->flags |= OWNER_MOURNING;
region_set_owner(r, NULL, turn); region_set_owner(r, NULL, turn);
f = NULL; f = NULL;
} }
@ -1409,6 +1411,6 @@ int owner_change(const region * r)
bool is_mourning(const region * r, int in_turn) bool is_mourning(const region * r, int in_turn)
{ {
int change = owner_change(r); int change = owner_change(r);
return (change == in_turn - 1 return (change == in_turn - 1 && r->land->ownership->last_owner && r->land->ownership->owner
&& (r->land->ownership->flags & OWNER_MOURNING)); && r->land->ownership->last_owner != r->land->ownership->owner);
} }

View file

@ -75,10 +75,9 @@ extern "C" {
#define MORALE_AVERAGE 6 /* default average time for morale to change */ #define MORALE_AVERAGE 6 /* default average time for morale to change */
#define MORALE_TRANSFER 2 /* points of morale lost when GIVE COMMAND */ #define MORALE_TRANSFER 2 /* points of morale lost when GIVE COMMAND */
#define OWNER_MOURNING 0x01
typedef struct region_owner { typedef struct region_owner {
struct faction *owner; struct faction *owner;
struct alliance *alliance; struct faction *last_owner;
int since_turn; /* turn the region changed owners */ int since_turn; /* turn the region changed owners */
int morale_turn; /* turn when morale has changed most recently */ int morale_turn; /* turn when morale has changed most recently */
int flags; int flags;

View file

@ -490,9 +490,6 @@ static int resolve_owner(variant id, void *address)
} }
} }
owner->owner = f; owner->owner = f;
if (f) {
owner->alliance = f->alliance;
}
return result; return result;
} }
@ -511,13 +508,20 @@ static void read_owner(struct gamedata *data, region_owner ** powner)
else { else {
owner->flags = 0; owner->flags = 0;
} }
if (data->version >= OWNER_2_VERSION) { if (data->version >= OWNER_3_VERSION) {
int id; int id;
READ_INT(data->store, &id); READ_INT(data->store, &id);
owner->alliance = id ? findalliance(id) : NULL; owner->last_owner = id ? findfaction(id) : NULL;
} else if (data->version >= OWNER_2_VERSION) {
int id;
alliance *a;
READ_INT(data->store, &id);
a = id ? findalliance(id) : NULL;
/* don't know which faction, take the leader */
owner->last_owner = a? a->_leader : NULL;
} }
else { else {
owner->alliance = NULL; owner->last_owner = NULL;
} }
read_reference(owner, data->store, &read_faction_reference, &resolve_owner); read_reference(owner, data->store, &read_faction_reference, &resolve_owner);
*powner = owner; *powner = owner;
@ -533,7 +537,7 @@ static void write_owner(struct gamedata *data, region_owner * owner)
WRITE_INT(data->store, owner->since_turn); WRITE_INT(data->store, owner->since_turn);
WRITE_INT(data->store, owner->morale_turn); WRITE_INT(data->store, owner->morale_turn);
WRITE_INT(data->store, owner->flags); WRITE_INT(data->store, owner->flags);
WRITE_INT(data->store, owner->alliance ? owner->alliance->id : 0); write_faction_reference(owner->last_owner, data->store);
write_faction_reference(owner->owner, data->store); write_faction_reference(owner->owner, data->store);
} }
else { else {

View file

@ -8,7 +8,7 @@
#include <stdlib.h> #include <stdlib.h>
static void test_create_spell(CuTest * tc) static void test_create_a_spell(CuTest * tc)
{ {
spell * sp; spell * sp;
@ -48,7 +48,7 @@ static void test_create_spell_with_id(CuTest * tc)
CuSuite *get_spell_suite(void) CuSuite *get_spell_suite(void)
{ {
CuSuite *suite = CuSuiteNew(); CuSuite *suite = CuSuiteNew();
SUITE_ADD_TEST(suite, test_create_spell); SUITE_ADD_TEST(suite, test_create_a_spell);
SUITE_ADD_TEST(suite, test_create_duplicate_spell); SUITE_ADD_TEST(suite, test_create_duplicate_spell);
SUITE_ADD_TEST(suite, test_create_spell_with_id); SUITE_ADD_TEST(suite, test_create_spell_with_id);
return suite; return suite;

View file

@ -31,8 +31,9 @@
#define JSON_REPORT_VERSION 346 /* bit 3 in f->options flags the json report */ #define JSON_REPORT_VERSION 346 /* bit 3 in f->options flags the json report */
#define EXPLICIT_CURSE_ISNEW_VERSION 347 /* CURSE_ISNEW is not reset in read/write, but in age() */ #define EXPLICIT_CURSE_ISNEW_VERSION 347 /* CURSE_ISNEW is not reset in read/write, but in age() */
#define SPELL_LEVEL_VERSION 348 /* f->max_spelllevel gets stored, not calculated */ #define SPELL_LEVEL_VERSION 348 /* f->max_spelllevel gets stored, not calculated */
#define OWNER_3_VERSION 349 /* regions store last owner, not last alliance */
#define RELEASE_VERSION SPELL_LEVEL_VERSION /* current datafile */ #define RELEASE_VERSION OWNER_3_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 */

View file

@ -1484,6 +1484,16 @@ static int parse_spells(xmlDocPtr doc)
sp->sptyp |= FARCASTING; sp->sptyp |= FARCASTING;
if (xml_bvalue(node, "variable", false)) if (xml_bvalue(node, "variable", false))
sp->sptyp |= SPELLLEVEL; sp->sptyp |= SPELLLEVEL;
if (xml_bvalue(node, "buildingtarget", false))
sp->sptyp |= BUILDINGSPELL;
if (xml_bvalue(node, "shiptarget", false))
sp->sptyp |= SHIPSPELL;
if (xml_bvalue(node, "unittarget", false))
sp->sptyp |= UNITSPELL;
if (xml_bvalue(node, "regiontarget", false))
sp->sptyp |= REGIONSPELL;
k = xml_ivalue(node, "combat", 0); k = xml_ivalue(node, "combat", 0);
if (k >= 0 && k <= 3) if (k >= 0 && k <= 3)
sp->sptyp |= modes[k]; sp->sptyp |= modes[k];
@ -1723,7 +1733,7 @@ static int parse_races(xmlDocPtr doc)
rc->ec_flags |= ECF_REC_UNLIMITED; rc->ec_flags |= ECF_REC_UNLIMITED;
if (xml_bvalue(node, "equipment", false)) if (xml_bvalue(node, "equipment", false))
rc->battle_flags |= BF_EQUIPMENT; rc->battle_flags |= BF_EQUIPMENT; // TODO: invert this flag, so rc_get_or_create gets simpler
if (xml_bvalue(node, "noblock", false)) if (xml_bvalue(node, "noblock", false))
rc->battle_flags |= BF_NOBLOCK; rc->battle_flags |= BF_NOBLOCK;
if (xml_bvalue(node, "invinciblenonmagic", false)) if (xml_bvalue(node, "invinciblenonmagic", false))
@ -1734,8 +1744,8 @@ static int parse_races(xmlDocPtr doc)
rc->battle_flags |= BF_RES_CUT; rc->battle_flags |= BF_RES_CUT;
if (xml_bvalue(node, "resistpierce", false)) if (xml_bvalue(node, "resistpierce", false))
rc->battle_flags |= BF_RES_PIERCE; rc->battle_flags |= BF_RES_PIERCE;
if (xml_bvalue(node, "canattack", true)) if (xml_bvalue(node, "noattack", false))
rc->battle_flags |= BF_CANATTACK; // TODO: invert this flag, so rc_get_or_create gets simpler rc->battle_flags |= BF_NO_ATTACK;
for (child = node->children; child; child = child->next) { for (child = node->children; child; child = child->next) {
if (strcmp((const char *)child->name, "ai") == 0) { if (strcmp((const char *)child->name, "ai") == 0) {

View file

@ -74,24 +74,6 @@ void test_spellbooks(CuTest * tc)
test_cleanup(); test_cleanup();
} }
static spell * test_magic_create_spell(void)
{
spell *sp;
sp = create_spell("testspell", 0);
sp->components = (spell_component *)calloc(4, sizeof(spell_component));
sp->components[0].amount = 1;
sp->components[0].type = get_resourcetype(R_SILVER);
sp->components[0].cost = SPC_FIX;
sp->components[1].amount = 1;
sp->components[1].type = get_resourcetype(R_AURA);
sp->components[1].cost = SPC_LEVEL;
sp->components[2].amount = 1;
sp->components[2].type = get_resourcetype(R_HORSE);
sp->components[2].cost = SPC_LINEAR;
return sp;
}
void test_pay_spell(CuTest * tc) void test_pay_spell(CuTest * tc)
{ {
spell *sp; spell *sp;
@ -107,7 +89,7 @@ void test_pay_spell(CuTest * tc)
u = test_create_unit(f, r); u = test_create_unit(f, r);
CuAssertPtrNotNull(tc, u); CuAssertPtrNotNull(tc, u);
sp = test_magic_create_spell(); sp = test_create_spell();
CuAssertPtrNotNull(tc, sp); CuAssertPtrNotNull(tc, sp);
set_level(u, SK_MAGIC, 5); set_level(u, SK_MAGIC, 5);
@ -141,7 +123,7 @@ void test_pay_spell_failure(CuTest * tc)
u = test_create_unit(f, r); u = test_create_unit(f, r);
CuAssertPtrNotNull(tc, u); CuAssertPtrNotNull(tc, u);
sp = test_magic_create_spell(); sp = test_create_spell();
CuAssertPtrNotNull(tc, sp); CuAssertPtrNotNull(tc, sp);
set_level(u, SK_MAGIC, 5); set_level(u, SK_MAGIC, 5);

View file

@ -248,14 +248,15 @@ static size_t write_spell_modifier(spell * sp, int flag, const char * str, bool
return 0; return 0;
} }
static void nr_spell(stream *out, spellbook_entry * sbe, const struct locale *lang) void nr_spell_syntax(struct stream *out, struct spellbook_entry * sbe, const struct locale *lang);
void nr_spell(stream *out, spellbook_entry * sbe, const struct locale *lang)
{ {
int bytes, k, itemanz, costtyp; int bytes, k, itemanz, costtyp;
char buf[4096]; char buf[4096];
char *startp, *bufp = buf; char *startp, *bufp = buf;
size_t size = sizeof(buf) - 1; size_t size = sizeof(buf) - 1;
spell * sp = sbe->sp; spell * sp = sbe->sp;
const char *params = sp->parameter;
newline(out); newline(out);
centre(out, spell_name(sp, lang), true); centre(out, spell_name(sp, lang), true);
@ -305,7 +306,7 @@ static void nr_spell(stream *out, spellbook_entry * sbe, const struct locale *la
if (sp->sptyp & SPELLLEVEL) { if (sp->sptyp & SPELLLEVEL) {
bytes = bytes =
_snprintf(bufp, size, " %d %s", itemanz, LOC(lang, resourcename(rtype, _snprintf(bufp, size, " %d %s", itemanz, LOC(lang, resourcename(rtype,
itemanz != 1))); itemanz != 1)));
if (wrptr(&bufp, &size, bytes) != 0) if (wrptr(&bufp, &size, bytes) != 0)
WARN_STATIC_BUFFER(); WARN_STATIC_BUFFER();
if (costtyp == SPC_LEVEL || costtyp == SPC_LINEAR) { if (costtyp == SPC_LEVEL || costtyp == SPC_LINEAR) {
@ -361,6 +362,20 @@ static void nr_spell(stream *out, spellbook_entry * sbe, const struct locale *la
bufp = buf; bufp = buf;
size = sizeof(buf) - 1; size = sizeof(buf) - 1;
nr_spell_syntax(out, sbe, lang);
newline(out);
}
void nr_spell_syntax(stream *out, spellbook_entry * sbe, const struct locale *lang)
{
int bytes;
char buf[4096];
char *bufp = buf;
size_t size = sizeof(buf) - 1;
spell * sp = sbe->sp;
const char *params = sp->parameter;
if (sp->sptyp & ISCOMBATSPELL) { if (sp->sptyp & ISCOMBATSPELL) {
bytes = (int)strlcpy(bufp, LOC(lang, keyword(K_COMBATSPELL)), size); bytes = (int)strlcpy(bufp, LOC(lang, keyword(K_COMBATSPELL)), size);
} }
@ -456,34 +471,38 @@ static void nr_spell(stream *out, spellbook_entry * sbe, const struct locale *la
WARN_STATIC_BUFFER(); WARN_STATIC_BUFFER();
} }
else if (cp == 'k') { else if (cp == 'k') {
if (*params == 'c') { bool multi = false;
if (params && *params == 'c') {
/* skip over a potential id */ /* skip over a potential id */
++params; ++params;
} }
if (params && *params == '+') {
++params;
multi = true;
}
for (targetp = targets; targetp->flag; ++targetp) { for (targetp = targets; targetp->flag; ++targetp) {
if (sp->sptyp & targetp->flag) if (sp->sptyp & targetp->flag)
++maxparam; ++maxparam;
} }
if (maxparam > 1) { if (!maxparam || maxparam > 1) {
bytes = (int)strlcpy(bufp, " (", size); bytes = (int)strlcpy(bufp, " (", size);
if (wrptr(&bufp, &size, bytes) != 0) if (wrptr(&bufp, &size, bytes) != 0)
WARN_STATIC_BUFFER(); WARN_STATIC_BUFFER();
} }
i = 0; i = 0;
for (targetp = targets; targetp->flag; ++targetp) { for (targetp = targets; targetp->flag; ++targetp) {
if (sp->sptyp & targetp->flag) { if (!maxparam || sp->sptyp & targetp->flag) {
if (i++ != 0) { if (i++ != 0) {
bytes = (int)strlcpy(bufp, " |", size); bytes = (int)strlcpy(bufp, " |", size);
if (wrptr(&bufp, &size, bytes) != 0) if (wrptr(&bufp, &size, bytes) != 0)
WARN_STATIC_BUFFER(); WARN_STATIC_BUFFER();
} }
if (targetp->param) { if (targetp->param && targetp->vars) {
locp = LOC(lang, targetp->vars); locp = LOC(lang, targetp->vars);
bytes = bytes =
(int)_snprintf(bufp, size, " %s <%s>", parameters[targetp->param], (int)_snprintf(bufp, size, " %s <%s>", parameters[targetp->param],
locp); locp);
if (*params == '+') { if (multi) {
++params;
if (wrptr(&bufp, &size, bytes) != 0) if (wrptr(&bufp, &size, bytes) != 0)
WARN_STATIC_BUFFER(); WARN_STATIC_BUFFER();
bytes = (int)_snprintf(bufp, size, " [<%s> ...]", locp); bytes = (int)_snprintf(bufp, size, " [<%s> ...]", locp);
@ -497,7 +516,7 @@ static void nr_spell(stream *out, spellbook_entry * sbe, const struct locale *la
WARN_STATIC_BUFFER(); WARN_STATIC_BUFFER();
} }
} }
if (maxparam > 1) { if (!maxparam || maxparam > 1) {
bytes = (int)strlcpy(bufp, " )", size); bytes = (int)strlcpy(bufp, " )", size);
if (wrptr(&bufp, &size, bytes) != 0) if (wrptr(&bufp, &size, bytes) != 0)
WARN_STATIC_BUFFER(); WARN_STATIC_BUFFER();
@ -520,11 +539,13 @@ static void nr_spell(stream *out, spellbook_entry * sbe, const struct locale *la
bytes = (int)_snprintf(bufp, size, " <%s>", locp); bytes = (int)_snprintf(bufp, size, " <%s>", locp);
if (wrptr(&bufp, &size, bytes) != 0) if (wrptr(&bufp, &size, bytes) != 0)
WARN_STATIC_BUFFER(); WARN_STATIC_BUFFER();
} else {
log_error("unknown spell parameter %c for spell", cp, sp->sname);
} }
} }
*bufp = 0; *bufp = 0;
paragraph(out, buf, 2, 0, 0); paragraph(out, buf, 2, 0, 0);
newline(out);
} }
static void static void

View file

@ -20,12 +20,17 @@ extern "C" {
#endif #endif
struct stream; struct stream;
struct spellbook_entry;
struct region; struct region;
struct faction; struct faction;
void register_nr(void); void register_nr(void);
void report_cleanup(void); void report_cleanup(void);
void write_spaces(struct stream *out, size_t num); void write_spaces(struct stream *out, size_t num);
void write_travelthru(struct stream *out, const struct region * r, const struct faction * f); void write_travelthru(struct stream *out, const struct region * r, const struct faction * f);
void nr_spell_syntax(struct stream *out, struct spellbook_entry * sbe, const struct locale *lang);
void nr_spell(struct stream *out, struct spellbook_entry * sbe, const struct locale *lang);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

View file

@ -6,6 +6,7 @@
#include "move.h" #include "move.h"
#include "seen.h" #include "seen.h"
#include "travelthru.h" #include "travelthru.h"
#include "keyword.h"
#include <kernel/building.h> #include <kernel/building.h>
#include <kernel/faction.h> #include <kernel/faction.h>
@ -13,6 +14,8 @@
#include <kernel/region.h> #include <kernel/region.h>
#include <kernel/ship.h> #include <kernel/ship.h>
#include <kernel/unit.h> #include <kernel/unit.h>
#include <kernel/spell.h>
#include <kernel/spellbook.h>
#include <util/language.h> #include <util/language.h>
@ -284,6 +287,130 @@ static void test_write_unit(CuTest *tc) {
test_cleanup(); test_cleanup();
} }
typedef struct {
struct locale *lang;
spell *sp;
spellbook *spb;
spellbook_entry * sbe;
} spell_fixture;
static void setup_spell_fixture(spell_fixture * spf) {
spf->lang = get_or_create_locale("de");
locale_setstring(spf->lang, mkname("spell", "testspell"), "Testzauber");
locale_setstring(spf->lang, "nr_spell_type", "Typ:");
locale_setstring(spf->lang, "sptype_normal", "Normal");
locale_setstring(spf->lang, "nr_spell_modifiers", "Modifier:");
locale_setstring(spf->lang, "smod_none", "Keine");
locale_setstring(spf->lang, keyword(K_CAST), "ZAUBERE");
locale_setstring(spf->lang, parameters[P_REGION], "REGION");
locale_setstring(spf->lang, parameters[P_LEVEL], "STUFE");
locale_setstring(spf->lang, "par_unit", "enr");
locale_setstring(spf->lang, "par_ship", "snr");
locale_setstring(spf->lang, "par_building", "bnr");
locale_setstring(spf->lang, "spellpar::hodor", "Hodor");
spf->spb = create_spellbook("testbook");
spf->sp = test_create_spell();
spellbook_add(spf->spb, spf->sp, 1);
spf->sbe = spellbook_get(spf->spb, spf->sp);
}
static void test_spell_syntax(CuTest *tc, char *msg, spell_fixture *spell, char *syntax) {
stream strm;
char buf[1024];
char *linestart, *newline;
size_t len;
mstream_init(&strm);
nr_spell_syntax(&strm, spell->sbe, spell->lang);
strm.api->rewind(strm.handle);
len = strm.api->read(strm.handle, buf, sizeof(buf));
buf[len] = '\0';
linestart = strtok(buf, "\n");
while (linestart && !strstr(linestart, "ZAUBERE"))
linestart = strtok(NULL, "\n") ;
CuAssertTrue(tc, (bool) linestart);
while ((newline = strtok(NULL, "\n")))
*(newline-1) = '\n';
CuAssertStrEquals_Msg(tc, msg, syntax, linestart);
mstream_done(&strm);
}
static void set_parameter(spell_fixture spell, char *value) {
free(spell.sp->parameter);
spell.sp->parameter = _strdup(value);
}
static void test_write_spell_syntax(CuTest *tc) {
spell_fixture spell;
test_cleanup();
setup_spell_fixture(&spell);
test_spell_syntax(tc, "vanilla", &spell, " ZAUBERE \"Testzauber\"");
spell.sp->sptyp |= FARCASTING;
test_spell_syntax(tc, "far", &spell, " ZAUBERE [REGION x y] \"Testzauber\"");
spell.sp->sptyp |= SPELLLEVEL;
test_spell_syntax(tc, "farlevel", &spell, " ZAUBERE [REGION x y] [STUFE n] \"Testzauber\"");
spell.sp->sptyp = 0;
set_parameter(spell, "kc");
test_spell_syntax(tc, "kc", &spell, " ZAUBERE \"Testzauber\" ( REGION | EINHEIT <enr> | SCHIFF <snr> | BURG <bnr> )");
spell.sp->sptyp |= BUILDINGSPELL;
test_spell_syntax(tc, "kc typed", &spell, " ZAUBERE \"Testzauber\" BURG <bnr>");
spell.sp->sptyp = 0;
set_parameter(spell, "b");
test_spell_syntax(tc, "b", &spell, " ZAUBERE \"Testzauber\" <bnr>");
set_parameter(spell, "s");
test_spell_syntax(tc, "s", &spell, " ZAUBERE \"Testzauber\" <snr>");
set_parameter(spell, "s+");
test_spell_syntax(tc, "s+", &spell, " ZAUBERE \"Testzauber\" <snr> [<snr> ...]");
set_parameter(spell, "u");
test_spell_syntax(tc, "u", &spell, " ZAUBERE \"Testzauber\" <enr>");
set_parameter(spell, "r");
test_spell_syntax(tc, "r", &spell, " ZAUBERE \"Testzauber\" <x> <y>");
set_parameter(spell, "bc");
free(spell.sp->syntax);
spell.sp->syntax = _strdup("hodor");
test_spell_syntax(tc, "bc hodor", &spell, " ZAUBERE \"Testzauber\" <bnr> <Hodor>");
free(spell.sp->syntax);
spell.sp->syntax = 0;
/* There are no spells with optional parameters, so we don't force this, for now
set_parameter(spell, "c?");
free(spell.sp->syntax);
spell.sp->syntax = _strdup("hodor");
test_spell_syntax(tc, "c?", &spell, " ZAUBERE \"Testzauber\" [<Hodor>]");
free(spell.sp->syntax);
spell.sp->syntax = 0;
*/
set_parameter(spell, "kc+");
test_spell_syntax(tc, "kc+", &spell,
" ZAUBERE \"Testzauber\" ( REGION | EINHEIT <enr> [<enr> ...] | SCHIFF <snr>\n [<snr> ...] | BURG <bnr> [<bnr> ...] )");
test_cleanup();
}
CuSuite *get_reports_suite(void) CuSuite *get_reports_suite(void)
{ {
CuSuite *suite = CuSuiteNew(); CuSuite *suite = CuSuiteNew();
@ -296,5 +423,6 @@ CuSuite *get_reports_suite(void)
SUITE_ADD_TEST(suite, test_sparagraph); SUITE_ADD_TEST(suite, test_sparagraph);
SUITE_ADD_TEST(suite, test_write_travelthru); SUITE_ADD_TEST(suite, test_write_travelthru);
SUITE_ADD_TEST(suite, test_write_unit); SUITE_ADD_TEST(suite, test_write_unit);
SUITE_ADD_TEST(suite, test_write_spell_syntax);
return suite; return suite;
} }

View file

@ -38,6 +38,7 @@ struct race *test_create_race(const char *name)
rc->hitpoints = 20; rc->hitpoints = 20;
rc->maxaura = 1.0; rc->maxaura = 1.0;
rc->ec_flags |= GETITEM; rc->ec_flags |= GETITEM;
rc->battle_flags = BF_EQUIPMENT;
return rc; return rc;
} }
@ -196,6 +197,26 @@ void test_create_castorder(castorder *co, unit *u, int level, float force, int r
free_order(ord); free_order(ord);
} }
spell * test_create_spell(void)
{
spell *sp;
sp = create_spell("testspell", 0);
sp->components = (spell_component *)calloc(4, sizeof(spell_component));
sp->components[0].amount = 1;
sp->components[0].type = get_resourcetype(R_SILVER);
sp->components[0].cost = SPC_FIX;
sp->components[1].amount = 1;
sp->components[1].type = get_resourcetype(R_AURA);
sp->components[1].cost = SPC_LEVEL;
sp->components[2].amount = 1;
sp->components[2].type = get_resourcetype(R_HORSE);
sp->components[2].cost = SPC_LINEAR;
sp->syntax = 0;
sp->parameter = 0;
return sp;
}
void test_translate_param(const struct locale *lang, param_t param, const char *text) { void test_translate_param(const struct locale *lang, param_t param, const char *text) {
struct critbit_tree **cb; struct critbit_tree **cb;

View file

@ -24,6 +24,7 @@ extern "C" {
struct terrain_type; struct terrain_type;
struct castorder; struct castorder;
struct spellparameter; struct spellparameter;
struct spell;
struct CuTest; struct CuTest;
@ -43,6 +44,7 @@ extern "C" {
struct ship_type *test_create_shiptype(const char * name); struct ship_type *test_create_shiptype(const char * name);
struct building_type *test_create_buildingtype(const char *name); struct building_type *test_create_buildingtype(const char *name);
void test_create_castorder(struct castorder *co, struct unit *u, int level, float force, int range, struct spellparameter *par); void test_create_castorder(struct castorder *co, struct unit *u, int level, float force, int range, struct spellparameter *par);
struct spell * test_create_spell(void);
int RunAllTests(void); int RunAllTests(void);
void test_translate_param(const struct locale *lang, param_t param, const char *text); void test_translate_param(const struct locale *lang, param_t param, const char *text);