forked from github/server
commit
17356ad0a9
|
@ -8,7 +8,7 @@
|
|||
<modifier building="smithy" type="save" value="2"/>
|
||||
<modifier building="mine" type="skill" value="1"/>
|
||||
<modifier building="mine" type="material" value="0.5"/>
|
||||
<modifier race="dwarf" type="material" value="0.6"/>
|
||||
<modifier races="dwarf" type="material" value="0.6"/>
|
||||
</resource>
|
||||
</resources>
|
||||
</eressea>
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
</item>
|
||||
<modifier building="quarry" type="skill" value="1"/>
|
||||
<modifier building="quarry" type="material" value="0.5"/>
|
||||
<modifier race="troll" type="material" value="0.75"/>
|
||||
<modifier races="troll" type="material" value="0.75"/>
|
||||
</resource>
|
||||
</resources>
|
||||
</eressea>
|
||||
|
|
|
@ -1,7 +0,0 @@
|
|||
<?xml version="1.0" ?>
|
||||
<spellbook name="cerddor">
|
||||
<entry spell="create_roi" level="6" />
|
||||
<entry spell="earn_silver#cerddor" level="1" />
|
||||
<entry spell="create_aots" level="6" />
|
||||
<entry spell="create_roqf" level="11" />
|
||||
</spellbook>
|
|
@ -1,8 +0,0 @@
|
|||
<?xml version="1.0" ?>
|
||||
<spellbook name="draig">
|
||||
<entry spell="create_roi" level="6" />
|
||||
<entry spell="earn_silver#draig" level="1" />
|
||||
<entry spell="create_aots" level="6" />
|
||||
<entry spell="create_firesword" level="12" />
|
||||
<entry spell="create_trollbelt" level="9" />
|
||||
</spellbook>
|
|
@ -1,7 +0,0 @@
|
|||
<?xml version="1.0" ?>
|
||||
<spellbook name="gray">
|
||||
<entry spell="create_runesword" level="6" />
|
||||
<entry spell="create_chastitybelt" level="7" />
|
||||
<entry spell="create_focus" level="9" />
|
||||
<entry spell="create_ror" level="9" />
|
||||
</spellbook>
|
|
@ -1,7 +0,0 @@
|
|||
<?xml version="1.0" ?>
|
||||
<spellbook name="gwyrrd">
|
||||
<entry spell="create_roi" level="6" />
|
||||
<entry spell="earn_silver#gwyrrd" level="1" />
|
||||
<entry spell="create_aots" level="6" />
|
||||
<entry spell="create_magicherbbag" level="5" />
|
||||
</spellbook>
|
|
@ -1,8 +0,0 @@
|
|||
<?xml version="1.0" ?>
|
||||
<spellbook name="illaun">
|
||||
<entry spell="create_roi" level="6" />
|
||||
<entry spell="earn_silver#illaun" level="1" />
|
||||
<entry spell="create_aots" level="6" />
|
||||
<entry spell="create_dreameye" level="14" />
|
||||
<entry spell="create_invisibility_sphere" level="13" />
|
||||
</spellbook>
|
|
@ -1,9 +0,0 @@
|
|||
<?xml version="1.0" ?>
|
||||
<spellbook name="tybied">
|
||||
<entry spell="create_roi" level="6" />
|
||||
<entry spell="earn_silver#tybied" level="1" />
|
||||
<entry spell="create_aots" level="6" />
|
||||
<entry spell="create_antimagic" level="7" />
|
||||
<entry spell="create_rop" level="9" />
|
||||
<entry spell="create_bagofholding" level="10" />
|
||||
</spellbook>
|
|
@ -2,7 +2,7 @@
|
|||
<eressea>
|
||||
<resources>
|
||||
<resource name="greatbow">
|
||||
<modifier type="require" race="elf"/>
|
||||
<modifier type="require" races="elf"/>
|
||||
<item weight="100">
|
||||
<construction skill="weaponsmithing" minskill="5">
|
||||
<requirement type="mallorn" quantity="2"/>
|
||||
|
@ -11,9 +11,7 @@
|
|||
<damage type="rider" value="2d6+4"/>
|
||||
<damage type="footman" value="2d6+4"/>
|
||||
<modifier type="missile_target" value="2"/>
|
||||
<modifier type="damage" value="1">
|
||||
<race name="elf"/>
|
||||
</modifier>
|
||||
<modifier type="damage" value="1" races="elf"/>
|
||||
</weapon>
|
||||
</item>
|
||||
</resource>
|
||||
|
|
|
@ -10,9 +10,7 @@
|
|||
<damage type="rider" value="1d11+2"/>
|
||||
<damage type="footman" value="1d11+2"/>
|
||||
<modifier type="missile_target" value="2"/>
|
||||
<modifier type="damage" value="1">
|
||||
<race name="elf"/>
|
||||
</modifier>
|
||||
<modifier type="damage" value="1" races="elf"/>
|
||||
</weapon>
|
||||
</item>
|
||||
</resource>
|
||||
|
|
|
@ -2,15 +2,12 @@
|
|||
<eressea>
|
||||
<resources>
|
||||
<resource name="towershield">
|
||||
<modifier type="require" race="dwarf"/>
|
||||
<modifier type="require" race="irongolem"/>
|
||||
<modifier type="require" races="dwarf irongolem"/>
|
||||
<item weight="200" score="60" allow="dwarf">
|
||||
<construction skill="armorer" minskill="4">
|
||||
<requirement type="iron" quantity="1"/>
|
||||
</construction>
|
||||
<armor ac="0" penalty="-0.15" projectile="0.25" magres="0.0" shield="yes">
|
||||
<modifier type="canuse" function="mod_dwarves_only"/>
|
||||
</armor>
|
||||
<armor ac="0" penalty="-0.15" projectile="0.25" magres="0.0" shield="yes"/>
|
||||
</item>
|
||||
</resource>
|
||||
<resource name="shield">
|
||||
|
@ -22,8 +19,7 @@
|
|||
</item>
|
||||
</resource>
|
||||
<resource name="scale">
|
||||
<modifier type="require" race="dwarf"/>
|
||||
<modifier type="require" race="irongolem"/>
|
||||
<modifier type="require" races="dwarf irongolem"/>
|
||||
<item weight="300" score="150" allow="dwarf halfling">
|
||||
<construction skill="armorer" minskill="5">
|
||||
<requirement type="iron" quantity="2"/>
|
||||
|
|
|
@ -31,7 +31,7 @@
|
|||
</item>
|
||||
</resource>
|
||||
<resource name="rep_crossbow">
|
||||
<modifier type="require" race="dwarf"/>
|
||||
<modifier type="require" races="dwarf"/>
|
||||
<item weight="100" allow="dwarf halfling">
|
||||
<construction skill="weaponsmithing" minskill="5">
|
||||
<requirement type="log" quantity="1"/>
|
||||
|
@ -127,7 +127,7 @@
|
|||
* has a lua canuse function
|
||||
* has lower damage
|
||||
-->
|
||||
<modifier type="require" race="elf"/>
|
||||
<modifier type="require" races="elf"/>
|
||||
<item weight="100" allow="elf">
|
||||
<construction skill="weaponsmithing" minskill="5">
|
||||
<requirement type="mallorn" quantity="2"/>
|
||||
|
@ -136,9 +136,7 @@
|
|||
<damage type="rider" value="2d4+5"/>
|
||||
<damage type="footman" value="2d4+5"/>
|
||||
<modifier type="missile_target" value="2"/>
|
||||
<modifier type="damage" value="1">
|
||||
<race name="elf"/>
|
||||
</modifier>
|
||||
<modifier type="damage" value="1" races="elf"/>
|
||||
</weapon>
|
||||
</item>
|
||||
</resource>
|
||||
|
|
|
@ -10,9 +10,7 @@
|
|||
<damage type="footman" value="3d8+8"/>
|
||||
<modifier type="missile_target" value="2"/>
|
||||
<modifier type="skill" value="-90"/>
|
||||
<modifier type="skill" value="100">
|
||||
<race name="snowman"/>
|
||||
</modifier>
|
||||
<modifier type="skill" value="100" races="snowman"/>
|
||||
</weapon>
|
||||
</item>
|
||||
</resource>
|
||||
|
|
|
@ -284,8 +284,6 @@ function test_block_movement()
|
|||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
function test_block_movement_aots()
|
||||
eressea.settings.set("rules.guard.base_stop_prob", "0.0")
|
||||
eressea.settings.set("rules.guard.skill_stop_prob", "1.0")
|
||||
|
@ -339,11 +337,11 @@ function test_stonegolems()
|
|||
u1:set_skill("building", 1)
|
||||
u2:set_skill("building", 1)
|
||||
|
||||
-- test that no server crash occur
|
||||
-- test that no server crash occurs
|
||||
u1:clear_orders()
|
||||
u1:add_order("Mache Burg")
|
||||
process_orders()
|
||||
assert_equal(0 ,u1.number, "There shoud be no Stone Golems")
|
||||
assert_equal(0, u1.number, "There should be no more stone golems")
|
||||
-- end test server crash
|
||||
|
||||
-- test that Stone Golems build for four stones
|
||||
|
@ -351,7 +349,7 @@ function test_stonegolems()
|
|||
u2:add_order("MACHE 4 BURG " .. itoa36(c1.id))
|
||||
process_orders()
|
||||
assert_equal(230, c1.size, "resulting size should be 230")
|
||||
assert_equal(1 ,u2.number, "There shoud be one Stone Golems")
|
||||
assert_equal(1, u2.number, "There should be one stone golem")
|
||||
-- end test Stone Golems four stones
|
||||
end
|
||||
|
||||
|
|
|
@ -12,6 +12,22 @@ local function create_faction(race)
|
|||
return faction.create(race, race .. '@example.com', "de")
|
||||
end
|
||||
|
||||
function test_produce_multi()
|
||||
local r = region.create(0, 0, 'mountain')
|
||||
local f = create_faction('human')
|
||||
local u = unit.create(f, r, 1)
|
||||
-- sword needs skill=3, iron=1
|
||||
u:set_skill('weaponsmithing', 15)
|
||||
u:add_item('iron', 5)
|
||||
|
||||
turn_begin()
|
||||
u:add_order("MACHE 6 Schwert")
|
||||
|
||||
turn_process()
|
||||
assert_equal(5, u:get_item('sword'))
|
||||
assert_equal(0, u:get_item('iron'))
|
||||
end
|
||||
|
||||
function test_greatbow_needs_elf()
|
||||
-- only elves can build a greatbow
|
||||
local r = region.create(0, 0, 'mountain')
|
||||
|
|
|
@ -43,7 +43,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
|
||||
typedef enum {
|
||||
typedef enum dict_type {
|
||||
TNONE = 0, TINTEGER = 1, TREAL = 2
|
||||
} dict_type;
|
||||
|
||||
|
|
|
@ -46,7 +46,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|||
|
||||
static int read_seenspells(variant *var, void *owner, struct gamedata *data)
|
||||
{
|
||||
selist *ql;
|
||||
selist *ql = NULL;
|
||||
storage *store = data->store;
|
||||
spell *sp = 0;
|
||||
char token[32];
|
||||
|
@ -107,14 +107,14 @@ static int cmp_spell(const void *a, const void *b) {
|
|||
return strcmp(spa->sname, spb->sname);
|
||||
}
|
||||
|
||||
static bool set_seen(attrib **alist, struct spell *sp) {
|
||||
static bool set_seen(attrib **alist, const struct spell *sp) {
|
||||
attrib *a = a_find(*alist, &at_seenspells);
|
||||
selist **sl;
|
||||
if (!a) {
|
||||
a = a_add(alist, a_new(&at_seenspells));
|
||||
}
|
||||
sl = (selist **)&a->data.v;
|
||||
return selist_set_insert(sl, sp, cmp_spell);
|
||||
return selist_set_insert(sl, (void *)sp, cmp_spell);
|
||||
}
|
||||
|
||||
static void upgrade_seenspell(attrib **alist, attrib *abegin) {
|
||||
|
@ -123,7 +123,7 @@ static void upgrade_seenspell(attrib **alist, attrib *abegin) {
|
|||
ak = a_find(*alist, &at_seenspells);
|
||||
if (ak) alist = &ak;
|
||||
for (a = abegin; a && a->type == abegin->type; a = a->next) {
|
||||
set_seen(alist, (struct spell *)a->data.v);
|
||||
set_seen(alist, (const struct spell *)a->data.v);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -156,11 +156,12 @@ attrib_type at_reportspell = {
|
|||
"reportspell", NULL
|
||||
};
|
||||
|
||||
void show_spell(faction *f, const spellbook_entry *sbe)
|
||||
void show_spell(faction *f, spellbook_entry *sbe)
|
||||
{
|
||||
if (!already_seen(f, sbe->sp)) {
|
||||
const spell *sp = spellref_get(&sbe->spref);
|
||||
if (!already_seen(f, sp)) {
|
||||
/* mark the spell as seen by this faction: */
|
||||
if (set_seen(&f->attribs, sbe->sp)) {
|
||||
if (set_seen(&f->attribs, sp)) {
|
||||
/* add the spell to the report: */
|
||||
attrib * a = a_new(&at_reportspell);
|
||||
a->data.v = (void *)sbe;
|
||||
|
|
|
@ -6,7 +6,7 @@ struct spellbook_entry;
|
|||
struct faction;
|
||||
struct spell;
|
||||
|
||||
void show_spell(struct faction * f, const struct spellbook_entry *sbe);
|
||||
void show_spell(struct faction * f, struct spellbook_entry *sbe);
|
||||
void reset_seen_spells(struct faction * f, const struct spell *sp);
|
||||
|
||||
extern struct attrib_type at_reportspell;
|
||||
|
|
50
src/battle.c
50
src/battle.c
|
@ -723,6 +723,7 @@ bool missile)
|
|||
}
|
||||
if (wtype->modifiers != NULL) {
|
||||
/* Pferdebonus, Lanzenbonus, usw. */
|
||||
const race *rc = u_race(tu);
|
||||
int m;
|
||||
unsigned int flags =
|
||||
WMF_SKILL | (attacking ? WMF_OFFENSIVE : WMF_DEFENSIVE);
|
||||
|
@ -738,17 +739,10 @@ bool missile)
|
|||
|
||||
for (m = 0; wtype->modifiers[m].value; ++m) {
|
||||
if ((wtype->modifiers[m].flags & flags) == flags) {
|
||||
race_list *rlist = wtype->modifiers[m].races;
|
||||
if (rlist != NULL) {
|
||||
while (rlist) {
|
||||
if (rlist->data == u_race(tu))
|
||||
break;
|
||||
rlist = rlist->next;
|
||||
}
|
||||
if (rlist == NULL)
|
||||
continue;
|
||||
int mask = wtype->modifiers[m].race_mask;
|
||||
if ((mask == 0) || (mask & rc->mask_item)) {
|
||||
skill += wtype->modifiers[m].value;
|
||||
}
|
||||
skill += wtype->modifiers[m].value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1029,17 +1023,10 @@ static int rc_specialdamage(const unit *au, const unit *du, const struct weapon_
|
|||
for (m = 0; wtype->modifiers[m].value; ++m) {
|
||||
/* weapon damage for this weapon, possibly by race */
|
||||
if (wtype->modifiers[m].flags & WMF_DAMAGE) {
|
||||
race_list *rlist = wtype->modifiers[m].races;
|
||||
if (rlist != NULL) {
|
||||
while (rlist) {
|
||||
if (rlist->data == ar)
|
||||
break;
|
||||
rlist = rlist->next;
|
||||
}
|
||||
if (rlist == NULL)
|
||||
continue;
|
||||
int mask = wtype->modifiers[m].race_mask;
|
||||
if ((mask == 0) || (mask & ar->mask_item)) {
|
||||
modifier += wtype->modifiers[m].value;
|
||||
}
|
||||
modifier += wtype->modifiers[m].value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1552,6 +1539,17 @@ static int get_tactics(const side * as, const side * ds)
|
|||
return result - defense;
|
||||
}
|
||||
|
||||
double tactics_chance(const unit *u, int skilldiff) {
|
||||
double tacch = 0.1 * skilldiff;
|
||||
if (fval(u->region->terrain, SEA_REGION)) {
|
||||
const ship *sh = u->ship;
|
||||
if (sh) {
|
||||
tacch *= sh->type->tac_bonus;
|
||||
}
|
||||
}
|
||||
return tacch;
|
||||
}
|
||||
|
||||
static troop select_opponent(battle * b, troop at, int mindist, int maxdist)
|
||||
{
|
||||
fighter *af = at.fighter;
|
||||
|
@ -1573,12 +1571,7 @@ static troop select_opponent(battle * b, troop at, int mindist, int maxdist)
|
|||
|
||||
/* percentage chance to get this attack */
|
||||
if (tactics > 0) {
|
||||
double tacch = 0.1 * tactics;
|
||||
if (fval(b->region->terrain, SEA_REGION)) {
|
||||
ship *sh = at.fighter->unit->ship;
|
||||
if (sh)
|
||||
tacch *= sh->type->tac_bonus;
|
||||
}
|
||||
double tacch = tactics_chance(af->unit, tactics);
|
||||
if (!chance(tacch)) {
|
||||
dt.fighter = NULL;
|
||||
}
|
||||
|
@ -1877,7 +1870,7 @@ static void do_extra_spell(troop at, const att * a)
|
|||
const spell *sp = spellref_get(a->data.sp);
|
||||
|
||||
if (!sp) {
|
||||
log_error("no such spell: '%s'", a->data.sp->name);
|
||||
log_error("no such spell: '%s'", a->data.sp->_name);
|
||||
}
|
||||
else {
|
||||
assert(a->level > 0);
|
||||
|
@ -3272,8 +3265,9 @@ fighter *make_fighter(battle * b, unit * u, side * s1, bool attack)
|
|||
adata->atype = itm->type->rtype->atype;
|
||||
adata->count = itm->number;
|
||||
for (aptr = &fig->armors; *aptr; aptr = &(*aptr)->next) {
|
||||
if (adata->atype->prot > (*aptr)->atype->prot)
|
||||
if (adata->atype->prot > (*aptr)->atype->prot) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
adata->next = *aptr;
|
||||
*aptr = adata;
|
||||
|
|
|
@ -143,7 +143,7 @@ extern "C" {
|
|||
} troop;
|
||||
|
||||
typedef struct armor {
|
||||
struct armor *next;
|
||||
struct armor *next; /* TODO: make this an array, not a list, like weapon */
|
||||
const struct armor_type *atype;
|
||||
int count;
|
||||
} armor;
|
||||
|
@ -270,6 +270,7 @@ extern "C" {
|
|||
const char *sidename(const struct side * s);
|
||||
void battle_message_faction(struct battle * b, struct faction * f, struct message *m);
|
||||
|
||||
double tactics_chance(const struct unit *u, int skilldiff);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#include <kernel/item.h>
|
||||
#include <kernel/race.h>
|
||||
#include <kernel/region.h>
|
||||
#include <kernel/ship.h>
|
||||
#include <kernel/unit.h>
|
||||
|
||||
#include <spells/buildingcurse.h>
|
||||
|
@ -17,9 +18,11 @@
|
|||
#include <util/functions.h>
|
||||
#include <util/rand.h>
|
||||
#include <util/rng.h>
|
||||
#include <util/strings.h>
|
||||
|
||||
#include <CuTest.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "tests.h"
|
||||
|
@ -68,16 +71,98 @@ static void test_make_fighter(CuTest * tc)
|
|||
test_teardown();
|
||||
}
|
||||
|
||||
static void test_select_weapon_restricted(CuTest *tc) {
|
||||
item_type *itype;
|
||||
unit *au;
|
||||
fighter *af;
|
||||
battle *b;
|
||||
race * rc;
|
||||
|
||||
test_setup();
|
||||
au = test_create_unit(test_create_faction(NULL), test_create_plain(0, 0));
|
||||
itype = test_create_itemtype("halberd");
|
||||
new_weapontype(itype, 0, frac_zero, NULL, 0, 0, 0, SK_MELEE);
|
||||
i_change(&au->items, itype, 1);
|
||||
rc = test_create_race("smurf");
|
||||
CuAssertIntEquals(tc, 0, rc->mask_item & au->_race->mask_item);
|
||||
|
||||
b = make_battle(au->region);
|
||||
af = make_fighter(b, au, make_side(b, au->faction, 0, 0, 0), false);
|
||||
CuAssertPtrNotNull(tc, af->weapons);
|
||||
CuAssertIntEquals(tc, 1, af->weapons[0].count);
|
||||
CuAssertIntEquals(tc, 0, af->weapons[1].count);
|
||||
free_battle(b);
|
||||
|
||||
itype->mask_deny = rc_mask(au->_race);
|
||||
b = make_battle(au->region);
|
||||
af = make_fighter(b, au, make_side(b, au->faction, 0, 0, 0), false);
|
||||
CuAssertPtrNotNull(tc, af->weapons);
|
||||
CuAssertIntEquals(tc, 0, af->weapons[0].count);
|
||||
free_battle(b);
|
||||
|
||||
itype->mask_deny = 0;
|
||||
itype->mask_allow = rc_mask(rc);
|
||||
b = make_battle(au->region);
|
||||
af = make_fighter(b, au, make_side(b, au->faction, 0, 0, 0), false);
|
||||
CuAssertPtrNotNull(tc, af->weapons);
|
||||
CuAssertIntEquals(tc, 0, af->weapons[0].count);
|
||||
free_battle(b);
|
||||
|
||||
itype->mask_deny = 0;
|
||||
itype->mask_allow = rc_mask(au->_race);
|
||||
b = make_battle(au->region);
|
||||
af = make_fighter(b, au, make_side(b, au->faction, 0, 0, 0), false);
|
||||
CuAssertPtrNotNull(tc, af->weapons);
|
||||
CuAssertIntEquals(tc, 1, af->weapons[0].count);
|
||||
CuAssertIntEquals(tc, 0, af->weapons[1].count);
|
||||
free_battle(b);
|
||||
|
||||
test_teardown();
|
||||
}
|
||||
|
||||
static void test_select_armor(CuTest *tc) {
|
||||
item_type *itype, *iscale;
|
||||
unit *au;
|
||||
fighter *af;
|
||||
battle *b;
|
||||
|
||||
test_setup();
|
||||
au = test_create_unit(test_create_faction(NULL), test_create_plain(0, 0));
|
||||
itype = test_create_itemtype("plate");
|
||||
new_armortype(itype, 0.0, frac_zero, 1, 0);
|
||||
i_change(&au->items, itype, 2);
|
||||
iscale = test_create_itemtype("scale");
|
||||
new_armortype(iscale, 0.0, frac_zero, 2, 0);
|
||||
i_change(&au->items, iscale, 1);
|
||||
|
||||
b = make_battle(au->region);
|
||||
af = make_fighter(b, au, make_side(b, au->faction, 0, 0, 0), false);
|
||||
CuAssertPtrNotNull(tc, af->armors);
|
||||
CuAssertIntEquals(tc, 1, af->armors->count);
|
||||
CuAssertPtrEquals(tc, iscale->rtype->atype, (armor_type *)af->armors->atype);
|
||||
CuAssertIntEquals(tc, 2, af->armors->next->count);
|
||||
CuAssertPtrEquals(tc, itype->rtype->atype, (armor_type *)af->armors->next->atype);
|
||||
CuAssertPtrEquals(tc, NULL, af->armors->next->next);
|
||||
free_battle(b);
|
||||
|
||||
test_teardown();
|
||||
}
|
||||
|
||||
static building_type * setup_castle(void) {
|
||||
building_type * btype;
|
||||
construction *cons;
|
||||
|
||||
btype = bt_get_or_create("castle");
|
||||
btype = test_create_buildingtype("castle");
|
||||
assert(btype->stages);
|
||||
assert(btype->stages->construction);
|
||||
|
||||
btype->flags |= BTF_FORTIFICATION;
|
||||
cons = btype->construction = calloc(1, sizeof(construction));
|
||||
cons = btype->stages->construction;
|
||||
cons->maxsize = 5;
|
||||
cons = cons->improvement = calloc(1, sizeof(construction));
|
||||
btype->stages->next = calloc(1, sizeof(building_stage));
|
||||
cons = calloc(1, sizeof(construction));
|
||||
cons->maxsize = -1;
|
||||
btype->stages->next->construction = cons;
|
||||
return btype;
|
||||
}
|
||||
|
||||
|
@ -486,9 +571,11 @@ static void test_battle_skilldiff_building(CuTest *tc)
|
|||
td.index = 0;
|
||||
ta.fighter = setup_fighter(&b, ua);
|
||||
ta.index = 0;
|
||||
CuAssertIntEquals(tc, 0, buildingeffsize(ud->building, false));
|
||||
CuAssertIntEquals(tc, 0, skilldiff(ta, td, 0));
|
||||
|
||||
ud->building->size = 10;
|
||||
CuAssertIntEquals(tc, 1, buildingeffsize(ud->building, false));
|
||||
CuAssertIntEquals(tc, -1, skilldiff(ta, td, 0));
|
||||
|
||||
create_curse(NULL, &ud->building->attribs, &ct_magicwalls, 1, 1, 1, 1);
|
||||
|
@ -579,10 +666,28 @@ static void test_drain_exp(CuTest *tc)
|
|||
test_teardown();
|
||||
}
|
||||
|
||||
static void test_tactics_chance(CuTest *tc) {
|
||||
unit *u;
|
||||
ship_type *stype;
|
||||
|
||||
test_setup();
|
||||
u = test_create_unit(test_create_faction(NULL), test_create_ocean(0, 0));
|
||||
CuAssertDblEquals(tc, 0.1, tactics_chance(u, 1), 0.01);
|
||||
CuAssertDblEquals(tc, 0.3, tactics_chance(u, 3), 0.01);
|
||||
stype = test_create_shiptype("brot");
|
||||
u->ship = test_create_ship(u->region, stype);
|
||||
CuAssertDblEquals(tc, 0.2, tactics_chance(u, 2), 0.01);
|
||||
stype->tac_bonus = 2.0;
|
||||
CuAssertDblEquals(tc, 0.4, tactics_chance(u, 2), 0.01);
|
||||
test_teardown();
|
||||
}
|
||||
|
||||
CuSuite *get_battle_suite(void)
|
||||
{
|
||||
CuSuite *suite = CuSuiteNew();
|
||||
SUITE_ADD_TEST(suite, test_make_fighter);
|
||||
SUITE_ADD_TEST(suite, test_select_weapon_restricted);
|
||||
SUITE_ADD_TEST(suite, test_select_armor);
|
||||
SUITE_ADD_TEST(suite, test_battle_skilldiff);
|
||||
SUITE_ADD_TEST(suite, test_battle_skilldiff_building);
|
||||
SUITE_ADD_TEST(suite, test_defenders_get_building_bonus);
|
||||
|
@ -593,6 +698,7 @@ CuSuite *get_battle_suite(void)
|
|||
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_tactics_chance);
|
||||
DISABLE_TEST(suite, test_drain_exp);
|
||||
return suite;
|
||||
}
|
||||
|
|
|
@ -770,26 +770,6 @@ static int config_get_btype(lua_State * L)
|
|||
}
|
||||
lua_settable(L, -3);
|
||||
}
|
||||
if (btype->construction) {
|
||||
lua_pushstring(L, "build_skill_min");
|
||||
lua_pushinteger(L, btype->construction->minskill);
|
||||
lua_settable(L, -3);
|
||||
lua_pushstring(L, "build_skill_name");
|
||||
lua_pushstring(L, skillnames[btype->construction->skill]);
|
||||
lua_settable(L, -3);
|
||||
if (btype->construction->materials) {
|
||||
int i;
|
||||
lua_pushstring(L, "materials");
|
||||
lua_newtable(L);
|
||||
for (i = 0; btype->construction->materials[i].number; ++i) {
|
||||
lua_pushstring(L,
|
||||
btype->construction->materials[i].rtype->_name);
|
||||
lua_pushinteger(L, btype->construction->materials[i].number);
|
||||
lua_settable(L, -3);
|
||||
}
|
||||
lua_settable(L, -3);
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
@ -880,7 +860,7 @@ static int tolua_get_spell_name(lua_State * L)
|
|||
static int tolua_get_spell_entry_name(lua_State * L)
|
||||
{
|
||||
spellbook_entry *self = (spellbook_entry*)tolua_tousertype(L, 1, 0);
|
||||
lua_pushstring(L, self->sp->sname);
|
||||
lua_pushstring(L, spellref_name(&self->spref));
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
|
|
@ -758,7 +758,7 @@ static void cr_output_spells(stream *out, const unit * u, int maxlevel)
|
|||
for (ql = book->spells, qi = 0; ql; selist_advance(&ql, &qi, 1)) {
|
||||
spellbook_entry * sbe = (spellbook_entry *)selist_get(ql, qi);
|
||||
if (sbe->level <= maxlevel) {
|
||||
spell * sp = sbe->sp;
|
||||
const spell *sp = spellref_get(&sbe->spref);
|
||||
const char *name = translate(mkname("spell", sp->sname), spell_name(sp, f->locale));
|
||||
if (!header) {
|
||||
stream_printf(out, "SPRUECHE\n");
|
||||
|
@ -1083,7 +1083,7 @@ static void cr_find_address(FILE * F, const faction * uf, selist * addresses)
|
|||
|
||||
/* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
|
||||
|
||||
static void cr_reportspell(FILE * F, spell * sp, int level, const struct locale *lang)
|
||||
static void cr_reportspell(FILE * F, const spell * sp, int level, const struct locale *lang)
|
||||
{
|
||||
int k;
|
||||
const char *name =
|
||||
|
@ -1673,7 +1673,8 @@ report_computer(const char *filename, report_context * ctx, const char *bom)
|
|||
a = a_find(f->attribs, &at_reportspell);
|
||||
while (a && a->type == &at_reportspell) {
|
||||
spellbook_entry *sbe = (spellbook_entry *)a->data.v;
|
||||
cr_reportspell(F, sbe->sp, sbe->level, f->locale);
|
||||
const spell *sp = spellref_get(&sbe->spref);
|
||||
cr_reportspell(F, sp, sbe->level, f->locale);
|
||||
a = a->next;
|
||||
}
|
||||
for (a = a_find(f->attribs, &at_showitem); a && a->type == &at_showitem;
|
||||
|
|
|
@ -8,7 +8,7 @@ extern "C"
|
|||
|
||||
struct locale;
|
||||
|
||||
typedef enum {
|
||||
typedef enum direction_t {
|
||||
D_NORTHWEST,
|
||||
D_NORTHEAST,
|
||||
D_EAST,
|
||||
|
|
|
@ -833,7 +833,8 @@ static struct message * get_modifiers(unit *u, skill_t sk, const resource_type *
|
|||
|
||||
for (mod = rtype->modifiers; mod && mod->type != RMT_END; ++mod) {
|
||||
if (mod->btype == NULL || mod->btype == btype) {
|
||||
if (mod->race == NULL || mod->race == u_race(u)) {
|
||||
const race * rc = u_race(u);
|
||||
if (mod->race_mask == 0 || (mod->race_mask & rc->mask_item)) {
|
||||
switch (mod->type) {
|
||||
case RMT_PROD_SAVE:
|
||||
if (savep) {
|
||||
|
@ -845,7 +846,7 @@ static struct message * get_modifiers(unit *u, skill_t sk, const resource_type *
|
|||
mod_skill(mod, sk, &skill);
|
||||
break;
|
||||
case RMT_PROD_REQUIRE:
|
||||
if (mod->race) need_race |= 1;
|
||||
if (mod->race_mask) need_race |= 1;
|
||||
if (mod->btype) {
|
||||
need_bldg |= 1;
|
||||
}
|
||||
|
@ -857,7 +858,7 @@ static struct message * get_modifiers(unit *u, skill_t sk, const resource_type *
|
|||
}
|
||||
}
|
||||
if (mod->type == RMT_PROD_REQUIRE) {
|
||||
if (mod->race) need_race |= 2;
|
||||
if (mod->race_mask) need_race |= 2;
|
||||
if (mod->btype) {
|
||||
btype_needed = mod->btype;
|
||||
need_bldg |= 2;
|
||||
|
@ -1408,7 +1409,7 @@ int make_cmd(unit * u, struct order *ord)
|
|||
if (pl && fval(pl, PFL_NOBUILD)) {
|
||||
cmistake(u, ord, 275, MSG_PRODUCE);
|
||||
}
|
||||
else if (btype->construction) {
|
||||
else if (btype->stages && btype->stages->construction) {
|
||||
int id = getid();
|
||||
build_building(u, btype, id, m, ord);
|
||||
}
|
||||
|
|
|
@ -509,7 +509,7 @@ static void test_modify_material(CuTest *tc) {
|
|||
mod = rtype->modifiers = calloc(2, sizeof(resource_mod));
|
||||
mod[0].type = RMT_USE_SAVE;
|
||||
mod[0].value = frac_make(2, 1);
|
||||
mod[0].race = u_race(u);
|
||||
mod[0].race_mask = rc_mask(u_race(u));
|
||||
|
||||
itype = test_create_itemtype("sword");
|
||||
make_item(u, itype, 1);
|
||||
|
@ -574,7 +574,7 @@ static void test_modify_skill(CuTest *tc) {
|
|||
mod[0].type = RMT_PROD_SKILL;
|
||||
mod[0].value.sa[0] = SK_WEAPONSMITH;
|
||||
mod[0].value.sa[1] = 1;
|
||||
mod[0].race = u_race(u);
|
||||
mod[0].race_mask = rc_mask(u_race(u));
|
||||
|
||||
set_item(u, rtype->itype, 2); /* 2 iron should get us 2 swords */
|
||||
make_item(u, itype, 2);
|
||||
|
@ -647,7 +647,7 @@ static void test_modify_production(CuTest *tc) {
|
|||
|
||||
rtype->modifiers = calloc(3, sizeof(resource_mod));
|
||||
rtype->modifiers[0].type = RMT_PROD_SAVE;
|
||||
rtype->modifiers[0].race = u->_race;
|
||||
rtype->modifiers[0].race_mask = rc_mask(u->_race);
|
||||
rtype->modifiers[0].value.sa[0] = (short)(0.5+100*d);
|
||||
rtype->modifiers[0].value.sa[1] = 100;
|
||||
rtype->modifiers[1].type = RMT_END;
|
||||
|
@ -668,7 +668,7 @@ static void test_modify_production(CuTest *tc) {
|
|||
CuAssertIntEquals(tc, 280, region_getresource(u->region, rtype)); /* 50% saving = 3 stones make 6 stones */
|
||||
|
||||
rtype->modifiers[0].type = RMT_PROD_REQUIRE;
|
||||
rtype->modifiers[0].race = NULL;
|
||||
rtype->modifiers[0].race_mask = 0;
|
||||
rtype->modifiers[0].btype = bt_get_or_create("mine");
|
||||
|
||||
test_clear_messages(u->faction);
|
||||
|
@ -677,7 +677,7 @@ static void test_modify_production(CuTest *tc) {
|
|||
CuAssertPtrNotNull(tc, test_find_messagetype(u->faction->msgs, "building_needed"));
|
||||
|
||||
rtype->modifiers[0].type = RMT_PROD_REQUIRE;
|
||||
rtype->modifiers[0].race = test_create_race("smurf");
|
||||
rtype->modifiers[0].race_mask = rc_mask(test_create_race("smurf"));
|
||||
rtype->modifiers[0].btype = NULL;
|
||||
|
||||
test_clear_messages(u->faction);
|
||||
|
@ -686,7 +686,7 @@ static void test_modify_production(CuTest *tc) {
|
|||
CuAssertPtrNotNull(tc, test_find_messagetype(u->faction->msgs, "error117"));
|
||||
|
||||
rtype->modifiers[1].type = RMT_PROD_REQUIRE;
|
||||
rtype->modifiers[1].race = u_race(u);
|
||||
rtype->modifiers[1].race_mask = rc_mask(u_race(u));
|
||||
rtype->modifiers[1].btype = NULL;
|
||||
rtype->modifiers[2].type = RMT_END;
|
||||
|
||||
|
|
|
@ -151,20 +151,6 @@ static void json_construction(cJSON *json, construction **consp) {
|
|||
cJSON *child;
|
||||
construction * cons;
|
||||
|
||||
if (json->type == cJSON_Array) {
|
||||
int size = 0;
|
||||
for (child = json->child; child; child = child->next) {
|
||||
construction *cons = 0;
|
||||
json_construction(child, &cons);
|
||||
if (cons) {
|
||||
cons->maxsize -= size;
|
||||
size += cons->maxsize + size;
|
||||
*consp = cons;
|
||||
consp = &cons->improvement;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (json->type != cJSON_Object) {
|
||||
log_error("construction %s is not a json object: %d", json->string, json->type);
|
||||
return;
|
||||
|
@ -309,6 +295,57 @@ static void json_terrain(cJSON *json, terrain_type *ter) {
|
|||
}
|
||||
}
|
||||
|
||||
static void json_stage(cJSON *json, building_stage *stage) {
|
||||
cJSON *child;
|
||||
|
||||
if (json->type != cJSON_Object) {
|
||||
log_error("building stages is not a json object: %d", json->type);
|
||||
return;
|
||||
}
|
||||
for (child = json->child; child; child = child->next) {
|
||||
switch (child->type) {
|
||||
case cJSON_Object:
|
||||
if (strcmp(child->string, "construction") == 0) {
|
||||
json_construction(child, &stage->construction);
|
||||
}
|
||||
break;
|
||||
case cJSON_String:
|
||||
if (strcmp(child->string, "name") == 0) {
|
||||
stage->name = str_strdup(child->valuestring);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void json_stages(cJSON *json, building_type *bt) {
|
||||
cJSON *child;
|
||||
building_stage *stage, **sp = &bt->stages;
|
||||
int size = 0;
|
||||
|
||||
if (json->type != cJSON_Array) {
|
||||
log_error("building stages is not a json array: %d", json->type);
|
||||
return;
|
||||
}
|
||||
|
||||
for (child = json->child; child; child = child->next) {
|
||||
switch (child->type) {
|
||||
case cJSON_Object:
|
||||
stage = calloc(sizeof(building_stage), 1);
|
||||
json_stage(child, stage);
|
||||
if (stage->construction->maxsize > 0) {
|
||||
stage->construction->maxsize -= size;
|
||||
size += stage->construction->maxsize;
|
||||
}
|
||||
*sp = stage;
|
||||
sp = &stage->next;
|
||||
break;
|
||||
default:
|
||||
log_error("building stage contains non-object type %d", child->type);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void json_building(cJSON *json, building_type *bt) {
|
||||
cJSON *child;
|
||||
const char *flags[] = {
|
||||
|
@ -321,8 +358,10 @@ static void json_building(cJSON *json, building_type *bt) {
|
|||
for (child = json->child; child; child = child->next) {
|
||||
switch (child->type) {
|
||||
case cJSON_Array:
|
||||
if (strcmp(child->string, "construction") == 0) {
|
||||
json_construction(child, &bt->construction);
|
||||
if (strcmp(child->string, "stages") == 0) {
|
||||
if (!bt->stages) {
|
||||
json_stages(child, bt);
|
||||
}
|
||||
}
|
||||
else if (strcmp(child->string, "maintenance") == 0) {
|
||||
json_maintenance(child, &bt->maintenance);
|
||||
|
@ -333,9 +372,14 @@ static void json_building(cJSON *json, building_type *bt) {
|
|||
break;
|
||||
case cJSON_Object:
|
||||
if (strcmp(child->string, "construction") == 0) {
|
||||
json_construction(child, &bt->construction);
|
||||
/* simple, single-stage building */
|
||||
if (!bt->stages) {
|
||||
building_stage *stage = calloc(sizeof(building_stage), 1);
|
||||
json_construction(child, &stage->construction);
|
||||
bt->stages = stage;
|
||||
}
|
||||
}
|
||||
else if (strcmp(child->string, "maintenance") == 0) {
|
||||
if (strcmp(child->string, "maintenance") == 0) {
|
||||
json_maintenance(child, &bt->maintenance);
|
||||
}
|
||||
break;
|
||||
|
|
|
@ -110,7 +110,7 @@ static void test_prefixes(CuTest * tc)
|
|||
CuAssertPtrNotNull(tc, race_prefixes);
|
||||
CuAssertStrEquals(tc, "snow", race_prefixes[0]);
|
||||
CuAssertStrEquals(tc, "dark", race_prefixes[2]);
|
||||
CuAssertPtrEquals(tc, 0, race_prefixes[3]);
|
||||
CuAssertPtrEquals(tc, NULL, race_prefixes[3]);
|
||||
cJSON_Delete(json);
|
||||
test_teardown();
|
||||
}
|
||||
|
@ -189,7 +189,7 @@ static void test_races(CuTest * tc)
|
|||
test_setup();
|
||||
|
||||
CuAssertPtrNotNull(tc, json);
|
||||
CuAssertPtrEquals(tc, 0, races);
|
||||
CuAssertPtrEquals(tc, NULL, races);
|
||||
json_config(json);
|
||||
|
||||
CuAssertPtrNotNull(tc, races);
|
||||
|
@ -222,7 +222,7 @@ static void test_findrace(CuTest *tc) {
|
|||
CuAssertPtrNotNull(tc, json);
|
||||
test_setup();
|
||||
lang = get_or_create_locale("de");
|
||||
CuAssertPtrEquals(tc, 0, (void *)findrace("Zwerg", lang));
|
||||
CuAssertPtrEquals(tc, NULL, (void *)findrace("Zwerg", lang));
|
||||
|
||||
json_config(json);
|
||||
init_locale(lang);
|
||||
|
@ -245,9 +245,9 @@ static void test_items(CuTest * tc)
|
|||
test_setup();
|
||||
|
||||
CuAssertPtrNotNull(tc, json);
|
||||
CuAssertPtrEquals(tc, 0, it_find("axe"));
|
||||
CuAssertPtrEquals(tc, 0, rt_find("axe"));
|
||||
CuAssertPtrEquals(tc, 0, (void *)get_resourcetype(R_HORSE));
|
||||
CuAssertPtrEquals(tc, NULL, it_find("axe"));
|
||||
CuAssertPtrEquals(tc, NULL, rt_find("axe"));
|
||||
CuAssertPtrEquals(tc, NULL, (void *)get_resourcetype(R_HORSE));
|
||||
|
||||
json_config(json);
|
||||
|
||||
|
@ -283,7 +283,7 @@ static void test_ships(CuTest * tc)
|
|||
test_setup();
|
||||
|
||||
CuAssertPtrNotNull(tc, json);
|
||||
CuAssertPtrEquals(tc, 0, shiptypes);
|
||||
CuAssertPtrEquals(tc, NULL, shiptypes);
|
||||
json_config(json);
|
||||
|
||||
CuAssertPtrNotNull(tc, shiptypes);
|
||||
|
@ -301,7 +301,7 @@ static void test_ships(CuTest * tc)
|
|||
|
||||
CuAssertPtrNotNull(tc, st->coasts);
|
||||
CuAssertPtrEquals(tc, (void *)ter, (void *)st->coasts[0]);
|
||||
CuAssertPtrEquals(tc, 0, (void *)st->coasts[1]);
|
||||
CuAssertPtrEquals(tc, NULL, (void *)st->coasts[1]);
|
||||
|
||||
cJSON_Delete(json);
|
||||
test_teardown();
|
||||
|
@ -309,28 +309,42 @@ static void test_ships(CuTest * tc)
|
|||
|
||||
static void test_castles(CuTest *tc) {
|
||||
const char * data = "{\"buildings\": { \"castle\" : { "
|
||||
"\"construction\" : ["
|
||||
"{ \"maxsize\" : 2 },"
|
||||
"{ \"maxsize\" : 8 }"
|
||||
"\"stages\" : ["
|
||||
"{ \"construction\": { \"maxsize\" : 2 }, \"name\": \"site\" },"
|
||||
"{ \"construction\": { \"maxsize\" : 8 } },"
|
||||
"{ \"construction\": { \"maxsize\" : -1 } }"
|
||||
"]}}}";
|
||||
|
||||
cJSON *json = cJSON_Parse(data);
|
||||
const building_type *bt;
|
||||
const building_stage *stage;
|
||||
const construction *con;
|
||||
|
||||
test_setup();
|
||||
|
||||
CuAssertPtrNotNull(tc, json);
|
||||
CuAssertPtrEquals(tc, 0, buildingtypes);
|
||||
CuAssertPtrEquals(tc, NULL, buildingtypes);
|
||||
json_config(json);
|
||||
|
||||
CuAssertPtrNotNull(tc, buildingtypes);
|
||||
bt = bt_find("castle");
|
||||
CuAssertPtrNotNull(tc, bt);
|
||||
CuAssertPtrNotNull(tc, bt->construction);
|
||||
CuAssertIntEquals(tc, 2, bt->construction->maxsize);
|
||||
CuAssertPtrNotNull(tc, bt->construction->improvement);
|
||||
CuAssertIntEquals(tc, 6, bt->construction->improvement->maxsize);
|
||||
CuAssertPtrEquals(tc, 0, bt->construction->improvement->improvement);
|
||||
CuAssertPtrNotNull(tc, stage = bt->stages);
|
||||
CuAssertStrEquals(tc, "site", stage->name);
|
||||
CuAssertPtrNotNull(tc, con = stage->construction);
|
||||
CuAssertIntEquals(tc, 2, con->maxsize);
|
||||
|
||||
CuAssertPtrNotNull(tc, stage = stage->next);
|
||||
CuAssertPtrEquals(tc, NULL, stage->name);
|
||||
CuAssertPtrNotNull(tc, con = stage->construction);
|
||||
CuAssertIntEquals(tc, 6, con->maxsize);
|
||||
|
||||
CuAssertPtrNotNull(tc, stage = stage->next);
|
||||
CuAssertPtrNotNull(tc, con = stage->construction);
|
||||
CuAssertIntEquals(tc, -1, con->maxsize);
|
||||
|
||||
CuAssertPtrEquals(tc, NULL, stage->next);
|
||||
|
||||
cJSON_Delete(json);
|
||||
test_teardown();
|
||||
}
|
||||
|
@ -344,7 +358,7 @@ static void test_spells(CuTest * tc)
|
|||
|
||||
test_setup();
|
||||
CuAssertPtrNotNull(tc, json);
|
||||
CuAssertPtrEquals(tc, 0, find_spell("fireball"));
|
||||
CuAssertPtrEquals(tc, NULL, find_spell("fireball"));
|
||||
|
||||
json_config(json);
|
||||
sp = find_spell("fireball");
|
||||
|
@ -353,7 +367,7 @@ static void test_spells(CuTest * tc)
|
|||
|
||||
cJSON_Delete(json);
|
||||
test_teardown();
|
||||
CuAssertPtrEquals(tc, 0, find_spell("fireball"));
|
||||
CuAssertPtrEquals(tc, NULL, find_spell("fireball"));
|
||||
}
|
||||
|
||||
static const char * building_data = "{\"buildings\": { "
|
||||
|
@ -380,11 +394,12 @@ static void test_buildings(CuTest * tc)
|
|||
{
|
||||
cJSON *json = cJSON_Parse(building_data);
|
||||
const building_type *bt;
|
||||
const construction *con;
|
||||
|
||||
test_setup();
|
||||
|
||||
CuAssertPtrNotNull(tc, json);
|
||||
CuAssertPtrEquals(tc, 0, buildingtypes);
|
||||
CuAssertPtrEquals(tc, NULL, buildingtypes);
|
||||
json_config(json);
|
||||
|
||||
CuAssertPtrNotNull(tc, buildingtypes);
|
||||
|
@ -406,17 +421,19 @@ static void test_buildings(CuTest * tc)
|
|||
CuAssertIntEquals(tc, MTF_VARIABLE, bt->maintenance[0].flags);
|
||||
CuAssertIntEquals(tc, 0, bt->maintenance[1].number);
|
||||
|
||||
CuAssertPtrNotNull(tc, bt->construction);
|
||||
CuAssertPtrNotNull(tc, bt->construction->materials);
|
||||
CuAssertIntEquals(tc, 2, bt->construction->materials[0].number);
|
||||
CuAssertPtrEquals(tc, (void *)get_resourcetype(R_STONE), (void *)bt->construction->materials[0].rtype);
|
||||
CuAssertIntEquals(tc, 1, bt->construction->materials[1].number);
|
||||
CuAssertPtrEquals(tc, (void *)get_resourcetype(R_IRON), (void *)bt->construction->materials[1].rtype);
|
||||
CuAssertIntEquals(tc, 0, bt->construction->materials[2].number);
|
||||
CuAssertIntEquals(tc, 10, bt->construction->reqsize);
|
||||
CuAssertIntEquals(tc, 20, bt->construction->maxsize);
|
||||
CuAssertIntEquals(tc, 1, bt->construction->minskill);
|
||||
CuAssertPtrEquals(tc, 0, bt->construction->improvement);
|
||||
CuAssertPtrNotNull(tc, bt->stages);
|
||||
CuAssertPtrEquals(tc, NULL, bt->stages->next);
|
||||
CuAssertPtrNotNull(tc, bt->stages->construction);
|
||||
CuAssertPtrNotNull(tc, con = bt->stages->construction);
|
||||
CuAssertPtrNotNull(tc, con->materials);
|
||||
CuAssertIntEquals(tc, 2, con->materials[0].number);
|
||||
CuAssertPtrEquals(tc, (void *)get_resourcetype(R_STONE), (void *)con->materials[0].rtype);
|
||||
CuAssertIntEquals(tc, 1, con->materials[1].number);
|
||||
CuAssertPtrEquals(tc, (void *)get_resourcetype(R_IRON), (void *)con->materials[1].rtype);
|
||||
CuAssertIntEquals(tc, 0, con->materials[2].number);
|
||||
CuAssertIntEquals(tc, 10, con->reqsize);
|
||||
CuAssertIntEquals(tc, 20, con->maxsize);
|
||||
CuAssertIntEquals(tc, 1, con->minskill);
|
||||
cJSON_Delete(json);
|
||||
test_teardown();
|
||||
}
|
||||
|
@ -483,7 +500,7 @@ static void test_configs(CuTest * tc)
|
|||
fwrite(building_data, 1, strlen(building_data), F);
|
||||
fclose(F);
|
||||
CuAssertPtrNotNull(tc, json);
|
||||
CuAssertPtrEquals(tc, 0, buildingtypes);
|
||||
CuAssertPtrEquals(tc, NULL, buildingtypes);
|
||||
json_config(json);
|
||||
CuAssertPtrNotNull(tc, buildingtypes);
|
||||
if (remove("test.json")!=0 && errno==ENOENT) {
|
||||
|
@ -508,7 +525,7 @@ static void test_terrains(CuTest * tc)
|
|||
|
||||
test_setup();
|
||||
CuAssertPtrNotNull(tc, json);
|
||||
CuAssertPtrEquals(tc, 0, (void *)get_terrain("plain"));
|
||||
CuAssertPtrEquals(tc, NULL, (void *)get_terrain("plain"));
|
||||
|
||||
json_config(json);
|
||||
ter = get_terrain("plain");
|
||||
|
@ -520,7 +537,7 @@ static void test_terrains(CuTest * tc)
|
|||
CuAssertPtrNotNull(tc, ter->herbs);
|
||||
CuAssertPtrEquals(tc, rt_get_or_create("h0"), ter->herbs[0]->rtype);
|
||||
CuAssertPtrEquals(tc, rt_get_or_create("h1"), ter->herbs[1]->rtype);
|
||||
CuAssertPtrEquals(tc, 0, (void *)ter->herbs[2]);
|
||||
CuAssertPtrEquals(tc, NULL, (void *)ter->herbs[2]);
|
||||
CuAssertPtrNotNull(tc, ter->name); /* anything named "plain" uses plain_name() */
|
||||
CuAssertPtrNotNull(tc, ter->production);
|
||||
CuAssertPtrEquals(tc, rt_get_or_create("stone"), (resource_type *)ter->production[0].type);
|
||||
|
@ -529,7 +546,7 @@ static void test_terrains(CuTest * tc)
|
|||
CuAssertStrEquals(tc, "1d5", ter->production[0].divisor);
|
||||
CuAssertStrEquals(tc, "1d6", ter->production[0].startlevel);
|
||||
CuAssertPtrEquals(tc, rt_get_or_create("iron"), (resource_type *)ter->production[1].type);
|
||||
CuAssertPtrEquals(tc, 0, (void *)ter->production[2].type);
|
||||
CuAssertPtrEquals(tc, NULL, (void *)ter->production[2].type);
|
||||
|
||||
cJSON_Delete(json);
|
||||
test_teardown();
|
||||
|
|
|
@ -145,13 +145,25 @@ static void destroy_road(unit * u, int nmax, struct order *ord)
|
|||
}
|
||||
}
|
||||
|
||||
static int recycle(unit *u, construction *con, int size) {
|
||||
/* TODO: Nicht an ZERST<53>RE mit Punktangabe angepasst! */
|
||||
int c;
|
||||
for (c = 0; con->materials[c].number; ++c) {
|
||||
const requirement *rq = con->materials + c;
|
||||
int num = (rq->number * size / con->reqsize) / 2;
|
||||
if (num) {
|
||||
change_resource(u, rq->rtype, num);
|
||||
}
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
int destroy_cmd(unit * u, struct order *ord)
|
||||
{
|
||||
char token[128];
|
||||
ship *sh;
|
||||
unit *u2;
|
||||
region *r = u->region;
|
||||
const construction *con = NULL;
|
||||
int size = 0;
|
||||
const char *s;
|
||||
int n = INT_MAX;
|
||||
|
@ -194,6 +206,7 @@ int destroy_cmd(unit * u, struct order *ord)
|
|||
return 138;
|
||||
}
|
||||
if (n >= b->size) {
|
||||
building_stage *stage;
|
||||
/* destroy completly */
|
||||
/* all units leave the building */
|
||||
for (u2 = r->units; u2; u2 = u2->next) {
|
||||
|
@ -202,11 +215,13 @@ int destroy_cmd(unit * u, struct order *ord)
|
|||
}
|
||||
}
|
||||
ADDMSG(&u->faction->msgs, msg_message("destroy", "building unit", b, u));
|
||||
con = b->type->construction;
|
||||
for (stage = b->type->stages; stage; stage = stage->next) {
|
||||
size = recycle(u, stage->construction, size);
|
||||
}
|
||||
remove_building(&r->buildings, b);
|
||||
}
|
||||
else {
|
||||
/* partial destroy */
|
||||
/* TODO: partial destroy does not recycle */
|
||||
b->size -= n;
|
||||
ADDMSG(&u->faction->msgs, msg_message("destroy_partial",
|
||||
"building unit", b, u));
|
||||
|
@ -234,7 +249,7 @@ int destroy_cmd(unit * u, struct order *ord)
|
|||
}
|
||||
ADDMSG(&u->faction->msgs, msg_message("shipdestroy",
|
||||
"unit region ship", u, r, sh));
|
||||
con = sh->type->construction;
|
||||
size = recycle(u, sh->type->construction, size);
|
||||
remove_ship(&sh->region->ships, sh);
|
||||
}
|
||||
else {
|
||||
|
@ -248,18 +263,6 @@ int destroy_cmd(unit * u, struct order *ord)
|
|||
cmistake(u, ord, 138, MSG_PRODUCE);
|
||||
return 138;
|
||||
}
|
||||
|
||||
if (con) {
|
||||
/* TODO: Nicht an ZERST<53>RE mit Punktangabe angepasst! */
|
||||
int c;
|
||||
for (c = 0; con->materials[c].number; ++c) {
|
||||
const requirement *rq = con->materials + c;
|
||||
int recycle = (rq->number * size / con->reqsize) / 2;
|
||||
if (recycle) {
|
||||
change_resource(u, rq->rtype, recycle);
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -419,7 +422,7 @@ static int matmod(const unit * u, const resource_type * rtype, int value)
|
|||
for (mod = rtype->modifiers; mod->type != RMT_END; ++mod) {
|
||||
if (mod->type == RMT_USE_SAVE) {
|
||||
if (!mod->btype || mod->btype == btype) {
|
||||
if (!mod->race || mod->race == rc) {
|
||||
if (!mod->race_mask || (mod->race_mask & rc->mask_item)) {
|
||||
save = frac_mul(save, mod->value);
|
||||
}
|
||||
}
|
||||
|
@ -512,15 +515,16 @@ int build(unit * u, const construction * ctype, int completed, int want, int ski
|
|||
|
||||
if (want <= 0)
|
||||
return 0;
|
||||
if (con == NULL)
|
||||
if (con == NULL) {
|
||||
return ENOMATERIALS;
|
||||
if (con->improvement == NULL && completed == con->maxsize)
|
||||
}
|
||||
if (completed == con->maxsize) {
|
||||
return ECOMPLETE;
|
||||
}
|
||||
if (con->skill != NOSKILL) {
|
||||
int effsk;
|
||||
int dm = get_effect(u, oldpotiontype[P_DOMORE]);
|
||||
|
||||
assert(u->number);
|
||||
basesk = effskill(u, con->skill, 0);
|
||||
if (basesk == 0)
|
||||
return ENEEDSKILL;
|
||||
|
@ -544,23 +548,6 @@ int build(unit * u, const construction * ctype, int completed, int want, int ski
|
|||
for (; want > 0 && skills > 0;) {
|
||||
int err, n;
|
||||
|
||||
/* skip over everything that's already been done:
|
||||
* type->improvement==NULL means no more improvements, but no size limits
|
||||
* type->improvement==type means build another object of the same time
|
||||
* while material lasts type->improvement==x means build x when type
|
||||
* is finished */
|
||||
while (con && con->improvement &&
|
||||
con->improvement != con &&
|
||||
con->maxsize > 0 && con->maxsize <= completed) {
|
||||
completed -= con->maxsize;
|
||||
con = con->improvement;
|
||||
}
|
||||
if (con == NULL) {
|
||||
if (made == 0)
|
||||
return ECOMPLETE;
|
||||
break; /* completed */
|
||||
}
|
||||
|
||||
/* Hier ist entweder maxsize == -1, oder completed < maxsize.
|
||||
* Andernfalls ist das Datenfile oder sonstwas kaputt...
|
||||
* (enno): Nein, das ist f<EFBFBD>r Dinge, bei denen die n<EFBFBD>chste Ausbaustufe
|
||||
|
@ -605,9 +592,7 @@ int build(unit * u, const construction * ctype, int completed, int want, int ski
|
|||
if (con->maxsize > 0) {
|
||||
int req = con->maxsize - completed;
|
||||
if (req < n) n = req;
|
||||
if (con->improvement == NULL) {
|
||||
want = n;
|
||||
}
|
||||
want = n;
|
||||
}
|
||||
|
||||
n = count_materials(u, con, n, completed);
|
||||
|
@ -660,7 +645,6 @@ message *msg_materials_required(unit * u, order * ord,
|
|||
|
||||
int maxbuild(const unit * u, const construction * cons)
|
||||
/* calculate maximum size that can be built from available material */
|
||||
/* !! ignores maximum objectsize and improvements... */
|
||||
{
|
||||
int c;
|
||||
int maximum = INT_MAX;
|
||||
|
@ -679,7 +663,72 @@ int maxbuild(const unit * u, const construction * cons)
|
|||
return maximum;
|
||||
}
|
||||
|
||||
/** old build routines */
|
||||
static int build_failure(unit *u, order *ord, const building_type *btype, int want, int err) {
|
||||
switch (err) {
|
||||
case ECOMPLETE:
|
||||
/* the building is already complete */
|
||||
cmistake(u, ord, 4, MSG_PRODUCE);
|
||||
break;
|
||||
case ENOMATERIALS:
|
||||
ADDMSG(&u->faction->msgs, msg_materials_required(u, ord,
|
||||
btype->stages->construction, want));
|
||||
break;
|
||||
case ELOWSKILL:
|
||||
case ENEEDSKILL:
|
||||
/* no skill, or not enough skill points to build */
|
||||
cmistake(u, ord, 50, MSG_PRODUCE);
|
||||
break;
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
static int build_stages(unit *u, const building_type *btype, int built, int n) {
|
||||
|
||||
const building_stage *stage;
|
||||
int made = 0;
|
||||
|
||||
for (stage = btype->stages; stage; stage = stage->next) {
|
||||
const construction * con = stage->construction;
|
||||
if (con->maxsize < 0 || con->maxsize > built) {
|
||||
int err, want = INT_MAX;
|
||||
if (n < INT_MAX) {
|
||||
/* do not build more than n total */
|
||||
want = n - made;
|
||||
}
|
||||
if (con->maxsize > 0) {
|
||||
/* do not build more than the rest of the stage */
|
||||
int todo = con->maxsize - built;
|
||||
if (todo < want) {
|
||||
want = todo;
|
||||
}
|
||||
}
|
||||
err = build(u, con, built, want, 0);
|
||||
if (err < 0) {
|
||||
if (made == 0) {
|
||||
/* could not make any part at all */
|
||||
return err;
|
||||
}
|
||||
else {
|
||||
/* could not build any part of this stage (low skill, etc). */
|
||||
break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* err is the amount we built of this stage */
|
||||
made += err;
|
||||
if (err != con->maxsize && con->maxsize > 0) {
|
||||
/* we did not finish the stage, can quit here */
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* build the next stage: */
|
||||
if (built >= con->maxsize && con->maxsize > 0) {
|
||||
built -= con->maxsize;
|
||||
}
|
||||
}
|
||||
return made;
|
||||
}
|
||||
|
||||
int
|
||||
build_building(unit * u, const building_type * btype, int id, int want, order * ord)
|
||||
|
@ -693,7 +742,7 @@ build_building(unit * u, const building_type * btype, int id, int want, order *
|
|||
const struct locale *lang = u->faction->locale;
|
||||
|
||||
assert(u->number);
|
||||
assert(btype->construction);
|
||||
assert(btype->stages && btype->stages->construction);
|
||||
if (effskill(u, SK_BUILDING, 0) == 0) {
|
||||
cmistake(u, ord, 101, MSG_PRODUCE);
|
||||
return 0;
|
||||
|
@ -783,30 +832,19 @@ build_building(unit * u, const building_type * btype, int id, int want, order *
|
|||
}
|
||||
}
|
||||
}
|
||||
built = build(u, btype->construction, built, n, 0);
|
||||
|
||||
switch (built) {
|
||||
case ECOMPLETE:
|
||||
/* the building is already complete */
|
||||
cmistake(u, ord, 4, MSG_PRODUCE);
|
||||
break;
|
||||
case ENOMATERIALS:
|
||||
ADDMSG(&u->faction->msgs, msg_materials_required(u, ord,
|
||||
btype->construction, want));
|
||||
break;
|
||||
case ELOWSKILL:
|
||||
case ENEEDSKILL:
|
||||
/* no skill, or not enough skill points to build */
|
||||
cmistake(u, ord, 50, MSG_PRODUCE);
|
||||
break;
|
||||
built = build_stages(u, btype, built, n);
|
||||
|
||||
if (built < 0) {
|
||||
return build_failure(u, ord, btype, want, built);
|
||||
}
|
||||
if (built <= 0) {
|
||||
return built;
|
||||
}
|
||||
/* at this point, the building size is increased. */
|
||||
if (b == NULL) {
|
||||
|
||||
if (b) {
|
||||
b->size += built;
|
||||
} else {
|
||||
/* build a new building */
|
||||
b = new_building(btype, r, lang);
|
||||
b->size = built;
|
||||
b->type = btype;
|
||||
fset(b, BLD_MAINTAINED);
|
||||
|
||||
|
@ -818,7 +856,7 @@ build_building(unit * u, const building_type * btype, int id, int want, order *
|
|||
|
||||
btname = LOC(lang, btype->_name);
|
||||
|
||||
if (want - built <= 0) {
|
||||
if (want <= built) {
|
||||
/* geb<65>ude fertig */
|
||||
new_order = default_order(lang);
|
||||
}
|
||||
|
@ -850,7 +888,9 @@ build_building(unit * u, const building_type * btype, int id, int want, order *
|
|||
free_order(new_order);
|
||||
}
|
||||
|
||||
b->size += built;
|
||||
ADDMSG(&u->faction->msgs, msg_message("buildbuilding",
|
||||
"building unit size", b, u, built));
|
||||
|
||||
if (b->type->maxsize > 0 && b->size > b->type->maxsize) {
|
||||
log_error("build: %s has size=%d, maxsize=%d", buildingname(b), b->size, b->type->maxsize);
|
||||
}
|
||||
|
@ -858,8 +898,6 @@ build_building(unit * u, const building_type * btype, int id, int want, order *
|
|||
|
||||
update_lighthouse(b);
|
||||
|
||||
ADDMSG(&u->faction->msgs, msg_message("buildbuilding",
|
||||
"building unit size", b, u, built));
|
||||
return built;
|
||||
}
|
||||
|
||||
|
@ -970,7 +1008,6 @@ void continue_ship(unit * u, int want)
|
|||
return;
|
||||
}
|
||||
cons = sh->type->construction;
|
||||
assert(cons->improvement == NULL); /* sonst ist construction::size nicht ship_type::maxsize */
|
||||
if (sh->size == cons->maxsize && !sh->damage) {
|
||||
cmistake(u, u->thisorder, 16, MSG_PRODUCE);
|
||||
return;
|
||||
|
@ -994,11 +1031,6 @@ void continue_ship(unit * u, int want)
|
|||
|
||||
void free_construction(struct construction *cons)
|
||||
{
|
||||
while (cons) {
|
||||
construction *next = cons->improvement;
|
||||
free(cons->name);
|
||||
free(cons->materials);
|
||||
free(cons);
|
||||
cons = next;
|
||||
}
|
||||
free(cons->materials);
|
||||
free(cons);
|
||||
}
|
||||
|
|
|
@ -37,25 +37,13 @@ extern "C" {
|
|||
int number;
|
||||
} requirement;
|
||||
|
||||
typedef enum construct_t {
|
||||
CONS_OTHER,
|
||||
CONS_ITEM,
|
||||
CONS_BUILDING
|
||||
} construct_t;
|
||||
|
||||
typedef struct construction {
|
||||
construct_t type;
|
||||
skill_t skill; /* skill req'd per point of size */
|
||||
int minskill; /* skill req'd per point of size */
|
||||
|
||||
int maxsize; /* maximum size of this type */
|
||||
int reqsize; /* size of object using up 1 set of requirement. */
|
||||
requirement *materials; /* material req'd to build one object */
|
||||
|
||||
/* only used by CONS_BUILDING: */
|
||||
char * name; /* building level name */
|
||||
struct construction *improvement;
|
||||
/* next level, if upgradable. */
|
||||
} construction;
|
||||
|
||||
void free_construction(struct construction *cons);
|
||||
|
|
|
@ -26,6 +26,7 @@ typedef struct build_fixture {
|
|||
region *r;
|
||||
race *rc;
|
||||
construction cons;
|
||||
building_type *btype;
|
||||
} build_fixture;
|
||||
|
||||
static unit * setup_build(build_fixture *bf) {
|
||||
|
@ -34,7 +35,7 @@ static unit * setup_build(build_fixture *bf) {
|
|||
init_resources();
|
||||
|
||||
test_create_itemtype("stone");
|
||||
test_create_buildingtype("castle");
|
||||
bf->btype = test_create_buildingtype("castle");
|
||||
bf->rc = test_create_race("human");
|
||||
bf->r = test_create_region(0, 0, NULL);
|
||||
bf->f = test_create_faction(bf->rc);
|
||||
|
@ -192,8 +193,7 @@ static void test_build_building_no_materials(CuTest *tc) {
|
|||
unit *u;
|
||||
|
||||
u = setup_build(&bf);
|
||||
btype = bt_find("castle");
|
||||
assert(btype);
|
||||
btype = bf.btype;
|
||||
set_level(u, SK_BUILDING, 1);
|
||||
u->orders = create_order(K_MAKE, u->faction->locale, 0);
|
||||
CuAssertIntEquals(tc, ENOMATERIALS, build_building(u, btype, 0, 4, u->orders));
|
||||
|
@ -209,9 +209,7 @@ static void test_build_building_with_golem(CuTest *tc) {
|
|||
|
||||
u = setup_build(&bf);
|
||||
bf.rc->ec_flags |= ECF_STONEGOLEM;
|
||||
btype = bt_find("castle");
|
||||
assert(btype);
|
||||
assert(btype->construction);
|
||||
btype = bf.btype;
|
||||
|
||||
set_level(bf.u, SK_BUILDING, 1);
|
||||
u->orders = create_order(K_MAKE, u->faction->locale, 0);
|
||||
|
@ -231,9 +229,8 @@ static void test_build_building_success(CuTest *tc) {
|
|||
u = setup_build(&bf);
|
||||
|
||||
rtype = get_resourcetype(R_STONE);
|
||||
btype = bt_find("castle");
|
||||
btype = bf.btype;
|
||||
assert(btype && rtype && rtype->itype);
|
||||
assert(btype->construction);
|
||||
assert(!u->region->buildings);
|
||||
|
||||
i_change(&bf.u->items, rtype->itype, 1);
|
||||
|
|
|
@ -116,7 +116,13 @@ static void bt_register(building_type * btype)
|
|||
|
||||
static void free_buildingtype(void *ptr) {
|
||||
building_type *btype = (building_type *)ptr;
|
||||
free_construction(btype->construction);
|
||||
while (btype->stages) {
|
||||
building_stage *next = btype->stages->next;
|
||||
free_construction(btype->stages->construction);
|
||||
free(btype->stages->name);
|
||||
free(btype->stages);
|
||||
btype->stages = next;
|
||||
}
|
||||
free(btype->maintenance);
|
||||
free(btype->_name);
|
||||
free(btype);
|
||||
|
@ -189,8 +195,6 @@ static int adjust_size(const building *b, int bsize) {
|
|||
*/
|
||||
const char *buildingtype(const building_type * btype, const building * b, int bsize)
|
||||
{
|
||||
const construction *con;
|
||||
|
||||
assert(btype);
|
||||
|
||||
if (b && b->attribs) {
|
||||
|
@ -201,14 +205,15 @@ const char *buildingtype(const building_type * btype, const building * b, int bs
|
|||
}
|
||||
}
|
||||
}
|
||||
if (btype->construction && btype->construction->name) {
|
||||
if (btype->stages && btype->stages->name) {
|
||||
const building_stage *stage;
|
||||
if (b) {
|
||||
bsize = adjust_size(b, bsize);
|
||||
}
|
||||
for (con = btype->construction; con; con = con->improvement) {
|
||||
bsize -= con->maxsize;
|
||||
if (!con->improvement || bsize <0) {
|
||||
return con->name;
|
||||
for (stage = btype->stages; stage; stage = stage->next) {
|
||||
bsize -= stage->construction->maxsize;
|
||||
if (!stage->next || bsize <0) {
|
||||
return stage->name;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -476,24 +481,30 @@ int buildingeffsize(const building * b, int img)
|
|||
|
||||
int bt_effsize(const building_type * btype, const building * b, int bsize)
|
||||
{
|
||||
int n = 0;
|
||||
const construction *cons = btype->construction;
|
||||
|
||||
if (b) {
|
||||
bsize = adjust_size(b, bsize);
|
||||
}
|
||||
|
||||
if (!cons) {
|
||||
return 0;
|
||||
if (btype->stages) {
|
||||
int n = 0;
|
||||
const building_stage *stage = btype->stages;
|
||||
do {
|
||||
const construction *con = stage->construction;
|
||||
if (con->maxsize < 0) {
|
||||
break;
|
||||
}
|
||||
else {
|
||||
if (bsize >= con->maxsize) {
|
||||
bsize -= con->maxsize;
|
||||
++n;
|
||||
}
|
||||
stage = stage->next;
|
||||
}
|
||||
} while (stage && bsize > 0);
|
||||
return n;
|
||||
}
|
||||
|
||||
while (cons && cons->maxsize != -1 && bsize >= cons->maxsize) {
|
||||
bsize -= cons->maxsize;
|
||||
cons = cons->improvement;
|
||||
++n;
|
||||
}
|
||||
|
||||
return n;
|
||||
return 0;
|
||||
}
|
||||
|
||||
const char *write_buildingname(const building * b, char *ibuf, size_t size)
|
||||
|
|
|
@ -54,6 +54,15 @@ extern "C" {
|
|||
#define BTF_NAMECHANGE 0x100 /* name and description can be changed more than once */
|
||||
#define BTF_FORTIFICATION 0x200 /* building_protection, safe from monsters */
|
||||
|
||||
typedef struct building_stage {
|
||||
/* construction of this building stage: */
|
||||
struct construction *construction;
|
||||
/* building stage name: */
|
||||
char * name;
|
||||
/* next stage, if upgradable: */
|
||||
struct building_stage * next;
|
||||
} building_stage;
|
||||
|
||||
typedef struct building_type {
|
||||
char *_name;
|
||||
|
||||
|
@ -67,8 +76,8 @@ extern "C" {
|
|||
int taxes; /* receive $1 tax per `taxes` in region */
|
||||
double auraregen; /* modifier for aura regeneration inside building */
|
||||
struct maintenance *maintenance; /* array of requirements */
|
||||
struct construction *construction; /* construction of 1 building-level */
|
||||
struct resource_mod *modifiers; /* modify production skills */
|
||||
struct building_stage *stages;
|
||||
} building_type;
|
||||
|
||||
extern struct selist *buildingtypes;
|
||||
|
|
|
@ -224,7 +224,7 @@ static void test_buildingowner_goes_to_same_faction_after_leave(CuTest * tc)
|
|||
leave_building(u3);
|
||||
CuAssertPtrEquals(tc, u2, building_owner(bld));
|
||||
leave_building(u2);
|
||||
CuAssertPtrEquals(tc, 0, building_owner(bld));
|
||||
CuAssertPtrEquals(tc, NULL, building_owner(bld));
|
||||
test_teardown();
|
||||
}
|
||||
|
||||
|
@ -281,7 +281,7 @@ void test_buildingowner_goes_to_empty_unit_after_leave(CuTest * tc)
|
|||
leave_building(u1);
|
||||
CuAssertPtrEquals(tc, u3, building_owner(bld));
|
||||
leave_building(u3);
|
||||
CuAssertPtrEquals(tc, 0, building_owner(bld));
|
||||
CuAssertPtrEquals(tc, NULL, building_owner(bld));
|
||||
u2->number = 1;
|
||||
CuAssertPtrEquals(tc, u2, building_owner(bld));
|
||||
test_teardown();
|
||||
|
@ -295,8 +295,8 @@ static void test_btype_defaults(CuTest *tc) {
|
|||
btype = bt_get_or_create("hodor");
|
||||
CuAssertPtrNotNull(tc, btype);
|
||||
CuAssertStrEquals(tc, "hodor", btype->_name);
|
||||
CuAssertPtrEquals(tc, 0, btype->maintenance);
|
||||
CuAssertPtrEquals(tc, 0, btype->construction);
|
||||
CuAssertPtrEquals(tc, NULL, btype->maintenance);
|
||||
CuAssertPtrEquals(tc, NULL, btype->stages);
|
||||
CuAssertDblEquals(tc, 1.0, btype->auraregen, 0.0);
|
||||
CuAssertIntEquals(tc, 0, btype->taxes);
|
||||
CuAssertIntEquals(tc, -1, btype->maxsize);
|
||||
|
@ -489,11 +489,11 @@ static void test_cmp_current_owner(CuTest *tc) {
|
|||
config_set("rules.region_owners", "1");
|
||||
r = test_create_region(0, 0, NULL);
|
||||
btype = test_create_buildingtype("watch");
|
||||
btype->construction->maxsize = 1;
|
||||
btype->stages->construction->maxsize = 1;
|
||||
btype->taxes = 200;
|
||||
b1 = test_create_building(r, btype);
|
||||
btype = test_create_buildingtype("castle");
|
||||
btype->construction->maxsize = 1;
|
||||
btype->stages->construction->maxsize = 1;
|
||||
btype->taxes = 100;
|
||||
b2 = test_create_building(r, btype);
|
||||
b1->size = 1;
|
||||
|
@ -515,16 +515,26 @@ static void test_cmp_current_owner(CuTest *tc) {
|
|||
static void test_building_effsize(CuTest *tc) {
|
||||
building *b;
|
||||
building_type *btype;
|
||||
building_stage *stage;
|
||||
construction *cons;
|
||||
|
||||
test_setup();
|
||||
btype = bt_get_or_create("castle");
|
||||
cons = btype->construction = calloc(1, sizeof(construction));
|
||||
btype = test_create_buildingtype("castle");
|
||||
stage = btype->stages;
|
||||
assert(stage && stage->construction);
|
||||
cons = stage->construction;
|
||||
cons->maxsize = 5;
|
||||
cons = cons->improvement = calloc(1, sizeof(construction));
|
||||
|
||||
stage->next = calloc(1, sizeof(building_stage));
|
||||
stage = stage->next;
|
||||
cons = stage->construction = calloc(1, sizeof(construction));
|
||||
cons->maxsize = 5;
|
||||
cons = cons->improvement = calloc(1, sizeof(construction));
|
||||
|
||||
stage->next = calloc(1, sizeof(building_stage));
|
||||
stage = stage->next;
|
||||
cons = stage->construction = calloc(1, sizeof(construction));
|
||||
cons->maxsize = -1;
|
||||
|
||||
b = test_create_building(test_create_region(0,0,0), btype);
|
||||
b->size = 1;
|
||||
CuAssertIntEquals(tc, 0, buildingeffsize(b, false));
|
||||
|
@ -563,14 +573,20 @@ static void test_largestbuilding(CuTest *tc) {
|
|||
static void test_buildingtype(CuTest *tc) {
|
||||
building_type *btype;
|
||||
test_setup();
|
||||
|
||||
btype = test_create_buildingtype("hodor");
|
||||
CuAssertPtrNotNull(tc, btype->construction);
|
||||
CuAssertPtrNotNull(tc, btype->stages);
|
||||
CuAssertPtrEquals(tc, NULL, btype->stages->name);
|
||||
CuAssertPtrNotNull(tc, btype->stages->construction);
|
||||
CuAssertStrEquals(tc, "hodor", buildingtype(btype, NULL, 1));
|
||||
btype->construction->name = str_strdup("castle");
|
||||
|
||||
btype->stages->name = str_strdup("castle");
|
||||
CuAssertStrEquals(tc, "castle", buildingtype(btype, NULL, 1));
|
||||
|
||||
btype = bt_get_or_create("portal");
|
||||
CuAssertPtrEquals(tc, NULL, btype->construction);
|
||||
CuAssertPtrEquals(tc, NULL, btype->stages);
|
||||
CuAssertStrEquals(tc, "portal", buildingtype(btype, NULL, 1));
|
||||
|
||||
test_teardown();
|
||||
}
|
||||
|
||||
|
|
|
@ -26,7 +26,8 @@ order_data *db_driver_order_load(int id)
|
|||
{
|
||||
order_data * od = NULL;
|
||||
int err;
|
||||
|
||||
|
||||
ERRNO_CHECK();
|
||||
if (g_order_tx_size > 0) {
|
||||
g_order_tx_size = 0;
|
||||
err = sqlite3_exec(g_db, "COMMIT", NULL, NULL, NULL);
|
||||
|
@ -45,10 +46,12 @@ order_data *db_driver_order_load(int id)
|
|||
assert(bytes > 0);
|
||||
text = sqlite3_column_text(g_stmt_select, 0);
|
||||
odata_create(&od, 1+(size_t)bytes, (const char *)text);
|
||||
ERRNO_CHECK();
|
||||
return od;
|
||||
}
|
||||
} while (err == SQLITE_ROW);
|
||||
assert(err == SQLITE_DONE);
|
||||
ERRNO_CHECK();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -58,7 +61,9 @@ int db_driver_order_save(order_data *od)
|
|||
sqlite3_int64 id;
|
||||
|
||||
assert(od && od->_str);
|
||||
|
||||
|
||||
ERRNO_CHECK();
|
||||
|
||||
if (g_order_batchsize > 0) {
|
||||
if (g_order_tx_size == 0) {
|
||||
err = sqlite3_exec(g_db, "BEGIN TRANSACTION", NULL, NULL, NULL);
|
||||
|
@ -82,7 +87,7 @@ int db_driver_order_save(order_data *od)
|
|||
g_order_tx_size = 0;
|
||||
}
|
||||
}
|
||||
|
||||
ERRNO_CHECK();
|
||||
return (int)id;
|
||||
}
|
||||
|
||||
|
@ -91,6 +96,7 @@ void db_driver_open(void)
|
|||
int err;
|
||||
const char *dbname;
|
||||
|
||||
ERRNO_CHECK();
|
||||
g_order_batchsize = config_get_int("game.dbbatch", 100);
|
||||
dbname = config_get("game.dbname");
|
||||
if (!dbname) {
|
||||
|
@ -108,16 +114,20 @@ void db_driver_open(void)
|
|||
assert(err == SQLITE_OK);
|
||||
err = sqlite3_prepare_v2(g_db, "SELECT data FROM orders WHERE id = ?", -1, &g_stmt_select, NULL);
|
||||
assert(err == SQLITE_OK);
|
||||
ERRNO_CHECK();
|
||||
}
|
||||
|
||||
void db_driver_close(void)
|
||||
{
|
||||
int err;
|
||||
|
||||
ERRNO_CHECK();
|
||||
err = sqlite3_finalize(g_stmt_select);
|
||||
assert(err == SQLITE_OK);
|
||||
err = sqlite3_finalize(g_stmt_insert);
|
||||
assert(err == SQLITE_OK);
|
||||
err = sqlite3_close(g_db);
|
||||
assert(err == SQLITE_OK);
|
||||
ERRNO_CHECK();
|
||||
}
|
||||
|
||||
|
|
|
@ -609,16 +609,6 @@ mod_elves_only(const unit * u, const region * r, skill_t sk, int value)
|
|||
return -118;
|
||||
}
|
||||
|
||||
static int
|
||||
mod_dwarves_only(const unit * u, const region * r, skill_t sk, int value)
|
||||
{
|
||||
UNUSED_ARG(r);
|
||||
if (u_race(u) == get_race(RC_DWARF) || (u_race(u)->ec_flags & ECF_IRONGOLEM)) {
|
||||
return value;
|
||||
}
|
||||
return -118;
|
||||
}
|
||||
|
||||
void
|
||||
register_item_give(int(*foo) (struct unit *, struct unit *,
|
||||
const struct item_type *, int, struct order *), const char *name)
|
||||
|
@ -910,7 +900,9 @@ void write_items(struct storage *store, item * ilist)
|
|||
|
||||
static void free_itype(item_type *itype) {
|
||||
assert(itype);
|
||||
free_construction(itype->construction);
|
||||
if (itype->construction) {
|
||||
free_construction(itype->construction);
|
||||
}
|
||||
free(itype->_appearance[0]);
|
||||
free(itype->_appearance[1]);
|
||||
free(itype);
|
||||
|
@ -973,7 +965,6 @@ void register_resources(void)
|
|||
registered = true;
|
||||
|
||||
register_function((pf_generic)mod_elves_only, "mod_elves_only");
|
||||
register_function((pf_generic)mod_dwarves_only, "mod_dwarves_only");
|
||||
register_function((pf_generic)res_changeitem, "changeitem");
|
||||
register_function((pf_generic)res_changeperson, "changeperson");
|
||||
register_function((pf_generic)res_changepeasants, "changepeasants");
|
||||
|
|
|
@ -147,8 +147,8 @@ extern "C" {
|
|||
struct race_list;
|
||||
typedef struct weapon_mod {
|
||||
int value;
|
||||
unsigned int flags;
|
||||
struct race_list *races;
|
||||
int flags;
|
||||
int race_mask;
|
||||
} weapon_mod;
|
||||
|
||||
#define ATF_NONE 0x00
|
||||
|
|
|
@ -365,6 +365,35 @@ static void test_study_order(CuTest *tc) {
|
|||
test_teardown();
|
||||
}
|
||||
|
||||
static void test_study_order_unknown(CuTest *tc) {
|
||||
char token[32];
|
||||
stream out;
|
||||
unit *u;
|
||||
struct locale *lang;
|
||||
|
||||
test_setup();
|
||||
lang = get_or_create_locale("de");
|
||||
locale_setstring(lang, "keyword::study", "LERNE");
|
||||
init_keywords(lang);
|
||||
init_skills(lang);
|
||||
u = test_create_unit(test_create_faction(NULL), test_create_plain(0, 0));
|
||||
u->thisorder = create_order(K_STUDY, lang, "Schiffsbau");
|
||||
CuAssertIntEquals(tc, K_STUDY, init_order(u->thisorder, lang));
|
||||
CuAssertStrEquals(tc, "Schiffsbau", gettoken(token, sizeof(token)));
|
||||
|
||||
CuAssertStrEquals(tc, "LERNE Schiffsbau", get_command(u->thisorder, lang, token, sizeof(token)));
|
||||
|
||||
mstream_init(&out);
|
||||
stream_order(&out, u->thisorder, lang, true);
|
||||
swrite("\n", 1, 1, &out);
|
||||
out.api->rewind(out.handle);
|
||||
out.api->readln(out.handle, token, sizeof(token));
|
||||
CuAssertStrEquals(tc, "LERNE Schiffsbau", token);
|
||||
mstream_done(&out);
|
||||
|
||||
test_teardown();
|
||||
}
|
||||
|
||||
static void test_study_order_quoted(CuTest *tc) {
|
||||
char token[32];
|
||||
stream out;
|
||||
|
@ -395,12 +424,73 @@ static void test_study_order_quoted(CuTest *tc) {
|
|||
test_teardown();
|
||||
}
|
||||
|
||||
static void test_study_order_unknown_tilde(CuTest *tc) {
|
||||
char token[32];
|
||||
stream out;
|
||||
unit *u;
|
||||
struct locale *lang;
|
||||
|
||||
test_setup();
|
||||
lang = get_or_create_locale("de");
|
||||
locale_setstring(lang, "keyword::study", "LERNE");
|
||||
init_keywords(lang);
|
||||
init_skills(lang);
|
||||
u = test_create_unit(test_create_faction(NULL), test_create_plain(0, 0));
|
||||
u->thisorder = create_order(K_STUDY, lang, "Waffenloser~Mampf");
|
||||
CuAssertIntEquals(tc, K_STUDY, init_order(u->thisorder, lang));
|
||||
CuAssertStrEquals(tc, "Waffenloser Mampf", gettoken(token, sizeof(token)));
|
||||
|
||||
CuAssertStrEquals(tc, "LERNE Waffenloser~Mampf", get_command(u->thisorder, lang, token, sizeof(token)));
|
||||
|
||||
mstream_init(&out);
|
||||
stream_order(&out, u->thisorder, lang, true);
|
||||
swrite("\n", 1, 1, &out);
|
||||
out.api->rewind(out.handle);
|
||||
out.api->readln(out.handle, token, sizeof(token));
|
||||
CuAssertStrEquals(tc, "LERNE Waffenloser~Mampf", token);
|
||||
mstream_done(&out);
|
||||
|
||||
test_teardown();
|
||||
}
|
||||
|
||||
static void test_study_order_unknown_quoted(CuTest *tc) {
|
||||
char token[32];
|
||||
stream out;
|
||||
unit *u;
|
||||
struct locale *lang;
|
||||
|
||||
test_setup();
|
||||
lang = get_or_create_locale("de");
|
||||
locale_setstring(lang, "keyword::study", "LERNE");
|
||||
init_keywords(lang);
|
||||
init_skills(lang);
|
||||
u = test_create_unit(test_create_faction(NULL), test_create_plain(0, 0));
|
||||
u->thisorder = create_order(K_STUDY, lang, "'Waffenloser Dampf'");
|
||||
CuAssertIntEquals(tc, K_STUDY, init_order(u->thisorder, lang));
|
||||
CuAssertStrEquals(tc, "Waffenloser Dampf", gettoken(token, sizeof(token)));
|
||||
|
||||
CuAssertStrEquals(tc, "LERNE 'Waffenloser Dampf'", get_command(u->thisorder, lang, token, sizeof(token)));
|
||||
|
||||
mstream_init(&out);
|
||||
stream_order(&out, u->thisorder, lang, true);
|
||||
swrite("\n", 1, 1, &out);
|
||||
out.api->rewind(out.handle);
|
||||
out.api->readln(out.handle, token, sizeof(token));
|
||||
CuAssertStrEquals(tc, "LERNE 'Waffenloser Dampf'", token);
|
||||
mstream_done(&out);
|
||||
|
||||
test_teardown();
|
||||
}
|
||||
|
||||
CuSuite *get_order_suite(void)
|
||||
{
|
||||
CuSuite *suite = CuSuiteNew();
|
||||
SUITE_ADD_TEST(suite, test_create_order);
|
||||
SUITE_ADD_TEST(suite, test_study_orders);
|
||||
SUITE_ADD_TEST(suite, test_study_order);
|
||||
SUITE_ADD_TEST(suite, test_study_order_unknown);
|
||||
SUITE_ADD_TEST(suite, test_study_order_unknown_tilde);
|
||||
SUITE_ADD_TEST(suite, test_study_order_unknown_quoted);
|
||||
SUITE_ADD_TEST(suite, test_study_order_quoted);
|
||||
SUITE_ADD_TEST(suite, test_parse_order);
|
||||
SUITE_ADD_TEST(suite, test_parse_make);
|
||||
|
|
|
@ -259,7 +259,10 @@ void racelist_insert(struct race_list **rl, const struct race *r)
|
|||
*rl = rl2;
|
||||
}
|
||||
|
||||
static int race_mask = 0;
|
||||
|
||||
void free_races(void) {
|
||||
race_mask = 0;
|
||||
while (races) {
|
||||
int i;
|
||||
race * rc = races->next;
|
||||
|
@ -347,6 +350,10 @@ race *rc_create(const char *zName)
|
|||
|
||||
assert(zName);
|
||||
rc = (race *)calloc(sizeof(race), 1);
|
||||
|
||||
rc->mask_item = 1 << race_mask;
|
||||
++race_mask;
|
||||
|
||||
rc->magres.sa[1] = 1;
|
||||
rc->hitpoints = 1;
|
||||
rc->weight = PERSON_WEIGHT;
|
||||
|
@ -574,3 +581,19 @@ struct race * read_race_reference(struct storage *store)
|
|||
void register_race_function(race_func func, const char *name) {
|
||||
register_function((pf_generic)func, name);
|
||||
}
|
||||
|
||||
int rc_mask(const race * rc) {
|
||||
assert(rc->mask_item);
|
||||
return rc->mask_item;
|
||||
}
|
||||
|
||||
int rc_get_mask(char *list) {
|
||||
int mask = 0;
|
||||
char * tok = strtok(list, " ,");
|
||||
while (tok) {
|
||||
race * rc = rc_get_or_create(tok);
|
||||
mask |= rc_mask(rc);
|
||||
tok = strtok(NULL, " ,");
|
||||
}
|
||||
return mask;
|
||||
}
|
||||
|
|
|
@ -197,6 +197,9 @@ extern "C" {
|
|||
#define MIGRANTS_NONE 0
|
||||
#define MIGRANTS_LOG10 1
|
||||
int rc_migrants_formula(const race *rc);
|
||||
|
||||
int rc_mask(const race *rc);
|
||||
int rc_get_mask(char *list);
|
||||
|
||||
/* Flags. Do not reorder these without changing json_race() in jsonconf.c */
|
||||
#define RCF_NPC (1<<0) /* cannot be the race for a player faction (and other limits?) */
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#include <CuTest.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <limits.h>
|
||||
#include <assert.h>
|
||||
|
||||
|
@ -25,6 +26,18 @@ static void test_rc_name(CuTest *tc) {
|
|||
test_teardown();
|
||||
}
|
||||
|
||||
static void test_rc_item_mask(CuTest *tc) {
|
||||
struct race *rc;
|
||||
test_setup();
|
||||
rc = rc_get_or_create("hooman");
|
||||
CuAssertIntEquals(tc, 1, rc->mask_item);
|
||||
rc = rc_get_or_create("aelf");
|
||||
CuAssertIntEquals(tc, 2, rc->mask_item);
|
||||
rc = rc_get_or_create("dorf");
|
||||
CuAssertIntEquals(tc, 4, rc->mask_item);
|
||||
test_teardown();
|
||||
}
|
||||
|
||||
static void test_rc_defaults(CuTest *tc) {
|
||||
struct race *rc;
|
||||
test_setup();
|
||||
|
@ -172,6 +185,19 @@ static void test_racename(CuTest *tc) {
|
|||
test_teardown();
|
||||
}
|
||||
|
||||
static void test_rc_mask(CuTest *tc) {
|
||||
int mask;
|
||||
char list[64];
|
||||
test_setup();
|
||||
strcpy(list, "goblin dwarf");
|
||||
mask = rc_get_mask(list);
|
||||
CuAssertIntEquals(tc, 3, mask);
|
||||
CuAssertStrEquals(tc, "goblin", list);
|
||||
mask = rc_get_mask(list);
|
||||
CuAssertIntEquals(tc, 1, mask);
|
||||
test_teardown();
|
||||
}
|
||||
|
||||
CuSuite *get_race_suite(void)
|
||||
{
|
||||
CuSuite *suite = CuSuiteNew();
|
||||
|
@ -179,7 +205,9 @@ CuSuite *get_race_suite(void)
|
|||
SUITE_ADD_TEST(suite, test_old_race);
|
||||
SUITE_ADD_TEST(suite, test_rc_name);
|
||||
SUITE_ADD_TEST(suite, test_rc_defaults);
|
||||
SUITE_ADD_TEST(suite, test_rc_item_mask);
|
||||
SUITE_ADD_TEST(suite, test_rc_find);
|
||||
SUITE_ADD_TEST(suite, test_rc_mask);
|
||||
SUITE_ADD_TEST(suite, test_rc_set_param);
|
||||
SUITE_ADD_TEST(suite, test_rc_can_use);
|
||||
SUITE_ADD_TEST(suite, test_racename);
|
||||
|
|
|
@ -50,7 +50,7 @@ extern "C" {
|
|||
resource_modifier_type type;
|
||||
variant value;
|
||||
const struct building_type *btype;
|
||||
const struct race *race;
|
||||
int race_mask;
|
||||
} resource_mod;
|
||||
|
||||
typedef struct rawmaterial_type {
|
||||
|
|
|
@ -127,6 +127,7 @@ ship_type *st_get_or_create(const char * name) {
|
|||
st = (ship_type *)calloc(sizeof(ship_type), 1);
|
||||
st->_name = str_strdup(name);
|
||||
st->storm = 1.0;
|
||||
st->tac_bonus = 1.0;
|
||||
st_register(st);
|
||||
}
|
||||
return st;
|
||||
|
@ -249,7 +250,9 @@ static void free_shiptype(void *ptr) {
|
|||
ship_type *stype = (ship_type *)ptr;
|
||||
free(stype->_name);
|
||||
free(stype->coasts);
|
||||
free_construction(stype->construction);
|
||||
if (stype->construction) {
|
||||
free_construction(stype->construction);
|
||||
}
|
||||
free(stype);
|
||||
}
|
||||
|
||||
|
@ -328,7 +331,6 @@ int shipspeed(const ship * sh, const unit * u)
|
|||
assert(u->ship == sh);
|
||||
assert(u == ship_owner(sh));
|
||||
assert(sh->type->construction);
|
||||
assert(sh->type->construction->improvement == NULL); /* sonst ist construction::size nicht ship_type::maxsize */
|
||||
|
||||
k = sh->type->range;
|
||||
if (sh->size != sh->type->construction->maxsize)
|
||||
|
@ -396,10 +398,6 @@ int shipcapacity(const ship * sh)
|
|||
{
|
||||
int i = sh->type->cargo;
|
||||
|
||||
/* sonst ist construction:: size nicht ship_type::maxsize */
|
||||
assert(!sh->type->construction
|
||||
|| sh->type->construction->improvement == NULL);
|
||||
|
||||
if (sh->type->construction && sh->size != sh->type->construction->maxsize)
|
||||
return 0;
|
||||
|
||||
|
|
|
@ -36,6 +36,8 @@ extern "C" {
|
|||
#define SFL_NOCOAST 0x04
|
||||
#define SFL_SPEEDY 0x08
|
||||
|
||||
#define SFL_DEFAULT 0
|
||||
|
||||
typedef struct ship_type {
|
||||
char *_name;
|
||||
|
||||
|
@ -57,7 +59,7 @@ extern "C" {
|
|||
|
||||
int at_bonus; /* Ver<65>ndert den Angriffsskill (default: 0) */
|
||||
int df_bonus; /* Ver<65>ndert den Verteidigungskill (default: 0) */
|
||||
float tac_bonus;
|
||||
double tac_bonus;
|
||||
|
||||
struct terrain_type ** coasts; /* coast that this ship can land on */
|
||||
|
||||
|
|
|
@ -369,7 +369,7 @@ static void test_stype_defaults(CuTest *tc) {
|
|||
CuAssertPtrEquals(tc, 0, stype->coasts);
|
||||
CuAssertDblEquals(tc, 0.0, stype->damage, 0.0);
|
||||
CuAssertDblEquals(tc, 1.0, stype->storm, 0.0);
|
||||
CuAssertDblEquals(tc, 0.0, stype->tac_bonus, 0.0);
|
||||
CuAssertDblEquals(tc, 1.0, stype->tac_bonus, 0.01);
|
||||
CuAssertIntEquals(tc, 0, stype->cabins);
|
||||
CuAssertIntEquals(tc, 0, stype->cargo);
|
||||
CuAssertIntEquals(tc, 0, stype->combat);
|
||||
|
|
|
@ -180,19 +180,37 @@ struct spellref *spellref_create(spell *sp, const char *name)
|
|||
|
||||
if (sp) {
|
||||
spref->sp = sp;
|
||||
spref->name = str_strdup(sp->sname);
|
||||
spref->_name = str_strdup(sp->sname);
|
||||
}
|
||||
else if (name) {
|
||||
spref->name = str_strdup(name);
|
||||
spref->_name = str_strdup(name);
|
||||
spref->sp = NULL;
|
||||
}
|
||||
return spref;
|
||||
}
|
||||
|
||||
void spellref_init(spellref *spref, spell *sp, const char *name)
|
||||
{
|
||||
if (sp) {
|
||||
spref->sp = sp;
|
||||
spref->_name = str_strdup(sp->sname);
|
||||
}
|
||||
else if (name) {
|
||||
spref->_name = str_strdup(name);
|
||||
spref->sp = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void spellref_done(spellref *spref) {
|
||||
if (spref) {
|
||||
free(spref->_name);
|
||||
}
|
||||
}
|
||||
|
||||
void spellref_free(spellref *spref)
|
||||
{
|
||||
if (spref) {
|
||||
free(spref->name);
|
||||
spellref_done(spref);
|
||||
free(spref);
|
||||
}
|
||||
}
|
||||
|
@ -200,12 +218,21 @@ void spellref_free(spellref *spref)
|
|||
struct spell *spellref_get(struct spellref *spref)
|
||||
{
|
||||
if (!spref->sp) {
|
||||
assert(spref->name);
|
||||
spref->sp = find_spell(spref->name);
|
||||
assert(spref->_name);
|
||||
spref->sp = find_spell(spref->_name);
|
||||
if (spref->sp) {
|
||||
free(spref->name);
|
||||
spref->name = NULL;
|
||||
free(spref->_name);
|
||||
spref->_name = NULL;
|
||||
}
|
||||
}
|
||||
return spref->sp;
|
||||
}
|
||||
|
||||
const char *spellref_name(const struct spellref *spref)
|
||||
{
|
||||
if (spref->_name) {
|
||||
return spref->_name;
|
||||
}
|
||||
assert(spref->sp);
|
||||
return spref->sp->sname;
|
||||
}
|
||||
|
|
|
@ -43,7 +43,7 @@ extern "C" {
|
|||
} spell;
|
||||
|
||||
typedef struct spellref {
|
||||
char * name;
|
||||
char * _name;
|
||||
struct spell *sp;
|
||||
} spellref;
|
||||
|
||||
|
@ -56,6 +56,10 @@ extern "C" {
|
|||
struct spellref *spellref_create(struct spell *sp, const char *name);
|
||||
void spellref_free(struct spellref *spref);
|
||||
struct spell *spellref_get(struct spellref *spref);
|
||||
const char *spellref_name(const struct spellref *spref);
|
||||
|
||||
void spellref_init(struct spellref *spref, struct spell *sp, const char *name);
|
||||
void spellref_done(struct spellref *spref);
|
||||
|
||||
int sp_antimagiczone(struct castorder *co);
|
||||
|
||||
|
|
|
@ -58,8 +58,9 @@ static void test_spellref(CuTest *tc)
|
|||
ref = spellref_create(NULL, "hodor");
|
||||
CuAssertPtrNotNull(tc, ref);
|
||||
CuAssertPtrEquals(tc, NULL, ref->sp);
|
||||
CuAssertStrEquals(tc, "hodor", ref->name);
|
||||
CuAssertStrEquals(tc, "hodor", ref->_name);
|
||||
CuAssertPtrEquals(tc, NULL, spellref_get(ref));
|
||||
CuAssertStrEquals(tc, "hodor", spellref_name(ref));
|
||||
sp = create_spell("hodor");
|
||||
CuAssertPtrNotNull(tc, sp);
|
||||
CuAssertPtrEquals(tc, sp, spellref_get(ref));
|
||||
|
|
|
@ -67,13 +67,23 @@ void write_spellbook(const struct spellbook *book, struct storage *store)
|
|||
if (book) {
|
||||
for (ql = book->spells, qi = 0; ql; selist_advance(&ql, &qi, 1)) {
|
||||
spellbook_entry *sbe = (spellbook_entry *)selist_get(ql, qi);
|
||||
WRITE_TOK(store, sbe->sp->sname);
|
||||
WRITE_TOK(store, spellref_name(&sbe->spref));
|
||||
WRITE_INT(store, sbe->level);
|
||||
}
|
||||
}
|
||||
WRITE_TOK(store, "end");
|
||||
}
|
||||
|
||||
void spellbook_addref(spellbook *sb, const char *name, int level) {
|
||||
spellbook_entry * sbe;
|
||||
|
||||
assert(sb && name && level > 0);
|
||||
sbe = (spellbook_entry *)malloc(sizeof(spellbook_entry));
|
||||
spellref_init(&sbe->spref, NULL, name);
|
||||
sbe->level = level;
|
||||
selist_push(&sb->spells, sbe);
|
||||
}
|
||||
|
||||
void spellbook_add(spellbook *sb, spell *sp, int level)
|
||||
{
|
||||
spellbook_entry * sbe;
|
||||
|
@ -85,7 +95,7 @@ void spellbook_add(spellbook *sb, spell *sp, int level)
|
|||
}
|
||||
#endif
|
||||
sbe = (spellbook_entry *)malloc(sizeof(spellbook_entry));
|
||||
sbe->sp = sp;
|
||||
spellref_init(&sbe->spref, sp, NULL);
|
||||
sbe->level = level;
|
||||
selist_push(&sb->spells, sbe);
|
||||
}
|
||||
|
@ -98,6 +108,7 @@ void spellbook_clear(spellbook *sb)
|
|||
assert(sb);
|
||||
for (qi = 0, ql = sb->spells; ql; selist_advance(&ql, &qi, 1)) {
|
||||
spellbook_entry *sbe = (spellbook_entry *)selist_get(ql, qi);
|
||||
spellref_done(&sbe->spref);
|
||||
free(sbe);
|
||||
}
|
||||
selist_free(sb->spells);
|
||||
|
@ -127,7 +138,7 @@ spellbook_entry * spellbook_get(spellbook *sb, const struct spell *sp)
|
|||
|
||||
for (qi = 0, ql = sb->spells; ql; selist_advance(&ql, &qi, 1)) {
|
||||
spellbook_entry *sbe = (spellbook_entry *)selist_get(ql, qi);
|
||||
if (sbe->sp==sp) {
|
||||
if (spellref_get(&sbe->spref) == sp) {
|
||||
return sbe;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,17 +19,18 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|||
#ifndef H_KRNL_SPELLBOOK_H
|
||||
#define H_KRNL_SPELLBOOK_H
|
||||
|
||||
#include "spell.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct spell;
|
||||
struct storage;
|
||||
struct gamedata;
|
||||
struct selist;
|
||||
|
||||
typedef struct spellbook_entry {
|
||||
struct spell *sp;
|
||||
spellref spref;
|
||||
int level;
|
||||
} spellbook_entry;
|
||||
|
||||
|
@ -45,6 +46,7 @@ extern "C" {
|
|||
void write_spellbook(const struct spellbook *book, struct storage *store);
|
||||
|
||||
void spellbook_add(spellbook *sbp, struct spell *sp, int level);
|
||||
void spellbook_addref(spellbook *sb, const char *name, int level);
|
||||
int spellbook_foreach(spellbook *sb, int(*callback)(spellbook_entry *, void *), void * data);
|
||||
void spellbook_clear(spellbook *sb);
|
||||
spellbook_entry * spellbook_get(spellbook *sb, const struct spell *sp);
|
||||
|
|
|
@ -40,7 +40,7 @@ void test_named_spellbooks(CuTest * tc)
|
|||
sbe = spellbook_get(sb, sp);
|
||||
CuAssertPtrNotNull(tc, sbe);
|
||||
CuAssertIntEquals(tc, 1, sbe->level);
|
||||
CuAssertPtrEquals(tc, sp, sbe->sp);
|
||||
CuAssertPtrEquals(tc, sp, spellref_get(&sbe->spref));
|
||||
|
||||
spellbook_foreach(sb, count_spell_cb, &counter);
|
||||
CuAssertIntEquals(tc, 1, counter);
|
||||
|
|
|
@ -11,7 +11,7 @@ extern "C"
|
|||
|
||||
struct locale;
|
||||
|
||||
typedef enum {
|
||||
typedef enum keyword_t {
|
||||
K_KOMMENTAR,
|
||||
K_BANNER,
|
||||
K_WORK,
|
||||
|
|
|
@ -3298,8 +3298,9 @@ static void copy_spells(const spellbook * src, spellbook * dst, int maxlevel)
|
|||
for (qi = 0, ql = src->spells; ql; selist_advance(&ql, &qi, 1)) {
|
||||
spellbook_entry * sbe = (spellbook_entry *)selist_get(ql, qi);
|
||||
if (sbe->level <= maxlevel) {
|
||||
if (!spellbook_get(dst, sbe->sp)) {
|
||||
spellbook_add(dst, sbe->sp, sbe->level);
|
||||
spell *sp = spellref_get(&sbe->spref);
|
||||
if (!spellbook_get(dst, sp)) {
|
||||
spellbook_add(dst, sp, sbe->level);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3548,7 +3549,7 @@ enum {
|
|||
PROC_LONGORDER = 1 << 1
|
||||
};
|
||||
|
||||
typedef enum { PR_GLOBAL, PR_REGION_PRE, PR_UNIT, PR_ORDER, PR_REGION_POST } processor_t;
|
||||
typedef enum processor_t { PR_GLOBAL, PR_REGION_PRE, PR_UNIT, PR_ORDER, PR_REGION_POST } processor_t;
|
||||
|
||||
typedef struct processor {
|
||||
struct processor *next;
|
||||
|
|
25
src/magic.c
25
src/magic.c
|
@ -375,13 +375,16 @@ void pick_random_spells(faction * f, int level, spellbook * book, int num_spells
|
|||
sbe = 0;
|
||||
}
|
||||
else {
|
||||
if (f->spellbook && spellbook_get(f->spellbook, sbe->sp)) {
|
||||
/* already have this spell, remove it from the list of candidates */
|
||||
commonspells[spellno] = commonspells[--numspells];
|
||||
if (maxspell > numspells) {
|
||||
maxspell = numspells;
|
||||
if (f->spellbook) {
|
||||
const spell *sp = spellref_get(&sbe->spref);
|
||||
if (sp && spellbook_get(f->spellbook, sp)) {
|
||||
/* already have this spell, remove it from the list of candidates */
|
||||
commonspells[spellno] = commonspells[--numspells];
|
||||
if (maxspell > numspells) {
|
||||
maxspell = numspells;
|
||||
}
|
||||
sbe = 0;
|
||||
}
|
||||
sbe = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -390,7 +393,7 @@ void pick_random_spells(faction * f, int level, spellbook * book, int num_spells
|
|||
if (!f->spellbook) {
|
||||
f->spellbook = create_spellbook(0);
|
||||
}
|
||||
spellbook_add(f->spellbook, sbe->sp, sbe->level);
|
||||
spellbook_add(f->spellbook, spellref_get(&sbe->spref), sbe->level);
|
||||
commonspells[spellno] = commonspells[--numspells];
|
||||
}
|
||||
}
|
||||
|
@ -2840,14 +2843,14 @@ static void select_spellbook(void **tokens, spellbook *sb, const struct locale *
|
|||
|
||||
for (qi = 0, ql = sb->spells; ql; selist_advance(&ql, &qi, 1)) {
|
||||
spellbook_entry *sbe = (spellbook_entry *)selist_get(ql, qi);
|
||||
|
||||
const char *n = spell_name(sbe->sp, lang);
|
||||
const spell *sp = spellref_get(&sbe->spref);
|
||||
const char *n = spell_name(sp, lang);
|
||||
if (!n) {
|
||||
log_error("no translation in locale %s for spell %s\n", locale_name(lang), sbe->sp->sname);
|
||||
log_error("no translation in locale %s for spell %s\n", locale_name(lang), sp->sname);
|
||||
}
|
||||
else {
|
||||
variant token;
|
||||
token.v = sbe->sp;
|
||||
token.v = (void *)sp;
|
||||
addtoken((struct tnode **)tokens, n, token);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -86,7 +86,7 @@ static void test_spellbooks(CuTest * tc)
|
|||
CuAssertPtrNotNull(tc, sp);
|
||||
entry = spellbook_get(herp, sp);
|
||||
CuAssertPtrNotNull(tc, entry);
|
||||
CuAssertPtrEquals(tc, sp, entry->sp);
|
||||
CuAssertPtrEquals(tc, sp, spellref_get(&entry->spref));
|
||||
|
||||
test_teardown();
|
||||
test_setup();
|
||||
|
@ -477,7 +477,7 @@ static void test_illusioncastle(CuTest *tc)
|
|||
CuAssertPtrEquals(tc, btype, (void *)icastle_type(a));
|
||||
CuAssertPtrEquals(tc, bt_icastle, (void *)b->type);
|
||||
CuAssertStrEquals(tc, "castle", buildingtype(btype, b, b->size));
|
||||
btype->construction->name = str_strdup("site");
|
||||
btype->stages->name = str_strdup("site");
|
||||
CuAssertStrEquals(tc, "site", buildingtype(btype, b, b->size));
|
||||
test_teardown();
|
||||
}
|
||||
|
|
|
@ -222,6 +222,9 @@ void score(void)
|
|||
|
||||
int default_score(const item_type *itype) {
|
||||
int result = 0;
|
||||
if (itype->rtype->wtype || itype->rtype->atype) {
|
||||
result += 10;
|
||||
}
|
||||
if (itype->construction) {
|
||||
requirement *req = itype->construction->materials;
|
||||
while (req->number) {
|
||||
|
|
|
@ -55,7 +55,6 @@
|
|||
/* util includes */
|
||||
#include <util/attrib.h>
|
||||
#include <util/base36.h>
|
||||
#include <util/bsdstring.h>
|
||||
#include <util/event.h>
|
||||
#include <util/language.h>
|
||||
#include <util/lists.h>
|
||||
|
@ -173,6 +172,9 @@ static order *monster_attack(unit * u, const unit * target)
|
|||
if (monster_is_waiting(u))
|
||||
return NULL;
|
||||
|
||||
if (u->region->land) {
|
||||
assert(u->region->flags & RF_GUARDED);
|
||||
}
|
||||
return create_order(K_ATTACK, u->faction->locale, "%i", target->no);
|
||||
}
|
||||
|
||||
|
@ -499,41 +501,30 @@ static attrib *set_new_dragon_target(unit * u, region * r, int range)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
static order *make_movement_order(unit * u, const region * target, int moves,
|
||||
static order *plan_move_to_target(unit * u, const region * target, int moves,
|
||||
bool(*allowed) (const region *, const region *))
|
||||
{
|
||||
region *r = u->region;
|
||||
region **plan;
|
||||
int position = 0;
|
||||
char zOrder[128], *bufp = zOrder;
|
||||
size_t size = sizeof(zOrder) - 1;
|
||||
direction_t steps[DRAGON_RANGE];
|
||||
int position;
|
||||
|
||||
if (monster_is_waiting(u))
|
||||
return NULL;
|
||||
|
||||
plan = path_find(r, target, DRAGON_RANGE * 5, allowed);
|
||||
plan = path_find(r, target, DRAGON_RANGE, allowed);
|
||||
if (plan == NULL)
|
||||
return NULL;
|
||||
|
||||
while (position != moves && plan[position + 1]) {
|
||||
int bytes;
|
||||
for (position = 0; position != moves && plan[position + 1]; ++position) {
|
||||
region *prev = plan[position];
|
||||
region *next = plan[++position];
|
||||
region *next = plan[position + 1];
|
||||
direction_t dir = reldirection(prev, next);
|
||||
assert(dir != NODIRECTION && dir != D_SPECIAL);
|
||||
if (size > 1 && bufp != zOrder) {
|
||||
*bufp++ = ' ';
|
||||
--size;
|
||||
}
|
||||
bytes =
|
||||
(int)str_strlcpy(bufp,
|
||||
(const char *)LOC(u->faction->locale, directions[dir]), size);
|
||||
if (wrptr(&bufp, &size, bytes) != 0)
|
||||
WARN_STATIC_BUFFER();
|
||||
steps[position] = dir;
|
||||
}
|
||||
|
||||
*bufp = 0;
|
||||
return create_order(K_MOVE, u->faction->locale, zOrder);
|
||||
return make_movement_order(u->faction->locale, steps, position);
|
||||
}
|
||||
|
||||
void random_growl(const unit *u, region *target, int rand)
|
||||
|
@ -686,15 +677,15 @@ static order *plan_dragon(unit * u)
|
|||
assert(long_order == NULL);
|
||||
/* TODO: per-race planning functions? */
|
||||
if (rc == rc_wyrm) {
|
||||
long_order = make_movement_order(u, tr, 1, allowed_dragon);
|
||||
long_order = plan_move_to_target(u, tr, 1, allowed_dragon);
|
||||
}
|
||||
else {
|
||||
switch (old_race(rc)) {
|
||||
case RC_FIREDRAGON:
|
||||
long_order = make_movement_order(u, tr, 4, allowed_dragon);
|
||||
long_order = plan_move_to_target(u, tr, 4, allowed_dragon);
|
||||
break;
|
||||
case RC_DRAGON:
|
||||
long_order = make_movement_order(u, tr, 3, allowed_dragon);
|
||||
long_order = plan_move_to_target(u, tr, 3, allowed_dragon);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
@ -747,7 +738,14 @@ void plan_monsters(faction * f)
|
|||
|
||||
for (r = regions; r; r = r->next) {
|
||||
unit *u;
|
||||
bool attacking = chance(attack_chance);
|
||||
bool attacking = false;
|
||||
/* Tiny optimization: Monsters on land only attack randomly when
|
||||
* they are guarding. If nobody is guarding this region (RF_GUARDED),
|
||||
* there can't be any random attacks.
|
||||
*/
|
||||
if (!r->land || r->flags & RF_GUARDED) {
|
||||
attacking = chance(attack_chance);
|
||||
}
|
||||
|
||||
for (u = r->units; u; u = u->next) {
|
||||
const race *rc = u_race(u);
|
||||
|
@ -768,8 +766,7 @@ void plan_monsters(faction * f)
|
|||
if (attacking && (!r->land || is_guard(u))) {
|
||||
monster_attacks(u, false);
|
||||
}
|
||||
|
||||
/* units with a plan to kill get ATTACK orders: */
|
||||
/* units with a plan to kill get ATTACK orders (even if they don't guard): */
|
||||
ta = a_find(u->attribs, &at_hate);
|
||||
if (ta && !monster_is_waiting(u)) {
|
||||
unit *tu = (unit *)ta->data.v;
|
||||
|
@ -780,15 +777,15 @@ void plan_monsters(faction * f)
|
|||
}
|
||||
}
|
||||
else if (tu) {
|
||||
tu = findunit(ta->data.i);
|
||||
if (tu != NULL) {
|
||||
long_order = make_movement_order(u, tu->region, 2, allowed_walk);
|
||||
bool(*allowed)(const struct region * src, const struct region * r) = allowed_walk;
|
||||
if (canfly(u)) {
|
||||
allowed = allowed_fly;
|
||||
}
|
||||
long_order = plan_move_to_target(u, tu->region, 2, allowed);
|
||||
}
|
||||
else
|
||||
a_remove(&u->attribs, ta);
|
||||
}
|
||||
|
||||
/* All monsters guard the region: */
|
||||
if (u->status < ST_FLEE && !monster_is_waiting(u) && r->land) {
|
||||
addlist(&u->orders, create_order(K_GUARD, u->faction->locale, NULL));
|
||||
|
|
|
@ -28,6 +28,8 @@ extern "C" {
|
|||
struct unit;
|
||||
struct region;
|
||||
struct faction;
|
||||
struct order;
|
||||
struct locale;
|
||||
|
||||
struct unit *spawn_seaserpent(struct region *r, struct faction *f);
|
||||
void spawn_dragons(void);
|
||||
|
|
|
@ -18,10 +18,13 @@
|
|||
#include "skill.h"
|
||||
#include "study.h"
|
||||
|
||||
#include <util/attrib.h>
|
||||
#include <util/language.h>
|
||||
#include <util/message.h>
|
||||
#include <util/nrmessage.h>
|
||||
|
||||
#include <attributes/hate.h>
|
||||
|
||||
#include <CuTest.h>
|
||||
#include <tests.h>
|
||||
#include <assert.h>
|
||||
|
@ -267,10 +270,35 @@ static void test_spawn_seaserpent(CuTest *tc) {
|
|||
test_teardown();
|
||||
}
|
||||
|
||||
static void test_monsters_hate(CuTest *tc) {
|
||||
unit *mu, *tu;
|
||||
order *ord;
|
||||
char buffer[32];
|
||||
const struct locale *lang;
|
||||
|
||||
test_setup();
|
||||
tu = test_create_unit(test_create_faction(NULL), test_create_plain(1, 0));
|
||||
mu = test_create_unit(get_monsters(), test_create_plain(0, 0));
|
||||
lang = mu->faction->locale;
|
||||
a_add(&mu->attribs, make_hate(tu));
|
||||
plan_monsters(mu->faction);
|
||||
CuAssertPtrNotNull(tc, mu->orders);
|
||||
for (ord = mu->orders; ord; ord = ord->next) {
|
||||
if (K_MOVE == getkeyword(ord)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
CuAssertPtrNotNull(tc, ord);
|
||||
CuAssertIntEquals(tc, K_MOVE, getkeyword(ord));
|
||||
CuAssertStrEquals(tc, "move east", get_command(ord, lang, buffer, sizeof(buffer)));
|
||||
test_teardown();
|
||||
}
|
||||
|
||||
CuSuite *get_monsters_suite(void)
|
||||
{
|
||||
CuSuite *suite = CuSuiteNew();
|
||||
SUITE_ADD_TEST(suite, test_monsters_attack);
|
||||
SUITE_ADD_TEST(suite, test_monsters_hate);
|
||||
SUITE_ADD_TEST(suite, test_spawn_seaserpent);
|
||||
SUITE_ADD_TEST(suite, test_monsters_attack_ocean);
|
||||
SUITE_ADD_TEST(suite, test_seaserpent_piracy);
|
||||
|
|
50
src/move.c
50
src/move.c
|
@ -479,10 +479,6 @@ static bool cansail(const region * r, ship * sh)
|
|||
{
|
||||
UNUSED_ARG(r);
|
||||
|
||||
/* sonst ist construction:: size nicht ship_type::maxsize */
|
||||
assert(!sh->type->construction
|
||||
|| sh->type->construction->improvement == NULL);
|
||||
|
||||
if (sh->type->construction && sh->size != sh->type->construction->maxsize) {
|
||||
return false;
|
||||
}
|
||||
|
@ -505,10 +501,6 @@ static double overload(const region * r, ship * sh)
|
|||
{
|
||||
UNUSED_ARG(r);
|
||||
|
||||
/* sonst ist construction:: size nicht ship_type::maxsize */
|
||||
assert(!sh->type->construction
|
||||
|| sh->type->construction->improvement == NULL);
|
||||
|
||||
if (sh->type->construction && sh->size != sh->type->construction->maxsize) {
|
||||
return DBL_MAX;
|
||||
}
|
||||
|
@ -847,7 +839,6 @@ static void drifting_ships(region * r)
|
|||
/* Kapitän da? Beschädigt? Genügend Matrosen?
|
||||
* Genügend leicht? Dann ist alles OK. */
|
||||
|
||||
assert(sh->type->construction->improvement == NULL); /* sonst ist construction::size nicht ship_type::maxsize */
|
||||
if (captain && sh->size == sh->type->construction->maxsize
|
||||
&& enoughsailors(sh, crew_skill(sh)) && cansail(r, sh)) {
|
||||
shp = &sh->next;
|
||||
|
@ -1052,7 +1043,7 @@ int movewhere(const unit * u, const char *token, region * r, region ** resultp)
|
|||
return E_MOVE_OK;
|
||||
}
|
||||
|
||||
static void cycle_route(order * ord, unit * u, int gereist)
|
||||
order * cycle_route(order * ord, const struct locale *lang, int gereist)
|
||||
{
|
||||
int cm = 0;
|
||||
char tail[1024], *bufp = tail;
|
||||
|
@ -1067,11 +1058,10 @@ static void cycle_route(order * ord, unit * u, int gereist)
|
|||
assert(getkeyword(ord) == K_ROUTE);
|
||||
tail[0] = '\0';
|
||||
neworder[0] = '\0';
|
||||
init_order(ord, u->faction->locale);
|
||||
init_order(ord, lang);
|
||||
|
||||
for (cm = 0;; ++cm) {
|
||||
const char *s;
|
||||
const struct locale *lang = u->faction->locale;
|
||||
pause = false;
|
||||
s = gettoken(token, sizeof(token));
|
||||
if (s && *s) {
|
||||
|
@ -1087,7 +1077,7 @@ static void cycle_route(order * ord, unit * u, int gereist)
|
|||
break;
|
||||
}
|
||||
if (cm < gereist) {
|
||||
/* hier sollte keine PAUSE auftreten */
|
||||
/* TODO: hier sollte keine PAUSE auftreten */
|
||||
assert(!pause);
|
||||
if (!pause) {
|
||||
const char *loc = LOC(lang, shortdirections[d]);
|
||||
|
@ -1124,13 +1114,30 @@ static void cycle_route(order * ord, unit * u, int gereist)
|
|||
}
|
||||
|
||||
if (neworder[0]) {
|
||||
norder = create_order(K_ROUTE, u->faction->locale, "%s %s", neworder, tail);
|
||||
norder = create_order(K_ROUTE, lang, "%s %s", neworder, tail);
|
||||
}
|
||||
else {
|
||||
norder = create_order(K_ROUTE, u->faction->locale, "%s", tail);
|
||||
norder = create_order(K_ROUTE, lang, "%s", tail);
|
||||
}
|
||||
replace_order(&u->orders, ord, norder);
|
||||
free_order(norder);
|
||||
return norder;
|
||||
}
|
||||
|
||||
order * make_movement_order(const struct locale *lang, direction_t steps[], int length)
|
||||
{
|
||||
sbstring sbs;
|
||||
char zOrder[128];
|
||||
int i;
|
||||
|
||||
sbs_init(&sbs, zOrder, sizeof(zOrder));
|
||||
for (i = 0; i != length; ++i) {
|
||||
direction_t dir = steps[i];
|
||||
if (i > 0) {
|
||||
sbs_strcat(&sbs, " ");
|
||||
}
|
||||
sbs_strcat(&sbs, LOC(lang, directions[dir]));
|
||||
}
|
||||
|
||||
return create_order(K_MOVE, lang, zOrder);
|
||||
}
|
||||
|
||||
static bool transport(unit * ut, unit * u)
|
||||
|
@ -1605,7 +1612,9 @@ static const region_list *travel_route(unit * u,
|
|||
|
||||
setguard(u, false);
|
||||
if (getkeyword(ord) == K_ROUTE) {
|
||||
cycle_route(ord, u, steps);
|
||||
order * norder = cycle_route(ord, u->faction->locale, steps);
|
||||
replace_order(&u->orders, ord, norder);
|
||||
free_order(norder);
|
||||
}
|
||||
|
||||
if (mode == TRAVEL_RUNNING) {
|
||||
|
@ -1651,7 +1660,6 @@ static bool ship_ready(const region * r, unit * u, order * ord)
|
|||
return false;
|
||||
}
|
||||
if (u->ship->type->construction) {
|
||||
assert(!u->ship->type->construction->improvement); /* sonst ist construction::size nicht ship_type::maxsize */
|
||||
if (u->ship->size != u->ship->type->construction->maxsize) {
|
||||
cmistake(u, ord, 15, MSG_MOVE);
|
||||
return false;
|
||||
|
@ -1937,7 +1945,9 @@ static void sail(unit * u, order * ord, region_list ** routep, bool drifting)
|
|||
/* nachdem alle Richtungen abgearbeitet wurden, und alle Einheiten
|
||||
* transferiert wurden, kann der aktuelle Befehl gelöscht werden. */
|
||||
if (getkeyword(ord) == K_ROUTE) {
|
||||
cycle_route(ord, u, step);
|
||||
order * norder = cycle_route(ord, u->faction->locale, step);
|
||||
replace_order(&u->orders, ord, norder);
|
||||
free_order(norder);
|
||||
}
|
||||
set_order(&u->thisorder, NULL);
|
||||
set_coast(sh, last_point, current_point);
|
||||
|
|
10
src/move.h
10
src/move.h
|
@ -26,12 +26,14 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct unit;
|
||||
struct attrib_type;
|
||||
struct building_type;
|
||||
struct locale;
|
||||
struct order;
|
||||
struct region;
|
||||
struct region_list;
|
||||
struct ship;
|
||||
struct building_type;
|
||||
struct order;
|
||||
struct unit;
|
||||
|
||||
extern struct attrib_type at_shiptrail;
|
||||
extern int *storms;
|
||||
|
@ -95,6 +97,8 @@ extern "C" {
|
|||
|
||||
int check_ship_allowed(struct ship *sh, const struct region * r);
|
||||
direction_t drift_target(struct ship *sh);
|
||||
struct order * cycle_route(struct order * ord, const struct locale *lang, int gereist);
|
||||
struct order * make_movement_order(const struct locale *lang, direction_t steps[], int length);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -593,6 +593,30 @@ static void test_route_cycle(CuTest *tc) {
|
|||
test_teardown();
|
||||
}
|
||||
|
||||
static void test_cycle_route(CuTest *tc) {
|
||||
struct locale *lang;
|
||||
char buffer[32];
|
||||
order *ord, *onew;
|
||||
|
||||
test_setup();
|
||||
lang = test_create_locale();
|
||||
CuAssertPtrNotNull(tc, LOC(lang, shortdirections[D_WEST]));
|
||||
|
||||
ord = create_order(K_ROUTE, lang, "WEST EAST PAUSE NW");
|
||||
CuAssertStrEquals(tc, "route WEST EAST PAUSE NW", get_command(ord, lang, buffer, sizeof(buffer)));
|
||||
|
||||
onew = cycle_route(ord, lang, 1);
|
||||
CuAssertStrEquals(tc, "route east PAUSE nw west", get_command(onew, lang, buffer, sizeof(buffer)));
|
||||
free_order(onew);
|
||||
|
||||
onew = cycle_route(ord, lang, 2);
|
||||
CuAssertStrEquals(tc, "route nw west east PAUSE", get_command(onew, lang, buffer, sizeof(buffer)));
|
||||
free_order(onew);
|
||||
|
||||
free_order(ord);
|
||||
test_teardown();
|
||||
}
|
||||
|
||||
static void test_route_pause(CuTest *tc) {
|
||||
unit *u;
|
||||
region *r;
|
||||
|
@ -630,6 +654,26 @@ static void test_movement_speed_dragon(CuTest *tc) {
|
|||
test_teardown();
|
||||
}
|
||||
|
||||
static void test_make_movement_order(CuTest *tc) {
|
||||
order *ord;
|
||||
char buffer[32];
|
||||
struct locale *lang;
|
||||
direction_t steps[] = { D_EAST, D_WEST, D_EAST, D_WEST };
|
||||
|
||||
test_setup();
|
||||
lang = test_create_locale();
|
||||
|
||||
ord = make_movement_order(lang, steps, 2);
|
||||
CuAssertStrEquals(tc, "move east west", get_command(ord, lang, buffer, sizeof(buffer)));
|
||||
free_order(ord);
|
||||
|
||||
ord = make_movement_order(lang, steps, 4);
|
||||
CuAssertStrEquals(tc, "move east west east west", get_command(ord, lang, buffer, sizeof(buffer)));
|
||||
free_order(ord);
|
||||
|
||||
test_teardown();
|
||||
}
|
||||
|
||||
CuSuite *get_move_suite(void)
|
||||
{
|
||||
CuSuite *suite = CuSuiteNew();
|
||||
|
@ -658,6 +702,8 @@ CuSuite *get_move_suite(void)
|
|||
SUITE_ADD_TEST(suite, test_follow_ship_msg);
|
||||
SUITE_ADD_TEST(suite, test_drifting_ships);
|
||||
SUITE_ADD_TEST(suite, test_route_cycle);
|
||||
SUITE_ADD_TEST(suite, test_cycle_route);
|
||||
SUITE_ADD_TEST(suite, test_route_pause);
|
||||
SUITE_ADD_TEST(suite, test_make_movement_order);
|
||||
return suite;
|
||||
}
|
||||
|
|
27
src/report.c
27
src/report.c
|
@ -96,7 +96,6 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|||
/* libc includes */
|
||||
#include <assert.h>
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
|
@ -111,17 +110,6 @@ extern int *storms;
|
|||
extern int weeks_per_month;
|
||||
extern int months_per_year;
|
||||
|
||||
static void check_errno(const char * file, int line) {
|
||||
if (errno) {
|
||||
char zText[64];
|
||||
sprintf(zText, "error %d during report at %s:%d", errno, file, line);
|
||||
perror(zText);
|
||||
errno = 0;
|
||||
}
|
||||
}
|
||||
|
||||
#define CHECK_ERRNO() check_errno(__FILE__, __LINE__)
|
||||
|
||||
static char *gamedate_season(const struct locale *lang)
|
||||
{
|
||||
static char buf[256]; /* FIXME: static return value */
|
||||
|
@ -261,7 +249,7 @@ void nr_spell_syntax(struct stream *out, spellbook_entry * sbe, const struct loc
|
|||
char buf[4096];
|
||||
char *bufp = buf;
|
||||
size_t size = sizeof(buf) - 1;
|
||||
const spell * sp = sbe->sp;
|
||||
const spell *sp = spellref_get(&sbe->spref);
|
||||
const char *params = sp->parameter;
|
||||
|
||||
if (sp->sptyp & ISCOMBATSPELL) {
|
||||
|
@ -451,7 +439,7 @@ void nr_spell(struct stream *out, spellbook_entry * sbe, const struct locale *la
|
|||
char buf[4096];
|
||||
char *startp, *bufp = buf;
|
||||
size_t size = sizeof(buf) - 1;
|
||||
const spell * sp = sbe->sp;
|
||||
const spell *sp = spellref_get(&sbe->spref);
|
||||
|
||||
newline(out);
|
||||
centre(out, spell_name(sp, lang), true);
|
||||
|
@ -1803,7 +1791,6 @@ nr_ship(struct stream *out, const region *r, const ship * sh, const faction * f,
|
|||
if (wrptr(&bufp, &size, bytes) != 0)
|
||||
WARN_STATIC_BUFFER();
|
||||
|
||||
assert(sh->type->construction->improvement == NULL); /* sonst ist construction::size nicht ship_type::maxsize */
|
||||
if (sh->size != sh->type->construction->maxsize) {
|
||||
bytes = snprintf(bufp, size, ", %s (%d/%d)",
|
||||
LOC(f->locale, "nr_undercons"), sh->size,
|
||||
|
@ -2196,7 +2183,7 @@ report_plaintext(const char *filename, report_context * ctx,
|
|||
}
|
||||
|
||||
ch = 0;
|
||||
CHECK_ERRNO();
|
||||
ERRNO_CHECK();
|
||||
for (a = a_find(f->attribs, &at_showitem); a && a->type == &at_showitem;
|
||||
a = a->next) {
|
||||
const item_type *itype = (const item_type *)a->data.v;
|
||||
|
@ -2246,7 +2233,7 @@ report_plaintext(const char *filename, report_context * ctx,
|
|||
}
|
||||
}
|
||||
newline(out);
|
||||
CHECK_ERRNO();
|
||||
ERRNO_CHECK();
|
||||
centre(out, LOC(f->locale, "nr_alliances"), false);
|
||||
newline(out);
|
||||
|
||||
|
@ -2254,7 +2241,7 @@ report_plaintext(const char *filename, report_context * ctx,
|
|||
|
||||
rpline(out);
|
||||
|
||||
CHECK_ERRNO();
|
||||
ERRNO_CHECK();
|
||||
anyunits = 0;
|
||||
|
||||
for (r = ctx->first; r != ctx->last; r = r->next) {
|
||||
|
@ -2368,7 +2355,7 @@ report_plaintext(const char *filename, report_context * ctx,
|
|||
|
||||
newline(out);
|
||||
rpline(out);
|
||||
CHECK_ERRNO();
|
||||
ERRNO_CHECK();
|
||||
}
|
||||
if (!is_monsters(f)) {
|
||||
if (!anyunits) {
|
||||
|
@ -2380,7 +2367,7 @@ report_plaintext(const char *filename, report_context * ctx,
|
|||
}
|
||||
}
|
||||
fstream_done(&strm);
|
||||
CHECK_ERRNO();
|
||||
ERRNO_CHECK();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -870,6 +870,7 @@ bufunit(const faction * f, const unit * u, seen_mode mode, char *buf,
|
|||
|
||||
for (header = 0, qi = 0; ql; selist_advance(&ql, &qi, 1)) {
|
||||
spellbook_entry * sbe = (spellbook_entry *)selist_get(ql, qi);
|
||||
const spell *sp = spellref_get(&sbe->spref);
|
||||
if (sbe->level <= maxlevel) {
|
||||
if (!header) {
|
||||
n = snprintf(bufp, size, ", %s: ", LOC(lang, "nr_spells"));
|
||||
|
@ -882,7 +883,7 @@ bufunit(const faction * f, const unit * u, seen_mode mode, char *buf,
|
|||
WARN_STATIC_BUFFER();
|
||||
}
|
||||
/* TODO: no need to deref the spellref here (spref->name is good) */
|
||||
bufp = STRLCPY(bufp, spell_name(sbe->sp, lang), size);
|
||||
bufp = STRLCPY(bufp, spell_name(sp, lang), size);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
#include <stdbool.h>
|
||||
struct locale;
|
||||
|
||||
typedef enum {
|
||||
typedef enum skill_t {
|
||||
SK_ALCHEMY,
|
||||
SK_CROSSBOW,
|
||||
SK_MINING,
|
||||
|
|
29
src/tests.c
29
src/tests.c
|
@ -336,20 +336,27 @@ ship_type * test_create_shiptype(const char * name)
|
|||
|
||||
building_type * test_create_buildingtype(const char * name)
|
||||
{
|
||||
construction *con;
|
||||
building_type *btype = bt_get_or_create(name);
|
||||
btype->flags = BTF_NAMECHANGE;
|
||||
if (!btype->construction) {
|
||||
btype->construction = (construction *)calloc(sizeof(construction), 1);
|
||||
btype->construction->skill = SK_BUILDING;
|
||||
btype->construction->maxsize = -1;
|
||||
btype->construction->minskill = 1;
|
||||
btype->construction->reqsize = 1;
|
||||
if (btype->stages) {
|
||||
con = btype->stages->construction;
|
||||
} else {
|
||||
btype->stages = calloc(1, sizeof(building_stage));
|
||||
con = (construction *)calloc(1, sizeof(construction));
|
||||
if (con) {
|
||||
con->skill = SK_BUILDING;
|
||||
con->maxsize = -1;
|
||||
con->minskill = 1;
|
||||
con->reqsize = 1;
|
||||
btype->stages->construction = con;
|
||||
}
|
||||
}
|
||||
if (!btype->construction->materials) {
|
||||
btype->construction->materials = (requirement *)calloc(sizeof(requirement), 2);
|
||||
btype->construction->materials[1].number = 0;
|
||||
btype->construction->materials[0].number = 1;
|
||||
btype->construction->materials[0].rtype = get_resourcetype(R_STONE);
|
||||
if (con && !con->materials) {
|
||||
con->materials = (requirement *)calloc(2, sizeof(requirement));
|
||||
con->materials[1].number = 0;
|
||||
con->materials[0].number = 1;
|
||||
con->materials[0].rtype = get_resourcetype(R_STONE);
|
||||
}
|
||||
if (default_locale) {
|
||||
locale_setstring(default_locale, name, name);
|
||||
|
|
|
@ -24,6 +24,14 @@ without prior permission by the authors of Eressea.
|
|||
#include <stdarg.h>
|
||||
#include <time.h>
|
||||
|
||||
void errno_check(const char * file, int line) {
|
||||
if (errno) {
|
||||
log_info("errno is %d (%s) at %s:%d",
|
||||
errno, strerror(errno), file, line);
|
||||
errno = 0;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef STDIO_CP
|
||||
static int stdio_codepage = STDIO_CP;
|
||||
#else
|
||||
|
|
|
@ -28,13 +28,17 @@ extern "C" {
|
|||
int log_level(struct log_t *log, int flags);
|
||||
void log_close(void);
|
||||
|
||||
extern void log_fatal(const char *format, ...);
|
||||
extern void log_error(const char *format, ...);
|
||||
extern void log_warning(const char *format, ...);
|
||||
extern void log_debug(const char *format, ...);
|
||||
extern void log_info(const char *format, ...);
|
||||
extern void log_printf(FILE * ios, const char *format, ...);
|
||||
void log_fatal(const char *format, ...);
|
||||
void log_error(const char *format, ...);
|
||||
void log_warning(const char *format, ...);
|
||||
void log_debug(const char *format, ...);
|
||||
void log_info(const char *format, ...);
|
||||
void log_printf(FILE * ios, const char *format, ...);
|
||||
|
||||
void errno_check(const char *file, int line);
|
||||
#define ERRNO_CHECK() errno_check(__FILE__, __LINE__)
|
||||
|
||||
|
||||
#define LOG_CPERROR 0x01
|
||||
#define LOG_CPWARNING 0x02
|
||||
#define LOG_CPINFO 0x04
|
||||
|
|
327
src/xmlreader.c
327
src/xmlreader.c
|
@ -61,6 +61,17 @@ without prior permission by the authors of Eressea.
|
|||
#include <string.h>
|
||||
|
||||
|
||||
static void mask_races(xmlNodePtr node, const char *key, int *maskp) {
|
||||
xmlChar *propValue = xmlGetProp(node, BAD_CAST key);
|
||||
int mask = 0;
|
||||
assert(maskp);
|
||||
if (propValue) {
|
||||
mask = rc_get_mask((char *)propValue);
|
||||
xmlFree(propValue);
|
||||
}
|
||||
*maskp = mask;
|
||||
}
|
||||
|
||||
static variant xml_fraction(xmlNodePtr node, const char *name) {
|
||||
xmlChar *propValue = xmlGetProp(node, BAD_CAST name);
|
||||
if (propValue != NULL) {
|
||||
|
@ -129,16 +140,8 @@ static resource_mod * xml_readmodifiers(xmlXPathObjectPtr result, xmlNodePtr nod
|
|||
xmlNodePtr node = result->nodesetval->nodeTab[k];
|
||||
xmlChar *propValue;
|
||||
building_type *btype = NULL;
|
||||
const race *rc = NULL;
|
||||
|
||||
propValue = xmlGetProp(node, BAD_CAST "race");
|
||||
if (propValue != NULL) {
|
||||
rc = rc_find((const char *)propValue);
|
||||
if (rc == NULL)
|
||||
rc = rc_get_or_create((const char *)propValue);
|
||||
xmlFree(propValue);
|
||||
}
|
||||
modifiers[k].race = rc;
|
||||
mask_races(node, "races", &modifiers[k].race_mask);
|
||||
|
||||
propValue = xmlGetProp(node, BAD_CAST "building");
|
||||
if (propValue != NULL) {
|
||||
|
@ -211,57 +214,64 @@ xml_readrequirements(xmlNodePtr * nodeTab, int nodeNr, requirement ** reqArray)
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
xml_readconstruction(xmlXPathContextPtr xpath, xmlNodeSetPtr nodeSet,
|
||||
construction ** consPtr, construct_t type)
|
||||
static construction *
|
||||
xml_readconstruction(xmlXPathContextPtr xpath, xmlNodePtr node)
|
||||
{
|
||||
xmlNodePtr pushNode = xpath->node;
|
||||
int k;
|
||||
for (k = 0; k != nodeSet->nodeNr; ++k) {
|
||||
xmlNodePtr node = nodeSet->nodeTab[k];
|
||||
xmlChar *propValue;
|
||||
construction *con;
|
||||
xmlXPathObjectPtr req;
|
||||
skill_t sk = NOSKILL;
|
||||
construction *con;
|
||||
xmlChar *propValue;
|
||||
xmlXPathObjectPtr req;
|
||||
skill_t sk = NOSKILL;
|
||||
|
||||
propValue = xmlGetProp(node, BAD_CAST "skill");
|
||||
if (propValue != NULL) {
|
||||
sk = findskill((const char *)propValue);
|
||||
if (sk == NOSKILL) {
|
||||
log_error("construction requires skill '%s' that does not exist.\n", (const char *)propValue);
|
||||
xmlFree(propValue);
|
||||
return NULL;
|
||||
}
|
||||
xmlFree(propValue);
|
||||
}
|
||||
|
||||
con = (construction *)calloc(sizeof(construction), 1);
|
||||
|
||||
con->skill = sk;
|
||||
con->maxsize = xml_ivalue(node, "maxsize", -1);
|
||||
con->minskill = xml_ivalue(node, "minskill", -1);
|
||||
con->reqsize = xml_ivalue(node, "reqsize", 1);
|
||||
|
||||
/* read construction/requirement */
|
||||
xpath->node = node;
|
||||
req = xmlXPathEvalExpression(BAD_CAST "requirement", xpath);
|
||||
xml_readrequirements(req->nodesetval->nodeTab,
|
||||
req->nodesetval->nodeNr, &con->materials);
|
||||
xmlXPathFreeObject(req);
|
||||
|
||||
return con;
|
||||
}
|
||||
|
||||
static void
|
||||
xml_readconstructions(xmlXPathContextPtr xpath, xmlNodeSetPtr nodeSet, building_type *btype)
|
||||
{
|
||||
building_stage **stage_ptr = &btype->stages;
|
||||
int k;
|
||||
|
||||
for (k = 0; k != nodeSet->nodeNr; ++k) {
|
||||
building_stage *stage = calloc(1, sizeof(building_stage));
|
||||
xmlNodePtr node = nodeSet->nodeTab[k];
|
||||
construction *con = xml_readconstruction(xpath, node);
|
||||
xmlChar *propValue = xmlGetProp(node, BAD_CAST "name");
|
||||
|
||||
propValue = xmlGetProp(node, BAD_CAST "skill");
|
||||
if (propValue != NULL) {
|
||||
sk = findskill((const char *)propValue);
|
||||
if (sk == NOSKILL) {
|
||||
log_error("construction requires skill '%s' that does not exist.\n", (const char *)propValue);
|
||||
xmlFree(propValue);
|
||||
continue;
|
||||
}
|
||||
stage->name = str_strdup((const char *)propValue);
|
||||
xmlFree(propValue);
|
||||
}
|
||||
stage->next = NULL;
|
||||
stage->construction = con;
|
||||
|
||||
assert(*consPtr == NULL);
|
||||
|
||||
*consPtr = con = (construction *)calloc(sizeof(construction), 1);
|
||||
consPtr = &con->improvement;
|
||||
|
||||
con->type = type;
|
||||
con->skill = sk;
|
||||
con->maxsize = xml_ivalue(node, "maxsize", -1);
|
||||
con->minskill = xml_ivalue(node, "minskill", -1);
|
||||
con->reqsize = xml_ivalue(node, "reqsize", 1);
|
||||
|
||||
if (type == CONS_BUILDING) {
|
||||
propValue = xmlGetProp(node, BAD_CAST "name");
|
||||
if (propValue != NULL) {
|
||||
con->name = str_strdup((const char *)propValue);
|
||||
xmlFree(propValue);
|
||||
}
|
||||
}
|
||||
|
||||
/* read construction/requirement */
|
||||
xpath->node = node;
|
||||
req = xmlXPathEvalExpression(BAD_CAST "requirement", xpath);
|
||||
xml_readrequirements(req->nodesetval->nodeTab,
|
||||
req->nodesetval->nodeNr, &con->materials);
|
||||
xmlXPathFreeObject(req);
|
||||
*stage_ptr = stage;
|
||||
stage_ptr = &stage->next;
|
||||
}
|
||||
xpath->node = pushNode;
|
||||
}
|
||||
|
||||
static int
|
||||
|
@ -339,7 +349,7 @@ static int parse_buildings(xmlDocPtr doc)
|
|||
/* reading eressea/buildings/building/construction */
|
||||
xpath->node = node;
|
||||
result = xmlXPathEvalExpression(BAD_CAST "construction", xpath);
|
||||
xml_readconstruction(xpath, result->nodesetval, &btype->construction, CONS_BUILDING);
|
||||
xml_readconstructions(xpath, result->nodesetval, btype);
|
||||
xmlXPathFreeObject(result);
|
||||
|
||||
/* reading eressea/buildings/building/function */
|
||||
|
@ -436,24 +446,27 @@ static int parse_ships(xmlDocPtr doc)
|
|||
st->range_max = xml_ivalue(node, "maxrange", st->range_max);
|
||||
st->storm = xml_fvalue(node, "storm", st->storm);
|
||||
|
||||
/* reading eressea/ships/ship/construction */
|
||||
xpath->node = node;
|
||||
result = xmlXPathEvalExpression(BAD_CAST "construction", xpath);
|
||||
xml_readconstruction(xpath, result->nodesetval, &st->construction, CONS_OTHER);
|
||||
xmlXPathFreeObject(result);
|
||||
|
||||
for (child = node->children; child; child = child->next) {
|
||||
if (strcmp((const char *)child->name, "modifier") == 0) {
|
||||
double value = xml_fvalue(child, "value", 0.0);
|
||||
propValue = xmlGetProp(child, BAD_CAST "type");
|
||||
if (strcmp((const char *)propValue, "tactics") == 0)
|
||||
st->tac_bonus = (float)value;
|
||||
else if (strcmp((const char *)propValue, "attack") == 0)
|
||||
st->at_bonus = (int)value;
|
||||
else if (strcmp((const char *)propValue, "defense") == 0)
|
||||
st->df_bonus = (int)value;
|
||||
if (strcmp((const char *)propValue, "tactics") == 0) {
|
||||
st->tac_bonus = xml_fvalue(child, "factor", 1.0);
|
||||
}
|
||||
else {
|
||||
int value = xml_ivalue(child, "value", 0);
|
||||
if (strcmp((const char *)propValue, "attack") == 0) {
|
||||
st->at_bonus = (int)value;
|
||||
}
|
||||
else if (strcmp((const char *)propValue, "defense") == 0) {
|
||||
st->df_bonus = (int)value;
|
||||
}
|
||||
}
|
||||
xmlFree(propValue);
|
||||
}
|
||||
else if (strcmp((const char *)child->name, "construction") == 0) {
|
||||
assert(!st->construction);
|
||||
st->construction = xml_readconstruction(xpath, child);
|
||||
}
|
||||
}
|
||||
/* reading eressea/ships/ship/coast */
|
||||
xpath->node = node;
|
||||
|
@ -488,22 +501,25 @@ static int parse_ships(xmlDocPtr doc)
|
|||
return result;
|
||||
}
|
||||
|
||||
static void xml_readpotion(xmlXPathContextPtr xpath, item_type * itype)
|
||||
static void xml_readpotion(xmlNodePtr node, item_type * itype)
|
||||
{
|
||||
int level = xml_ivalue(xpath->node, "level", 0);
|
||||
int level = xml_ivalue(node, "level", 0);
|
||||
|
||||
if ((itype->flags & ITF_CANUSE) == 0) {
|
||||
log_error("potion %s has no use attribute", itype->rtype->_name);
|
||||
itype->flags |= ITF_CANUSE;
|
||||
}
|
||||
new_potiontype(itype, level);
|
||||
}
|
||||
|
||||
static luxury_type *xml_readluxury(xmlXPathContextPtr xpath, item_type * itype)
|
||||
static luxury_type *xml_readluxury(xmlNodePtr node, item_type * itype)
|
||||
{
|
||||
int price = xml_ivalue(xpath->node, "price", 0);
|
||||
int price = xml_ivalue(node, "price", 0);
|
||||
return new_luxurytype(itype, price);
|
||||
}
|
||||
|
||||
static armor_type *xml_readarmor(xmlXPathContextPtr xpath, item_type * itype)
|
||||
static armor_type *xml_readarmor(xmlNodePtr node, item_type * itype)
|
||||
{
|
||||
xmlNodePtr node = xpath->node;
|
||||
armor_type *atype = NULL;
|
||||
unsigned int flags = ATF_NONE;
|
||||
int ac = xml_ivalue(node, "ac", 0);
|
||||
|
@ -591,8 +607,7 @@ static weapon_type *xml_readweapon(xmlXPathContextPtr xpath, item_type * itype)
|
|||
wtype->modifiers = calloc(result->nodesetval->nodeNr + 1, sizeof(weapon_mod));
|
||||
for (k = 0; k != result->nodesetval->nodeNr; ++k) {
|
||||
xmlNodePtr node = result->nodesetval->nodeTab[k];
|
||||
xmlXPathObjectPtr races;
|
||||
int r, flags = 0;
|
||||
int flags = 0;
|
||||
|
||||
if (xml_bvalue(node, "walking", false))
|
||||
flags |= WMF_WALKING;
|
||||
|
@ -619,21 +634,8 @@ static weapon_type *xml_readweapon(xmlXPathContextPtr xpath, item_type * itype)
|
|||
wtype->modifiers[k].flags = flags;
|
||||
wtype->modifiers[k].value = xml_ivalue(node, "value", 0);
|
||||
|
||||
xpath->node = node;
|
||||
races = xmlXPathEvalExpression(BAD_CAST "race", xpath);
|
||||
for (r = 0; r != races->nodesetval->nodeNr; ++r) {
|
||||
xmlNodePtr node = races->nodesetval->nodeTab[r];
|
||||
|
||||
propValue = xmlGetProp(node, BAD_CAST "name");
|
||||
if (propValue != NULL) {
|
||||
const race *rc = rc_find((const char *)propValue);
|
||||
if (rc == NULL)
|
||||
rc = rc_get_or_create((const char *)propValue);
|
||||
racelist_insert(&wtype->modifiers[k].races, rc);
|
||||
xmlFree(propValue);
|
||||
}
|
||||
}
|
||||
xmlXPathFreeObject(races);
|
||||
mask_races(node, "races", &wtype->modifiers[k].race_mask);
|
||||
wtype->modifiers[k].race_mask = 0;
|
||||
}
|
||||
xmlXPathFreeObject(result);
|
||||
|
||||
|
@ -668,35 +670,11 @@ static weapon_type *xml_readweapon(xmlXPathContextPtr xpath, item_type * itype)
|
|||
return wtype;
|
||||
}
|
||||
|
||||
static int race_mask = 1;
|
||||
|
||||
static void mask_races(xmlNodePtr node, const char *key, int *maskp) {
|
||||
xmlChar *propValue = xmlGetProp(node, BAD_CAST key);
|
||||
int mask = 0;
|
||||
assert(maskp);
|
||||
if (propValue) {
|
||||
char * tok = strtok((char *)propValue, " ,");
|
||||
while (tok) {
|
||||
race * rc = rc_get_or_create(tok);
|
||||
if (!rc->mask_item) {
|
||||
rc->mask_item = race_mask;
|
||||
race_mask = race_mask << 1;
|
||||
}
|
||||
mask |= rc->mask_item;
|
||||
tok = strtok(NULL, " ,");
|
||||
}
|
||||
xmlFree(propValue);
|
||||
}
|
||||
*maskp = mask;
|
||||
}
|
||||
|
||||
static item_type *xml_readitem(xmlXPathContextPtr xpath, resource_type * rtype)
|
||||
{
|
||||
xmlNodePtr node = xpath->node;
|
||||
xmlNodePtr child, node = xpath->node;
|
||||
item_type *itype = NULL;
|
||||
unsigned int flags = ITF_NONE;
|
||||
xmlXPathObjectPtr result;
|
||||
int k;
|
||||
|
||||
if (xml_bvalue(node, "cursed", false))
|
||||
flags |= ITF_CURSED;
|
||||
|
@ -715,82 +693,45 @@ static item_type *xml_readitem(xmlXPathContextPtr xpath, resource_type * rtype)
|
|||
itype = rtype->itype ? rtype->itype : it_get_or_create(rtype);
|
||||
itype->weight = xml_ivalue(node, "weight", 0);
|
||||
itype->capacity = xml_ivalue(node, "capacity", 0);
|
||||
itype->score = xml_ivalue(node, "score", 0);
|
||||
|
||||
mask_races(node, "allow", &itype->mask_allow);
|
||||
mask_races(node, "deny", &itype->mask_deny);
|
||||
itype->flags |= flags;
|
||||
|
||||
/* reading item/construction */
|
||||
xpath->node = node;
|
||||
result = xmlXPathEvalExpression(BAD_CAST "construction", xpath);
|
||||
xml_readconstruction(xpath, result->nodesetval, &itype->construction, CONS_ITEM);
|
||||
xmlXPathFreeObject(result);
|
||||
|
||||
/* reading item/weapon */
|
||||
xpath->node = node;
|
||||
result = xmlXPathEvalExpression(BAD_CAST "weapon", xpath);
|
||||
assert(result->nodesetval->nodeNr <= 1);
|
||||
if (result->nodesetval->nodeNr != 0) {
|
||||
xpath->node = result->nodesetval->nodeTab[0];
|
||||
rtype->wtype = xml_readweapon(xpath, itype);
|
||||
}
|
||||
xmlXPathFreeObject(result);
|
||||
|
||||
/* reading item/potion */
|
||||
xpath->node = node;
|
||||
result = xmlXPathEvalExpression(BAD_CAST "potion", xpath);
|
||||
assert(result->nodesetval->nodeNr <= 1);
|
||||
if (result->nodesetval->nodeNr != 0) {
|
||||
if ((itype->flags & ITF_CANUSE) == 0) {
|
||||
log_error("potion %s has no use attribute", rtype->_name);
|
||||
itype->flags |= ITF_CANUSE;
|
||||
for (child = node->children; child; child = child->next) {
|
||||
if (strcmp((const char *)child->name, "construction") == 0) {
|
||||
/* reading item/construction */
|
||||
assert(!itype->construction);
|
||||
xpath->node = child;
|
||||
itype->construction = xml_readconstruction(xpath, child);
|
||||
}
|
||||
xpath->node = result->nodesetval->nodeTab[0];
|
||||
xml_readpotion(xpath, itype);
|
||||
}
|
||||
xmlXPathFreeObject(result);
|
||||
|
||||
/* reading item/luxury */
|
||||
xpath->node = node;
|
||||
result = xmlXPathEvalExpression(BAD_CAST "luxury", xpath);
|
||||
assert(result->nodesetval->nodeNr <= 1);
|
||||
if (result->nodesetval->nodeNr != 0) {
|
||||
xpath->node = result->nodesetval->nodeTab[0];
|
||||
rtype->ltype = xml_readluxury(xpath, itype);
|
||||
}
|
||||
xmlXPathFreeObject(result);
|
||||
|
||||
/* reading item/armor */
|
||||
xpath->node = node;
|
||||
result = xmlXPathEvalExpression(BAD_CAST "armor", xpath);
|
||||
assert(result->nodesetval->nodeNr <= 1);
|
||||
if (result->nodesetval->nodeNr != 0) {
|
||||
xpath->node = result->nodesetval->nodeTab[0];
|
||||
rtype->atype = xml_readarmor(xpath, itype);
|
||||
}
|
||||
xmlXPathFreeObject(result);
|
||||
|
||||
/* reading item/function */
|
||||
xpath->node = node;
|
||||
result = xmlXPathEvalExpression(BAD_CAST "function", xpath);
|
||||
for (k = 0; k != result->nodesetval->nodeNr; ++k) {
|
||||
xmlNodePtr node = result->nodesetval->nodeTab[k];
|
||||
xmlChar *propValue;
|
||||
pf_generic fun;
|
||||
|
||||
parse_function(node, &fun, &propValue);
|
||||
if (fun == NULL) {
|
||||
log_error("unknown function name '%s' for item '%s'\n", (const char *)propValue, rtype->_name);
|
||||
xmlFree(propValue);
|
||||
continue;
|
||||
else if (strcmp((const char *)child->name, "weapon") == 0) {
|
||||
/* reading item/weapon */
|
||||
assert(!rtype->wtype);
|
||||
xpath->node = child;
|
||||
rtype->wtype = xml_readweapon(xpath, itype);
|
||||
}
|
||||
else if (strcmp((const char *)child->name, "armor") == 0) {
|
||||
/* reading item/weapon */
|
||||
assert(!rtype->atype);
|
||||
rtype->atype = xml_readarmor(child, itype);
|
||||
}
|
||||
else if (strcmp((const char *)child->name, "luxury") == 0) {
|
||||
/* reading item/luxury */
|
||||
assert(!rtype->ltype);
|
||||
rtype->ltype = xml_readluxury(child, itype);
|
||||
}
|
||||
else if (strcmp((const char *)child->name, "potion") == 0) {
|
||||
/* reading item/potion */
|
||||
xml_readpotion(child, itype);
|
||||
}
|
||||
assert(propValue != NULL);
|
||||
log_error("unknown function type '%s' for item '%s'\n", (const char *)propValue, rtype->_name);
|
||||
xmlFree(propValue);
|
||||
}
|
||||
itype->score = xml_ivalue(node, "score", 0);
|
||||
if (!itype->score) itype->score = default_score(itype);
|
||||
xmlXPathFreeObject(result);
|
||||
|
||||
if (!itype->score) {
|
||||
/* do this last, because score depends on itype data */
|
||||
itype->score = default_score(itype);
|
||||
}
|
||||
return itype;
|
||||
}
|
||||
|
||||
|
@ -869,10 +810,6 @@ static int parse_resources(xmlDocPtr doc)
|
|||
result = xmlXPathEvalExpression(BAD_CAST "modifier", xpath);
|
||||
rtype->modifiers = xml_readmodifiers(result, node);
|
||||
xmlXPathFreeObject(result);
|
||||
/* reading eressea/resources/resource/resourcelimit/function */
|
||||
xpath->node = node;
|
||||
result = xmlXPathEvalExpression(BAD_CAST "resourcelimit/function", xpath);
|
||||
xmlXPathFreeObject(result);
|
||||
|
||||
/* reading eressea/resources/resource/item */
|
||||
xpath->node = node;
|
||||
|
@ -1156,17 +1093,12 @@ static int parse_spellbooks(xmlDocPtr doc)
|
|||
if (result->nodesetval->nodeNr > 0) {
|
||||
for (k = 0; k != result->nodesetval->nodeNr; ++k) {
|
||||
xmlNodePtr node = result->nodesetval->nodeTab[k];
|
||||
spell * sp = 0;
|
||||
int level = xml_ivalue(node, "level", -1);
|
||||
|
||||
propValue = xmlGetProp(node, BAD_CAST "spell");
|
||||
if (propValue) {
|
||||
sp = find_spell((const char *)propValue);
|
||||
if (level > 0 && (propValue = xmlGetProp(node, BAD_CAST "spell")) != NULL) {
|
||||
spellbook_addref(sb, (const char *)propValue, level);
|
||||
xmlFree(propValue);
|
||||
}
|
||||
if (sp && level > 0) {
|
||||
spellbook_add(sb, sp, level);
|
||||
}
|
||||
else {
|
||||
log_error("invalid entry at index '%d' in spellbook '%s'\n", k, sb->name);
|
||||
}
|
||||
|
@ -1335,7 +1267,7 @@ static void parse_ai(race * rc, xmlNodePtr node)
|
|||
rc->flags |= RCF_ATTACK_MOVED;
|
||||
}
|
||||
|
||||
static void set_study_speed(race *rc, skill_t sk, int modifier){
|
||||
static void set_study_speed(race *rc, skill_t sk, int modifier) {
|
||||
if (!rc->study_speed)
|
||||
rc->study_speed = calloc(1, MAXSKILLS);
|
||||
rc->study_speed[sk] = (char)modifier;
|
||||
|
@ -1573,7 +1505,8 @@ static int parse_races(xmlDocPtr doc)
|
|||
if (attack->data.sp) {
|
||||
attack->level = xml_ivalue(node, "level", 0);
|
||||
if (attack->level <= 0) {
|
||||
log_error("magical attack '%s' for race '%s' needs a level: %d\n", attack->data.sp->name, rc->_name, attack->level);
|
||||
log_error("magical attack '%s' for race '%s' needs a level: %d\n",
|
||||
spellref_name(attack->data.sp), rc->_name, attack->level);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1772,8 +1705,8 @@ void register_xmlreader(void)
|
|||
xml_register_callback(parse_ships); /* requires resources, terrains */
|
||||
xml_register_callback(parse_equipment); /* requires resources */
|
||||
|
||||
xml_register_callback(parse_spells); /* requires resources */
|
||||
xml_register_callback(parse_spellbooks); /* requires spells */
|
||||
xml_register_callback(parse_spells); /* requires resources */
|
||||
|
||||
xml_register_callback(parse_strings);
|
||||
xml_register_callback(parse_messages);
|
||||
|
|
Loading…
Reference in New Issue