forked from github/server
Merge branch 'develop' of github.com:eressea/server into develop
This commit is contained in:
commit
c0a760a645
|
@ -11,6 +11,7 @@ addons:
|
|||
- libncurses5-dev
|
||||
- libsqlite3-dev
|
||||
- libxml2-dev
|
||||
- valgrind
|
||||
os:
|
||||
- linux
|
||||
- osx
|
||||
|
|
|
@ -2830,17 +2830,6 @@
|
|||
<text locale="de">"$unit($unit) in $region($region) produziert $int($amount)$if($eq($wanted,$amount),""," von $int($wanted)") $resource($resource,$wanted)."</text>
|
||||
<text locale="en">"$unit($unit) in $region($region) produces $int($amount)$if($eq($wanted,$amount),""," of $int($wanted)") $resource($resource,$amount)."</text>
|
||||
</message>
|
||||
<message name="manufacture" section="production">
|
||||
<type>
|
||||
<arg name="unit" type="unit"/>
|
||||
<arg name="region" type="region"/>
|
||||
<arg name="amount" type="int"/>
|
||||
<arg name="wanted" type="int"/>
|
||||
<arg name="resource" type="resource"/>
|
||||
</type>
|
||||
<text locale="de">"$unit($unit) in $region($region) produziert $int($amount)$if($eq($wanted,$amount),""," von $int($wanted)") $resource($resource,$wanted)."</text>
|
||||
<text locale="en">"$unit($unit) in $region($region) produces $int($amount)$if($eq($wanted,$amount),""," of $int($wanted)") $resource($resource,$amount)."</text>
|
||||
</message>
|
||||
<message name="buildbuilding" section="production">
|
||||
<type>
|
||||
<arg name="unit" type="unit"/>
|
||||
|
|
|
@ -16,3 +16,5 @@ s/build
|
|||
cd $ROOT
|
||||
inifile
|
||||
s/runtests
|
||||
cd tests
|
||||
./write-reports.sh
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
local pkg = {}
|
||||
|
||||
print("loading jsreport module")
|
||||
|
||||
function pkg.init()
|
||||
eressea.settings.set("feature.jsreport.enable", "1")
|
||||
end
|
||||
|
|
|
@ -460,7 +460,6 @@ function test_canoe_passes_through_land()
|
|||
u1:add_order("NACH O O O")
|
||||
process_orders()
|
||||
assert_equal(land, u2.region, "canoe did not stop at coast")
|
||||
u1:add_order("NACH O O O")
|
||||
process_orders()
|
||||
assert_equal(dst, sh.region, "canoe could not leave coast")
|
||||
assert_equal(dst, u1.region, "canoe could not leave coast")
|
||||
|
|
|
@ -58,7 +58,6 @@ function test_magic()
|
|||
u:add_spell("protective_runes")
|
||||
u:add_spell("analyze_magic")
|
||||
u:clear_orders()
|
||||
u:add_order("ZAUBERE \"Runen des Schutzes\" BURG " .. itoa36(b.id));
|
||||
u.building = b
|
||||
u:add_order("ZAUBERE \"Magie analysieren\" BURG " .. itoa36(b.id));
|
||||
process_orders()
|
||||
|
|
|
@ -6,13 +6,19 @@ function setup()
|
|||
conf = [[{
|
||||
"races" : { "human" : {} },
|
||||
"terrains" : { "plain" : { "flags" : [ "land" ] } },
|
||||
"keywords" : { "de" : { "study": "LERNEN" } },
|
||||
"skills" : { "de": { "alchemy" : "Alchemie", "crossbow" : "Armbrust" } },
|
||||
"keywords" : { "de" : { "study": "LERNEN", "teach": "LEHREN" } },
|
||||
"skills" : { "de": {
|
||||
"tactics" : "Taktik",
|
||||
"alchemy" : "Alchemie",
|
||||
"crossbow" : "Armbrust"
|
||||
} },
|
||||
"spells" : { "fireball" : { "syntax" : "u+" } }
|
||||
}]]
|
||||
eressea.game.reset()
|
||||
eressea.config.reset();
|
||||
eressea.settings.set('rules.magic.playerschools', '')
|
||||
eressea.settings.set("rules.economy.food", "4")
|
||||
eressea.settings.set('study.random_progress', '0')
|
||||
eressea.config.parse(conf)
|
||||
end
|
||||
|
||||
|
@ -51,3 +57,62 @@ function test_unit_spells()
|
|||
assert_equal("fireball", sp.name)
|
||||
assert_equal(2, sp.level)
|
||||
end
|
||||
|
||||
local function make_teacher(student, f, skill)
|
||||
f = f or student.faction
|
||||
local u = unit.create(f, student.region, 1)
|
||||
u:clear_orders()
|
||||
u:add_order("LEHRE " .. itoa36(student.id))
|
||||
u:set_skill(skill or "crossbow", 10)
|
||||
return u
|
||||
end
|
||||
|
||||
local function make_student(f, r, num, skill)
|
||||
local u = unit.create(f, r, num or 1)
|
||||
u:clear_orders()
|
||||
u:add_order("LERNE " .. (skill or "Armbrust"))
|
||||
return u
|
||||
end
|
||||
|
||||
function test_study_no_teacher()
|
||||
local r = region.create(0, 0, "plain")
|
||||
local f = faction.create("test@example.com", "human", "de")
|
||||
local u1 = make_student(f, r, 1)
|
||||
u1:set_skill("crossbow", 1)
|
||||
process_orders()
|
||||
assert_equal(1, u1:get_skill("crossbow"))
|
||||
end
|
||||
|
||||
function test_study_with_teacher()
|
||||
local r = region.create(0, 0, "plain")
|
||||
local f = faction.create("test@example.com", "human", "de")
|
||||
local u1 = make_student(f, r, 1)
|
||||
|
||||
make_teacher(u1)
|
||||
u1:set_skill("crossbow", 1)
|
||||
process_orders()
|
||||
assert_equal(2, u1:get_skill("crossbow"))
|
||||
end
|
||||
|
||||
function test_study_too_many_students()
|
||||
local r = region.create(0, 0, "plain")
|
||||
local f = faction.create("test@example.com", "human", "de")
|
||||
local u1 = make_student(f, r, 20, "Taktik")
|
||||
u1.name = "Student"
|
||||
u1:add_item("money", 201*u1.number)
|
||||
make_teacher(u1, f, "tactics")
|
||||
process_orders()
|
||||
assert_equal(u1.number, u1:get_item("money"))
|
||||
end
|
||||
|
||||
function test_study_multiple_teachers()
|
||||
local r = region.create(0, 0, "plain")
|
||||
local f = faction.create("test@example.com", "human", "de")
|
||||
local u1 = make_student(f, r, 20, "Taktik")
|
||||
u1.name = "Student"
|
||||
u1:add_item("money", 201*u1.number)
|
||||
make_teacher(u1, f, "tactics")
|
||||
make_teacher(u1, f, "tactics")
|
||||
process_orders()
|
||||
assert_equal(u1.number, u1:get_item("money"))
|
||||
end
|
||||
|
|
|
@ -193,6 +193,7 @@ set(TESTS_SRC
|
|||
skill.test.c
|
||||
spells.test.c
|
||||
spy.test.c
|
||||
study.test.c
|
||||
upkeep.test.c
|
||||
spells/magicresistance.test.c
|
||||
${ATTRIBUTES_TESTS}
|
||||
|
|
|
@ -3231,7 +3231,7 @@ fighter *make_fighter(battle * b, unit * u, side * s1, bool attack)
|
|||
}
|
||||
|
||||
/* Illusionen und Zauber kaempfen nicht */
|
||||
if (fval(u_race(u), RCF_ILLUSIONARY) || idle(u->faction) || u->number == 0) {
|
||||
if (fval(u_race(u), RCF_ILLUSIONARY) || u->number == 0) {
|
||||
return NULL;
|
||||
}
|
||||
if (s1 == NULL) {
|
||||
|
|
|
@ -159,7 +159,7 @@ void process_quit(void) {
|
|||
|
||||
void process_study(void) {
|
||||
process_cmd(K_TEACH, teach_cmd, PROC_LONG_ORDER);
|
||||
process_cmd(K_STUDY, learn_cmd, PROC_LONG_ORDER);
|
||||
process_cmd(K_STUDY, study_cmd, PROC_LONG_ORDER);
|
||||
}
|
||||
|
||||
void process_movement(void) {
|
||||
|
|
171
src/creport.c
171
src/creport.c
|
@ -68,6 +68,7 @@ without prior permission by the authors of Eressea.
|
|||
#include <util/message.h>
|
||||
#include <util/nrmessage.h>
|
||||
#include <quicklist.h>
|
||||
#include <filestream.h>
|
||||
|
||||
/* libc includes */
|
||||
#include <assert.h>
|
||||
|
@ -176,7 +177,7 @@ static void print_items(FILE * F, item * items, const struct locale *lang)
|
|||
}
|
||||
|
||||
static void
|
||||
cr_output_curses(FILE * F, const faction * viewer, const void *obj, objtype_t typ)
|
||||
cr_output_curses(stream *out, const faction * viewer, const void *obj, objtype_t typ)
|
||||
{
|
||||
bool header = false;
|
||||
attrib *a = NULL;
|
||||
|
@ -258,10 +259,10 @@ cr_output_curses(FILE * F, const faction * viewer, const void *obj, objtype_t ty
|
|||
char buf[BUFFERSIZE];
|
||||
if (!header) {
|
||||
header = 1;
|
||||
fputs("EFFECTS\n", F);
|
||||
stream_printf(out, "EFFECTS\n");
|
||||
}
|
||||
nr_render(msg, viewer->locale, buf, sizeof(buf), viewer);
|
||||
fprintf(F, "\"%s\"\n", buf);
|
||||
stream_printf(out, "\"%s\"\n", buf);
|
||||
msg_release(msg);
|
||||
}
|
||||
a = a->next;
|
||||
|
@ -272,9 +273,9 @@ cr_output_curses(FILE * F, const faction * viewer, const void *obj, objtype_t ty
|
|||
const char *key = resourcename(data->type->itype->rtype, 0);
|
||||
if (!header) {
|
||||
header = 1;
|
||||
fputs("EFFECTS\n", F);
|
||||
stream_printf(out, "EFFECTS\n");
|
||||
}
|
||||
fprintf(F, "\"%d %s\"\n", data->value, translate(key,
|
||||
stream_printf(out, "\"%d %s\"\n", data->value, translate(key,
|
||||
LOC(default_locale, key)));
|
||||
}
|
||||
a = a->next;
|
||||
|
@ -285,6 +286,13 @@ cr_output_curses(FILE * F, const faction * viewer, const void *obj, objtype_t ty
|
|||
}
|
||||
}
|
||||
|
||||
static void cr_output_curses_compat(FILE *F, const faction * viewer, const void *obj, objtype_t typ) {
|
||||
// TODO: eliminate this function
|
||||
stream strm;
|
||||
fstream_init(&strm, F);
|
||||
cr_output_curses(&strm, viewer, obj, typ);
|
||||
}
|
||||
|
||||
static int cr_unit(variant var, char *buffer, const void *userdata)
|
||||
{
|
||||
unit *u = (unit *)var.v;
|
||||
|
@ -636,7 +644,7 @@ faction * f)
|
|||
fprintf(F, "%d;Partei\n", fno);
|
||||
if (b->besieged)
|
||||
fprintf(F, "%d;Belagerer\n", b->besieged);
|
||||
cr_output_curses(F, f, b, TYP_BUILDING);
|
||||
cr_output_curses_compat(F, f, b, TYP_BUILDING);
|
||||
}
|
||||
|
||||
/* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
|
||||
|
@ -682,30 +690,22 @@ const faction * f, const region * r)
|
|||
if (w != NODIRECTION)
|
||||
fprintf(F, "%d;Kueste\n", w);
|
||||
|
||||
cr_output_curses(F, f, sh, TYP_SHIP);
|
||||
cr_output_curses_compat(F, f, sh, TYP_SHIP);
|
||||
}
|
||||
|
||||
static void
|
||||
fwriteorder(FILE * F, const struct order *ord, const struct locale *lang,
|
||||
bool escape)
|
||||
{
|
||||
static int stream_order(stream *out, const struct order *ord) {
|
||||
const char *str;
|
||||
char ebuf[1025];
|
||||
char obuf[1024];
|
||||
const char *str = obuf;
|
||||
fputc('"', F);
|
||||
write_order(ord, obuf, sizeof(obuf));
|
||||
if (escape) {
|
||||
str = escape_string(obuf, ebuf, sizeof(ebuf));
|
||||
if (str == ebuf) {
|
||||
ebuf[1024] = 0;
|
||||
}
|
||||
str = escape_string(obuf, ebuf, sizeof(ebuf));
|
||||
if (str == ebuf) {
|
||||
ebuf[1024] = 0;
|
||||
}
|
||||
if (str[0])
|
||||
fputs(str, F);
|
||||
fputc('"', F);
|
||||
return stream_printf(out, "\"%s\"\n", str);
|
||||
}
|
||||
|
||||
static void cr_output_spells(FILE * F, const unit * u, int maxlevel)
|
||||
static void cr_output_spells(stream *out, const unit * u, int maxlevel)
|
||||
{
|
||||
spellbook * book = unit_get_spellbook(u);
|
||||
|
||||
|
@ -720,17 +720,20 @@ static void cr_output_spells(FILE * F, const unit * u, int maxlevel)
|
|||
spell * sp = sbe->sp;
|
||||
const char *name = translate(mkname("spell", sp->sname), spell_name(sp, f->locale));
|
||||
if (!header) {
|
||||
fputs("SPRUECHE\n", F);
|
||||
stream_printf(out, "SPRUECHE\n");
|
||||
header = 1;
|
||||
}
|
||||
fprintf(F, "\"%s\"\n", name);
|
||||
stream_printf(out, "\"%s\"\n", name);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* prints all that belongs to a unit */
|
||||
static void cr_output_unit(FILE * F, const region * r, const faction * f, /* observers faction */
|
||||
/** prints all that belongs to a unit
|
||||
* @param f observers faction
|
||||
* @param u unit to report
|
||||
*/
|
||||
void cr_output_unit(stream *out, const region * r, const faction * f,
|
||||
const unit * u, int mode)
|
||||
{
|
||||
/* Race attributes are always plural and item attributes always
|
||||
|
@ -751,7 +754,7 @@ static void cr_output_unit(FILE * F, const region * r, const faction * f,
|
|||
const char *prefix;
|
||||
|
||||
assert(u && u->number);
|
||||
if (u != NULL || fval(u_race(u), RCF_INVISIBLE))
|
||||
if (fval(u_race(u), RCF_INVISIBLE))
|
||||
return;
|
||||
|
||||
if (!init) {
|
||||
|
@ -763,11 +766,11 @@ static void cr_output_unit(FILE * F, const region * r, const faction * f,
|
|||
itemcloak = cu && curse_active(cu);
|
||||
}
|
||||
|
||||
fprintf(F, "EINHEIT %d\n", u->no);
|
||||
fprintf(F, "\"%s\";Name\n", unit_getname(u));
|
||||
stream_printf(out, "EINHEIT %d\n", u->no);
|
||||
stream_printf(out, "\"%s\";Name\n", unit_getname(u));
|
||||
str = u_description(u, f->locale);
|
||||
if (str) {
|
||||
fprintf(F, "\"%s\";Beschr\n", str);
|
||||
stream_printf(out, "\"%s\";Beschr\n", str);
|
||||
}
|
||||
/* print faction information */
|
||||
sf = visible_faction(f, u);
|
||||
|
@ -784,41 +787,41 @@ static void cr_output_unit(FILE * F, const region * r, const faction * f,
|
|||
a = a_find(u->attribs, &at_group);
|
||||
if (a != NULL) {
|
||||
const group *g = (const group *)a->data.v;
|
||||
fprintf(F, "%d;gruppe\n", g->gid);
|
||||
stream_printf(out, "%d;gruppe\n", g->gid);
|
||||
}
|
||||
fprintf(F, "%d;Partei\n", u->faction->no);
|
||||
stream_printf(out, "%d;Partei\n", u->faction->no);
|
||||
if (sf != u->faction)
|
||||
fprintf(F, "%d;Verkleidung\n", sf->no);
|
||||
stream_printf(out, "%d;Verkleidung\n", sf->no);
|
||||
if (fval(u, UFL_ANON_FACTION))
|
||||
fprintf(F, "%d;Parteitarnung\n", i2b(fval(u, UFL_ANON_FACTION)));
|
||||
stream_printf(out, "%d;Parteitarnung\n", i2b(fval(u, UFL_ANON_FACTION)));
|
||||
if (otherfaction) {
|
||||
if (otherfaction != u->faction) {
|
||||
fprintf(F, "%d;Anderepartei\n", otherfaction->no);
|
||||
stream_printf(out, "%d;Anderepartei\n", otherfaction->no);
|
||||
}
|
||||
}
|
||||
mage = get_familiar_mage(u);
|
||||
if (mage) {
|
||||
fprintf(F, "%u;familiarmage\n", mage->no);
|
||||
stream_printf(out, "%u;familiarmage\n", mage->no);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (fval(u, UFL_ANON_FACTION)) {
|
||||
/* faction info is hidden */
|
||||
fprintf(F, "%d;Parteitarnung\n", i2b(fval(u, UFL_ANON_FACTION)));
|
||||
stream_printf(out, "%d;Parteitarnung\n", i2b(fval(u, UFL_ANON_FACTION)));
|
||||
}
|
||||
else {
|
||||
const attrib *a_otherfaction = a_find(u->attribs, &at_otherfaction);
|
||||
const faction *otherfaction =
|
||||
a_otherfaction ? get_otherfaction(a_otherfaction) : NULL;
|
||||
/* other unit. show visible faction, not u->faction */
|
||||
fprintf(F, "%d;Partei\n", sf->no);
|
||||
stream_printf(out, "%d;Partei\n", sf->no);
|
||||
if (sf == f) {
|
||||
fprintf(F, "1;Verraeter\n");
|
||||
stream_printf(out, "1;Verraeter\n");
|
||||
}
|
||||
if (a_otherfaction) {
|
||||
if (otherfaction != u->faction) {
|
||||
if (alliedunit(u, f, HELP_FSTEALTH)) {
|
||||
fprintf(F, "%d;Anderepartei\n", otherfaction->no);
|
||||
stream_printf(out, "%d;Anderepartei\n", otherfaction->no);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -826,53 +829,53 @@ static void cr_output_unit(FILE * F, const region * r, const faction * f,
|
|||
}
|
||||
if (prefix) {
|
||||
prefix = mkname("prefix", prefix);
|
||||
fprintf(F, "\"%s\";typprefix\n", translate(prefix, LOC(f->locale,
|
||||
stream_printf(out, "\"%s\";typprefix\n", translate(prefix, LOC(f->locale,
|
||||
prefix)));
|
||||
}
|
||||
if (u->faction != f && a_fshidden
|
||||
&& a_fshidden->data.ca[0] == 1 && effskill(u, SK_STEALTH) >= 6) {
|
||||
fprintf(F, "-1;Anzahl\n");
|
||||
stream_printf(out, "-1;Anzahl\n");
|
||||
}
|
||||
else {
|
||||
fprintf(F, "%d;Anzahl\n", u->number);
|
||||
stream_printf(out, "%d;Anzahl\n", u->number);
|
||||
}
|
||||
|
||||
pzTmp = get_racename(u->attribs);
|
||||
if (pzTmp) {
|
||||
fprintf(F, "\"%s\";Typ\n", pzTmp);
|
||||
stream_printf(out, "\"%s\";Typ\n", pzTmp);
|
||||
if (u->faction == f && fval(u_race(u), RCF_SHAPESHIFTANY)) {
|
||||
const char *zRace = rc_name_s(u_race(u), NAME_PLURAL);
|
||||
fprintf(F, "\"%s\";wahrerTyp\n",
|
||||
stream_printf(out, "\"%s\";wahrerTyp\n",
|
||||
translate(zRace, LOC(f->locale, zRace)));
|
||||
}
|
||||
}
|
||||
else {
|
||||
const race *irace = u_irace(u);
|
||||
const char *zRace = rc_name_s(irace, NAME_PLURAL);
|
||||
fprintf(F, "\"%s\";Typ\n",
|
||||
stream_printf(out, "\"%s\";Typ\n",
|
||||
translate(zRace, LOC(f->locale, zRace)));
|
||||
if (u->faction == f && irace != u_race(u)) {
|
||||
assert(skill_enabled(SK_STEALTH)
|
||||
|| !"we're resetting this on load, so.. ircase should never be used");
|
||||
zRace = rc_name_s(u_race(u), NAME_PLURAL);
|
||||
fprintf(F, "\"%s\";wahrerTyp\n",
|
||||
stream_printf(out, "\"%s\";wahrerTyp\n",
|
||||
translate(zRace, LOC(f->locale, zRace)));
|
||||
}
|
||||
}
|
||||
|
||||
if (u->building) {
|
||||
assert(u->building->region);
|
||||
fprintf(F, "%d;Burg\n", u->building->no);
|
||||
stream_printf(out, "%d;Burg\n", u->building->no);
|
||||
}
|
||||
if (u->ship) {
|
||||
assert(u->ship->region);
|
||||
fprintf(F, "%d;Schiff\n", u->ship->no);
|
||||
stream_printf(out, "%d;Schiff\n", u->ship->no);
|
||||
}
|
||||
if (is_guard(u, GUARD_ALL) != 0) {
|
||||
fprintf(F, "%d;bewacht\n", 1);
|
||||
stream_printf(out, "%d;bewacht\n", 1);
|
||||
}
|
||||
if ((b = usiege(u)) != NULL) {
|
||||
fprintf(F, "%d;belagert\n", b->no);
|
||||
stream_printf(out, "%d;belagert\n", b->no);
|
||||
}
|
||||
/* additional information for own units */
|
||||
if (u->faction == f || omniscient(f)) {
|
||||
|
@ -884,56 +887,55 @@ static void cr_output_unit(FILE * F, const region * r, const faction * f,
|
|||
|
||||
i = ualias(u);
|
||||
if (i > 0)
|
||||
fprintf(F, "%d;temp\n", i);
|
||||
stream_printf(out, "%d;temp\n", i);
|
||||
else if (i < 0)
|
||||
fprintf(F, "%d;alias\n", -i);
|
||||
stream_printf(out, "%d;alias\n", -i);
|
||||
i = get_money(u);
|
||||
fprintf(F, "%d;Kampfstatus\n", u->status);
|
||||
fprintf(F, "%d;weight\n", weight(u));
|
||||
stream_printf(out, "%d;Kampfstatus\n", u->status);
|
||||
stream_printf(out, "%d;weight\n", weight(u));
|
||||
if (fval(u, UFL_NOAID)) {
|
||||
fputs("1;unaided\n", F);
|
||||
stream_printf(out, "1;unaided\n");
|
||||
}
|
||||
if (fval(u, UFL_STEALTH)) {
|
||||
i = u_geteffstealth(u);
|
||||
if (i >= 0) {
|
||||
fprintf(F, "%d;Tarnung\n", i);
|
||||
stream_printf(out, "%d;Tarnung\n", i);
|
||||
}
|
||||
}
|
||||
xc = uprivate(u);
|
||||
if (xc) {
|
||||
fprintf(F, "\"%s\";privat\n", xc);
|
||||
stream_printf(out, "\"%s\";privat\n", xc);
|
||||
}
|
||||
c = hp_status(u);
|
||||
if (c && *c && (u->faction == f || omniscient(f))) {
|
||||
fprintf(F, "\"%s\";hp\n", translate(c,
|
||||
stream_printf(out, "\"%s\";hp\n", translate(c,
|
||||
LOC(u->faction->locale, c)));
|
||||
}
|
||||
if (fval(u, UFL_HERO)) {
|
||||
fputs("1;hero\n", F);
|
||||
stream_printf(out, "1;hero\n");
|
||||
}
|
||||
|
||||
if (fval(u, UFL_HUNGER) && (u->faction == f)) {
|
||||
fputs("1;hunger\n", F);
|
||||
stream_printf(out, "1;hunger\n");
|
||||
}
|
||||
if (is_mage(u)) {
|
||||
fprintf(F, "%d;Aura\n", get_spellpoints(u));
|
||||
fprintf(F, "%d;Auramax\n", max_spellpoints(u->region, u));
|
||||
stream_printf(out, "%d;Aura\n", get_spellpoints(u));
|
||||
stream_printf(out, "%d;Auramax\n", max_spellpoints(u->region, u));
|
||||
}
|
||||
/* default commands */
|
||||
fprintf(F, "COMMANDS\n");
|
||||
stream_printf(out, "COMMANDS\n");
|
||||
for (ord = u->old_orders; ord; ord = ord->next) {
|
||||
/* this new order will replace the old defaults */
|
||||
if (is_persistent(ord)) {
|
||||
fwriteorder(F, ord, f->locale, true);
|
||||
fputc('\n', F);
|
||||
stream_order(out, ord);
|
||||
}
|
||||
}
|
||||
for (ord = u->orders; ord; ord = ord->next) {
|
||||
if (u->old_orders && is_repeated(ord))
|
||||
keyword_t kwd = getkeyword(ord);
|
||||
if (u->old_orders && is_repeated(kwd))
|
||||
continue; /* unit has defaults */
|
||||
if (is_persistent(ord)) {
|
||||
fwriteorder(F, ord, f->locale, true);
|
||||
fputc('\n', F);
|
||||
stream_order(out, ord);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -945,9 +947,9 @@ static void cr_output_unit(FILE * F, const region * r, const faction * f,
|
|||
int esk = eff_skill(u, sk, r);
|
||||
if (!pr) {
|
||||
pr = 1;
|
||||
fprintf(F, "TALENTE\n");
|
||||
stream_printf(out, "TALENTE\n");
|
||||
}
|
||||
fprintf(F, "%d %d;%s\n", u->number * level_days(sv->level), esk,
|
||||
stream_printf(out, "%d %d;%s\n", u->number * level_days(sv->level), esk,
|
||||
translate(mkname("skill", skillnames[sk]), skillname(sk,
|
||||
f->locale)));
|
||||
}
|
||||
|
@ -957,7 +959,7 @@ static void cr_output_unit(FILE * F, const region * r, const faction * f,
|
|||
mage = get_mage(u);
|
||||
if (mage) {
|
||||
int i, maxlevel = effskill(u, SK_MAGIC);
|
||||
cr_output_spells(F, u, maxlevel);
|
||||
cr_output_spells(out, u, maxlevel);
|
||||
|
||||
for (i = 0; i != MAXCOMBATSPELLS; ++i) {
|
||||
const spell *sp = mage->combatspells[i].sp;
|
||||
|
@ -965,9 +967,9 @@ static void cr_output_unit(FILE * F, const region * r, const faction * f,
|
|||
const char *name =
|
||||
translate(mkname("spell", sp->sname), spell_name(sp,
|
||||
f->locale));
|
||||
fprintf(F, "KAMPFZAUBER %d\n", i);
|
||||
fprintf(F, "\"%s\";name\n", name);
|
||||
fprintf(F, "%d;level\n", mage->combatspells[i].level);
|
||||
stream_printf(out, "KAMPFZAUBER %d\n", i);
|
||||
stream_printf(out, "\"%s\";name\n", name);
|
||||
stream_printf(out, "%d;level\n", mage->combatspells[i].level);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1000,12 +1002,21 @@ static void cr_output_unit(FILE * F, const region * r, const faction * f,
|
|||
continue;
|
||||
if (!pr) {
|
||||
pr = 1;
|
||||
fputs("GEGENSTAENDE\n", F);
|
||||
stream_printf(out, "GEGENSTAENDE\n");
|
||||
}
|
||||
fprintf(F, "%d;%s\n", in, translate(ic, LOC(f->locale, ic)));
|
||||
stream_printf(out, "%d;%s\n", in, translate(ic, LOC(f->locale, ic)));
|
||||
}
|
||||
|
||||
cr_output_curses(F, f, u, TYP_UNIT);
|
||||
cr_output_curses(out, f, u, TYP_UNIT);
|
||||
}
|
||||
|
||||
static void cr_output_unit_compat(FILE * F, const region * r, const faction * f,
|
||||
const unit * u, int mode)
|
||||
{
|
||||
// TODO: eliminate this function
|
||||
stream strm;
|
||||
fstream_init(&strm, F);
|
||||
cr_output_unit(&strm, r, f, u, mode);
|
||||
}
|
||||
|
||||
/* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
|
||||
|
@ -1376,7 +1387,7 @@ static void cr_output_region(FILE * F, report_context * ctx, seen_region * sr)
|
|||
if (r->land) {
|
||||
print_items(F, r->land->items, f->locale);
|
||||
}
|
||||
cr_output_curses(F, f, r, TYP_REGION);
|
||||
cr_output_curses_compat(F, f, r, TYP_REGION);
|
||||
cr_borders(ctx->seen, r, f, sr->mode, F);
|
||||
if (sr->mode == see_unit && is_astral(r)
|
||||
&& !is_cursed(r->attribs, C_ASTRALBLOCK, 0)) {
|
||||
|
@ -1468,7 +1479,7 @@ static void cr_output_region(FILE * F, report_context * ctx, seen_region * sr)
|
|||
|
||||
if (u->building || u->ship || (stealthmod > INT_MIN
|
||||
&& cansee(f, r, u, stealthmod))) {
|
||||
cr_output_unit(F, r, f, u, sr->mode);
|
||||
cr_output_unit_compat(F, r, f, u, sr->mode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,10 +15,16 @@
|
|||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct stream;
|
||||
struct region;
|
||||
struct faction;
|
||||
struct unit;
|
||||
|
||||
void creport_cleanup(void);
|
||||
void register_cr(void);
|
||||
|
||||
int crwritemap(const char *filename);
|
||||
void cr_output_unit(struct stream *out, const struct region * r, const struct faction * f, const struct unit * u, int mode);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
|
|
@ -563,7 +563,7 @@ static void recruit(unit * u, struct order *ord, request ** recruitorders)
|
|||
return;
|
||||
}
|
||||
}
|
||||
if (!playerrace(rc) || idle(u->faction)) {
|
||||
if (!playerrace(rc)) {
|
||||
cmistake(u, ord, 139, MSG_EVENT);
|
||||
return;
|
||||
}
|
||||
|
@ -979,26 +979,13 @@ void economics(region * r)
|
|||
remove_empty_units_in_region(r);
|
||||
|
||||
for (u = r->units; u; u = u->next) {
|
||||
order *ord;
|
||||
bool destroyed = false;
|
||||
if (u->number > 0) {
|
||||
for (ord = u->orders; ord; ord = ord->next) {
|
||||
keyword_t kwd = getkeyword(ord);
|
||||
if (kwd == K_DESTROY) {
|
||||
if (!destroyed) {
|
||||
if (destroy_cmd(u, ord) != 0)
|
||||
ord = NULL;
|
||||
destroyed = true;
|
||||
}
|
||||
}
|
||||
if (u->orders == NULL) {
|
||||
break;
|
||||
}
|
||||
order *ord = u->thisorder;
|
||||
keyword_t kwd = getkeyword(ord);
|
||||
if (kwd == K_DESTROY) {
|
||||
if (destroy_cmd(u, ord) == 0) {
|
||||
fset(u, UFL_LONGACTION | UFL_NOTMOVING);
|
||||
}
|
||||
}
|
||||
if (destroyed) {
|
||||
fset(u, UFL_LONGACTION | UFL_NOTMOVING);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1051,7 +1038,7 @@ static void manufacture(unit * u, const item_type * itype, int want)
|
|||
i_change(&u->items, itype, n);
|
||||
if (want == INT_MAX)
|
||||
want = n;
|
||||
ADDMSG(&u->faction->msgs, msg_message("manufacture",
|
||||
ADDMSG(&u->faction->msgs, msg_message("produce",
|
||||
"unit region amount wanted resource", u, u->region, n, want,
|
||||
itype->rtype));
|
||||
}
|
||||
|
@ -1466,7 +1453,7 @@ static void create_potion(unit * u, const potion_type * ptype, int want)
|
|||
i_change(&u->items, ptype->itype, built);
|
||||
if (want == INT_MAX)
|
||||
want = built;
|
||||
ADDMSG(&u->faction->msgs, msg_message("manufacture",
|
||||
ADDMSG(&u->faction->msgs, msg_message("produce",
|
||||
"unit region amount wanted resource", u, u->region, built, want,
|
||||
ptype->itype->rtype));
|
||||
break;
|
||||
|
@ -3216,7 +3203,7 @@ void produce(struct region *r)
|
|||
continue;
|
||||
|
||||
if (fval(u, UFL_LONGACTION) && u->thisorder == NULL) {
|
||||
/* this message was already given in laws.setdefaults
|
||||
/* this message was already given in laws.c:update_long_order
|
||||
cmistake(u, u->thisorder, 52, MSG_PRODUCE);
|
||||
*/
|
||||
continue;
|
||||
|
|
|
@ -59,9 +59,11 @@ static int report_json(const char *filename, report_context * ctx, const char *c
|
|||
if (sr) {
|
||||
terrain_t ter = oldterrain(r->terrain);
|
||||
if (ter == NOTERRAIN) {
|
||||
log_warning("report_json: %s has no terrain id\n", r->terrain->_name);
|
||||
data = 1 + r->terrain->_name[0];
|
||||
}
|
||||
else {
|
||||
data = 1 + (int)ter;
|
||||
}
|
||||
data = 1 + (int)ter;
|
||||
}
|
||||
}
|
||||
fprintf(F, "%d", data);
|
||||
|
|
|
@ -151,11 +151,11 @@ int destroy_cmd(unit * u, struct order *ord)
|
|||
int n = INT_MAX;
|
||||
|
||||
if (u->number < 1)
|
||||
return 0;
|
||||
return 1;
|
||||
|
||||
if (fval(u, UFL_LONGACTION)) {
|
||||
cmistake(u, ord, 52, MSG_PRODUCE);
|
||||
return 0;
|
||||
return 52;
|
||||
}
|
||||
|
||||
init_order(ord);
|
||||
|
@ -183,11 +183,11 @@ int destroy_cmd(unit * u, struct order *ord)
|
|||
|
||||
if (u != building_owner(b)) {
|
||||
cmistake(u, ord, 138, MSG_PRODUCE);
|
||||
return 0;
|
||||
return 138;
|
||||
}
|
||||
if (fval(b->type, BTF_INDESTRUCTIBLE)) {
|
||||
cmistake(u, ord, 138, MSG_PRODUCE);
|
||||
return 0;
|
||||
return 138;
|
||||
}
|
||||
if (n >= b->size) {
|
||||
/* destroy completly */
|
||||
|
@ -213,11 +213,11 @@ int destroy_cmd(unit * u, struct order *ord)
|
|||
|
||||
if (u != ship_owner(sh)) {
|
||||
cmistake(u, ord, 138, MSG_PRODUCE);
|
||||
return 0;
|
||||
return 138;
|
||||
}
|
||||
if (fval(r->terrain, SEA_REGION)) {
|
||||
cmistake(u, ord, 14, MSG_EVENT);
|
||||
return 0;
|
||||
return 14;
|
||||
}
|
||||
|
||||
if (n >= (sh->size * 100) / sh->type->construction->maxsize) {
|
||||
|
@ -242,11 +242,11 @@ int destroy_cmd(unit * u, struct order *ord)
|
|||
}
|
||||
else {
|
||||
cmistake(u, ord, 138, MSG_PRODUCE);
|
||||
return 0;
|
||||
return 138;
|
||||
}
|
||||
|
||||
if (con) {
|
||||
/* TODO: Nicht an ZERSTÖRE mit Punktangabe angepaßt! */
|
||||
/* TODO: Nicht an ZERSTÖRE mit Punktangabe angepasst! */
|
||||
int c;
|
||||
for (c = 0; con->materials[c].number; ++c) {
|
||||
const requirement *rq = con->materials + c;
|
||||
|
|
|
@ -530,7 +530,9 @@ int alliedunit(const unit * u, const faction * f2, int mode)
|
|||
ally *sf;
|
||||
int automode;
|
||||
|
||||
assert(u && u->region); /* the unit should be in a region, but it's possible that u->number==0 (TEMP units) */
|
||||
assert(u);
|
||||
assert(f2);
|
||||
assert(u->region); /* the unit should be in a region, but it's possible that u->number==0 (TEMP units) */
|
||||
if (u->faction == f2)
|
||||
return mode;
|
||||
if (u->faction != NULL && f2 != NULL) {
|
||||
|
@ -904,11 +906,6 @@ int newcontainerid(void)
|
|||
return random_no;
|
||||
}
|
||||
|
||||
bool idle(faction * f)
|
||||
{
|
||||
return (bool)(f ? false : true);
|
||||
}
|
||||
|
||||
int maxworkingpeasants(const struct region *r)
|
||||
{
|
||||
int size = production(r);
|
||||
|
@ -922,6 +919,10 @@ static const char * parameter_key(int i)
|
|||
return parameters[i];
|
||||
}
|
||||
|
||||
void init_parameters(struct locale *lang) {
|
||||
init_translations(lang, UT_PARAMS, parameter_key, MAXPARAMS);
|
||||
}
|
||||
|
||||
|
||||
void init_terrains_translation(const struct locale *lang) {
|
||||
void **tokens;
|
||||
|
@ -1012,7 +1013,7 @@ void init_locale(struct locale *lang)
|
|||
if (name) addtoken(tokens, name, var);
|
||||
}
|
||||
|
||||
init_translations(lang, UT_PARAMS, parameter_key, MAXPARAMS);
|
||||
init_parameters(lang);
|
||||
|
||||
init_options_translation(lang);
|
||||
init_terrains_translation(lang);
|
||||
|
@ -1684,6 +1685,11 @@ void kernel_init(void)
|
|||
}
|
||||
|
||||
static order * defaults[MAXLOCALES];
|
||||
keyword_t default_keyword = NOKEYWORD;
|
||||
|
||||
void set_default_order(int kwd) {
|
||||
default_keyword = (keyword_t)kwd;
|
||||
}
|
||||
|
||||
order *default_order(const struct locale *lang)
|
||||
{
|
||||
|
@ -1691,6 +1697,11 @@ order *default_order(const struct locale *lang)
|
|||
int i = locale_index(lang);
|
||||
order *result = 0;
|
||||
assert(i < MAXLOCALES);
|
||||
|
||||
if (default_keyword!=NOKEYWORD) {
|
||||
return create_order(default_keyword, lang, 0);
|
||||
}
|
||||
|
||||
result = defaults[i];
|
||||
if (!result && usedefault) {
|
||||
const char * str = LOC(lang, "defaultorder");
|
||||
|
|
|
@ -179,7 +179,6 @@ extern "C" {
|
|||
bool has_limited_skills(const struct unit *u);
|
||||
const struct race *findrace(const char *, const struct locale *);
|
||||
|
||||
bool idle(struct faction *f);
|
||||
bool unit_has_cursed_item(const struct unit *u);
|
||||
|
||||
/* grammatik-flags: */
|
||||
|
@ -287,8 +286,12 @@ extern "C" {
|
|||
int AllianceAuto(void); /* flags that allied factions get automatically */
|
||||
int AllianceRestricted(void); /* flags restricted to allied factions */
|
||||
int HelpMask(void); /* flags restricted to allied factions */
|
||||
|
||||
struct order *default_order(const struct locale *lang);
|
||||
void set_default_order(int kwd);
|
||||
|
||||
int entertainmoney(const struct region *r);
|
||||
void init_parameters(struct locale *lang);
|
||||
|
||||
void free_gamedata(void);
|
||||
|
||||
|
|
|
@ -285,8 +285,9 @@ extern unsigned int new_hashstring(const char *s);
|
|||
|
||||
void free_messagelist(message_list * msgs)
|
||||
{
|
||||
struct mlist **mlistptr = &msgs->begin;
|
||||
while (*mlistptr) {
|
||||
struct mlist **mlistptr;
|
||||
assert(msgs && msgs->begin);
|
||||
for (mlistptr = &msgs->begin; *mlistptr;) {
|
||||
struct mlist *ml = *mlistptr;
|
||||
*mlistptr = ml->next;
|
||||
msg_release(ml->msg);
|
||||
|
|
|
@ -115,7 +115,9 @@ char* get_command(const order *ord, char *sbuffer, size_t size) {
|
|||
assert(str);
|
||||
if (text) --size;
|
||||
bytes = (int)strlcpy(bufp, str, size);
|
||||
if (wrptr(&bufp, &size, bytes) != 0) WARN_STATIC_BUFFER();
|
||||
if (wrptr(&bufp, &size, bytes) != 0) {
|
||||
WARN_STATIC_BUFFER();
|
||||
}
|
||||
if (text) *bufp++ = ' ';
|
||||
}
|
||||
else {
|
||||
|
@ -252,6 +254,19 @@ static order_data *create_data(keyword_t kwd, const char *sptr, int lindex)
|
|||
return data;
|
||||
}
|
||||
|
||||
static void free_localedata(int lindex) {
|
||||
int i;
|
||||
for (i = 0; i != MAXKEYWORDS; ++i) {
|
||||
release_data(locale_array[lindex]->short_orders[i]);
|
||||
locale_array[lindex]->short_orders[i] = 0;
|
||||
}
|
||||
for (i = 0; i != MAXSKILLS; ++i) {
|
||||
release_data(locale_array[lindex]->study_orders[i]);
|
||||
locale_array[lindex]->study_orders[i] = 0;
|
||||
}
|
||||
locale_array[lindex]->lang = 0;
|
||||
}
|
||||
|
||||
static order *create_order_i(keyword_t kwd, const char *sptr, bool persistent,
|
||||
const struct locale *lang)
|
||||
{
|
||||
|
@ -276,7 +291,12 @@ static order *create_order_i(keyword_t kwd, const char *sptr, bool persistent,
|
|||
|
||||
lindex = locale_index(lang);
|
||||
assert(lindex < MAXLOCALES);
|
||||
locale_array[lindex] = (locale_data *)calloc(1, sizeof(locale_data));
|
||||
if (!locale_array[lindex]) {
|
||||
locale_array[lindex] = (locale_data *)calloc(1, sizeof(locale_data));
|
||||
}
|
||||
else if (locale_array[lindex]->lang != lang) {
|
||||
free_localedata(lindex);
|
||||
}
|
||||
locale_array[lindex]->lang = lang;
|
||||
|
||||
ord = (order *)malloc(sizeof(order));
|
||||
|
@ -292,13 +312,13 @@ order *create_order(keyword_t kwd, const struct locale * lang,
|
|||
const char *params, ...)
|
||||
{
|
||||
char zBuffer[DISPLAYSIZE];
|
||||
assert(lang);
|
||||
if (params) {
|
||||
char *bufp = zBuffer;
|
||||
int bytes;
|
||||
size_t size = sizeof(zBuffer) - 1;
|
||||
va_list marker;
|
||||
|
||||
assert(lang);
|
||||
va_start(marker, params);
|
||||
while (*params) {
|
||||
if (*params == '%') {
|
||||
|
@ -389,9 +409,8 @@ order *parse_order(const char *s, const struct locale * lang)
|
|||
* \return true if the order is long
|
||||
* \sa is_exclusive(), is_repeated(), is_persistent()
|
||||
*/
|
||||
bool is_repeated(const order * ord)
|
||||
bool is_repeated(keyword_t kwd)
|
||||
{
|
||||
keyword_t kwd = ORD_KEYWORD(ord);
|
||||
switch (kwd) {
|
||||
case K_CAST:
|
||||
case K_BUY:
|
||||
|
@ -468,10 +487,8 @@ bool is_exclusive(const order * ord)
|
|||
* \return true if the order is long
|
||||
* \sa is_exclusive(), is_repeated(), is_persistent()
|
||||
*/
|
||||
bool is_long(const order * ord)
|
||||
bool is_long(keyword_t kwd)
|
||||
{
|
||||
keyword_t kwd = ORD_KEYWORD(ord);
|
||||
|
||||
switch (kwd) {
|
||||
case K_CAST:
|
||||
case K_BUY:
|
||||
|
@ -522,7 +539,7 @@ bool is_persistent(const order * ord)
|
|||
case K_KOMMENTAR:
|
||||
return true;
|
||||
default:
|
||||
return ord->_persistent || is_repeated(ord);
|
||||
return ord->_persistent || is_repeated(kwd);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -55,8 +55,8 @@ extern "C" {
|
|||
char* get_command(const order *ord, char *buffer, size_t size);
|
||||
bool is_persistent(const order * ord);
|
||||
bool is_exclusive(const order * ord);
|
||||
bool is_repeated(const order * ord);
|
||||
bool is_long(const order * ord);
|
||||
bool is_repeated(keyword_t kwd);
|
||||
bool is_long(keyword_t kwd);
|
||||
|
||||
char *write_order(const order * ord, char *buffer, size_t size);
|
||||
keyword_t init_order(const struct order *ord);
|
||||
|
|
|
@ -139,7 +139,8 @@ static unit *unitorders(FILE * F, int enc, struct faction *f)
|
|||
ordp = &u->old_orders;
|
||||
while (*ordp) {
|
||||
order *ord = *ordp;
|
||||
if (!is_repeated(ord)) {
|
||||
keyword_t kwd = getkeyword(ord);
|
||||
if (!is_repeated(kwd)) {
|
||||
*ordp = ord->next;
|
||||
ord->next = NULL;
|
||||
free_order(ord);
|
||||
|
@ -233,7 +234,7 @@ static faction *factionorders(void)
|
|||
f->no, pass));
|
||||
return 0;
|
||||
}
|
||||
/* Die Partei hat sich zumindest gemeldet, so daß sie noch
|
||||
/* Die Partei hat sich zumindest gemeldet, so dass sie noch
|
||||
* nicht als untätig gilt */
|
||||
|
||||
/* TODO: +1 ist ein Workaround, weil cturn erst in process_orders
|
||||
|
@ -309,8 +310,8 @@ int readorders(const char *filename)
|
|||
* Partei, eine neue Einheit oder das File-Ende. Das switch() wird erneut
|
||||
* durchlaufen, und die entsprechende Funktion aufgerufen. Man darf buf
|
||||
* auf alle Fälle nicht überschreiben! Bei allen anderen Einträgen hier
|
||||
* muß buf erneut gefüllt werden, da die betreffende Information in nur
|
||||
* einer Zeile steht, und nun die nächste gelesen werden muß. */
|
||||
* muss buf erneut gefüllt werden, da die betreffende Information in nur
|
||||
* einer Zeile steht, und nun die nächste gelesen werden muss. */
|
||||
|
||||
case P_NEXT:
|
||||
f = NULL;
|
||||
|
@ -777,7 +778,8 @@ void write_unit(struct gamedata *data, const unit * u)
|
|||
}
|
||||
}
|
||||
for (ord = u->orders; ord; ord = ord->next) {
|
||||
if (u->old_orders && is_repeated(ord))
|
||||
keyword_t kwd = getkeyword(ord);
|
||||
if (u->old_orders && is_repeated(kwd))
|
||||
continue; /* has new defaults */
|
||||
if (is_persistent(ord)) {
|
||||
if (++p < MAXPERSISTENT) {
|
||||
|
@ -1603,7 +1605,6 @@ int readgame(const char *filename, bool backup)
|
|||
|
||||
while (--p >= 0) {
|
||||
unit *u = read_unit(&gdata);
|
||||
sc_mage *mage;
|
||||
|
||||
if (gdata.version < JSON_REPORT_VERSION) {
|
||||
if (u->_name && fval(u->faction, FFL_NPC)) {
|
||||
|
@ -1618,21 +1619,6 @@ int readgame(const char *filename, bool backup)
|
|||
up = &u->next;
|
||||
|
||||
update_interval(u->faction, u->region);
|
||||
mage = get_mage(u);
|
||||
if (mage) {
|
||||
faction *f = u->faction;
|
||||
int skl = effskill(u, SK_MAGIC);
|
||||
if (!fval(f, FFL_NPC) && f->magiegebiet == M_GRAY) {
|
||||
log_error("faction %s had magic=gray, fixing (%s)\n", factionname(f), magic_school[mage->magietyp]);
|
||||
f->magiegebiet = mage->magietyp;
|
||||
}
|
||||
if (f->max_spelllevel < skl) {
|
||||
f->max_spelllevel = skl;
|
||||
}
|
||||
if (mage->spellcount < 0) {
|
||||
mage->spellcount = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
log_printf(stdout, "\n");
|
||||
|
@ -1656,6 +1642,7 @@ int readgame(const char *filename, bool backup)
|
|||
for (f = factions; f; f = f->next) {
|
||||
if (f->flags & FFL_NPC) {
|
||||
f->alive = 1;
|
||||
f->magiegebiet = M_GRAY;
|
||||
if (f->no == 0) {
|
||||
int no = 666;
|
||||
while (findfaction(no))
|
||||
|
@ -1666,8 +1653,23 @@ int readgame(const char *filename, bool backup)
|
|||
}
|
||||
else {
|
||||
for (u = f->units; u; u = u->nextF) {
|
||||
sc_mage *mage = get_mage(u);
|
||||
if (mage) {
|
||||
faction *f = u->faction;
|
||||
int skl = effskill(u, SK_MAGIC);
|
||||
if (f->magiegebiet == M_GRAY) {
|
||||
log_error("faction %s had magic=gray, fixing (%s)\n", factionname(f), magic_school[mage->magietyp]);
|
||||
f->magiegebiet = mage->magietyp;
|
||||
}
|
||||
if (f->max_spelllevel < skl) {
|
||||
f->max_spelllevel = skl;
|
||||
}
|
||||
if (mage->spellcount < 0) {
|
||||
mage->spellcount = 0;
|
||||
}
|
||||
}
|
||||
if (u->number > 0) {
|
||||
f->alive = 1;
|
||||
f->alive = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -127,8 +127,7 @@ const struct terrain_type *newterrain(terrain_t t)
|
|||
terrain_t oldterrain(const struct terrain_type * terrain)
|
||||
{
|
||||
terrain_t t;
|
||||
if (terrain == NULL)
|
||||
return NOTERRAIN;
|
||||
assert(terrain);
|
||||
for (t = 0; t != MAXTERRAINS; ++t) {
|
||||
if (newterrains[t] == terrain)
|
||||
return t;
|
||||
|
|
|
@ -1274,25 +1274,10 @@ static int item_modification(const unit * u, skill_t sk, int val)
|
|||
return val;
|
||||
}
|
||||
|
||||
static int update_gbdream(const unit * u, int bonus, curse *c, const curse_type *gbdream_ct, int sign){
|
||||
if (curse_active(c) && c->type == gbdream_ct) {
|
||||
double effect = curse_geteffect(c);
|
||||
unit *mage = c->magician;
|
||||
/* wir suchen jeweils den groessten Bonus und den groestsen Malus */
|
||||
if (sign * effect > sign * bonus) {
|
||||
if (mage == NULL || mage->number == 0
|
||||
|| (sign>0?alliedunit(mage, u->faction, HELP_GUARD):!alliedunit(mage, u->faction, HELP_GUARD))) {
|
||||
bonus = (int)effect;
|
||||
}
|
||||
}
|
||||
}
|
||||
return bonus;
|
||||
}
|
||||
|
||||
int att_modification(const unit * u, skill_t sk)
|
||||
static int att_modification(const unit * u, skill_t sk)
|
||||
{
|
||||
double result = 0;
|
||||
static bool init = false;
|
||||
static bool init = false; // TODO: static variables are bad global state
|
||||
static const curse_type *skillmod_ct, *gbdream_ct, *worse_ct;
|
||||
curse *c;
|
||||
|
||||
|
@ -1321,15 +1306,21 @@ int att_modification(const unit * u, skill_t sk)
|
|||
/* TODO hier kann nicht mit get/iscursed gearbeitet werden, da nur der
|
||||
* jeweils erste vom Typ C_GBDREAM zurueckgegen wird, wir aber alle
|
||||
* durchsuchen und aufaddieren muessen */
|
||||
if (u->region) {
|
||||
if (gbdream_ct && u->region) {
|
||||
int bonus = 0, malus = 0;
|
||||
attrib *a = a_find(u->region->attribs, &at_curse);
|
||||
while (a && a->type == &at_curse) {
|
||||
curse *c = (curse *)a->data.v;
|
||||
|
||||
bonus = update_gbdream(u, bonus, c, gbdream_ct, 1);
|
||||
malus = update_gbdream(u, malus, c, gbdream_ct, -1);
|
||||
|
||||
if (curse_active(c) && c->type == gbdream_ct) {
|
||||
int effect = curse_geteffect_int(c);
|
||||
bool allied = alliedunit(c->magician, u->faction, HELP_GUARD);
|
||||
if (allied) {
|
||||
if (effect > bonus) bonus = effect;
|
||||
} else {
|
||||
if (effect < malus) malus = effect;
|
||||
}
|
||||
}
|
||||
a = a->next;
|
||||
}
|
||||
result = result + bonus + malus;
|
||||
|
@ -1717,6 +1708,16 @@ int unit_getcapacity(const unit * u)
|
|||
return walkingcapacity(u);
|
||||
}
|
||||
|
||||
void renumber_unit(unit *u, int no) {
|
||||
uunhash(u);
|
||||
if (!ualias(u)) {
|
||||
attrib *a = a_add(&u->attribs, a_new(&at_alias));
|
||||
a->data.i = -u->no;
|
||||
}
|
||||
u->no = no;
|
||||
uhash(u);
|
||||
}
|
||||
|
||||
void unit_addorder(unit * u, order * ord)
|
||||
{
|
||||
order **ordp = &u->orders;
|
||||
|
|
|
@ -127,6 +127,8 @@ extern "C" {
|
|||
int ualias(const struct unit *u);
|
||||
int weight(const struct unit *u);
|
||||
|
||||
void renumber_unit(struct unit *u, int no);
|
||||
|
||||
const struct race *u_irace(const struct unit *u);
|
||||
const struct race *u_race(const struct unit *u);
|
||||
void u_setrace(struct unit *u, const struct race *);
|
||||
|
|
200
src/laws.c
200
src/laws.c
|
@ -183,7 +183,7 @@ static void live(region * r)
|
|||
reduce_skill(u, sb, weeks);
|
||||
ADDMSG(&u->faction->msgs, msg_message("dumbeffect",
|
||||
"unit weeks skill", u, weeks, (skill_t)sb->id));
|
||||
} /* sonst Glück gehabt: wer nix weiß, kann nix vergessen... */
|
||||
} /* sonst Glück gehabt: wer nix weiss, kann nix vergessen... */
|
||||
change_effect(u, oldpotiontype[P_FOOL], -effect);
|
||||
}
|
||||
age_unit(r, u);
|
||||
|
@ -402,7 +402,7 @@ static void migrate(region * r)
|
|||
* wer fragt das? Die Baumwanderung war abhängig von der
|
||||
* Auswertungsreihenfolge der regionen,
|
||||
* das hatte ich geändert. jemand hat es wieder gelöscht, toll.
|
||||
* ich habe es wieder aktiviert, muß getestet werden.
|
||||
* ich habe es wieder aktiviert, muss getestet werden.
|
||||
*/
|
||||
*hp = m->next;
|
||||
m->next = free_migrants;
|
||||
|
@ -442,7 +442,7 @@ static void horses(region * r)
|
|||
|
||||
/* Pferde wandern in Nachbarregionen.
|
||||
* Falls die Nachbarregion noch berechnet
|
||||
* werden muß, wird eine migration-Struktur gebildet,
|
||||
* werden muss, wird eine migration-Struktur gebildet,
|
||||
* die dann erst in die Berechnung der Nachbarstruktur einfließt.
|
||||
*/
|
||||
|
||||
|
@ -632,7 +632,7 @@ growing_trees(region * r, const int current_season, const int last_weeks_season)
|
|||
a->data.sa[0] = (short)rtrees(r, 0);
|
||||
a->data.sa[1] = (short)rtrees(r, 1);
|
||||
}
|
||||
/* wir haben 6 Wochen zum wachsen, jeder Same/Sproß hat 18% Chance
|
||||
/* wir haben 6 Wochen zum wachsen, jeder Same/Spross hat 18% Chance
|
||||
* zu wachsen, damit sollten nach 5-6 Wochen alle gewachsen sein */
|
||||
growth = 1800;
|
||||
|
||||
|
@ -1347,10 +1347,12 @@ int ally_cmd(unit * u, struct order *ord)
|
|||
|
||||
s = gettoken(token, sizeof(token));
|
||||
|
||||
if (s && !s[0])
|
||||
if (!s || !s[0]) {
|
||||
keyword = P_ANY;
|
||||
else
|
||||
}
|
||||
else {
|
||||
keyword = findparam(s, u->faction->locale);
|
||||
}
|
||||
|
||||
sfp = &u->faction->allies;
|
||||
if (fval(u, UFL_GROUP)) {
|
||||
|
@ -1990,7 +1992,7 @@ int mail_cmd(unit * u, struct order *ord)
|
|||
s = gettoken(token, sizeof(token));
|
||||
|
||||
/* Falls kein Parameter, ist das eine Einheitsnummer;
|
||||
* das Füllwort "AN" muß wegfallen, da gültige Nummer! */
|
||||
* das Füllwort "AN" muss wegfallen, da gültige Nummer! */
|
||||
|
||||
do {
|
||||
cont = 0;
|
||||
|
@ -3020,13 +3022,7 @@ int renumber_cmd(unit * u, order * ord)
|
|||
break;
|
||||
}
|
||||
}
|
||||
uunhash(u);
|
||||
if (!ualias(u)) {
|
||||
attrib *a = a_add(&u->attribs, a_new(&at_alias));
|
||||
a->data.i = -u->no;
|
||||
}
|
||||
u->no = i;
|
||||
uhash(u);
|
||||
renumber_unit(u, i);
|
||||
break;
|
||||
|
||||
case P_SHIP:
|
||||
|
@ -3407,126 +3403,101 @@ void new_units(void)
|
|||
}
|
||||
}
|
||||
|
||||
/** Checks for two long orders and issues a warning if necessary.
|
||||
*/
|
||||
void check_long_orders(unit * u)
|
||||
void update_long_order(unit * u)
|
||||
{
|
||||
order *ord;
|
||||
keyword_t otherorder = MAXKEYWORDS;
|
||||
bool exclusive = true;
|
||||
keyword_t thiskwd = NOKEYWORD;
|
||||
bool hunger = LongHunger(u);
|
||||
|
||||
freset(u, UFL_MOVED);
|
||||
freset(u, UFL_LONGACTION);
|
||||
|
||||
/* check all orders for a potential new long order this round: */
|
||||
for (ord = u->orders; ord; ord = ord->next) {
|
||||
if (getkeyword(ord) == NOKEYWORD) {
|
||||
cmistake(u, ord, 22, MSG_EVENT);
|
||||
keyword_t kwd = getkeyword(ord);
|
||||
if (kwd == NOKEYWORD) continue;
|
||||
|
||||
if (u->old_orders && is_repeated(kwd)) {
|
||||
/* this new order will replace the old defaults */
|
||||
free_orders(&u->old_orders);
|
||||
}
|
||||
else if (is_long(ord)) {
|
||||
keyword_t longorder = getkeyword(ord);
|
||||
if (otherorder != MAXKEYWORDS) {
|
||||
switch (longorder) {
|
||||
|
||||
// hungry units do not get long orders:
|
||||
if (hunger) {
|
||||
if (u->old_orders) {
|
||||
// keep looking for repeated orders that might clear the old_orders
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (is_long(kwd)) {
|
||||
if (thiskwd == NOKEYWORD) {
|
||||
// we have found the (first) long order
|
||||
// some long orders can have multiple instances:
|
||||
switch (kwd) {
|
||||
/* Wenn gehandelt wird, darf kein langer Befehl ausgeführt
|
||||
* werden. Da Handel erst nach anderen langen Befehlen kommt,
|
||||
* muss das vorher abgefangen werden. Wir merken uns also
|
||||
* hier, ob die Einheit handelt. */
|
||||
case K_BUY:
|
||||
case K_SELL:
|
||||
case K_CAST:
|
||||
if (otherorder != longorder) {
|
||||
// non-exclusive orders can be used with others. BUY can be paired with SELL,
|
||||
// CAST with other CAST orders. compatibility is checked once the second
|
||||
// long order is analyzed (below).
|
||||
exclusive = false;
|
||||
break;
|
||||
|
||||
default:
|
||||
set_order(&u->thisorder, copy_order(ord));
|
||||
break;
|
||||
}
|
||||
thiskwd = kwd;
|
||||
}
|
||||
else {
|
||||
// we have found a second long order. this is okay for some, but not all commands.
|
||||
// u->thisorder is already set, and should not have to be updated.
|
||||
switch (kwd) {
|
||||
case K_CAST:
|
||||
if (thiskwd != K_CAST) {
|
||||
cmistake(u, ord, 52, MSG_EVENT);
|
||||
}
|
||||
break;
|
||||
case K_SELL:
|
||||
if (thiskwd != K_SELL && thiskwd != K_BUY) {
|
||||
cmistake(u, ord, 52, MSG_EVENT);
|
||||
}
|
||||
break;
|
||||
case K_BUY:
|
||||
if (otherorder == K_SELL) {
|
||||
otherorder = K_BUY;
|
||||
if (thiskwd != K_SELL) {
|
||||
cmistake(u, ord, 52, MSG_EVENT);
|
||||
}
|
||||
else {
|
||||
thiskwd = K_BUY;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
// TODO: decide https://bugs.eressea.de/view.php?id=2080#c6011
|
||||
if (kwd > thiskwd) {
|
||||
// swap out thisorder for the new one
|
||||
cmistake(u, u->thisorder, 52, MSG_EVENT);
|
||||
set_order(&u->thisorder, copy_order(ord));
|
||||
}
|
||||
else {
|
||||
cmistake(u, ord, 52, MSG_EVENT);
|
||||
}
|
||||
break;
|
||||
case K_SELL:
|
||||
if (otherorder != K_SELL && otherorder != K_BUY) {
|
||||
cmistake(u, ord, 52, MSG_EVENT);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
cmistake(u, ord, 52, MSG_EVENT);
|
||||
}
|
||||
}
|
||||
else {
|
||||
otherorder = longorder;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void update_long_order(unit * u)
|
||||
{
|
||||
order *ord;
|
||||
bool trade = false;
|
||||
bool hunger = LongHunger(u);
|
||||
|
||||
freset(u, UFL_MOVED);
|
||||
freset(u, UFL_LONGACTION);
|
||||
if (hunger) {
|
||||
/* Hungernde Einheiten führen NUR den default-Befehl aus */
|
||||
// Hungernde Einheiten führen NUR den default-Befehl aus
|
||||
set_order(&u->thisorder, default_order(u->faction->locale));
|
||||
}
|
||||
else {
|
||||
check_long_orders(u);
|
||||
}
|
||||
/* check all orders for a potential new long order this round: */
|
||||
for (ord = u->orders; ord; ord = ord->next) {
|
||||
if (getkeyword(ord) == NOKEYWORD)
|
||||
continue;
|
||||
|
||||
if (u->old_orders && is_repeated(ord)) {
|
||||
/* this new order will replace the old defaults */
|
||||
free_orders(&u->old_orders);
|
||||
if (hunger)
|
||||
break;
|
||||
}
|
||||
if (hunger)
|
||||
continue;
|
||||
|
||||
if (is_exclusive(ord)) {
|
||||
/* Über dieser Zeile nur Befehle, die auch eine idle Faction machen darf */
|
||||
if (idle(u->faction)) {
|
||||
set_order(&u->thisorder, default_order(u->faction->locale));
|
||||
}
|
||||
else {
|
||||
set_order(&u->thisorder, copy_order(ord));
|
||||
}
|
||||
break;
|
||||
}
|
||||
else {
|
||||
keyword_t keyword = getkeyword(ord);
|
||||
switch (keyword) {
|
||||
/* Wenn gehandelt wird, darf kein langer Befehl ausgeführt
|
||||
* werden. Da Handel erst nach anderen langen Befehlen kommt,
|
||||
* muß das vorher abgefangen werden. Wir merken uns also
|
||||
* hier, ob die Einheit handelt. */
|
||||
case K_BUY:
|
||||
case K_SELL:
|
||||
/* Wenn die Einheit handelt, muß der Default-Befehl gelöscht
|
||||
* werden.
|
||||
* Wird je diese Ausschliesslichkeit aufgehoben, muss man aufpassen
|
||||
* mit der Reihenfolge von Kaufen, Verkaufen etc., damit es Spielern
|
||||
* nicht moeglich ist, Schulden zu machen. */
|
||||
trade = true;
|
||||
break;
|
||||
|
||||
case K_CAST:
|
||||
/* dient dazu, das neben Zaubern kein weiterer Befehl
|
||||
* ausgeführt werden kann, Zaubern ist ein kurzer Befehl */
|
||||
set_order(&u->thisorder, copy_order(ord));
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (hunger) {
|
||||
return;
|
||||
}
|
||||
/* Wenn die Einheit handelt, muß der Default-Befehl gelöscht
|
||||
* werden. */
|
||||
|
||||
if (trade) {
|
||||
/* fset(u, UFL_LONGACTION|UFL_NOTMOVING); */
|
||||
} else if (!exclusive) {
|
||||
// Wenn die Einheit handelt oder zaubert, muss der Default-Befehl gelöscht werden.
|
||||
set_order(&u->thisorder, NULL);
|
||||
}
|
||||
}
|
||||
|
@ -3696,6 +3667,7 @@ void defaultorders(void)
|
|||
free_order(ord);
|
||||
if (!neworders) {
|
||||
/* lange Befehle aus orders und old_orders löschen zu gunsten des neuen */
|
||||
// TODO: why only is_exclusive, not is_long? what about CAST, BUY, SELL?
|
||||
remove_exclusive(&u->orders);
|
||||
remove_exclusive(&u->old_orders);
|
||||
neworders = true;
|
||||
|
@ -4489,7 +4461,7 @@ void init_processor(void)
|
|||
add_proc_order(p, K_TEACH, teach_cmd, PROC_THISORDER | PROC_LONGORDER,
|
||||
"Lehren");
|
||||
p += 10;
|
||||
add_proc_order(p, K_STUDY, learn_cmd, PROC_THISORDER | PROC_LONGORDER,
|
||||
add_proc_order(p, K_STUDY, study_cmd, PROC_THISORDER | PROC_LONGORDER,
|
||||
"Lernen");
|
||||
|
||||
p += 10;
|
||||
|
|
18
src/laws.h
18
src/laws.h
|
@ -56,15 +56,15 @@ extern "C" {
|
|||
extern int *age;
|
||||
|
||||
|
||||
extern void new_units(void);
|
||||
extern void defaultorders(void);
|
||||
extern void quit(void);
|
||||
extern void monthly_healing(void);
|
||||
extern void renumber_factions(void);
|
||||
extern void restack_units(void);
|
||||
extern void update_long_order(struct unit *u);
|
||||
extern void sinkships(struct region * r);
|
||||
extern void do_enter(struct region *r, bool is_final_attempt);
|
||||
void new_units(void);
|
||||
void defaultorders(void);
|
||||
void quit(void);
|
||||
void monthly_healing(void);
|
||||
void renumber_factions(void);
|
||||
void restack_units(void);
|
||||
void update_long_order(struct unit *u);
|
||||
void sinkships(struct region * r);
|
||||
void do_enter(struct region *r, bool is_final_attempt);
|
||||
|
||||
extern int password_cmd(struct unit *u, struct order *ord);
|
||||
extern int banner_cmd(struct unit *u, struct order *ord);
|
||||
|
|
217
src/laws.test.c
217
src/laws.test.c
|
@ -1,6 +1,7 @@
|
|||
#include <platform.h>
|
||||
#include "laws.h"
|
||||
#include "battle.h"
|
||||
#include "monster.h"
|
||||
|
||||
#include <kernel/ally.h>
|
||||
#include <kernel/config.h>
|
||||
|
@ -768,9 +769,225 @@ static void test_luck_message(CuTest *tc) {
|
|||
test_cleanup();
|
||||
}
|
||||
|
||||
static void test_long_order_normal(CuTest *tc) {
|
||||
// TODO: write more tests
|
||||
unit *u;
|
||||
order *ord;
|
||||
test_cleanup();
|
||||
u = test_create_unit(test_create_faction(0), test_create_region(0, 0, 0));
|
||||
fset(u, UFL_MOVED);
|
||||
fset(u, UFL_LONGACTION);
|
||||
u->faction->locale = get_or_create_locale("de");
|
||||
ord = create_order(K_MOVE, u->faction->locale, 0);
|
||||
unit_addorder(u, ord);
|
||||
update_long_order(u);
|
||||
CuAssertPtrEquals(tc, ord->data, u->thisorder->data);
|
||||
CuAssertIntEquals(tc, 0, fval(u, UFL_MOVED));
|
||||
CuAssertIntEquals(tc, 0, fval(u, UFL_LONGACTION));
|
||||
CuAssertPtrNotNull(tc, u->orders);
|
||||
CuAssertPtrEquals(tc, 0, u->faction->msgs);
|
||||
CuAssertPtrEquals(tc, 0, u->old_orders);
|
||||
test_cleanup();
|
||||
}
|
||||
|
||||
static void test_long_order_none(CuTest *tc) {
|
||||
// TODO: write more tests
|
||||
unit *u;
|
||||
test_cleanup();
|
||||
u = test_create_unit(test_create_faction(0), test_create_region(0, 0, 0));
|
||||
u->faction->locale = get_or_create_locale("de");
|
||||
update_long_order(u);
|
||||
CuAssertPtrEquals(tc, 0, u->thisorder);
|
||||
CuAssertPtrEquals(tc, 0, u->orders);
|
||||
CuAssertPtrEquals(tc, 0, u->faction->msgs);
|
||||
test_cleanup();
|
||||
}
|
||||
|
||||
static void test_long_order_cast(CuTest *tc) {
|
||||
// TODO: write more tests
|
||||
unit *u;
|
||||
test_cleanup();
|
||||
u = test_create_unit(test_create_faction(0), test_create_region(0, 0, 0));
|
||||
u->faction->locale = get_or_create_locale("de");
|
||||
unit_addorder(u, create_order(K_CAST, u->faction->locale, 0));
|
||||
unit_addorder(u, create_order(K_CAST, u->faction->locale, 0));
|
||||
update_long_order(u);
|
||||
CuAssertPtrEquals(tc, 0, u->thisorder);
|
||||
CuAssertPtrNotNull(tc, u->orders);
|
||||
CuAssertPtrEquals(tc, 0, u->faction->msgs);
|
||||
test_cleanup();
|
||||
}
|
||||
|
||||
static void test_long_order_buy_sell(CuTest *tc) {
|
||||
// TODO: write more tests
|
||||
unit *u;
|
||||
test_cleanup();
|
||||
u = test_create_unit(test_create_faction(0), test_create_region(0, 0, 0));
|
||||
u->faction->locale = get_or_create_locale("de");
|
||||
unit_addorder(u, create_order(K_BUY, u->faction->locale, 0));
|
||||
unit_addorder(u, create_order(K_SELL, u->faction->locale, 0));
|
||||
unit_addorder(u, create_order(K_SELL, u->faction->locale, 0));
|
||||
update_long_order(u);
|
||||
CuAssertPtrEquals(tc, 0, u->thisorder);
|
||||
CuAssertPtrNotNull(tc, u->orders);
|
||||
CuAssertPtrEquals(tc, 0, u->faction->msgs);
|
||||
test_cleanup();
|
||||
}
|
||||
|
||||
static void test_long_order_multi_long(CuTest *tc) {
|
||||
// TODO: write more tests
|
||||
unit *u;
|
||||
test_cleanup();
|
||||
u = test_create_unit(test_create_faction(0), test_create_region(0, 0, 0));
|
||||
u->faction->locale = get_or_create_locale("de");
|
||||
unit_addorder(u, create_order(K_MOVE, u->faction->locale, 0));
|
||||
unit_addorder(u, create_order(K_DESTROY, u->faction->locale, 0));
|
||||
update_long_order(u);
|
||||
CuAssertPtrNotNull(tc, u->thisorder);
|
||||
CuAssertPtrNotNull(tc, u->orders);
|
||||
CuAssertStrEquals(tc, "error52", test_get_messagetype(u->faction->msgs->begin->msg));
|
||||
test_cleanup();
|
||||
}
|
||||
|
||||
static void test_long_order_multi_buy(CuTest *tc) {
|
||||
// TODO: write more tests
|
||||
unit *u;
|
||||
test_cleanup();
|
||||
u = test_create_unit(test_create_faction(0), test_create_region(0, 0, 0));
|
||||
u->faction->locale = get_or_create_locale("de");
|
||||
unit_addorder(u, create_order(K_BUY, u->faction->locale, 0));
|
||||
unit_addorder(u, create_order(K_BUY, u->faction->locale, 0));
|
||||
update_long_order(u);
|
||||
CuAssertPtrEquals(tc, 0, u->thisorder);
|
||||
CuAssertPtrNotNull(tc, u->orders);
|
||||
CuAssertStrEquals(tc, "error52", test_get_messagetype(u->faction->msgs->begin->msg));
|
||||
test_cleanup();
|
||||
}
|
||||
|
||||
static void test_long_order_multi_sell(CuTest *tc) {
|
||||
// TODO: write more tests
|
||||
unit *u;
|
||||
test_cleanup();
|
||||
u = test_create_unit(test_create_faction(0), test_create_region(0, 0, 0));
|
||||
u->faction->locale = get_or_create_locale("de");
|
||||
unit_addorder(u, create_order(K_SELL, u->faction->locale, 0));
|
||||
unit_addorder(u, create_order(K_BUY, u->faction->locale, 0));
|
||||
unit_addorder(u, create_order(K_SELL, u->faction->locale, 0));
|
||||
update_long_order(u);
|
||||
CuAssertPtrEquals(tc, 0, u->thisorder);
|
||||
CuAssertPtrNotNull(tc, u->orders);
|
||||
CuAssertPtrEquals(tc, 0, u->faction->msgs);
|
||||
test_cleanup();
|
||||
}
|
||||
|
||||
static void test_long_order_buy_cast(CuTest *tc) {
|
||||
// TODO: write more tests
|
||||
unit *u;
|
||||
test_cleanup();
|
||||
u = test_create_unit(test_create_faction(0), test_create_region(0, 0, 0));
|
||||
u->faction->locale = get_or_create_locale("de");
|
||||
unit_addorder(u, create_order(K_BUY, u->faction->locale, 0));
|
||||
unit_addorder(u, create_order(K_CAST, u->faction->locale, 0));
|
||||
update_long_order(u);
|
||||
CuAssertPtrEquals(tc, 0, u->thisorder);
|
||||
CuAssertPtrNotNull(tc, u->orders);
|
||||
CuAssertStrEquals(tc, "error52", test_get_messagetype(u->faction->msgs->begin->msg));
|
||||
test_cleanup();
|
||||
}
|
||||
|
||||
static void test_long_order_hungry(CuTest *tc) {
|
||||
// TODO: write more tests
|
||||
unit *u;
|
||||
test_cleanup();
|
||||
set_param(&global.parameters, "hunger.long", "1");
|
||||
u = test_create_unit(test_create_faction(0), test_create_region(0, 0, 0));
|
||||
fset(u, UFL_HUNGER);
|
||||
u->faction->locale = get_or_create_locale("de");
|
||||
unit_addorder(u, create_order(K_MOVE, u->faction->locale, 0));
|
||||
unit_addorder(u, create_order(K_DESTROY, u->faction->locale, 0));
|
||||
set_default_order(K_WORK);
|
||||
update_long_order(u);
|
||||
CuAssertIntEquals(tc, K_WORK, getkeyword(u->thisorder));
|
||||
CuAssertPtrNotNull(tc, u->orders);
|
||||
CuAssertPtrEquals(tc, 0, u->faction->msgs);
|
||||
set_default_order(NOKEYWORD);
|
||||
test_cleanup();
|
||||
}
|
||||
|
||||
static void test_ally_cmd_errors(CuTest *tc) {
|
||||
unit *u;
|
||||
int fid;
|
||||
order *ord;
|
||||
|
||||
test_cleanup();
|
||||
u = test_create_unit(test_create_faction(0), test_create_region(0, 0, 0));
|
||||
u->faction->locale = get_or_create_locale("de");
|
||||
fid = u->faction->no + 1;
|
||||
CuAssertPtrEquals(tc, 0, findfaction(fid));
|
||||
|
||||
ord = create_order(K_ALLY, u->faction->locale, itoa36(fid));
|
||||
ally_cmd(u, ord);
|
||||
CuAssertStrEquals(tc, "error66", test_get_messagetype(u->faction->msgs->begin->msg));
|
||||
free_order(ord);
|
||||
|
||||
test_cleanup();
|
||||
}
|
||||
|
||||
static void test_ally_cmd(CuTest *tc) {
|
||||
unit *u;
|
||||
faction * f;
|
||||
order *ord;
|
||||
struct locale *lang;
|
||||
|
||||
test_cleanup();
|
||||
u = test_create_unit(test_create_faction(0), test_create_region(0, 0, 0));
|
||||
f = test_create_faction(0);
|
||||
u->faction->locale = lang = get_or_create_locale("de");
|
||||
locale_setstring(lang, parameters[P_NOT], "NICHT");
|
||||
locale_setstring(lang, parameters[P_GUARD], "BEWACHE");
|
||||
init_parameters(lang);
|
||||
|
||||
ord = create_order(K_ALLY, lang, "%s", itoa36(f->no));
|
||||
ally_cmd(u, ord);
|
||||
CuAssertPtrEquals(tc, 0, u->faction->msgs);
|
||||
CuAssertIntEquals(tc, HELP_ALL, alliedfaction(0, u->faction, f, HELP_ALL));
|
||||
free_order(ord);
|
||||
|
||||
ord = create_order(K_ALLY, lang, "%s NICHT", itoa36(f->no));
|
||||
ally_cmd(u, ord);
|
||||
CuAssertPtrEquals(tc, 0, u->faction->msgs);
|
||||
CuAssertIntEquals(tc, 0, alliedfaction(0, u->faction, f, HELP_ALL));
|
||||
free_order(ord);
|
||||
|
||||
ord = create_order(K_ALLY, lang, "%s BEWACHE", itoa36(f->no));
|
||||
ally_cmd(u, ord);
|
||||
CuAssertPtrEquals(tc, 0, u->faction->msgs);
|
||||
CuAssertIntEquals(tc, HELP_GUARD, alliedfaction(0, u->faction, f, HELP_ALL));
|
||||
free_order(ord);
|
||||
|
||||
ord = create_order(K_ALLY, lang, "%s BEWACHE NICHT", itoa36(f->no));
|
||||
ally_cmd(u, ord);
|
||||
CuAssertPtrEquals(tc, 0, u->faction->msgs);
|
||||
CuAssertIntEquals(tc, 0, alliedfaction(0, u->faction, f, HELP_ALL));
|
||||
free_order(ord);
|
||||
|
||||
test_cleanup();
|
||||
}
|
||||
|
||||
CuSuite *get_laws_suite(void)
|
||||
{
|
||||
CuSuite *suite = CuSuiteNew();
|
||||
SUITE_ADD_TEST(suite, test_ally_cmd);
|
||||
SUITE_ADD_TEST(suite, test_ally_cmd_errors);
|
||||
SUITE_ADD_TEST(suite, test_long_order_normal);
|
||||
SUITE_ADD_TEST(suite, test_long_order_none);
|
||||
SUITE_ADD_TEST(suite, test_long_order_cast);
|
||||
SUITE_ADD_TEST(suite, test_long_order_buy_sell);
|
||||
SUITE_ADD_TEST(suite, test_long_order_multi_long);
|
||||
SUITE_ADD_TEST(suite, test_long_order_multi_buy);
|
||||
SUITE_ADD_TEST(suite, test_long_order_multi_sell);
|
||||
SUITE_ADD_TEST(suite, test_long_order_buy_cast);
|
||||
SUITE_ADD_TEST(suite, test_long_order_hungry);
|
||||
SUITE_ADD_TEST(suite, test_new_building_can_be_renamed);
|
||||
SUITE_ADD_TEST(suite, test_rename_building);
|
||||
SUITE_ADD_TEST(suite, test_rename_building_twice);
|
||||
|
|
26
src/magic.c
26
src/magic.c
|
@ -777,7 +777,7 @@ int spellcost(unit * u, const spell * sp)
|
|||
int count = countspells(u, 0);
|
||||
const resource_type *r_aura = get_resourcetype(R_AURA);
|
||||
|
||||
for (k = 0; sp->components[k].type; k++) {
|
||||
for (k = 0; sp->components && sp->components[k].type; k++) {
|
||||
if (sp->components[k].type == r_aura) {
|
||||
aura = sp->components[k].amount;
|
||||
}
|
||||
|
@ -798,7 +798,7 @@ static int spl_costtyp(const spell * sp)
|
|||
int k;
|
||||
int costtyp = SPC_FIX;
|
||||
|
||||
for (k = 0; sp->components[k].type; k++) {
|
||||
for (k = 0; sp->components && sp->components[k].type; k++) {
|
||||
if (costtyp == SPC_LINEAR)
|
||||
return SPC_LINEAR;
|
||||
|
||||
|
@ -827,7 +827,7 @@ int eff_spelllevel(unit * u, const spell * sp, int cast_level, int range)
|
|||
int k, maxlevel, needplevel;
|
||||
int costtyp = SPC_FIX;
|
||||
|
||||
for (k = 0; sp->components[k].type; k++) {
|
||||
for (k = 0; sp->components && sp->components[k].type; k++) {
|
||||
if (cast_level == 0)
|
||||
return 0;
|
||||
|
||||
|
@ -894,7 +894,7 @@ void pay_spell(unit * u, const spell * sp, int cast_level, int range)
|
|||
int resuse;
|
||||
|
||||
assert(cast_level > 0);
|
||||
for (k = 0; sp->components[k].type; k++) {
|
||||
for (k = 0; sp->components && sp->components[k].type; k++) {
|
||||
if (sp->components[k].type == r_aura) {
|
||||
resuse = spellcost(u, sp) * range;
|
||||
}
|
||||
|
@ -954,7 +954,7 @@ cancast(unit * u, const spell * sp, int level, int range, struct order * ord)
|
|||
return false;
|
||||
}
|
||||
|
||||
for (k = 0; sp->components[k].type; ++k) {
|
||||
for (k = 0; sp->components && sp->components[k].type; ++k) {
|
||||
if (sp->components[k].amount > 0) {
|
||||
const resource_type *rtype = sp->components[k].type;
|
||||
int itemhave;
|
||||
|
@ -2766,15 +2766,13 @@ void magic(void)
|
|||
continue;
|
||||
}
|
||||
|
||||
if (u->thisorder != NULL) {
|
||||
for (ord = u->orders; ord; ord = ord->next) {
|
||||
if (getkeyword(ord) == K_CAST) {
|
||||
castorder *co = cast_cmd(u, ord);
|
||||
fset(u, UFL_LONGACTION | UFL_NOTMOVING);
|
||||
if (co) {
|
||||
const spell *sp = co->sp;
|
||||
add_castorder(&spellranks[sp->rank], co);
|
||||
}
|
||||
for (ord = u->orders; ord; ord = ord->next) {
|
||||
if (getkeyword(ord) == K_CAST) {
|
||||
castorder *co = cast_cmd(u, ord);
|
||||
fset(u, UFL_LONGACTION | UFL_NOTMOVING);
|
||||
if (co) {
|
||||
const spell *sp = co->sp;
|
||||
add_castorder(&spellranks[sp->rank], co);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
#include "magic.h"
|
||||
|
||||
#include <kernel/faction.h>
|
||||
#include <kernel/order.h>
|
||||
#include <kernel/item.h>
|
||||
#include <kernel/region.h>
|
||||
#include <kernel/spell.h>
|
||||
|
@ -382,9 +383,45 @@ void test_hasspell(CuTest * tc)
|
|||
test_cleanup();
|
||||
}
|
||||
|
||||
static quicklist * casts;
|
||||
|
||||
static int cast_fireball(struct castorder * co) {
|
||||
ql_push(&casts, co);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void test_multi_cast(CuTest *tc) {
|
||||
unit *u;
|
||||
spell *sp;
|
||||
struct locale * lang;
|
||||
|
||||
test_cleanup();
|
||||
sp = create_spell("fireball", 0);
|
||||
sp->cast = cast_fireball;
|
||||
CuAssertPtrEquals(tc, sp, find_spell("fireball"));
|
||||
|
||||
u = test_create_unit(test_create_faction(0), test_create_region(0, 0, 0));
|
||||
u->faction->locale = lang = get_or_create_locale("de");
|
||||
locale_setstring(lang, mkname("spell", sp->sname), "Feuerball");
|
||||
CuAssertStrEquals(tc, "Feuerball", spell_name(sp, lang));
|
||||
set_level(u, SK_MAGIC, 10);
|
||||
unit_add_spell(u, 0, sp, 1);
|
||||
CuAssertPtrEquals(tc, sp, unit_getspell(u, "Feuerball", lang));
|
||||
|
||||
unit_addorder(u, create_order(K_CAST, u->faction->locale, "Feuerball"));
|
||||
unit_addorder(u, create_order(K_CAST, u->faction->locale, "Feuerball"));
|
||||
CuAssertPtrEquals(tc, casts, 0);
|
||||
magic();
|
||||
CuAssertPtrNotNull(tc, casts);
|
||||
CuAssertIntEquals(tc, 2, ql_length(casts));
|
||||
ql_free(casts);
|
||||
test_cleanup();
|
||||
}
|
||||
|
||||
CuSuite *get_magic_suite(void)
|
||||
{
|
||||
CuSuite *suite = CuSuiteNew();
|
||||
SUITE_ADD_TEST(suite, test_multi_cast);
|
||||
SUITE_ADD_TEST(suite, test_updatespells);
|
||||
SUITE_ADD_TEST(suite, test_spellbooks);
|
||||
SUITE_ADD_TEST(suite, test_pay_spell);
|
||||
|
|
|
@ -366,7 +366,7 @@ static int canwalk(unit * u)
|
|||
return E_CANWALK_TOOMANYCARTS;
|
||||
/* Es muß nicht zwingend an den Wagen liegen, aber egal... (man
|
||||
* könnte z.B. auch 8 Eisen abladen, damit ein weiterer Wagen als
|
||||
* Fracht draufpaßt) */
|
||||
* Fracht draufpasst) */
|
||||
|
||||
return E_CANWALK_TOOHEAVY;
|
||||
}
|
||||
|
|
|
@ -1471,14 +1471,12 @@ report_template(const char *filename, report_context * ctx, const char *charset)
|
|||
newline(out);
|
||||
newline(out);
|
||||
|
||||
sprintf(buf, "%s %s \"%s\"", LOC(f->locale, "ERESSEA"), factionid(f),
|
||||
LOC(f->locale, "enterpasswd"));
|
||||
sprintf(buf, "%s %s \"%s\"", LOC(f->locale, "ERESSEA"), factionid(f), f->passw);
|
||||
rps_nowrap(out, buf);
|
||||
newline(out);
|
||||
newline(out);
|
||||
sprintf(buf, "; ECHECK -l -w4 -r%d -v%s", f->race->recruitcost,
|
||||
ECHECK_VERSION);
|
||||
/* -v3.4: ECheck Version 3.4.x */
|
||||
rps_nowrap(out, buf);
|
||||
newline(out);
|
||||
|
||||
|
@ -1575,7 +1573,8 @@ report_template(const char *filename, report_context * ctx, const char *charset)
|
|||
newline(out);
|
||||
}
|
||||
for (ord = u->orders; ord; ord = ord->next) {
|
||||
if (u->old_orders && is_repeated(ord))
|
||||
keyword_t kwd = getkeyword(ord);
|
||||
if (u->old_orders && is_repeated(kwd))
|
||||
continue; /* unit has defaults */
|
||||
if (is_persistent(ord)) {
|
||||
strcpy(buf, " ");
|
||||
|
|
|
@ -52,6 +52,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|||
#include <util/language.h>
|
||||
#include <util/lists.h>
|
||||
#include <util/log.h>
|
||||
#include <stream.h>
|
||||
#include <quicklist.h>
|
||||
|
||||
/* libc includes */
|
||||
|
@ -59,6 +60,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|||
#include <errno.h>
|
||||
#include <limits.h>
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
|
||||
|
@ -793,7 +795,8 @@ size_t size)
|
|||
bool printed = 0;
|
||||
order *ord;;
|
||||
for (ord = u->old_orders; ord; ord = ord->next) {
|
||||
if (is_repeated(ord)) {
|
||||
keyword_t kwd = getkeyword(ord);
|
||||
if (is_repeated(kwd)) {
|
||||
if (printed < ORDERS_IN_NR) {
|
||||
bytes = buforder(bufp, size, ord, printed++);
|
||||
if (wrptr(&bufp, &size, bytes) != 0)
|
||||
|
@ -805,7 +808,8 @@ size_t size)
|
|||
}
|
||||
if (printed < ORDERS_IN_NR)
|
||||
for (ord = u->orders; ord; ord = ord->next) {
|
||||
if (is_repeated(ord)) {
|
||||
keyword_t kwd = getkeyword(ord);
|
||||
if (is_repeated(kwd)) {
|
||||
if (printed < ORDERS_IN_NR) {
|
||||
bytes = buforder(bufp, size, ord, printed++);
|
||||
if (wrptr(&bufp, &size, bytes) != 0)
|
||||
|
@ -2291,7 +2295,7 @@ static void eval_race(struct opstack **stack, const void *userdata)
|
|||
static void eval_order(struct opstack **stack, const void *userdata)
|
||||
{ /* order -> string */
|
||||
const struct order *ord = (const struct order *)opop(stack).v;
|
||||
char buf[512];
|
||||
char buf[4096];
|
||||
size_t len;
|
||||
variant var;
|
||||
|
||||
|
@ -2497,6 +2501,23 @@ static void log_orders(const struct message *msg)
|
|||
}
|
||||
}
|
||||
|
||||
int stream_printf(struct stream * out, const char *format, ...) {
|
||||
va_list args;
|
||||
int result;
|
||||
char buffer[4096];
|
||||
size_t bytes = sizeof(buffer);
|
||||
// TODO: should be in storage/stream.c (doesn't exist yet)
|
||||
va_start(args, format);
|
||||
result = vsnprintf(buffer, bytes, format, args);
|
||||
if (result >= 0 && (size_t)result < bytes) {
|
||||
bytes = (size_t)result;
|
||||
// TODO: else = buffer too small
|
||||
}
|
||||
out->api->write(out->handle, buffer, bytes);
|
||||
va_end(args);
|
||||
return result;
|
||||
}
|
||||
|
||||
void register_reports(void)
|
||||
{
|
||||
/* register datatypes for the different message objects */
|
||||
|
|
|
@ -25,6 +25,8 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|||
#include <kernel/objtypes.h>
|
||||
#include <kernel/types.h>
|
||||
|
||||
struct stream;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
@ -153,6 +155,7 @@ extern "C" {
|
|||
void freestrlist(strlist * s);
|
||||
void split_paragraph(strlist ** SP, const char *s, unsigned int indent, unsigned int width, char mark);
|
||||
|
||||
int stream_printf(struct stream * out, const char *format, ...);
|
||||
|
||||
#define GR_PLURAL 0x01 /* grammar: plural */
|
||||
#define MAX_INVENTORY 128 /* maimum number of different items in an inventory */
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
#include <config.h>
|
||||
#include "reports.h"
|
||||
#include "report.h"
|
||||
#include "creport.h"
|
||||
|
||||
#include <kernel/building.h>
|
||||
#include <kernel/faction.h>
|
||||
|
@ -155,9 +156,32 @@ static void test_sparagraph(CuTest *tc) {
|
|||
CuAssertPtrEquals(tc, 0, sp->next->next->next);
|
||||
}
|
||||
|
||||
static void test_cr_unit(CuTest *tc) {
|
||||
stream strm;
|
||||
char line[1024];
|
||||
faction *f;
|
||||
region *r;
|
||||
unit *u;
|
||||
|
||||
test_cleanup();
|
||||
f = test_create_faction(0);
|
||||
r = test_create_region(0, 0, 0);
|
||||
u = test_create_unit(f, r);
|
||||
renumber_unit(u, 1234);
|
||||
|
||||
mstream_init(&strm);
|
||||
cr_output_unit(&strm, r, f, u, see_unit);
|
||||
strm.api->rewind(strm.handle);
|
||||
CuAssertIntEquals(tc, 0, strm.api->readln(strm.handle, line, sizeof(line)));
|
||||
CuAssertStrEquals(tc, line, "EINHEIT 1234");
|
||||
mstream_done(&strm);
|
||||
test_cleanup();
|
||||
}
|
||||
|
||||
CuSuite *get_reports_suite(void)
|
||||
{
|
||||
CuSuite *suite = CuSuiteNew();
|
||||
SUITE_ADD_TEST(suite, test_cr_unit);
|
||||
SUITE_ADD_TEST(suite, test_reorder_units);
|
||||
SUITE_ADD_TEST(suite, test_seen_faction);
|
||||
SUITE_ADD_TEST(suite, test_regionid);
|
||||
|
|
|
@ -20,13 +20,10 @@
|
|||
#include <assert.h>
|
||||
|
||||
|
||||
static struct castorder *test_create_castorder(castorder *order, unit *u, const char *name, int level, float force, int range) {
|
||||
static void test_create_castorder(castorder *order, unit *u, int level, float force, int range) {
|
||||
struct locale * lang;
|
||||
spell *sp;
|
||||
|
||||
lang = get_or_create_locale("en");
|
||||
sp = create_spell(name, 0);
|
||||
return order = create_castorder(order, u, NULL, sp, u->region, level, force, range, create_order(K_CAST, lang, ""), NULL);
|
||||
create_castorder(order, u, NULL, NULL, u->region, level, force, range, create_order(K_CAST, lang, ""), NULL);
|
||||
}
|
||||
|
||||
static void test_dreams(CuTest *tc) {
|
||||
|
@ -39,12 +36,12 @@ static void test_dreams(CuTest *tc) {
|
|||
test_cleanup();
|
||||
test_create_world();
|
||||
r=findregion(0, 0);
|
||||
f1 = test_create_faction(test_create_race("human"));
|
||||
f2 = test_create_faction(test_create_race("human"));
|
||||
f1 = test_create_faction(0);
|
||||
f2 = test_create_faction(0);
|
||||
u1 = test_create_unit(f1, r);
|
||||
u2 = test_create_unit(f2, r);
|
||||
|
||||
test_create_castorder(&order, u1, "goodreams", 10, 10., 0);
|
||||
test_create_castorder(&order, u1, 10, 10., 0);
|
||||
level = sp_gooddreams(&order);
|
||||
CuAssertIntEquals(tc, 10, level);
|
||||
|
||||
|
@ -57,7 +54,7 @@ static void test_dreams(CuTest *tc) {
|
|||
CuAssertIntEquals(tc, 1, get_modifier(u1, SK_MELEE, 11, r, false));
|
||||
CuAssertIntEquals(tc, 0, get_modifier(u2, SK_MELEE, 11, r, false));
|
||||
|
||||
test_create_castorder(&order, u1, "baddreams", 10, 10., 0);
|
||||
test_create_castorder(&order, u1, 10, 10., 0);
|
||||
level = sp_baddreams(&order);
|
||||
CuAssertIntEquals(tc, 10, level);
|
||||
|
||||
|
|
|
@ -123,9 +123,9 @@ static void update_faction(sqlite3 *db, const faction *f) {
|
|||
"INSERT INTO faction_data (faction_id, code, name, email, lang, turn)"
|
||||
" VALUES (?, ?, ?, ?, ?, ?)";
|
||||
sqlite3_stmt *stmt = 0;
|
||||
strcpy(code, itoa36(f->no));
|
||||
sqlite3_prepare_v2(db, sql, -1, &stmt, 0);
|
||||
sqlite3_bind_int(stmt, 1, f->subscription);
|
||||
strcpy(code, itoa36(f->no));
|
||||
sqlite3_bind_text(stmt, 2, code, -1, SQLITE_STATIC);
|
||||
sqlite3_bind_text(stmt, 3, f->name, -1, SQLITE_STATIC);
|
||||
sqlite3_bind_text(stmt, 4, f->email, -1, SQLITE_STATIC);
|
||||
|
|
|
@ -222,7 +222,7 @@ bool report, int *academy)
|
|||
teach->teachers[index] = NULL;
|
||||
}
|
||||
else {
|
||||
log_warning("MAXTEACHERS is too low at %d", MAXTEACHERS);
|
||||
log_error("MAXTEACHERS=%d is too low for student %s, teacher %s", MAXTEACHERS, unitname(student), unitname(teacher));
|
||||
}
|
||||
teach->value += n;
|
||||
|
||||
|
@ -527,7 +527,7 @@ static double study_speedup(unit * u, skill_t s, study_rule_t rule)
|
|||
return 1.0;
|
||||
}
|
||||
|
||||
int learn_cmd(unit * u, order * ord)
|
||||
int study_cmd(unit * u, order * ord)
|
||||
{
|
||||
region *r = u->region;
|
||||
int p;
|
||||
|
|
|
@ -20,19 +20,20 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|||
#define H_KRNL_STUDY
|
||||
|
||||
#include "skill.h"
|
||||
#include <kernel/types.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
extern int teach_cmd(struct unit *u, struct order *ord);
|
||||
extern int learn_cmd(struct unit *u, struct order *ord);
|
||||
extern int study_cmd(struct unit *u, struct order *ord);
|
||||
|
||||
extern magic_t getmagicskill(const struct locale *lang);
|
||||
extern bool is_migrant(struct unit *u);
|
||||
extern int study_cost(struct unit *u, skill_t talent);
|
||||
|
||||
#define MAXTEACHERS 16
|
||||
#define MAXTEACHERS 20
|
||||
typedef struct teaching_info {
|
||||
struct unit *teachers[MAXTEACHERS];
|
||||
int value;
|
||||
|
|
|
@ -0,0 +1,99 @@
|
|||
#include <platform.h>
|
||||
|
||||
#include "study.h"
|
||||
|
||||
#include <kernel/unit.h>
|
||||
#include <kernel/faction.h>
|
||||
#include <kernel/order.h>
|
||||
#include <util/message.h>
|
||||
#include <util/language.h>
|
||||
#include <util/base36.h>
|
||||
#include <tests.h>
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#include <CuTest.h>
|
||||
|
||||
typedef struct {
|
||||
unit *u;
|
||||
unit *teachers[2];
|
||||
} study_fixture;
|
||||
|
||||
static void setup_study(study_fixture *fix, skill_t sk) {
|
||||
struct region * r;
|
||||
struct faction *f;
|
||||
struct locale *lang;
|
||||
|
||||
assert(fix);
|
||||
test_cleanup();
|
||||
test_create_world();
|
||||
r = test_create_region(0, 0, 0);
|
||||
f = test_create_faction(0);
|
||||
lang = get_or_create_locale(locale_name(f->locale));
|
||||
locale_setstring(lang, mkname("skill", skillnames[sk]), skillnames[sk]);
|
||||
init_skills(lang);
|
||||
fix->u = test_create_unit(f, r);
|
||||
assert(fix->u);
|
||||
fix->u->thisorder = create_order(K_STUDY, f->locale, "%s", skillnames[sk]);
|
||||
|
||||
fix->teachers[0] = test_create_unit(f, r);
|
||||
assert(fix->teachers[0]);
|
||||
fix->teachers[0]->thisorder = create_order(K_TEACH, f->locale, "%s", itoa36(fix->u->no));
|
||||
|
||||
fix->teachers[1] = test_create_unit(f, r);
|
||||
assert(fix->teachers[1]);
|
||||
fix->teachers[1]->thisorder = create_order(K_TEACH, f->locale, "%s", itoa36(fix->u->no));
|
||||
}
|
||||
|
||||
static void test_study_no_teacher(CuTest *tc) {
|
||||
study_fixture fix;
|
||||
skill *sv;
|
||||
|
||||
setup_study(&fix, SK_CROSSBOW);
|
||||
study_cmd(fix.u, fix.u->thisorder);
|
||||
CuAssertPtrNotNull(tc, sv = unit_skill(fix.u, SK_CROSSBOW));
|
||||
CuAssertIntEquals(tc, 1, sv->level);
|
||||
CuAssertIntEquals(tc, 2, sv->weeks);
|
||||
CuAssertPtrEquals(tc, 0, test_get_last_message(fix.u->faction->msgs));
|
||||
test_cleanup();
|
||||
}
|
||||
|
||||
static void test_study_with_teacher(CuTest *tc) {
|
||||
study_fixture fix;
|
||||
skill *sv;
|
||||
|
||||
setup_study(&fix, SK_CROSSBOW);
|
||||
set_level(fix.teachers[0], SK_CROSSBOW, TEACHDIFFERENCE);
|
||||
teach_cmd(fix.teachers[0], fix.teachers[0]->thisorder);
|
||||
CuAssertPtrEquals(tc, 0, test_get_last_message(fix.u->faction->msgs));
|
||||
study_cmd(fix.u, fix.u->thisorder);
|
||||
CuAssertPtrNotNull(tc, sv = unit_skill(fix.u, SK_CROSSBOW));
|
||||
CuAssertIntEquals(tc, 1, sv->level);
|
||||
CuAssertIntEquals(tc, 1, sv->weeks);
|
||||
test_cleanup();
|
||||
}
|
||||
|
||||
static void test_study_with_bad_teacher(CuTest *tc) {
|
||||
study_fixture fix;
|
||||
skill *sv;
|
||||
message *msg;
|
||||
|
||||
setup_study(&fix, SK_CROSSBOW);
|
||||
teach_cmd(fix.teachers[0], fix.teachers[0]->thisorder);
|
||||
CuAssertPtrNotNull(tc, msg = test_get_last_message(fix.u->faction->msgs));
|
||||
CuAssertStrEquals(tc, "teach_asgood", test_get_messagetype(msg));
|
||||
study_cmd(fix.u, fix.u->thisorder);
|
||||
CuAssertPtrNotNull(tc, sv = unit_skill(fix.u, SK_CROSSBOW));
|
||||
CuAssertIntEquals(tc, 1, sv->level);
|
||||
CuAssertIntEquals(tc, 2, sv->weeks);
|
||||
test_cleanup();
|
||||
}
|
||||
|
||||
CuSuite *get_study_suite(void)
|
||||
{
|
||||
CuSuite *suite = CuSuiteNew();
|
||||
SUITE_ADD_TEST(suite, test_study_no_teacher);
|
||||
SUITE_ADD_TEST(suite, test_study_with_teacher);
|
||||
SUITE_ADD_TEST(suite, test_study_with_bad_teacher);
|
||||
return suite;
|
||||
}
|
|
@ -89,6 +89,7 @@ int RunAllTests(void)
|
|||
RUN_TESTS(suite, vortex);
|
||||
RUN_TESTS(suite, wormhole);
|
||||
RUN_TESTS(suite, spy);
|
||||
RUN_TESTS(suite, study);
|
||||
|
||||
printf("\ntest summary: %d tests, %d failed\n", suite->count, suite->failCount);
|
||||
log_flags = flags;
|
||||
|
|
15
src/tests.c
15
src/tests.c
|
@ -209,15 +209,20 @@ void test_create_world(void)
|
|||
}
|
||||
|
||||
message * test_get_last_message(message_list *msgs) {
|
||||
struct mlist *iter = msgs->begin;
|
||||
while (iter->next) {
|
||||
iter = iter->next;
|
||||
if (msgs) {
|
||||
struct mlist *iter = msgs->begin;
|
||||
while (iter->next) {
|
||||
iter = iter->next;
|
||||
}
|
||||
return iter->msg;
|
||||
}
|
||||
return iter->msg;
|
||||
return 0;
|
||||
}
|
||||
|
||||
const char * test_get_messagetype(const message *msg) {
|
||||
const char * name = msg->type->name;
|
||||
const char * name;
|
||||
assert(msg);
|
||||
name = msg->type->name;
|
||||
if (strcmp(name, "missing_message") == 0) {
|
||||
name = (const char *)msg->parameters[0].v;
|
||||
}
|
||||
|
|
|
@ -43,6 +43,7 @@ char *set_string(char **s, const char *neu)
|
|||
unsigned int hashstring(const char *s)
|
||||
{
|
||||
unsigned int key = 0;
|
||||
assert(s);
|
||||
while (*s) {
|
||||
key = key * 37 + *s++;
|
||||
}
|
||||
|
|
|
@ -31,7 +31,7 @@
|
|||
typedef struct opstack {
|
||||
variant *begin;
|
||||
variant *top;
|
||||
int size;
|
||||
unsigned int size;
|
||||
} opstack;
|
||||
|
||||
variant opstack_pop(opstack ** stackp)
|
||||
|
@ -53,10 +53,16 @@ void opstack_push(opstack ** stackp, variant data)
|
|||
stack->top = stack->begin;
|
||||
*stackp = stack;
|
||||
}
|
||||
if (stack->top - stack->begin == stack->size) {
|
||||
if (stack->top == stack->begin + stack->size) {
|
||||
size_t pos = stack->top - stack->begin;
|
||||
void *tmp;
|
||||
stack->size += stack->size;
|
||||
stack->begin = realloc(stack->begin, sizeof(variant) * stack->size);
|
||||
tmp = realloc(stack->begin, sizeof(variant) * stack->size);
|
||||
if (!tmp) {
|
||||
log_error("realloc out of memory");
|
||||
abort();
|
||||
}
|
||||
stack->begin = (variant *)tmp;
|
||||
stack->top = stack->begin + pos;
|
||||
}
|
||||
*stack->top++ = data;
|
||||
|
@ -66,7 +72,7 @@ void opstack_push(opstack ** stackp, variant data)
|
|||
** static buffer malloc
|
||||
**/
|
||||
|
||||
#define BBUFSIZE 128*1024
|
||||
#define BBUFSIZE 0x20000
|
||||
static struct {
|
||||
char *begin;
|
||||
char *end;
|
||||
|
@ -79,7 +85,7 @@ char *balloc(size_t size)
|
|||
static int init = 0; /* STATIC_XCALL: used across calls */
|
||||
if (!init) {
|
||||
init = 1;
|
||||
buffer.current = buffer.begin = malloc(BBUFSIZE);
|
||||
buffer.current = buffer.begin = malloc(BBUFSIZE * sizeof(char));
|
||||
buffer.end = buffer.begin + BBUFSIZE;
|
||||
}
|
||||
if (buffer.current + size > buffer.end) {
|
||||
|
@ -269,7 +275,7 @@ static const char *parse_string(opstack ** stack, const char *in,
|
|||
}
|
||||
else {
|
||||
int ch = (unsigned char)(*ic);
|
||||
int bytes;
|
||||
size_t bytes;
|
||||
|
||||
switch (ch) {
|
||||
case '\\':
|
||||
|
@ -285,8 +291,8 @@ static const char *parse_string(opstack ** stack, const char *in,
|
|||
if (ic == NULL)
|
||||
return NULL;
|
||||
c = (char *)opop_v(stack);
|
||||
bytes = (int)(c ? strlcpy(oc, c, size) : 0);
|
||||
if (bytes < (int)size)
|
||||
bytes = (c ? strlcpy(oc, c, size) : 0);
|
||||
if (bytes < size)
|
||||
oc += bytes;
|
||||
else
|
||||
oc += size;
|
||||
|
@ -363,7 +369,7 @@ static const char *parse(opstack ** stack, const char *inn,
|
|||
const char *translate(const char *format, const void *userdata,
|
||||
const char *vars, variant args[])
|
||||
{
|
||||
int i = 0;
|
||||
unsigned int i = 0;
|
||||
const char *ic = vars;
|
||||
char symbol[32];
|
||||
char *oc = symbol;
|
||||
|
|
2
storage
2
storage
|
@ -1 +1 @@
|
|||
Subproject commit 2bcd3b1e64764321773672333bd133a61b35b840
|
||||
Subproject commit 86b96744157eb08c55998df4c12fa2e073005b49
|
Binary file not shown.
|
@ -0,0 +1,40 @@
|
|||
cleanup () {
|
||||
rm -rf reports score
|
||||
}
|
||||
|
||||
setup() {
|
||||
ln -sf ../scripts/config.lua
|
||||
}
|
||||
|
||||
quit() {
|
||||
test -n "$2" && echo $2
|
||||
exit $1
|
||||
}
|
||||
|
||||
ROOT=`pwd`
|
||||
while [ ! -d $ROOT/.git ]; do
|
||||
ROOT=`dirname $ROOT`
|
||||
done
|
||||
|
||||
set -e
|
||||
cd $ROOT/tests
|
||||
setup
|
||||
cleanup
|
||||
VALGRIND=`which valgrind`
|
||||
SERVER=../Debug/eressea/eressea
|
||||
if [ -n "$VALGRIND" ]; then
|
||||
SUPP=../share/ubuntu-12_04.supp
|
||||
SERVER="$VALGRIND --suppressions=$SUPP --error-exitcode=1 --leak-check=no $SERVER"
|
||||
fi
|
||||
echo "running $SERVER"
|
||||
$SERVER -t 184 ../scripts/reports.lua
|
||||
[ -d reports ] || quit 4 "no reports directory created"
|
||||
CRFILE=184-zvto.cr
|
||||
grep -q PARTEI reports/$CRFILE || quit 1 "CR did not contain any factions"
|
||||
grep -q REGION reports/$CRFILE || quit 2 "CR did not contain any regions"
|
||||
grep -q SCHIFF reports/$CRFILE || quit 3 "CR did not contain any ships"
|
||||
grep -q BURG reports/$CRFILE || quit 4 "CR did not contain any buildings"
|
||||
grep -q EINHEIT reports/$CRFILE || quit 5 "CR did not contain any units"
|
||||
grep -q GEGENSTAENDE reports/$CRFILE || quit 6 "CR did not contain any items"
|
||||
echo "integration tests: PASS"
|
||||
cleanup
|
Loading…
Reference in New Issue