Merge branch 'master' of github.com:badgerman/eressea

This commit is contained in:
Enno Rehling 2014-12-10 22:09:45 +00:00
commit ee4eb61811
36 changed files with 431 additions and 513 deletions

View file

@ -84,6 +84,7 @@ set (ERESSEA_SRC
laws.c
magic.c
market.c
morale.c
monster.c
randenc.c
report.c

View file

@ -215,10 +215,6 @@ static int age_potiondelay(attrib * a)
return AT_AGE_REMOVE;
}
/* TODO:
* - this should be a more general item_delay
* - it should not just happen in age(), but be done with eventhandling
*/
attrib_type at_potiondelay = {
"potiondelay",
init_potiondelay,

View file

@ -4,7 +4,6 @@ stealth.test.c
)
SET(_FILES
alliance.c
attributes.c
fleechance.c
follow.c

View file

@ -1,33 +0,0 @@
/*
Copyright (c) 1998-2010, Enno Rehling <enno@eressea.de>
Katja Zedel <katze@felidae.kn-bremen.de
Christian Schlittchen <corwin@amber.kn-bremen.de>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
**/
#include <platform.h>
#include "alliance.h"
#include <kernel/save.h>
#include <util/attrib.h>
attrib_type at_alliance = {
"alliance",
NULL,
NULL,
NULL,
a_writeint,
a_readint,
ATF_UNIQUE
};

View file

@ -37,9 +37,6 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#include "raceprefix.h"
#include "reduceproduction.h"
#include "targetregion.h"
#ifdef WDW_PYRAMID
# include "alliance.h"
#endif
/* kernel includes */
#include <kernel/unit.h>
@ -75,8 +72,4 @@ void register_attributes(void)
at_register(&at_racename);
at_register(&at_movement);
at_register(&at_moved);
#ifdef WDW_PYRAMID
at_register(&at_alliance);
#endif /* WDW_PYRAMID */
}

View file

@ -2052,9 +2052,6 @@ void dazzle(battle * b, troop * td)
td->fighter->person[td->index].defence--;
}
/* TODO: Gebäude/Schiffe sollten auch zerstörbar sein. Schwierig im Kampf,
* besonders bei Schiffen. */
void damage_building(battle * b, building * bldg, int damage_abs)
{
bldg->size = _max(1, bldg->size - damage_abs);
@ -2262,9 +2259,9 @@ static void attack(battle * b, troop ta, const att * a, int numattack)
ta.fighter->person[ta.index].last_action = b->turn;
}
if (td.fighter->unit->ship) {
/* FIXME should use damage_ship here? */
td.fighter->unit->ship->damage +=
DAMAGE_SCALE * dice_rand(a->data.dice);
int dice = dice_rand(a->data.dice);
ship * sh = td.fighter->unit->ship;
damage_ship(sh, dice / sh->type->damage / sh->size);
}
else if (td.fighter->unit->building) {
damage_building(b, td.fighter->unit->building, dice_rand(a->data.dice));
@ -3689,18 +3686,6 @@ static void free_battle(battle * b)
static int *get_alive(side * s)
{
#if 0
static int alive[NUMROWS];
fighter *fig;
memset(alive, 0, NUMROWS * sizeof(int));
for (fig = s->fighters; fig; fig = fig->next) {
if (fig->alive > 0) {
int row = statusrow(fig);
alive[row] += fig->alive;
}
}
return alive;
#endif
return s->size;
}

View file

@ -243,10 +243,6 @@ void tolua_building_open(lua_State * L)
tolua_variable(L, TOLUA_CAST "size", tolua_building_get_size,
tolua_building_set_size);
tolua_function(L, TOLUA_CAST "get_typename", tolua_building_get_typename);
#ifdef TODO
.property("type", &building_gettype)
.def_readwrite("size", &building::size)
#endif
tolua_variable(L, TOLUA_CAST "objects", tolua_building_get_objects, 0);
tolua_variable(L, TOLUA_CAST "working", tolua_building_get_working, tolua_building_set_working);

View file

@ -578,15 +578,6 @@ void tolua_faction_open(lua_State * L)
tolua_function(L, TOLUA_CAST "create", tolua_faction_create);
tolua_function(L, TOLUA_CAST "get", tolua_faction_get);
tolua_function(L, TOLUA_CAST "destroy", tolua_faction_destroy);
#ifdef TODO
def("faction_origin", &faction_getorigin,
pure_out_value(_2) + pure_out_value(_3)),.def_readwrite("subscription",
&faction::subscription)
.property("x", &faction_getorigin_x, &faction_setorigin_x)
.property("y", &faction_getorigin_y, &faction_setorigin_y)
#endif
tolua_function(L, TOLUA_CAST "add_notice", &tolua_faction_addnotice);
tolua_variable(L, TOLUA_CAST "objects", tolua_faction_get_objects,

View file

@ -219,7 +219,6 @@ void tolua_ship_open(lua_State * L)
.property("maxsize", &ship_maxsize)
.def_readwrite("damage", &ship::damage)
.def_readwrite("size", &ship::size)
.def_readwrite("coast", &ship::coast)
#endif
tolua_variable(L, TOLUA_CAST "objects", tolua_ship_get_objects, 0);

View file

@ -29,6 +29,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#include "spy.h"
#include "move.h"
#include "monster.h"
#include "morale.h"
#include "reports.h"
/* kernel includes */
@ -596,12 +597,8 @@ static void recruit(unit * u, struct order *ord, request ** recruitorders)
static void friendly_takeover(region * r, faction * f)
{
int morale = region_get_morale(r);
region_set_owner(r, f, turn);
if (morale > 0) {
morale = _max(0, morale - MORALE_TRANSFER);
region_set_morale(r, morale, turn);
}
morale_change(r, MORALE_TRANSFER);
}
void give_control(unit * u, unit * u2)

View file

@ -210,63 +210,81 @@ struct order *ord)
return 0;
}
void give_men(int n, unit * u, unit * u2, struct order *ord)
static bool can_give_men(const unit *u, order *ord, message **msg) {
if (u_race(u) == get_race(RC_SNOTLING)) {
/* snotlings may not be given to the peasants. */
if (msg) *msg = msg_error(u, ord, 307);
}
else if (unit_has_cursed_item(u)) {
if (msg) *msg = msg_error(u, ord, 78);
}
else if (has_skill(u, SK_MAGIC)) {
/* cannot give units to and from magicians */
if (msg) *msg = msg_error(u, ord, 158);
}
else if (fval(u, UFL_HUNGER)) {
/* hungry people cannot be given away */
if (msg) *msg = msg_error(u, ord, 73);
}
else if (fval(u, UFL_LOCKED) || is_cursed(u->attribs, C_SLAVE, 0)) {
if (msg) *msg = msg_error(u, ord, 74);
}
else {
return true;
}
return false;
}
message * give_men(int n, unit * u, unit * u2, struct order *ord)
{
ship *sh;
int k = 0;
int error = 0;
message * msg;
if (u2 && u->faction != u2->faction && u->faction->age < GiveRestriction()) {
ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "giverestriction",
"turns", GiveRestriction()));
return;
assert(u2);
if (!can_give_men(u, ord, &msg)) {
return msg;
}
if (u->faction != u2->faction && u->faction->age < GiveRestriction()) {
return msg_feedback(u, ord, "giverestriction",
"turns", GiveRestriction());
}
else if (u == u2) {
error = 10;
}
else if (!u2 && u_race(u) == get_race(RC_SNOTLING)) {
/* snotlings may not be given to the peasants. */
error = 307;
}
else if (u2 && u2->number && (fval(u, UFL_HERO) != fval(u2, UFL_HERO))) {
else if (u2->number && (fval(u, UFL_HERO) != fval(u2, UFL_HERO))) {
/* heroes may not be given to non-heroes and vice versa */
error = 75;
}
else if (unit_has_cursed_item(u) || (u2 && unit_has_cursed_item(u2))) {
else if (unit_has_cursed_item(u2)) {
error = 78;
}
else if (fval(u, UFL_LOCKED) || is_cursed(u->attribs, C_SLAVE, 0)) {
error = 74;
}
else if (u2 && fval(u, UFL_HUNGER)) {
/* hungry people cannot be given away */
error = 73;
}
else if (u2 && (fval(u2, UFL_LOCKED) || is_cursed(u2->attribs, C_SLAVE, 0))) {
else if (fval(u2, UFL_LOCKED) || is_cursed(u2->attribs, C_SLAVE, 0)) {
error = 75;
}
else if (u2 && !ucontact(u2, u)) {
ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_no_contact",
"target", u2));
error = -1;
else if (!ucontact(u2, u)) {
return msg_feedback(u, ord, "feedback_no_contact",
"target", u2);
}
else if (u2 && (has_skill(u, SK_MAGIC) || has_skill(u2, SK_MAGIC))) {
else if (has_skill(u2, SK_MAGIC)) {
/* cannot give units to and from magicians */
error = 158;
}
else if (u2 && (fval(u, UFL_WERE) != fval(u2, UFL_WERE))) {
else if (fval(u, UFL_WERE) != fval(u2, UFL_WERE)) {
/* werewolves can't be given to non-werewolves and vice-versa */
error = 312;
}
else if (u2 && u2->number != 0 && u_race(u2) != u_race(u)) {
else if (u2->number != 0 && u_race(u2) != u_race(u)) {
log_debug("faction %s attempts to give %s to %s.\n", itoa36(u->faction->no), u_race(u)->_name, u_race(u2)->_name);
error = 139;
}
else if (u2 != NULL && (get_racename(u2->attribs)
|| get_racename(u->attribs))) {
else if (get_racename(u2->attribs) || get_racename(u->attribs)) {
error = 139;
}
else if (u2 && u2->faction != u->faction && !rule_transfermen()) {
else if (u2->faction != u->faction && !rule_transfermen()) {
error = 74;
}
else {
@ -281,7 +299,7 @@ void give_men(int n, unit * u, unit * u2, struct order *ord)
if (n == 0) {
error = 96;
}
else if (u2 && u->faction != u2->faction) {
else if (u->faction != u2->faction) {
if (u2->faction->newbies + n > MAXNEWBIES) {
error = 129;
}
@ -303,7 +321,7 @@ void give_men(int n, unit * u, unit * u2, struct order *ord)
}
}
if (u2 && (has_skill(u, SK_ALCHEMY) || has_skill(u2, SK_ALCHEMY))) {
if (has_skill(u, SK_ALCHEMY) || has_skill(u2, SK_ALCHEMY)) {
k = count_skill(u2->faction, SK_ALCHEMY);
/* Falls die Zieleinheit keine Alchemisten sind, werden sie nun
@ -327,7 +345,7 @@ void give_men(int n, unit * u, unit * u2, struct order *ord)
}
if (error == 0) {
if (u2 && u2->number == 0) {
if (u2->number == 0) {
set_racename(&u2->attribs, get_racename(u->attribs));
u_setrace(u2, u_race(u));
u2->irace = u->irace;
@ -337,7 +355,6 @@ void give_men(int n, unit * u, unit * u2, struct order *ord)
freset(u2, UFL_HERO);
}
if (u2) {
/* Einheiten von Schiffen können nicht NACH in von
* Nicht-alliierten bewachten Regionen ausführen */
sh = leftship(u);
@ -349,36 +366,34 @@ void give_men(int n, unit * u, unit * u2, struct order *ord)
u2->faction->newbies += n;
}
}
else {
if (getunitpeasants) {
#ifdef ORCIFICATION
if (u_race(u) == get_race(RC_SNOTLING) && !fval(u->region, RF_ORCIFIED)) {
attrib *a = a_find(u->region->attribs, &at_orcification);
if (!a)
a = a_add(&u->region->attribs, a_new(&at_orcification));
a->data.i += n;
}
#endif
transfermen(u, NULL, n);
}
else {
error = 159;
}
}
}
if (error > 0) {
cmistake(u, ord, error, MSG_COMMERCE);
}
else if (!u2) {
ADDMSG(&u->faction->msgs,
msg_message("give_person_peasants", "unit amount", u, n));
return msg_error(u, ord, error);
}
else if (u2->faction != u->faction) {
message *msg = msg_message("give_person", "unit target amount", u, u2, n);
add_message(&u->faction->msgs, msg);
add_message(&u2->faction->msgs, msg);
msg_release(msg);
return msg;
}
return NULL;
}
message * disband_men(int n, unit * u, struct order *ord) {
message * msg;
if (!can_give_men(u, ord, &msg)) {
return msg;
}
transfermen(u, NULL, n);
#ifdef ORCIFICATION
if (u_race(u) == get_race(RC_SNOTLING) && !fval(u->region, RF_ORCIFIED)) {
attrib *a = a_find(u->region->attribs, &at_orcification);
if (!a) {
a = a_add(&u->region->attribs, a_new(&at_orcification));
}
a->data.i += n;
}
#endif
return msg_message("give_person_peasants", "unit amount", u, n);
}
void give_unit(unit * u, unit * u2, order * ord)
@ -411,6 +426,7 @@ void give_unit(unit * u, unit * u2, order * ord)
}
else if (getunitpeasants) {
unit *u3;
message *msg;
for (u3 = r->units; u3; u3 = u3->next)
if (u3->faction == u->faction && u != u3)
@ -428,9 +444,14 @@ void give_unit(unit * u, unit * u2, order * ord)
}
}
}
give_men(u->number, u, NULL, ord);
msg = disband_men(u->number, u, ord);
if (msg) {
ADDMSG(&u->faction->msgs, msg);
}
else {
cmistake(u, ord, 153, MSG_COMMERCE);
}
}
else {
ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_unit_not_found",
""));
@ -669,8 +690,11 @@ void give_cmd(unit * u, order * ord)
msg_feedback(u, ord, "race_noregroup", "race", u_race(u)));
}
else {
n = u->number;
give_men(n, u, u2, ord);
message * msg;
msg = getunitpeasants ? disband_men(u->number, u, ord) : give_men(u->number, u, u2, ord);
if (msg) {
ADDMSG(&u->faction->msgs, msg);
}
}
}
else if (!(u_race(u)->ec_flags & GIVEITEM) && u2 != NULL) {
@ -717,12 +741,16 @@ void give_cmd(unit * u, order * ord)
}
if (isparam(s, u->faction->locale, P_PERSON)) {
message * msg;
if (!(u_race(u)->ec_flags & GIVEPERSON)) {
ADDMSG(&u->faction->msgs,
msg_feedback(u, ord, "race_noregroup", "race", u_race(u)));
return;
}
give_men(n, u, u2, ord);
msg = getunitpeasants ? disband_men(u->number, u, ord) : give_men(u->number, u, u2, ord);
if (msg) {
ADDMSG(&u->faction->msgs, msg);
}
return;
}

View file

@ -19,10 +19,12 @@ extern "C" {
struct item_type;
struct order;
struct unit;
struct message;
int give_item(int want, const struct item_type *itype,
struct unit *src, struct unit *dest, struct order *ord);
void give_men(int n, struct unit *u, struct unit *u2,
struct message * disband_men(int n, struct unit * u, struct order *ord);
struct message * give_men(int n, struct unit *u, struct unit *u2,
struct order *ord);
void give_unit(struct unit *u, struct unit *u2, struct order *ord);
void give_cmd(struct unit * u, struct order * ord);

View file

@ -6,6 +6,7 @@
#include <kernel/config.h>
#include <kernel/item.h>
#include <kernel/terrain.h>
#include <kernel/region.h>
#include <kernel/order.h>
#include <kernel/unit.h>
#include <kernel/faction.h>
@ -29,12 +30,107 @@ struct give {
static void setup_give(struct give *env) {
struct terrain_type *ter = test_create_terrain("plain", LAND_REGION);
env->r = test_create_region(0, 0, ter);
env->src = test_create_unit(env->f1, env->r);
env->dst = test_create_unit(env->f2, env->r);
env->src = env->f1 ? test_create_unit(env->f1, env->r) : 0;
env->dst = env->f2 ? test_create_unit(env->f2, env->r) : 0;
env->itype = it_get_or_create(rt_get_or_create("money"));
env->itype->flags |= ITF_HERB;
}
static void test_give_men(CuTest * tc) {
struct give env;
test_cleanup();
env.f2 = env.f1 = test_create_faction(0);
setup_give(&env);
CuAssertPtrEquals(tc, 0, give_men(1, env.src, env.dst, NULL));
CuAssertIntEquals(tc, 2, env.dst->number);
CuAssertIntEquals(tc, 0, env.src->number);
test_cleanup();
}
static void test_give_men_too_many(CuTest * tc) {
struct give env;
test_cleanup();
env.f2 = env.f1 = test_create_faction(0);
setup_give(&env);
CuAssertPtrEquals(tc, 0, give_men(2, env.src, env.dst, NULL));
CuAssertIntEquals(tc, 2, env.dst->number);
CuAssertIntEquals(tc, 0, env.src->number);
test_cleanup();
}
static void test_give_men_none(CuTest * tc) {
struct give env;
message * msg;
test_cleanup();
env.f2 = env.f1 = test_create_faction(0);
setup_give(&env);
msg = give_men(0, env.src, env.dst, NULL);
CuAssertStrEquals(tc, "error96", (const char *)msg->parameters[3].v);
CuAssertIntEquals(tc, 1, env.dst->number);
CuAssertIntEquals(tc, 1, env.src->number);
test_cleanup();
}
static void test_give_men_other_faction(CuTest * tc) {
struct give env;
message * msg;
test_cleanup();
env.f1 = test_create_faction(0);
env.f2 = test_create_faction(0);
setup_give(&env);
usetcontact(env.dst, env.src);
msg = give_men(1, env.src, env.dst, NULL);
CuAssertStrEquals(tc, "give_person", (const char *)msg->parameters[0].v);
CuAssertIntEquals(tc, 2, env.dst->number);
CuAssertIntEquals(tc, 0, env.src->number);
test_cleanup();
}
static void test_give_men_requires_contact(CuTest * tc) {
struct give env;
message * msg;
test_cleanup();
env.f1 = test_create_faction(0);
env.f2 = test_create_faction(0);
setup_give(&env);
msg = give_men(1, env.src, env.dst, NULL);
CuAssertStrEquals(tc, "feedback_no_contact", (const char *)msg->parameters[3].v);
CuAssertIntEquals(tc, 1, env.dst->number);
CuAssertIntEquals(tc, 1, env.src->number);
test_cleanup();
}
static void test_give_men_not_to_self(CuTest * tc) {
struct give env;
message * msg;
test_cleanup();
env.f2 = env.f1 = test_create_faction(0);
setup_give(&env);
msg = give_men(1, env.src, env.src, NULL);
CuAssertStrEquals(tc, "error10", (const char *)msg->parameters[3].v);
CuAssertIntEquals(tc, 1, env.src->number);
test_cleanup();
}
static void test_give_peasants(CuTest * tc) {
struct give env;
message * msg;
int peasants;
test_cleanup();
env.f1 = test_create_faction(0);
env.f2 = 0;
setup_give(&env);
peasants = env.r->land->peasants;
msg = disband_men(1, env.src, NULL);
CuAssertStrEquals(tc, "give_person_peasants", (const char*)msg->parameters[0].v);
CuAssertIntEquals(tc, 0, env.src->number);
CuAssertIntEquals(tc, peasants+1, env.r->land->peasants);
test_cleanup();
}
static void test_give(CuTest * tc) {
struct give env;
@ -110,6 +206,13 @@ CuSuite *get_give_suite(void)
{
CuSuite *suite = CuSuiteNew();
SUITE_ADD_TEST(suite, test_give);
SUITE_ADD_TEST(suite, test_give_men);
SUITE_ADD_TEST(suite, test_give_men_none);
SUITE_ADD_TEST(suite, test_give_men_too_many);
SUITE_ADD_TEST(suite, test_give_men_other_faction);
SUITE_ADD_TEST(suite, test_give_men_requires_contact);
SUITE_ADD_TEST(suite, test_give_men_not_to_self);
SUITE_ADD_TEST(suite, test_give_peasants);
SUITE_ADD_TEST(suite, test_give_herbs);
SUITE_ADD_TEST(suite, test_give_okay);
SUITE_ADD_TEST(suite, test_give_denied_by_rules);

View file

@ -1,6 +1,7 @@
project(kernel C)
SET(_TEST_FILES
alliance.test.c
build.test.c
config.test.c
group.test.c

View file

@ -43,13 +43,18 @@ without prior permission by the authors of Eressea.
alliance *alliances = NULL;
void free_alliance(alliance * al)
void free_alliances(void)
{
while (alliances) {
alliance *al = alliances;
alliances = al->next;
free(al->name);
if (al->members)
if (al->members) {
ql_free(al->members);
}
free(al);
}
}
alliance *makealliance(int id, const char *name)
{
@ -513,3 +518,7 @@ void alliance_setname(alliance * self, const char *name)
else
self->name = NULL;
}
bool is_allied(const struct faction *f1, const struct faction *f2) {
return (f1 == f2 || (f1->alliance && f1->alliance == f2->alliance));
}

View file

@ -57,9 +57,10 @@ extern "C" {
extern alliance *makealliance(int id, const char *name);
extern const char *alliancename(const struct alliance *al);
extern void setalliance(struct faction *f, alliance * al);
void free_alliance(struct alliance *al);
void free_alliances(void);
extern struct faction *alliance_get_leader(struct alliance *al);
extern void alliance_cmd(void);
bool is_allied(const struct faction *f1, const struct faction *f2);
void alliance_setname(alliance * self, const char *name);
/* execute commands */

View file

@ -0,0 +1,68 @@
#include <platform.h>
#include <kernel/config.h>
#include <kernel/faction.h>
#include "alliance.h"
#include <CuTest.h>
#include <tests.h>
#include <assert.h>
typedef struct alliance_fixture {
struct race * rc;
struct faction *f1, *f2;
} alliance_fixture;
static void setup_alliance(alliance_fixture *fix) {
test_cleanup();
test_create_world();
fix->rc = test_create_race("human");
fix->f1 = test_create_faction(fix->rc);
fix->f2 = test_create_faction(fix->rc);
assert(fix->rc && fix->f1 && fix->f2);
}
static void test_alliance_make(CuTest *tc) {
alliance * al;
test_cleanup();
assert(!alliances);
al = makealliance(1, "Hodor");
CuAssertPtrNotNull(tc, al);
CuAssertStrEquals(tc, "Hodor", al->name);
CuAssertIntEquals(tc, 1, al->id);
CuAssertIntEquals(tc, 0, al->flags);
CuAssertPtrEquals(tc, 0, al->members);
CuAssertPtrEquals(tc, 0, al->_leader);
CuAssertPtrEquals(tc, 0, al->allies);
CuAssertPtrEquals(tc, al, findalliance(1));
CuAssertPtrEquals(tc, al, alliances);
free_alliances();
CuAssertPtrEquals(tc, 0, findalliance(1));
CuAssertPtrEquals(tc, 0, alliances);
test_cleanup();
}
static void test_alliance_join(CuTest *tc) {
alliance_fixture fix;
alliance * al;
setup_alliance(&fix);
CuAssertPtrEquals(tc, 0, fix.f1->alliance);
CuAssertPtrEquals(tc, 0, fix.f2->alliance);
al = makealliance(1, "Hodor");
setalliance(fix.f1, al);
CuAssertPtrEquals(tc, fix.f1, alliance_get_leader(al));
setalliance(fix.f2, al);
CuAssertPtrEquals(tc, fix.f1, alliance_get_leader(al));
CuAssertTrue(tc, is_allied(fix.f1, fix.f2));
test_cleanup();
}
CuSuite *get_alliance_suite(void)
{
CuSuite *suite = CuSuiteNew();
SUITE_ADD_TEST(suite, test_alliance_make);
SUITE_ADD_TEST(suite, test_alliance_join);
return suite;
}

View file

@ -65,7 +65,6 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
/* attributes inclues */
#include <attributes/matmod.h>
#include <attributes/alliance.h>
struct building *getbuilding(const struct region *r)
{
@ -775,12 +774,6 @@ build_building(unit * u, const building_type * btype, int id, int want, order *
if (u->number && leave(u, false)) {
u_set_building(u, b);
}
#ifdef WDW_PYRAMID
if (b->type == bt_find("pyramid") && f_get_alliance(u->faction) != NULL) {
attrib *a = a_add(&b->attribs, a_new(&at_alliance));
a->data.i = u->faction->alliance->id;
}
#endif
}
btname = LOC(lang, btype->_name);

View file

@ -270,45 +270,6 @@ static const char *fort_name(const struct building_type *btype,
return castle_name_i(btype, b, bsize, fname);
}
#ifdef WDW_PYRAMID
static const char *pyramid_name(const struct building_type *btype, int bsize)
{
static char p_name_buf[32];
int level = 0;
const construction *ctype;
ctype = btype->construction;
while (ctype && ctype->maxsize != -1 && ctype->maxsize <= bsize) {
bsize -= ctype->maxsize;
ctype = ctype->improvement;
++level;
}
sprintf(p_name_buf, "pyramid%d", level);
return p_name_buf;
}
int wdw_pyramid_level(const struct building *b)
{
const construction *ctype = b->type->construction;
int completed = b->size;
int level = 0;
while (ctype->improvement != NULL &&
ctype->improvement != ctype &&
ctype->maxsize > 0 && ctype->maxsize <= completed) {
++level;
completed -= ctype->maxsize;
ctype = ctype->improvement;
}
return level;
}
#endif
/* for finding out what was meant by a particular building string */
static local_names *bnames;
@ -371,9 +332,6 @@ void register_buildings(void)
register_function((pf_generic) & castle_name, "castle_name");
register_function((pf_generic) & castle_name_2, "castle_name_2");
register_function((pf_generic) & fort_name, "fort_name");
#ifdef WDW_PYRAMID
register_function((pf_generic) & pyramid_name, "pyramid_name");
#endif
}
void write_building_reference(const struct building *b, struct storage *store)

View file

@ -604,7 +604,7 @@ unsigned int atoip(const char *s)
return n;
}
bool unit_has_cursed_item(unit * u)
bool unit_has_cursed_item(const unit * u)
{
item *itm = u->items;
while (itm) {
@ -734,20 +734,6 @@ int alliedunit(const unit * u, const faction * f2, int mode)
return 0;
}
#ifndef NDEBUG
const char *strcheck(const char *s, size_t maxlen)
{
static char buffer[16 * 1024]; // FIXME: static return value
if (strlen(s) > maxlen) {
assert(maxlen < 16 * 1024);
log_warning("[strcheck] string was shortened to %d bytes:\n%s\n", (int)maxlen, s);
strlcpy(buffer, s, maxlen);
return buffer;
}
return s;
}
#endif
static attrib_type at_lighthouse = {
"lighthouse"
/* Rest ist NULL; temporäres, nicht alterndes Attribut */
@ -1031,20 +1017,6 @@ int read_unitid(const faction * f, const region * r)
/* exported symbol */
bool getunitpeasants;
unit *getunitg(const region * r, const faction * f)
{
int n = read_unitid(f, r);
if (n == 0) {
getunitpeasants = 1;
return NULL;
}
getunitpeasants = 0;
if (n < 0)
return 0;
return findunit(n);
}
unit *getunit(const region * r, const faction * f)
{
@ -1632,9 +1604,6 @@ void kernel_done(void)
gc_done();
}
/* TODO: soll hier weg */
extern struct attrib_type at_shiptrail;
attrib_type at_germs = {
"germs",
DEFAULT_INIT,
@ -2168,6 +2137,7 @@ bool has_limited_skills(const struct unit * u)
void attrib_init(void)
{
/* Alle speicherbaren Attribute müssen hier registriert werden */
at_register(&at_speedup);
at_register(&at_shiptrail);
at_register(&at_familiar);
at_register(&at_familiarmage);
@ -2211,7 +2181,6 @@ void attrib_init(void)
at_register(&at_germs);
at_deprecate("xontormiaexpress", a_readint); /* required for old datafiles */
at_register(&at_speedup);
}
void kernel_init(void)
@ -2290,11 +2259,7 @@ void free_gamedata(void)
defaults[i] = 0;
}
}
while (alliances) {
alliance *al = alliances;
alliances = al->next;
free_alliance(al);
}
free_alliances();
while (factions) {
faction *f = factions;
factions = f->next;

View file

@ -34,9 +34,6 @@ extern "C" {
#define INSECT_POTION /* Spezialtrank für Insekten */
#define ORCIFICATION /* giving snotlings to the peasants gets counted */
// TODO: remove macro, move all alliance code into a module.
#define ALLIED(f1, f2) (f1==f2 || (f1->alliance && f1->alliance==f2->alliance))
/* for some good prime numbers, check http://www.math.niu.edu/~rusin/known-math/98/pi_x */
#ifndef MAXREGIONS
# define MAXREGIONS 524287 /* must be prime for hashing. 262139 was a little small */
@ -166,7 +163,6 @@ extern "C" {
struct unit *createunit(struct region *r, struct faction *f,
int number, const struct race *rc);
void create_unitid(struct unit *u, int id);
struct unit *getunitg(const struct region *r, const struct faction *f);
struct unit *getunit(const struct region *r, const struct faction *f);
int read_unitid(const struct faction *f, const struct region *r);
@ -238,7 +234,7 @@ extern "C" {
struct region *lastregion(struct faction *f);
bool idle(struct faction *f);
bool unit_has_cursed_item(struct unit *u);
bool unit_has_cursed_item(const struct unit *u);
/* simple garbage collection: */
void *gc_add(void *p);

View file

@ -480,9 +480,6 @@ item *i_change(item ** pi, const item_type * itype, int delta)
i->number += delta;
if (i->number < 0) {
log_error("serious accounting error. number of items is %d.\n", i->number);
/* FIXME what's this supposed to mean??
assert(i >= 0);
*/
i->number = 0;
}
if (i->number == 0) {

View file

@ -251,16 +251,20 @@ void addmessage(region * r, faction * f, const char *s, msg_t mtype, int level)
caddmessage(r, f, s, mtype, level);
}
message * cmistake(const unit * u, struct order *ord, int mno, int mtype)
{
message * result;
message * msg_error(const unit * u, struct order *ord, int mno) {
static char msgname[20];
unused_arg(mtype);
if (fval(u->faction, FFL_NPC))
return 0;
sprintf(msgname, "error%d", mno);
result = msg_feedback(u, ord, msgname, "");
return msg_feedback(u, ord, msgname, "");
}
message * cmistake(const unit * u, struct order *ord, int mno, int mtype)
{
message * result;
unused_arg(mtype);
result = msg_error(u, ord, mno);
ADDMSG(&u->faction->msgs, result);
return result;
}

View file

@ -55,8 +55,8 @@ extern "C" {
#define ADDMSG(msgs, mcreate) { message * m = mcreate; if (m) { assert(m->refcount>=1); add_message(msgs, m); msg_release(m); } }
extern struct message * cmistake(const struct unit *u, struct order *ord, int mno,
int mtype);
struct message * cmistake(const struct unit *u, struct order *ord, int mno, int mtype);
struct message * msg_error(const struct unit * u, struct order *ord, int mno);
#ifdef __cplusplus
}
#endif

View file

@ -568,6 +568,7 @@ keyword_t init_order(const struct order *ord)
{
char *cmd = 0;
assert(ord && ord->data);
if (ord->data->_str) cmd = _strdup(ord->data->_str);
init_tokens_str(cmd, cmd);
return ord->data->_keyword;

View file

@ -172,6 +172,7 @@ race *rc_get_or_create(const char *zName)
rc = (race *)calloc(sizeof(race), 1);
rc->hitpoints = 1;
rc->recruit_multi = 1.0F;
if (strchr(zName, ' ') != NULL) {
log_error("race '%s' has an invalid name. remove spaces\n", zName);
assert(strchr(zName, ' ') == NULL);

View file

@ -552,43 +552,6 @@ static int parse_ships(xmlDocPtr doc)
return 0;
}
#if 0
static void race_compat(void)
{
/* required for old_race, do not change order! */
const char *oldracenames[MAXRACES] = {
"dwarf", "elf", NULL, "goblin", "human", "troll", "demon", "insect",
"halfling", "cat", "aquarian", "orc", "snotling", "undead", "illusion",
"youngdragon", "dragon", "wyrm", "ent", "catdragon", "dracoid",
"special", "spell", "irongolem", "stonegolem", "shadowdemon",
"shadowmaster", "mountainguard", "alp", "toad", "braineater", "peasant",
"wolf", NULL, NULL, NULL, NULL, "songdragon", NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, "seaserpent",
"shadowknight", "centaur", "skeleton", "skeletonlord", "zombie",
"juju-zombie", "ghoul", "ghast", "museumghost", "gnome", "template",
"clone"
};
int i;
for (i = 0; i != MAXRACES; ++i) {
const char *rcname = oldracenames[i];
if (rcname == NULL) {
new_race[i] = NULL;
} else {
race *rc = rc_get_or_create(oldracenames[i]);
if (rc) {
new_race[i] = rc;
if (rc == new_race[RC_TROLL]) {
a_add(&rc->attribs, make_skillmod(NOSKILL, SMF_RIDING, NULL, 0.0,
-1));
}
}
}
}
}
#endif
static potion_type *xml_readpotion(xmlXPathContextPtr xpath, item_type * itype)
{
int level = xml_ivalue(xpath->node, "level", 0);

View file

@ -28,6 +28,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#include "economy.h"
#include "keyword.h"
#include "market.h"
#include "morale.h"
#include "monster.h"
#include "move.h"
#include "randenc.h"
@ -857,19 +858,15 @@ int can_contact(const region * r, const unit * u, const unit * u2) {
int contact_cmd(unit * u, order * ord)
{
/* unit u kontaktiert unit u2. Dies setzt den contact einfach auf 1 -
* ein richtiger toggle ist (noch?) nicht noetig. die region als
* parameter ist nur deswegen wichtig, weil er an getunit ()
* weitergegeben wird. dies wird fuer das auffinden von tempunits in
* getnewunit () verwendet! */
unit *u2;
region *r = u->region;
int n;
init_order(ord);
u2 = getunitg(r, u->faction);
n = read_unitid(u->faction, u->region);
u2 = findunit(n);
if (u2 != NULL) {
if (!can_contact(r, u, u2)) {
if (!can_contact(u->region, u, u2)) {
cmistake(u, u->thisorder, 23, MSG_EVENT);
return -1;
}
@ -3160,12 +3157,6 @@ static building *age_building(building * b)
return b;
}
static double rc_popularity(const struct race *rc)
{
int pop = get_param_int(rc->parameters, "morale", MORALE_AVERAGE);
return 1.0 / (pop - MORALE_COOLDOWN); /* 10 turns average */
}
static void age_region(region * r)
{
a_age(&r->attribs);
@ -3174,33 +3165,7 @@ static void age_region(region * r)
if (!r->land)
return;
if (r->land->ownership && r->land->ownership->owner) {
int stability = turn - r->land->ownership->morale_turn;
int maxmorale = MORALE_DEFAULT;
building *b = largestbuilding(r, &cmp_taxes, false);
if (b) {
int bsize = buildingeffsize(b, false);
maxmorale = (int)(0.5 + b->type->taxes(b, bsize + 1) / MORALE_TAX_FACTOR);
}
if (r->land->morale < maxmorale) {
if (stability > MORALE_COOLDOWN && r->land->ownership->owner
&& r->land->morale < MORALE_MAX) {
double ch = rc_popularity(r->land->ownership->owner->race);
if (is_cursed(r->attribs, C_GENEROUS, 0)) {
ch *= 1.2; /* 20% improvement */
}
if (stability >= MORALE_AVERAGE * 2 || chance(ch)) {
region_set_morale(r, r->land->morale + 1, turn);
}
}
}
else if (r->land->morale > maxmorale) {
region_set_morale(r, r->land->morale - 1, turn);
}
}
else if (r->land->morale > MORALE_DEFAULT) {
region_set_morale(r, r->land->morale - 1, turn);
}
morale_update(r);
}
static void ageing(void)

74
src/morale.c Normal file
View file

@ -0,0 +1,74 @@
/*
Copyright (c) 1998-2014,
Enno Rehling <enno@eressea.de>
Katja Zedel <katze@felidae.kn-bremen.de
Christian Schlittchen <corwin@amber.kn-bremen.de>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
**/
#include <platform.h>
#include "morale.h"
#include <kernel/config.h>
#include <kernel/curse.h>
#include <kernel/region.h>
#include <kernel/faction.h>
#include <kernel/race.h>
#include <kernel/building.h>
#include <util/rand.h>
static double rc_popularity(const struct race *rc)
{
int pop = get_param_int(rc->parameters, "morale", MORALE_AVERAGE);
return 1.0 / (pop - MORALE_COOLDOWN); /* 10 turns average */
}
void morale_update(region *r) {
if (r->land->ownership && r->land->ownership->owner) {
int stability = turn - r->land->ownership->morale_turn;
int maxmorale = MORALE_DEFAULT;
building *b = largestbuilding(r, &cmp_taxes, false);
if (b) {
int bsize = buildingeffsize(b, false);
maxmorale = (int)(0.5 + b->type->taxes(b, bsize + 1) / MORALE_TAX_FACTOR);
}
if (r->land->morale < maxmorale) {
if (stability > MORALE_COOLDOWN && r->land->ownership->owner
&& r->land->morale < MORALE_MAX) {
double ch = rc_popularity(r->land->ownership->owner->race);
if (is_cursed(r->attribs, C_GENEROUS, 0)) {
ch *= 1.2; /* 20% improvement */
}
if (stability >= MORALE_AVERAGE * 2 || chance(ch)) {
region_set_morale(r, r->land->morale + 1, turn);
}
}
}
else if (r->land->morale > maxmorale) {
region_set_morale(r, r->land->morale - 1, turn);
}
}
else if (r->land->morale > MORALE_DEFAULT) {
region_set_morale(r, r->land->morale - 1, turn);
}
}
void morale_change(region *r, int value) {
int morale = region_get_morale(r);
if (morale > 0) {
morale = _max(0, morale - value);
region_set_morale(r, morale, turn);
}
}

View file

@ -16,13 +16,18 @@ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
**/
#ifndef H_ATTRIBUTE_ALLIANCE
#define H_ATTRIBUTE_ALLIANCE
#ifndef H_GC_MORALE
#define H_GC_MORALE
#include <kernel/types.h>
#ifdef __cplusplus
extern "C" {
#endif
extern struct attrib_type at_alliance;
struct region;
void morale_update(struct region *r);
void morale_change(struct region *r, int value);
#ifdef __cplusplus
}

View file

@ -32,6 +32,7 @@ extern "C" {
struct building_type;
extern struct attrib_type at_speedup;
extern struct attrib_type at_shiptrail;
/* die Zahlen sind genau äquivalent zu den race Flags */
#define MV_CANNOTMOVE (1<<5)

View file

@ -31,7 +31,6 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
/* attributes includes */
#include <attributes/overrideroads.h>
#include <attributes/otherfaction.h>
#include <attributes/alliance.h>
#include <attributes/reduceproduction.h>
/* gamecode includes */
@ -711,8 +710,7 @@ nr_unit(FILE * F, const faction * f, const unit * u, int indent, int mode)
if (u->faction == f) {
marker = '*';
}
else if ALLIED
(u->faction, f) {
else if (is_allied(u->faction, f)) {
marker = 'o';
}
else if (a_otherfaction && f != u->faction
@ -1889,7 +1887,7 @@ static void list_address(FILE * F, const faction * uf, quicklist * seenfactions)
f->banner ? f->banner : "");
if (uf == f)
label = '*';
else if (ALLIED(uf, f))
else if (is_allied(uf, f))
label = 'o';
else if (alliedfaction(NULL, uf, f, HELP_ALL))
label = '+';
@ -2046,62 +2044,12 @@ const faction * f)
WARN_STATIC_BUFFER();
i = b->display[strlen(b->display) - 1];
}
#ifdef WDW_PYRAMID
if (i != '!' && i != '?' && i != '.') {
scat(", ");
}
if (b->type == bt_find("pyramid")) {
unit *owner = building_owner(b);
scat("Größenstufe ");
icat(wdw_pyramid_level(b));
scat(".");
if (owner && owner->faction == f) {
const construction *ctype = b->type->construction;
int completed = b->size;
int c;
scat(" Baukosten pro Größenpunkt: ");
while (ctype->improvement != NULL &&
ctype->improvement != ctype &&
ctype->maxsize > 0 && ctype->maxsize <= completed) {
completed -= ctype->maxsize;
ctype = ctype->improvement;
}
assert(ctype->materials != NULL);
for (c = 0; ctype->materials[c].number; c++) {
const resource_type *rtype = ctype->materials[c].rtype;
int number = ctype->materials[c].number;
if (c > 0) {
scat(", ");
}
icat(number);
scat(" ");
scat(locale_string(lang, resourcename(rtype,
number != 1 ? GR_PLURAL : 0)));
}
scat(".");
scat(" Erforderlicher Talentwert: ");
icat(b->type->construction->minskill);
scat(".");
}
}
#else
if (i != '!' && i != '?' && i != '.') {
bytes = (int)strlcpy(bufp, ".", size);
if (wrptr(&bufp, &size, bytes) != 0)
WARN_STATIC_BUFFER();
}
#endif
*bufp = 0;
rparagraph(F, buffer, 2, 0, 0);

View file

@ -1108,7 +1108,7 @@ static void get_addresses(report_context * ctx)
faction *sf = visible_faction(ctx->f, u);
bool ballied = sf && sf != ctx->f && sf != lastf
&& !fval(u, UFL_ANON_FACTION) && cansee(ctx->f, r, u, stealthmod);
if (ballied || ALLIED(ctx->f, sf)) {
if (ballied || is_allied(ctx->f, sf)) {
add_seen_faction_i(&flist, sf);
lastf = sf;
}

View file

@ -394,46 +394,10 @@ int report_action(region * r, unit * actor, message * msg, int flags)
static void
report_effect(region * r, unit * mage, message * seen, message * unseen)
{
#if 0
unit *u;
/* melden, 1x pro Partei */
freset(mage->faction, FFL_SELECT);
for (u = r->units; u; u = u->next)
freset(u->faction, FFL_SELECT);
for (u = r->units; u; u = u->next) {
if (!fval(u->faction, FFL_SELECT)) {
fset(u->faction, FFL_SELECT);
/* Bei Fernzaubern sieht nur die eigene Partei den Magier */
if (u->faction != mage->faction) {
if (r == mage->region) {
/* kein Fernzauber, pruefe, ob der Magier ueberhaupt gesehen
* wird */
if (cansee(u->faction, r, mage, 0)) {
r_addmessage(r, u->faction, seen);
} else {
r_addmessage(r, u->faction, unseen);
}
} else { /* Fernzauber, fremde Partei sieht den Magier niemals */
r_addmessage(r, u->faction, unseen);
}
} else { /* Partei des Magiers, sieht diesen immer */
r_addmessage(r, u->faction, seen);
}
}
}
/* Ist niemand von der Partei des Magiers in der Region, dem Magier
* nochmal gesondert melden */
if (!fval(mage->faction, FFL_SELECT)) {
add_message(&mage->faction->msgs, seen);
}
#else
int err = report_action(r, mage, seen, ACTION_RESET | ACTION_CANSEE);
if (err) {
report_action(r, mage, seen, ACTION_CANNOTSEE);
}
#endif
}
/* ------------------------------------------------------------- */
@ -3613,11 +3577,6 @@ static int sp_charmingsong(castorder * co)
/* Magieresistenz */
if (target_resists_magic(mage, target, TYP_UNIT, resist_bonus)) {
report_failure(mage, co->order);
#if 0
sprintf(buf, "%s fuehlt sich einen Moment lang benommen und desorientiert.",
unitname(target));
addmessage(target->region, target->faction, buf, MSG_EVENT, ML_WARN);
#endif
return 0;
}
@ -6526,54 +6485,6 @@ int sp_becomewyrm(castorder * co)
return 0;
}
/* ------------------------------------------------------------- */
/* Name: WDW-Pyramidenfindezauber
* Stufe: unterschiedlich
* Gebiet: alle
* Wirkung:
* gibt die ungefaehre Entfernung zur naechstgelegenen Pyramiden-
* region an.
*
* Flags:
*/
static int sp_wdwpyramid(castorder * co)
{
region *r = co_get_region(co);
unit *mage = co->magician.u;
int cast_level = co->level;
if (a_find(r->attribs, &at_wdwpyramid) != NULL) {
ADDMSG(&mage->faction->msgs, msg_message("wdw_pyramidspell_found",
"unit region command", mage, r, co->order));
}
else {
region *r2;
int mindist = INT_MAX;
int minshowdist;
int maxshowdist;
for (r2 = regions; r2; r2 = r2->next) {
if (a_find(r2->attribs, &at_wdwpyramid) != NULL) {
int dist = distance(mage->region, r2);
if (dist < mindist) {
mindist = dist;
}
}
}
assert(mindist >= 1);
minshowdist = mindist - rng_int() % 5;
maxshowdist = minshowdist + 4;
ADDMSG(&mage->faction->msgs, msg_message("wdw_pyramidspell_notfound",
"unit region command mindist maxdist", mage, r, co->order,
_max(1, minshowdist), maxshowdist));
}
return cast_level;
}
typedef struct spelldata {
const char *sname;
spell_f cast;
@ -6861,7 +6772,6 @@ void register_spells(void)
ct_register(&ct_deathcloud);
register_function((pf_generic)sp_blessedharvest, "cast_blessedharvest");
register_function((pf_generic)sp_wdwpyramid, "wdwpyramid");
register_function((pf_generic)sp_summon_familiar, "cast_familiar");
register_function((pf_generic)sp_babbler, "cast_babbler");
register_function((pf_generic)sp_readmind, "cast_readmind");

View file

@ -38,6 +38,7 @@ int RunAllTests(void)
ADD_TESTS(suite, unicode);
ADD_TESTS(suite, strings);
/* kernel */
ADD_TESTS(suite, alliance);
ADD_TESTS(suite, unit);
ADD_TESTS(suite, faction);
ADD_TESTS(suite, group);

View file

@ -23,7 +23,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
/* kernel includes */
#include <kernel/unit.h>
#include <kernel/save.h>
#include <kernel/faction.h> /* FIXME: resolve_faction */
#include <kernel/faction.h>
/* util includes */
#include <util/attrib.h>