forked from github/server
Merge branch 'develop'
This commit is contained in:
commit
34808a25c5
|
@ -13,7 +13,12 @@
|
|||
"game.id" : 2,
|
||||
"orders.default": "work",
|
||||
"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.perlevel": 20,
|
||||
"taxing.perlevel": 20,
|
||||
|
|
|
@ -32,8 +32,10 @@
|
|||
"database.gameid": 7,
|
||||
"NewbieImmunity": 4,
|
||||
"modules.astralspace": false,
|
||||
"modules.wormholes": false,
|
||||
"modules.markets": true,
|
||||
"modules.wormhole": false,
|
||||
"modules.market": true,
|
||||
"modules.iceberg": false,
|
||||
"modules.volcano": true,
|
||||
"magic.regeneration": 0.75,
|
||||
"magic.power": 0.5,
|
||||
"resource.factor": 0.25,
|
||||
|
|
|
@ -807,7 +807,6 @@ end
|
|||
function test_swim_and_survive()
|
||||
local r = region.create(0, 0, "plain")
|
||||
local f = create_faction('human')
|
||||
f.nam = "chaos"
|
||||
local u = unit.create(f, r, 1)
|
||||
process_orders()
|
||||
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 *awtype = NULL;
|
||||
const weapon *weapon;
|
||||
variant res = frac_make(1, 1);
|
||||
variant res = frac_one;
|
||||
|
||||
int rda, sk = 0, sd;
|
||||
bool magic = false;
|
||||
|
@ -1185,6 +1185,7 @@ terminate(troop dt, troop at, int type, const char *damage, bool missile)
|
|||
}
|
||||
|
||||
if (magic) {
|
||||
res = frac_sub(frac_one, res);
|
||||
res = frac_mul(frac_make(da, 1), res);
|
||||
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",
|
||||
translate(zRace, LOC(lang, zRace)));
|
||||
if (u->faction == f && irace != u_race(u)) {
|
||||
assert(skill_enabled(SK_STEALTH)
|
||||
|| !"we're resetting this on load, so.. ircase should never be used");
|
||||
zRace = rc_name_s(u_race(u), NAME_PLURAL);
|
||||
stream_printf(out, "\"%s\";wahrerTyp\n",
|
||||
translate(zRace, LOC(lang, zRace)));
|
||||
|
|
|
@ -1067,7 +1067,7 @@ static int required(int want, variant save)
|
|||
{
|
||||
int req = (int)(want * save.sa[0] / save.sa[1]);
|
||||
int r = want * save.sa[0] % save.sa[1];
|
||||
if (r>0) ++req;
|
||||
if (r > 0) ++req;
|
||||
return req;
|
||||
}
|
||||
|
||||
|
@ -1173,7 +1173,7 @@ attrib_allocation(const resource_type * rtype, region * r, allocation * alist)
|
|||
int x = avail * want / nreq;
|
||||
int rx = (avail * want) % nreq;
|
||||
/* Wenn Rest, dann wuerfeln, ob ich was bekomme: */
|
||||
if (rx>0 && rng_int() % nreq < rx) ++x;
|
||||
if (rx > 0 && rng_int() % nreq < rx) ++x;
|
||||
avail -= x;
|
||||
nreq -= want;
|
||||
al->get = x * al->save.sa[1] / al->save.sa[0];
|
||||
|
@ -1446,25 +1446,20 @@ static void expandbuying(region * r, request * buyorders)
|
|||
const resource_type *rsilver = get_resourcetype(R_SILVER);
|
||||
int max_products;
|
||||
unit *u;
|
||||
static struct trade {
|
||||
struct trade {
|
||||
const luxury_type *type;
|
||||
int number;
|
||||
int multi;
|
||||
} trades[MAXLUXURIES], *trade;
|
||||
static int ntrades = 0;
|
||||
int i;
|
||||
int ntrades = 0;
|
||||
const luxury_type *ltype;
|
||||
|
||||
if (ntrades == 0) {
|
||||
for (ntrades = 0, ltype = luxurytypes; ltype; ltype = ltype->next) {
|
||||
assert(ntrades < MAXLUXURIES);
|
||||
trades[ntrades].number = 0;
|
||||
trades[ntrades].multi = 1;
|
||||
trades[ntrades++].type = ltype;
|
||||
}
|
||||
}
|
||||
for (i = 0; i != ntrades; ++i) {
|
||||
trades[i].number = 0;
|
||||
trades[i].multi = 1;
|
||||
}
|
||||
|
||||
if (!buyorders)
|
||||
return;
|
||||
|
@ -1490,7 +1485,7 @@ static void expandbuying(region * r, request * buyorders)
|
|||
int price, multi;
|
||||
ltype = g_requests[j].type.ltype;
|
||||
trade = trades;
|
||||
while (trade->type != ltype)
|
||||
while (trade->type && trade->type != ltype)
|
||||
++trade;
|
||||
multi = trade->multi;
|
||||
price = ltype->price * multi;
|
||||
|
@ -1595,17 +1590,10 @@ static void buy(unit * u, request ** buyorders, struct order *ord)
|
|||
return;
|
||||
}
|
||||
|
||||
if (u_race(u) == get_race(RC_INSECT)) {
|
||||
/* entweder man ist insekt, oder... */
|
||||
if (r->terrain != newterrain(T_SWAMP) && r->terrain != newterrain(T_DESERT)
|
||||
&& !rbuildings(r)) {
|
||||
cmistake(u, ord, 119, MSG_COMMERCE);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* ...oder in der Region mu<6D> es eine Burg geben. */
|
||||
building *b = 0;
|
||||
/* Entweder man ist Insekt in Sumpf/Wueste, oder es muss
|
||||
* einen Handelsposten in der Region geben: */
|
||||
if (u_race(u) != get_race(RC_INSECT) || (r->terrain == newterrain(T_SWAMP) || r->terrain == newterrain(T_DESERT))) {
|
||||
building *b = NULL;
|
||||
if (r->buildings) {
|
||||
static int cache;
|
||||
static const struct building_type *bt_castle;
|
||||
|
@ -2724,7 +2712,7 @@ static void expandloot(region * r, request * lootorders)
|
|||
|
||||
/* Lowering morale by 1 depending on the looted money (+20%) */
|
||||
m = region_get_morale(r);
|
||||
if (m && startmoney>0) {
|
||||
if (m && startmoney > 0) {
|
||||
if (rng_int() % 100 < 20 + (looted * 80) / startmoney) {
|
||||
/*Nur Moral -1, turns is not changed, so the first time nothing happens if the morale is good*/
|
||||
region_set_morale(r, m - 1, -1);
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
#include <kernel/resources.h>
|
||||
#include <kernel/ship.h>
|
||||
#include <kernel/terrain.h>
|
||||
#include <kernel/terrainid.h>
|
||||
#include <kernel/unit.h>
|
||||
|
||||
#include <util/attrib.h>
|
||||
|
@ -170,6 +171,133 @@ static void test_normals_recruit(CuTest * tc) {
|
|||
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 {
|
||||
struct request *next;
|
||||
struct unit *unit;
|
||||
|
@ -568,6 +696,8 @@ CuSuite *get_economy_suite(void)
|
|||
SUITE_ADD_TEST(suite, test_normals_recruit);
|
||||
SUITE_ADD_TEST(suite, test_heroes_dont_recruit);
|
||||
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_recruit);
|
||||
return suite;
|
||||
|
|
|
@ -76,7 +76,7 @@ int *casualties)
|
|||
killed += terminate(dt, *at, AT_SPELL, damage, 1);
|
||||
}
|
||||
} while (force && killed < enemies);
|
||||
if (casualties)
|
||||
if (killed > 0 && casualties)
|
||||
*casualties = killed;
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -216,7 +216,6 @@ static void test_alliance_cmd_transfer(CuTest *tc) {
|
|||
test_cleanup();
|
||||
}
|
||||
|
||||
|
||||
CuSuite *get_alliance_suite(void)
|
||||
{
|
||||
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)
|
||||
{
|
||||
if (rtype->modifiers) {
|
||||
variant save = frac_make(1, 1);
|
||||
variant save = frac_one;
|
||||
const struct building_type *btype = NULL;
|
||||
const struct race *rc = u_race(u);
|
||||
resource_mod *mod;
|
||||
|
|
|
@ -224,7 +224,7 @@ extern "C" {
|
|||
|
||||
/* convenience: */
|
||||
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 */
|
||||
resource_type *rt_get_or_create(const char *name);
|
||||
|
@ -300,7 +300,6 @@ extern "C" {
|
|||
|
||||
void register_resources(void);
|
||||
void init_resources(void);
|
||||
void init_itemtypes(void);
|
||||
|
||||
void register_item_give(int(*foo) (struct unit *, struct unit *,
|
||||
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;
|
||||
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) {
|
||||
if (dmd->value == 0)
|
||||
return dmd->type->itype;
|
||||
|
|
|
@ -37,9 +37,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#define MAXTERRAINS 14
|
||||
|
||||
const char *terraindata[MAXTERRAINS] = {
|
||||
static const char *terrainnames[MAXTERRAINS] = {
|
||||
"ocean",
|
||||
"plain",
|
||||
"swamp",
|
||||
|
@ -57,6 +55,17 @@ const char *terraindata[MAXTERRAINS] = {
|
|||
};
|
||||
|
||||
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)
|
||||
{
|
||||
|
@ -76,6 +85,7 @@ void free_terrains(void)
|
|||
}
|
||||
free(t);
|
||||
}
|
||||
++terrain_changes;
|
||||
}
|
||||
|
||||
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 *terrain = terrain_find_i(name);
|
||||
if (!terrain) {
|
||||
++terrain_changes;
|
||||
terrain = (terrain_type *)calloc(sizeof(terrain_type), 1);
|
||||
if (terrain) {
|
||||
terrain->_name = strdup(name);
|
||||
|
@ -128,11 +139,20 @@ static const terrain_type *newterrains[MAXTERRAINS];
|
|||
|
||||
const struct terrain_type *newterrain(terrain_t t)
|
||||
{
|
||||
if (t == NOTERRAIN)
|
||||
const struct terrain_type *result;
|
||||
if (t == NOTERRAIN) {
|
||||
return NULL;
|
||||
}
|
||||
assert(t >= 0);
|
||||
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)
|
||||
|
@ -176,8 +196,8 @@ void init_terrains(void)
|
|||
const terrain_type *newterrain = newterrains[t];
|
||||
if (newterrain != NULL)
|
||||
continue;
|
||||
if (terraindata[t] != NULL) {
|
||||
newterrain = get_terrain(terraindata[t]);
|
||||
if (terrainnames[t] != NULL) {
|
||||
newterrain = get_terrain(terrainnames[t]);
|
||||
if (newterrain != NULL) {
|
||||
newterrains[t] = newterrain;
|
||||
}
|
||||
|
|
|
@ -18,6 +18,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|||
|
||||
#ifndef TERRAIN_H
|
||||
#define TERRAIN_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
@ -68,12 +69,13 @@ extern "C" {
|
|||
struct terrain_type *next;
|
||||
} terrain_type;
|
||||
|
||||
extern terrain_type *get_or_create_terrain(const char *name);
|
||||
extern const terrain_type *terrains(void);
|
||||
extern const terrain_type *get_terrain(const char *name);
|
||||
extern const char *terrain_name(const struct region *r);
|
||||
terrain_type *get_or_create_terrain(const char *name);
|
||||
const terrain_type *terrains(void);
|
||||
const terrain_type *get_terrain(const char *name);
|
||||
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);
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
extern "C" {
|
||||
#endif
|
||||
|
||||
enum {
|
||||
typedef enum {
|
||||
T_OCEAN = 0,
|
||||
T_PLAIN,
|
||||
T_SWAMP,
|
||||
|
@ -29,8 +29,9 @@ extern "C" {
|
|||
T_VOLCANO_SMOKING,
|
||||
T_ICEBERG_SLEEP,
|
||||
T_ICEBERG,
|
||||
NOTERRAIN = (terrain_t) - 1
|
||||
};
|
||||
MAXTERRAINS,
|
||||
NOTERRAIN = - 1
|
||||
} terrain_t;
|
||||
|
||||
extern const struct terrain_type *newterrain(terrain_t t);
|
||||
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 <util/variant.h>
|
||||
|
||||
typedef short terrain_t;
|
||||
typedef short item_t;
|
||||
|
||||
struct attrib;
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
|
||||
#ifndef ERESSEA_VERSION
|
||||
/* 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
|
||||
|
||||
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 "calendar.h"
|
||||
#include "guard.h"
|
||||
#include "volcano.h"
|
||||
|
||||
/* attributes includes */
|
||||
#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/spellbook.h>
|
||||
#include <kernel/terrain.h>
|
||||
#include <kernel/terrainid.h> /* for volcanoes in emigration (needs a flag) */
|
||||
#include <kernel/terrainid.h>
|
||||
#include <kernel/unit.h>
|
||||
|
||||
/* util includes */
|
||||
|
@ -247,10 +248,20 @@ static void calculate_emigration(region * r)
|
|||
int rp = rpeasants(r);
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; max_immigrants > 0 && i != MAXDIRECTIONS; i++) {
|
||||
int dir = (turn + 1 + i) % MAXDIRECTIONS;
|
||||
|
@ -4215,7 +4226,7 @@ void turn_process(void)
|
|||
init_processor();
|
||||
process();
|
||||
|
||||
if (config_get_int("modules.markets", 0)) {
|
||||
if (markets_module()) {
|
||||
do_markets();
|
||||
}
|
||||
}
|
||||
|
@ -4227,7 +4238,7 @@ void turn_end(void)
|
|||
remove_empty_units();
|
||||
|
||||
/* 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();
|
||||
}
|
||||
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
#include <kernel/region.h>
|
||||
#include <kernel/ship.h>
|
||||
#include <kernel/terrain.h>
|
||||
#include <kernel/terrainid.h>
|
||||
#include <kernel/unit.h>
|
||||
|
||||
#include <util/attrib.h>
|
||||
|
@ -864,11 +865,25 @@ static void test_peasant_luck_effect(CuTest *tc) {
|
|||
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) {
|
||||
region* r;
|
||||
attrib *a;
|
||||
|
||||
test_setup();
|
||||
setup_terrains(tc);
|
||||
r = test_create_region(0, 0, NULL);
|
||||
rsetpeasants(r, 1);
|
||||
|
||||
|
@ -1149,10 +1164,12 @@ static void test_ally_cmd_errors(CuTest *tc) {
|
|||
static void test_name_cmd(CuTest *tc) {
|
||||
unit *u;
|
||||
faction *f;
|
||||
alliance *al;
|
||||
order *ord;
|
||||
|
||||
test_setup();
|
||||
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]));
|
||||
name_cmd(u, ord);
|
||||
|
@ -1181,6 +1198,11 @@ static void test_name_cmd(CuTest *tc) {
|
|||
CuAssertStrEquals(tc, "Hodor", u->region->land->name);
|
||||
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();
|
||||
}
|
||||
|
||||
|
|
10
src/main.c
10
src/main.c
|
@ -102,7 +102,8 @@ static dictionary *parse_config(const char *filename)
|
|||
join_path(cfgpath, filename, path, sizeof(path));
|
||||
log_debug("reading from configuration file %s\n", path);
|
||||
d = iniparser_load(path);
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
log_debug("reading from configuration file %s\n", filename);
|
||||
d = iniparser_load(filename);
|
||||
}
|
||||
|
@ -168,8 +169,7 @@ static int verbosity_to_flags(int verbosity) {
|
|||
static int parse_args(int argc, char **argv)
|
||||
{
|
||||
int i;
|
||||
int log_stderr = LOG_CPERROR;
|
||||
int log_flags = LOG_CPERROR | LOG_CPWARNING | LOG_CPINFO;
|
||||
int log_stderr, log_flags = 2;
|
||||
|
||||
for (i = 1; i != argc; ++i) {
|
||||
char *argi = argv[i];
|
||||
|
@ -300,8 +300,8 @@ int main(int argc, char **argv)
|
|||
setup_signal_handler();
|
||||
/* parse arguments again, to override ini file */
|
||||
err = parse_args(argc, argv);
|
||||
if (err!=0) {
|
||||
return (err>0) ? 0 : err;
|
||||
if (err != 0) {
|
||||
return (err > 0) ? 0 : err;
|
||||
}
|
||||
d = parse_config(inifile);
|
||||
if (!d) {
|
||||
|
|
|
@ -71,7 +71,7 @@ attrib_type at_market = {
|
|||
|
||||
bool markets_module(void)
|
||||
{
|
||||
return (bool)config_get_int("modules.markets", 0);
|
||||
return (bool)config_get_int("modules.market", 0);
|
||||
}
|
||||
|
||||
void do_markets(void)
|
||||
|
|
|
@ -874,19 +874,27 @@ void spawn_dragons(void)
|
|||
{
|
||||
region *r;
|
||||
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) {
|
||||
unit *u;
|
||||
|
||||
if (r->age < minage) {
|
||||
continue;
|
||||
}
|
||||
if (fval(r->terrain, SEA_REGION)) {
|
||||
if (rng_int() % 10000 < 1) {
|
||||
if (rng_int() % spawn_chance < 1) {
|
||||
u = spawn_seaserpent(r, monsters);
|
||||
}
|
||||
}
|
||||
else if ((r->terrain == newterrain(T_GLACIER)
|
||||
|| r->terrain == newterrain(T_SWAMP)
|
||||
|| r->terrain == newterrain(T_DESERT))
|
||||
&& rng_int() % 10000 < (5 + 100 * chaosfactor(r))) {
|
||||
&& rng_int() % spawn_chance < (5 + 100 * chaosfactor(r))) {
|
||||
if (chance(0.80)) {
|
||||
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);
|
||||
}
|
||||
|
||||
region * drift_target(ship *sh) {
|
||||
int d, d_offset = rng_int() % MAXDIRECTIONS;
|
||||
region *rnext = NULL;
|
||||
direction_t drift_target(ship *sh) {
|
||||
direction_t d, dir = rng_int() % MAXDIRECTIONS;
|
||||
direction_t result = NODIRECTION;
|
||||
for (d = 0; d != MAXDIRECTIONS; ++d) {
|
||||
region *rn;
|
||||
direction_t dir = (direction_t)((d + d_offset) % MAXDIRECTIONS);
|
||||
rn = rconnect(sh->region, dir);
|
||||
direction_t dn = (direction_t)((d + dir) % MAXDIRECTIONS);
|
||||
rn = rconnect(sh->region, dn);
|
||||
if (rn != NULL && check_ship_allowed(sh, rn) >= 0) {
|
||||
rnext = rn;
|
||||
if (!fval(rnext->terrain, SEA_REGION)) {
|
||||
result = dn;
|
||||
if (!fval(rn->terrain, SEA_REGION)) {
|
||||
/* prefer drifting towards non-ocean regions */
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return rnext;
|
||||
return result;
|
||||
}
|
||||
|
||||
static void drifting_ships(region * r)
|
||||
|
@ -817,7 +817,7 @@ static void drifting_ships(region * r)
|
|||
region *rnext = NULL;
|
||||
region_list *route = NULL;
|
||||
unit *firstu = r->units, *lastu = NULL, *captain;
|
||||
direction_t dir = 0;
|
||||
direction_t dir = NODIRECTION;
|
||||
double ovl;
|
||||
|
||||
if (sh->type->fishing > 0) {
|
||||
|
@ -846,13 +846,13 @@ static void drifting_ships(region * r)
|
|||
}
|
||||
|
||||
ovl = overload(r, sh);
|
||||
if (ovl >= overload_start()) {
|
||||
rnext = NULL;
|
||||
}
|
||||
else {
|
||||
if (ovl < overload_start()) {
|
||||
/* Auswahl einer Richtung: Zuerst auf Land, dann
|
||||
* 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) {
|
||||
|
|
|
@ -94,7 +94,7 @@ extern "C" {
|
|||
#define SA_NO_COAST -2
|
||||
|
||||
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
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -477,19 +477,19 @@ static void test_follow_ship_msg(CuTest * tc) {
|
|||
|
||||
static void test_drifting_ships(CuTest *tc) {
|
||||
ship *sh;
|
||||
region *r1, *r2, *r3;
|
||||
region *r;
|
||||
terrain_type *t_ocean, *t_plain;
|
||||
ship_type *st_boat;
|
||||
test_setup();
|
||||
t_ocean = test_create_terrain("ocean", SEA_REGION);
|
||||
t_plain = test_create_terrain("plain", LAND_REGION);
|
||||
r1 = test_create_region(0, 0, t_ocean);
|
||||
r2 = test_create_region(1, 0, t_ocean);
|
||||
r = test_create_region(0, 0, t_ocean);
|
||||
test_create_region(1, 0, t_ocean);
|
||||
st_boat = test_create_shiptype("boat");
|
||||
sh = test_create_ship(r1, st_boat);
|
||||
CuAssertPtrEquals(tc, r2, drift_target(sh));
|
||||
r3 = test_create_region(-1, 0, t_plain);
|
||||
CuAssertPtrEquals(tc, r3, drift_target(sh));
|
||||
sh = test_create_ship(r, st_boat);
|
||||
CuAssertIntEquals(tc, D_EAST, drift_target(sh));
|
||||
test_create_region(-1, 0, t_plain);
|
||||
CuAssertIntEquals(tc, D_WEST, drift_target(sh));
|
||||
test_cleanup();
|
||||
}
|
||||
|
||||
|
|
|
@ -248,6 +248,8 @@ static void dragon_name(unit * u)
|
|||
case T_GLACIER:
|
||||
ter = 5;
|
||||
break;
|
||||
default:
|
||||
ter = 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;
|
||||
unit *u;
|
||||
|
@ -456,11 +456,7 @@ static void melt_iceberg(region * r)
|
|||
}
|
||||
|
||||
/* in Ozean wandeln */
|
||||
terraform_region(r, newterrain(T_OCEAN));
|
||||
|
||||
/* Einheiten, die nicht schwimmen k<>nnen oder in Schiffen sind,
|
||||
* ertrinken */
|
||||
drown(r);
|
||||
terraform_region(r, t_ocean);
|
||||
}
|
||||
|
||||
static void move_iceberg(region * r)
|
||||
|
@ -589,14 +585,20 @@ static void move_iceberg(region * r)
|
|||
static void move_icebergs(void)
|
||||
{
|
||||
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) {
|
||||
if (r->terrain == newterrain(T_ICEBERG) && !fval(r, RF_SELECT)) {
|
||||
if (r->terrain == t_iceberg && !fval(r, RF_SELECT)) {
|
||||
int select = rng_int() % 10;
|
||||
if (select < 4) {
|
||||
/* 4% chance */
|
||||
fset(r, RF_SELECT);
|
||||
melt_iceberg(r);
|
||||
melt_iceberg(r, t_ocean);
|
||||
}
|
||||
else if (select < 64) {
|
||||
/* 60% chance */
|
||||
|
@ -610,9 +612,14 @@ static void move_icebergs(void)
|
|||
void create_icebergs(void)
|
||||
{
|
||||
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) {
|
||||
if (r->terrain == newterrain(T_ICEBERG_SLEEP) && chance(0.05)) {
|
||||
if (r->terrain == t_sleep && chance(0.05)) {
|
||||
bool has_ocean_neighbour = false;
|
||||
direction_t dir;
|
||||
region *rc;
|
||||
|
@ -629,7 +636,7 @@ void create_icebergs(void)
|
|||
if (!has_ocean_neighbour)
|
||||
continue;
|
||||
|
||||
rsetterrain(r, T_ICEBERG);
|
||||
r->terrain = t_iceberg;
|
||||
|
||||
fset(r, RF_SELECT);
|
||||
move_iceberg(r);
|
||||
|
@ -750,12 +757,8 @@ static void demon_skillchanges(void)
|
|||
*/
|
||||
static void icebergs(void)
|
||||
{
|
||||
region *r;
|
||||
create_icebergs();
|
||||
move_icebergs();
|
||||
for (r = regions; r; r = r->next) {
|
||||
drown(r);
|
||||
}
|
||||
}
|
||||
|
||||
#define HERBS_ROT /* herbs owned by units have a chance to rot. */
|
||||
|
@ -801,11 +804,18 @@ void randomevents(void)
|
|||
region *r;
|
||||
faction *monsters = get_monsters();
|
||||
|
||||
if (config_get_int("modules.iceberg", 0)) {
|
||||
icebergs();
|
||||
}
|
||||
for (r = regions; r; r = r->next) {
|
||||
drown(r);
|
||||
}
|
||||
godcurse();
|
||||
orc_growth();
|
||||
demon_skillchanges();
|
||||
if (volcano_module()) {
|
||||
volcano_update();
|
||||
}
|
||||
/* Monumente zerfallen, Schiffe verfaulen */
|
||||
|
||||
for (r = regions; r; r = r->next) {
|
||||
|
|
12
src/tests.c
12
src/tests.c
|
@ -122,10 +122,10 @@ struct locale * test_create_locale(void) {
|
|||
for (i = 0; i != MAXDIRECTIONS; ++i) {
|
||||
locale_setstring(loc, directions[i], directions[i]);
|
||||
init_direction(loc, i, directions[i]);
|
||||
init_direction(loc, i, coasts[i]+7);
|
||||
init_direction(loc, i, coasts[i] + 7);
|
||||
}
|
||||
for (i = 0; i <= ST_FLEE; ++i) {
|
||||
locale_setstring(loc, combatstatus[i], combatstatus[i]+7);
|
||||
locale_setstring(loc, combatstatus[i], combatstatus[i] + 7);
|
||||
}
|
||||
for (i = 0; i != MAXKEYWORDS; ++i) {
|
||||
locale_setstring(loc, mkname("keyword", keywords[i]), keywords[i]);
|
||||
|
@ -545,20 +545,20 @@ void assert_message(CuTest * tc, message *msg, char *name, int numpar) {
|
|||
|
||||
void assert_pointer_parameter(CuTest * tc, message *msg, int index, void *arg) {
|
||||
const message_type *mtype = (msg)->type;
|
||||
CuAssertIntEquals((tc), VAR_VOIDPTR, mtype->types[(index)]->vtype);CuAssertPtrEquals((tc), (arg), msg->parameters[(index)].v);
|
||||
CuAssertIntEquals((tc), VAR_VOIDPTR, mtype->types[(index)]->vtype); CuAssertPtrEquals((tc), (arg), msg->parameters[(index)].v);
|
||||
}
|
||||
|
||||
void assert_int_parameter(CuTest * tc, message *msg, int index, int arg) {
|
||||
const message_type *mtype = (msg)->type;
|
||||
CuAssertIntEquals((tc), VAR_INT, mtype->types[(index)]->vtype);CuAssertIntEquals((tc), (arg), msg->parameters[(index)].i);
|
||||
CuAssertIntEquals((tc), VAR_INT, mtype->types[(index)]->vtype); CuAssertIntEquals((tc), (arg), msg->parameters[(index)].i);
|
||||
}
|
||||
|
||||
void assert_string_parameter(CuTest * tc, message *msg, int index, const char *arg) {
|
||||
const message_type *mtype = (msg)->type;
|
||||
CuAssertIntEquals((tc), VAR_VOIDPTR, mtype->types[(index)]->vtype);CuAssertStrEquals((tc), (arg), msg->parameters[(index)].v);
|
||||
CuAssertIntEquals((tc), VAR_VOIDPTR, mtype->types[(index)]->vtype); CuAssertStrEquals((tc), (arg), msg->parameters[(index)].v);
|
||||
}
|
||||
|
||||
void disabled_test(void *suite, void (*test)(CuTest *), const char *name) {
|
||||
void disabled_test(void *suite, void(*test)(CuTest *), const char *name) {
|
||||
(void)test;
|
||||
fprintf(stderr, "%s: SKIP\n", name);
|
||||
}
|
||||
|
|
|
@ -45,9 +45,6 @@ typedef struct locale {
|
|||
struct locale_str *strings[SMAXHASH];
|
||||
} locale;
|
||||
|
||||
extern locale *default_locale;
|
||||
extern locale *locales;
|
||||
|
||||
locale *default_locale;
|
||||
locale *locales;
|
||||
|
||||
|
|
|
@ -177,11 +177,15 @@ char *parse_token(const char **str, char *lbuf, size_t buflen)
|
|||
++ctoken;
|
||||
}
|
||||
else {
|
||||
if (cursor - buflen < lbuf - len) {
|
||||
*cursor++ = *ctoken++;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (utf8_character == SPACE_REPLACEMENT) {
|
||||
if (cursor - buflen < lbuf - len) {
|
||||
*cursor++ = ' ';
|
||||
}
|
||||
++ctoken;
|
||||
}
|
||||
else if (utf8_character == ESCAPE_CHAR) {
|
||||
|
|
|
@ -28,6 +28,15 @@ static void test_parse_token(CuTest *tc) {
|
|||
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) {
|
||||
char lbuf[8];
|
||||
const char *tok;
|
||||
|
@ -117,6 +126,7 @@ CuSuite *get_parser_suite(void)
|
|||
SUITE_ADD_TEST(suite, test_atoip);
|
||||
SUITE_ADD_TEST(suite, test_skip_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_utf8);
|
||||
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);
|
||||
if (magic) {
|
||||
variant magres = magic_resistance(u);
|
||||
magres = frac_sub(frac_make(1, 1), magres);
|
||||
damage = damage * magres.sa[0] / magres.sa[1];
|
||||
int save = magres.sa[0] / magres.sa[1];
|
||||
damage -= damage * save;
|
||||
}
|
||||
if (physical) {
|
||||
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_update(void);
|
||||
bool volcano_module(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue