Merge pull request #725 from ennorehling/develop

Bugfixes for 3.14 release
This commit is contained in:
Enno Rehling 2017-09-01 22:23:48 +02:00 committed by GitHub
commit 5f518ae4f0
28 changed files with 175 additions and 178 deletions

View File

@ -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,

View File

@ -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",

View File

@ -4990,12 +4990,12 @@
<string name="sacrifice_strength">
<text locale="de">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.</text>
Auf einen Magier des selben Magiegebietes kann er die Hälfte der
eingesetzten Kraft übertragen, auf andere Magier ein Drittel.</text>
<text locale="en">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.</text>
his magical powers to another magician. Magicians of the seam school
will receive half the power invested, magicians of other schoolsreceive
receive one third.</text>
</string>
<string name="eternal_walls">
<text locale="de">Mit dieser Formel bindet der Magier auf ewig die

View File

@ -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:

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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" }

View File

@ -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

View File

@ -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 = {

View File

@ -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)

View File

@ -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;

View File

@ -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);
}

View File

@ -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 <kernel/config.h>
#include <util/log.h>
@ -25,16 +36,6 @@
#include <util/message.h>
#include <races/races.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 "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();
}

View File

@ -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);

View File

@ -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;

View File

@ -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

View File

@ -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;
}

View File

@ -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 */

View File

@ -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;

View File

@ -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;
}

View File

@ -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);

View File

@ -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

View File

@ -1,6 +1,7 @@
#include <platform.h>
#include "borders.h"
#include "vortex.h"
#include <kernel/connection.h>
#include <kernel/curse.h>
@ -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);

View File

@ -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
}

View File

@ -4,6 +4,7 @@
#include "prefix.h"
#include "reports.h"
#include "calendar.h"
#include "vortex.h"
#include <kernel/config.h>
#include <kernel/alliance.h>
@ -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();

View File

@ -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);

View File

@ -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,