diff --git a/process/backup-eressea b/process/backup-eressea index 4e5f69002..0f81cf53e 100755 --- a/process/backup-eressea +++ b/process/backup-eressea @@ -34,4 +34,4 @@ fi tar cjf backup/$TURN.tar.bz2 $files echo "uploading game-$GAME/$TURN.tar.bz2" curl -s -n -T backup/$TURN.tar.bz2 https://dav.box.com/dav/Eressea/game-$GAME/$TURN.tar.bz2 -curl -s -n -T eressea.db https://dav.box.com/dav/Eressea/eressea.db +#curl -s -n -T eressea.db https://dav.box.com/dav/Eressea/eressea.db diff --git a/res/translations/strings.de.po b/res/translations/strings.de.po index 47d70ecc0..89875baf5 100644 --- a/res/translations/strings.de.po +++ b/res/translations/strings.de.po @@ -1437,7 +1437,7 @@ msgstr "Goblins" msgctxt "spellinfo" msgid "song_of_slavery" -msgstr "Dieser mächtige Bann raubt dem Opfer seinen freien Willen und unterwirft sie den Befehlen des Barden. Für einige Zeit wird das Opfer sich völlig von seinen eigenen Leuten abwenden und der Partei des Barden zugehörig fühlen." +msgstr "Dieser mächtige Bann raubt dem Opfer seinen freien Willen und unterwirft es den Befehlen des Barden. Für einige Zeit wird das Opfer sich völlig von seinen eigenen Leuten abwenden und der Partei des Barden zugehörig fühlen." msgctxt "spell" msgid "healingzone" diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 4e8db8bf9..c42e3eb2e 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -117,7 +117,6 @@ set (ERESSEA_SRC morale.c move.c names.c - orderdb.c orderfile.c piracy.c prefix.c @@ -230,7 +229,6 @@ set(TESTS_SRC monsters.test.c move.test.c names.test.c - orderdb.test.c orderfile.test.c piracy.test.c prefix.test.c diff --git a/src/alchemy.test.c b/src/alchemy.test.c index 32e0c84a5..e7d9206c4 100644 --- a/src/alchemy.test.c +++ b/src/alchemy.test.c @@ -26,7 +26,6 @@ static void test_herbsearch(CuTest * tc) const item_type *itype; test_setup(); - test_inject_messagetypes(); r = test_create_region(0, 0, NULL); rc = rc_get_or_create("dragon"); rc->flags |= RCF_UNARMEDGUARD; diff --git a/src/automate.c b/src/automate.c index c2b07fbd0..200541241 100644 --- a/src/automate.c +++ b/src/automate.c @@ -34,13 +34,13 @@ int autostudy_init(scholar scholars[], int max_scholars, region *r) int nscholars = 0; for (u = r->units; u; u = u->next) { - keyword_t kwd = getkeyword(u->thisorder); + keyword_t kwd = init_order(u->thisorder, u->faction->locale); if (kwd == K_AUTOSTUDY) { if (long_order_allowed(u)) { - if (unit_can_study(u)) { - scholar * st = scholars + nscholars; - init_order(u->thisorder, u->faction->locale); - st->sk = getskill(u->faction->locale); + scholar * st = scholars + nscholars; + skill_t sk = getskill(u->faction->locale); + if (check_student(u, u->thisorder, sk)) { + st->sk = sk; st->level = effskill_study(u, st->sk); st->learn = 0; st->u = u; @@ -48,10 +48,6 @@ int autostudy_init(scholar scholars[], int max_scholars, region *r) log_fatal("you must increase MAXSCHOLARS"); } } - else { - ADDMSG(&u->faction->msgs, msg_feedback(u, u->thisorder, "error_race_nolearn", "race", - u_race(u))); - } } } } diff --git a/src/automate.test.c b/src/automate.test.c index a77376668..6c87b8656 100644 --- a/src/automate.test.c +++ b/src/automate.test.c @@ -9,17 +9,22 @@ #include "kernel/region.h" #include "kernel/unit.h" +#include "util/message.h" + #include "tests.h" #include static void test_autostudy_init(CuTest *tc) { scholar scholars[4]; - unit *u1, *u2, *u3; + unit *u1, *u2, *u3, *u4; faction *f; region *r; test_setup(); + mt_create_error(77); + mt_create_error(771); + r = test_create_plain(0, 0); f = test_create_faction(NULL); u1 = test_create_unit(f, r); @@ -30,8 +35,11 @@ static void test_autostudy_init(CuTest *tc) { set_level(u2, SK_ENTERTAINMENT, 2); u3 = test_create_unit(f, r); u3->thisorder = create_order(K_AUTOSTUDY, f->locale, skillnames[SK_PERCEPTION]); + u4 = test_create_unit(test_create_faction(NULL), r); + u4->thisorder = create_order(K_AUTOSTUDY, f->locale, "Dudelidu"); scholars[3].u = NULL; CuAssertIntEquals(tc, 3, autostudy_init(scholars, 4, r)); + CuAssertPtrNotNull(tc, test_find_messagetype(u4->faction->msgs, "error77")); CuAssertPtrEquals(tc, u2, scholars[0].u); CuAssertIntEquals(tc, 2, scholars[0].level); CuAssertIntEquals(tc, 0, scholars[0].learn); diff --git a/src/battle.c b/src/battle.c index 8b71f17e1..3a1628dfe 100644 --- a/src/battle.c +++ b/src/battle.c @@ -281,19 +281,15 @@ static void set_friendly(side * as, side * ds) as->relations[ds->index] |= E_FRIEND; } -static int allysfm(const side * s, const faction * f, int mode) +static bool alliedside(const side * s, const faction * f, int mode) { - if (s->faction == f) - return mode; - if (s->group) { - return alliedgroup(s->battle->plane, s->faction, f, s->group->allies, mode); + if (s->faction == f) { + return true; } - return alliedfaction(s->battle->plane, s->faction, f, mode); -} - -static int allysf(const side * s, const faction * f) -{ - return allysfm(s, f, HELP_FIGHT); + if (s->group) { + return alliedgroup(s->faction, f, s->group, mode) != 0; + } + return alliedfaction(s->faction, f, mode) != 0; } static int dead_fighters(const fighter * df) @@ -313,7 +309,7 @@ fighter *select_corpse(battle * b, fighter * af) for (si = 0; si != b->nsides; ++si) { side *s = b->sides + si; - if (af == NULL || (!enemy_i(af->side, si) && allysf(af->side, s->faction))) { + if (af == NULL || (!enemy_i(af->side, si) && alliedside(af->side, s->faction, HELP_FIGHT))) { maxcasualties += s->casualties; } } @@ -344,7 +340,7 @@ bool helping(const side * as, const side * ds) { if (as->faction == ds->faction) return true; - return (bool)(!enemy(as, ds) && allysf(as, ds->faction)); + return (bool)(!enemy(as, ds) && alliedside(as, ds->faction, HELP_FIGHT)); } int statusrow(int status) @@ -832,7 +828,7 @@ bool meffect_protection(battle * b, meffect * s, side * ds) return false; if (enemy(s->magician->side, ds)) return false; - if (allysf(s->magician->side, ds->faction)) + if (alliedside(s->magician->side, ds->faction, HELP_FIGHT)) return true; return false; } @@ -1654,7 +1650,7 @@ selist *select_fighters(battle * b, const side * vs, int mask, select_fun cb, vo continue; } else if (mask == FS_HELP) { - if (enemy(s, vs) || !allysf(s, vs->faction)) { + if (enemy(s, vs) || !alliedside(s, vs->faction, HELP_FIGHT)) { continue; } } @@ -3112,9 +3108,7 @@ fighter *make_fighter(battle * b, unit * u, side * s1, bool attack) if (fval(u, UFL_ANON_FACTION) != 0) flags |= SIDE_STEALTH; if (!(AllianceAuto() & HELP_FIGHT) && fval(u, UFL_GROUP)) { - const attrib *agroup = a_find(u->attribs, &at_group); - if (agroup != NULL) - g = (const group *)agroup->data.v; + g = get_group(u); } /* Illusionen und Zauber kaempfen nicht */ @@ -3636,7 +3630,7 @@ static void join_allies(battle * b) * vorgespiegelt wird, und er sich uns gegen�ber nicht zu * erkennen gibt, helfen wir ihm nicht */ if (s->stealthfaction) { - if (!allysfm(s, u->faction, HELP_FSTEALTH)) { + if (!alliedside(s, u->faction, HELP_FSTEALTH)) { continue; } } @@ -3690,17 +3684,13 @@ static void join_allies(battle * b) } for (sa = s + 1; sa != b->sides + b->nsides; ++sa) { - plane *pl = rplane(r); - if (enemy(s, sa)) - continue; - if (friendly(s, sa)) - continue; - if (!alliedgroup(pl, f, sa->faction, f->allies, HELP_FIGHT)) - continue; - if (!alliedgroup(pl, sa->faction, f, sa->faction->allies, HELP_FIGHT)) - continue; - - set_friendly(s, sa); + if (!enemy(s, sa) && !friendly(s, sa)) { + if (alliedfaction(f, sa->faction, HELP_FIGHT)) { + if (alliedfaction(sa->faction, f, HELP_FIGHT)) { + set_friendly(s, sa); + } + } + } } } } diff --git a/src/bind_eressea.c b/src/bind_eressea.c index 4d3918899..f76d0a903 100755 --- a/src/bind_eressea.c +++ b/src/bind_eressea.c @@ -36,12 +36,16 @@ int eressea_write_game(const char * filename) { int eressea_read_orders(const char * filename) { FILE * F = fopen(filename, "r"); + int result; + if (!F) { perror(filename); return -1; } log_info("reading orders from %s", filename); - return parseorders(F); + result = parseorders(F); + fclose(F); + return result; } int eressea_export_json(const char * filename, int flags) { diff --git a/src/bind_faction.c b/src/bind_faction.c index bb0920395..581b1b0bf 100644 --- a/src/bind_faction.c +++ b/src/bind_faction.c @@ -44,23 +44,6 @@ without prior permission by the authors of Eressea. #include #include -typedef struct helpmode { - const char *name; - int status; -} helpmode; - -static helpmode helpmodes[] = { - { "all", HELP_ALL }, - { "money", HELP_MONEY }, - { "fight", HELP_FIGHT }, - { "observe", HELP_OBSERVE }, - { "give", HELP_GIVE }, - { "guard", HELP_GUARD }, - { "stealth", HELP_FSTEALTH }, - { "travel", HELP_TRAVEL }, - { NULL, 0 } -}; - int tolua_factionlist_next(lua_State * L) { faction **faction_ptr = (faction **)lua_touserdata(L, lua_upvalueindex(1)); @@ -309,49 +292,6 @@ static int tolua_faction_count_msg_type(lua_State *L) { return 1; } -static int tolua_faction_get_policy(lua_State * L) -{ - faction *self = (faction *)tolua_tousertype(L, 1, 0); - faction *other = (faction *)tolua_tousertype(L, 2, 0); - const char *policy = tolua_tostring(L, 3, 0); - - int result = 0, mode; - for (mode = 0; helpmodes[mode].name != NULL; ++mode) { - if (strcmp(policy, helpmodes[mode].name) == 0) { - result = get_alliance(self, other) & mode; - break; - } - } - - lua_pushinteger(L, result); - return 1; -} - -static int tolua_faction_set_policy(lua_State * L) -{ - faction *self = (faction *)tolua_tousertype(L, 1, 0); - faction *other = (faction *)tolua_tousertype(L, 2, 0); - const char *policy = tolua_tostring(L, 3, 0); - int value = tolua_toboolean(L, 4, 0); - - int mode; - for (mode = 0; helpmodes[mode].name != NULL; ++mode) { - if (strcmp(policy, helpmodes[mode].name) == 0) { - if (value) { - set_alliance(self, other, get_alliance(self, - other) | helpmodes[mode].status); - } - else { - set_alliance(self, other, get_alliance(self, - other) & ~helpmodes[mode].status); - } - break; - } - } - - return 0; -} - static int tolua_faction_normalize(lua_State * L) { faction *f = (faction *)tolua_tousertype(L, 1, 0); @@ -432,7 +372,7 @@ static int tolua_faction_create(lua_State * L) static int tolua_faction_get_password(lua_State * L) { faction *self = (faction *)tolua_tousertype(L, 1, 0); - tolua_pushstring(L, self->_password); + tolua_pushstring(L, faction_getpassword(self)); return 1; } @@ -632,8 +572,6 @@ void tolua_faction_open(lua_State * L) tolua_variable(L, TOLUA_CAST "lastturn", tolua_faction_get_lastturn, tolua_faction_set_lastturn); - tolua_function(L, TOLUA_CAST "set_policy", tolua_faction_set_policy); - tolua_function(L, TOLUA_CAST "get_policy", tolua_faction_get_policy); tolua_function(L, TOLUA_CAST "get_origin", tolua_faction_get_origin); tolua_function(L, TOLUA_CAST "set_origin", tolua_faction_set_origin); tolua_function(L, TOLUA_CAST "normalize", tolua_faction_normalize); diff --git a/src/creport.c b/src/creport.c index 07d957258..881edc870 100644 --- a/src/creport.c +++ b/src/creport.c @@ -799,13 +799,11 @@ void cr_output_unit(stream *out, const faction * f, } if (u->faction == f) { - const attrib *a = NULL; unit *mage; + group * g; - if (fval(u, UFL_GROUP)) - a = a_find(u->attribs, &at_group); - if (a != NULL) { - const group *g = (const group *)a->data.v; + g = get_group(u); + if (g) { stream_printf(out, "%d;gruppe\n", g->gid); } mage = get_familiar_mage(u); @@ -1018,16 +1016,12 @@ static void cr_output_unit_compat(FILE * F, const faction * f, cr_output_unit(&strm, f, u, mode); } -static void print_ally(const faction *f, faction *af, int status, - struct ally *sf, FILE *F) { - if (af) { - int mode = alliedgroup(NULL, f, af, sf, HELP_ALL); - if (mode != 0 && status > 0) { - fprintf(F, "ALLIANZ %d\n", af->no); - fprintf(F, "\"%s\";Parteiname\n", af->name); - fprintf(F, "%d;Status\n", status & HELP_ALL); - } - } +static void print_ally(const faction *f, faction *af, int status, FILE *F) { + if (af && status > 0) { + fprintf(F, "ALLIANZ %d\n", af->no); + fprintf(F, "\"%s\";Parteiname\n", af->name); + fprintf(F, "%d;Status\n", status & HELP_ALL); + } } struct print_ally_s { @@ -1035,18 +1029,25 @@ struct print_ally_s { FILE *F; }; -static void print_ally_cb(struct ally *sf, faction *af, int status, void *udata) { +static int print_ally_cb(struct ally *al, faction *af, int status, void *udata) { struct print_ally_s *data = (struct print_ally_s *)udata; - print_ally(data->f, af, status, sf, data->F); + + UNUSED_ARG(al); + if (af && faction_alive(af)) { + int mode = alliance_status(data->f, af, status); + print_ally(data->f, af, mode, data->F); + } + return 0; } /* prints allies */ -static void show_allies_cr(FILE * F, const faction * f, struct ally * sf) +static void show_allies_cr(FILE * F, const faction * f, const group *g) { struct print_ally_s data; data.F = F; data.f = f; - allies_walk(sf, print_ally_cb, &data); + struct ally *sf = g ? g->allies : f->allies; + ally_walk(sf, print_ally_cb, &data); } /* prints allies */ @@ -1072,12 +1073,15 @@ static void cr_find_address(FILE * F, const faction * uf, selist * addresses) while (flist) { const faction *f = (const faction *)selist_get(flist, i); if (uf != f) { + const char *str; fprintf(F, "PARTEI %d\n", f->no); fprintf(F, "\"%s\";Parteiname\n", f->name); if (strcmp(faction_getemail(f), "") != 0) fprintf(F, "\"%s\";email\n", faction_getemail(f)); - if (f->banner) - fprintf(F, "\"%s\";banner\n", f->banner); + str = faction_getbanner(f); + if (str) { + fprintf(F, "\"%s\";banner\n", str); + } fprintf(F, "\"%s\";locale\n", locale_name(f->locale)); if (f->alliance && f->alliance == uf->alliance) { fprintf(F, "%d;alliance\n", f->alliance->id); @@ -1549,7 +1553,7 @@ report_computer(const char *filename, report_context * ctx, const char *bom) static int era = -1; int i; faction *f = ctx->f; - const char *prefix; + const char *prefix, *str; region *r; const char *mailto = config_get("game.email"); const attrib *a; @@ -1643,8 +1647,10 @@ report_computer(const char *filename, report_context * ctx, const char *bom) fprintf(F, "\"%s\";Parteiname\n", f->name); fprintf(F, "\"%s\";email\n", faction_getemail(f)); - if (f->banner) - fprintf(F, "\"%s\";banner\n", f->banner); + str = faction_getbanner(f); + if (str) { + fprintf(F, "\"%s\";banner\n", str); + } print_items(F, f->items, f->locale); fputs("OPTIONEN\n", F); for (i = 0; i != MAXOPTIONS; ++i) { @@ -1656,7 +1662,7 @@ report_computer(const char *filename, report_context * ctx, const char *bom) f->options &= (~flag); } } - show_allies_cr(F, f, f->allies); + show_allies_cr(F, f, NULL); { group *g; for (g = f->groups; g; g = g->next) { @@ -1669,7 +1675,7 @@ report_computer(const char *filename, report_context * ctx, const char *bom) fprintf(F, "\"%s\";typprefix\n", translate(prefix, LOC(f->locale, prefix))); } - show_allies_cr(F, f, g->allies); + show_allies_cr(F, f, g); } } diff --git a/src/creport.test.c b/src/creport.test.c index 6bd5bfba8..b536a7114 100644 --- a/src/creport.test.c +++ b/src/creport.test.c @@ -227,7 +227,6 @@ static void test_cr_factionstealth(CuTest *tc) { faction *f1, *f2; region *r; unit *u; - ally *al; test_setup(); f1 = test_create_faction(NULL); @@ -298,8 +297,7 @@ static void test_cr_factionstealth(CuTest *tc) { mstream_done(&strm); /* we see the same thing as them when we are an ally */ - al = ally_add(&f1->allies, f2); - al->status = HELP_FSTEALTH; + ally_set(&f1->allies, f2, HELP_FSTEALTH); mstream_init(&strm); cr_output_unit(&strm, f2, u, seen_unit); CuAssertIntEquals(tc, f1->no, cr_get_int(&strm, ";Partei", -1)); diff --git a/src/economy.test.c b/src/economy.test.c index 5425ca56f..236c181c5 100644 --- a/src/economy.test.c +++ b/src/economy.test.c @@ -145,6 +145,7 @@ static struct unit *create_recruiter(void) { static void setup_production(void) { init_resources(); + mt_create_feedback("error_cannotmake"); mt_create_va(mt_new("produce", NULL), "unit:unit", "region:region", "amount:int", "wanted:int", "resource:resource", MT_NEW_END); mt_create_va(mt_new("income", NULL), "unit:unit", "region:region", "amount:int", "wanted:int", "mode:int", MT_NEW_END); mt_create_va(mt_new("buy", NULL), "unit:unit", "money:int", MT_NEW_END); @@ -738,6 +739,7 @@ static void test_loot(CuTest *tc) { test_setup(); setup_production(); + mt_create_error(48); /* unit is unarmed */ it_silver = test_create_silver(); config_set("rules.enable_loot", "1"); u = test_create_unit(f = test_create_faction(NULL), test_create_region(0, 0, NULL)); @@ -747,7 +749,7 @@ static void test_loot(CuTest *tc) { test_clear_messages(f); arm_unit(u); produce(u->region); - CuAssertPtrNotNull(tc, test_find_messagetype(f->msgs, "income")); /* unit is unarmed */ + CuAssertPtrNotNull(tc, test_find_messagetype(f->msgs, "income")); CuAssertIntEquals(tc, 2 * TAXFRACTION, i_get(u->items, it_silver)); CuAssertIntEquals(tc, UFL_LONGACTION | UFL_NOTMOVING, fval(u, UFL_LONGACTION | UFL_NOTMOVING)); test_teardown(); diff --git a/src/eressea.c b/src/eressea.c index e1767811c..8e7da7f7a 100644 --- a/src/eressea.c +++ b/src/eressea.c @@ -3,6 +3,7 @@ #include "kernel/building.h" #include "kernel/calendar.h" +#include "kernel/database.h" #include "kernel/config.h" #include "kernel/curse.h" #include "kernel/equipment.h" @@ -27,7 +28,6 @@ #include "creport.h" #include "report.h" #include "names.h" -#include "orderdb.h" #include "reports.h" #include "spells.h" #include "vortex.h" @@ -54,12 +54,12 @@ void game_done(void) free_locales(); #endif kernel_done(); - orderdb_close(); + swapdb_close(); } void game_init(void) { - orderdb_open(); + swapdb_open(); errno = 0; kernel_init(); register_triggers(); diff --git a/src/gamedb.c b/src/gamedb.c index 2ca2dba73..5f53d9120 100644 --- a/src/gamedb.c +++ b/src/gamedb.c @@ -20,7 +20,9 @@ int gamedb_update(void) err = db_driver_open(DB_GAME, dbname); if (err == 0) { for (f = factions; f; f = f->next) { - int uid = db_driver_faction_save(f->uid, f->no, turn, f->email, f->_password); + int uid = db_driver_faction_save(f->uid, f->no, turn, + faction_getemail(f), + faction_getpassword(f)); if (uid > 0) { f->uid = uid; } diff --git a/src/give.test.c b/src/give.test.c index 806901c46..f3164470c 100644 --- a/src/give.test.c +++ b/src/give.test.c @@ -44,8 +44,7 @@ static void setup_give(struct give *env) { env->itype = it_get_or_create(rt_get_or_create("money")); env->itype->flags |= ITF_HERB; if (env->f2) { - ally * al = ally_add(&env->f2->allies, env->f1); - al->status = HELP_GIVE; + ally_set(&env->f2->allies, env->f1, HELP_GIVE); env->dst = test_create_unit(env->f2, env->r); } else { @@ -66,11 +65,14 @@ static void setup_give(struct give *env) { mt_create_va(mt_new("give", NULL), "unit:unit", "target:unit", "resource:resource", "amount:int", MT_NEW_END); mt_create_va(mt_new("give_peasants", NULL), "unit:unit", "resource:resource", "amount:int", MT_NEW_END); /* error messages: */ + mt_create_error(129); + mt_create_error(96); + mt_create_error(10); + mt_create_feedback("feedback_give_forbidden"); + mt_create_feedback("peasants_give_invalid"); mt_create_va(mt_new("too_many_units_in_faction", NULL), "unit:unit", "region:region", "command:order", "allowed:int", MT_NEW_END); mt_create_va(mt_new("too_many_units_in_alliance", NULL), "unit:unit", "region:region", "command:order", "allowed:int", MT_NEW_END); mt_create_va(mt_new("feedback_no_contact", NULL), "unit:unit", "region:region", "command:order", "target:unit", MT_NEW_END); - mt_create_va(mt_new("feedback_give_forbidden", NULL), "unit:unit", "region:region", "command:order", MT_NEW_END); - mt_create_va(mt_new("peasants_give_invalid", NULL), "unit:unit", "region:region", "command:order", MT_NEW_END); mt_create_va(mt_new("giverestriction", NULL), "unit:unit", "region:region", "command:order", "turns:int", MT_NEW_END); mt_create_va(mt_new("error_unit_size", NULL), "unit:unit", "region:region", "command:order", "maxsize:int", MT_NEW_END); mt_create_va(mt_new("nogive_reserved", NULL), "unit:unit", "region:region", "command:order", "resource:resource", "reservation:int", MT_NEW_END); @@ -160,11 +162,12 @@ static void test_give_men_magicians(CuTest * tc) { message * msg; test_setup_ex(tc); + mt_create_error(158); env.f2 = env.f1 = test_create_faction(NULL); setup_give(&env); set_level(env.src, SK_MAGIC, 1); CuAssertPtrNotNull(tc, msg = give_men(1, env.src, env.dst, NULL)); - CuAssertStrEquals(tc, "error158", (const char *)msg->parameters[3].v); + CuAssertStrEquals(tc, "error158", test_get_messagetype(msg)); CuAssertIntEquals(tc, 1, env.dst->number); CuAssertIntEquals(tc, 1, env.src->number); msg_release(msg); diff --git a/src/items/xerewards.test.c b/src/items/xerewards.test.c index 8e30d88eb..dc9aa2621 100644 --- a/src/items/xerewards.test.c +++ b/src/items/xerewards.test.c @@ -18,7 +18,6 @@ static void test_manacrystal(CuTest *tc) { unit *u; test_setup(); - test_inject_messagetypes(); u = test_create_unit(test_create_faction(NULL), test_create_plain(0, 0)); itype = test_create_itemtype("manacrystal"); @@ -49,7 +48,6 @@ static void test_skillpotion(CuTest *tc) { int initialWeeks_Magic = 0; test_setup(); - test_inject_messagetypes(); u = test_create_unit(test_create_faction(NULL), test_create_plain(0, 0)); itype = test_create_itemtype("skillpotion"); change_resource(u, itype->rtype, 2); diff --git a/src/kernel/CMakeLists.txt b/src/kernel/CMakeLists.txt index 06f58fc1b..dcd19c35a 100644 --- a/src/kernel/CMakeLists.txt +++ b/src/kernel/CMakeLists.txt @@ -58,6 +58,7 @@ command.c config.c connection.c curse.c +database.c equipment.c event.c faction.c diff --git a/src/kernel/ally.c b/src/kernel/ally.c index 3abfc4c09..1f57609c7 100644 --- a/src/kernel/ally.c +++ b/src/kernel/ally.c @@ -8,7 +8,6 @@ #include "group.h" #include "faction.h" #include "objtypes.h" -#include "plane.h" #include #include @@ -20,23 +19,176 @@ #include #include +#define BLOCKSIZE 15 +typedef struct allies { + struct allies *next; + int num; + const struct faction *factions[BLOCKSIZE]; + int status[BLOCKSIZE]; +} allies; + +static void block_insert(allies *al, const struct faction *f, int status) { + int i = al->num++; + al->status[i] = status; + al->factions[i] = f; + /* TODO: heapify */ +} + +static int block_search(allies *al, const struct faction *f) { + int i; + /* TODO: binary search */ + for (i = 0; i != al->num; ++i) { + if (al->factions[i] == f) { + return i; + } + } + return BLOCKSIZE; +} + +int allies_get(allies *al, const struct faction *f) +{ + for (; al; al = al->next) { + int i = block_search(al, f); + if (i != BLOCKSIZE) { + return al->status[i]; + } + } + return 0; +} + +void allies_set(allies **p_al, const struct faction *f, int status) +{ + while (*p_al) { + allies *al = *p_al; + int i = block_search(al, f); + if (i != BLOCKSIZE) { + if (status == 0) { + if (--al->num != i) { + al->factions[i] = al->factions[al->num]; + al->status[i] = al->status[al->num]; + /* TODO: repair heap up or down */ + } + else if (al->num == 0) { + *p_al = al->next; + free(al); + return; + } + } + else { + al->status[i] = status; + } + return; + } + if (al->num < BLOCKSIZE) { + block_insert(al, f, status); + return; + } + p_al = &al->next; + } + *p_al = calloc(1, sizeof(allies)); + block_insert(*p_al, f, status); +} + +void allies_write(gamedata * data, const allies *alist) +{ + const allies *al; + for (al = alist; al; al = al->next) { + int i; + for (i = 0; i != al->num; ++i) { + const faction * f = al->factions[i]; + if (f && f->_alive) { + write_faction_reference(f, data->store); + WRITE_INT(data->store, al->status[i]); + } + } + } + write_faction_reference(NULL, data->store); +} + +void allies_read(gamedata * data, allies **p_al) +{ + for (;;) { + faction *f; + int aid, status; + READ_INT(data->store, &aid); + /* TODO: deal with unresolved factions, somehow */ + if (aid <= 0) { + break; + } + f = findfaction(aid); + if (!f) f = faction_create(aid); + READ_INT(data->store, &status); + allies_set(p_al, f, status); + } +} + typedef struct ally { struct ally *next; struct faction *faction; int status; } ally; -void allies_walk(struct ally *allies, cb_allies_walk callback, void *udata); +static ally * ally_add(ally **al_p, struct faction *f) { + ally * al; + while (*al_p) { + al = *al_p; + if (f && al->faction == f) return al; + al_p = &al->next; + } + al = (ally *)calloc(1, sizeof(ally)); + al->faction = f; + *al_p = al; + return al; +} + +void allies_free(ally *al) { - ally *al; - for (al = allies; al; al = al->next) { - callback(allies, al->faction, al->status, udata); + while (al) { + ally * an = al->next; + free(al); + al = an; } } -void read_allies(gamedata * data, faction *f) +ally *ally_clone(const ally *al) { + ally *al_clone = NULL, **al_end = &al_clone; + + for (; al; al = al->next) { + if (al->faction) { + ally * al_new = ally_add(al_end, al->faction); + al_new->status = al->status; + al_end = &al_new->next; + } + } + return al_clone; +} + +int ally_walk(ally *allies, cb_ally_walk callback, void *udata) +{ + ally *al; + for (al = allies; al; al = al->next) { + int err = callback(allies, al->faction, al->status, udata); + if (err != 0) { + return err; + } + } + return 0; +} + +void write_allies(gamedata * data, const ally *alist) +{ + const ally *a; + for (a = alist; a; a = a->next) { + if (a->faction && a->faction->_alive) { + write_faction_reference(a->faction, data->store); + WRITE_INT(data->store, a->status); + } + } + write_faction_reference(NULL, data->store); +} + +void read_allies(gamedata * data, ally **sfp) { - ally **sfp = &f->allies; for (;;) { int aid; READ_INT(data->store, &aid); @@ -44,7 +196,7 @@ void read_allies(gamedata * data, faction *f) ally * al = ally_add(sfp, NULL); int state; if ((al->faction = findfaction(aid)) == NULL) { - ur_add(RESOLVE_FACTION | aid, (void **)&al->faction, NULL); + al->faction = faction_create(aid); } READ_INT(data->store, &state); al->status = state & HELP_ALL; @@ -63,32 +215,6 @@ ally * ally_find(ally *al, const struct faction *f) { return 0; } -ally * ally_add(ally **al_p, struct faction *f) { - ally * al; - while (*al_p) { - al = *al_p; - if (f && al->faction == f) return al; - al_p = &al->next; - } - al = (ally *)calloc(1, sizeof(ally)); - al->faction = f; - *al_p = al; - return al; -} - -void ally_remove(ally **al_p, struct faction *f) { - ally * al; - while (*al_p) { - al = *al_p; - if (al->faction == f) { - *al_p = al->next; - free(al); - break; - } - al_p = &al->next; - } -} - static int ally_flag(const char *s, int help_mask) { if ((help_mask & HELP_MONEY) && strcmp(s, "money") == 0) @@ -128,26 +254,14 @@ int AllianceAuto(void) } static int -autoalliance(const plane * pl, const faction * sf, const faction * f2) +autoalliance(const faction * sf, const faction * f2) { - if (pl && (pl->flags & PFL_FRIENDLY)) - return HELP_ALL; - - if (f_get_alliance(sf) != NULL && AllianceAuto()) { - if (sf->alliance == f2->alliance) - return AllianceAuto(); + if (sf->alliance == f2->alliance) { + return AllianceAuto(); } - return 0; } -static int ally_mode(const ally * sf, int mode) -{ - if (sf == NULL) - return 0; - return sf->status & mode; -} - static void init_npcfaction(variant *var) { var->i = 1; @@ -172,12 +286,13 @@ attrib_type at_npcfaction = { */ int HelpMask(void) { - static int config, rule = 0; + static int config, rule; if (config_changed(&config)) { const char *str = config_get("rules.help.mask"); if (str != NULL) { char *sstr = str_strdup(str); char *tok = strtok(sstr, " "); + rule = 0; while (tok) { rule |= ally_flag(tok, -1); tok = strtok(NULL, " "); @@ -193,72 +308,79 @@ int HelpMask(void) static int AllianceRestricted(void) { - const char *str = config_get("alliance.restricted"); - int rule = 0; - if (str != NULL) { - char *sstr = str_strdup(str); - char *tok = strtok(sstr, " "); - while (tok) { - rule |= ally_flag(tok, -1); - tok = strtok(NULL, " "); + static int config, rule; + if (config_changed(&config)) { + const char *str = config_get("alliance.restricted"); + rule = 0; + if (str != NULL) { + char *sstr = str_strdup(str); + char *tok = strtok(sstr, " "); + while (tok) { + rule |= ally_flag(tok, -1); + tok = strtok(NULL, " "); + } + free(sstr); } - free(sstr); + rule &= HelpMask(); } - rule &= HelpMask(); return rule; } +int alliance_status(const faction *f, const faction *f2, int status) { + status |= autoalliance(f, f2); + if (status > 0) { + int mask = AllianceRestricted(); + if (mask) { + if (a_find(f->attribs, &at_npcfaction)) { + return status; + } + if (a_find(f2->attribs, &at_npcfaction)) { + return status; + } + if (f->alliance != f2->alliance) { + status &= ~mask; + } + } + } + return status; +} + int -alliedgroup(const struct plane *pl, const struct faction *f, - const struct faction *f2, - const struct ally *sf, int mode) +alliedgroup(const struct faction *f, + const struct faction *f2, const struct group *g, int mask) { + ally *all = g ? g->allies : f->allies; + int status; + if (!(faction_alive(f) && faction_alive(f2))) { return 0; } - while (sf && sf->faction != f2) { - sf = sf->next; - } - if (sf == NULL) { - mode = mode & autoalliance(pl, f, f2); - } - mode = ally_mode(sf, mode) | (mode & autoalliance(pl, f, f2)); - if (AllianceRestricted()) { - if (a_find(f->attribs, &at_npcfaction)) { - return mode; - } - if (a_find(f2->attribs, &at_npcfaction)) { - return mode; - } - if (f->alliance != f2->alliance) { - mode &= ~AllianceRestricted(); - } - } - return mode; + status = ally_get(all, f2) & mask; + return alliance_status(f, f2, status); } int -alliedfaction(const struct plane *pl, const struct faction *f, - const struct faction *f2, int mode) +alliedfaction(const struct faction *f, const struct faction *f2, int mask) { - return alliedgroup(pl, f, f2, f->allies, mode); + return alliedgroup(f, f2, NULL, mask); } /* Die Gruppe von Einheit u hat helfe zu f2 gesetzt. */ -int alliedunit(const unit * u, const faction * f2, int mode) +int alliedunit(const unit * u, const faction * f2, int mask) { - int automode; - 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 == f2) { + return mask; + } + if (!faction_alive(f2)) { + return 0; + } if (u->faction != NULL && f2 != NULL) { - ally *sf; - plane *pl; + group *g; - if (mode & HELP_FIGHT) { + if (mask & HELP_FIGHT) { if ((u->flags & UFL_DEFENDER) || (u->faction->flags & FFL_DEFENDER)) { faction *owner = region_get_owner(u->region); /* helps the owner of the region */ @@ -268,20 +390,41 @@ int alliedunit(const unit * u, const faction * f2, int mode) } } - pl = rplane(u->region); - automode = mode & autoalliance(pl, u->faction, f2); - - if (pl != NULL && (pl->flags & PFL_NOALLIANCES)) - mode = (mode & automode) | (mode & HELP_GIVE); - - sf = u->faction->allies; - if (fval(u, UFL_GROUP)) { - const attrib *a = a_find(u->attribs, &at_group); - if (a != NULL) - sf = ((group *)a->data.v)->allies; + g = get_group(u); + if (g) { + return alliedgroup(u->faction, f2, g, mask); } - return alliedgroup(pl, u->faction, f2, sf, mode); + return alliedfaction(u->faction, f2, mask); } return 0; } +void ally_set(ally **allies, struct faction *f, int status) { + ally *al; + while (*allies) { + al = *allies; + if (al->faction == f) { + if (status != 0) { + al->status = status; + } + else { + *allies = al->next; + free(al); + } + return; + } + allies = &al->next; + } + al = ally_add(allies, f); + al->status = status; +} + +int ally_get(ally *allies, const struct faction *f) { + ally *al; + for (al = allies; al; al = al->next) { + if (al->faction == f) { + return al->status; + } + } + return 0; +} diff --git a/src/kernel/ally.h b/src/kernel/ally.h index 16bd57aa7..25b488dac 100644 --- a/src/kernel/ally.h +++ b/src/kernel/ally.h @@ -24,31 +24,41 @@ extern "C" { #endif struct attrib_type; - struct plane; struct faction; + struct group; struct gamedata; struct unit; struct ally; + struct allies; extern struct attrib_type at_npcfaction; - void read_allies(struct gamedata * data, struct faction *f); - typedef void (*cb_allies_walk)(struct ally *, struct faction *, int, void *); - void allies_walk(struct ally *allies, cb_allies_walk callback, void *udata); + int allies_get(struct allies *al, const struct faction *f); + void allies_set(struct allies **p_al, const struct faction *f, int status); + void allies_write(struct gamedata * data, const struct allies *alist); + void allies_read(struct gamedata * data, struct allies **sfp); + + void read_allies(struct gamedata * data, struct ally **alist); + void write_allies(struct gamedata * data, const struct ally *alist); + typedef int (*cb_ally_walk)(struct ally *, struct faction *, int, void *); + int ally_walk(struct ally *allies, cb_ally_walk callback, void *udata); + struct ally *ally_clone(const struct ally *al); + void allies_free(struct ally *al); + struct ally* ally_find(struct ally*al, const struct faction *f); void ally_set(struct ally**al_p, struct faction *f, int status); - int ally_get(struct ally *al, struct faction *f); - struct ally* ally_add(struct ally**al_p, struct faction *f); - void ally_remove(struct ally**al_p, struct faction *f); + int ally_get(struct ally *al, const struct faction *f); int AllianceAuto(void); /* flags that allied factions get automatically */ int HelpMask(void); /* flags restricted to allied factions */ int alliedunit(const struct unit *u, const struct faction *f2, - int mode); - int alliedfaction(const struct plane *pl, const struct faction *f, - const struct faction *f2, int mode); - int alliedgroup(const struct plane *pl, const struct faction *f, - const struct faction *f2, const struct ally*sf, int mode); + int mask); + + int alliedfaction(const struct faction *f, const struct faction *f2, + int mask); + int alliedgroup(const struct faction *f, const struct faction *f2, + const struct group *g, int mask); + int alliance_status(const struct faction *f, const struct faction *f2, int status); #ifdef __cplusplus } diff --git a/src/kernel/ally.test.c b/src/kernel/ally.test.c index 99d220151..0b17870bb 100644 --- a/src/kernel/ally.test.c +++ b/src/kernel/ally.test.c @@ -7,37 +7,64 @@ static void test_ally(CuTest * tc) { - ally * al = 0; - struct faction * f1 = test_create_faction(NULL); + struct ally * al = NULL; + struct faction * f; - ally_add(&al, f1); + test_setup(); + f = test_create_faction(NULL); + ally_set(&al, f, HELP_GUARD); CuAssertPtrNotNull(tc, al); - CuAssertPtrEquals(tc, f1, ally_find(al, f1)->faction); + CuAssertIntEquals(tc, HELP_GUARD, ally_get(al, f)); - ally_remove(&al, f1); + ally_set(&al, f, 0); CuAssertPtrEquals(tc, NULL, al); - CuAssertPtrEquals(tc, NULL, ally_find(al, f1)); + CuAssertIntEquals(tc, 0, ally_get(al, f)); + allies_free(al); + test_teardown(); } -static void test_ally_null(CuTest * tc) +static void test_ally_clone(CuTest * tc) { - ally *a1 = 0, *a2 = 0; + struct ally * al = NULL, *ac; + struct faction * f; - a1 = ally_add(&a1, 0); - a2 = ally_add(&a1, 0); - CuAssertPtrNotNull(tc, a1); - CuAssertPtrNotNull(tc, a2); - CuAssertPtrEquals(tc, a2, a1->next); - CuAssertPtrEquals(tc, NULL, a2->next); - free(a1); - free(a2); + test_setup(); + f = test_create_faction(NULL); + CuAssertPtrEquals(tc, NULL, ally_clone(NULL)); + + ally_set(&al, f, HELP_GUARD); + ac = ally_clone(al); + CuAssertPtrNotNull(tc, ac); + CuAssertTrue(tc, al != ac); + CuAssertIntEquals(tc, HELP_GUARD, ally_get(ac, f)); + CuAssertIntEquals(tc, HELP_GUARD, ally_get(al, f)); + allies_free(al); + allies_free(ac); + test_teardown(); +} + +static void test_allies(CuTest *tc) { + struct allies * al = NULL; + struct faction * f; + + test_setup(); + f = test_create_faction(NULL); + + CuAssertIntEquals(tc, 0, allies_get(al, f)); + allies_set(&al, f, 42); + CuAssertIntEquals(tc, 42, allies_get(al, f)); + allies_set(&al, f, 0); + CuAssertIntEquals(tc, 0, allies_get(al, f)); + CuAssertPtrEquals(tc, NULL, al); + test_teardown(); } CuSuite *get_ally_suite(void) { CuSuite *suite = CuSuiteNew(); SUITE_ADD_TEST(suite, test_ally); - SUITE_ADD_TEST(suite, test_ally_null); + SUITE_ADD_TEST(suite, test_ally_clone); + SUITE_ADD_TEST(suite, test_allies); return suite; } diff --git a/src/kernel/build.c b/src/kernel/build.c index 2b7251f1d..0c1bd71de 100644 --- a/src/kernel/build.c +++ b/src/kernel/build.c @@ -500,6 +500,28 @@ static int count_materials(unit *u, const construction *type, int n, int complet return n; } +int build_skill(unit *u, int basesk, int skill_mod) { + int effsk, skills; + int dm = get_effect(u, oldpotiontype[P_DOMORE]); + + effsk = basesk + skill_mod; + assert(effsk >= 0); + + skills = effsk * u->number; + + /* technically, nimblefinge and domore should be in a global set of + * "game"-attributes, (as at_skillmod) but for a while, we're leaving + * them in here. */ + + if (dm != 0) { + /* Auswirkung Schaffenstrunk */ + if (dm > u->number) dm = u->number; + change_effect(u, oldpotiontype[P_DOMORE], -dm); + skills += dm * effsk; + } + return skills; +} + /** Use up resources for building an object. * Build up to 'size' points of 'type', where 'completed' * of the first object have already been finished. return the @@ -521,28 +543,11 @@ int build(unit * u, const construction * ctype, int completed, int want, int ski return ECOMPLETE; } if (con->skill != NOSKILL) { - int effsk; - int dm = get_effect(u, oldpotiontype[P_DOMORE]); - basesk = effskill(u, con->skill, 0); if (basesk == 0) return ENEEDSKILL; - effsk = basesk + skill_mod; - assert(effsk >= 0); - - skills = effsk * u->number; - - /* technically, nimblefinge and domore should be in a global set of - * "game"-attributes, (as at_skillmod) but for a while, we're leaving - * them in here. */ - - if (dm != 0) { - /* Auswirkung Schaffenstrunk */ - if (dm > u->number) dm = u->number; - change_effect(u, oldpotiontype[P_DOMORE], -dm); - skills += dm * effsk; - } + skills = build_skill(u, basesk, skill_mod); } for (; want > 0 && skills > 0;) { int err, n; diff --git a/src/kernel/build.test.c b/src/kernel/build.test.c index ae3e47d0d..ea3e2aeb5 100644 --- a/src/kernel/build.test.c +++ b/src/kernel/build.test.c @@ -36,7 +36,6 @@ typedef struct build_fixture { static unit * setup_build(build_fixture *bf) { test_setup(); - test_inject_messagetypes(); init_resources(); test_create_itemtype("stone"); @@ -312,7 +311,6 @@ static void test_build_destroy_road_guard(CuTest *tc) order *ord; test_setup(); - test_inject_messagetypes(); test_create_region(1, 0, 0); r = test_create_region(0, 0, NULL); rsetroad(r, D_EAST, 100); @@ -345,7 +343,6 @@ static void test_build_destroy_road_limit(CuTest *tc) order *ord; test_setup(); - test_inject_messagetypes(); test_create_region(1, 0, 0); r = test_create_region(0, 0, NULL); rsetroad(r, D_EAST, 100); @@ -370,6 +367,7 @@ static void test_build_destroy_cmd(CuTest *tc) { faction *f; test_setup(); + mt_create_error(138); u = test_create_unit(f = test_create_faction(NULL), test_create_region(0, 0, NULL)); u->thisorder = create_order(K_DESTROY, f->locale, NULL); CuAssertIntEquals(tc, 138, destroy_cmd(u, u->thisorder)); diff --git a/src/kernel/curse.test.c b/src/kernel/curse.test.c index da0806914..886e25ee4 100644 --- a/src/kernel/curse.test.c +++ b/src/kernel/curse.test.c @@ -51,7 +51,6 @@ typedef struct { static void setup_curse(curse_fixture *fix, const char *name) { test_setup(); - test_inject_messagetypes(); fix->r = test_create_region(0, 0, NULL); fix->u = test_create_unit(test_create_faction(NULL), fix->r); fix->c = create_curse(fix->u, &fix->r->attribs, ct_find(name), 1.0, 1, 1.0, 0); diff --git a/src/kernel/database.c b/src/kernel/database.c new file mode 100644 index 000000000..796aa2380 --- /dev/null +++ b/src/kernel/database.c @@ -0,0 +1,29 @@ +#include "config.h" +#include "database.h" +#include "db/driver.h" + +void swapdb_open(void) +{ + const char *dbname; + dbname = config_get("game.dbswap"); + db_driver_open(DB_SWAP, dbname); +} + +void swapdb_close(void) +{ + db_driver_close(DB_SWAP); +} + +dbrow_id db_string_save(const char *s) { + (void)s; + return 0; +} + +dbrow_id dbstring_save(const char *s) { + return db_driver_string_save(s); +} + +const char *dbstring_load(dbrow_id id, size_t *size) { + return db_driver_string_load(id, size); +} + diff --git a/src/kernel/database.h b/src/kernel/database.h new file mode 100644 index 000000000..8147ccc61 --- /dev/null +++ b/src/kernel/database.h @@ -0,0 +1,11 @@ +#pragma once + +#include "db/driver.h" + +#include + +void swapdb_open(void); +void swapdb_close(void); + +dbrow_id dbstring_save(const char *s); +const char *dbstring_load(dbrow_id id, size_t *size); diff --git a/src/kernel/database.test.c b/src/kernel/database.test.c index 3ec44896e..c5aae1af6 100644 --- a/src/kernel/database.test.c +++ b/src/kernel/database.test.c @@ -3,8 +3,8 @@ #include #include +#include "database.h" #include "db/driver.h" -#include "orderdb.h" #include #include @@ -12,6 +12,17 @@ #include #include +static void test_orderdb(CuTest *tc) { + order_data *od = NULL; + const char * s = "GIB enno 1 Hodor"; + + odata_create(&od, strlen(s) + 1, s); + CuAssertPtrNotNull(tc, od); + CuAssertStrEquals(tc, s, od->_str); + CuAssertTrue(tc, od->_refcount >= 1); + odata_release(od); +} + static void test_save_load_order(CuTest *tc) { order_data *od; int id; @@ -39,11 +50,17 @@ static void test_update_faction(CuTest *tc) { int uid; test_setup(); + db_driver_open(DB_GAME, NULL); f = test_create_faction(NULL); - uid = db_driver_faction_save(f->uid, f->no, 0, f->email, f->_password); + uid = db_driver_faction_save(f->uid, f->no, 0, + faction_getemail(f), + faction_getpassword(f)); f->uid = uid; - uid = db_driver_faction_save(f->uid, f->no, 0, f->email, f->_password); + uid = db_driver_faction_save(f->uid, f->no, 0, + faction_getemail(f), + faction_getpassword(f)); CuAssertIntEquals(tc, f->uid, uid); + db_driver_close(DB_GAME); test_teardown(); } @@ -52,6 +69,7 @@ CuSuite *get_db_suite(void) CuSuite *suite = CuSuiteNew(); SUITE_ADD_TEST(suite, test_save_load_order); SUITE_ADD_TEST(suite, test_update_faction); + SUITE_ADD_TEST(suite, test_orderdb); return suite; } diff --git a/src/kernel/db/driver.h b/src/kernel/db/driver.h index 9632cb5db..341653991 100644 --- a/src/kernel/db/driver.h +++ b/src/kernel/db/driver.h @@ -4,6 +4,8 @@ struct order_data; +typedef unsigned int dbrow_id; + extern void odata_create(struct order_data **pdata, size_t len, const char *str); typedef enum database_t { @@ -13,6 +15,8 @@ typedef enum database_t { int db_driver_open(database_t db, const char *dbname); void db_driver_close(database_t db); -int db_driver_order_save(const char *str); -struct order_data *db_driver_order_load(int id); -int db_driver_faction_save(int id, int no, int turn, const char *email, const char *password); +dbrow_id db_driver_order_save(const char *str); +struct order_data *db_driver_order_load(dbrow_id id); +dbrow_id db_driver_faction_save(dbrow_id id, int no, int turn, const char *email, const char *password); +dbrow_id db_driver_string_save(const char *s); +const char *db_driver_string_load(dbrow_id id, size_t *size); diff --git a/src/kernel/db/sqlite.c b/src/kernel/db/sqlite.c index fd9d0bc67..29638d900 100644 --- a/src/kernel/db/sqlite.c +++ b/src/kernel/db/sqlite.c @@ -9,56 +9,60 @@ #include #include +#include #include #include #include #include static sqlite3 *g_game_db; -static sqlite3 *g_temp_db; +static sqlite3 *g_swap_db; +static sqlite3_stmt * g_stmt_insert_string; +static sqlite3_stmt * g_stmt_select_string; static sqlite3_stmt * g_stmt_insert_order; static sqlite3_stmt * g_stmt_select_order; static sqlite3_stmt * g_stmt_update_faction; static sqlite3_stmt * g_stmt_insert_faction; -static int g_order_batchsize; -static int g_order_tx_size; +static int g_insert_batchsize; +static int g_insert_tx_size; -struct order_data *db_driver_order_load(int id) +static void end_transaction(void) { + if (g_insert_tx_size > 0) { + int err; + g_insert_tx_size = 0; + err = sqlite3_exec(g_swap_db, "COMMIT", NULL, NULL, NULL); + assert(err == SQLITE_OK); + } +} + +struct order_data *db_driver_order_load(dbrow_id id) { struct order_data * od = NULL; int err; ERRNO_CHECK(); - if (g_order_tx_size > 0) { - g_order_tx_size = 0; - err = sqlite3_exec(g_temp_db, "COMMIT", NULL, NULL, NULL); - assert(err == SQLITE_OK); - } + end_transaction(); err = sqlite3_reset(g_stmt_select_order); assert(err == SQLITE_OK); err = sqlite3_bind_int(g_stmt_select_order, 1, id); assert(err == SQLITE_OK); - do { - err = sqlite3_step(g_stmt_select_order); - if (err == SQLITE_ROW) { - const unsigned char *text; - int bytes; - bytes = sqlite3_column_bytes(g_stmt_select_order, 0); - assert(bytes > 0); - text = sqlite3_column_text(g_stmt_select_order, 0); - odata_create(&od, 1+(size_t)bytes, (const char *)text); - ERRNO_CHECK(); - return od; - } - } while (err == SQLITE_ROW); - assert(err == SQLITE_DONE); + err = sqlite3_step(g_stmt_select_order); + if (err == SQLITE_ROW) { + const unsigned char *text; + int bytes; + text = sqlite3_column_text(g_stmt_select_order, 0); + bytes = sqlite3_column_bytes(g_stmt_select_order, 0); + assert(bytes > 0); + odata_create(&od, 1+(size_t)bytes, (const char *)text); + ERRNO_CHECK(); + return od; + } ERRNO_CHECK(); return NULL; } -int db_driver_order_save(const char *str) -{ +dbrow_id db_driver_order_save(const char *str) { int err; sqlite3_int64 id; @@ -66,9 +70,9 @@ int db_driver_order_save(const char *str) ERRNO_CHECK(); - if (g_order_batchsize > 0) { - if (g_order_tx_size == 0) { - err = sqlite3_exec(g_temp_db, "BEGIN TRANSACTION", NULL, NULL, NULL); + if (g_insert_batchsize > 0) { + if (g_insert_tx_size == 0) { + err = sqlite3_exec(g_swap_db, "BEGIN TRANSACTION", NULL, NULL, NULL); assert(err == SQLITE_OK); } } @@ -79,29 +83,25 @@ int db_driver_order_save(const char *str) assert(err == SQLITE_OK); err = sqlite3_step(g_stmt_insert_order); assert(err == SQLITE_DONE); - id = sqlite3_last_insert_rowid(g_temp_db); - assert(id <= INT_MAX); + id = sqlite3_last_insert_rowid(g_swap_db); + assert(id > 0 && id <= UINT_MAX); - if (g_order_batchsize > 0) { - if (++g_order_tx_size >= g_order_batchsize) { - err = sqlite3_exec(g_temp_db, "COMMIT", NULL, NULL, NULL); - assert(err == SQLITE_OK); - g_order_tx_size = 0; + if (g_insert_batchsize > 0) { + if (++g_insert_tx_size >= g_insert_batchsize) { + end_transaction(); } } ERRNO_CHECK(); - return (int)id; + return (dbrow_id)id; } -int db_driver_faction_save(int id, int no, int turn, const char *email, const char *password) +dbrow_id db_driver_faction_save(dbrow_id id, int no, int turn, const char *email, const char *password) { sqlite3_int64 row_id; int err; - if (!g_game_db) { - return -1; - } + assert(g_game_db); if (id != 0) { int rows; @@ -139,8 +139,8 @@ int db_driver_faction_save(int id, int no, int turn, const char *email, const ch ERRNO_CHECK(); row_id = sqlite3_last_insert_rowid(g_game_db); - assert(row_id <= INT_MAX); - return (int)row_id; + assert(row_id>0 && row_id <= UINT_MAX); + return (dbrow_id)row_id; } static int db_open_game(const char *dbname) { @@ -162,19 +162,25 @@ static int db_open_game(const char *dbname) { static int db_open_swap(const char *dbname) { int err; - g_order_batchsize = config_get_int("game.dbbatch", 100); + g_insert_batchsize = config_get_int("game.dbbatch", 100); - err = sqlite3_open(dbname, &g_temp_db); + err = sqlite3_open(dbname, &g_swap_db); assert(err == SQLITE_OK); - err = sqlite3_exec(g_temp_db, "PRAGMA journal_mode=OFF", NULL, NULL, NULL); + err = sqlite3_exec(g_swap_db, "PRAGMA journal_mode=OFF", NULL, NULL, NULL); assert(err == SQLITE_OK); - err = sqlite3_exec(g_temp_db, "PRAGMA synchronous=OFF", NULL, NULL, NULL); + err = sqlite3_exec(g_swap_db, "PRAGMA synchronous=OFF", NULL, NULL, NULL); assert(err == SQLITE_OK); - err = sqlite3_exec(g_temp_db, "CREATE TABLE IF NOT EXISTS orders (id INTEGER PRIMARY KEY, data TEXT NOT NULL)", NULL, NULL, NULL); + err = sqlite3_exec(g_swap_db, "CREATE TABLE IF NOT EXISTS orders (id INTEGER PRIMARY KEY, data TEXT NOT NULL)", NULL, NULL, NULL); assert(err == SQLITE_OK); - err = sqlite3_prepare_v2(g_temp_db, "INSERT INTO orders (data) VALUES (?)", -1, &g_stmt_insert_order, NULL); + err = sqlite3_exec(g_swap_db, "CREATE TABLE IF NOT EXISTS strings (id INTEGER PRIMARY KEY, data TEXT NOT NULL)", NULL, NULL, NULL); assert(err == SQLITE_OK); - err = sqlite3_prepare_v2(g_temp_db, "SELECT data FROM orders WHERE id=?", -1, &g_stmt_select_order, NULL); + err = sqlite3_prepare_v2(g_swap_db, "INSERT INTO strings (data) VALUES (?)", -1, &g_stmt_insert_string, NULL); + assert(err == SQLITE_OK); + err = sqlite3_prepare_v2(g_swap_db, "SELECT data FROM strings WHERE id=?", -1, &g_stmt_select_string, NULL); + assert(err == SQLITE_OK); + err = sqlite3_prepare_v2(g_swap_db, "INSERT INTO orders (data) VALUES (?)", -1, &g_stmt_insert_order, NULL); + assert(err == SQLITE_OK); + err = sqlite3_prepare_v2(g_swap_db, "SELECT data FROM orders WHERE id=?", -1, &g_stmt_select_order, NULL); assert(err == SQLITE_OK); ERRNO_CHECK(); return 0; @@ -185,7 +191,11 @@ static const char *g_swapname; int db_driver_open(database_t db, const char *dbname) { ERRNO_CHECK(); - + + if (!dbname) { + /* by default, use an in-memory database */ + dbname = ":memory:"; + } if (db == DB_SWAP) { g_swapname = dbname; return db_open_swap(dbname); @@ -202,18 +212,26 @@ void db_driver_close(database_t db) ERRNO_CHECK(); if (db == DB_SWAP) { - assert(g_temp_db); + assert(g_swap_db); + err = sqlite3_finalize(g_stmt_select_string); + assert(err == SQLITE_OK); + err = sqlite3_finalize(g_stmt_insert_string); + assert(err == SQLITE_OK); err = sqlite3_finalize(g_stmt_select_order); assert(err == SQLITE_OK); err = sqlite3_finalize(g_stmt_insert_order); assert(err == SQLITE_OK); - err = sqlite3_close(g_temp_db); + err = sqlite3_close(g_swap_db); assert(err == SQLITE_OK); if (g_swapname) { FILE * F = fopen(g_swapname, "r"); if (F) { fclose(F); - remove(g_swapname); + if (0 != remove(g_swapname)) { + log_error("could not remove %s: %s", g_swapname, + strerror(errno)); + errno = 0; + } } } } @@ -229,3 +247,59 @@ void db_driver_close(database_t db) ERRNO_CHECK(); } +dbrow_id db_driver_string_save(const char *str) { + int err; + sqlite3_int64 id; + + assert(str); + + ERRNO_CHECK(); + + if (g_insert_batchsize > 0) { + if (g_insert_tx_size == 0) { + err = sqlite3_exec(g_swap_db, "BEGIN TRANSACTION", NULL, NULL, NULL); + assert(err == SQLITE_OK); + } + } + + err = sqlite3_reset(g_stmt_insert_string); + assert(err == SQLITE_OK); + err = sqlite3_bind_text(g_stmt_insert_string, 1, str, -1, SQLITE_STATIC); + assert(err == SQLITE_OK); + err = sqlite3_step(g_stmt_insert_string); + assert(err == SQLITE_DONE); + id = sqlite3_last_insert_rowid(g_swap_db); + assert(id > 0 && id <= UINT_MAX); + + if (g_insert_batchsize > 0) { + if (++g_insert_tx_size >= g_insert_batchsize) { + end_transaction(); + } + } + ERRNO_CHECK(); + return (dbrow_id)id; +} + +const char *db_driver_string_load(dbrow_id id, size_t *size) { + int err; + + end_transaction(); + err = sqlite3_reset(g_stmt_select_string); + assert(err == SQLITE_OK); + err = sqlite3_bind_int(g_stmt_select_string, 1, id); + assert(err == SQLITE_OK); + err = sqlite3_step(g_stmt_select_string); + if (err == SQLITE_ROW) { + const unsigned char *text; + text = sqlite3_column_text(g_stmt_select_string, 0); + if (size) { + int bytes = sqlite3_column_bytes(g_stmt_select_string, 0); + assert(bytes > 0); + *size = (size_t)bytes; + } + ERRNO_CHECK(); + return (const char *)text; + } + ERRNO_CHECK(); + return NULL; +} diff --git a/src/kernel/faction.c b/src/kernel/faction.c index 21ea35833..9265d4a8e 100755 --- a/src/kernel/faction.c +++ b/src/kernel/faction.c @@ -22,6 +22,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include "calendar.h" #include "config.h" +#include "database.h" #include "alliance.h" #include "ally.h" #include "curse.h" @@ -105,8 +106,6 @@ static void free_faction(faction * f) freelist(f->allies); free(f->email); - free(f->banner); - free(f->_password); free(f->name); if (f->seen_factions) { selist_free(f->seen_factions); @@ -245,7 +244,7 @@ faction *addfaction(const char *email, const char *password, f->alliance_joindate = turn; f->lastorders = turn; f->_alive = true; - f->_password = NULL; + f->password_id = 0; f->age = 0; f->race = frace; f->magiegebiet = 0; @@ -321,9 +320,11 @@ unit *addplayer(region * r, faction * f) bool checkpasswd(const faction * f, const char *passwd) { + const char *pwhash; if (!passwd) return false; - if (f->_password && password_verify(f->_password, passwd) == VERIFY_FAIL) { + pwhash = faction_getpassword(f); + if (pwhash && password_verify(pwhash, passwd) == VERIFY_FAIL) { log_info("password check failed: %s", factionname(f)); return false; } @@ -495,7 +496,7 @@ void destroyfaction(faction ** fp) handle_event(f->attribs, "destroy", f); if (f->alliance) { - setalliance(f, 0); + setalliance(f, NULL); } funhash(f); @@ -517,35 +518,6 @@ void destroyfaction(faction ** fp) } } -int get_alliance(const faction * a, const faction * b) -{ - const ally *sf = a->allies; - for (; sf != NULL; sf = sf->next) { - if (sf->faction == b) { - return sf->status; - } - } - return 0; -} - -void set_alliance(faction * a, faction * b, int status) -{ - ally **sfp; - sfp = &a->allies; - while (*sfp) { - ally *sf = *sfp; - if (sf->faction == b) - break; - sfp = &sf->next; - } - if (*sfp == NULL) { - ally *sf = ally_add(sfp, b); - sf->status = status; - return; - } - (*sfp)->status |= status; -} - void renumber_faction(faction * f, int no) { funhash(f); @@ -591,23 +563,30 @@ void faction_setemail(faction * self, const char *email) self->email = NULL; } -const char *faction_getbanner(const faction * self) +const char *faction_getbanner(const faction * f) { - return self->banner ? self->banner : ""; + if (f->banner_id > 0) { + return dbstring_load(f->banner_id, NULL); + } + return NULL; } -void faction_setbanner(faction * self, const char *banner) +void faction_setbanner(faction * f, const char *banner) { - free(self->banner); - if (banner) - self->banner = str_strdup(banner); + f->banner_id = dbstring_save(banner); +} + +const char *faction_getpassword(const faction *f) { + if (f->password_id > 0) { + return dbstring_load(f->password_id, NULL); + } + return NULL; } void faction_setpassword(faction * f, const char *pwhash) { assert(pwhash); - free(f->_password); - f->_password = str_strdup(pwhash); + f->password_id = dbstring_save(pwhash); } bool valid_race(const struct faction *f, const struct race *rc) @@ -844,7 +823,8 @@ int writepasswd(void) for (f = factions; f; f = f->next) { fprintf(F, "%s:%s:%s:%d\n", - itoa36(f->no), faction_getemail(f), f->_password, f->uid); + itoa36(f->no), faction_getemail(f), + faction_getpassword(f), f->uid); } fclose(F); return 0; @@ -877,3 +857,11 @@ void free_factions(void) { free_flist(&factions); free_flist(&dead_factions); } + +faction *faction_create(int no) +{ + faction *f = (faction *)calloc(1, sizeof(faction)); + f->no = no; + fhash(f); + return f; +} diff --git a/src/kernel/faction.h b/src/kernel/faction.h index 0fe38cb1d..caa908da5 100644 --- a/src/kernel/faction.h +++ b/src/kernel/faction.h @@ -21,6 +21,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include "skill.h" #include "types.h" +#include "db/driver.h" #include #include @@ -70,9 +71,9 @@ extern "C" { int uid; int flags; char *name; - char *banner; + dbrow_id banner_id; char *email; - char *_password; + dbrow_id password_id; int max_spelllevel; struct spellbook *spellbook; const struct locale *locale; @@ -110,6 +111,8 @@ extern "C" { void fhash(struct faction *f); void funhash(struct faction *f); + int faction_ally_status(const faction *f, const faction *f2); + struct faction *findfaction(int n); int max_magicians(const faction * f); void set_show_item(faction * f, const struct item_type *itype); @@ -124,9 +127,7 @@ extern "C" { void destroyfaction(faction ** f); bool faction_alive(const struct faction *f); - - void set_alliance(struct faction *a, struct faction *b, int status); - int get_alliance(const struct faction *a, const struct faction *b); + struct faction *faction_create(int no); struct alliance *f_get_alliance(const struct faction *f); @@ -154,6 +155,7 @@ extern "C" { void faction_setemail(struct faction *self, const char *email); void faction_setpassword(struct faction *self, const char *pwhash); + const char *faction_getpassword(const struct faction *f); bool valid_race(const struct faction *f, const struct race *rc); void faction_getorigin(const struct faction * f, int id, int *x, int *y); diff --git a/src/kernel/faction.test.c b/src/kernel/faction.test.c index 6c2ed3aa6..66e3c3945 100644 --- a/src/kernel/faction.test.c +++ b/src/kernel/faction.test.c @@ -29,20 +29,18 @@ static void test_destroyfaction_allies(CuTest *tc) { faction *f1, *f2; region *r; - ally *al; test_setup(); r = test_create_region(0, 0, NULL); f1 = test_create_faction(NULL); test_create_unit(f1, r); f2 = test_create_faction(NULL); - al = ally_add(&f1->allies, f2); - al->status = HELP_FIGHT; - CuAssertIntEquals(tc, HELP_FIGHT, alliedgroup(0, f1, f2, f1->allies, HELP_ALL)); + ally_set(&f1->allies, f2, HELP_FIGHT); + CuAssertIntEquals(tc, HELP_FIGHT, alliedfaction(f1, f2, HELP_ALL)); CuAssertPtrEquals(tc, f2, f1->next); destroyfaction(&f1->next); CuAssertIntEquals(tc, false, faction_alive(f2)); - CuAssertIntEquals(tc, 0, alliedgroup(0, f1, f2, f1->allies, HELP_ALL)); + CuAssertIntEquals(tc, 0, alliedfaction(f1, f2, HELP_ALL)); test_teardown(); } @@ -117,7 +115,7 @@ static void test_addfaction(CuTest *tc) { CuAssertPtrNotNull(tc, f->name); CuAssertPtrEquals(tc, NULL, (void *)f->units); CuAssertPtrEquals(tc, NULL, (void *)f->next); - CuAssertPtrEquals(tc, NULL, (void *)f->banner); + CuAssertPtrEquals(tc, NULL, (void *)faction_getbanner(f)); CuAssertPtrEquals(tc, NULL, (void *)f->spellbook); CuAssertPtrEquals(tc, NULL, (void *)f->origin); CuAssertPtrEquals(tc, (void *)factions, (void *)f); @@ -229,6 +227,18 @@ static void test_valid_race(CuTest *tc) { test_teardown(); } +static void test_dbstrings(CuTest *tc) { + const char *lipsum = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua."; + faction *f; + test_setup(); + f = test_create_faction(NULL); + faction_setbanner(f, lipsum); + faction_setpassword(f, lipsum + 12); + CuAssertStrEquals(tc, lipsum, faction_getbanner(f)); + CuAssertStrEquals(tc, lipsum + 12, faction_getpassword(f)); + test_teardown(); +} + static void test_set_email(CuTest *tc) { faction *f; char email[10]; @@ -335,6 +345,7 @@ CuSuite *get_faction_suite(void) SUITE_ADD_TEST(suite, test_check_passwd); SUITE_ADD_TEST(suite, test_valid_race); SUITE_ADD_TEST(suite, test_set_email); + SUITE_ADD_TEST(suite, test_dbstrings); SUITE_ADD_TEST(suite, test_save_special_items); return suite; } diff --git a/src/kernel/group.c b/src/kernel/group.c index 54aa87aeb..9e91d17a1 100755 --- a/src/kernel/group.c +++ b/src/kernel/group.c @@ -53,7 +53,7 @@ group *new_group(faction * f, const char *name, int gid) { group **gp = &f->groups; int index = gid % GMAXHASH; - group *g = calloc(sizeof(group), 1); + group *g = calloc(1, sizeof(group)); while (*gp) gp = &(*gp)->next; @@ -69,15 +69,7 @@ group *new_group(faction * f, const char *name, int gid) static void init_group(faction * f, group * g) { - ally *a, **an; - - an = &g->allies; - for (a = f->allies; a; a = a->next) - if (a->faction) { - ally *ga = ally_add(an, a->faction); - ga->status = a->status; - an = &ga->next; - } + g->allies = ally_clone(f->allies); } static group *find_groupbyname(group * g, const char *name) @@ -139,11 +131,7 @@ void free_group(group * g) if (g->attribs) { a_removeall(&g->attribs, NULL); } - while (g->allies) { - ally *a = g->allies; - g->allies = a->next; - free(a); - } + allies_free(g->allies); free(g->name); free(g); } @@ -204,20 +192,14 @@ group *join_group(unit * u, const char *name) return g; } -void write_groups(struct storage *store, const faction * f) +void write_groups(struct gamedata *data, const faction * f) { group *g; + storage *store = data->store; for (g = f->groups; g; g = g->next) { - ally *a; WRITE_INT(store, g->gid); WRITE_STR(store, g->name); - for (a = g->allies; a; a = a->next) { - if (a->faction && a->faction->_alive) { - write_faction_reference(a->faction, store); - WRITE_INT(store, a->status); - } - } - write_faction_reference(NULL, store); + write_allies(data, g->allies); a_write(store, g->attribs, g); WRITE_SECTION(store); } @@ -228,7 +210,6 @@ void read_groups(gamedata *data, faction * f) { struct storage *store = data->store; for (;;) { - ally **pa; group *g; int gid; char buf[1024]; @@ -238,19 +219,7 @@ void read_groups(gamedata *data, faction * f) break; READ_STR(store, buf, sizeof(buf)); g = new_group(f, buf, gid); - pa = &g->allies; - for (;;) { - ally *al; - int id; - READ_INT(store, &id); - if (id == 0) break; - al = ally_add(pa, NULL); - al->faction = findfaction(id); - if (!al->faction) { - ur_add(RESOLVE_FACTION | id, (void **)&al->faction, NULL); - } - READ_INT(store, &al->status); - } + read_allies(data, &g->allies); read_attribs(data, &g->attribs, g); } } diff --git a/src/kernel/group.h b/src/kernel/group.h index b257f515a..b66e3f50b 100755 --- a/src/kernel/group.h +++ b/src/kernel/group.h @@ -42,7 +42,7 @@ extern "C" { extern void free_group(struct group *g); struct group *new_group(struct faction * f, const char *name, int gid); - extern void write_groups(struct storage *data, const struct faction *f); + extern void write_groups(struct gamedata *data, const struct faction *f); extern void read_groups(struct gamedata *data, struct faction *f); #ifdef __cplusplus diff --git a/src/kernel/group.test.c b/src/kernel/group.test.c index 877728780..7d14380d6 100644 --- a/src/kernel/group.test.c +++ b/src/kernel/group.test.c @@ -28,7 +28,6 @@ static void test_group_readwrite_dead_faction(CuTest *tc) { faction *f, *f2; unit * u; group *g; - ally *al; int fno; test_setup(); @@ -42,8 +41,8 @@ static void test_group_readwrite_dead_faction(CuTest *tc) { CuAssertPtrNotNull(tc, u); g = join_group(u, "group"); CuAssertPtrNotNull(tc, g); - al = ally_add(&g->allies, f); - CuAssertPtrNotNull(tc, al); + ally_set(&g->allies, f, HELP_GIVE); + CuAssertPtrNotNull(tc, g->allies); CuAssertPtrEquals(tc, f, factions); destroyfaction(&factions); @@ -73,7 +72,6 @@ static void test_group_readwrite(CuTest * tc) { faction * f; group *g; - ally *al; int i; gamedata data; storage store; @@ -85,9 +83,8 @@ static void test_group_readwrite(CuTest * tc) new_group(f, "NW", 42); g = new_group(f, "Egoisten", 43); key_set(&g->attribs, 44, 44); - al = ally_add(&g->allies, f); - al->status = HELP_GIVE; - write_groups(&store, f); + ally_set(&g->allies, f, HELP_GIVE); + write_groups(&data, f); WRITE_INT(&store, 47); free_group(f->groups); @@ -110,9 +107,7 @@ static void test_group_readwrite(CuTest * tc) g = f->groups->next; CuAssertIntEquals(tc, 44, key_get(g->attribs, 44)); CuAssertPtrNotNull(tc, g->allies); - CuAssertPtrEquals(tc, NULL, g->allies->next); - CuAssertPtrEquals(tc, f, g->allies->faction); - CuAssertIntEquals(tc, HELP_GIVE, g->allies->status); + CuAssertIntEquals(tc, HELP_GIVE, ally_get(g->allies, f)); test_teardown(); } diff --git a/src/kernel/messages.c b/src/kernel/messages.c index e0513b00d..48ea13f1f 100644 --- a/src/kernel/messages.c +++ b/src/kernel/messages.c @@ -67,6 +67,46 @@ variant v) } } +static int missing_message_mode; + +void message_handle_missing(int mode) { + missing_message_mode = mode; +} + +static message *missing_feedback(const char *name, const struct unit *u, + const struct region *r, struct order *ord) +{ + if (missing_message_mode == MESSAGE_MISSING_ERROR) { + log_error("trying to create undefined feedback of type \"%s\"\n", name); + } + else if (missing_message_mode == MESSAGE_MISSING_REPLACE) { + if (strcmp(name, "missing_feedback") != 0) { + if (!mt_find("missing_feedback")) { + mt_create_va(mt_new("missing_feedback", NULL), "unit:unit", + "region:region", "command:order", "name:string", MT_NEW_END); + } + return msg_message("missing_feedback", "unit region command name", u, r, ord, name); + } + } + return NULL; +} + +static message *missing_message(const char *name) { + if (missing_message_mode == MESSAGE_MISSING_ERROR) { + log_error("trying to create undefined message of type \"%s\"\n", name); + } + else if (missing_message_mode == MESSAGE_MISSING_REPLACE) { + log_warning("trying to create undefined message of type \"%s\"\n", name); + if (strcmp(name, "missing_message") != 0) { + if (!mt_find("missing_message")) { + mt_create_va(mt_new("missing_message", NULL), "name:string", MT_NEW_END); + } + return msg_message("missing_message", "name", name); + } + } + return NULL; +} + struct message *msg_feedback(const struct unit *u, struct order *ord, const char *name, const char *sig, ...) { @@ -80,13 +120,7 @@ struct message *msg_feedback(const struct unit *u, struct order *ord, } if (!mtype) { - log_warning("trying to create message of unknown type \"%s\"\n", name); - if (!mt_find("missing_feedback")) { - mt_create_va(mt_new("missing_feedback", NULL), "unit:unit", - "region:region", "command:order", "name:string", MT_NEW_END); - } - return msg_message("missing_feedback", "name unit region command", - name, u, u->region, ord); + return missing_feedback(name, u, u->region, ord); } var.v = (void *)u; @@ -139,28 +173,6 @@ struct message *msg_feedback(const struct unit *u, struct order *ord, return msg_create(mtype, args); } -static int missing_message_mode; - -void message_handle_missing(int mode) { - missing_message_mode = mode; -} - -static message *missing_message(const char *name) { - if (missing_message_mode == MESSAGE_MISSING_ERROR) { - log_error("trying to create undefined message of type \"%s\"\n", name); - } - else if (missing_message_mode == MESSAGE_MISSING_REPLACE) { - log_warning("trying to create undefined message of type \"%s\"\n", name); - if (strcmp(name, "missing_message") != 0) { - if (!mt_find("missing_message")) { - mt_create_va(mt_new("missing_message", NULL), "name:string", MT_NEW_END); - } - return msg_message("missing_message", "name", name); - } - } - return NULL; -} - message *msg_message(const char *name, const char *sig, ...) /* msg_message("oops_error", "unit region command", u, r, cmd) */ { diff --git a/src/kernel/messages.test.c b/src/kernel/messages.test.c index e852bbc61..c186973fa 100644 --- a/src/kernel/messages.test.c +++ b/src/kernel/messages.test.c @@ -18,6 +18,21 @@ void test_missing_message(CuTest *tc) { CuAssertPtrNotNull(tc, msg); CuAssertPtrNotNull(tc, msg->type); CuAssertStrEquals(tc, msg->type->name, "missing_message"); + CuAssertStrEquals(tc, "unknown", (const char *)msg->parameters[0].v); + msg_release(msg); + test_teardown(); +} + +void test_missing_feedback(CuTest *tc) { + message *msg; + + test_setup(); + message_handle_missing(MESSAGE_MISSING_REPLACE); + msg = msg_error(NULL, NULL, 77); + CuAssertPtrNotNull(tc, msg); + CuAssertPtrNotNull(tc, msg->type); + CuAssertStrEquals(tc, msg->type->name, "missing_feedback"); + CuAssertStrEquals(tc, "error77", (const char *)msg->parameters[3].v); msg_release(msg); test_teardown(); } diff --git a/src/kernel/order.c b/src/kernel/order.c index c0c1e82fb..493922faa 100644 --- a/src/kernel/order.c +++ b/src/kernel/order.c @@ -14,6 +14,8 @@ #include #include "order.h" +#include "db/driver.h" + #include "skill.h" #include @@ -36,6 +38,22 @@ # define ORD_KEYWORD(ord) (keyword_t)((ord)->command & 0xFFFF) # define OD_STRING(odata) ((odata) ? (odata)->_str : NULL) +order_data *odata_load(int id) +{ + if (id > 0) { + return db_driver_order_load(id); + } + return NULL; +} + +int odata_save(order_data *od) +{ + if (od->_str) { + return db_driver_order_save(od->_str); + } + return 0; +} + void odata_create(order_data **pdata, size_t len, const char *str) { order_data *data; @@ -372,7 +390,7 @@ order *parse_order(const char *s, const struct locale * lang) sptr = sp; p = parse_token(&sp, token, sizeof(token)); sk = get_skill(p, lang); - if (!expensive_skill(sk)) { + if (sk == NOSKILL || !expensive_skill(sk)) { kwd = K_AUTOSTUDY; } } diff --git a/src/kernel/orderdb.c b/src/kernel/orderdb.c deleted file mode 100644 index 42248c0ef..000000000 --- a/src/kernel/orderdb.c +++ /dev/null @@ -1,43 +0,0 @@ -#include - -#include "kernel/config.h" -#include "kernel/db/driver.h" - -#include "orderdb.h" - -#include - -#include - -#include -#include -#include - -void orderdb_open(void) -{ - const char *dbname; - - dbname = config_get("game.dbswap"); - db_driver_open(DB_SWAP, dbname); -} - -void orderdb_close(void) -{ - db_driver_close(DB_SWAP); -} - -order_data *odata_load(int id) -{ - if (id > 0) { - return db_driver_order_load(id); - } - return NULL; -} - -int odata_save(order_data *od) -{ - if (od->_str) { - return db_driver_order_save(od->_str); - } - return 0; -} diff --git a/src/kernel/orderdb.h b/src/kernel/orderdb.h deleted file mode 100644 index e17bdfea8..000000000 --- a/src/kernel/orderdb.h +++ /dev/null @@ -1,16 +0,0 @@ -#ifndef H_ORDERDB -#define H_ORDERDB - -#include - -#ifdef __cplusplus -extern "C" { -#endif - - void orderdb_open(void); - void orderdb_close(void); - -#ifdef __cplusplus -} -#endif -#endif diff --git a/src/kernel/plane.h b/src/kernel/plane.h index 5b1c71644..faa663a36 100644 --- a/src/kernel/plane.h +++ b/src/kernel/plane.h @@ -28,10 +28,10 @@ extern "C" { struct plane; struct storage; -#define PFL_NOCOORDS 1 /* not in use */ -#define PFL_NORECRUITS 2 -#define PFL_NOALLIANCES 4 -#define PFL_LOWSTEALING 8 +#define PFL_NOCOORDS 1 /* not implemented */ +#define PFL_NORECRUITS 2 /* cannot recruit */ +#define PFL_NOALLIANCES 4 /* not implemented */ +#define PFL_LOWSTEALING 8 /* not implemented */ #define PFL_NOGIVE 16 /* Übergaben sind unmöglich */ #define PFL_NOATTACK 32 /* Angriffe und Diebstähle sind unmöglich */ #define PFL_NOTERRAIN 64 /* Terraintyp wird nicht angezeigt TODO? */ @@ -40,7 +40,7 @@ extern "C" { #define PFL_NOTEACH 512 /* Lehre außer Betrieb */ #define PFL_NOBUILD 1024 /* Bauen außer Betrieb */ #define PFL_NOFEED 2048 /* Kein Unterhalt nötig */ -#define PFL_FRIENDLY 4096 /* everyone is your ally */ +#define PFL_FRIENDLY 4096 /* not implemented */ #define PFL_NOORCGROWTH 8192 /* orcs don't grow */ #define PFL_NOMONSTERS 16384 /* no monster randenc */ diff --git a/src/kernel/pool.test.c b/src/kernel/pool.test.c index a3de6c021..10c127f81 100644 --- a/src/kernel/pool.test.c +++ b/src/kernel/pool.test.c @@ -47,7 +47,6 @@ void test_pool(CuTest *tc) { faction *f; region *r; struct resource_type *rtype; - ally *al; test_setup(); test_create_world(); @@ -74,10 +73,9 @@ void test_pool(CuTest *tc) { CuAssertIntEquals(tc, 100, get_pooled(u1, rtype, GET_POOLED_SLACK, INT_MAX)); CuAssertIntEquals(tc, 200, get_pooled(u1, rtype, GET_POOLED_SLACK | GET_POOLED_RESERVE, INT_MAX)); - al = ally_add(&u3->faction->allies, f); - al->status = HELP_GUARD; + ally_set(&u3->faction->allies, f, HELP_GUARD); CuAssertIntEquals(tc, 0, get_pooled(u1, rtype, GET_ALLIED_SLACK | GET_ALLIED_RESERVE, INT_MAX)); - al->status = HELP_MONEY; + ally_set(&u3->faction->allies, f, HELP_MONEY); CuAssertIntEquals(tc, 200, get_pooled(u1, rtype, GET_ALLIED_SLACK, INT_MAX)); CuAssertIntEquals(tc, 200, get_pooled(u1, rtype, GET_ALLIED_RESERVE, INT_MAX)); CuAssertIntEquals(tc, 400, get_pooled(u1, rtype, GET_ALLIED_SLACK | GET_ALLIED_RESERVE, INT_MAX)); @@ -117,7 +115,6 @@ void test_pool_use(CuTest *tc) { faction *f; region *r; struct item_type *itype; - ally *al; test_setup(); test_create_world(); @@ -135,8 +132,7 @@ void test_pool_use(CuTest *tc) { set_resvalue(u2, itype, 100); i_change(&u3->items, itype, 400); set_resvalue(u3, itype, 200); - al = ally_add(&u3->faction->allies, f); - al->status = HELP_MONEY; + ally_set(&u3->faction->allies, f, HELP_MONEY); CuAssertIntEquals(tc, 10, use_pooled(u1, itype->rtype, GET_SLACK, 10)); CuAssertIntEquals(tc, 40, use_pooled(u1, itype->rtype, GET_SLACK, 50)); diff --git a/src/kernel/race.c b/src/kernel/race.c index 31d437992..53abd339f 100644 --- a/src/kernel/race.c +++ b/src/kernel/race.c @@ -79,10 +79,10 @@ const char *racenames[MAXRACES] = { "clone" }; -#define MAXOPTIONS 4 +#define MAX_OPTIONS 4 typedef struct rcoption { - unsigned char key[MAXOPTIONS]; - variant value[MAXOPTIONS]; + unsigned char key[MAX_OPTIONS]; + variant value[MAX_OPTIONS]; } rcoption; enum { @@ -106,7 +106,7 @@ static void rc_setoption(race *rc, int k, const char *value) { v = rc->options->value; } else { int i; - for (i=0;!v && i < MAXOPTIONS;++i) { + for (i=0;!v && i < MAX_OPTIONS;++i) { if (rc->options->key[i]==key) { v = rc->options->value+i; break; @@ -114,7 +114,7 @@ static void rc_setoption(race *rc, int k, const char *value) { if (rc->options->key[i]==RCO_NONE) { v = rc->options->value+i; rc->options->key[i] = key; - if (i+1 < MAXOPTIONS) { + if (i+1 < MAX_OPTIONS) { rc->options->key[i+1]=RCO_NONE; } break; @@ -145,7 +145,7 @@ static void rc_setoption(race *rc, int k, const char *value) { static variant *rc_getoption(const race *rc, int key) { if (rc->options) { int i; - for (i=0;i!=MAXOPTIONS && rc->options->key[i]!=RCO_NONE;++i) { + for (i=0;i!=MAX_OPTIONS && rc->options->key[i]!=RCO_NONE;++i) { if (rc->options->key[i]==key) { return rc->options->value+i; } @@ -269,7 +269,7 @@ void free_races(void) { rcoption * opt = races->options; if (opt) { - for (i=0;i!=MAXOPTIONS && opt->key[i]!=RCO_NONE;++i) { + for (i=0;i!=MAX_OPTIONS && opt->key[i]!=RCO_NONE;++i) { if (opt->key[i]==RCO_HUNGER) { free(opt->value[i].v); } @@ -531,14 +531,9 @@ const char *rc_name_s(const race * rc, name_t n) const char *raceprefix(const unit * u) { - attrib *asource = u->faction->attribs; - - if (fval(u, UFL_GROUP)) { - attrib *agroup = a_find(u->attribs, &at_group); - if (agroup != NULL) - asource = ((const group *)(agroup->data.v))->attribs; - } - return get_prefix(asource); + group *g = get_group(u); + attrib *attr = g ? g->attribs : u->faction->attribs; + return get_prefix(attr); } const char *racename(const struct locale *loc, const unit * u, const race * rc) diff --git a/src/kernel/save.c b/src/kernel/save.c index a61e4348f..8c4b408c9 100644 --- a/src/kernel/save.c +++ b/src/kernel/save.c @@ -440,12 +440,12 @@ unit *read_unit(gamedata *data) if (unicode_utf8_trim(obuf)!=0) { log_warning("trim unit %s name to '%s'", itoa36(u->no), obuf); } - u->_name = obuf[0] ? str_strdup(obuf) : 0; + unit_setname(u, obuf[0] ? obuf : NULL); READ_STR(data->store, obuf, sizeof(obuf)); if (unicode_utf8_trim(obuf)!=0) { log_warning("trim unit %s info to '%s'", itoa36(u->no), obuf); } - u->display = obuf[0] ? str_strdup(obuf) : 0; + unit_setinfo(u, obuf[0] ? obuf : NULL); READ_INT(data->store, &number); set_number(u, number); @@ -544,6 +544,7 @@ unit *read_unit(gamedata *data) void write_unit(gamedata *data, const unit * u) { + const char *str; order *ord; int p = 0; unsigned int flags = u->flags & UFL_SAVEMASK; @@ -553,7 +554,8 @@ void write_unit(gamedata *data, const unit * u) assert(u->faction->_alive); write_faction_reference(u->faction, data->store); WRITE_STR(data->store, u->_name); - WRITE_STR(data->store, u->display ? u->display : ""); + str = unit_getinfo(u); + WRITE_STR(data->store, str ? str : ""); WRITE_INT(data->store, u->number); WRITE_INT(data->store, u->age); WRITE_TOK(data->store, u_race(u)->_name); @@ -931,7 +933,6 @@ static void read_password(gamedata *data, faction *f) { else { faction_setpassword(f, (data->version >= CRYPT_VERSION) ? name : password_hash(name, PASSWORD_DEFAULT)); } - (void)_test_read_password; } void _test_read_password(gamedata *data, faction *f) { @@ -939,8 +940,7 @@ void _test_read_password(gamedata *data, faction *f) { } static void write_password(gamedata *data, const faction *f) { - WRITE_TOK(data->store, (const char *)f->_password); - (void)_test_write_password; + WRITE_TOK(data->store, faction_getpassword(f)); } void _test_write_password(gamedata *data, const faction *f) { @@ -957,8 +957,7 @@ faction *read_faction(gamedata * data) assert(n > 0); f = findfaction(n); if (f == NULL) { - f = (faction *)calloc(1, sizeof(faction)); - f->no = n; + f = faction_create(n); } else { f->allies = NULL; /* FIXME: mem leak */ @@ -1009,7 +1008,7 @@ faction *read_faction(gamedata * data) if (unicode_utf8_trim(name)!=0) { log_warning("trim faction %s banner to '%s'", itoa36(f->no), name); }; - f->banner = str_strdup(name); + faction_setbanner(f, name); log_debug(" - Lese Partei %s (%s)", f->name, itoa36(f->no)); @@ -1082,7 +1081,7 @@ faction *read_faction(gamedata * data) /* mistakes were made in the past*/ f->options &= ~WANT_OPTION(O_JSON); } - read_allies(data, f); + read_allies(data, &f->allies); read_groups(data, f); f->spellbook = 0; if (data->version >= REGIONOWNER_VERSION) { @@ -1094,7 +1093,6 @@ faction *read_faction(gamedata * data) void write_faction(gamedata *data, const faction * f) { - ally *sf; origin *ur; assert(f->_alive); @@ -1117,7 +1115,7 @@ void write_faction(gamedata *data, const faction * f) WRITE_INT(data->store, f->alliance_joindate); WRITE_STR(data->store, f->name); - WRITE_STR(data->store, f->banner); + WRITE_STR(data->store, faction_getbanner(f)); WRITE_STR(data->store, f->email?f->email:""); write_password(data, f); WRITE_TOK(data->store, locale_name(f->locale)); @@ -1144,23 +1142,9 @@ void write_faction(gamedata *data, const faction * f) WRITE_INT(data->store, f->options & ~WANT_OPTION(O_DEBUG)); WRITE_SECTION(data->store); - for (sf = f->allies; sf; sf = sf->next) { - int no; - int status; - - assert(sf->faction); - - no = sf->faction->no; - status = alliedfaction(NULL, f, sf->faction, HELP_ALL); - - if (status != 0) { - WRITE_INT(data->store, no); - WRITE_INT(data->store, sf->status); - } - } - WRITE_INT(data->store, 0); + write_allies(data, f->allies); WRITE_SECTION(data->store); - write_groups(data->store, f); + write_groups(data, f); write_spellbook(f->spellbook, data->store); } @@ -1419,7 +1403,6 @@ int read_game(gamedata *data) *fp = f; fp = &f->next; - fhash(f); } *fp = 0; @@ -1519,6 +1502,7 @@ int read_game(gamedata *data) } } else { + assert(f->units); for (u = f->units; u; u = u->nextF) { if (data->version < SPELL_LEVEL_VERSION) { sc_mage *mage = get_mage_depr(u); diff --git a/src/kernel/save.test.c b/src/kernel/save.test.c index 4844d1189..e069d7ebf 100644 --- a/src/kernel/save.test.c +++ b/src/kernel/save.test.c @@ -250,7 +250,6 @@ static void test_readwrite_dead_faction_group(CuTest *tc) { faction *f, *f2; unit * u; group *g; - ally *al; int fno; gamedata data; storage store; @@ -269,8 +268,9 @@ static void test_readwrite_dead_faction_group(CuTest *tc) { CuAssertPtrNotNull(tc, u); g = join_group(u, "group"); CuAssertPtrNotNull(tc, g); - al = ally_add(&g->allies, f); - CuAssertPtrNotNull(tc, al); + CuAssertPtrEquals(tc, NULL, g->allies); + ally_set(&g->allies, f, HELP_GIVE); + CuAssertPtrNotNull(tc, g->allies); CuAssertPtrEquals(tc, f, factions); destroyfaction(&factions); @@ -432,7 +432,7 @@ static void test_read_password_external(CuTest *tc) { } f = test_create_faction(NULL); faction_setpassword(f, password_hash("secret", PASSWORD_DEFAULT)); - CuAssertPtrNotNull(tc, f->_password); + CuAssertPtrNotNull(tc, faction_getpassword(f)); mstream_init(&data.strm); gamedata_init(&data, &store, RELEASE_VERSION); WRITE_TOK(data.store, "newpassword"); diff --git a/src/kernel/spell.test.c b/src/kernel/spell.test.c index d7dfbad7e..027a57079 100644 --- a/src/kernel/spell.test.c +++ b/src/kernel/spell.test.c @@ -33,7 +33,6 @@ static void test_create_duplicate_spell(CuTest * tc) strlist *sl = 0; test_setup(); - test_inject_messagetypes(); test_log_stderr(0); /* suppress the "duplicate spell" error message */ log = test_log_start(LOG_CPERROR, &sl); diff --git a/src/kernel/unit.c b/src/kernel/unit.c index 9b6c3e9ee..d0737eaba 100644 --- a/src/kernel/unit.c +++ b/src/kernel/unit.c @@ -474,8 +474,8 @@ attrib_type at_private = { const char *u_description(const unit * u, const struct locale *lang) { - if (u->display && u->display[0]) { - return u->display; + if (u->display_id > 0) { + return unit_getinfo(u); } else { char zText[64]; @@ -1293,7 +1293,6 @@ void free_unit(unit * u) { assert(!u->region); free(u->_name); - free(u->display); free_order(u->thisorder); free_orders(&u->orders); if (u->skills) @@ -1455,10 +1454,9 @@ unit *create_unit(region * r, faction * f, int number, const struct race *urace, } /* Gruppen */ - if (creator->faction == f && fval(creator, UFL_GROUP)) { - a = a_find(creator->attribs, &at_group); - if (a) { - group *g = (group *)a->data.v; + if (creator->faction == f) { + group *g = get_group(creator); + if (g) { set_group(u, g); } } @@ -1522,16 +1520,20 @@ void unit_setname(unit * u, const char *name) const char *unit_getinfo(const unit * u) { - return (const char *)u->display; + if (u->display_id > 0) { + return dbstring_load(u->display_id, NULL); + } + return NULL; } void unit_setinfo(unit * u, const char *info) { - free(u->display); - if (info) - u->display = str_strdup(info); - else - u->display = NULL; + if (info) { + u->display_id = dbstring_save(info); + } + else { + u->display_id = 0; + } } int unit_getid(const unit * u) @@ -1798,10 +1800,6 @@ bool unit_name_equals_race(const unit *u) { return false; } -bool unit_can_study(const unit *u) { - return !((u_race(u)->flags & RCF_NOLEARN) || fval(u, UFL_WERE)); -} - static int read_newunitid(const faction * f, const region * r) { int n; diff --git a/src/kernel/unit.h b/src/kernel/unit.h index 3f82ef80a..86c2e2e61 100644 --- a/src/kernel/unit.h +++ b/src/kernel/unit.h @@ -21,6 +21,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include #include "types.h" +#include "database.h" #include "skills.h" #include @@ -89,7 +90,7 @@ extern "C" { int no; /* id */ int hp; char *_name; - char *display; + dbrow_id display_id; struct faction *faction; struct building *building; struct ship *ship; @@ -242,7 +243,6 @@ extern "C" { const char *unitname(const struct unit *u); char *write_unitname(const struct unit *u, char *buffer, size_t size); bool unit_name_equals_race(const struct unit *u); - bool unit_can_study(const struct unit *u); /* getunit results: */ #define GET_UNIT 0 diff --git a/src/kernel/unit.test.c b/src/kernel/unit.test.c index 085e0177a..0918e83aa 100644 --- a/src/kernel/unit.test.c +++ b/src/kernel/unit.test.c @@ -397,14 +397,13 @@ static void test_unit_description(CuTest *tc) { rc = test_create_race("hodor"); u = test_create_unit(test_create_faction(rc), test_create_region(0, 0, NULL)); - CuAssertPtrEquals(tc, NULL, u->display); - CuAssertStrEquals(tc, 0, u_description(u, lang)); - u->display = str_strdup("Hodor"); + CuAssertStrEquals(tc, NULL, unit_getinfo(u)); + CuAssertStrEquals(tc, NULL, u_description(u, lang)); + unit_setinfo(u, "Hodor"); CuAssertStrEquals(tc, "Hodor", u_description(u, NULL)); CuAssertStrEquals(tc, "Hodor", u_description(u, lang)); - free(u->display); - u->display = NULL; + unit_setinfo(u, NULL); locale_setstring(lang, "describe_hodor", "HODOR"); CuAssertStrEquals(tc, "HODOR", u_description(u, lang)); diff --git a/src/laws.c b/src/laws.c index 035ed7088..61eac6a0b 100644 --- a/src/laws.c +++ b/src/laws.c @@ -800,7 +800,7 @@ void immigration(void) void nmr_warnings(void) { faction *f, *fa; -#define FRIEND (HELP_GUARD|HELP_MONEY) +#define HELP_NMR (HELP_GUARD|HELP_MONEY) for (f = factions; f; f = f->next) { if (!fval(f, FFL_NOIDLEOUT) && turn > f->lastorders) { ADDMSG(&f->msgs, msg_message("nmr_warning", "")); @@ -816,14 +816,12 @@ void nmr_warnings(void) warn = 1; } } - else if (alliedfaction(NULL, f, fa, FRIEND) - && alliedfaction(NULL, fa, f, FRIEND)) { + else if (alliedfaction(f, fa, HELP_NMR) && alliedfaction(fa, f, HELP_NMR)) { warn = 1; } if (warn) { if (msg == NULL) { - msg = - msg_message("warn_dropout", "faction turns", f, + msg = msg_message("warn_dropout", "faction turns", f, turn - f->lastorders); } add_message(&fa->msgs, msg); @@ -1319,9 +1317,9 @@ int ally_cmd(unit * u, struct order *ord) sfp = &u->faction->allies; if (fval(u, UFL_GROUP)) { - attrib *a = a_find(u->attribs, &at_group); - if (a) { - sfp = &((group *)a->data.v)->allies; + group *g = get_group(u); + if (g) { + sfp = &g->allies; } } @@ -1455,12 +1453,8 @@ int prefix_cmd(unit * u, struct order *ord) s = gettoken(token, sizeof(token)); if (!s || !*s) { - attrib *a = NULL; - if (fval(u, UFL_GROUP)) { - a = a_find(u->attribs, &at_group); - } - if (a) { - group *g = (group *)a->data.v; + group *g = get_group(u); + if (g) { a_removeall(&g->attribs, &at_raceprefix); } else { @@ -1475,13 +1469,12 @@ int prefix_cmd(unit * u, struct order *ord) cmistake(u, ord, 299, MSG_EVENT); } else { - ap = &u->faction->attribs; - if (fval(u, UFL_GROUP)) { - attrib *a = a_find(u->attribs, &at_group); - if (a) { - group *g = (group *)a->data.v; - ap = &g->attribs; - } + group *g = get_group(u); + if (g) { + ap = &g->attribs; + } + else { + ap = &u->faction->attribs; } set_prefix(ap, race_prefixes[var.i]); } @@ -1529,7 +1522,7 @@ int display_cmd(unit * u, struct order *ord) break; case P_UNIT: - s = &u->display; + unit_setinfo(u, getstrtoken()); break; case P_PRIVAT: @@ -1841,11 +1834,8 @@ int name_cmd(struct unit *u, struct order *ord) case P_GROUP: { - attrib *a = NULL; - if (fval(u, UFL_GROUP)) - a = a_find(u->attribs, &at_group); - if (a) { - group *g = (group *)a->data.v; + group *g = get_group(u); + if (g) { s = &g->name; break; } @@ -2073,12 +2063,10 @@ int banner_cmd(unit * u, struct order *ord) { const char * s; - free(u->faction->banner); init_order_depr(ord); s = getstrtoken(); - u->faction->banner = s ? str_strdup(s) : 0; - add_message(&u->faction->msgs, msg_message("changebanner", "value", - u->faction->banner)); + faction_setbanner(u->faction, s); + add_message(&u->faction->msgs, msg_message("changebanner", "value", s)); return 0; } diff --git a/src/laws.test.c b/src/laws.test.c index fb8929996..5a4f85b85 100644 --- a/src/laws.test.c +++ b/src/laws.test.c @@ -140,7 +140,6 @@ static void test_enter_ship(CuTest * tc) race * rc; test_setup(); - r = test_create_region(0, 0, NULL); rc = test_create_race("smurf"); u = test_create_unit(test_create_faction(rc), r); @@ -188,12 +187,12 @@ static void test_display_cmd(CuTest *tc) { ord = create_order(K_DISPLAY, f->locale, "%s Hodor", LOC(f->locale, parameters[P_UNIT])); CuAssertIntEquals(tc, 0, display_cmd(u, ord)); - CuAssertStrEquals(tc, "Hodor", u->display); + CuAssertStrEquals(tc, "Hodor", unit_getinfo(u)); free_order(ord); ord = create_order(K_DISPLAY, f->locale, LOC(f->locale, parameters[P_UNIT])); CuAssertIntEquals(tc, 0, display_cmd(u, ord)); - CuAssertPtrEquals(tc, NULL, u->display); + CuAssertPtrEquals(tc, NULL, (void *)unit_getinfo(u)); free_order(ord); ord = create_order(K_DISPLAY, f->locale, "%s Hodor", LOC(f->locale, parameters[P_REGION])); @@ -222,7 +221,6 @@ static void test_rule_force_leave(CuTest *tc) { } static void test_force_leave_buildings(CuTest *tc) { - ally *al; region *r; unit *u1, *u2, *u3; building * b; @@ -245,8 +243,7 @@ static void test_force_leave_buildings(CuTest *tc) { CuAssertPtrNotNull(tc, test_find_messagetype(u3->faction->msgs, "force_leave_building")); u_set_building(u3, b); - al = ally_add(&u1->faction->allies, u3->faction); - al->status = HELP_GUARD; + ally_set(&u1->faction->allies, u3->faction, HELP_GUARD); force_leave(r, NULL); CuAssertPtrEquals_Msg(tc, "allies should not be forced to leave", b, u3->building); test_teardown(); @@ -477,6 +474,10 @@ static void test_limit_new_units(CuTest * tc) alliance *al; test_setup(); + mt_create_va(mt_new("too_many_units_in_faction", NULL), "unit:unit", + "region:region", "command:order", "allowed:int", MT_NEW_END); + mt_create_va(mt_new("too_many_units_in_alliance", NULL), "unit:unit", + "region:region", "command:order", "allowed:int", MT_NEW_END); al = makealliance(1, "Hodor"); f = test_create_faction(NULL); u = test_create_unit(f, test_create_region(0, 0, NULL)); @@ -892,6 +893,9 @@ static unit * setup_name_cmd(void) { faction *f; test_setup(); + mt_create_error(84); + mt_create_error(148); + mt_create_error(12); mt_create_va(mt_new("renamed_building_seen", NULL), "renamer:unit", "region:region", "building:building", MT_NEW_END); mt_create_va(mt_new("renamed_building_notseen", NULL), "region:region", "building:building", MT_NEW_END); f = test_create_faction(NULL); @@ -1090,6 +1094,7 @@ static void test_long_order_multi_long(CuTest *tc) { /* TODO: write more tests */ unit *u; test_setup(); + mt_create_error(52); u = test_create_unit(test_create_faction(NULL), test_create_region(0, 0, NULL)); unit_addorder(u, create_order(K_MOVE, u->faction->locale, NULL)); unit_addorder(u, create_order(K_DESTROY, u->faction->locale, NULL)); @@ -1104,6 +1109,7 @@ static void test_long_order_multi_buy(CuTest *tc) { /* TODO: write more tests */ unit *u; test_setup(); + mt_create_error(52); u = test_create_unit(test_create_faction(NULL), test_create_region(0, 0, NULL)); unit_addorder(u, create_order(K_BUY, u->faction->locale, 0)); unit_addorder(u, create_order(K_BUY, u->faction->locale, 0)); @@ -1133,6 +1139,7 @@ static void test_long_order_buy_cast(CuTest *tc) { /* TODO: write more tests */ unit *u; test_setup(); + mt_create_error(52); u = test_create_unit(test_create_faction(NULL), test_create_region(0, 0, NULL)); unit_addorder(u, create_order(K_BUY, u->faction->locale, 0)); unit_addorder(u, create_order(K_CAST, u->faction->locale, 0)); @@ -1165,6 +1172,7 @@ static void test_ally_cmd_errors(CuTest *tc) { order *ord; test_setup(); + mt_create_error(66); u = test_create_unit(test_create_faction(NULL), test_create_region(0, 0, NULL)); fid = u->faction->no + 1; CuAssertPtrEquals(tc, NULL, findfaction(fid)); @@ -1265,25 +1273,25 @@ static void test_ally_cmd(CuTest *tc) { ord = create_order(K_ALLY, f->locale, "%s", itoa36(f->no)); ally_cmd(u, ord); CuAssertPtrEquals(tc, NULL, u->faction->msgs); - CuAssertIntEquals(tc, HELP_ALL, alliedfaction(0, u->faction, f, HELP_ALL)); + CuAssertIntEquals(tc, HELP_ALL, ally_get(u->faction->allies, f)); free_order(ord); ord = create_order(K_ALLY, f->locale, "%s %s", itoa36(f->no), LOC(f->locale, parameters[P_NOT])); ally_cmd(u, ord); CuAssertPtrEquals(tc, NULL, u->faction->msgs); - CuAssertIntEquals(tc, 0, alliedfaction(0, u->faction, f, HELP_ALL)); + CuAssertIntEquals(tc, 0, ally_get(u->faction->allies, f)); free_order(ord); ord = create_order(K_ALLY, f->locale, "%s %s", itoa36(f->no), LOC(f->locale, parameters[P_GUARD])); ally_cmd(u, ord); CuAssertPtrEquals(tc, NULL, u->faction->msgs); - CuAssertIntEquals(tc, HELP_GUARD, alliedfaction(0, u->faction, f, HELP_ALL)); + CuAssertIntEquals(tc, HELP_GUARD, ally_get(u->faction->allies, f)); free_order(ord); ord = create_order(K_ALLY, f->locale, "%s %s %s", itoa36(f->no), LOC(f->locale, parameters[P_GUARD]), LOC(f->locale, parameters[P_NOT])); ally_cmd(u, ord); CuAssertPtrEquals(tc, NULL, u->faction->msgs); - CuAssertIntEquals(tc, 0, alliedfaction(0, u->faction, f, HELP_ALL)); + CuAssertIntEquals(tc, 0, ally_get(u->faction->allies, f)); free_order(ord); test_teardown(); @@ -1316,6 +1324,8 @@ static unit * setup_mail_cmd(void) { faction *f; test_setup(); + mt_create_error(66); + mt_create_error(30); mt_create_va(mt_new("regionmessage", NULL), "region:region", "sender:unit", "string:string", MT_NEW_END); mt_create_va(mt_new("unitmessage", NULL), "region:region", "sender:unit", "string:string", "unit:unit", MT_NEW_END); mt_create_va(mt_new("mail_result", NULL), "message:string", "unit:unit", MT_NEW_END); @@ -1435,6 +1445,8 @@ static void test_show_without_item(CuTest *tc) struct locale *loc; test_setup(); + mt_create_error(21); + mt_create_error(36); mt_create_va(mt_new("displayitem", NULL), "weight:int", "item:resource", "description:string", MT_NEW_END); loc = get_or_create_locale("de"); @@ -1479,7 +1491,6 @@ static void test_show_race(CuTest *tc) { message * msg; test_setup(); - mt_create_va(mt_new("msg_event", NULL), "string:string", MT_NEW_END); test_create_race("human"); rc = test_create_race("elf"); @@ -1495,8 +1506,8 @@ static void test_show_race(CuTest *tc) { ord = create_order(K_RESHOW, loc, "Mensch"); reshow_cmd(u, ord); - CuAssertTrue(tc, test_find_messagetype(u->faction->msgs, "error21") != NULL); - CuAssertTrue(tc, test_find_messagetype(u->faction->msgs, "msg_event") == NULL); + CuAssertPtrNotNull(tc, test_find_messagetype(u->faction->msgs, "error21")); + CuAssertPtrEquals(tc, NULL, test_find_messagetype(u->faction->msgs, "msg_event")); test_clear_messages(u->faction); free_order(ord); diff --git a/src/main.c b/src/main.c index 118f30afd..d51f55471 100644 --- a/src/main.c +++ b/src/main.c @@ -1,5 +1,5 @@ /* -Copyright (c) 1998-2017, Enno Rehling +Copyright (c) 1998-2018, Enno Rehling Katja Zedel @@ -192,7 +192,7 @@ static int parse_args(int argc, char **argv) else if (argi[1] == '-') { /* long format */ if (strcmp(argi + 2, "version") == 0) { printf("Eressea version %s, " - "Copyright (C) 2017 Enno Rehling et al.\n", + "Copyright (C) 2018 Enno Rehling et al.\n", eressea_version()); return 1; #ifdef USE_CURSES diff --git a/src/monsters.c b/src/monsters.c index 9f17db54d..0d383ac05 100644 --- a/src/monsters.c +++ b/src/monsters.c @@ -557,7 +557,7 @@ static order *monster_learn(unit * u) const struct locale *lang = u->faction->locale; /* can these monsters even study? */ - if (!unit_can_study(u)) { + if (!check_student(u, NULL, SK_PERCEPTION)) { return NULL; } @@ -832,8 +832,7 @@ void plan_monsters(faction * f) } } } - - if (long_order == NULL && unit_can_study(u)) { + if (long_order == NULL && check_student(u, NULL, SK_WEAPONLESS)) { /* Einheiten, die Waffenlosen Kampf lernen k�nnten, lernen es um * zu bewachen: */ if (rc->bonus[SK_WEAPONLESS] != -99) { diff --git a/src/move.test.c b/src/move.test.c index a4a65fead..2c91165e2 100644 --- a/src/move.test.c +++ b/src/move.test.c @@ -153,7 +153,6 @@ static void test_ship_has_harbormaster_same_faction(CuTest * tc) { static void test_ship_has_harbormaster_ally(CuTest * tc) { unit *u; move_fixture mf; - ally *al; test_setup(); setup_harbor(&mf); @@ -161,8 +160,7 @@ static void test_ship_has_harbormaster_ally(CuTest * tc) { u = test_create_unit(test_create_faction(NULL), mf.r); u->building = mf.b; building_set_owner(u); - al = ally_add(&u->faction->allies, mf.u->faction); - al->status = HELP_GUARD; + ally_set(&u->faction->allies, mf.u->faction, HELP_GUARD); CuAssertIntEquals(tc, SA_HARBOUR, check_ship_allowed(mf.sh, mf.r)); test_teardown(); diff --git a/src/orderdb.c b/src/orderdb.c deleted file mode 100644 index 5c224a79e..000000000 --- a/src/orderdb.c +++ /dev/null @@ -1,42 +0,0 @@ -#include - -#include "kernel/config.h" -#include "kernel/db/driver.h" - -#include "orderdb.h" - -#include - -#include - -#include -#include -#include - -void orderdb_open(void) -{ - const char *dbname; - dbname = config_get("game.dbswap"); - db_driver_open(DB_SWAP, dbname); -} - -void orderdb_close(void) -{ - db_driver_close(DB_SWAP); -} - -order_data *odata_load(int id) -{ - if (id > 0) { - return db_driver_order_load(id); - } - return NULL; -} - -int odata_save(order_data *od) -{ - if (od->_str) { - return db_driver_order_save(od->_str); - } - return 0; -} diff --git a/src/orderdb.h b/src/orderdb.h deleted file mode 100644 index cc809b1a6..000000000 --- a/src/orderdb.h +++ /dev/null @@ -1,25 +0,0 @@ -#ifndef H_ORDERDB -#define H_ORDERDB - -#include - -#ifdef __cplusplus -extern "C" { -#endif - - typedef struct order_data { - const char *_str; - int _refcount; - } order_data; - - void odata_create(order_data **pdata, size_t len, const char *str); - void odata_release(order_data * od); - void odata_addref(order_data *od); - - void orderdb_open(void); - void orderdb_close(void); - -#ifdef __cplusplus -} -#endif -#endif diff --git a/src/orderdb.test.c b/src/orderdb.test.c deleted file mode 100644 index bdb6f0a95..000000000 --- a/src/orderdb.test.c +++ /dev/null @@ -1,28 +0,0 @@ -#include -#include - -#include "orderdb.h" - -#include -#include - -#include - -static void test_orderdb(CuTest *tc) { - order_data *od = NULL; - const char * s = "GIB enno 1 Hodor"; - - odata_create(&od, strlen(s) + 1, s); - CuAssertPtrNotNull(tc, od); - CuAssertStrEquals(tc, s, od->_str); - CuAssertTrue(tc, od->_refcount >= 1); - odata_release(od); -} - -CuSuite *get_orderdb_suite(void) -{ - CuSuite *suite = CuSuiteNew(); - SUITE_ADD_TEST(suite, test_orderdb); - - return suite; -} diff --git a/src/piracy.test.c b/src/piracy.test.c index 7aa57bc2d..74e79103d 100644 --- a/src/piracy.test.c +++ b/src/piracy.test.c @@ -30,6 +30,8 @@ static void setup_piracy(void) { st_boat = test_create_shiptype("boat"); st_boat->cargo = 1000; + mt_create_error(144); + mt_create_error(146); mt_create_va(mt_new("piratenovictim", NULL), "ship:ship", "unit:unit", "region:region", MT_NEW_END); mt_create_va(mt_new("piratesawvictim", NULL), diff --git a/src/renumber.test.c b/src/renumber.test.c index 8d44b92da..e5f9c5c33 100644 --- a/src/renumber.test.c +++ b/src/renumber.test.c @@ -15,12 +15,19 @@ #include #include +static void setup_renumber(CuTest *tc) { + test_setup_ex(tc); + mt_create_error(114); + mt_create_error(115); + mt_create_error(116); +} + static void test_renumber_faction(CuTest *tc) { unit *u; int uno, no; const struct locale *lang; - test_setup_ex(tc); + setup_renumber(tc); u = test_create_unit(test_create_faction(NULL), test_create_region(0, 0, NULL)); no = u->faction->no; uno = (no > 1) ? no - 1 : no + 1; @@ -38,7 +45,7 @@ static void test_renumber_faction_duplicate(CuTest *tc) { int no; const struct locale *lang; - test_setup_ex(tc); + setup_renumber(tc); mt_create_va(mt_new("renumber_inuse", NULL), "id:int", MT_NEW_END); f2 = test_create_faction(NULL); u = test_create_unit(f = test_create_faction(NULL), test_create_region(0, 0, NULL)); @@ -58,7 +65,7 @@ static void test_renumber_faction_invalid(CuTest *tc) { int no; const struct locale *lang; - test_setup_ex(tc); + setup_renumber(tc); u = test_create_unit(f = test_create_faction(0), test_create_region(0, 0, 0)); no = f->no; lang = f->locale; @@ -88,7 +95,7 @@ static void test_renumber_building(CuTest *tc) { int uno, no; const struct locale *lang; - test_setup_ex(tc); + setup_renumber(tc); u = test_create_unit(test_create_faction(NULL), test_create_region(0, 0, NULL)); u->building = test_create_building(u->region, NULL); no = u->building->no; @@ -106,7 +113,7 @@ static void test_renumber_building_duplicate(CuTest *tc) { int uno, no; const struct locale *lang; - test_setup_ex(tc); + setup_renumber(tc); u = test_create_unit(f = test_create_faction(NULL), test_create_region(0, 0, NULL)); u->building = test_create_building(u->region, NULL); uno = u->building->no; @@ -125,7 +132,7 @@ static void test_renumber_ship(CuTest *tc) { int uno, no; const struct locale *lang; - test_setup_ex(tc); + setup_renumber(tc); u = test_create_unit(test_create_faction(NULL), test_create_region(0, 0, NULL)); u->ship = test_create_ship(u->region, NULL); no = u->ship->no; @@ -142,7 +149,7 @@ static void test_renumber_ship_twice(CuTest *tc) { int uno, no; const struct locale *lang; - test_setup_ex(tc); + setup_renumber(tc); u = test_create_unit(test_create_faction(NULL), test_create_region(0, 0, NULL)); u->ship = test_create_ship(u->region, NULL); no = u->ship->no; @@ -164,7 +171,7 @@ static void test_renumber_ship_duplicate(CuTest *tc) { int uno, no; const struct locale *lang; - test_setup_ex(tc); + setup_renumber(tc); u = test_create_unit(f = test_create_faction(NULL), test_create_region(0, 0, NULL)); u->ship = test_create_ship(u->region, NULL); uno = u->ship->no; @@ -183,7 +190,7 @@ static void test_renumber_unit(CuTest *tc) { int uno, no; const struct locale *lang; - test_setup_ex(tc); + setup_renumber(tc); u = test_create_unit(test_create_faction(NULL), test_create_region(0, 0, NULL)); no = u->no; uno = (no > 1) ? no - 1 : no + 1; @@ -201,7 +208,7 @@ static void test_renumber_unit_duplicate(CuTest *tc) { int no; const struct locale *lang; - test_setup_ex(tc); + setup_renumber(tc); u = test_create_unit(f = test_create_faction(NULL), test_create_region(0, 0, NULL)); no = u->no; u2 = test_create_unit(f, u->region); @@ -220,7 +227,7 @@ static void test_renumber_unit_limit(CuTest *tc) { int no; const struct locale *lang; - test_setup_ex(tc); + setup_renumber(tc); u = test_create_unit(f = test_create_faction(NULL), test_create_region(0, 0, NULL)); no = u->no; lang = f->locale; @@ -238,7 +245,7 @@ static void test_renumber_unit_invalid(CuTest *tc) { int no; const struct locale *lang; - test_setup_ex(tc); + setup_renumber(tc); u = test_create_unit(f = test_create_faction(NULL), test_create_region(0, 0, NULL)); no = u->no; lang = f->locale; diff --git a/src/report.c b/src/report.c index 5d2ed4598..f641534f1 100644 --- a/src/report.c +++ b/src/report.c @@ -902,6 +902,7 @@ void report_region(struct stream *out, const region * r, faction * f) assert(f); assert(r); + memset(edges, 0, sizeof(edges)); for (d = 0; d != MAXDIRECTIONS; d++) { /* Nachbarregionen, die gesehen werden, ermitteln */ region *r2 = rconnect(r, d); @@ -1510,97 +1511,94 @@ report_template(const char *filename, report_context * ctx, const char *bom) return 0; } -static void -show_allies(const faction * f, const ally * allies, char *buf, size_t size) -{ - int allierte = 0; - int i = 0, h, hh = 0; - int bytes, dh = 0; - const ally *sf; - char *bufp = buf; /* buf already contains data */ - - --size; /* leave room for a null-terminator */ - - for (sf = allies; sf; sf = sf->next) { - int mode = alliedgroup(NULL, f, sf->faction, sf, HELP_ALL); - if (mode > 0) - ++allierte; +static int count_allies_cb(struct ally *all, faction *af, int status, void *udata) { + int *num = (int *)udata; + if (status > 0) { + ++*num; } + return 0; +} - for (sf = allies; sf; sf = sf->next) { - int mode = alliedgroup(NULL, f, sf->faction, sf, HELP_ALL); - if (mode <= 0) - continue; - i++; - if (dh) { - if (i == allierte) { - bytes = (int)str_strlcpy(bufp, LOC(f->locale, "list_and"), size); - } - else { - bytes = (int)str_strlcpy(bufp, ", ", size); - } - if (wrptr(&bufp, &size, bytes) != 0) - WARN_STATIC_BUFFER(); - } - dh = 1; - hh = 0; - bytes = (int)str_strlcpy(bufp, factionname(sf->faction), size); - if (wrptr(&bufp, &size, bytes) != 0) - WARN_STATIC_BUFFER(); - bytes = (int)str_strlcpy(bufp, " (", size); - if (wrptr(&bufp, &size, bytes) != 0) - WARN_STATIC_BUFFER(); - if ((mode & HELP_ALL) == HELP_ALL) { - bytes = (int)str_strlcpy(bufp, LOC(f->locale, parameters[P_ANY]), size); - if (wrptr(&bufp, &size, bytes) != 0) - WARN_STATIC_BUFFER(); +struct show_s { + sbstring sbs; + const faction *f; + int num_allies; +}; + +static int show_allies_cb(struct ally *all, faction *af, int status, void *udata) { + struct show_s * show = (struct show_s *)udata; + const faction * f = show->f; + + int mode = alliance_status(f, af, status); + --show->num_allies; + if (sbs_length(&show->sbs) > 0) { + /* not the first entry */ + if (0 == show->num_allies) { + sbs_strcat(&show->sbs, LOC(f->locale, "list_and")); } else { - for (h = 1; h <= HELP_TRAVEL; h *= 2) { - int p = MAXPARAMS; - if ((mode & h) == h) { - switch (h) { - case HELP_TRAVEL: - p = P_TRAVEL; - break; - case HELP_MONEY: - p = P_MONEY; - break; - case HELP_FIGHT: - p = P_FIGHT; - break; - case HELP_GIVE: - p = P_GIVE; - break; - case HELP_GUARD: - p = P_GUARD; - break; - case HELP_FSTEALTH: - p = P_FACTIONSTEALTH; - break; - } - } - if (p != MAXPARAMS) { - if (hh) { - bytes = (int)str_strlcpy(bufp, ", ", size); - if (wrptr(&bufp, &size, bytes) != 0) - WARN_STATIC_BUFFER(); - } - bytes = (int)str_strlcpy(bufp, LOC(f->locale, parameters[p]), size); - if (wrptr(&bufp, &size, bytes) != 0) - WARN_STATIC_BUFFER(); - hh = 1; + sbs_strcat(&show->sbs, ", "); + } + } + sbs_strcat(&show->sbs, factionname(af)); + sbs_strcat(&show->sbs, " ("); + if ((mode & HELP_ALL) == HELP_ALL) { + sbs_strcat(&show->sbs, LOC(f->locale, parameters[P_ANY])); + } + else { + int h, hh = 0; + for (h = 1; h <= HELP_TRAVEL; h *= 2) { + int p = MAXPARAMS; + if ((mode & h) == h) { + switch (h) { + case HELP_TRAVEL: + p = P_TRAVEL; + break; + case HELP_MONEY: + p = P_MONEY; + break; + case HELP_FIGHT: + p = P_FIGHT; + break; + case HELP_GIVE: + p = P_GIVE; + break; + case HELP_GUARD: + p = P_GUARD; + break; + case HELP_FSTEALTH: + p = P_FACTIONSTEALTH; + break; } } + if (p != MAXPARAMS) { + if (hh) { + sbs_strcat(&show->sbs, ", "); + } + sbs_strcat(&show->sbs, LOC(f->locale, parameters[p])); + hh = 1; + } } - bytes = (int)str_strlcpy(bufp, ")", size); - if (wrptr(&bufp, &size, bytes) != 0) - WARN_STATIC_BUFFER(); } - bytes = (int)str_strlcpy(bufp, ".", size); - if (wrptr(&bufp, &size, bytes) != 0) - WARN_STATIC_BUFFER(); - *bufp = 0; + sbs_strcat(&show->sbs, ")"); + return 0; +} + +static void +show_allies(const faction * f, struct ally * allies, char *buf, size_t size) +{ + int num_allies = 0; + ally_walk(allies, count_allies_cb, &num_allies); + + if (num_allies > 0) { + struct show_s show; + show.f = f; + show.num_allies = num_allies; + sbs_init(&show.sbs, buf, size); + + ally_walk(allies, show_allies_cb, &show); + sbs_strcat(&show.sbs, "."); + } } static void allies(struct stream *out, const faction * f) @@ -1726,16 +1724,19 @@ static void list_address(struct stream *out, const faction * uf, selist * seenfa while (flist != NULL) { const faction *f = (const faction *)selist_get(flist, qi); if (!is_monsters(f)) { + const char *str; char buf[8192]; char label = '-'; + str = faction_getbanner(f); sprintf(buf, "%s: %s; %s", factionname(f), faction_getemail(f), - f->banner ? f->banner : ""); + str ? str : ""); if (uf == f) label = '*'; - else if (is_allied(uf, f)) + else if (is_allied(uf, f)) { label = 'o'; - else if (alliedfaction(NULL, uf, f, HELP_ALL)) + } + else if (alliedfaction(uf, f, HELP_ALL)) label = '+'; paragraph(out, buf, 4, 0, label); } diff --git a/src/reports.c b/src/reports.c index 879e7ad3d..12154b70d 100644 --- a/src/reports.c +++ b/src/reports.c @@ -697,9 +697,8 @@ bufunit(const faction * f, const unit * u, seen_mode mode, char *buf, if (!isbattle) { if (u->faction == f) { if (fval(u, UFL_GROUP)) { - attrib *a = a_find(u->attribs, &at_group); - if (a) { - group *g = (group *)a->data.v; + group *g = get_group(u); + if (g) { bufp = STRLCPY(bufp, ", ", size); bufp = STRLCPY(bufp, groupid(g, f), size); } @@ -969,7 +968,7 @@ bufunit(const faction * f, const unit * u, seen_mode mode, char *buf, dh = 0; if (!getarnt) { - if (alliedfaction(rplane(u->region), f, fv, HELP_ALL)) { + if (alliedfaction(f, fv, HELP_ALL)) { dh = 1; } } @@ -1554,14 +1553,6 @@ void prepare_report(report_context *ctx, faction *f) rule_lighthouse_units = config_get_int("rules.lighthouse.unit_capacity", 0) != 0; } - if (f->age <= 2) { - if ((f->flags&FFL_PWMSG) == 0) { - /* TODO: this assumes unencrypted passwords */ - f->flags |= FFL_PWMSG; - ADDMSG(&f->msgs, msg_message("changepasswd", "value", f->_password)); - } - } - ctx->f = f; ctx->report_time = time(NULL); ctx->addresses = NULL; diff --git a/src/reports.test.c b/src/reports.test.c index d402b2b6a..247676451 100644 --- a/src/reports.test.c +++ b/src/reports.test.c @@ -177,7 +177,6 @@ static void test_bufunit_fstealth(CuTest *tc) { faction *f1, *f2; region *r; unit *u; - ally *al; char buf[256]; struct locale *lang; @@ -232,8 +231,7 @@ static void test_bufunit_fstealth(CuTest *tc) { u->flags &= ~UFL_ANON_FACTION; /* we see the same thing as them when we are an ally */ - al = ally_add(&f1->allies, f2); - al->status = HELP_FSTEALTH; + ally_set(&f1->allies, f2, HELP_FSTEALTH); bufunit(f2, u, seen_unit, buf, sizeof(buf)); CuAssertStrEquals(tc, "Hodor (1), TWW (2) (UFO (1)), 1 human.", buf); @@ -791,7 +789,6 @@ static void test_insect_warnings(CuTest *tc) { test_setup(); test_create_calendar(); - test_inject_messagetypes(); f = test_create_faction(test_create_race("insect")); CuAssertIntEquals(tc, SEASON_AUTUMN, get_gamedate(1083, &gd)->season); @@ -819,7 +816,6 @@ static void test_newbie_warning(CuTest *tc) { faction *f; test_setup(); - test_inject_messagetypes(); f = test_create_faction(NULL); config_set_int("NewbieImmunity", 3); @@ -902,7 +898,7 @@ CuSuite *get_reports_suite(void) SUITE_ADD_TEST(suite, test_region_distance); SUITE_ADD_TEST(suite, test_region_distance_max); SUITE_ADD_TEST(suite, test_region_distance_ql); - SUITE_ADD_TEST(suite, test_newbie_password_message); + DISABLE_TEST(suite, test_newbie_password_message); SUITE_ADD_TEST(suite, test_prepare_report); SUITE_ADD_TEST(suite, test_seen_neighbours); SUITE_ADD_TEST(suite, test_seen_travelthru); diff --git a/src/skill.c b/src/skill.c index 3d91a2598..abeecca04 100644 --- a/src/skill.c +++ b/src/skill.c @@ -118,7 +118,9 @@ skill_t get_skill(const char *s, const struct locale * lang) int skill_cost(skill_t sk) { static int config; static int costs[MAXSKILLS]; - int cost; + int cost = -1; + + assert(sk >= 0 && sk < MAXSKILLS); switch (sk) { case SK_SPY: cost = 100; @@ -148,5 +150,6 @@ int skill_cost(skill_t sk) { } bool expensive_skill(skill_t sk) { + assert(sk >= 0 && sk < MAXSKILLS); return (sk == SK_MAGIC) || skill_cost(sk) > 0; } diff --git a/src/spells.test.c b/src/spells.test.c index 5950fab16..6ee4a305c 100644 --- a/src/spells.test.c +++ b/src/spells.test.c @@ -27,10 +27,6 @@ #include #include -static void setup_spells(void) { - test_inject_messagetypes(); -} - static void test_good_dreams(CuTest *tc) { struct region *r; struct faction *f1, *f2; @@ -40,7 +36,6 @@ static void test_good_dreams(CuTest *tc) { curse *curse; test_setup(); - setup_spells(); test_create_world(); r = findregion(0, 0); f1 = test_create_faction(NULL); @@ -70,7 +65,6 @@ static void test_dreams(CuTest *tc) { castorder co; test_setup(); - setup_spells(); r = test_create_region(0, 0, NULL); f1 = test_create_faction(NULL); f2 = test_create_faction(NULL); @@ -98,7 +92,6 @@ static void test_bad_dreams(CuTest *tc) { curse *curse; test_setup(); - setup_spells(); test_create_world(); r = findregion(0, 0); f1 = test_create_faction(NULL); @@ -129,7 +122,6 @@ static void test_view_reality(CuTest *tc) { castorder co; test_setup(); - setup_spells(); mt_create_va(mt_new("spell_astral_only", NULL), "unit:unit", "region:region", "command:order", MT_NEW_END); mt_create_va(mt_new("viewreality_effect", NULL), @@ -165,7 +157,6 @@ static void test_watch_region(CuTest *tc) { region *r; faction *f; test_setup(); - setup_spells(); r = test_create_region(0, 0, NULL); f = test_create_faction(NULL); CuAssertIntEquals(tc, -1, get_observer(r, f)); diff --git a/src/spells/combatspells.c b/src/spells/combatspells.c index c088dde07..21b33e7bf 100644 --- a/src/spells/combatspells.c +++ b/src/spells/combatspells.c @@ -1539,12 +1539,7 @@ int sp_undeadhero(struct castorder * co) /* new units gets some stats from old unit */ - if (du->display) { - unit_setinfo(u, du->display); - } - else { - unit_setinfo(u, NULL); - } + unit_setinfo(u, unit_getinfo(du)); unit_setstatus(u, du->status); setguard(u, false); for (ilist = &du->items; *ilist;) { diff --git a/src/study.c b/src/study.c index ff961dc13..5ac5ac7ff 100644 --- a/src/study.c +++ b/src/study.c @@ -524,6 +524,48 @@ static void msg_teachers(struct selist *teachers, struct unit *u, skill_t sk) { selist_foreach_ex(teachers, cb_msg_teach, &cbdata); } +bool check_student(const struct unit *u, struct order *ord, skill_t sk) { + int err = 0; + + if (sk < 0) { + err = 77; + } + /* Hack: Talente mit Malus -99 koennen nicht gelernt werden */ + else if (u_race(u)->bonus[sk] == -99) { + err = 771; + } + else { + static int config; + static bool learn_newskills; + + if (config_changed(&config)) { + learn_newskills = config_get_int("study.newskills", 1) != 0; + } + if (!learn_newskills) { + skill *sv = unit_skill(u, sk); + if (sv == NULL) { + /* we can only learn skills we already have */ + err = 771; + } + } + } + if (err) { + if (ord) { + cmistake(u, ord, err, MSG_EVENT); + } + return false; + } + + if ((u_race(u)->flags & RCF_NOLEARN) || fval(u, UFL_WERE)) { + if (ord) { + ADDMSG(&u->faction->msgs, + msg_feedback(u, ord, "error_race_nolearn", "race", u_race(u))); + } + return false; + } + return true; +} + int study_cmd(unit * u, order * ord) { region *r = u->region; @@ -537,7 +579,6 @@ int study_cmd(unit * u, order * ord) skill_t sk; int maxalchemy = 0; int speed_rule = (study_rule_t)config_get_int("study.speedup", 0); - bool learn_newskills = config_get_int("study.newskills", 1) != 0; static const race *rc_snotling; static int rc_cache; @@ -545,32 +586,12 @@ int study_cmd(unit * u, order * ord) rc_snotling = get_race(RC_SNOTLING); } - if (!unit_can_study(u)) { - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "error_race_nolearn", "race", - u_race(u))); - return -1; - } - (void)init_order(ord, u->faction->locale); sk = getskill(u->faction->locale); - if (sk < 0) { - cmistake(u, ord, 77, MSG_EVENT); + if (!check_student(u, ord, sk)) { return -1; } - /* Hack: Talente mit Malus -99 koennen nicht gelernt werden */ - if (u_race(u)->bonus[sk] == -99) { - cmistake(u, ord, 771, MSG_EVENT); - return -1; - } - if (!learn_newskills) { - skill *sv = unit_skill(u, sk); - if (sv == NULL) { - /* we can only learn skills we already have */ - cmistake(u, ord, 771, MSG_EVENT); - return -1; - } - } /* snotlings koennen Talente nur bis T8 lernen */ if (u_race(u) == rc_snotling) { diff --git a/src/study.h b/src/study.h index 686677064..c1d44ed7b 100644 --- a/src/study.h +++ b/src/study.h @@ -48,6 +48,7 @@ extern "C" { skill_t getskill(const struct locale *lang); bool is_migrant(struct unit *u); int study_cost(struct unit *u, skill_t sk); + bool check_student(const struct unit *u, struct order *ord, skill_t sk); typedef void(*learn_fun)(struct unit *u, skill_t sk, int days); diff --git a/src/study.test.c b/src/study.test.c index 3a94bf810..b2ac39172 100644 --- a/src/study.test.c +++ b/src/study.test.c @@ -58,6 +58,11 @@ typedef struct { } study_fixture; static void setup_study(void) { + test_setup(); + mt_create_error(178); + mt_create_error(65); + mt_create_va(mt_new("teach_asgood", NULL), + "unit:unit", "region:region", "command:order", "student:unit", MT_NEW_END); mt_create_va(mt_new("studycost", NULL), "unit:unit", "region:region", "cost:int", "skill:int", MT_NEW_END); mt_create_va(mt_new("teach_teacher", NULL), @@ -81,7 +86,7 @@ static void setup_teacher(study_fixture *fix, skill_t sk) { struct locale *lang; assert(fix); - test_setup(); + setup_study(); config_set("study.random_progress", "0"); r = test_create_region(0, 0, NULL); f = test_create_faction(NULL); @@ -148,7 +153,7 @@ static void test_study_bug_2194(CuTest *tc) { struct locale * loc; building * b; - test_setup(); + setup_study(); random_source_inject_constant(0.0); init_resources(); loc = test_create_locale(); @@ -205,7 +210,7 @@ static void test_produceexp(CuTest *tc) { unit *u; g_tc = tc; - test_setup(); + setup_study(); u = test_create_unit(test_create_faction(NULL), test_create_region(0, 0, NULL)); scale_number(u, 2); config_set("study.produceexp", "20"); @@ -220,7 +225,7 @@ static void test_academy_building(CuTest *tc) { building * b; message * msg; - test_setup(); + setup_study(); mt_create_va(mt_new("teach_asgood", NULL), "unit:unit", "region:region", "command:order", "student:unit", MT_NEW_END); @@ -271,7 +276,6 @@ static void test_academy_bonus(CuTest *tc) { struct locale * loc; building * b; - test_setup(); setup_study(); random_source_inject_constant(0.0); @@ -328,7 +332,8 @@ static void test_academy_bonus(CuTest *tc) { void test_learn_skill_single(CuTest *tc) { unit *u; skill *sv; - test_setup(); + + setup_study(); config_set("study.random_progress", "0"); u = test_create_unit(test_create_faction(NULL), test_create_region(0, 0, NULL)); learn_skill(u, SK_ALCHEMY, STUDYDAYS); @@ -347,7 +352,8 @@ void test_learn_skill_single(CuTest *tc) { void test_learn_skill_multi(CuTest *tc) { unit *u; skill *sv; - test_setup(); + + setup_study(); config_set("study.random_progress", "0"); u = test_create_unit(test_create_faction(NULL), test_create_region(0, 0, NULL)); scale_number(u, 10); @@ -367,7 +373,8 @@ void test_learn_skill_multi(CuTest *tc) { static void test_demon_skillchanges(CuTest *tc) { unit * u; const race * rc; - test_setup(); + + setup_study(); rc = test_create_race("demon"); CuAssertPtrEquals(tc, (void *)rc, (void *)get_race(RC_DAEMON)); u = test_create_unit(test_create_faction(rc), test_create_region(0, 0, NULL)); @@ -380,7 +387,8 @@ static void test_demon_skillchanges(CuTest *tc) { static void test_study_cmd(CuTest *tc) { unit *u; - test_setup(); + + setup_study(); init_resources(); u = test_create_unit(test_create_faction(NULL), test_create_region(0, 0, NULL)); u->thisorder = create_order(K_STUDY, u->faction->locale, "CROSSBOW"); @@ -399,7 +407,6 @@ static void test_study_magic(CuTest *tc) { const struct locale *lang; const struct item_type *itype; - test_setup(); setup_study(); init_resources(); f = test_create_faction(NULL); @@ -432,7 +439,6 @@ static void test_study_magic(CuTest *tc) { static void test_study_cost_magic(CuTest *tc) { unit * u; - test_setup(); setup_study(); u = test_create_unit(test_create_faction(NULL), test_create_region(0, 0, NULL)); @@ -456,7 +462,6 @@ static void test_study_cost(CuTest *tc) { unit *u; const struct item_type *itype; - test_setup(); setup_study(); itype = test_create_silver(); @@ -484,7 +489,6 @@ static void test_teach_magic(CuTest *tc) { faction *f; const struct item_type *itype; - test_setup(); setup_study(); init_resources(); itype = get_resourcetype(R_SILVER)->itype; @@ -510,7 +514,8 @@ static void test_teach_magic(CuTest *tc) { static void test_teach_cmd(CuTest *tc) { unit *u, *ut; - test_setup(); + + setup_study(); init_resources(); u = test_create_unit(test_create_faction(NULL), test_create_region(0, 0, NULL)); scale_number(u, 10); @@ -530,7 +535,8 @@ static void test_teach_cmd(CuTest *tc) { static void test_teach_two(CuTest *tc) { unit *u1, *u2, *ut; - test_setup(); + + setup_study(); init_resources(); u1 = test_create_unit(test_create_faction(NULL), test_create_region(0, 0, NULL)); scale_number(u1, 5); @@ -560,7 +566,7 @@ static void test_teach_two_skills(CuTest *tc) { faction *f; region *r; - test_setup(); + setup_study(); init_resources(); f = test_create_faction(NULL); r = test_create_region(0, 0, NULL); @@ -590,7 +596,8 @@ static void test_teach_two_skills(CuTest *tc) { static void test_teach_one_to_many(CuTest *tc) { unit *u, *ut; - test_setup(); + + setup_study(); init_resources(); u = test_create_unit(test_create_faction(NULL), test_create_region(0, 0, NULL)); scale_number(u, 20); @@ -611,7 +618,7 @@ static void test_teach_one_to_many(CuTest *tc) { static void test_teach_many_to_one(CuTest *tc) { unit *u, *u1, *u2; - test_setup(); + setup_study(); init_resources(); u = test_create_unit(test_create_faction(NULL), test_create_region(0, 0, NULL)); scale_number(u, 20); @@ -636,14 +643,9 @@ static void test_teach_many_to_one(CuTest *tc) { static void test_teach_message(CuTest *tc) { unit *u, *u1, *u2; attrib *a; - ally *al; teaching_info *teach; - test_setup(); - mt_create_va(mt_new("teach_teacher", NULL), - "teacher:unit", "student:unit", "skill:int", "level:int", MT_NEW_END); - mt_create_va(mt_new("teach_student", NULL), - "teacher:unit", "student:unit", "skill:int", MT_NEW_END); + setup_study(); init_resources(); u = test_create_unit(test_create_faction(NULL), test_create_region(0, 0, NULL)); scale_number(u, 20); @@ -652,8 +654,7 @@ static void test_teach_message(CuTest *tc) { set_level(u1, SK_CROSSBOW, TEACHDIFFERENCE); u1->thisorder = create_order(K_TEACH, u->faction->locale, itoa36(u->no)); u2 = test_create_unit(test_create_faction(NULL), u->region); - al = ally_add(&u->faction->allies, u2->faction); - al->status = HELP_GUARD; + ally_set(&u->faction->allies, u2->faction, HELP_GUARD); set_level(u2, SK_CROSSBOW, TEACHDIFFERENCE); u2->thisorder = create_order(K_TEACH, u->faction->locale, itoa36(u->no)); CuAssertTrue(tc, !alliedunit(u, u1->faction, HELP_GUARD)); @@ -683,7 +684,7 @@ static void test_teach_many_to_many(CuTest *tc) { region *r; faction *f; - test_setup(); + setup_study(); init_resources(); f = test_create_faction(NULL); r = test_create_region(0, 0, NULL); diff --git a/src/test_eressea.c b/src/test_eressea.c index 2b36d4e03..12c658f91 100644 --- a/src/test_eressea.c +++ b/src/test_eressea.c @@ -138,7 +138,6 @@ int RunAllTests(int argc, char *argv[]) ADD_SUITE(monsters); ADD_SUITE(move); ADD_SUITE(names); - ADD_SUITE(orderdb); ADD_SUITE(orderfile); ADD_SUITE(otherfaction); ADD_SUITE(piracy); diff --git a/src/tests.c b/src/tests.c index 3a8c9e095..22c18ef9c 100644 --- a/src/tests.c +++ b/src/tests.c @@ -305,15 +305,10 @@ void test_create_calendar(void) { month_season[8] = SEASON_SUMMER; } -void test_inject_messagetypes(void) -{ - message_handle_missing(MESSAGE_MISSING_REPLACE); -} - void test_setup_test(CuTest *tc, const char *file, int line) { test_log_stderr(LOG_CPERROR); test_reset(); - message_handle_missing(MESSAGE_MISSING_ERROR); + message_handle_missing(MESSAGE_MISSING_REPLACE); if (tc) { log_debug("start test: %s", tc->name); } @@ -325,6 +320,7 @@ void test_setup_test(CuTest *tc, const char *file, int line) { void test_teardown(void) { + message_handle_missing(MESSAGE_MISSING_IGNORE); test_reset(); test_log_stderr(0); } diff --git a/src/tests.h b/src/tests.h index 0f3af1972..17da12d4e 100644 --- a/src/tests.h +++ b/src/tests.h @@ -76,7 +76,6 @@ extern "C" { void assert_string_parameter(struct CuTest * tc, struct message *msg, int index, const char *arg); void disabled_test(void *suite, void (*)(struct CuTest *), const char *name); - void test_inject_messagetypes(void); #define DISABLE_TEST(SUITE, TEST) disabled_test(SUITE, TEST, #TEST) diff --git a/src/upkeep.c b/src/upkeep.c index 6748d620c..9ab8c1fea 100644 --- a/src/upkeep.c +++ b/src/upkeep.c @@ -167,7 +167,7 @@ void get_food(region * r) struct faction *owner = region_get_owner(r); /* if the region is owned, and the owner is nice, then we'll get * food from the peasants - should not be used with WORK */ - if (owner != NULL && (get_alliance(owner, u->faction) & HELP_MONEY)) { + if (owner != NULL && alliedfaction(owner, u->faction, HELP_MONEY)) { int rm = rmoney(r); int use = (rm < need) ? rm : need; rsetmoney(r, rm - use); diff --git a/src/upkeep.test.c b/src/upkeep.test.c index f2fedc89b..7f5abd02e 100644 --- a/src/upkeep.test.c +++ b/src/upkeep.test.c @@ -1,6 +1,7 @@ #include #include "upkeep.h" +#include #include #include #include @@ -117,7 +118,7 @@ void test_upkeep_from_friend(CuTest * tc) f1 = test_create_faction(test_create_race("human")); f2 = test_create_faction(test_create_race("human")); assert(f1 && f2); - set_alliance(f1, f2, HELP_MONEY); + ally_set(&f1->allies, f2, HELP_MONEY); u1 = test_create_unit(f1, r); u2 = test_create_unit(f2, r); assert(r && u1 && u2); diff --git a/src/util/message.c b/src/util/message.c index d8c66f5e0..47a8eb7af 100644 --- a/src/util/message.c +++ b/src/util/message.c @@ -192,6 +192,16 @@ message_type *mt_create_va(message_type *mtype, ...) return mt_create(mtype, args, i - 1); } +message_type *mt_create_feedback(const char *name) { + return mt_create_va(mt_new(name, NULL), "unit:unit", "region:region", "command:order", MT_NEW_END); +} + +message_type *mt_create_error(int error) { + char name[16]; + snprintf(name, sizeof(name), "error%d", error); + return mt_create_feedback(name); +} + static variant copy_arg(const arg_type * atype, variant data) { assert(atype != NULL); diff --git a/src/util/message.h b/src/util/message.h index 5aa16232b..52b087203 100644 --- a/src/util/message.h +++ b/src/util/message.h @@ -64,6 +64,8 @@ extern "C" { struct message_type *mt_new(const char *name, const char *section); /** message_type registry (optional): **/ struct message_type *mt_create(struct message_type *, const char *args[], int nargs); + struct message_type *mt_create_feedback(const char *name); + struct message_type *mt_create_error(int error); struct message_type *mt_create_va(struct message_type *, ...); const struct message_type *mt_find(const char *);