forked from github/server
Merge branch 'develop'
This commit is contained in:
commit
34808a25c5
|
@ -13,7 +13,12 @@
|
||||||
"game.id" : 2,
|
"game.id" : 2,
|
||||||
"orders.default": "work",
|
"orders.default": "work",
|
||||||
"NewbieImmunity": 8,
|
"NewbieImmunity": 8,
|
||||||
"modules.wormholes": true,
|
"modules.market": false,
|
||||||
|
"modules.astralspace": true,
|
||||||
|
"modules.wormhole": true,
|
||||||
|
"modules.iceberg": true,
|
||||||
|
"modules.volcano": true,
|
||||||
|
"monsters.spawn.chance": 50,
|
||||||
"entertain.base": 0,
|
"entertain.base": 0,
|
||||||
"entertain.perlevel": 20,
|
"entertain.perlevel": 20,
|
||||||
"taxing.perlevel": 20,
|
"taxing.perlevel": 20,
|
||||||
|
|
|
@ -32,8 +32,10 @@
|
||||||
"database.gameid": 7,
|
"database.gameid": 7,
|
||||||
"NewbieImmunity": 4,
|
"NewbieImmunity": 4,
|
||||||
"modules.astralspace": false,
|
"modules.astralspace": false,
|
||||||
"modules.wormholes": false,
|
"modules.wormhole": false,
|
||||||
"modules.markets": true,
|
"modules.market": true,
|
||||||
|
"modules.iceberg": false,
|
||||||
|
"modules.volcano": true,
|
||||||
"magic.regeneration": 0.75,
|
"magic.regeneration": 0.75,
|
||||||
"magic.power": 0.5,
|
"magic.power": 0.5,
|
||||||
"resource.factor": 0.25,
|
"resource.factor": 0.25,
|
||||||
|
|
|
@ -807,7 +807,6 @@ end
|
||||||
function test_swim_and_survive()
|
function test_swim_and_survive()
|
||||||
local r = region.create(0, 0, "plain")
|
local r = region.create(0, 0, "plain")
|
||||||
local f = create_faction('human')
|
local f = create_faction('human')
|
||||||
f.nam = "chaos"
|
|
||||||
local u = unit.create(f, r, 1)
|
local u = unit.create(f, r, 1)
|
||||||
process_orders()
|
process_orders()
|
||||||
r.terrain = "ocean"
|
r.terrain = "ocean"
|
||||||
|
|
|
@ -1141,7 +1141,7 @@ terminate(troop dt, troop at, int type, const char *damage, bool missile)
|
||||||
const weapon_type *dwtype = NULL;
|
const weapon_type *dwtype = NULL;
|
||||||
const weapon_type *awtype = NULL;
|
const weapon_type *awtype = NULL;
|
||||||
const weapon *weapon;
|
const weapon *weapon;
|
||||||
variant res = frac_make(1, 1);
|
variant res = frac_one;
|
||||||
|
|
||||||
int rda, sk = 0, sd;
|
int rda, sk = 0, sd;
|
||||||
bool magic = false;
|
bool magic = false;
|
||||||
|
@ -1185,6 +1185,7 @@ terminate(troop dt, troop at, int type, const char *damage, bool missile)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (magic) {
|
if (magic) {
|
||||||
|
res = frac_sub(frac_one, res);
|
||||||
res = frac_mul(frac_make(da, 1), res);
|
res = frac_mul(frac_make(da, 1), res);
|
||||||
da = res.sa[0] / res.sa[1];
|
da = res.sa[0] / res.sa[1];
|
||||||
}
|
}
|
||||||
|
|
|
@ -855,8 +855,6 @@ void cr_output_unit(stream *out, const region * r, const faction * f,
|
||||||
stream_printf(out, "\"%s\";Typ\n",
|
stream_printf(out, "\"%s\";Typ\n",
|
||||||
translate(zRace, LOC(lang, zRace)));
|
translate(zRace, LOC(lang, zRace)));
|
||||||
if (u->faction == f && irace != u_race(u)) {
|
if (u->faction == f && irace != u_race(u)) {
|
||||||
assert(skill_enabled(SK_STEALTH)
|
|
||||||
|| !"we're resetting this on load, so.. ircase should never be used");
|
|
||||||
zRace = rc_name_s(u_race(u), NAME_PLURAL);
|
zRace = rc_name_s(u_race(u), NAME_PLURAL);
|
||||||
stream_printf(out, "\"%s\";wahrerTyp\n",
|
stream_printf(out, "\"%s\";wahrerTyp\n",
|
||||||
translate(zRace, LOC(lang, zRace)));
|
translate(zRace, LOC(lang, zRace)));
|
||||||
|
|
|
@ -1446,25 +1446,20 @@ static void expandbuying(region * r, request * buyorders)
|
||||||
const resource_type *rsilver = get_resourcetype(R_SILVER);
|
const resource_type *rsilver = get_resourcetype(R_SILVER);
|
||||||
int max_products;
|
int max_products;
|
||||||
unit *u;
|
unit *u;
|
||||||
static struct trade {
|
struct trade {
|
||||||
const luxury_type *type;
|
const luxury_type *type;
|
||||||
int number;
|
int number;
|
||||||
int multi;
|
int multi;
|
||||||
} trades[MAXLUXURIES], *trade;
|
} trades[MAXLUXURIES], *trade;
|
||||||
static int ntrades = 0;
|
int ntrades = 0;
|
||||||
int i;
|
|
||||||
const luxury_type *ltype;
|
const luxury_type *ltype;
|
||||||
|
|
||||||
if (ntrades == 0) {
|
|
||||||
for (ntrades = 0, ltype = luxurytypes; ltype; ltype = ltype->next) {
|
for (ntrades = 0, ltype = luxurytypes; ltype; ltype = ltype->next) {
|
||||||
assert(ntrades < MAXLUXURIES);
|
assert(ntrades < MAXLUXURIES);
|
||||||
|
trades[ntrades].number = 0;
|
||||||
|
trades[ntrades].multi = 1;
|
||||||
trades[ntrades++].type = ltype;
|
trades[ntrades++].type = ltype;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
for (i = 0; i != ntrades; ++i) {
|
|
||||||
trades[i].number = 0;
|
|
||||||
trades[i].multi = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!buyorders)
|
if (!buyorders)
|
||||||
return;
|
return;
|
||||||
|
@ -1490,7 +1485,7 @@ static void expandbuying(region * r, request * buyorders)
|
||||||
int price, multi;
|
int price, multi;
|
||||||
ltype = g_requests[j].type.ltype;
|
ltype = g_requests[j].type.ltype;
|
||||||
trade = trades;
|
trade = trades;
|
||||||
while (trade->type != ltype)
|
while (trade->type && trade->type != ltype)
|
||||||
++trade;
|
++trade;
|
||||||
multi = trade->multi;
|
multi = trade->multi;
|
||||||
price = ltype->price * multi;
|
price = ltype->price * multi;
|
||||||
|
@ -1595,17 +1590,10 @@ static void buy(unit * u, request ** buyorders, struct order *ord)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (u_race(u) == get_race(RC_INSECT)) {
|
/* Entweder man ist Insekt in Sumpf/Wueste, oder es muss
|
||||||
/* entweder man ist insekt, oder... */
|
* einen Handelsposten in der Region geben: */
|
||||||
if (r->terrain != newterrain(T_SWAMP) && r->terrain != newterrain(T_DESERT)
|
if (u_race(u) != get_race(RC_INSECT) || (r->terrain == newterrain(T_SWAMP) || r->terrain == newterrain(T_DESERT))) {
|
||||||
&& !rbuildings(r)) {
|
building *b = NULL;
|
||||||
cmistake(u, ord, 119, MSG_COMMERCE);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
/* ...oder in der Region mu<6D> es eine Burg geben. */
|
|
||||||
building *b = 0;
|
|
||||||
if (r->buildings) {
|
if (r->buildings) {
|
||||||
static int cache;
|
static int cache;
|
||||||
static const struct building_type *bt_castle;
|
static const struct building_type *bt_castle;
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
#include <kernel/resources.h>
|
#include <kernel/resources.h>
|
||||||
#include <kernel/ship.h>
|
#include <kernel/ship.h>
|
||||||
#include <kernel/terrain.h>
|
#include <kernel/terrain.h>
|
||||||
|
#include <kernel/terrainid.h>
|
||||||
#include <kernel/unit.h>
|
#include <kernel/unit.h>
|
||||||
|
|
||||||
#include <util/attrib.h>
|
#include <util/attrib.h>
|
||||||
|
@ -170,6 +171,133 @@ static void test_normals_recruit(CuTest * tc) {
|
||||||
test_cleanup();
|
test_cleanup();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create any terrain types that are used by the trade rules.
|
||||||
|
*
|
||||||
|
* This should prevent newterrain from returning NULL.
|
||||||
|
*/
|
||||||
|
static void setup_terrains(CuTest *tc) {
|
||||||
|
test_create_terrain("plain", LAND_REGION | FOREST_REGION | WALK_INTO | CAVALRY_REGION | FLY_INTO);
|
||||||
|
test_create_terrain("ocean", SEA_REGION | SWIM_INTO | FLY_INTO);
|
||||||
|
test_create_terrain("swamp", LAND_REGION | WALK_INTO | FLY_INTO);
|
||||||
|
test_create_terrain("desert", LAND_REGION | WALK_INTO | FLY_INTO);
|
||||||
|
test_create_terrain("mountain", LAND_REGION | WALK_INTO | FLY_INTO);
|
||||||
|
init_terrains();
|
||||||
|
CuAssertPtrNotNull(tc, newterrain(T_MOUNTAIN));
|
||||||
|
CuAssertPtrNotNull(tc, newterrain(T_OCEAN));
|
||||||
|
CuAssertPtrNotNull(tc, newterrain(T_PLAIN));
|
||||||
|
CuAssertPtrNotNull(tc, newterrain(T_SWAMP));
|
||||||
|
CuAssertPtrNotNull(tc, newterrain(T_DESERT));
|
||||||
|
}
|
||||||
|
|
||||||
|
static region *setup_trade_region(CuTest *tc, const struct terrain_type *terrain) {
|
||||||
|
region *r;
|
||||||
|
item_type *it_luxury;
|
||||||
|
struct locale * lang = default_locale;
|
||||||
|
|
||||||
|
new_luxurytype(it_luxury = test_create_itemtype("jewel"), 5);
|
||||||
|
locale_setstring(lang, it_luxury->rtype->_name, it_luxury->rtype->_name);
|
||||||
|
CuAssertStrEquals(tc, it_luxury->rtype->_name, LOC(lang, resourcename(it_luxury->rtype, 0)));
|
||||||
|
|
||||||
|
new_luxurytype(it_luxury = test_create_itemtype("balm"), 5);
|
||||||
|
locale_setstring(lang, it_luxury->rtype->_name, it_luxury->rtype->_name);
|
||||||
|
CuAssertStrEquals(tc, it_luxury->rtype->_name, LOC(lang, resourcename(it_luxury->rtype, 0)));
|
||||||
|
|
||||||
|
r = test_create_region(0, 0, terrain);
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
static unit *setup_trade_unit(CuTest *tc, region *r, const struct race *rc) {
|
||||||
|
unit *u;
|
||||||
|
|
||||||
|
UNUSED_ARG(tc);
|
||||||
|
u = test_create_unit(test_create_faction(rc), r);
|
||||||
|
set_level(u, SK_TRADE, 2);
|
||||||
|
return u;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_trade_insect(CuTest *tc) {
|
||||||
|
/* Insekten können in Wüsten und Sümpfen auch ohne Burgen handeln. */
|
||||||
|
unit *u;
|
||||||
|
region *r;
|
||||||
|
const item_type *it_luxury;
|
||||||
|
const item_type *it_silver;
|
||||||
|
|
||||||
|
test_setup();
|
||||||
|
init_resources();
|
||||||
|
test_create_locale();
|
||||||
|
setup_terrains(tc);
|
||||||
|
r = setup_trade_region(tc, get_terrain("swamp"));
|
||||||
|
init_terrains();
|
||||||
|
|
||||||
|
it_luxury = r_luxury(r);
|
||||||
|
CuAssertPtrNotNull(tc, it_luxury);
|
||||||
|
it_silver = get_resourcetype(R_SILVER)->itype;
|
||||||
|
|
||||||
|
u = setup_trade_unit(tc, r, test_create_race("insect"));
|
||||||
|
unit_addorder(u, create_order(K_BUY, u->faction->locale, "1 %s",
|
||||||
|
LOC(u->faction->locale, resourcename(it_luxury->rtype, 0))));
|
||||||
|
|
||||||
|
set_item(u, it_silver, 10);
|
||||||
|
produce(u->region);
|
||||||
|
CuAssertIntEquals(tc, 1, get_item(u, it_luxury));
|
||||||
|
CuAssertIntEquals(tc, 5, get_item(u, it_silver));
|
||||||
|
|
||||||
|
terraform_region(r, get_terrain("swamp"));
|
||||||
|
test_cleanup();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_buy_cmd(CuTest *tc) {
|
||||||
|
region * r;
|
||||||
|
unit *u;
|
||||||
|
building *b;
|
||||||
|
const resource_type *rt_silver;
|
||||||
|
const item_type *it_luxury;
|
||||||
|
test_setup();
|
||||||
|
init_resources();
|
||||||
|
test_create_locale();
|
||||||
|
setup_terrains(tc);
|
||||||
|
r = setup_trade_region(tc, test_create_terrain("swamp", LAND_REGION));
|
||||||
|
init_terrains();
|
||||||
|
|
||||||
|
it_luxury = r_luxury(r);
|
||||||
|
CuAssertPtrNotNull(tc, it_luxury);
|
||||||
|
rt_silver = get_resourcetype(R_SILVER);
|
||||||
|
CuAssertPtrNotNull(tc, rt_silver);
|
||||||
|
CuAssertPtrNotNull(tc, rt_silver->itype);
|
||||||
|
|
||||||
|
u = test_create_unit(test_create_faction(NULL), r);
|
||||||
|
unit_addorder(u, create_order(K_BUY, u->faction->locale, "1 %s", LOC(u->faction->locale, resourcename(it_luxury->rtype, 0))));
|
||||||
|
set_item(u, rt_silver->itype, 1000);
|
||||||
|
|
||||||
|
produce(r);
|
||||||
|
CuAssertPtrNotNullMsg(tc, "trading requires a castle", test_find_messagetype(u->faction->msgs, "error119"));
|
||||||
|
test_clear_messages(u->faction);
|
||||||
|
freset(u, UFL_LONGACTION);
|
||||||
|
|
||||||
|
b = test_create_building(r, test_create_buildingtype("castle"));
|
||||||
|
produce(r);
|
||||||
|
CuAssertPtrNotNullMsg(tc, "castle must have size >=2", test_find_messagetype(u->faction->msgs, "error119"));
|
||||||
|
test_clear_messages(u->faction);
|
||||||
|
freset(u, UFL_LONGACTION);
|
||||||
|
|
||||||
|
b->size = 2;
|
||||||
|
produce(r);
|
||||||
|
CuAssertPtrEquals(tc, NULL, test_find_messagetype(u->faction->msgs, "error119"));
|
||||||
|
CuAssertPtrNotNullMsg(tc, "traders need SK_TRADE skill", test_find_messagetype(u->faction->msgs, "error102"));
|
||||||
|
test_clear_messages(u->faction);
|
||||||
|
freset(u, UFL_LONGACTION);
|
||||||
|
|
||||||
|
/* at last, the happy case: */
|
||||||
|
set_level(u, SK_TRADE, 1);
|
||||||
|
produce(r);
|
||||||
|
CuAssertPtrNotNull(tc, test_find_messagetype(u->faction->msgs, "buy"));
|
||||||
|
CuAssertPtrNotNull(tc, test_find_messagetype(u->faction->msgs, "buyamount"));
|
||||||
|
CuAssertIntEquals(tc, 1, get_item(u, it_luxury));
|
||||||
|
CuAssertIntEquals(tc, 995, get_item(u, rt_silver->itype));
|
||||||
|
test_cleanup();
|
||||||
|
}
|
||||||
|
|
||||||
typedef struct request {
|
typedef struct request {
|
||||||
struct request *next;
|
struct request *next;
|
||||||
struct unit *unit;
|
struct unit *unit;
|
||||||
|
@ -568,6 +696,8 @@ CuSuite *get_economy_suite(void)
|
||||||
SUITE_ADD_TEST(suite, test_normals_recruit);
|
SUITE_ADD_TEST(suite, test_normals_recruit);
|
||||||
SUITE_ADD_TEST(suite, test_heroes_dont_recruit);
|
SUITE_ADD_TEST(suite, test_heroes_dont_recruit);
|
||||||
SUITE_ADD_TEST(suite, test_tax_cmd);
|
SUITE_ADD_TEST(suite, test_tax_cmd);
|
||||||
|
SUITE_ADD_TEST(suite, test_buy_cmd);
|
||||||
|
SUITE_ADD_TEST(suite, test_trade_insect);
|
||||||
SUITE_ADD_TEST(suite, test_maintain_buildings);
|
SUITE_ADD_TEST(suite, test_maintain_buildings);
|
||||||
SUITE_ADD_TEST(suite, test_recruit);
|
SUITE_ADD_TEST(suite, test_recruit);
|
||||||
return suite;
|
return suite;
|
||||||
|
|
|
@ -76,7 +76,7 @@ int *casualties)
|
||||||
killed += terminate(dt, *at, AT_SPELL, damage, 1);
|
killed += terminate(dt, *at, AT_SPELL, damage, 1);
|
||||||
}
|
}
|
||||||
} while (force && killed < enemies);
|
} while (force && killed < enemies);
|
||||||
if (casualties)
|
if (killed > 0 && casualties)
|
||||||
*casualties = killed;
|
*casualties = killed;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -216,7 +216,6 @@ static void test_alliance_cmd_transfer(CuTest *tc) {
|
||||||
test_cleanup();
|
test_cleanup();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
CuSuite *get_alliance_suite(void)
|
CuSuite *get_alliance_suite(void)
|
||||||
{
|
{
|
||||||
CuSuite *suite = CuSuiteNew();
|
CuSuite *suite = CuSuiteNew();
|
||||||
|
|
|
@ -405,7 +405,7 @@ static int required(int size, int msize, int maxneed)
|
||||||
static int matmod(const unit * u, const resource_type * rtype, int value)
|
static int matmod(const unit * u, const resource_type * rtype, int value)
|
||||||
{
|
{
|
||||||
if (rtype->modifiers) {
|
if (rtype->modifiers) {
|
||||||
variant save = frac_make(1, 1);
|
variant save = frac_one;
|
||||||
const struct building_type *btype = NULL;
|
const struct building_type *btype = NULL;
|
||||||
const struct race *rc = u_race(u);
|
const struct race *rc = u_race(u);
|
||||||
resource_mod *mod;
|
resource_mod *mod;
|
||||||
|
|
|
@ -224,7 +224,7 @@ extern "C" {
|
||||||
|
|
||||||
/* convenience: */
|
/* convenience: */
|
||||||
item *i_change(item ** items, const item_type * it, int delta);
|
item *i_change(item ** items, const item_type * it, int delta);
|
||||||
int i_get(const item * i, const item_type * it);
|
int i_get(const item * items, const item_type * it);
|
||||||
|
|
||||||
/* creation */
|
/* creation */
|
||||||
resource_type *rt_get_or_create(const char *name);
|
resource_type *rt_get_or_create(const char *name);
|
||||||
|
@ -300,7 +300,6 @@ extern "C" {
|
||||||
|
|
||||||
void register_resources(void);
|
void register_resources(void);
|
||||||
void init_resources(void);
|
void init_resources(void);
|
||||||
void init_itemtypes(void);
|
|
||||||
|
|
||||||
void register_item_give(int(*foo) (struct unit *, struct unit *,
|
void register_item_give(int(*foo) (struct unit *, struct unit *,
|
||||||
const struct item_type *, int, struct order *), const char *name);
|
const struct item_type *, int, struct order *), const char *name);
|
||||||
|
|
|
@ -711,7 +711,7 @@ const item_type *r_luxury(const region * r)
|
||||||
{
|
{
|
||||||
struct demand *dmd;
|
struct demand *dmd;
|
||||||
if (r->land) {
|
if (r->land) {
|
||||||
assert(r->land->demands || !"need to call fix_demands on a region");
|
assert(r->land->demands || !"need to call fix_demand on a region");
|
||||||
for (dmd = r->land->demands; dmd; dmd = dmd->next) {
|
for (dmd = r->land->demands; dmd; dmd = dmd->next) {
|
||||||
if (dmd->value == 0)
|
if (dmd->value == 0)
|
||||||
return dmd->type->itype;
|
return dmd->type->itype;
|
||||||
|
|
|
@ -37,9 +37,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#define MAXTERRAINS 14
|
static const char *terrainnames[MAXTERRAINS] = {
|
||||||
|
|
||||||
const char *terraindata[MAXTERRAINS] = {
|
|
||||||
"ocean",
|
"ocean",
|
||||||
"plain",
|
"plain",
|
||||||
"swamp",
|
"swamp",
|
||||||
|
@ -57,6 +55,17 @@ const char *terraindata[MAXTERRAINS] = {
|
||||||
};
|
};
|
||||||
|
|
||||||
static terrain_type *registered_terrains;
|
static terrain_type *registered_terrains;
|
||||||
|
static int terrain_changes = 1;
|
||||||
|
|
||||||
|
bool terrain_changed(int *cache) {
|
||||||
|
assert(cache);
|
||||||
|
if (*cache != terrain_changes) {
|
||||||
|
*cache = terrain_changes;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void free_terrains(void)
|
void free_terrains(void)
|
||||||
{
|
{
|
||||||
|
@ -76,6 +85,7 @@ void free_terrains(void)
|
||||||
}
|
}
|
||||||
free(t);
|
free(t);
|
||||||
}
|
}
|
||||||
|
++terrain_changes;
|
||||||
}
|
}
|
||||||
|
|
||||||
const terrain_type *terrains(void)
|
const terrain_type *terrains(void)
|
||||||
|
@ -110,6 +120,7 @@ const terrain_type *get_terrain(const char *name) {
|
||||||
terrain_type * get_or_create_terrain(const char *name) {
|
terrain_type * get_or_create_terrain(const char *name) {
|
||||||
terrain_type *terrain = terrain_find_i(name);
|
terrain_type *terrain = terrain_find_i(name);
|
||||||
if (!terrain) {
|
if (!terrain) {
|
||||||
|
++terrain_changes;
|
||||||
terrain = (terrain_type *)calloc(sizeof(terrain_type), 1);
|
terrain = (terrain_type *)calloc(sizeof(terrain_type), 1);
|
||||||
if (terrain) {
|
if (terrain) {
|
||||||
terrain->_name = strdup(name);
|
terrain->_name = strdup(name);
|
||||||
|
@ -128,11 +139,20 @@ static const terrain_type *newterrains[MAXTERRAINS];
|
||||||
|
|
||||||
const struct terrain_type *newterrain(terrain_t t)
|
const struct terrain_type *newterrain(terrain_t t)
|
||||||
{
|
{
|
||||||
if (t == NOTERRAIN)
|
const struct terrain_type *result;
|
||||||
|
if (t == NOTERRAIN) {
|
||||||
return NULL;
|
return NULL;
|
||||||
|
}
|
||||||
assert(t >= 0);
|
assert(t >= 0);
|
||||||
assert(t < MAXTERRAINS);
|
assert(t < MAXTERRAINS);
|
||||||
return newterrains[t];
|
result = newterrains[t];
|
||||||
|
if (!result) {
|
||||||
|
result = newterrains[t] = get_terrain(terrainnames[t]);
|
||||||
|
}
|
||||||
|
if (!result) {
|
||||||
|
log_error("no such terrain: %s.", terrainnames[t]);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
terrain_t oldterrain(const struct terrain_type * terrain)
|
terrain_t oldterrain(const struct terrain_type * terrain)
|
||||||
|
@ -176,8 +196,8 @@ void init_terrains(void)
|
||||||
const terrain_type *newterrain = newterrains[t];
|
const terrain_type *newterrain = newterrains[t];
|
||||||
if (newterrain != NULL)
|
if (newterrain != NULL)
|
||||||
continue;
|
continue;
|
||||||
if (terraindata[t] != NULL) {
|
if (terrainnames[t] != NULL) {
|
||||||
newterrain = get_terrain(terraindata[t]);
|
newterrain = get_terrain(terrainnames[t]);
|
||||||
if (newterrain != NULL) {
|
if (newterrain != NULL) {
|
||||||
newterrains[t] = newterrain;
|
newterrains[t] = newterrain;
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,6 +18,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
|
||||||
#ifndef TERRAIN_H
|
#ifndef TERRAIN_H
|
||||||
#define TERRAIN_H
|
#define TERRAIN_H
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
@ -68,12 +69,13 @@ extern "C" {
|
||||||
struct terrain_type *next;
|
struct terrain_type *next;
|
||||||
} terrain_type;
|
} terrain_type;
|
||||||
|
|
||||||
extern terrain_type *get_or_create_terrain(const char *name);
|
terrain_type *get_or_create_terrain(const char *name);
|
||||||
extern const terrain_type *terrains(void);
|
const terrain_type *terrains(void);
|
||||||
extern const terrain_type *get_terrain(const char *name);
|
const terrain_type *get_terrain(const char *name);
|
||||||
extern const char *terrain_name(const struct region *r);
|
const char *terrain_name(const struct region *r);
|
||||||
|
bool terrain_changed(int *cache);
|
||||||
|
|
||||||
extern void init_terrains(void);
|
void init_terrains(void);
|
||||||
void free_terrains(void);
|
void free_terrains(void);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
|
|
@ -14,7 +14,7 @@
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
enum {
|
typedef enum {
|
||||||
T_OCEAN = 0,
|
T_OCEAN = 0,
|
||||||
T_PLAIN,
|
T_PLAIN,
|
||||||
T_SWAMP,
|
T_SWAMP,
|
||||||
|
@ -29,8 +29,9 @@ extern "C" {
|
||||||
T_VOLCANO_SMOKING,
|
T_VOLCANO_SMOKING,
|
||||||
T_ICEBERG_SLEEP,
|
T_ICEBERG_SLEEP,
|
||||||
T_ICEBERG,
|
T_ICEBERG,
|
||||||
NOTERRAIN = (terrain_t) - 1
|
MAXTERRAINS,
|
||||||
};
|
NOTERRAIN = - 1
|
||||||
|
} terrain_t;
|
||||||
|
|
||||||
extern const struct terrain_type *newterrain(terrain_t t);
|
extern const struct terrain_type *newterrain(terrain_t t);
|
||||||
extern terrain_t oldterrain(const struct terrain_type *terrain);
|
extern terrain_t oldterrain(const struct terrain_type *terrain);
|
||||||
|
|
|
@ -22,7 +22,6 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
#include <settings.h>
|
#include <settings.h>
|
||||||
#include <util/variant.h>
|
#include <util/variant.h>
|
||||||
|
|
||||||
typedef short terrain_t;
|
|
||||||
typedef short item_t;
|
typedef short item_t;
|
||||||
|
|
||||||
struct attrib;
|
struct attrib;
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
|
|
||||||
#ifndef ERESSEA_VERSION
|
#ifndef ERESSEA_VERSION
|
||||||
/* the version number, if it was not passed to make with -D */
|
/* the version number, if it was not passed to make with -D */
|
||||||
#define ERESSEA_VERSION "3.14.0"
|
#define ERESSEA_VERSION "3.15.0"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
const char *eressea_version(void) {
|
const char *eressea_version(void) {
|
||||||
|
|
21
src/laws.c
21
src/laws.c
|
@ -41,6 +41,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
#include "teleport.h"
|
#include "teleport.h"
|
||||||
#include "calendar.h"
|
#include "calendar.h"
|
||||||
#include "guard.h"
|
#include "guard.h"
|
||||||
|
#include "volcano.h"
|
||||||
|
|
||||||
/* attributes includes */
|
/* attributes includes */
|
||||||
#include <attributes/racename.h>
|
#include <attributes/racename.h>
|
||||||
|
@ -72,7 +73,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
#include <kernel/spell.h>
|
#include <kernel/spell.h>
|
||||||
#include <kernel/spellbook.h>
|
#include <kernel/spellbook.h>
|
||||||
#include <kernel/terrain.h>
|
#include <kernel/terrain.h>
|
||||||
#include <kernel/terrainid.h> /* for volcanoes in emigration (needs a flag) */
|
#include <kernel/terrainid.h>
|
||||||
#include <kernel/unit.h>
|
#include <kernel/unit.h>
|
||||||
|
|
||||||
/* util includes */
|
/* util includes */
|
||||||
|
@ -247,10 +248,20 @@ static void calculate_emigration(region * r)
|
||||||
int rp = rpeasants(r);
|
int rp = rpeasants(r);
|
||||||
int max_immigrants = MAX_IMMIGRATION(maxp - rp);
|
int max_immigrants = MAX_IMMIGRATION(maxp - rp);
|
||||||
|
|
||||||
if (r->terrain == newterrain(T_VOLCANO)
|
|
||||||
|| r->terrain == newterrain(T_VOLCANO_SMOKING)) {
|
if (volcano_module()) {
|
||||||
|
static int terrain_cache;
|
||||||
|
static const terrain_type *t_volcano;
|
||||||
|
static const terrain_type *t_smoking;
|
||||||
|
|
||||||
|
if (terrain_changed(&terrain_cache)) {
|
||||||
|
t_volcano = newterrain(T_VOLCANO);
|
||||||
|
t_smoking = newterrain(T_VOLCANO_SMOKING);
|
||||||
|
}
|
||||||
|
if (r->terrain == t_volcano || r->terrain == t_smoking) {
|
||||||
max_immigrants = max_immigrants / 10;
|
max_immigrants = max_immigrants / 10;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for (i = 0; max_immigrants > 0 && i != MAXDIRECTIONS; i++) {
|
for (i = 0; max_immigrants > 0 && i != MAXDIRECTIONS; i++) {
|
||||||
int dir = (turn + 1 + i) % MAXDIRECTIONS;
|
int dir = (turn + 1 + i) % MAXDIRECTIONS;
|
||||||
|
@ -4215,7 +4226,7 @@ void turn_process(void)
|
||||||
init_processor();
|
init_processor();
|
||||||
process();
|
process();
|
||||||
|
|
||||||
if (config_get_int("modules.markets", 0)) {
|
if (markets_module()) {
|
||||||
do_markets();
|
do_markets();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4227,7 +4238,7 @@ void turn_end(void)
|
||||||
remove_empty_units();
|
remove_empty_units();
|
||||||
|
|
||||||
/* must happen AFTER age, because that would destroy them right away */
|
/* must happen AFTER age, because that would destroy them right away */
|
||||||
if (config_get_int("modules.wormholes", 0)) {
|
if (config_get_int("modules.wormhole", 0)) {
|
||||||
wormholes_update();
|
wormholes_update();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
#include <kernel/region.h>
|
#include <kernel/region.h>
|
||||||
#include <kernel/ship.h>
|
#include <kernel/ship.h>
|
||||||
#include <kernel/terrain.h>
|
#include <kernel/terrain.h>
|
||||||
|
#include <kernel/terrainid.h>
|
||||||
#include <kernel/unit.h>
|
#include <kernel/unit.h>
|
||||||
|
|
||||||
#include <util/attrib.h>
|
#include <util/attrib.h>
|
||||||
|
@ -864,11 +865,25 @@ static void test_peasant_luck_effect(CuTest *tc) {
|
||||||
test_cleanup();
|
test_cleanup();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create any terrain types that are used by demographics.
|
||||||
|
*
|
||||||
|
* This should prevent newterrain from returning NULL.
|
||||||
|
*/
|
||||||
|
static void setup_terrains(CuTest *tc) {
|
||||||
|
test_create_terrain("volcano", SEA_REGION | SWIM_INTO | FLY_INTO);
|
||||||
|
test_create_terrain("activevolcano", LAND_REGION | WALK_INTO | FLY_INTO);
|
||||||
|
init_terrains();
|
||||||
|
CuAssertPtrNotNull(tc, newterrain(T_VOLCANO));
|
||||||
|
CuAssertPtrNotNull(tc, newterrain(T_VOLCANO_SMOKING));
|
||||||
|
}
|
||||||
|
|
||||||
static void test_luck_message(CuTest *tc) {
|
static void test_luck_message(CuTest *tc) {
|
||||||
region* r;
|
region* r;
|
||||||
attrib *a;
|
attrib *a;
|
||||||
|
|
||||||
test_setup();
|
test_setup();
|
||||||
|
setup_terrains(tc);
|
||||||
r = test_create_region(0, 0, NULL);
|
r = test_create_region(0, 0, NULL);
|
||||||
rsetpeasants(r, 1);
|
rsetpeasants(r, 1);
|
||||||
|
|
||||||
|
@ -1149,10 +1164,12 @@ static void test_ally_cmd_errors(CuTest *tc) {
|
||||||
static void test_name_cmd(CuTest *tc) {
|
static void test_name_cmd(CuTest *tc) {
|
||||||
unit *u;
|
unit *u;
|
||||||
faction *f;
|
faction *f;
|
||||||
|
alliance *al;
|
||||||
order *ord;
|
order *ord;
|
||||||
|
|
||||||
test_setup();
|
test_setup();
|
||||||
u = test_create_unit(f = test_create_faction(0), test_create_region(0, 0, 0));
|
u = test_create_unit(f = test_create_faction(0), test_create_region(0, 0, 0));
|
||||||
|
setalliance(f, al = makealliance(42, ""));
|
||||||
|
|
||||||
ord = create_order(K_NAME, f->locale, "%s ' Ho\tdor '", LOC(f->locale, parameters[P_UNIT]));
|
ord = create_order(K_NAME, f->locale, "%s ' Ho\tdor '", LOC(f->locale, parameters[P_UNIT]));
|
||||||
name_cmd(u, ord);
|
name_cmd(u, ord);
|
||||||
|
@ -1181,6 +1198,11 @@ static void test_name_cmd(CuTest *tc) {
|
||||||
CuAssertStrEquals(tc, "Hodor", u->region->land->name);
|
CuAssertStrEquals(tc, "Hodor", u->region->land->name);
|
||||||
free_order(ord);
|
free_order(ord);
|
||||||
|
|
||||||
|
ord = create_order(K_NAME, f->locale, "%s ' Ho\tdor '", LOC(f->locale, parameters[P_ALLIANCE]));
|
||||||
|
name_cmd(u, ord);
|
||||||
|
CuAssertStrEquals(tc, "Hodor", al->name);
|
||||||
|
free_order(ord);
|
||||||
|
|
||||||
test_cleanup();
|
test_cleanup();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -102,7 +102,8 @@ static dictionary *parse_config(const char *filename)
|
||||||
join_path(cfgpath, filename, path, sizeof(path));
|
join_path(cfgpath, filename, path, sizeof(path));
|
||||||
log_debug("reading from configuration file %s\n", path);
|
log_debug("reading from configuration file %s\n", path);
|
||||||
d = iniparser_load(path);
|
d = iniparser_load(path);
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
log_debug("reading from configuration file %s\n", filename);
|
log_debug("reading from configuration file %s\n", filename);
|
||||||
d = iniparser_load(filename);
|
d = iniparser_load(filename);
|
||||||
}
|
}
|
||||||
|
@ -168,8 +169,7 @@ static int verbosity_to_flags(int verbosity) {
|
||||||
static int parse_args(int argc, char **argv)
|
static int parse_args(int argc, char **argv)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
int log_stderr = LOG_CPERROR;
|
int log_stderr, log_flags = 2;
|
||||||
int log_flags = LOG_CPERROR | LOG_CPWARNING | LOG_CPINFO;
|
|
||||||
|
|
||||||
for (i = 1; i != argc; ++i) {
|
for (i = 1; i != argc; ++i) {
|
||||||
char *argi = argv[i];
|
char *argi = argv[i];
|
||||||
|
|
|
@ -71,7 +71,7 @@ attrib_type at_market = {
|
||||||
|
|
||||||
bool markets_module(void)
|
bool markets_module(void)
|
||||||
{
|
{
|
||||||
return (bool)config_get_int("modules.markets", 0);
|
return (bool)config_get_int("modules.market", 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void do_markets(void)
|
void do_markets(void)
|
||||||
|
|
|
@ -874,19 +874,27 @@ void spawn_dragons(void)
|
||||||
{
|
{
|
||||||
region *r;
|
region *r;
|
||||||
faction *monsters = get_or_create_monsters();
|
faction *monsters = get_or_create_monsters();
|
||||||
|
int minage = config_get_int("monsters.spawn.min_age", 100);
|
||||||
|
int spawn_chance = 100 * config_get_int("monsters.spawn.chance", 100);
|
||||||
|
|
||||||
|
if (spawn_chance <= 0) {
|
||||||
|
/* monster spawning disabled */
|
||||||
|
return;
|
||||||
|
}
|
||||||
for (r = regions; r; r = r->next) {
|
for (r = regions; r; r = r->next) {
|
||||||
unit *u;
|
unit *u;
|
||||||
|
if (r->age < minage) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
if (fval(r->terrain, SEA_REGION)) {
|
if (fval(r->terrain, SEA_REGION)) {
|
||||||
if (rng_int() % 10000 < 1) {
|
if (rng_int() % spawn_chance < 1) {
|
||||||
u = spawn_seaserpent(r, monsters);
|
u = spawn_seaserpent(r, monsters);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if ((r->terrain == newterrain(T_GLACIER)
|
else if ((r->terrain == newterrain(T_GLACIER)
|
||||||
|| r->terrain == newterrain(T_SWAMP)
|
|| r->terrain == newterrain(T_SWAMP)
|
||||||
|| r->terrain == newterrain(T_DESERT))
|
|| r->terrain == newterrain(T_DESERT))
|
||||||
&& rng_int() % 10000 < (5 + 100 * chaosfactor(r))) {
|
&& rng_int() % spawn_chance < (5 + 100 * chaosfactor(r))) {
|
||||||
if (chance(0.80)) {
|
if (chance(0.80)) {
|
||||||
u = create_unit(r, monsters, nrand(60, 20) + 1, get_race(RC_FIREDRAGON), 0, NULL, NULL);
|
u = create_unit(r, monsters, nrand(60, 20) + 1, get_race(RC_FIREDRAGON), 0, NULL, NULL);
|
||||||
}
|
}
|
||||||
|
|
28
src/move.c
28
src/move.c
|
@ -787,22 +787,22 @@ static void msg_to_ship_inmates(ship *sh, unit **firstu, unit **lastu, message *
|
||||||
msg_release(msg);
|
msg_release(msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
region * drift_target(ship *sh) {
|
direction_t drift_target(ship *sh) {
|
||||||
int d, d_offset = rng_int() % MAXDIRECTIONS;
|
direction_t d, dir = rng_int() % MAXDIRECTIONS;
|
||||||
region *rnext = NULL;
|
direction_t result = NODIRECTION;
|
||||||
for (d = 0; d != MAXDIRECTIONS; ++d) {
|
for (d = 0; d != MAXDIRECTIONS; ++d) {
|
||||||
region *rn;
|
region *rn;
|
||||||
direction_t dir = (direction_t)((d + d_offset) % MAXDIRECTIONS);
|
direction_t dn = (direction_t)((d + dir) % MAXDIRECTIONS);
|
||||||
rn = rconnect(sh->region, dir);
|
rn = rconnect(sh->region, dn);
|
||||||
if (rn != NULL && check_ship_allowed(sh, rn) >= 0) {
|
if (rn != NULL && check_ship_allowed(sh, rn) >= 0) {
|
||||||
rnext = rn;
|
result = dn;
|
||||||
if (!fval(rnext->terrain, SEA_REGION)) {
|
if (!fval(rn->terrain, SEA_REGION)) {
|
||||||
/* prefer drifting towards non-ocean regions */
|
/* prefer drifting towards non-ocean regions */
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return rnext;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void drifting_ships(region * r)
|
static void drifting_ships(region * r)
|
||||||
|
@ -817,7 +817,7 @@ static void drifting_ships(region * r)
|
||||||
region *rnext = NULL;
|
region *rnext = NULL;
|
||||||
region_list *route = NULL;
|
region_list *route = NULL;
|
||||||
unit *firstu = r->units, *lastu = NULL, *captain;
|
unit *firstu = r->units, *lastu = NULL, *captain;
|
||||||
direction_t dir = 0;
|
direction_t dir = NODIRECTION;
|
||||||
double ovl;
|
double ovl;
|
||||||
|
|
||||||
if (sh->type->fishing > 0) {
|
if (sh->type->fishing > 0) {
|
||||||
|
@ -846,13 +846,13 @@ static void drifting_ships(region * r)
|
||||||
}
|
}
|
||||||
|
|
||||||
ovl = overload(r, sh);
|
ovl = overload(r, sh);
|
||||||
if (ovl >= overload_start()) {
|
if (ovl < overload_start()) {
|
||||||
rnext = NULL;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
/* Auswahl einer Richtung: Zuerst auf Land, dann
|
/* Auswahl einer Richtung: Zuerst auf Land, dann
|
||||||
* zufällig. Falls unmögliches Resultat: vergiß es. */
|
* zufällig. Falls unmögliches Resultat: vergiß es. */
|
||||||
rnext = drift_target(sh);
|
dir = drift_target(sh);
|
||||||
|
if (dir != NODIRECTION) {
|
||||||
|
rnext = rconnect(sh->region, dir);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rnext != NULL) {
|
if (rnext != NULL) {
|
||||||
|
|
|
@ -94,7 +94,7 @@ extern "C" {
|
||||||
#define SA_NO_COAST -2
|
#define SA_NO_COAST -2
|
||||||
|
|
||||||
int check_ship_allowed(struct ship *sh, const struct region * r);
|
int check_ship_allowed(struct ship *sh, const struct region * r);
|
||||||
struct region * drift_target(struct ship *sh);
|
direction_t drift_target(struct ship *sh);
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -477,19 +477,19 @@ static void test_follow_ship_msg(CuTest * tc) {
|
||||||
|
|
||||||
static void test_drifting_ships(CuTest *tc) {
|
static void test_drifting_ships(CuTest *tc) {
|
||||||
ship *sh;
|
ship *sh;
|
||||||
region *r1, *r2, *r3;
|
region *r;
|
||||||
terrain_type *t_ocean, *t_plain;
|
terrain_type *t_ocean, *t_plain;
|
||||||
ship_type *st_boat;
|
ship_type *st_boat;
|
||||||
test_setup();
|
test_setup();
|
||||||
t_ocean = test_create_terrain("ocean", SEA_REGION);
|
t_ocean = test_create_terrain("ocean", SEA_REGION);
|
||||||
t_plain = test_create_terrain("plain", LAND_REGION);
|
t_plain = test_create_terrain("plain", LAND_REGION);
|
||||||
r1 = test_create_region(0, 0, t_ocean);
|
r = test_create_region(0, 0, t_ocean);
|
||||||
r2 = test_create_region(1, 0, t_ocean);
|
test_create_region(1, 0, t_ocean);
|
||||||
st_boat = test_create_shiptype("boat");
|
st_boat = test_create_shiptype("boat");
|
||||||
sh = test_create_ship(r1, st_boat);
|
sh = test_create_ship(r, st_boat);
|
||||||
CuAssertPtrEquals(tc, r2, drift_target(sh));
|
CuAssertIntEquals(tc, D_EAST, drift_target(sh));
|
||||||
r3 = test_create_region(-1, 0, t_plain);
|
test_create_region(-1, 0, t_plain);
|
||||||
CuAssertPtrEquals(tc, r3, drift_target(sh));
|
CuAssertIntEquals(tc, D_WEST, drift_target(sh));
|
||||||
test_cleanup();
|
test_cleanup();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -248,6 +248,8 @@ static void dragon_name(unit * u)
|
||||||
case T_GLACIER:
|
case T_GLACIER:
|
||||||
ter = 5;
|
ter = 5;
|
||||||
break;
|
break;
|
||||||
|
default:
|
||||||
|
ter = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (num_postfix <=0) {
|
if (num_postfix <=0) {
|
||||||
|
|
|
@ -432,7 +432,7 @@ void drown(region * r)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void melt_iceberg(region * r)
|
static void melt_iceberg(region * r, const terrain_type *t_ocean)
|
||||||
{
|
{
|
||||||
attrib *a;
|
attrib *a;
|
||||||
unit *u;
|
unit *u;
|
||||||
|
@ -456,11 +456,7 @@ static void melt_iceberg(region * r)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* in Ozean wandeln */
|
/* in Ozean wandeln */
|
||||||
terraform_region(r, newterrain(T_OCEAN));
|
terraform_region(r, t_ocean);
|
||||||
|
|
||||||
/* Einheiten, die nicht schwimmen k<>nnen oder in Schiffen sind,
|
|
||||||
* ertrinken */
|
|
||||||
drown(r);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void move_iceberg(region * r)
|
static void move_iceberg(region * r)
|
||||||
|
@ -589,14 +585,20 @@ static void move_iceberg(region * r)
|
||||||
static void move_icebergs(void)
|
static void move_icebergs(void)
|
||||||
{
|
{
|
||||||
region *r;
|
region *r;
|
||||||
|
static int terrain_cache;
|
||||||
|
static const terrain_type *t_iceberg, *t_ocean;
|
||||||
|
|
||||||
|
if (terrain_changed(&terrain_cache)) {
|
||||||
|
t_iceberg = newterrain(T_ICEBERG);
|
||||||
|
t_ocean = newterrain(T_OCEAN);
|
||||||
|
}
|
||||||
for (r = regions; r; r = r->next) {
|
for (r = regions; r; r = r->next) {
|
||||||
if (r->terrain == newterrain(T_ICEBERG) && !fval(r, RF_SELECT)) {
|
if (r->terrain == t_iceberg && !fval(r, RF_SELECT)) {
|
||||||
int select = rng_int() % 10;
|
int select = rng_int() % 10;
|
||||||
if (select < 4) {
|
if (select < 4) {
|
||||||
/* 4% chance */
|
/* 4% chance */
|
||||||
fset(r, RF_SELECT);
|
fset(r, RF_SELECT);
|
||||||
melt_iceberg(r);
|
melt_iceberg(r, t_ocean);
|
||||||
}
|
}
|
||||||
else if (select < 64) {
|
else if (select < 64) {
|
||||||
/* 60% chance */
|
/* 60% chance */
|
||||||
|
@ -610,9 +612,14 @@ static void move_icebergs(void)
|
||||||
void create_icebergs(void)
|
void create_icebergs(void)
|
||||||
{
|
{
|
||||||
region *r;
|
region *r;
|
||||||
|
const struct terrain_type *t_iceberg, *t_sleep;
|
||||||
|
|
||||||
|
t_iceberg = get_terrain("iceberg");
|
||||||
|
t_sleep = get_terrain("iceberg_sleep");
|
||||||
|
assert(t_iceberg && t_sleep);
|
||||||
|
|
||||||
for (r = regions; r; r = r->next) {
|
for (r = regions; r; r = r->next) {
|
||||||
if (r->terrain == newterrain(T_ICEBERG_SLEEP) && chance(0.05)) {
|
if (r->terrain == t_sleep && chance(0.05)) {
|
||||||
bool has_ocean_neighbour = false;
|
bool has_ocean_neighbour = false;
|
||||||
direction_t dir;
|
direction_t dir;
|
||||||
region *rc;
|
region *rc;
|
||||||
|
@ -629,7 +636,7 @@ void create_icebergs(void)
|
||||||
if (!has_ocean_neighbour)
|
if (!has_ocean_neighbour)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
rsetterrain(r, T_ICEBERG);
|
r->terrain = t_iceberg;
|
||||||
|
|
||||||
fset(r, RF_SELECT);
|
fset(r, RF_SELECT);
|
||||||
move_iceberg(r);
|
move_iceberg(r);
|
||||||
|
@ -750,12 +757,8 @@ static void demon_skillchanges(void)
|
||||||
*/
|
*/
|
||||||
static void icebergs(void)
|
static void icebergs(void)
|
||||||
{
|
{
|
||||||
region *r;
|
|
||||||
create_icebergs();
|
create_icebergs();
|
||||||
move_icebergs();
|
move_icebergs();
|
||||||
for (r = regions; r; r = r->next) {
|
|
||||||
drown(r);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#define HERBS_ROT /* herbs owned by units have a chance to rot. */
|
#define HERBS_ROT /* herbs owned by units have a chance to rot. */
|
||||||
|
@ -801,11 +804,18 @@ void randomevents(void)
|
||||||
region *r;
|
region *r;
|
||||||
faction *monsters = get_monsters();
|
faction *monsters = get_monsters();
|
||||||
|
|
||||||
|
if (config_get_int("modules.iceberg", 0)) {
|
||||||
icebergs();
|
icebergs();
|
||||||
|
}
|
||||||
|
for (r = regions; r; r = r->next) {
|
||||||
|
drown(r);
|
||||||
|
}
|
||||||
godcurse();
|
godcurse();
|
||||||
orc_growth();
|
orc_growth();
|
||||||
demon_skillchanges();
|
demon_skillchanges();
|
||||||
|
if (volcano_module()) {
|
||||||
volcano_update();
|
volcano_update();
|
||||||
|
}
|
||||||
/* Monumente zerfallen, Schiffe verfaulen */
|
/* Monumente zerfallen, Schiffe verfaulen */
|
||||||
|
|
||||||
for (r = regions; r; r = r->next) {
|
for (r = regions; r; r = r->next) {
|
||||||
|
|
|
@ -45,9 +45,6 @@ typedef struct locale {
|
||||||
struct locale_str *strings[SMAXHASH];
|
struct locale_str *strings[SMAXHASH];
|
||||||
} locale;
|
} locale;
|
||||||
|
|
||||||
extern locale *default_locale;
|
|
||||||
extern locale *locales;
|
|
||||||
|
|
||||||
locale *default_locale;
|
locale *default_locale;
|
||||||
locale *locales;
|
locale *locales;
|
||||||
|
|
||||||
|
|
|
@ -177,11 +177,15 @@ char *parse_token(const char **str, char *lbuf, size_t buflen)
|
||||||
++ctoken;
|
++ctoken;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
if (cursor - buflen < lbuf - len) {
|
||||||
*cursor++ = *ctoken++;
|
*cursor++ = *ctoken++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
else if (utf8_character == SPACE_REPLACEMENT) {
|
else if (utf8_character == SPACE_REPLACEMENT) {
|
||||||
|
if (cursor - buflen < lbuf - len) {
|
||||||
*cursor++ = ' ';
|
*cursor++ = ' ';
|
||||||
|
}
|
||||||
++ctoken;
|
++ctoken;
|
||||||
}
|
}
|
||||||
else if (utf8_character == ESCAPE_CHAR) {
|
else if (utf8_character == ESCAPE_CHAR) {
|
||||||
|
|
|
@ -28,6 +28,15 @@ static void test_parse_token(CuTest *tc) {
|
||||||
CuAssertPtrEquals(tc, NULL, (void *)tok);
|
CuAssertPtrEquals(tc, NULL, (void *)tok);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void test_parse_token_bug_2381(CuTest *tc) {
|
||||||
|
const char *stok, *s = "Bitte~wechselt~auf~die~trireme~3im9,~sobald~eine~Crew~da~ist,~geht~es~los~:)";
|
||||||
|
char token[64];
|
||||||
|
|
||||||
|
stok = s;
|
||||||
|
stok = parse_token(&stok, token, sizeof(token));
|
||||||
|
CuAssertTrue(tc, strlen(token) < sizeof(token));
|
||||||
|
}
|
||||||
|
|
||||||
static void test_parse_token_limit(CuTest *tc) {
|
static void test_parse_token_limit(CuTest *tc) {
|
||||||
char lbuf[8];
|
char lbuf[8];
|
||||||
const char *tok;
|
const char *tok;
|
||||||
|
@ -117,6 +126,7 @@ CuSuite *get_parser_suite(void)
|
||||||
SUITE_ADD_TEST(suite, test_atoip);
|
SUITE_ADD_TEST(suite, test_atoip);
|
||||||
SUITE_ADD_TEST(suite, test_skip_token);
|
SUITE_ADD_TEST(suite, test_skip_token);
|
||||||
SUITE_ADD_TEST(suite, test_parse_token);
|
SUITE_ADD_TEST(suite, test_parse_token);
|
||||||
|
SUITE_ADD_TEST(suite, test_parse_token_bug_2381);
|
||||||
SUITE_ADD_TEST(suite, test_parse_token_limit);
|
SUITE_ADD_TEST(suite, test_parse_token_limit);
|
||||||
SUITE_ADD_TEST(suite, test_parse_token_limit_utf8);
|
SUITE_ADD_TEST(suite, test_parse_token_limit_utf8);
|
||||||
SUITE_ADD_TEST(suite, test_gettoken);
|
SUITE_ADD_TEST(suite, test_gettoken);
|
||||||
|
|
|
@ -106,8 +106,8 @@ damage_unit(unit * u, const char *dam, bool physical, bool magic)
|
||||||
int damage = dice_rand(dam);
|
int damage = dice_rand(dam);
|
||||||
if (magic) {
|
if (magic) {
|
||||||
variant magres = magic_resistance(u);
|
variant magres = magic_resistance(u);
|
||||||
magres = frac_sub(frac_make(1, 1), magres);
|
int save = magres.sa[0] / magres.sa[1];
|
||||||
damage = damage * magres.sa[0] / magres.sa[1];
|
damage -= damage * save;
|
||||||
}
|
}
|
||||||
if (physical) {
|
if (physical) {
|
||||||
damage -= nb_armor(u, i);
|
damage -= nb_armor(u, i);
|
||||||
|
@ -314,3 +314,13 @@ void volcano_update(void)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool volcano_module(void)
|
||||||
|
{
|
||||||
|
static int cache;
|
||||||
|
static bool active;
|
||||||
|
if (config_changed(&cache)) {
|
||||||
|
active = config_get_int("modules.volcano", 0) != 0;
|
||||||
|
}
|
||||||
|
return active;
|
||||||
|
}
|
||||||
|
|
|
@ -27,6 +27,7 @@ extern "C" {
|
||||||
|
|
||||||
void volcano_outbreak(struct region * r, struct region *rn);
|
void volcano_outbreak(struct region * r, struct region *rn);
|
||||||
void volcano_update(void);
|
void volcano_update(void);
|
||||||
|
bool volcano_module(void);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue