diff --git a/conf/e2/config.json b/conf/e2/config.json index b8ca2f178..0c85b316b 100644 --- a/conf/e2/config.json +++ b/conf/e2/config.json @@ -27,7 +27,7 @@ "rules.reserve.twophase": true, "rules.give.max_men": -1, "rules.check_overload": false, - "rules.limit.faction": 3000, + "rules.limit.faction": 2500, "rules.maxskills.magic": 5, "rules.guard.base_stop_prob": 0.30, "rules.guard.skill_stop_prob": 0.05, diff --git a/conf/e3/config.json b/conf/e3/config.json index 3305ce221..b70d415a7 100644 --- a/conf/e3/config.json +++ b/conf/e3/config.json @@ -88,7 +88,7 @@ "rules.economy.herbrot": 0, "rules.region_owner_pay_building": "market harbour lighthouse", "rules.dwarf_castles": true, - "rules.limit.faction": 500, + "rules.limit.faction": 250, "rules.grow.formula": 1, "rules.tactics.formula": 1, "rules.help.mask": "fight guard money give", diff --git a/res/core/de/strings.xml b/res/core/de/strings.xml index c26bfe03b..ea4acf758 100644 --- a/res/core/de/strings.xml +++ b/res/core/de/strings.xml @@ -4990,12 +4990,12 @@ Mit Hilfe dieses Zaubers kann der Magier einen Teil seiner magischen Kraft permanent auf einen anderen Magier übertragen. - Auf einen Tybied-Magier kann er die Hälfte der eingesetzten Kraft - übertragen, auf einen Magier eines anderen Gebietes ein Drittel. + Auf einen Magier des selben Magiegebietes kann er die Hälfte der + eingesetzten Kraft übertragen, auf andere Magier ein Drittel. This spell allows the magician to transfer part of - his magical powers to another magician. Tybied magicians will receive - half the power invested, magicians of another school will receive one - third. + his magical powers to another magician. Magicians of the seam school + will receive half the power invested, magicians of other schoolsreceive + receive one third. Mit dieser Formel bindet der Magier auf ewig die diff --git a/scripts/eressea/autoseed.lua b/scripts/eressea/autoseed.lua index 2896708f8..10a33627f 100644 --- a/scripts/eressea/autoseed.lua +++ b/scripts/eressea/autoseed.lua @@ -1,4 +1,4 @@ -if not config.autoseed then return nil end +if not config.autoseed or config.autoseed==0 then return nil end local autoseed = {} -- minimum required resources in the 7-hex neighborhood: diff --git a/scripts/eressea/embassy.lua b/scripts/eressea/embassy.lua index 93ff66d7c..00b50b482 100644 --- a/scripts/eressea/embassy.lua +++ b/scripts/eressea/embassy.lua @@ -1,6 +1,6 @@ -- Muschelplateau -if not config.embassy then return nil end +if not config.embassy or config.embassy==0 then return nil end local embassy = {} local home = nil diff --git a/scripts/eressea/eternath.lua b/scripts/eressea/eternath.lua index 063577b74..208af0c8b 100644 --- a/scripts/eressea/eternath.lua +++ b/scripts/eressea/eternath.lua @@ -1,5 +1,5 @@ -- DEPRECATED -if not config.eternath then return nil end +if not config.eternath or config.eternath==0 then return nil end -- implements parts of a quest in E2 -- this module is deprecated, because it puts functions in the global environment for at_building_action diff --git a/scripts/eressea/modules.lua b/scripts/eressea/modules.lua new file mode 100644 index 000000000..6a93362cb --- /dev/null +++ b/scripts/eressea/modules.lua @@ -0,0 +1,21 @@ +local modules = {} + +function add_module(pkg) + table.insert(modules, pkg) +end + +local pkg = {} + +function pkg.init() + for k, v in ipairs(modules) do + if v.init then v.init() end + end +end + +function pkg.update() + for k, v in ipairs(modules) do + if v.update then v.update() end + end +end + +return pkg diff --git a/scripts/eressea/ponnuki.lua b/scripts/eressea/ponnuki.lua index b5ba58fbe..3ead8c57c 100644 --- a/scripts/eressea/ponnuki.lua +++ b/scripts/eressea/ponnuki.lua @@ -1,4 +1,4 @@ -if not config.ponnuki then return nil end +if not config.ponnuki or config.ponnuki==0 then return nil end local ponnuki = {} local directions = { "NW", "NO", "O", "SO", "SW", "W" } diff --git a/scripts/eressea/wedding.lua b/scripts/eressea/wedding.lua index 2c06d9891..71664eec9 100644 --- a/scripts/eressea/wedding.lua +++ b/scripts/eressea/wedding.lua @@ -1,5 +1,5 @@ -- DEPRECATED -if not config.wedding then return nil end +if not config.wedding or config.wedding==0 then return nil end -- this script contains the action functions for the two portals -- used on the jadee/wildente wedding island. the two _action functions diff --git a/scripts/eressea/xmas.lua b/scripts/eressea/xmas.lua index 0316e6265..b728c9976 100644 --- a/scripts/eressea/xmas.lua +++ b/scripts/eressea/xmas.lua @@ -1,4 +1,4 @@ -if not config.xmas then return nil end +if not config.xmas or config.xmas==0 then return nil end local gifts = { e2 = { diff --git a/scripts/tests/economy.lua b/scripts/tests/economy.lua index a1bfa3bb6..9289efa2b 100644 --- a/scripts/tests/economy.lua +++ b/scripts/tests/economy.lua @@ -11,6 +11,23 @@ function setup() eressea.settings.set("rules.encounters", "0") end +function test_bug_2361_forget_magic() + -- https://bugs.eressea.de/view.php?id=2361 + -- familiars cannot forget magic + local r = region.create(0, 0, "plain") + local f = faction.create("human") + local u = unit.create(f, r, 1) + u:clear_orders() + u:add_order("VERGESSE Magie") + u:set_skill('magic', 5) + u.race = 'unicorn' + process_orders() + assert_equal(5, u:get_skill('magic')) + u.race = 'human' + process_orders() + assert_equal(0, u:get_skill('magic')) +end + function test_mine_bonus() local r = region.create(0, 0, "mountain") r:set_resource("iron", 100) diff --git a/src/creport.c b/src/creport.c index 57ba12ee0..14f2a6c56 100644 --- a/src/creport.c +++ b/src/creport.c @@ -254,7 +254,7 @@ cr_output_curses(struct stream *out, const faction * viewer, const void *obj, ob } while (a) { - if (fval(a->type, ATF_CURSE)) { + if (a->type == &at_curse) { curse *c = (curse *)a->data.v; message *msg; diff --git a/src/economy.c b/src/economy.c index 4122fa6a1..546f7876e 100644 --- a/src/economy.c +++ b/src/economy.c @@ -661,7 +661,12 @@ static int forget_cmd(unit * u, order * ord) init_order(ord); s = gettoken(token, sizeof(token)); - if ((sk = get_skill(s, u->faction->locale)) != NOSKILL) { + sk = get_skill(s, u->faction->locale); + if (sk != NOSKILL) { + if (sk == SK_MAGIC && (u_race(u)->flags & RCF_FAMILIAR)) { + /* some races cannot forget their innate magical abilities */ + return 0; + } ADDMSG(&u->faction->msgs, msg_message("forget", "unit skill", u, sk)); set_level(u, sk, 0); } diff --git a/src/eressea.c b/src/eressea.c index a9dddd130..2174450eb 100755 --- a/src/eressea.c +++ b/src/eressea.c @@ -2,6 +2,17 @@ #include "settings.h" #include "eressea.h" +#include "calendar.h" +#include "chaos.h" +#include "items.h" +#include "creport.h" +#include "report.h" +#include "names.h" +#include "reports.h" +#include "spells.h" +#include "vortex.h" +#include "wormhole.h" + #include #include @@ -25,16 +36,6 @@ #include #include -#include "calendar.h" -#include "chaos.h" -#include "items.h" -#include "creport.h" -#include "report.h" -#include "names.h" -#include "reports.h" -#include "spells.h" -#include "wormhole.h" - void game_done(void) { #ifdef CLEANUP_CODE @@ -53,6 +54,7 @@ void game_done(void) calendar_cleanup(); free_functions(); free_config(); + free_special_directions(); free_locales(); kernel_done(); } diff --git a/src/items.c b/src/items.c index dd4abe1ac..8190693b0 100644 --- a/src/items.c +++ b/src/items.c @@ -145,7 +145,7 @@ struct order *ord) while (*ap && force > 0) { curse *c; attrib *a = *ap; - if (!(a->type->flags & ATF_CURSE)) { + if (a->type != &at_curse) { do { ap = &(*ap)->next; } while (*ap && a->type == (*ap)->type); diff --git a/src/kernel/curse.c b/src/kernel/curse.c index b0367484d..9702d7649 100644 --- a/src/kernel/curse.c +++ b/src/kernel/curse.c @@ -273,8 +273,7 @@ attrib_type at_curse = { curse_age, curse_write, curse_read, - NULL, - ATF_CURSE + NULL }; /* ------------------------------------------------------------- */ @@ -363,7 +362,7 @@ void ct_checknames(void) { static bool cmp_curse(const attrib * a, const void *data) { const curse *c = (const curse *)data; - if (a->type->flags & ATF_CURSE) { + if (a->type == &at_curse) { if (!data || c == (curse *)a->data.v) return true; } @@ -375,7 +374,7 @@ curse *get_curse(attrib * ap, const curse_type * ctype) attrib *a = ap; if (!ctype) return NULL; while (a) { - if (a->type->flags & ATF_CURSE) { + if (a->type == &at_curse) { const attrib_type *at = a->type; while (a && a->type == at) { curse *c = (curse *)a->data.v; @@ -710,7 +709,7 @@ bool is_cursed_with(const attrib * ap, const curse * c) const attrib *a = ap; while (a) { - if ((a->type->flags & ATF_CURSE) && (c == (const curse *)a->data.v)) { + if ((a->type == &at_curse) && (c == (const curse *)a->data.v)) { return true; } a = a->next; diff --git a/src/kernel/curse.h b/src/kernel/curse.h index 9b6113d96..054387d59 100644 --- a/src/kernel/curse.h +++ b/src/kernel/curse.h @@ -311,9 +311,6 @@ extern "C" { #define get_curseeffect(a, ctype) \ curse_geteffect(get_curse(a, ctype)) - /* eressea-defined attribute-type flags */ -#define ATF_CURSE ATF_USER_DEFINED - #ifdef __cplusplus } #endif diff --git a/src/kernel/region.c b/src/kernel/region.c index 7e6104406..e8da83c50 100644 --- a/src/kernel/region.c +++ b/src/kernel/region.c @@ -745,11 +745,17 @@ int rtrees(const region * r, int ageclass) int rsettrees(const region * r, int ageclass, int value) { - if (!r->land) + if (!r->land) { assert(value == 0); + } else { assert(value >= 0); - return r->land->trees[ageclass] = value; + if (value <= MAXTREES) { + return r->land->trees[ageclass] = value; + } + else { + r->land->trees[ageclass] = MAXTREES; + } } return 0; } diff --git a/src/kernel/region.h b/src/kernel/region.h index 5117567a6..c81411468 100644 --- a/src/kernel/region.h +++ b/src/kernel/region.h @@ -26,6 +26,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #define MAXLUXURIES 16 /* there must be no more than MAXLUXURIES kinds of luxury goods in any game */ #define MAXREGIONS 524287 /* must be prime for hashing. 262139 was a little small */ +#define MAXTREES 100 * 1000 * 1000 /* bug 2360: some players are crazy */ /* FAST_CONNECT: regions are directly connected to neighbours, saves doing a hash-access each time a neighbour is needed, 6 extra pointers per hex */ diff --git a/src/kernel/region.test.c b/src/kernel/region.test.c index 879faad50..8f16842c4 100644 --- a/src/kernel/region.test.c +++ b/src/kernel/region.test.c @@ -78,10 +78,29 @@ static void test_region_getset_resource(CuTest *tc) { test_cleanup(); } +static void test_trees(CuTest *tc) { + region *r; + + test_setup(); + r = test_create_region(0, 0, NULL); + rsettrees(r, 0, 1000); + rsettrees(r, 1, 2000); + rsettrees(r, 2, 3000); + CuAssertIntEquals(tc, 1000, rtrees(r, 0)); + CuAssertIntEquals(tc, 2000, rtrees(r, 1)); + CuAssertIntEquals(tc, 3000, rtrees(r, 2)); + rsettrees(r, 0, MAXTREES); + CuAssertIntEquals(tc, MAXTREES, rtrees(r, 0)); + rsettrees(r, 0, MAXTREES+100); + CuAssertIntEquals(tc, MAXTREES, rtrees(r, 0)); + test_cleanup(); +} + CuSuite *get_region_suite(void) { CuSuite *suite = CuSuiteNew(); SUITE_ADD_TEST(suite, test_terraform); + SUITE_ADD_TEST(suite, test_trees); SUITE_ADD_TEST(suite, test_region_getset_resource); SUITE_ADD_TEST(suite, test_region_get_owner); return suite; diff --git a/src/magic.c b/src/magic.c index 16ee37e60..7d33a28e1 100644 --- a/src/magic.c +++ b/src/magic.c @@ -329,8 +329,9 @@ sc_mage *get_mage(const unit * u) { if (has_skill(u, SK_MAGIC)) { attrib *a = a_find(u->attribs, &at_mage); - if (a) - return a->data.v; + if (a) { + return (sc_mage *)a->data.v; + } } return (sc_mage *)NULL; } diff --git a/src/report.c b/src/report.c index 2cafe3157..18d48b86b 100644 --- a/src/report.c +++ b/src/report.c @@ -568,7 +568,7 @@ nr_curses_i(struct stream *out, int indent, const faction *viewer, objtype_t typ char buf[4096]; message *msg = 0; - if (fval(a->type, ATF_CURSE)) { + if (a->type == &at_curse) { curse *c = (curse *)a->data.v; self = curse_cansee(c, viewer, typ, obj, self); diff --git a/src/spells.c b/src/spells.c index 31d75c6b3..c6860bebe 100644 --- a/src/spells.c +++ b/src/spells.c @@ -144,7 +144,7 @@ static void magicanalyse_region(region * r, unit * mage, double force) double probability; int mon; - if (!fval(a->type, ATF_CURSE)) + if (a->type != &at_curse) continue; /* ist der curse schwaecher als der Analysezauber, so ergibt sich @@ -184,7 +184,7 @@ static void magicanalyse_unit(unit * u, unit * mage, double force) curse *c; double probability; int mon; - if (!fval(a->type, ATF_CURSE)) + if (a->type != &at_curse) continue; c = (curse *)a->data.v; @@ -225,7 +225,7 @@ static void magicanalyse_building(building * b, unit * mage, double force) double probability; int mon; - if (!fval(a->type, ATF_CURSE)) + if (a->type != &at_curse) continue; c = (curse *)a->data.v; @@ -266,7 +266,7 @@ static void magicanalyse_ship(ship * sh, unit * mage, double force) curse *c; double probability; int mon; - if (!fval(a->type, ATF_CURSE)) + if (a->type != &at_curse) continue; c = (curse *)a->data.v; @@ -308,7 +308,7 @@ static int break_curse(attrib ** alist, int cast_level, double force, curse * c) while (*ap && force > 0) { curse *c1; attrib *a = *ap; - if (!fval(a->type, ATF_CURSE)) { + if (a->type != &at_curse) { do { ap = &(*ap)->next; } while (*ap && a->type == (*ap)->type); @@ -2970,7 +2970,7 @@ static int sp_deathcloud(castorder * co) unit *u; while (a) { - if ((a->type->flags & ATF_CURSE)) { + if (a->type == &at_curse) { curse *c = a->data.v; if (c->type == &ct_deathcloud) { report_failure(mage, co->order); @@ -3116,46 +3116,6 @@ static int sp_summonshadowlords(castorder * co) return cast_level; } -static bool chaosgate_valid(const connection * b) -{ - const attrib *a = a_find(b->from->attribs, &at_direction); - if (!a) - a = a_find(b->to->attribs, &at_direction); - if (!a) - return false; - return true; -} - -static struct region *chaosgate_move(const connection * b, struct unit *u, - struct region *from, struct region *to, bool routing) -{ - UNUSED_ARG(from); - UNUSED_ARG(b); - if (!routing) { - int maxhp = u->hp / 4; - if (maxhp < u->number) - maxhp = u->number; - u->hp = maxhp; - } - return to; -} - -border_type bt_chaosgate = { - "chaosgate", VAR_NONE, - b_transparent, /* transparent */ - NULL, /* init */ - NULL, /* destroy */ - NULL, /* read */ - NULL, /* write */ - b_blocknone, /* block */ - NULL, /* name */ - b_rinvisible, /* rvisible */ - b_finvisible, /* fvisible */ - b_uinvisible, /* uvisible */ - chaosgate_valid, - chaosgate_move -}; - /* ------------------------------------------------------------- */ /* Name: Chaossog * Stufe: 14 diff --git a/src/spells/borders.c b/src/spells/borders.c index 00019e92c..331e7380f 100644 --- a/src/spells/borders.c +++ b/src/spells/borders.c @@ -1,6 +1,7 @@ #include #include "borders.h" +#include "vortex.h" #include #include @@ -28,46 +29,15 @@ typedef struct wallcurse { connection *wall; } wallcurse; -static void cw_init(attrib * a) -{ - curse *c; - curse_init(a); - c = (curse *)a->data.v; - c->data.v = calloc(sizeof(wallcurse), 1); -} - -static void cw_write(const attrib * a, const void *target, storage * store) -{ - connection *b = ((wallcurse *)((curse *)a->data.v)->data.v)->wall; - curse_write(a, target, store); - WRITE_INT(store, b->id); -} - -typedef struct bresolve { - int id; - curse *self; -} bresolve; - -static int resolve_buddy(variant data, void *addr); - -static int cw_read(attrib * a, void *target, gamedata *data) +static int cw_read_depr(attrib * a, void *target, gamedata *data) { storage *store = data->store; - bresolve *br = calloc(sizeof(bresolve), 1); - curse *c = (curse *)a->data.v; - wallcurse *wc = (wallcurse *)c->data.v; - variant var; + curse_init(a); curse_read(a, store, target); - br->self = c; - READ_INT(store, &br->id); - - var.i = br->id; - ur_add(var, &wc->wall, resolve_borderid); - - var.v = br; - ur_add(var, &wc->buddy, resolve_buddy); - return AT_READ_OK; + curse_done(a); + READ_INT(store, NULL); + return AT_READ_DEPR; } /* ------------------------------------------------------------- */ @@ -105,61 +75,6 @@ const curse_type ct_firewall = { wall_vigour /* change_vigour */ }; -static attrib_type at_cursewall = { - "cursewall", - cw_init, - curse_done, - curse_age, - cw_write, - cw_read, - NULL, - ATF_CURSE -}; - -static int resolve_buddy(variant data, void *addr) -{ - curse *result = NULL; - bresolve *br = (bresolve *)data.v; - connection *b; - - assert(br->id > 0); - b = find_border(br->id); - - if (b && b->from && b->to) { - attrib *a = a_find(b->from->attribs, &at_cursewall); - while (a && a->data.v != br->self) { - curse *c = (curse *)a->data.v; - wallcurse *wc = (wallcurse *)c->data.v; - if (wc->wall->id == br->id) - break; - a = a->next; - } - if (!a || a->type != &at_cursewall) { - a = a_find(b->to->attribs, &at_cursewall); - while (a && a->type == &at_cursewall && a->data.v != br->self) { - curse *c = (curse *)a->data.v; - wallcurse *wc = (wallcurse *)c->data.v; - if (wc->wall->id == br->id) - break; - a = a->next; - } - } - if (a && a->type == &at_cursewall) { - curse *c = (curse *)a->data.v; - free(br); - result = c; - } - } - else { - /* fail, object does not exist (but if you're still loading then - * you may want to try again later) */ - *(curse **)addr = NULL; - return -1; - } - *(curse **)addr = result; - return 0; -} - static void wall_init(connection * b) { wall_data *fd = (wall_data *)calloc(sizeof(wall_data), 1); @@ -284,10 +199,50 @@ border_type bt_wisps = { /* only here for reading old data */ 0 }; +static bool chaosgate_valid(const connection * b) +{ + const attrib *a = a_find(b->from->attribs, &at_direction); + if (!a) + a = a_find(b->to->attribs, &at_direction); + if (!a) + return false; + return true; +} + +static struct region *chaosgate_move(const connection * b, struct unit *u, + struct region *from, struct region *to, bool routing) +{ + UNUSED_ARG(from); + UNUSED_ARG(b); + if (!routing) { + int maxhp = u->hp / 4; + if (maxhp < u->number) + maxhp = u->number; + u->hp = maxhp; + } + return to; +} + +border_type bt_chaosgate = { + "chaosgate", VAR_NONE, + b_transparent, /* transparent */ + NULL, /* init */ + NULL, /* destroy */ + NULL, /* read */ + NULL, /* write */ + b_blocknone, /* block */ + NULL, /* name */ + b_rinvisible, /* rvisible */ + b_finvisible, /* fvisible */ + b_uinvisible, /* uvisible */ + chaosgate_valid, + chaosgate_move +}; + void register_borders(void) { border_convert_cb = &convert_firewall_timeouts; - at_register(&at_cursewall); + at_deprecate("cursewall", cw_read_depr); register_bordertype(&bt_firewall); register_bordertype(&bt_wisps); diff --git a/src/spells/borders.h b/src/spells/borders.h index b14661b9f..40bc55682 100644 --- a/src/spells/borders.h +++ b/src/spells/borders.h @@ -15,6 +15,7 @@ extern "C" { **/ extern struct border_type bt_chaosgate; extern struct border_type bt_firewall; + extern const struct curse_type ct_firewall; typedef struct wall_data { struct unit *mage; @@ -23,7 +24,6 @@ extern "C" { int countdown; } wall_data; - extern const struct curse_type ct_firewall; #ifdef __cplusplus } diff --git a/src/tests.c b/src/tests.c index cfcd6d0ca..49b5b7c05 100644 --- a/src/tests.c +++ b/src/tests.c @@ -4,6 +4,7 @@ #include "prefix.h" #include "reports.h" #include "calendar.h" +#include "vortex.h" #include #include @@ -209,6 +210,7 @@ static void test_reset(void) { default_locale = 0; calendar_cleanup(); close_orders(); + free_special_directions(); free_locales(); free_spells(); free_buildingtypes(); diff --git a/src/vortex.c b/src/vortex.c index 7b6206d03..773982124 100644 --- a/src/vortex.c +++ b/src/vortex.c @@ -26,6 +26,16 @@ typedef struct dir_lookup { static dir_lookup *dir_name_lookup; +void free_special_directions(void) +{ + while (dir_name_lookup) { + dir_lookup *dl = dir_name_lookup; + dir_name_lookup = dl->next; + free(dl->name); + free(dl); + } +} + void register_special_direction(struct locale *lang, const char *name) { const char *token = locale_string(lang, name, false); diff --git a/src/vortex.h b/src/vortex.h index 993f5cdab..ea7af624a 100644 --- a/src/vortex.h +++ b/src/vortex.h @@ -26,6 +26,8 @@ extern "C" { struct region *find_special_direction(const struct region *r, const char *token); void register_special_direction(struct locale *lang, const char *name); + void free_special_directions(void); + struct spec_direction *special_direction(const struct region * from, const struct region * to); struct attrib *create_special_direction(struct region *r, struct region *rt,