forked from github/server
Merge branch 'master' of github.com:eressea/server
This commit is contained in:
commit
a5961d069c
|
@ -68,6 +68,7 @@ set (ERESSEA_SRC
|
||||||
battle.c
|
battle.c
|
||||||
alchemy.c
|
alchemy.c
|
||||||
stealth.c
|
stealth.c
|
||||||
|
upkeep.c
|
||||||
vortex.c
|
vortex.c
|
||||||
names.c
|
names.c
|
||||||
reports.c
|
reports.c
|
||||||
|
@ -159,15 +160,16 @@ set(TESTS_SRC
|
||||||
tests.test.c
|
tests.test.c
|
||||||
reports.test.c
|
reports.test.c
|
||||||
stealth.test.c
|
stealth.test.c
|
||||||
move.test.c
|
|
||||||
callback.test.c
|
callback.test.c
|
||||||
direction.test.c
|
direction.test.c
|
||||||
keyword.test.c
|
|
||||||
skill.test.c
|
|
||||||
json.test.c
|
|
||||||
economy.test.c
|
economy.test.c
|
||||||
market.test.c
|
json.test.c
|
||||||
|
keyword.test.c
|
||||||
laws.test.c
|
laws.test.c
|
||||||
|
market.test.c
|
||||||
|
move.test.c
|
||||||
|
skill.test.c
|
||||||
|
upkeep.test.c
|
||||||
${UTIL_TESTS}
|
${UTIL_TESTS}
|
||||||
${KERNEL_TESTS}
|
${KERNEL_TESTS}
|
||||||
${ERESSEA_SRC}
|
${ERESSEA_SRC}
|
||||||
|
|
|
@ -11,11 +11,13 @@ without prior permission by the authors of Eressea.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <platform.h>
|
#include <platform.h>
|
||||||
|
#include <kernel/types.h>
|
||||||
#include "bind_faction.h"
|
#include "bind_faction.h"
|
||||||
#include "bind_unit.h"
|
#include "bind_unit.h"
|
||||||
#include "bindings.h"
|
#include "bindings.h"
|
||||||
|
|
||||||
#include <kernel/alliance.h>
|
#include <kernel/alliance.h>
|
||||||
|
#include <kernel/faction.h>
|
||||||
#include <kernel/config.h>
|
#include <kernel/config.h>
|
||||||
#include <kernel/unit.h>
|
#include <kernel/unit.h>
|
||||||
#include <kernel/item.h>
|
#include <kernel/item.h>
|
||||||
|
@ -452,8 +454,8 @@ static int tolua_faction_get_alliance(lua_State * L)
|
||||||
|
|
||||||
static int tolua_faction_set_alliance(lua_State * L)
|
static int tolua_faction_set_alliance(lua_State * L)
|
||||||
{
|
{
|
||||||
faction *self = (faction *) tolua_tousertype(L, 1, 0);
|
struct faction *self = (struct faction *)tolua_tousertype(L, 1, 0);
|
||||||
alliance *alli = (alliance *) tolua_tousertype(L, 2, 0);
|
struct alliance *alli = (struct alliance *) tolua_tousertype(L, 2, 0);
|
||||||
|
|
||||||
setalliance(self, alli);
|
setalliance(self, alli);
|
||||||
|
|
||||||
|
|
|
@ -2154,6 +2154,13 @@ static void buy(unit * u, request ** buyorders, struct order *ord)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ------------------------------------------------------------- */
|
/* ------------------------------------------------------------- */
|
||||||
|
static void add_income(unit * u, int type, int want, int qty)
|
||||||
|
{
|
||||||
|
if (want == INT_MAX)
|
||||||
|
want = qty;
|
||||||
|
ADDMSG(&u->faction->msgs, msg_message("income",
|
||||||
|
"unit region mode wanted amount", u, u->region, type, want, qty));
|
||||||
|
}
|
||||||
|
|
||||||
/* Steuersätze in % bei Burggröße */
|
/* Steuersätze in % bei Burggröße */
|
||||||
static int tax_per_size[7] = { 0, 6, 12, 18, 24, 30, 36 };
|
static int tax_per_size[7] = { 0, 6, 12, 18, 24, 30, 36 };
|
||||||
|
|
|
@ -2240,27 +2240,6 @@ int besieged(const unit * u)
|
||||||
&& u->building->besieged >= u->building->size * SIEGEFACTOR);
|
&& u->building->besieged >= u->building->size * SIEGEFACTOR);
|
||||||
}
|
}
|
||||||
|
|
||||||
int lifestyle(const unit * u)
|
|
||||||
{
|
|
||||||
int need;
|
|
||||||
plane *pl;
|
|
||||||
static int gamecookie = -1;
|
|
||||||
if (gamecookie != global.cookie) {
|
|
||||||
gamecookie = global.cookie;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (is_monsters(u->faction))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
need = maintenance_cost(u);
|
|
||||||
|
|
||||||
pl = rplane(u->region);
|
|
||||||
if (pl && fval(pl, PFL_NOFEED))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
return need;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool has_horses(const struct unit * u)
|
bool has_horses(const struct unit * u)
|
||||||
{
|
{
|
||||||
item *itm = u->items;
|
item *itm = u->items;
|
||||||
|
@ -2271,56 +2250,6 @@ bool has_horses(const struct unit * u)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool hunger(int number, unit * u)
|
|
||||||
{
|
|
||||||
region *r = u->region;
|
|
||||||
int dead = 0, hpsub = 0;
|
|
||||||
int hp = u->hp / u->number;
|
|
||||||
static const char *damage = 0;
|
|
||||||
static const char *rcdamage = 0;
|
|
||||||
static const race *rc = 0;
|
|
||||||
|
|
||||||
if (!damage) {
|
|
||||||
damage = get_param(global.parameters, "hunger.damage");
|
|
||||||
if (damage == NULL)
|
|
||||||
damage = "1d12+12";
|
|
||||||
}
|
|
||||||
if (rc != u_race(u)) {
|
|
||||||
rcdamage = get_param(u_race(u)->parameters, "hunger.damage");
|
|
||||||
rc = u_race(u);
|
|
||||||
}
|
|
||||||
|
|
||||||
while (number--) {
|
|
||||||
int dam = dice_rand(rcdamage ? rcdamage : damage);
|
|
||||||
if (dam >= hp) {
|
|
||||||
++dead;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
hpsub += dam;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (dead) {
|
|
||||||
/* Gestorbene aus der Einheit nehmen,
|
|
||||||
* Sie bekommen keine Beerdingung. */
|
|
||||||
ADDMSG(&u->faction->msgs, msg_message("starvation",
|
|
||||||
"unit region dead live", u, r, dead, u->number - dead));
|
|
||||||
|
|
||||||
scale_number(u, u->number - dead);
|
|
||||||
deathcounts(r, dead);
|
|
||||||
}
|
|
||||||
if (hpsub > 0) {
|
|
||||||
/* Jetzt die Schäden der nicht gestorbenen abziehen. */
|
|
||||||
u->hp -= hpsub;
|
|
||||||
/* Meldung nur, wenn noch keine für Tote generiert. */
|
|
||||||
if (dead == 0) {
|
|
||||||
/* Durch unzureichende Ernährung wird %s geschwächt */
|
|
||||||
ADDMSG(&u->faction->msgs, msg_message("malnourish", "unit region", u, r));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return (dead || hpsub);
|
|
||||||
}
|
|
||||||
|
|
||||||
void plagues(region * r, bool ismagic)
|
void plagues(region * r, bool ismagic)
|
||||||
{
|
{
|
||||||
int peasants;
|
int peasants;
|
||||||
|
@ -2653,51 +2582,6 @@ int maintenance_cost(const struct unit *u)
|
||||||
return u_race(u)->maintenance * u->number;
|
return u_race(u)->maintenance * u->number;
|
||||||
}
|
}
|
||||||
|
|
||||||
message *movement_error(unit * u, const char *token, order * ord,
|
|
||||||
int error_code)
|
|
||||||
{
|
|
||||||
direction_t d;
|
|
||||||
switch (error_code) {
|
|
||||||
case E_MOVE_BLOCKED:
|
|
||||||
d = get_direction(token, u->faction->locale);
|
|
||||||
return msg_message("moveblocked", "unit direction", u, d);
|
|
||||||
case E_MOVE_NOREGION:
|
|
||||||
return msg_feedback(u, ord, "unknowndirection", "dirname", token);
|
|
||||||
}
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool move_blocked(const unit * u, const region * r, const region * r2)
|
|
||||||
{
|
|
||||||
connection *b;
|
|
||||||
curse *c;
|
|
||||||
static const curse_type *fogtrap_ct = NULL;
|
|
||||||
|
|
||||||
if (r2 == NULL)
|
|
||||||
return true;
|
|
||||||
b = get_borders(r, r2);
|
|
||||||
while (b) {
|
|
||||||
if (b->type->block && b->type->block(b, u, r))
|
|
||||||
return true;
|
|
||||||
b = b->next;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (fogtrap_ct == NULL)
|
|
||||||
fogtrap_ct = ct_find("fogtrap");
|
|
||||||
c = get_curse(r->attribs, fogtrap_ct);
|
|
||||||
if (curse_active(c))
|
|
||||||
return true;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void add_income(unit * u, int type, int want, int qty)
|
|
||||||
{
|
|
||||||
if (want == INT_MAX)
|
|
||||||
want = qty;
|
|
||||||
ADDMSG(&u->faction->msgs, msg_message("income",
|
|
||||||
"unit region mode wanted amount", u, u->region, type, want, qty));
|
|
||||||
}
|
|
||||||
|
|
||||||
int produceexp(struct unit *u, skill_t sk, int n)
|
int produceexp(struct unit *u, skill_t sk, int n)
|
||||||
{
|
{
|
||||||
if (global.producexpchance > 0.0F) {
|
if (global.producexpchance > 0.0F) {
|
||||||
|
|
|
@ -324,8 +324,6 @@ extern "C" {
|
||||||
*/
|
*/
|
||||||
unsigned int guard_flags(const struct unit *u);
|
unsigned int guard_flags(const struct unit *u);
|
||||||
|
|
||||||
bool hunger(int number, struct unit *u);
|
|
||||||
int lifestyle(const struct unit *);
|
|
||||||
int besieged(const struct unit *u);
|
int besieged(const struct unit *u);
|
||||||
int maxworkingpeasants(const struct region *r);
|
int maxworkingpeasants(const struct region *r);
|
||||||
bool has_horses(const struct unit *u);
|
bool has_horses(const struct unit *u);
|
||||||
|
@ -333,11 +331,6 @@ extern "C" {
|
||||||
int wage(const struct region *r, const struct faction *f,
|
int wage(const struct region *r, const struct faction *f,
|
||||||
const struct race *rc, int in_turn);
|
const struct race *rc, int in_turn);
|
||||||
int maintenance_cost(const struct unit *u);
|
int maintenance_cost(const struct unit *u);
|
||||||
struct message *movement_error(struct unit *u, const char *token,
|
|
||||||
struct order *ord, int error_code);
|
|
||||||
bool move_blocked(const struct unit *u, const struct region *src,
|
|
||||||
const struct region *dest);
|
|
||||||
void add_income(struct unit *u, int type, int want, int qty);
|
|
||||||
|
|
||||||
const char *datapath(void);
|
const char *datapath(void);
|
||||||
void set_datapath(const char *path);
|
void set_datapath(const char *path);
|
||||||
|
|
|
@ -277,7 +277,7 @@ rel_to_abs(const struct plane *pl, const struct faction *f, int rel,
|
||||||
return (rel + ursprung_y(f, pl, NULL) + plane_center_y(pl));
|
return (rel + ursprung_y(f, pl, NULL) + plane_center_y(pl));
|
||||||
}
|
}
|
||||||
|
|
||||||
int resolve_plane(variant id, void *addr)
|
static int resolve_plane(variant id, void *addr)
|
||||||
{
|
{
|
||||||
int result = 0;
|
int result = 0;
|
||||||
plane *pl = NULL;
|
plane *pl = NULL;
|
||||||
|
|
|
@ -74,7 +74,6 @@ extern "C" {
|
||||||
extern int rel_to_abs(const struct plane *pl, const struct faction *f,
|
extern int rel_to_abs(const struct plane *pl, const struct faction *f,
|
||||||
int rel, unsigned char index);
|
int rel, unsigned char index);
|
||||||
extern bool is_watcher(const struct plane *p, const struct faction *f);
|
extern bool is_watcher(const struct plane *p, const struct faction *f);
|
||||||
extern int resolve_plane(variant data, void *addr);
|
|
||||||
extern void write_plane_reference(const plane * p, struct storage *store);
|
extern void write_plane_reference(const plane * p, struct storage *store);
|
||||||
extern int read_plane_reference(plane ** pp, struct storage *store);
|
extern int read_plane_reference(plane ** pp, struct storage *store);
|
||||||
extern int plane_width(const plane * pl);
|
extern int plane_width(const plane * pl);
|
||||||
|
|
|
@ -1,9 +1,11 @@
|
||||||
#include <platform.h>
|
#include <platform.h>
|
||||||
#include "kernel/types.h"
|
#include "kernel/types.h"
|
||||||
|
#include "kernel/config.h"
|
||||||
#include "keyword.h"
|
#include "keyword.h"
|
||||||
#include "util/language.h"
|
#include "util/language.h"
|
||||||
#include "tests.h"
|
#include "tests.h"
|
||||||
|
|
||||||
|
#include <critbit.h>
|
||||||
#include <CuTest.h>
|
#include <CuTest.h>
|
||||||
|
|
||||||
static void test_init_keywords(CuTest *tc) {
|
static void test_init_keywords(CuTest *tc) {
|
||||||
|
@ -51,6 +53,24 @@ static void test_get_keyword_default(CuTest *tc) {
|
||||||
CuAssertIntEquals(tc, K_STUDY, get_keyword("study", lang));
|
CuAssertIntEquals(tc, K_STUDY, get_keyword("study", lang));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void test_get_shortest_match(CuTest *tc) {
|
||||||
|
struct locale *lang;
|
||||||
|
critbit_tree ** cb;
|
||||||
|
|
||||||
|
test_cleanup();
|
||||||
|
lang = get_or_create_locale("en");
|
||||||
|
|
||||||
|
cb = (critbit_tree **)get_translations(lang, UT_KEYWORDS);
|
||||||
|
/* note that the english order is FIGHT, not COMBAT, so this is a poor example */
|
||||||
|
add_translation(cb, "COMBAT", K_STATUS);
|
||||||
|
add_translation(cb, "COMBATSPELL", K_COMBATSPELL);
|
||||||
|
|
||||||
|
CuAssertIntEquals(tc, NOKEYWORD, get_keyword("", lang));
|
||||||
|
CuAssertIntEquals(tc, K_STATUS, get_keyword("COM", lang));
|
||||||
|
CuAssertIntEquals(tc, K_STATUS, get_keyword("COMBAT", lang));
|
||||||
|
CuAssertIntEquals(tc, K_COMBATSPELL, get_keyword("COMBATS", lang));
|
||||||
|
}
|
||||||
|
|
||||||
#define SUITE_DISABLE_TEST(suite, test) (void)test
|
#define SUITE_DISABLE_TEST(suite, test) (void)test
|
||||||
|
|
||||||
CuSuite *get_keyword_suite(void)
|
CuSuite *get_keyword_suite(void)
|
||||||
|
@ -59,6 +79,7 @@ CuSuite *get_keyword_suite(void)
|
||||||
SUITE_ADD_TEST(suite, test_init_keyword);
|
SUITE_ADD_TEST(suite, test_init_keyword);
|
||||||
SUITE_ADD_TEST(suite, test_init_keywords);
|
SUITE_ADD_TEST(suite, test_init_keywords);
|
||||||
SUITE_ADD_TEST(suite, test_findkeyword);
|
SUITE_ADD_TEST(suite, test_findkeyword);
|
||||||
|
SUITE_ADD_TEST(suite, test_get_shortest_match);
|
||||||
SUITE_DISABLE_TEST(suite, test_get_keyword_default);
|
SUITE_DISABLE_TEST(suite, test_get_keyword_default);
|
||||||
return suite;
|
return suite;
|
||||||
}
|
}
|
||||||
|
|
223
src/laws.c
223
src/laws.c
|
@ -138,229 +138,6 @@ static void checkorders(void)
|
||||||
ADDMSG(&f->msgs, msg_message("turnreminder", ""));
|
ADDMSG(&f->msgs, msg_message("turnreminder", ""));
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool help_money(const unit * u)
|
|
||||||
{
|
|
||||||
if (u_race(u)->ec_flags & GIVEITEM)
|
|
||||||
return true;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void help_feed(unit * donor, unit * u, int *need_p)
|
|
||||||
{
|
|
||||||
int need = *need_p;
|
|
||||||
int give = get_money(donor) - lifestyle(donor);
|
|
||||||
give = _min(need, give);
|
|
||||||
|
|
||||||
if (give > 0) {
|
|
||||||
change_money(donor, -give);
|
|
||||||
change_money(u, give);
|
|
||||||
need -= give;
|
|
||||||
add_spende(donor->faction, u->faction, give, donor->region);
|
|
||||||
}
|
|
||||||
*need_p = need;
|
|
||||||
}
|
|
||||||
|
|
||||||
enum {
|
|
||||||
FOOD_FROM_PEASANTS = 1,
|
|
||||||
FOOD_FROM_OWNER = 2,
|
|
||||||
FOOD_IS_FREE = 4
|
|
||||||
};
|
|
||||||
|
|
||||||
void get_food(region * r)
|
|
||||||
{
|
|
||||||
plane *pl = rplane(r);
|
|
||||||
unit *u;
|
|
||||||
int peasantfood = rpeasants(r) * 10;
|
|
||||||
static int food_rules = -1;
|
|
||||||
static int gamecookie = -1;
|
|
||||||
|
|
||||||
if (food_rules < 0 || gamecookie != global.cookie) {
|
|
||||||
gamecookie = global.cookie;
|
|
||||||
food_rules = get_param_int(global.parameters, "rules.economy.food", 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (food_rules & FOOD_IS_FREE) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
/* 1. Versorgung von eigenen Einheiten. Das vorhandene Silber
|
|
||||||
* wird zunächst so auf die Einheiten aufgeteilt, dass idealerweise
|
|
||||||
* jede Einheit genug Silber für ihren Unterhalt hat. */
|
|
||||||
|
|
||||||
for (u = r->units; u; u = u->next) {
|
|
||||||
int need = lifestyle(u);
|
|
||||||
|
|
||||||
/* Erstmal zurücksetzen */
|
|
||||||
freset(u, UFL_HUNGER);
|
|
||||||
|
|
||||||
if (u->ship && (u->ship->flags & SF_FISHING)) {
|
|
||||||
unit *v;
|
|
||||||
int c = 2;
|
|
||||||
for (v = u; c > 0 && v; v = v->next) {
|
|
||||||
if (v->ship == u->ship) {
|
|
||||||
int get = 0;
|
|
||||||
if (v->number <= c) {
|
|
||||||
get = lifestyle(v);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
get = lifestyle(v) * c / v->number;
|
|
||||||
}
|
|
||||||
if (get) {
|
|
||||||
change_money(v, get);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
c -= v->number;
|
|
||||||
}
|
|
||||||
u->ship->flags -= SF_FISHING;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (food_rules & FOOD_FROM_PEASANTS) {
|
|
||||||
faction *owner = region_get_owner(r);
|
|
||||||
/* if the region is owned, and the owner is nice, then we'll get
|
|
||||||
* food from the peasants - should not be used with WORK */
|
|
||||||
if (owner != NULL && (get_alliance(owner, u->faction) & HELP_MONEY)) {
|
|
||||||
int rm = rmoney(r);
|
|
||||||
int use = _min(rm, need);
|
|
||||||
rsetmoney(r, rm - use);
|
|
||||||
need -= use;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
need -= get_money(u);
|
|
||||||
if (need > 0) {
|
|
||||||
unit *v;
|
|
||||||
|
|
||||||
for (v = r->units; need && v; v = v->next) {
|
|
||||||
if (v->faction == u->faction && help_money(v)) {
|
|
||||||
int give = get_money(v) - lifestyle(v);
|
|
||||||
give = _min(need, give);
|
|
||||||
if (give > 0) {
|
|
||||||
change_money(v, -give);
|
|
||||||
change_money(u, give);
|
|
||||||
need -= give;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 2. Versorgung durch Fremde. Das Silber alliierter Einheiten wird
|
|
||||||
* entsprechend verteilt. */
|
|
||||||
for (u = r->units; u; u = u->next) {
|
|
||||||
int need = lifestyle(u);
|
|
||||||
faction *f = u->faction;
|
|
||||||
|
|
||||||
need -= _max(0, get_money(u));
|
|
||||||
|
|
||||||
if (need > 0) {
|
|
||||||
unit *v;
|
|
||||||
|
|
||||||
if (food_rules & FOOD_FROM_OWNER) {
|
|
||||||
/* the owner of the region is the first faction to help out when you're hungry */
|
|
||||||
faction *owner = region_get_owner(r);
|
|
||||||
if (owner && owner != u->faction) {
|
|
||||||
for (v = r->units; v; v = v->next) {
|
|
||||||
if (v->faction == owner && alliedunit(v, f, HELP_MONEY)
|
|
||||||
&& help_money(v)) {
|
|
||||||
help_feed(v, u, &need);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (v = r->units; need && v; v = v->next) {
|
|
||||||
if (v->faction != f && alliedunit(v, f, HELP_MONEY)
|
|
||||||
&& help_money(v)) {
|
|
||||||
help_feed(v, u, &need);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Die Einheit hat nicht genug Geld zusammengekratzt und
|
|
||||||
* nimmt Schaden: */
|
|
||||||
if (need > 0) {
|
|
||||||
int lspp = lifestyle(u) / u->number;
|
|
||||||
if (lspp > 0) {
|
|
||||||
int number = (need + lspp - 1) / lspp;
|
|
||||||
if (hunger(number, u))
|
|
||||||
fset(u, UFL_HUNGER);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 3. bestimmen, wie viele Bauern gefressen werden.
|
|
||||||
* bei fehlenden Bauern den Dämon hungern lassen
|
|
||||||
*/
|
|
||||||
for (u = r->units; u; u = u->next) {
|
|
||||||
if (u_race(u) == get_race(RC_DAEMON)) {
|
|
||||||
int hungry = u->number;
|
|
||||||
|
|
||||||
/* use peasantblood before eating the peasants themselves */
|
|
||||||
const struct potion_type *pt_blood = 0;
|
|
||||||
const resource_type *rt_blood = rt_find("peasantblood");
|
|
||||||
if (rt_blood) {
|
|
||||||
pt_blood = rt_blood->ptype;
|
|
||||||
}
|
|
||||||
if (pt_blood) {
|
|
||||||
/* always start with the unit itself, then the first known unit that may have some blood */
|
|
||||||
unit *donor = u;
|
|
||||||
while (donor != NULL && hungry > 0) {
|
|
||||||
int blut = get_effect(donor, pt_blood);
|
|
||||||
blut = _min(blut, hungry);
|
|
||||||
if (blut) {
|
|
||||||
change_effect(donor, pt_blood, -blut);
|
|
||||||
hungry -= blut;
|
|
||||||
}
|
|
||||||
if (donor == u)
|
|
||||||
donor = r->units;
|
|
||||||
while (donor != NULL) {
|
|
||||||
if (u_race(donor) == get_race(RC_DAEMON) && donor != u) {
|
|
||||||
if (get_effect(donor, pt_blood)) {
|
|
||||||
/* if he's in our faction, drain him: */
|
|
||||||
if (donor->faction == u->faction)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
donor = donor->next;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/* remaining demons feed on peasants */
|
|
||||||
if (pl == NULL || !fval(pl, PFL_NOFEED)) {
|
|
||||||
if (peasantfood >= hungry) {
|
|
||||||
peasantfood -= hungry;
|
|
||||||
hungry = 0;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
hungry -= peasantfood;
|
|
||||||
peasantfood = 0;
|
|
||||||
}
|
|
||||||
if (hungry > 0) {
|
|
||||||
static int demon_hunger = -1;
|
|
||||||
if (demon_hunger < 0) {
|
|
||||||
demon_hunger = get_param_int(global.parameters, "hunger.demons", 0);
|
|
||||||
}
|
|
||||||
if (demon_hunger == 0) {
|
|
||||||
/* demons who don't feed are hungry */
|
|
||||||
if (hunger(hungry, u))
|
|
||||||
fset(u, UFL_HUNGER);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
/* no damage, but set the hungry-flag */
|
|
||||||
fset(u, UFL_HUNGER);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
rsetpeasants(r, peasantfood / 10);
|
|
||||||
|
|
||||||
/* 3. Von den überlebenden das Geld abziehen: */
|
|
||||||
for (u = r->units; u; u = u->next) {
|
|
||||||
int need = _min(get_money(u), lifestyle(u));
|
|
||||||
change_money(u, -need);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void age_unit(region * r, unit * u)
|
static void age_unit(region * r, unit * u)
|
||||||
{
|
{
|
||||||
if (u_race(u) == get_race(RC_SPELL)) {
|
if (u_race(u) == get_race(RC_SPELL)) {
|
||||||
|
|
37
src/move.c
37
src/move.c
|
@ -1069,6 +1069,29 @@ unit *is_guarded(region * r, unit * u, unsigned int mask)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool move_blocked(const unit * u, const region * r, const region * r2)
|
||||||
|
{
|
||||||
|
connection *b;
|
||||||
|
curse *c;
|
||||||
|
static const curse_type *fogtrap_ct = NULL;
|
||||||
|
|
||||||
|
if (r2 == NULL)
|
||||||
|
return true;
|
||||||
|
b = get_borders(r, r2);
|
||||||
|
while (b) {
|
||||||
|
if (b->type->block && b->type->block(b, u, r))
|
||||||
|
return true;
|
||||||
|
b = b->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fogtrap_ct == NULL)
|
||||||
|
fogtrap_ct = ct_find("fogtrap");
|
||||||
|
c = get_curse(r->attribs, fogtrap_ct);
|
||||||
|
if (curse_active(c))
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
int movewhere(const unit * u, const char *token, region * r, region ** resultp)
|
int movewhere(const unit * u, const char *token, region * r, region ** resultp)
|
||||||
{
|
{
|
||||||
region *r2;
|
region *r2;
|
||||||
|
@ -1389,6 +1412,20 @@ static const region_list *reroute(unit * u, const region_list * route,
|
||||||
return route;
|
return route;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static message *movement_error(unit * u, const char *token, order * ord,
|
||||||
|
int error_code)
|
||||||
|
{
|
||||||
|
direction_t d;
|
||||||
|
switch (error_code) {
|
||||||
|
case E_MOVE_BLOCKED:
|
||||||
|
d = get_direction(token, u->faction->locale);
|
||||||
|
return msg_message("moveblocked", "unit direction", u, d);
|
||||||
|
case E_MOVE_NOREGION:
|
||||||
|
return msg_feedback(u, ord, "unknowndirection", "dirname", token);
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
static void make_route(unit * u, order * ord, region_list ** routep)
|
static void make_route(unit * u, order * ord, region_list ** routep)
|
||||||
{
|
{
|
||||||
region_list **iroute = routep;
|
region_list **iroute = routep;
|
||||||
|
|
|
@ -79,6 +79,8 @@ extern "C" {
|
||||||
const struct building_type *bt, bool working);
|
const struct building_type *bt, bool working);
|
||||||
struct unit *owner_buildingtyp(const struct region *r,
|
struct unit *owner_buildingtyp(const struct region *r,
|
||||||
const struct building_type *bt);
|
const struct building_type *bt);
|
||||||
|
bool move_blocked(const struct unit *u, const struct region *src,
|
||||||
|
const struct region *dest);
|
||||||
|
|
||||||
#define SA_HARBOUR 2
|
#define SA_HARBOUR 2
|
||||||
#define SA_COAST 1
|
#define SA_COAST 1
|
||||||
|
|
|
@ -32,12 +32,10 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
#include <attributes/reduceproduction.h>
|
#include <attributes/reduceproduction.h>
|
||||||
|
|
||||||
/* gamecode includes */
|
/* gamecode includes */
|
||||||
#include "creport.h"
|
|
||||||
#include "economy.h"
|
|
||||||
#include "monster.h"
|
|
||||||
#include "laws.h"
|
|
||||||
#include "move.h"
|
|
||||||
#include "alchemy.h"
|
#include "alchemy.h"
|
||||||
|
#include "economy.h"
|
||||||
|
#include "move.h"
|
||||||
|
#include "upkeep.h"
|
||||||
#include "vortex.h"
|
#include "vortex.h"
|
||||||
|
|
||||||
/* kernel includes */
|
/* kernel includes */
|
||||||
|
|
|
@ -58,6 +58,7 @@ int RunAllTests(void)
|
||||||
ADD_TESTS(suite, market);
|
ADD_TESTS(suite, market);
|
||||||
ADD_TESTS(suite, move);
|
ADD_TESTS(suite, move);
|
||||||
ADD_TESTS(suite, stealth);
|
ADD_TESTS(suite, stealth);
|
||||||
|
ADD_TESTS(suite, upkeep);
|
||||||
ADD_TESTS(suite, vortex);
|
ADD_TESTS(suite, vortex);
|
||||||
|
|
||||||
CuSuiteRun(suite);
|
CuSuiteRun(suite);
|
||||||
|
|
|
@ -0,0 +1,308 @@
|
||||||
|
#include <platform.h>
|
||||||
|
#include "upkeep.h"
|
||||||
|
|
||||||
|
#include <kernel/types.h>
|
||||||
|
#include <kernel/faction.h>
|
||||||
|
#include <kernel/config.h>
|
||||||
|
#include <kernel/item.h>
|
||||||
|
#include <kernel/messages.h>
|
||||||
|
#include <kernel/plane.h>
|
||||||
|
#include <kernel/race.h>
|
||||||
|
#include <kernel/region.h>
|
||||||
|
#include <kernel/ship.h>
|
||||||
|
#include <kernel/unit.h>
|
||||||
|
|
||||||
|
#include <util/rand.h>
|
||||||
|
|
||||||
|
#include "alchemy.h"
|
||||||
|
#include "economy.h"
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
int lifestyle(const unit * u)
|
||||||
|
{
|
||||||
|
int need;
|
||||||
|
plane *pl;
|
||||||
|
static int gamecookie = -1;
|
||||||
|
if (gamecookie != global.cookie) {
|
||||||
|
gamecookie = global.cookie;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_monsters(u->faction))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
need = maintenance_cost(u);
|
||||||
|
|
||||||
|
pl = rplane(u->region);
|
||||||
|
if (pl && fval(pl, PFL_NOFEED))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return need;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool help_money(const unit * u)
|
||||||
|
{
|
||||||
|
if (u_race(u)->ec_flags & GIVEITEM)
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void help_feed(unit * donor, unit * u, int *need_p)
|
||||||
|
{
|
||||||
|
int need = *need_p;
|
||||||
|
int give = get_money(donor) - lifestyle(donor);
|
||||||
|
give = _min(need, give);
|
||||||
|
|
||||||
|
if (give > 0) {
|
||||||
|
change_money(donor, -give);
|
||||||
|
change_money(u, give);
|
||||||
|
need -= give;
|
||||||
|
add_spende(donor->faction, u->faction, give, donor->region);
|
||||||
|
}
|
||||||
|
*need_p = need;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool hunger(int number, unit * u)
|
||||||
|
{
|
||||||
|
region *r = u->region;
|
||||||
|
int dead = 0, hpsub = 0;
|
||||||
|
int hp = u->hp / u->number;
|
||||||
|
static const char *damage = 0;
|
||||||
|
static const char *rcdamage = 0;
|
||||||
|
static const race *rc = 0;
|
||||||
|
|
||||||
|
if (!damage) {
|
||||||
|
damage = get_param(global.parameters, "hunger.damage");
|
||||||
|
if (damage == NULL)
|
||||||
|
damage = "1d12+12";
|
||||||
|
}
|
||||||
|
if (rc != u_race(u)) {
|
||||||
|
rcdamage = get_param(u_race(u)->parameters, "hunger.damage");
|
||||||
|
rc = u_race(u);
|
||||||
|
}
|
||||||
|
|
||||||
|
while (number--) {
|
||||||
|
int dam = dice_rand(rcdamage ? rcdamage : damage);
|
||||||
|
if (dam >= hp) {
|
||||||
|
++dead;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
hpsub += dam;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dead) {
|
||||||
|
/* Gestorbene aus der Einheit nehmen,
|
||||||
|
* Sie bekommen keine Beerdingung. */
|
||||||
|
ADDMSG(&u->faction->msgs, msg_message("starvation",
|
||||||
|
"unit region dead live", u, r, dead, u->number - dead));
|
||||||
|
|
||||||
|
scale_number(u, u->number - dead);
|
||||||
|
deathcounts(r, dead);
|
||||||
|
}
|
||||||
|
if (hpsub > 0) {
|
||||||
|
/* Jetzt die Schäden der nicht gestorbenen abziehen. */
|
||||||
|
u->hp -= hpsub;
|
||||||
|
/* Meldung nur, wenn noch keine für Tote generiert. */
|
||||||
|
if (dead == 0) {
|
||||||
|
/* Durch unzureichende Ernährung wird %s geschwächt */
|
||||||
|
ADDMSG(&u->faction->msgs, msg_message("malnourish", "unit region", u, r));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return (dead || hpsub);
|
||||||
|
}
|
||||||
|
|
||||||
|
void get_food(region * r)
|
||||||
|
{
|
||||||
|
plane *pl = rplane(r);
|
||||||
|
unit *u;
|
||||||
|
int peasantfood = rpeasants(r) * 10;
|
||||||
|
static int food_rules = -1;
|
||||||
|
static int gamecookie = -1;
|
||||||
|
|
||||||
|
if (food_rules < 0 || gamecookie != global.cookie) {
|
||||||
|
gamecookie = global.cookie;
|
||||||
|
food_rules = get_param_int(global.parameters, "rules.economy.food", 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (food_rules & FOOD_IS_FREE) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
/* 1. Versorgung von eigenen Einheiten. Das vorhandene Silber
|
||||||
|
* wird zunächst so auf die Einheiten aufgeteilt, dass idealerweise
|
||||||
|
* jede Einheit genug Silber für ihren Unterhalt hat. */
|
||||||
|
|
||||||
|
for (u = r->units; u; u = u->next) {
|
||||||
|
int need = lifestyle(u);
|
||||||
|
|
||||||
|
/* Erstmal zurücksetzen */
|
||||||
|
freset(u, UFL_HUNGER);
|
||||||
|
|
||||||
|
if (u->ship && (u->ship->flags & SF_FISHING)) {
|
||||||
|
unit *v;
|
||||||
|
int c = 2;
|
||||||
|
for (v = u; c > 0 && v; v = v->next) {
|
||||||
|
if (v->ship == u->ship) {
|
||||||
|
int get = 0;
|
||||||
|
if (v->number <= c) {
|
||||||
|
get = lifestyle(v);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
get = lifestyle(v) * c / v->number;
|
||||||
|
}
|
||||||
|
if (get) {
|
||||||
|
change_money(v, get);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
c -= v->number;
|
||||||
|
}
|
||||||
|
u->ship->flags -= SF_FISHING;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (food_rules & FOOD_FROM_PEASANTS) {
|
||||||
|
struct faction *owner = region_get_owner(r);
|
||||||
|
/* if the region is owned, and the owner is nice, then we'll get
|
||||||
|
* food from the peasants - should not be used with WORK */
|
||||||
|
if (owner != NULL && (get_alliance(owner, u->faction) & HELP_MONEY)) {
|
||||||
|
int rm = rmoney(r);
|
||||||
|
int use = _min(rm, need);
|
||||||
|
rsetmoney(r, rm - use);
|
||||||
|
need -= use;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
need -= get_money(u);
|
||||||
|
if (need > 0) {
|
||||||
|
unit *v;
|
||||||
|
|
||||||
|
for (v = r->units; need && v; v = v->next) {
|
||||||
|
if (v->faction == u->faction && help_money(v)) {
|
||||||
|
int give = get_money(v) - lifestyle(v);
|
||||||
|
give = _min(need, give);
|
||||||
|
if (give > 0) {
|
||||||
|
change_money(v, -give);
|
||||||
|
change_money(u, give);
|
||||||
|
need -= give;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 2. Versorgung durch Fremde. Das Silber alliierter Einheiten wird
|
||||||
|
* entsprechend verteilt. */
|
||||||
|
for (u = r->units; u; u = u->next) {
|
||||||
|
int need = lifestyle(u);
|
||||||
|
faction *f = u->faction;
|
||||||
|
|
||||||
|
need -= _max(0, get_money(u));
|
||||||
|
|
||||||
|
if (need > 0) {
|
||||||
|
unit *v;
|
||||||
|
|
||||||
|
if (food_rules & FOOD_FROM_OWNER) {
|
||||||
|
/* the owner of the region is the first faction to help out when you're hungry */
|
||||||
|
faction *owner = region_get_owner(r);
|
||||||
|
if (owner && owner != u->faction) {
|
||||||
|
for (v = r->units; v; v = v->next) {
|
||||||
|
if (v->faction == owner && alliedunit(v, f, HELP_MONEY)
|
||||||
|
&& help_money(v)) {
|
||||||
|
help_feed(v, u, &need);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (v = r->units; need && v; v = v->next) {
|
||||||
|
if (v->faction != f && alliedunit(v, f, HELP_MONEY)
|
||||||
|
&& help_money(v)) {
|
||||||
|
help_feed(v, u, &need);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Die Einheit hat nicht genug Geld zusammengekratzt und
|
||||||
|
* nimmt Schaden: */
|
||||||
|
if (need > 0) {
|
||||||
|
int lspp = lifestyle(u) / u->number;
|
||||||
|
if (lspp > 0) {
|
||||||
|
int number = (need + lspp - 1) / lspp;
|
||||||
|
if (hunger(number, u))
|
||||||
|
fset(u, UFL_HUNGER);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 3. bestimmen, wie viele Bauern gefressen werden.
|
||||||
|
* bei fehlenden Bauern den Dämon hungern lassen
|
||||||
|
*/
|
||||||
|
for (u = r->units; u; u = u->next) {
|
||||||
|
if (u_race(u) == get_race(RC_DAEMON)) {
|
||||||
|
int hungry = u->number;
|
||||||
|
|
||||||
|
/* use peasantblood before eating the peasants themselves */
|
||||||
|
const struct potion_type *pt_blood = 0;
|
||||||
|
const resource_type *rt_blood = rt_find("peasantblood");
|
||||||
|
if (rt_blood) {
|
||||||
|
pt_blood = rt_blood->ptype;
|
||||||
|
}
|
||||||
|
if (pt_blood) {
|
||||||
|
/* always start with the unit itself, then the first known unit that may have some blood */
|
||||||
|
unit *donor = u;
|
||||||
|
while (donor != NULL && hungry > 0) {
|
||||||
|
int blut = get_effect(donor, pt_blood);
|
||||||
|
blut = _min(blut, hungry);
|
||||||
|
if (blut) {
|
||||||
|
change_effect(donor, pt_blood, -blut);
|
||||||
|
hungry -= blut;
|
||||||
|
}
|
||||||
|
if (donor == u)
|
||||||
|
donor = r->units;
|
||||||
|
while (donor != NULL) {
|
||||||
|
if (u_race(donor) == get_race(RC_DAEMON) && donor != u) {
|
||||||
|
if (get_effect(donor, pt_blood)) {
|
||||||
|
/* if he's in our faction, drain him: */
|
||||||
|
if (donor->faction == u->faction)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
donor = donor->next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* remaining demons feed on peasants */
|
||||||
|
if (pl == NULL || !fval(pl, PFL_NOFEED)) {
|
||||||
|
if (peasantfood >= hungry) {
|
||||||
|
peasantfood -= hungry;
|
||||||
|
hungry = 0;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
hungry -= peasantfood;
|
||||||
|
peasantfood = 0;
|
||||||
|
}
|
||||||
|
if (hungry > 0) {
|
||||||
|
static int demon_hunger = -1;
|
||||||
|
if (demon_hunger < 0) {
|
||||||
|
demon_hunger = get_param_int(global.parameters, "hunger.demons", 0);
|
||||||
|
}
|
||||||
|
if (demon_hunger == 0) {
|
||||||
|
/* demons who don't feed are hungry */
|
||||||
|
if (hunger(hungry, u))
|
||||||
|
fset(u, UFL_HUNGER);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
/* no damage, but set the hungry-flag */
|
||||||
|
fset(u, UFL_HUNGER);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
rsetpeasants(r, peasantfood / 10);
|
||||||
|
|
||||||
|
/* 3. Von den überlebenden das Geld abziehen: */
|
||||||
|
for (u = r->units; u; u = u->next) {
|
||||||
|
int need = _min(get_money(u), lifestyle(u));
|
||||||
|
change_money(u, -need);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,22 @@
|
||||||
|
#ifndef UPKEEP_H
|
||||||
|
#define UPKEEP_H
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
struct region;
|
||||||
|
struct unit;
|
||||||
|
void get_food(struct region * r);
|
||||||
|
int lifestyle(const struct unit * u);
|
||||||
|
|
||||||
|
enum {
|
||||||
|
FOOD_FROM_PEASANTS = 1,
|
||||||
|
FOOD_FROM_OWNER = 2,
|
||||||
|
FOOD_IS_FREE = 4
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#endif
|
|
@ -0,0 +1,170 @@
|
||||||
|
#include <platform.h>
|
||||||
|
#include "upkeep.h"
|
||||||
|
|
||||||
|
#include <kernel/config.h>
|
||||||
|
#include <kernel/faction.h>
|
||||||
|
#include <kernel/region.h>
|
||||||
|
#include <kernel/unit.h>
|
||||||
|
#include <kernel/item.h>
|
||||||
|
|
||||||
|
#include <CuTest.h>
|
||||||
|
#include <tests.h>
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
void test_upkeep_default(CuTest * tc)
|
||||||
|
{
|
||||||
|
region *r;
|
||||||
|
unit *u1, *u2;
|
||||||
|
faction *f1, *f2;
|
||||||
|
const item_type *i_silver;
|
||||||
|
|
||||||
|
test_cleanup();
|
||||||
|
test_create_world();
|
||||||
|
|
||||||
|
i_silver = it_find("money");
|
||||||
|
assert(i_silver);
|
||||||
|
r = findregion(0, 0);
|
||||||
|
f1 = test_create_faction(test_create_race("human"));
|
||||||
|
f2 = test_create_faction(test_create_race("human"));
|
||||||
|
assert(f1 && f2);
|
||||||
|
u1 = test_create_unit(f1, r);
|
||||||
|
u2 = test_create_unit(f2, r);
|
||||||
|
assert(r && u1 && u2);
|
||||||
|
|
||||||
|
set_param(&global.parameters, "rules.economy.food", "0");
|
||||||
|
i_change(&u1->items, i_silver, 20);
|
||||||
|
get_food(r);
|
||||||
|
// since u1 and u2 are not allied, u1 should not help u2 with upkeep
|
||||||
|
CuAssertIntEquals(tc, 10, i_get(u1->items, i_silver));
|
||||||
|
CuAssertIntEquals(tc, 0, fval(u1, UFL_HUNGER));
|
||||||
|
CuAssertIntEquals(tc, UFL_HUNGER, fval(u2, UFL_HUNGER));
|
||||||
|
|
||||||
|
test_cleanup();
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_upkeep_hunger_damage(CuTest * tc)
|
||||||
|
{
|
||||||
|
region *r;
|
||||||
|
unit *u1;
|
||||||
|
faction *f1;
|
||||||
|
const item_type *i_silver;
|
||||||
|
|
||||||
|
test_cleanup();
|
||||||
|
test_create_world();
|
||||||
|
|
||||||
|
i_silver = it_find("money");
|
||||||
|
assert(i_silver);
|
||||||
|
r = findregion(0, 0);
|
||||||
|
f1 = test_create_faction(test_create_race("human"));
|
||||||
|
u1 = test_create_unit(f1, r);
|
||||||
|
assert(r && u1);
|
||||||
|
|
||||||
|
set_param(&global.parameters, "rules.economy.food", "0");
|
||||||
|
u1->hp = 100;
|
||||||
|
get_food(r);
|
||||||
|
// since u1 and u2 are not allied, u1 should not help u2 with upkeep
|
||||||
|
CuAssertTrue(tc, u1->hp<100);
|
||||||
|
|
||||||
|
test_cleanup();
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_upkeep_from_pool(CuTest * tc)
|
||||||
|
{
|
||||||
|
region *r;
|
||||||
|
unit *u1, *u2;
|
||||||
|
const item_type *i_silver;
|
||||||
|
|
||||||
|
test_cleanup();
|
||||||
|
test_create_world();
|
||||||
|
|
||||||
|
i_silver = it_find("money");
|
||||||
|
assert(i_silver);
|
||||||
|
r = findregion(0, 0);
|
||||||
|
u1 = test_create_unit(test_create_faction(test_create_race("human")), r);
|
||||||
|
u2 = test_create_unit(u1->faction, r);
|
||||||
|
assert(r && u1 && u2);
|
||||||
|
|
||||||
|
set_param(&global.parameters, "rules.economy.food", "0");
|
||||||
|
i_change(&u1->items, i_silver, 30);
|
||||||
|
get_food(r);
|
||||||
|
CuAssertIntEquals(tc, 10, i_get(u1->items, i_silver));
|
||||||
|
CuAssertIntEquals(tc, 0, fval(u1, UFL_HUNGER));
|
||||||
|
CuAssertIntEquals(tc, 0, fval(u2, UFL_HUNGER));
|
||||||
|
get_food(r);
|
||||||
|
CuAssertIntEquals(tc, 0, i_get(u1->items, i_silver));
|
||||||
|
CuAssertIntEquals(tc, 0, fval(u1, UFL_HUNGER));
|
||||||
|
CuAssertIntEquals(tc, UFL_HUNGER, fval(u2, UFL_HUNGER));
|
||||||
|
|
||||||
|
test_cleanup();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void test_upkeep_from_friend(CuTest * tc)
|
||||||
|
{
|
||||||
|
region *r;
|
||||||
|
unit *u1, *u2;
|
||||||
|
faction *f1, *f2;
|
||||||
|
const item_type *i_silver;
|
||||||
|
|
||||||
|
test_cleanup();
|
||||||
|
test_create_world();
|
||||||
|
|
||||||
|
i_silver = it_find("money");
|
||||||
|
assert(i_silver);
|
||||||
|
r = findregion(0, 0);
|
||||||
|
f1 = test_create_faction(test_create_race("human"));
|
||||||
|
f2 = test_create_faction(test_create_race("human"));
|
||||||
|
assert(f1 && f2);
|
||||||
|
set_alliance(f1, f2, HELP_MONEY);
|
||||||
|
u1 = test_create_unit(f1, r);
|
||||||
|
u2 = test_create_unit(f2, r);
|
||||||
|
assert(r && u1 && u2);
|
||||||
|
|
||||||
|
set_param(&global.parameters, "rules.economy.food", "0");
|
||||||
|
i_change(&u1->items, i_silver, 30);
|
||||||
|
get_food(r);
|
||||||
|
CuAssertIntEquals(tc, 10, i_get(u1->items, i_silver));
|
||||||
|
CuAssertIntEquals(tc, 0, fval(u1, UFL_HUNGER));
|
||||||
|
CuAssertIntEquals(tc, 0, fval(u2, UFL_HUNGER));
|
||||||
|
get_food(r);
|
||||||
|
CuAssertIntEquals(tc, 0, i_get(u1->items, i_silver));
|
||||||
|
CuAssertIntEquals(tc, 0, fval(u1, UFL_HUNGER));
|
||||||
|
CuAssertIntEquals(tc, UFL_HUNGER, fval(u2, UFL_HUNGER));
|
||||||
|
|
||||||
|
test_cleanup();
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_upkeep_free(CuTest * tc)
|
||||||
|
{
|
||||||
|
region *r;
|
||||||
|
unit *u;
|
||||||
|
const item_type *i_silver;
|
||||||
|
|
||||||
|
test_cleanup();
|
||||||
|
test_create_world();
|
||||||
|
|
||||||
|
i_silver = it_find("money");
|
||||||
|
assert(i_silver);
|
||||||
|
r = findregion(0, 0);
|
||||||
|
u = test_create_unit(test_create_faction(test_create_race("human")), r);
|
||||||
|
assert(r && u);
|
||||||
|
|
||||||
|
set_param(&global.parameters, "rules.economy.food", "4"); // FOOD_IS_FREE
|
||||||
|
get_food(r);
|
||||||
|
CuAssertIntEquals(tc, 0, i_get(u->items, i_silver));
|
||||||
|
CuAssertIntEquals(tc, 0, fval(u, UFL_HUNGER));
|
||||||
|
|
||||||
|
test_cleanup();
|
||||||
|
}
|
||||||
|
|
||||||
|
CuSuite *get_upkeep_suite(void)
|
||||||
|
{
|
||||||
|
CuSuite *suite = CuSuiteNew();
|
||||||
|
SUITE_ADD_TEST(suite, test_upkeep_default);
|
||||||
|
SUITE_ADD_TEST(suite, test_upkeep_from_pool);
|
||||||
|
SUITE_ADD_TEST(suite, test_upkeep_from_friend);
|
||||||
|
SUITE_ADD_TEST(suite, test_upkeep_hunger_damage);
|
||||||
|
SUITE_ADD_TEST(suite, test_upkeep_free);
|
||||||
|
return suite;
|
||||||
|
}
|
Loading…
Reference in New Issue