Merge remote-tracking branch 'upstream/develop' into develop

This commit is contained in:
Enno Rehling 2016-08-31 18:51:29 +01:00
commit 3c1704e691
77 changed files with 1375 additions and 1105 deletions

View File

@ -34,7 +34,7 @@
</string>
<string name="songdragon">
<text locale="de">Singdrachen sind von der Größe eines ausgewachsenden Tigers. Ihre Färbung reicht von schillerndem Rot, über dunkles Grün bis hin zu tiefem Schwarz. Alle bekannten Drachen dieser Art weisen eine hohe Intelligenz und ein hohes Maß an magischen Fähigkeiten auf. Wie Ihre großen Verwandten verfügen sie über einen Feuerodem. Sie lieben den Gesang und das üppige Mahl. Von Zeit zu Zeit gehen sie eine engen magisches Bund zu einem Magier ein. Wenn dies geschieht, so steht dem Magier ein äußerst loyaler und lohnender Vertrauter zur Seite.
</text>
</text>
<text locale="en">Song Dragons are roughly the size of a fully grown tiger. Their coloring ranges from bright red, through a dark green shade to a deep black. All known dragons of this species display a high level of intelligence and highly developed magical skills. Like their larger cousins, Song Dragons posess a firegland. They love singing and a good meal. From time to time one of these magnificent creatures will bond with a mage. When this happens, the mage is assured of a most loyal and useful familiar at his side.</text>
</string>
<string name="unicorn">
@ -1118,14 +1118,6 @@
<text locale="de">Trollhörner</text>
<text locale="en">troll horns</text>
</string>
<string name="phoenixfeather">
<text locale="de">Feder des Phönix</text>
<text locale="en">feather of the phoenix</text>
</string>
<string name="phoenixfeather_p">
<text locale="de">Federn des Phönix</text>
<text locale="en">feathers of the phoenix</text>
</string>
<!--Resourcen -->
<string name="money">
@ -3195,23 +3187,6 @@
<text locale="en">young dragon</text>
</string>
<string name="phoenix">
<text locale="de">Phönix</text>
<text locale="en">phoenix</text>
</string>
<string name="phoenix_p">
<text locale="de">Phönixe</text>
<text locale="en">phoenixes</text>
</string>
<string name="phoenix_d">
<text locale="de">Phönixen</text>
<text locale="en">phoenixes</text>
</string>
<string name="phoenix_x">
<text locale="de">Phönix</text>
<text locale="en">phoenix</text>
</string>
<string name="illusion">
<text locale="de">Illusion</text>
<text locale="en">illusion</text>

View File

@ -8090,27 +8090,6 @@
<text locale="en">"The plank of $ship($ship) are inscribed with strange runes. ($int36($id))"</text>
</message>
<message name="phoenixcompass_confusion" section="magic">
<type>
<arg name="unit" type="unit"/>
<arg name="region" type="region"/>
<arg name="command" type="order"/>
</type>
<text locale="de">"$unit($unit) in $region($region): '$order($command)' - Die Kompassnadel springt wild hin und her und es lässt sich keine Richtung erkennen."</text>
<text locale="en">"$unit($unit) in $region($region): '$order($command)' - The needle jumps wildly and there is no specific direction recognizable."</text>
</message>
<message name="phoenixcompass_success" section="magic">
<type>
<arg name="unit" type="unit"/>
<arg name="region" type="region"/>
<arg name="command" type="order"/>
<arg name="dir" type="int"/>
</type>
<text locale="de">"$unit($unit) in $region($region): '$order($command)' - Die Kompassnadel zeigt nach $direction($dir)."</text>
<text locale="en">"$unit($unit) in $region($region): '$order($command)' - The needle points $direction($dir)."</text>
</message>
<message name="disrupt_astral" section="magic">
<type>
<arg name="unit" type="unit"/>

View File

@ -619,7 +619,7 @@
<race name="braineater" magres="0.900000" maxaura="1.0" regaura="1.0" weight="100" capacity="540" speed="1.0" hp="20" damage="0d0" unarmedattack="0" unarmeddefense="0" attackmodifier="6" defensemodifier="10" scarepeasants="yes" fly="yes" walk="yes" teach="no" invinciblenonmagic="yes">
<ai splitsize="500" killpeasants="yes" moverandom="yes" learn="yes"/>
<function name="name" value="namegeneric"/>
<function name="describe" value="describe_braineater"/>
<function name="describe" value="describe_race"/>
<attack type="2" damage="3d15"/>
<attack type="3" damage="1d1"/>
<attack type="4" damage="1d1"/>

View File

@ -602,7 +602,7 @@
regaura="1.000000" recruitcost="50000" weight="100" capacity="540" speed="1.000000" hp="20" damage="0d0" unarmedattack="0" unarmeddefense="0" attackmodifier="6" defensemodifier="10" scarepeasants="yes" fly="yes" walk="yes" teach="no" invinciblenonmagic="yes">
<ai splitsize="500" killpeasants="yes" moverandom="yes" learn="yes"/>
<function name="name" value="namegeneric"/>
<function name="describe" value="describe_braineater"/>
<function name="describe" value="describe_race"/>
<attack type="2" damage="3d15"/>
<attack type="3" damage="1d1"/>
<attack type="4" damage="1d1"/>

View File

@ -111,6 +111,7 @@ set (ERESSEA_SRC
morale.c
monster.c
randenc.c
volcano.c
chaos.c
report.c
spy.c
@ -183,6 +184,7 @@ target_link_libraries(eressea
set(TESTS_SRC
monsters.test.c
names.test.c
donations.test.c
wormhole.test.c
alchemy.test.c
@ -191,6 +193,7 @@ set(TESTS_SRC
battle.test.c
vortex.test.c
tests.test.c
volcano.test.c
reports.test.c
seen.test.c
travelthru.test.c

View File

@ -25,7 +25,7 @@ static void test_herbsearch(CuTest * tc)
region *r;
const item_type *itype;
test_cleanup();
test_setup();
r = test_create_region(0, 0, 0);
rc = rc_get_or_create("dragon");
rc->flags |= RCF_UNARMEDGUARD;

View File

@ -16,7 +16,7 @@
#include <assert.h>
static void test_rules(CuTest *tc) {
test_cleanup();
test_setup();
config_set("stealth.faction.other", NULL);
CuAssertIntEquals(tc, true, rule_stealth_other());
config_set("stealth.faction.other", "0");
@ -37,7 +37,7 @@ static void test_otherfaction(CuTest *tc) {
unit *u;
faction *f;
test_cleanup();
test_setup();
u = test_create_unit(test_create_faction(0), test_create_region(0, 0, 0));
f = test_create_faction(0);
config_set("stealth.faction.other", "1");

View File

@ -56,10 +56,12 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#include <attributes/moved.h>
/* util includes */
#include <util/assert.h>
#include <util/attrib.h>
#include <util/base36.h>
#include <util/bsdstring.h>
#include <util/language.h>
#include <util/lists.h>
#include <util/log.h>
#include <util/parser.h>
#include <quicklist.h>
@ -67,7 +69,6 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#include <util/rng.h>
/* libc includes */
#include <assert.h>
#include <ctype.h>
#include <limits.h>
#include <math.h>
@ -218,6 +219,7 @@ static void message_faction(battle * b, faction * f, struct message *m)
assert(f);
if (f->battles == NULL || f->battles->r != r) {
struct bmsg *bm = (struct bmsg *)calloc(1, sizeof(struct bmsg));
assert_alloc(bm);
bm->next = f->battles;
f->battles = bm;
bm->r = r;
@ -251,6 +253,7 @@ static void fbattlerecord(battle * b, faction * f, const char *s)
static bool set_enemy(side * as, side * ds, bool attacking)
{
int i;
assert(as && ds);
for (i = 0; i != MAXSIDES; ++i) {
if (ds->enemies[i] == NULL)
ds->enemies[i] = as;
@ -1920,38 +1923,33 @@ int skilldiff(troop at, troop dt, int dist)
}
if (df->building) {
bool init = false;
static const curse_type *strongwall_ct, *magicwalls_ct;
if (!init) {
strongwall_ct = ct_find("strongwall");
magicwalls_ct = ct_find("magicwalls");
init = true;
if (df->building->attribs) {
const curse_type *strongwall_ct = ct_find("strongwall");
if (strongwall_ct) {
curse *c = get_curse(df->building->attribs, strongwall_ct);
if (curse_active(c)) {
/* wirkt auf alle Gebäude */
skdiff -= curse_geteffect_int(c);
is_protected = 2;
}
}
}
if (df->building->type->protection) {
int beff = df->building->type->protection(df->building, du, DEFENSE_BONUS);
if (beff) {
skdiff -= beff;
is_protected = 2;
if (df->building->attribs) {
const curse_type *magicwalls_ct = ct_find("magicwalls");
if (magicwalls_ct
&& curse_active(get_curse(df->building->attribs, magicwalls_ct))) {
/* Verdoppelt Burgenbonus */
skdiff -= beff;
}
}
}
}
if (strongwall_ct) {
curse *c = get_curse(df->building->attribs, strongwall_ct);
if (curse_active(c)) {
/* wirkt auf alle Gebäude */
skdiff -= curse_geteffect_int(c);
is_protected = 2;
}
}
if (magicwalls_ct
&& curse_active(get_curse(df->building->attribs, magicwalls_ct))) {
/* Verdoppelt Burgenbonus */
skdiff -= df->building->type->protection(df->building, du, DEFENSE_BONUS);
}
}
/* Goblin-Verteidigung
* ist direkt in der Rassentabelle als df_default
*/
/* Effekte der Waffen */
skdiff += weapon_effskill(at, dt, awp, true, dist > 1);
if (awp && fval(awp->type, WTF_MISSILE)) {
@ -3262,8 +3260,8 @@ fighter *make_fighter(battle * b, unit * u, side * s1, bool attack)
/* Effekte von Sprüchen */
{
static const curse_type *speed_ct;
if (u->attribs) {
const curse_type *speed_ct;
speed_ct = ct_find("speed");
if (speed_ct) {
curse *c = get_curse(u->attribs, speed_ct);

View File

@ -6,6 +6,7 @@
#include <kernel/config.h>
#include <kernel/building.h>
#include <kernel/faction.h>
#include <kernel/curse.h>
#include <kernel/item.h>
#include <kernel/race.h>
#include <kernel/region.h>
@ -59,7 +60,7 @@ static void test_make_fighter(CuTest * tc)
test_cleanup();
}
static int add_two(building * b, unit * u, building_bonus bonus) {
static int add_two(const building * b, const unit * u, building_bonus bonus) {
return 2;
}
@ -187,7 +188,7 @@ static void test_building_defence_bonus(CuTest * tc)
test_cleanup();
r = test_create_region(0, 0, 0);
btype = test_create_buildingtype("castle");
btype->protection = (int(*)(struct building *, struct unit *, building_bonus))get_function("building_protection");
btype->protection = (int(*)(const struct building *, const struct unit *, building_bonus))get_function("building_protection");
btype->construction->defense_bonus = 3;
bld = test_create_building(r, btype);
bld->size = 1;
@ -203,10 +204,14 @@ static void test_building_defence_bonus(CuTest * tc)
}
static fighter *setup_fighter(battle **bp, unit *u) {
battle *b;
battle *b = *bp;
side *s;
*bp = b = make_battle(u->region);
return make_fighter(b, u, make_side(b, u->faction, 0, 0, 0), false);
if (!b) {
*bp = b = make_battle(u->region);
}
s = make_side(b, u->faction, 0, 0, 0);
return make_fighter(b, u, s, false);
}
static void test_natural_armor(CuTest * tc)
@ -229,7 +234,7 @@ static void test_natural_armor(CuTest * tc)
static void test_calculate_armor(CuTest * tc)
{
troop dt;
battle *b;
battle *b = NULL;
region *r;
unit *du;
weapon_type *wtype;
@ -255,6 +260,7 @@ static void test_calculate_armor(CuTest * tc)
CuAssertDblEquals_Msg(tc, "magres unmodified", 1.0, magres, 0.01);
free_battle(b);
b = NULL;
i_change(&du->items, ibelt, 1);
dt.fighter = setup_fighter(&b, du);
CuAssertIntEquals_Msg(tc, "magical armor", 1, calculate_armor(dt, 0, 0, 0));
@ -263,6 +269,7 @@ static void test_calculate_armor(CuTest * tc)
rc->armor = 0;
free_battle(b);
b = NULL;
i_change(&du->items, ishield, 1);
i_change(&du->items, ichain, 1);
dt.fighter = setup_fighter(&b, du);
@ -270,6 +277,7 @@ static void test_calculate_armor(CuTest * tc)
CuAssertIntEquals_Msg(tc, "require BF_EQUIPMENT", 1, calculate_armor(dt, 0, 0, 0));
free_battle(b);
b = NULL;
rc->battle_flags |= BF_EQUIPMENT;
dt.fighter = setup_fighter(&b, du);
CuAssertIntEquals_Msg(tc, "stack equipment rc", 5, calculate_armor(dt, 0, 0, 0));
@ -296,7 +304,7 @@ static void test_calculate_armor(CuTest * tc)
static void test_magic_resistance(CuTest *tc)
{
troop dt;
battle *b;
battle *b = NULL;
region *r;
unit *du;
armor_type *ashield, *achain;
@ -324,6 +332,7 @@ static void test_magic_resistance(CuTest *tc)
calculate_armor(dt, 0, 0, &magres);
free_battle(b);
b = NULL;
i_change(&du->items, ishield, 1);
i_change(&du->items, ichain, 1);
achain->flags |= ATF_LAEN;
@ -335,6 +344,7 @@ static void test_magic_resistance(CuTest *tc)
CuAssertDblEquals_Msg(tc, "laen reduction", 0.81, magres, 0.01);
free_battle(b);
b = NULL;
i_change(&du->items, ishield, -1);
i_change(&du->items, ichain, -1);
set_level(du, SK_MAGIC, 2);
@ -359,7 +369,7 @@ static void test_magic_resistance(CuTest *tc)
static void test_projectile_armor(CuTest * tc)
{
troop dt;
battle *b;
battle *b = NULL;
region *r;
unit *du;
weapon_type *wtype;
@ -394,10 +404,88 @@ static void test_projectile_armor(CuTest * tc)
test_cleanup();
}
static void test_battle_skilldiff(CuTest *tc)
{
troop ta, td;
region *r;
unit *ua, *ud;
battle *b = NULL;
test_cleanup();
r = test_create_region(0, 0, 0);
ud = test_create_unit(test_create_faction(0), r);
ua = test_create_unit(test_create_faction(0), r);
td.fighter = setup_fighter(&b, ud);
td.index = 0;
ta.fighter = setup_fighter(&b, ua);
ta.index = 0;
ua = test_create_unit(test_create_faction(0), r);
CuAssertIntEquals(tc, 0, skilldiff(ta, td, 0));
ta.fighter->person[0].attack = 2;
td.fighter->person[0].defence = 1;
CuAssertIntEquals(tc, 1, skilldiff(ta, td, 0));
td.fighter->person[0].flags |= FL_SLEEPING;
CuAssertIntEquals(tc, 3, skilldiff(ta, td, 0));
// TODO: unarmed halfling vs. dragon: +5
// TODO: rule_goblin_bonus
// TODO: weapon modifiers, missiles, skill_formula
free_battle(b);
test_cleanup();
}
static int protect(const building *b, const unit *u, building_bonus bonus) {
return (bonus == DEFENSE_BONUS) ? 4 : 0;
}
static void test_battle_skilldiff_building(CuTest *tc)
{
troop ta, td;
region *r;
unit *ua, *ud;
battle *b = NULL;
building_type *btype;
const curse_type *strongwall_ct, *magicwalls_ct;
test_cleanup();
btype = test_create_buildingtype("castle");
strongwall_ct = ct_find("strongwall");
magicwalls_ct = ct_find("magicwalls");
r = test_create_region(0, 0, 0);
ud = test_create_unit(test_create_faction(0), r);
ud->building = test_create_building(ud->region, btype);
ua = test_create_unit(test_create_faction(0), r);
td.fighter = setup_fighter(&b, ud);
td.index = 0;
ta.fighter = setup_fighter(&b, ua);
ta.index = 0;
ua = test_create_unit(test_create_faction(0), r);
CuAssertIntEquals(tc, 0, skilldiff(ta, td, 0));
btype->protection = protect;
CuAssertIntEquals(tc, -4, skilldiff(ta, td, 0));
create_curse(NULL, &ud->building->attribs, magicwalls_ct, 1, 1, 1, 1);
CuAssertIntEquals(tc, -8, skilldiff(ta, td, 0));
create_curse(NULL, &ud->building->attribs, strongwall_ct, 1, 1, 2, 1);
CuAssertIntEquals(tc, -10, skilldiff(ta, td, 0));
free_battle(b);
test_cleanup();
}
CuSuite *get_battle_suite(void)
{
CuSuite *suite = CuSuiteNew();
SUITE_ADD_TEST(suite, test_make_fighter);
SUITE_ADD_TEST(suite, test_battle_skilldiff);
SUITE_ADD_TEST(suite, test_battle_skilldiff_building);
SUITE_ADD_TEST(suite, test_defenders_get_building_bonus);
SUITE_ADD_TEST(suite, test_attackers_get_no_building_bonus);
SUITE_ADD_TEST(suite, test_building_bonus_respects_size);

View File

@ -1,3 +1,3 @@
#define VERSION_MAJOR 3
#define VERSION_MINOR 9
#define VERSION_MINOR 10
#define VERSION_BUILD 0

View File

@ -742,13 +742,10 @@ void cr_output_unit(stream *out, const region * r, const faction * f,
const char *str;
const item_type *lasttype;
int pr;
item *itm, *show;
item *itm, *show = NULL;
building *b;
const char *pzTmp;
skill *sv;
bool itemcloak = false;
static const curse_type *itemcloak_ct = 0;
static bool init = false;
item result[MAX_INVENTORY];
const faction *sf;
const char *prefix;
@ -758,15 +755,6 @@ void cr_output_unit(stream *out, const region * r, const faction * f,
if (fval(u_race(u), RCF_INVISIBLE))
return;
if (!init) {
init = true;
itemcloak_ct = ct_find("itemcloak");
}
if (itemcloak_ct != NULL) {
curse * cu = get_curse(u->attribs, itemcloak_ct);
itemcloak = cu && curse_active(cu);
}
stream_printf(out, "EINHEIT %d\n", u->no);
stream_printf(out, "\"%s\";Name\n", unit_getname(u));
str = u_description(u, f->locale);
@ -970,16 +958,14 @@ void cr_output_unit(stream *out, const region * r, const faction * f,
if (f == u->faction || omniscient(f)) {
show = u->items;
}
else if (!itemcloak && mode >= see_unit) {
int n = report_items(u->items, result, MAX_INVENTORY, u, f);
assert(n >= 0);
if (n > 0)
show = result;
else
show = NULL;
}
else {
show = NULL;
if (mode >= see_unit) {
int n = report_items(u, result, MAX_INVENTORY, u, f);
assert(n >= 0);
if (n > 0) {
show = result;
}
}
}
lasttype = NULL;
for (itm = show; itm; itm = itm->next) {

View File

@ -1795,6 +1795,7 @@ static void expandselling(region * r, request * sellorders, int limit)
unit *hafenowner;
static int counter[MAXLUXURIES];
static int ncounter = 0;
const struct building_type *castle_bt;
if (ncounter == 0) {
const luxury_type *ltype;
@ -1810,15 +1811,15 @@ static void expandselling(region * r, request * sellorders, int limit)
}
/* Stelle Eigentümer der größten Burg fest. Bekommt Steuern aus jedem
* Verkauf. Wenn zwei Burgen gleicher Größe bekommt gar keiner etwas. */
castle_bt = bt_find("castle");
for (b = rbuildings(r); b; b = b->next) {
if (b->size > maxsize && building_owner(b) != NULL
&& b->type == bt_find("castle")) {
&& b->type == castle_bt) {
maxb = b;
maxsize = b->size;
maxowner = building_owner(b);
}
else if (b->size == maxsize && b->type == bt_find("castle")) {
else if (b->size == maxsize && b->type == castle_bt) {
maxb = (building *)NULL;
maxowner = (unit *)NULL;
}
@ -1923,13 +1924,7 @@ static void expandselling(region * r, request * sellorders, int limit)
}
}
if (use > 0) {
#ifdef NDEBUG
use_pooled(oa[j].unit, ltype->itype->rtype, GET_DEFAULT, use);
#else
/* int i = */ use_pooled(oa[j].unit, ltype->itype->rtype, GET_DEFAULT,
use);
/* assert(i==use); */
#endif
}
}
free(oa);
@ -2756,13 +2751,10 @@ expandwork(region * r, request * work_begin, request * work_end, int maxwork)
jobs = rpeasants(r);
}
earnings = jobs * p_wage;
if (rule_blessed_harvest() == HARVEST_TAXES) {
if (r->attribs && rule_blessed_harvest() == HARVEST_TAXES) {
/* E3 rules */
static const curse_type *blessedharvest_ct;
if (!blessedharvest_ct) {
blessedharvest_ct = ct_find("blessedharvest");
}
if (blessedharvest_ct && r->attribs) {
const curse_type *blessedharvest_ct = ct_find("blessedharvest");
if (blessedharvest_ct) {
int happy =
(int)curse_geteffect(get_curse(r->attribs, blessedharvest_ct));
happy = _min(happy, jobs);

View File

@ -8,7 +8,6 @@ SET(_FILES
artrewards.c
demonseye.c
itemtypes.c
phoenixcompass.c
seed.c
speedsail.c
weapons.c

View File

@ -16,7 +16,6 @@
#include "xerewards.h"
#include "artrewards.h"
#include "phoenixcompass.h"
#include "weapons.h"
#include "seed.h"
@ -26,7 +25,6 @@ void register_itemtypes(void)
register_weapons();
register_xerewards();
register_artrewards();
register_phoenixcompass();
}
void init_itemtypes(void)

View File

@ -1,131 +0,0 @@
/*
Copyright (c) 1998-2015, 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 <kernel/config.h>
#include "phoenixcompass.h"
/* kernel includes */
#include <kernel/item.h>
#include <kernel/race.h>
#include <kernel/region.h>
#include <kernel/faction.h>
#include <kernel/unit.h>
#include <kernel/messages.h>
/* util includes */
#include <util/functions.h>
#include <util/rand.h>
#include <util/rng.h>
/* libc includes */
#include <assert.h>
#include <string.h>
#include <limits.h>
static int
use_phoenixcompass(struct unit *u, const struct item_type *itype,
int amount, struct order *ord)
{
region *r;
unit *closest_phoenix = NULL;
int closest_phoenix_distance = INT_MAX;
bool confusion = false;
direction_t direction;
unit *u2;
direction_t closest_neighbour_direction = 0;
static const race *rc_phoenix = NULL;
if (rc_phoenix == NULL) {
rc_phoenix = rc_find("phoenix");
if (rc_phoenix == NULL)
return 0;
}
/* find the closest phoenix. */
for (r = regions; r; r = r->next) {
for (u2 = r->units; u2; u2 = u2->next) {
if (u_race(u2) == rc_phoenix) {
if (closest_phoenix == NULL) {
closest_phoenix = u2;
closest_phoenix_distance =
distance(u->region, closest_phoenix->region);
}
else {
int dist = distance(u->region, r);
if (dist < closest_phoenix_distance) {
closest_phoenix = u2;
closest_phoenix_distance = dist;
confusion = false;
}
else if (dist == closest_phoenix_distance) {
confusion = true;
}
}
}
}
}
/* no phoenix found at all.* if confusion == true more than one phoenix
* at the same distance was found and the device is confused */
if (closest_phoenix == NULL
|| closest_phoenix->region == u->region || confusion) {
add_message(&u->faction->msgs, msg_message("phoenixcompass_confusion",
"unit region command", u, u->region, ord));
return 0;
}
/* else calculate the direction. this is tricky. we calculate the
* neighbouring region which is closest to the phoenix found. hardcoded
* for readability. */
for (direction = 0; direction < MAXDIRECTIONS; ++direction) {
region *neighbour;
int closest_neighbour_distance = INT_MAX;
neighbour = r_connect(u->region, direction);
if (neighbour != NULL) {
int dist = distance(neighbour, closest_phoenix->region);
if (dist < closest_neighbour_distance) {
closest_neighbour_direction = direction;
closest_neighbour_distance = dist;
}
else if (dist == closest_neighbour_distance && rng_int() % 100 < 50) {
/* there can never be more than two neighbours with the same
* distance (except when you are standing in the same region
* as the phoenix, but that case has already been handled).
* therefore this simple solution is correct */
closest_neighbour_direction = direction;
closest_neighbour_distance = dist;
}
}
}
add_message(&u->faction->msgs, msg_message("phoenixcompass_success",
"unit region command dir",
u, u->region, ord, closest_neighbour_direction));
return 0;
}
void register_phoenixcompass(void)
{
register_item_use(use_phoenixcompass, "use_phoenixcompass");
}

View File

@ -17,7 +17,6 @@ typedef struct alliance_fixture {
} 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);
@ -28,7 +27,7 @@ static void setup_alliance(alliance_fixture *fix) {
static void test_alliance_make(CuTest *tc) {
alliance * al;
test_cleanup();
test_setup();
assert(!alliances);
al = makealliance(1, "Hodor");
CuAssertPtrNotNull(tc, al);
@ -50,6 +49,7 @@ static void test_alliance_join(CuTest *tc) {
alliance_fixture fix;
alliance * al;
test_setup();
setup_alliance(&fix);
CuAssertPtrEquals(tc, 0, fix.f1->alliance);
CuAssertPtrEquals(tc, 0, fix.f2->alliance);
@ -69,7 +69,7 @@ static void test_alliance_dead_faction(CuTest *tc) {
faction *f, *f2;
alliance *al;
test_cleanup();
test_setup();
f = test_create_faction(0);
f2 = test_create_faction(0);
al = makealliance(42, "Hodor");
@ -91,7 +91,7 @@ static void test_alliance_cmd(CuTest *tc) {
struct region *r;
struct alliance *al;
test_cleanup();
test_setup();
r = test_create_region(0, 0, 0);
u1 = test_create_unit(test_create_faction(0), r);
u2 = test_create_unit(test_create_faction(0), r);
@ -118,7 +118,7 @@ static void test_alliance_cmd_kick(CuTest *tc) {
struct region *r;
struct alliance *al;
test_cleanup();
test_setup();
al = makealliance(42, "Hodor");
r = test_create_region(0, 0, 0);
u1 = test_create_unit(test_create_faction(0), r);
@ -138,7 +138,7 @@ static void test_alliance_cmd_no_invite(CuTest *tc) {
unit *u1, *u2;
struct region *r;
test_cleanup();
test_setup();
r = test_create_region(0, 0, 0);
u1 = test_create_unit(test_create_faction(0), r);
u2 = test_create_unit(test_create_faction(0), r);
@ -159,7 +159,7 @@ static void test_alliance_cmd_leave(CuTest *tc) {
struct region *r;
struct alliance *al;
test_cleanup();
test_setup();
al = makealliance(42, "Hodor");
r = test_create_region(0, 0, 0);
u1 = test_create_unit(test_create_faction(0), r);
@ -180,7 +180,7 @@ static void test_alliance_cmd_transfer(CuTest *tc) {
struct region *r;
struct alliance *al;
test_cleanup();
test_setup();
al = makealliance(42, "Hodor");
r = test_create_region(0, 0, 0);
u1 = test_create_unit(test_create_faction(0), r);

View File

@ -130,13 +130,15 @@ static void destroy_road(unit * u, int nmax, struct order *ord)
if (willdo == 0) {
/* TODO: error message */
}
if (willdo > SHRT_MAX)
else if (willdo > SHRT_MAX)
road = 0;
else
road = (short)(road - willdo);
rsetroad(r, d, road);
ADDMSG(&u->faction->msgs, msg_message("destroy_road",
"unit from to", u, r, r2));
if (willdo > 0) {
ADDMSG(&u->faction->msgs, msg_message("destroy_road",
"unit from to", u, r, r2));
}
}
}
}
@ -163,19 +165,17 @@ int destroy_cmd(unit * u, struct order *ord)
init_order(ord);
s = gettoken(token, sizeof(token));
if (findparam(s, u->faction->locale) == P_ROAD) {
destroy_road(u, INT_MAX, ord);
return 0;
}
if (s && *s) {
n = atoi((const char *)s);
if (n <= 0) {
n = INT_MAX;
}
else {
s = gettoken(token, sizeof(token));
}
}
if (getparam(u->faction->locale) == P_ROAD) {
if (isparam(s, u->faction->locale, P_ROAD)) {
destroy_road(u, n, ord);
return 0;
}
@ -640,7 +640,6 @@ message *msg_materials_required(unit * u, order * ord,
if (multi <= 0 || multi == INT_MAX)
multi = 1;
for (c = 0; ctype && ctype->materials[c].number; ++c) {
// TODO: lots of alloc/dealloc calls here (make var_copy_resources take an array)
resource *res = malloc(sizeof(resource));
res->number = multi * ctype->materials[c].number / ctype->reqsize;
res->type = ctype->materials[c].rtype;

View File

@ -1,8 +1,11 @@
#include <platform.h>
#include <kernel/config.h>
#include <kernel/messages.h>
#include "alchemy.h"
#include "types.h"
#include "build.h"
#include "guard.h"
#include "order.h"
#include "unit.h"
#include "building.h"
@ -265,6 +268,120 @@ static void test_build_building_success(CuTest *tc) {
teardown_build(&bf);
}
static void test_build_destroy_road(CuTest *tc)
{
region *r, *r2;
faction *f;
unit *u;
order *ord;
message *m;
test_cleanup();
mt_register(mt_new_va("destroy_road", "unit:unit", "from:region", "to:region", 0));
r2 = test_create_region(1, 0, 0);
r = test_create_region(0, 0, 0);
rsetroad(r, D_EAST, 100);
u = test_create_unit(f = test_create_faction(0), r);
ord = create_order(K_DESTROY, f->locale, "%s %s", LOC(f->locale, parameters[P_ROAD]), LOC(f->locale, directions[D_EAST]));
CuAssertIntEquals(tc, 0, destroy_cmd(u, ord));
CuAssertIntEquals(tc, 100, rroad(r, D_EAST));
CuAssertPtrEquals(tc, 0, test_find_messagetype(f->msgs, "destroy_road"));
set_level(u, SK_ROAD_BUILDING, 1);
CuAssertIntEquals(tc, 0, destroy_cmd(u, ord));
CuAssertIntEquals(tc, 99, rroad(r, D_EAST));
CuAssertPtrNotNull(tc, m = test_find_messagetype(f->msgs, "destroy_road"));
CuAssertPtrEquals(tc, u, m->parameters[0].v);
CuAssertPtrEquals(tc, r, m->parameters[1].v);
CuAssertPtrEquals(tc, r2, m->parameters[2].v);
set_level(u, SK_ROAD_BUILDING, 4);
CuAssertIntEquals(tc, 0, destroy_cmd(u, ord));
CuAssertIntEquals(tc, 95, rroad(r, D_EAST));
scale_number(u, 4);
set_level(u, SK_ROAD_BUILDING, 2);
CuAssertIntEquals(tc, 0, destroy_cmd(u, ord));
CuAssertIntEquals(tc, 87, rroad(r, D_EAST));
test_cleanup();
}
unit *test_create_guard(region *r, faction *f, race *rc) {
unit *ug;
if (!rc) {
rc = test_create_race("guardian");
rc->flags |= RCF_UNARMEDGUARD;
}
if (!f) {
f = test_create_faction(rc);
}
ug = test_create_unit(f, r);
guard(ug, GUARD_TAX);
return ug;
}
static void test_build_destroy_road_guard(CuTest *tc)
{
region *r;
faction *f;
unit *u, *ug;
order *ord;
test_cleanup();
test_create_region(1, 0, 0);
r = test_create_region(0, 0, 0);
rsetroad(r, D_EAST, 100);
ug = test_create_guard(r, 0, 0);
u = test_create_unit(f = test_create_faction(0), r);
ord = create_order(K_DESTROY, f->locale, "%s %s", LOC(f->locale, parameters[P_ROAD]), LOC(f->locale, directions[D_EAST]));
set_level(u, SK_ROAD_BUILDING, 1);
CuAssertIntEquals(tc, 0, destroy_cmd(u, ord));
CuAssertIntEquals(tc, 100, rroad(r, D_EAST));
CuAssertPtrNotNull(tc, test_find_messagetype(f->msgs, "error70"));
CuAssertPtrEquals(tc, 0, test_find_messagetype(f->msgs, "destroy_road"));
test_clear_messages(f);
guard(ug, GUARD_NONE);
CuAssertIntEquals(tc, 0, destroy_cmd(u, ord));
CuAssertIntEquals(tc, 99, rroad(r, D_EAST));
CuAssertPtrEquals(tc, NULL, test_find_messagetype(f->msgs, "error70"));
CuAssertPtrNotNull(tc, test_find_messagetype(f->msgs, "destroy_road"));
test_cleanup();
}
static void test_build_destroy_road_limit(CuTest *tc)
{
region *r;
faction *f;
unit *u;
order *ord;
test_cleanup();
test_create_region(1, 0, 0);
r = test_create_region(0, 0, 0);
rsetroad(r, D_EAST, 100);
u = test_create_unit(f = test_create_faction(0), r);
ord = create_order(K_DESTROY, f->locale, "1 %s %s", LOC(f->locale, parameters[P_ROAD]), LOC(f->locale, directions[D_EAST]));
set_level(u, SK_ROAD_BUILDING, 1);
CuAssertIntEquals(tc, 0, destroy_cmd(u, ord));
CuAssertIntEquals(tc, 99, rroad(r, D_EAST));
CuAssertPtrNotNull(tc, test_find_messagetype(f->msgs, "destroy_road"));
set_level(u, SK_ROAD_BUILDING, 4);
CuAssertIntEquals(tc, 0, destroy_cmd(u, ord));
CuAssertIntEquals(tc, 98, rroad(r, D_EAST));
CuAssertPtrNotNull(tc, test_find_messagetype(f->msgs, "destroy_road"));
test_cleanup();
}
CuSuite *get_build_suite(void)
{
CuSuite *suite = CuSuiteNew();
@ -279,6 +396,9 @@ CuSuite *get_build_suite(void)
SUITE_ADD_TEST(suite, test_build_building_success);
SUITE_ADD_TEST(suite, test_build_building_with_golem);
SUITE_ADD_TEST(suite, test_build_building_no_materials);
SUITE_ADD_TEST(suite, test_build_destroy_road);
SUITE_ADD_TEST(suite, test_build_destroy_road_limit);
SUITE_ADD_TEST(suite, test_build_destroy_road_guard);
return suite;
}

View File

@ -158,9 +158,7 @@ const char *buildingtype(const building_type * btype, const building * b, int bs
s = btype->name(btype, b, bsize);
}
if (b && b->attribs) {
const struct building_type *bt_generic = bt_find("generic");
if (btype == bt_generic) {
if (is_building_type(btype, "generic")) {
const attrib *a = a_find(b->attribs, &at_building_generic_type);
if (a) {
s = (const char *)a->data.v;
@ -322,9 +320,8 @@ const building_type *findbuildingtype(const char *name,
return (const building_type *)type.v;
}
static int building_protection(building * b, unit * u, building_bonus bonus)
static int building_protection(const building * b, const unit * u, building_bonus bonus)
{
int i = 0;
int bsize = buildingeffsize(b, false);
const construction *cons = b->type->construction;
@ -350,17 +347,10 @@ static int building_protection(building * b, unit * u, building_bonus bonus)
}
}
static int meropis_building_protection(building * b, unit * u)
{
return 2;
}
void register_buildings(void)
{
register_function((pf_generic)building_protection,
"building_protection");
register_function((pf_generic)meropis_building_protection,
"meropis_building_protection");
register_function((pf_generic)init_smithy, "init_smithy");
register_function((pf_generic)castle_name, "castle_name");
register_function((pf_generic)castle_name_2, "castle_name_2");
@ -398,16 +388,9 @@ building *new_building(const struct building_type * btype, region * r,
{
building **bptr = &r->buildings;
building *b = (building *)calloc(1, sizeof(building));
static bool init_lighthouse = false;
static const struct building_type *bt_lighthouse = 0;
const char *bname = 0;
char buffer[32];
if (!init_lighthouse) {
bt_lighthouse = bt_find("lighthouse");
init_lighthouse = true;
}
b->no = newcontainerid();
bhash(b);
@ -417,9 +400,7 @@ building *new_building(const struct building_type * btype, region * r,
bptr = &(*bptr)->next;
*bptr = b;
if (b->type == bt_lighthouse) {
r->flags |= RF_LIGHTHOUSE;
}
update_lighthouse(b);
if (b->type->name) {
bname = LOC(lang, buildingtype(btype, b, 0));
}
@ -465,6 +446,7 @@ void remove_building(building ** blist, building * b)
/* Falls Karawanserei, Damm oder Tunnel einstürzen, wird die schon
* gebaute Straße zur Hälfte vernichtet */
// TODO: caravan, tunnel, dam modularization ? is_building_type ?
if (b->type == bt_caravan || b->type == bt_dam || b->type == bt_tunnel) {
region *r = b->region;
int d;
@ -703,3 +685,8 @@ bool in_safe_building(unit *u1, unit *u2) {
}
return false;
}
bool is_building_type(const struct building_type *btype, const char *name) {
assert(btype);
return name && strcmp(btype->_name, name)==0;
}

View File

@ -53,7 +53,7 @@ extern "C" {
typedef enum {
DEFENSE_BONUS,
CLOSE_COMBAT_ATTACK_BONUS,
CLOSE_COMBAT_ATTACK_BONUS, // TODO: only DEFENSE_BONUS is in use?
RANGED_ATTACK_BONUS,
} building_bonus;
@ -75,7 +75,7 @@ extern "C" {
const struct building * b, int size);
void(*init) (struct building_type *);
void(*age) (struct building *);
int(*protection) (struct building *, struct unit *, building_bonus);
int(*protection) (const struct building *, const struct unit *, building_bonus bonus);
double(*taxes) (const struct building *, int size);
struct attrib *attribs;
} building_type;
@ -163,6 +163,7 @@ extern "C" {
bool buildingtype_exists(const struct region *r,
const struct building_type *bt, bool working);
bool building_is_active(const struct building *b);
bool is_building_type(const struct building_type *btype, const char *name);
struct building *active_building(const struct unit *u, const struct building_type *btype);
extern const char *buildingname(const struct building *b);

View File

@ -480,6 +480,15 @@ static void test_safe_building(CuTest *tc) {
test_cleanup();
}
static void test_building_type(CuTest *tc) {
building_type *btype;
test_setup();
btype = test_create_buildingtype("house");
CuAssertIntEquals(tc, true, is_building_type(btype, "house"));
CuAssertIntEquals(tc, false, is_building_type(btype, "castle"));
test_cleanup();
}
CuSuite *get_building_suite(void)
{
CuSuite *suite = CuSuiteNew();
@ -494,6 +503,7 @@ CuSuite *get_building_suite(void)
SUITE_ADD_TEST(suite, test_buildingowner_goes_to_other_after_leave);
SUITE_ADD_TEST(suite, test_buildingowner_goes_to_same_faction_after_leave);
SUITE_ADD_TEST(suite, test_buildingowner_goes_to_empty_unit_after_leave);
SUITE_ADD_TEST(suite, test_building_type);
SUITE_ADD_TEST(suite, test_active_building);
SUITE_ADD_TEST(suite, test_buildingtype_exists);
SUITE_ADD_TEST(suite, test_safe_building);

View File

@ -764,8 +764,7 @@ static const int wagetable[7][4] = {
int cmp_wage(const struct building *b, const building * a)
{
const struct building_type *bt_castle = bt_find("castle");
if (b->type == bt_castle) {
if (is_building_type(b->type, "castle")) {
if (!a)
return 1;
if (b->size > a->size)
@ -897,18 +896,9 @@ default_wage(const region * r, const faction * f, const race * rc, int in_turn)
{
building *b = largestbuilding(r, &cmp_wage, false);
int esize = 0;
curse *c;
double wage;
attrib *a;
const building_type *artsculpture_type = bt_find("artsculpture");
static const curse_type *drought_ct, *blessedharvest_ct;
static bool init;
if (!init) {
init = true;
drought_ct = ct_find("drought");
blessedharvest_ct = ct_find("blessedharvest");
}
const struct curse_type *ctype;
if (b != NULL) {
/* TODO: this reveals imaginary castles */
@ -937,13 +927,13 @@ default_wage(const region * r, const faction * f, const race * rc, int in_turn)
}
if (rule_blessed_harvest() == HARVEST_WORK) {
/* E1 rules */
wage += curse_geteffect(get_curse(r->attribs, blessedharvest_ct));
wage += curse_geteffect(get_curse(r->attribs, ct_find("blessedharvest")));
}
}
/* Artsculpture: Income +5 */
for (b = r->buildings; b; b = b->next) {
if (b->type == artsculpture_type) {
if (is_building_type(b->type, "artsculpture")) {
wage += 5;
}
}
@ -954,8 +944,9 @@ default_wage(const region * r, const faction * f, const race * rc, int in_turn)
}
/* Bei einer Dürre verdient man nur noch ein Viertel */
if (drought_ct) {
c = get_curse(r->attribs, drought_ct);
ctype = ct_find("drought");
if (ctype) {
curse *c = get_curse(r->attribs, ctype);
if (curse_active(c))
wage /= curse_geteffect(c);
}

View File

@ -304,7 +304,7 @@ extern "C" {
const struct curse *c, int self);
int curse_cansee(const struct curse *c, const struct faction *viewer, objtype_t typ, const void *obj, int self);
#define is_cursed(a, id, id2) \
curse_active(get_curse(a, ct_find(oldcursename(id))))
(a && curse_active(get_curse(a, ct_find(oldcursename(id)))))
#define get_curseeffect(a, id, id2) \
curse_geteffect(get_curse(a, ct_find(oldcursename(id))))

View File

@ -491,7 +491,7 @@ item *i_change(item ** pi, const item_type * itype, int delta)
item *i = *pi;
i->number += delta;
if (i->number < 0) {
log_error("serious accounting error. number of items is %d.\n", i->number);
log_error("serious accounting error. number of items is %d.", i->number);
i->number = 0;
}
if (i->number == 0) {
@ -862,11 +862,9 @@ struct order *ord)
else {
const race *irace = u_irace(u);
if (irace == u_race(u)) {
static const race *rcfailure;
const race *rcfailure = rc_find("smurf");
if (!rcfailure) {
rcfailure = rc_find("smurf");
if (!rcfailure)
rcfailure = rc_find("toad");
rcfailure = rc_find("toad");
}
if (rcfailure) {
trigger *trestore = trigger_changerace(u, u_race(u), irace);

View File

@ -6,6 +6,8 @@
#include <kernel/terrain.h>
#include <kernel/unit.h>
#include <util/language.h>
#include <util/lists.h>
#include <util/log.h>
#include <util/functions.h>
#include <CuTest.h>
@ -45,8 +47,11 @@ static void test_resourcename_with_appearance(CuTest *tc) {
static void test_uchange(CuTest * tc, unit * u, const resource_type * rtype) {
int n;
struct log_t *log;
strlist *sl = 0;
assert(rtype);
log = test_log_start(LOG_CPERROR, &sl);
change_resource(u, rtype, 4);
n = get_resource(u, rtype);
CuAssertPtrNotNull(tc, rtype->uchange);
@ -54,25 +59,31 @@ static void test_uchange(CuTest * tc, unit * u, const resource_type * rtype) {
CuAssertIntEquals(tc, n - 3, rtype->uchange(u, rtype, -3));
CuAssertIntEquals(tc, n - 3, get_resource(u, rtype));
CuAssertIntEquals(tc, 0, rtype->uchange(u, rtype, -n));
CuAssertPtrNotNull(tc, sl);
CuAssertStrEquals(tc, "serious accounting error. number of items is %d.", sl->s);
CuAssertPtrEquals(tc, 0, sl->next);
test_log_stop(log, sl);
}
void test_change_item(CuTest * tc)
{
unit * u;
test_cleanup();
test_setup();
test_log_stderr(0);
test_create_itemtype("iron");
init_resources();
u = test_create_unit(test_create_faction(0), 0);
test_uchange(tc, u, get_resourcetype(R_IRON));
test_cleanup();
}
void test_resource_type(CuTest * tc)
{
struct item_type *itype;
test_cleanup();
test_setup();
CuAssertPtrEquals(tc, 0, rt_find("herpderp"));
@ -89,7 +100,7 @@ void test_finditemtype(CuTest * tc)
const item_type *itype;
struct locale * lang;
test_cleanup();
test_setup();
lang = get_or_create_locale("de");
locale_setstring(lang, "horse", "Pferd");
@ -103,7 +114,7 @@ void test_findresourcetype(CuTest * tc)
const item_type *itype;
struct locale * lang;
test_cleanup();
test_setup();
lang = get_or_create_locale("de");
locale_setstring(lang, "horse", "Pferd");
@ -124,7 +135,7 @@ static void test_fix_demand(CuTest *tc) {
terrain_type *tplain;
item_type *ltype;
test_cleanup();
test_setup();
ltype = test_create_itemtype("balm");
ltype->rtype->flags |= (RTF_ITEM | RTF_POOLED);
new_luxurytype(ltype, 0);
@ -145,7 +156,8 @@ static void test_fix_demand(CuTest *tc) {
static void test_core_resources(CuTest *tc) {
resource_type * rtype;
test_cleanup();
test_setup();
init_resources();
CuAssertPtrNotNull(tc, rtype = rt_find("money"));
CuAssertPtrNotNull(tc, rtype->itype);

View File

@ -303,19 +303,17 @@ variant read_race_reference(struct storage *store)
return result;
}
/** Returns the English name of the race, which is what the database uses.
*/
const char *dbrace(const struct race *rc)
{
static char zText[32]; // FIXME: static return value
char *zPtr = zText;
/* the english names are all in ASCII, so we don't need to worry about UTF8 */
strlcpy(zText, (const char *)LOC(get_locale("en"), rc_name_s(rc, NAME_SINGULAR)), sizeof(zText));
while (*zPtr) {
*zPtr = (char)(toupper(*zPtr));
++zPtr;
}
return zText;
void register_race_description_function(race_desc_func func, const char *name) {
register_function((pf_generic)func, name);
}
void register_race_name_function(race_name_func func, const char *name) {
register_function((pf_generic)func, name);
}
char * race_namegen(const struct race *rc, struct unit *u) {
if (rc->generate_name) {
rc->generate_name(u);
}
return NULL;
}

View File

@ -45,6 +45,8 @@ extern "C" {
struct param;
struct spell;
extern int num_races;
typedef enum {
RC_DWARF, /* 0 - Zwerg */
RC_ELF,
@ -117,7 +119,8 @@ extern "C" {
int level;
} att;
extern int num_races;
typedef const char *(*race_desc_func)(const struct race *rc, const struct locale *lang);
typedef void (*race_name_func)(struct unit *);
typedef struct race {
char *_name;
@ -149,8 +152,8 @@ extern "C" {
struct att attack[RACE_ATTACKS];
signed char bonus[MAXSKILLS];
const char *(*generate_name) (const struct unit *);
const char *(*describe) (const struct unit *, const struct locale *);
race_name_func generate_name;
race_desc_func describe;
void(*age) (struct unit * u);
bool(*move_allowed) (const struct region *, const struct region *);
struct item *(*itemdrop) (const struct race *, int size);
@ -166,8 +169,8 @@ extern "C" {
const struct race *data;
} race_list;
extern void racelist_clear(struct race_list **rl);
extern void racelist_insert(struct race_list **rl, const struct race *r);
void racelist_clear(struct race_list **rl);
void racelist_insert(struct race_list **rl, const struct race *r);
struct race_list *get_familiarraces(void);
@ -176,8 +179,8 @@ extern "C" {
/** TODO: compatibility hacks: **/
race_t old_race(const struct race *);
extern race *rc_get_or_create(const char *name);
extern const race *rc_find(const char *);
race *rc_get_or_create(const char *name);
const race *rc_find(const char *);
void free_races(void);
typedef enum name_t { NAME_SINGULAR, NAME_PLURAL, NAME_DEFINITIVE, NAME_CATEGORY } name_t;
@ -234,7 +237,6 @@ extern "C" {
#define BF_INV_NONMAGIC (1<<5) /* Immun gegen nichtmagischen Schaden */
#define BF_NO_ATTACK (1<<6) /* Kann keine ATTACKIERE Befehle ausfuehren */
int unit_old_max_hp(struct unit *u);
const char *racename(const struct locale *lang, const struct unit *u,
const race * rc);
@ -255,10 +257,9 @@ extern "C" {
variant read_race_reference(struct storage *store);
const char *raceprefix(const struct unit *u);
void give_starting_equipment(const struct equipment *eq,
struct unit *u);
const char *dbrace(const struct race *rc);
void register_race_name_function(race_name_func, const char *);
void register_race_description_function(race_desc_func, const char *);
char * race_namegen(const struct race *rc, struct unit *u);
#ifdef __cplusplus
}

View File

@ -146,23 +146,24 @@ int deathcount(const region * r)
void deathcounts(region * r, int fallen)
{
attrib *a;
static const curse_type *ctype = NULL;
attrib *a = NULL;
if (fallen == 0)
return;
if (!ctype)
ctype = ct_find("holyground");
if (ctype && curse_active(get_curse(r->attribs, ctype)))
return;
a = a_find(r->attribs, &at_deathcount);
if (!a)
if (r->attribs) {
const curse_type *ctype = ct_find("holyground");
if (ctype && curse_active(get_curse(r->attribs, ctype)))
return;
a = a_find(r->attribs, &at_deathcount);
}
if (!a) {
a = a_add(&r->attribs, a_new(&at_deathcount));
}
a->data.i += fallen;
if (a->data.i <= 0)
if (a->data.i <= 0) {
a_remove(&r->attribs, a);
}
}
/* Moveblock wird zur Zeit nicht über Attribute, sondern ein Bitfeld

View File

@ -172,9 +172,9 @@ static unit *unitorders(FILE * F, int enc, struct faction *f)
if (s[0]) {
if (s[0] != '@') {
char token[128];
char token[64];
const char *stok = s;
stok = parse_token(&stok, token, 64); // FIXME: use sizeof, but parse_token overwrites the buffer
stok = parse_token(&stok, token, sizeof(token));
if (stok) {
bool quit = false;
@ -699,6 +699,7 @@ void write_attribs(storage *store, attrib *alist, const void *owner)
unit *read_unit(struct gamedata *data)
{
unit *u;
const race *rc;
int number, n, p;
order **orderp;
char obuf[DISPLAYSIZE];
@ -760,7 +761,9 @@ unit *read_unit(struct gamedata *data)
u->age = (short)n;
READ_TOK(data->store, rname, sizeof(rname));
u_setrace(u, rc_find(rname));
rc = rc_find(rname);
assert(rc);
u_setrace(u, rc);
READ_TOK(data->store, rname, sizeof(rname));
if (rname[0] && skill_enabled(SK_STEALTH))
@ -768,8 +771,8 @@ unit *read_unit(struct gamedata *data)
else
u->irace = NULL;
if (u_race(u)->describe) {
const char *rcdisp = u_race(u)->describe(u, u->faction->locale);
if (rc->describe) {
const char *rcdisp = rc->describe(rc, u->faction->locale);
if (u->display && rcdisp) {
/* see if the data file contains old descriptions */
if (strcmp(rcdisp, u->display) == 0) {

View File

@ -298,8 +298,6 @@ int crew_skill(const ship *sh) {
int shipspeed(const ship * sh, const unit * u)
{
int k = sh->type->range;
static const struct curse_type *stormwind_ct, *nodrift_ct;
static bool init;
attrib *a;
struct curse *c;
int bonus;
@ -312,19 +310,17 @@ int shipspeed(const ship * sh, const unit * u)
assert(sh->type->construction);
assert(sh->type->construction->improvement == NULL); /* sonst ist construction::size nicht ship_type::maxsize */
if (!init) {
init = true;
stormwind_ct = ct_find("stormwind");
nodrift_ct = ct_find("nodrift");
}
if (sh->size != sh->type->construction->maxsize)
return 0;
if (curse_active(get_curse(sh->attribs, stormwind_ct)))
k *= 2;
if (curse_active(get_curse(sh->attribs, nodrift_ct)))
k += 1;
if (sh->attribs) {
if (curse_active(get_curse(sh->attribs, ct_find("stormwind")))) {
k *= 2;
}
if (curse_active(get_curse(sh->attribs, ct_find("nodrift")))) {
k += 1;
}
}
if (u->faction->race == u_race(u)) {
/* race bonus for this faction? */
if (fval(u_race(u), RCF_SHIPSPEED)) {
@ -333,7 +329,7 @@ int shipspeed(const ship * sh, const unit * u)
}
bonus = ShipSpeedBonus(u);
if (bonus > 0 && sh->type->range_max>sh->type->range) {
if (bonus > 0 && sh->type->range_max > sh->type->range) {
int crew = crew_skill(sh);
int crew_bonus = (crew / sh->type->sumskill / 2) - 1;
if (crew_bonus > 0) {
@ -358,7 +354,7 @@ int shipspeed(const ship * sh, const unit * u)
c = c->nexthash;
}
if (sh->damage>0) {
if (sh->damage > 0) {
int size = sh->size * DAMAGE_SCALE;
k *= (size - sh->damage);
k = (k + size - 1) / size;

View File

@ -123,33 +123,6 @@ int skill_mod(const race * rc, skill_t sk, const struct terrain_type *terrain)
return result;
}
#define RCMODMAXHASH 31
#ifdef FASTER_SKILLMOD
static struct skillmods {
struct skillmods *next;
const struct race *race;
struct modifiers {
int value[MAXSKILLS];
} mod[MAXTERRAINS];
} *modhash[RCMODMAXHASH];
static struct skillmods *init_skills(const race * rc)
{
terrain_t t;
struct skillmods *mods =
(struct skillmods *)calloc(1, sizeof(struct skillmods));
mods->race = rc;
for (t = 0; t != MAXTERRAINS; ++t) {
skill_t sk;
for (sk = 0; sk != MAXSKILLS; ++sk) {
mods->mod[t].value[sk] = skill_mod(rc, sk, newterrain(t));
}
}
return mods;
}
#endif
int rc_skillmod(const struct race *rc, const region * r, skill_t sk)
{
int mods = 0;
@ -157,21 +130,9 @@ int rc_skillmod(const struct race *rc, const region * r, skill_t sk)
if (!skill_enabled(sk)) {
return 0;
}
#ifdef FASTER_SKILLMOD
unsigned int index = hashstring(rc->_name) % RCMODMAXHASH;
struct skillmods **imods = &modhash[index];
while (*imods && (*imods)->race != rc) {
imods = &(*imods)->next;
}
if (*imods == NULL) {
*imods = init_skills(rc);
}
mods = (*imods)->mod[rterrain(r)].value[sk];
#else
if (r) {
mods = skill_mod(rc, sk, r->terrain);
}
#endif
if (rc == get_race(RC_ELF) && r && r_isforest(r)) {
if (sk == SK_PERCEPTION || sk == SK_STEALTH) {
++mods;

View File

@ -71,7 +71,7 @@ spell * create_spell(const char * name, unsigned int id)
assert(len + sizeof(sp) < sizeof(buffer));
if (cb_find_str(&cb_spells, name)) {
log_error("create_spell: duplicate name '%s'\n", name);
log_error("create_spell: duplicate name '%s'", name);
return 0;
}
sp = (spell *)calloc(1, sizeof(spell));

View File

@ -1,9 +1,11 @@
#include <platform.h>
#include <quicklist.h>
#include <kernel/spell.h>
#include <util/log.h>
#include <util/log.h>
#include <util/lists.h>
#include <quicklist.h>
#include <CuTest.h>
#include <tests.h>
@ -13,39 +15,58 @@ static void test_create_a_spell(CuTest * tc)
{
spell * sp;
test_cleanup();
test_setup();
CuAssertPtrEquals(tc, 0, spells);
CuAssertPtrEquals(tc, 0, find_spell("testspell"));
sp = create_spell("testspell", 0);
CuAssertPtrEquals(tc, sp, find_spell("testspell"));
CuAssertPtrNotNull(tc, spells);
test_cleanup();
}
static void test_create_duplicate_spell(CuTest * tc)
{
spell *sp;
/* FIXME: this test emits ERROR messages (duplicate spells), inject a logger to verify that */
struct log_t *log;
strlist *sl = 0;
test_setup();
test_log_stderr(0);
log = test_log_start(LOG_CPERROR, &sl);
test_cleanup();
CuAssertPtrEquals(tc, 0, find_spell("testspell"));
sp = create_spell("testspell", 0);
CuAssertPtrEquals(tc, 0, create_spell("testspell", 0));
CuAssertPtrNotNull(tc, sl);
CuAssertStrEquals(tc, "create_spell: duplicate name '%s'", sl->s);
CuAssertPtrEquals(tc, 0, sl->next);
CuAssertPtrEquals(tc, sp, find_spell("testspell"));
test_log_stop(log, sl);
test_cleanup();
}
static void test_create_spell_with_id(CuTest * tc)
{
spell *sp;
/* FIXME: this test emits ERROR messages (duplicate spells), inject a logger to verify that */
struct log_t *log;
strlist *sl = 0;
test_setup();
test_log_stderr(0);
log = test_log_start(LOG_CPERROR, &sl);
test_cleanup();
CuAssertPtrEquals(tc, 0, find_spellbyid(42));
sp = create_spell("testspell", 42);
CuAssertPtrEquals(tc, sp, find_spellbyid(42));
CuAssertPtrEquals(tc, 0, create_spell("testspell", 47));
CuAssertPtrEquals(tc, 0, find_spellbyid(47));
CuAssertPtrNotNull(tc, sl);
CuAssertStrEquals(tc, "create_spell: duplicate name '%s'", sl->s);
CuAssertPtrEquals(tc, 0, sl->next);
test_log_stop(log, sl);
test_cleanup();
}
CuSuite *get_spell_suite(void)

View File

@ -470,7 +470,7 @@ const char *u_description(const unit * u, const struct locale *lang)
return u->display;
}
else if (u_race(u)->describe) {
return u_race(u)->describe(u, lang);
return u_race(u)->describe(u->_race, lang);
}
return NULL;
}
@ -863,16 +863,15 @@ bool can_survive(const unit * u, const region * r)
if ((fval(r->terrain, WALK_INTO) && (u_race(u)->flags & RCF_WALK))
|| (fval(r->terrain, SWIM_INTO) && (u_race(u)->flags & RCF_SWIM))
|| (fval(r->terrain, FLY_INTO) && (u_race(u)->flags & RCF_FLY))) {
static const curse_type *ctype = NULL;
if (has_horses(u) && !fval(r->terrain, WALK_INTO))
return false;
if (!ctype)
ctype = ct_find("holyground");
if (fval(u_race(u), RCF_UNDEAD) && curse_active(get_curse(r->attribs, ctype)))
return false;
if (r->attribs) {
const curse_type *ctype = ct_find("holyground");
if (fval(u_race(u), RCF_UNDEAD) && curse_active(get_curse(r->attribs, ctype)))
return false;
}
return true;
}
return false;
@ -1217,54 +1216,51 @@ static int item_modification(const unit * u, skill_t sk, int val)
static int att_modification(const unit * u, skill_t sk)
{
double result = 0;
static bool init = false; // TODO: static variables are bad global state
static const curse_type *skillmod_ct, *gbdream_ct, *worse_ct;
curse *c;
if (!init) {
init = true;
skillmod_ct = ct_find("skillmod");
gbdream_ct = ct_find("gbdream");
worse_ct = ct_find("worse");
}
c = get_curse(u->attribs, worse_ct);
if (c != NULL)
result += curse_geteffect(c);
if (skillmod_ct) {
attrib *a = a_find(u->attribs, &at_curse);
while (a && a->type == &at_curse) {
curse *c = (curse *)a->data.v;
if (c->type == skillmod_ct && c->data.i == sk) {
result += curse_geteffect(c);
break;
if (u->attribs) {
curse *c;
const curse_type *skillmod_ct = ct_find("skillmod");
const curse_type *worse_ct = ct_find("worse");
c = get_curse(u->attribs, worse_ct);
if (c != NULL)
result += curse_geteffect(c);
if (skillmod_ct) {
attrib *a = a_find(u->attribs, &at_curse);
while (a && a->type == &at_curse) {
curse *c = (curse *)a->data.v;
if (c->type == skillmod_ct && c->data.i == sk) {
result += curse_geteffect(c);
break;
}
a = a->next;
}
a = a->next;
}
}
/* TODO hier kann nicht mit get/iscursed gearbeitet werden, da nur der
* jeweils erste vom Typ C_GBDREAM zurueckgegen wird, wir aber alle
* durchsuchen und aufaddieren muessen */
if (gbdream_ct && u->region) {
int bonus = 0, malus = 0;
attrib *a = a_find(u->region->attribs, &at_curse);
while (a && a->type == &at_curse) {
curse *c = (curse *)a->data.v;
if (u->region && u->region->attribs) {
const curse_type *gbdream_ct = ct_find("gbdream");
if (gbdream_ct) {
int bonus = 0, malus = 0;
attrib *a = a_find(u->region->attribs, &at_curse);
while (a && a->type == &at_curse) {
curse *c = (curse *)a->data.v;
if (curse_active(c) && c->type == gbdream_ct) {
int effect = curse_geteffect_int(c);
bool allied = alliedunit(c->magician, u->faction, HELP_GUARD);
if (allied) {
if (effect > bonus) bonus = effect;
}
else {
if (effect < malus) malus = effect;
if (curse_active(c) && c->type == gbdream_ct) {
int effect = curse_geteffect_int(c);
bool allied = alliedunit(c->magician, u->faction, HELP_GUARD);
if (allied) {
if (effect > bonus) bonus = effect;
}
else {
if (effect < malus) malus = effect;
}
}
a = a->next;
}
a = a->next;
result = result + bonus + malus;
}
result = result + bonus + malus;
}
return (int)result;
@ -1393,15 +1389,12 @@ void default_name(const unit *u, char name[], int len) {
const char * result;
const struct locale * lang = u->faction ? u->faction->locale : default_locale;
if (lang) {
static const char * prefix[MAXLOCALES];
int i = locale_index(lang);
/*if (!prefix[i]) {*/
prefix[i] = LOC(lang, "unitdefault");
if (!prefix[i]) {
prefix[i] = parameters[P_UNIT];
const char * prefix;
prefix = LOC(lang, "unitdefault");
if (!prefix) {
prefix= parameters[P_UNIT];
}
/*}*/
result = prefix[i];
result = prefix;
}
else {
result = parameters[P_UNIT];
@ -1414,9 +1407,10 @@ void default_name(const unit *u, char name[], int len) {
void name_unit(unit * u)
{
if (u_race(u)->generate_name) {
const char *gen_name = u_race(u)->generate_name(u);
char *gen_name = race_namegen(u_race(u), u);
if (gen_name) {
unit_setname(u, gen_name);
free(u->_name);
u->_name = gen_name;
}
else {
unit_setname(u, racename(u->faction->locale, u, u_race(u)));
@ -1665,7 +1659,6 @@ int unit_max_hp(const unit * u)
{
int h;
double p;
static const curse_type *heal_ct = NULL;
int rule_stamina = config_get_int("rules.stamina", STAMINA_AFFECTS_HP);
h = u_race(u)->hitpoints;
@ -1675,9 +1668,8 @@ int unit_max_hp(const unit * u)
}
/* der healing curse veraendert die maximalen hp */
if (u->region) {
if (heal_ct == NULL)
heal_ct = ct_find("healingzone");
if (u->region && u->region->attribs) {
const curse_type *heal_ct = ct_find("healingzone");
if (heal_ct) {
curse *c = get_curse(u->region->attribs, heal_ct);
if (c) {

View File

@ -305,7 +305,7 @@ static int parse_buildings(xmlDocPtr doc)
btype->age = (void(*)(struct building *))fun;
}
else if (strcmp((const char *)propValue, "protection") == 0) {
btype->protection = (int(*)(struct building *, struct unit *, building_bonus))fun;
btype->protection = (int(*)(const struct building *, const struct unit *, building_bonus))fun;
}
else if (strcmp((const char *)propValue, "taxes") == 0) {
btype->taxes = (double(*)(const struct building *, int))fun;
@ -1797,11 +1797,10 @@ static int parse_races(xmlDocPtr doc)
}
assert(propValue != NULL);
if (strcmp((const char *)propValue, "name") == 0) {
rc->generate_name = (const char *(*)(const struct unit *))fun;
rc->generate_name = (race_name_func)fun;
}
else if (strcmp((const char *)propValue, "describe") == 0) {
rc->describe =
(const char *(*)(const struct unit *, const struct locale *))fun;
rc->describe = (race_desc_func)fun;
}
else if (strcmp((const char *)propValue, "age") == 0) {
rc->age = (void(*)(struct unit *))fun;

View File

@ -3082,10 +3082,7 @@ static void age_stonecircle(building *b) {
static building *age_building(building * b)
{
const struct building_type *bt_blessed;
bt_blessed = bt_find("blessedstonecircle");
if (bt_blessed && b->type == bt_blessed) {
if (is_building_type(b->type, "blessedstonecircle")) {
age_stonecircle(b);
}
a_age(&b->attribs, b);
@ -3487,15 +3484,13 @@ static double heal_factor(const unit * u)
void monthly_healing(void)
{
region *r;
static const curse_type *heal_ct = NULL;
if (heal_ct == NULL)
heal_ct = ct_find("healingzone");
const curse_type *heal_ct = ct_find("healingzone");
for (r = regions; r; r = r->next) {
unit *u;
double healingcurse = 0;
if (heal_ct != NULL) {
if (r->attribs && heal_ct) {
/* bonus zurücksetzen */
curse *c = get_curse(r->attribs, heal_ct);
if (c != NULL) {

View File

@ -25,8 +25,7 @@ static attrib_type at_lighthouse = {
*/
void update_lighthouse(building * lh)
{
const struct building_type *bt_lighthouse = bt_find("lighthouse");
if (bt_lighthouse && lh->type == bt_lighthouse) {
if (is_building_type(lh->type, "lighthouse")) {
region *r = lh->region;
int d = (int)log10(lh->size) + 1;
int x;
@ -111,7 +110,7 @@ bool check_leuchtturm(region * r, faction * f)
a = a->next) {
building *b = (building *)a->data.v;
assert(b->type == bt_find("lighthouse"));
assert(is_building_type(b->type, "lighthouse"));
if (fval(b, BLD_MAINTAINED) && b->size >= 10) {
int maxd = (int)log10(b->size) + 1;

View File

@ -939,16 +939,16 @@ void spawn_undead(void)
{
region *r;
faction *monsters = get_monsters();
const curse_type *ctype = ct_find("holyground");
for (r = regions; r; r = r->next) {
int unburied = deathcount(r);
static const curse_type *ctype = NULL;
if (!ctype)
ctype = ct_find("holyground");
if (ctype && curse_active(get_curse(r->attribs, ctype)))
continue;
if (r->attribs && ctype) {
if (curse_active(get_curse(r->attribs, ctype))) {
continue;
}
}
/* Chance 0.1% * chaosfactor */
if (r->land && unburied > rpeasants(r) / 20
&& rng_int() % 10000 < (100 + 100 * chaosfactor(r))) {

View File

@ -57,6 +57,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#include "skill.h"
/* util includes */
#include <util/assert.h>
#include <util/attrib.h>
#include <util/base36.h>
#include <util/bsdstring.h>
@ -77,7 +78,6 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#include <attributes/targetregion.h>
/* libc includes */
#include <assert.h>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
@ -127,6 +127,7 @@ get_followers(unit * target, region * r, const region_list * route_end,
const attrib *a = a_find(uf->attribs, &at_follow);
if (a && a->data.v == target) {
follower *fnew = (follower *)malloc(sizeof(follower));
assert_alloc(fnew);
fnew->uf = uf;
fnew->ut = target;
fnew->route_end = route_end;
@ -495,7 +496,8 @@ static double overload(const region * r, ship * sh)
if (sh->type->construction && sh->size != sh->type->construction->maxsize) {
return DBL_MAX;
} else {
}
else {
int n = 0, p = 0;
int mcabins = sh->type->cabins;
@ -585,18 +587,21 @@ static void leave_trail(ship * sh, region * from, region_list * route)
while (a != NULL && a->type == &at_shiptrail) {
td = (traveldir *)a->data.v;
if (td->no == sh->no)
if (td->no == sh->no) {
td->dir = dir;
td->age = 2;
break;
}
a = a->next;
}
if (a == NULL || a->type != &at_shiptrail) {
if (a == NULL) {
a = a_add(&(r->attribs), a_new(&at_shiptrail));
td = (traveldir *)a->data.v;
td->no = sh->no;
td->dir = dir;
td->age = 2;
}
td->dir = dir;
td->age = 2;
}
route = route->next;
r = rn;
@ -664,8 +669,7 @@ static bool is_freezing(const unit * u)
int check_ship_allowed(struct ship *sh, const region * r)
{
int c = 0;
const building_type *bt_harbour = NULL;
bt_harbour = bt_find("harbour");
const building_type *bt_harbour = bt_find("harbour");
if (sh->region && r_insectstalled(r)) {
/* insekten dürfen nicht hier rein. haben wir welche? */
@ -769,8 +773,9 @@ static void msg_to_ship_inmates(ship *sh, unit **firstu, unit **lastu, message *
*lastu = u->next;
}
}
if (shipfirst)
if (shipfirst) {
*firstu = shipfirst;
}
for (u = *firstu; u != *lastu; u = u->next) {
freset(u->faction, FFL_MARK);
}
@ -823,7 +828,7 @@ static void drifting_ships(region * r)
/* Kapitän bestimmen */
captain = ship_owner(sh);
if (captain && effskill(captain, SK_SAILING, r) < sh->type->cptskill)
captain = NULL;
captain = NULL;
/* Kapitän da? Beschädigt? Genügend Matrosen?
* Genügend leicht? Dann ist alles OK. */
@ -838,7 +843,8 @@ static void drifting_ships(region * r)
ovl = overload(r, sh);
if (ovl >= overload_start()) {
rnext = NULL;
} else {
}
else {
/* Auswahl einer Richtung: Zuerst auf Land, dann
* zufällig. Falls unmögliches Resultat: vergiß es. */
rnext = drift_target(sh);
@ -865,7 +871,8 @@ static void drifting_ships(region * r)
if (ovl >= overload_start()) {
damage_ship(sh, damage_overload(ovl));
msg_to_ship_inmates(sh, &firstu, &lastu, msg_message("massive_overload", "ship", sh));
} else
}
else
damage_ship(sh, damage_drift);
if (sh->damage >= sh->size * DAMAGE_SCALE) {
msg_to_ship_inmates(sh, &firstu, &lastu, msg_message("shipsink", "ship", sh));
@ -915,6 +922,7 @@ static unit *bewegung_blockiert_von(unit * reisender, region * r)
int guard_count = 0;
int stealth = eff_stealth(reisender, r);
const struct resource_type *ramulet = get_resourcetype(R_AMULET_OF_TRUE_SEEING);
const struct building_type *castle_bt = bt_find("castle");
double base_prob = config_get_flt("rules.guard.base_stop_prob", .3);
double skill_prob = config_get_flt("rules.guard.skill_stop_prob", .1);
@ -939,7 +947,7 @@ static unit *bewegung_blockiert_von(unit * reisender, region * r)
double prob_u = (sk - stealth) * skill_prob;
/* amulet counts at most once */
prob_u += _min(1, _min(u->number, i_get(u->items, ramulet->itype))) * amulet_prob;
if (u->building && (u->building->type == bt_find("castle")) && u == building_owner(u->building))
if (u->building && (u->building->type == castle_bt) && u == building_owner(u->building))
prob_u += castle_prob*buildingeffsize(u->building, 0);
if (prob_u >= prob) {
prob = prob_u;
@ -1048,23 +1056,22 @@ unit *is_guarded(region * r, unit * u, unsigned int mask)
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))
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;
if (r->attribs) {
const curse_type *fogtrap_ct = ct_find("fogtrap");
curse *c = get_curse(r->attribs, fogtrap_ct);
return curse_active(c);
}
return false;
}
@ -1303,7 +1310,6 @@ static bool roadto(const region * r, direction_t dir)
/* wenn es hier genug strassen gibt, und verbunden ist, und es dort
* genug strassen gibt, dann existiert eine strasse in diese richtung */
region *r2;
static const curse_type *roads_ct = NULL;
assert(r);
assert(dir < MAXDIRECTIONS);
@ -1313,13 +1319,14 @@ static bool roadto(const region * r, direction_t dir)
if (r == NULL || r2 == NULL)
return false;
if (roads_ct == NULL)
roads_ct = ct_find("magicstreet");
if (roads_ct != NULL) {
if (get_curse(r->attribs, roads_ct) != NULL)
return true;
if (get_curse(r2->attribs, roads_ct) != NULL)
return true;
if (r->attribs || r2->attribs) {
const curse_type *roads_ct = ct_find("magicstreet");
if (roads_ct != NULL) {
if (get_curse(r->attribs, roads_ct) != NULL)
return true;
if (get_curse(r2->attribs, roads_ct) != NULL)
return true;
}
}
if (r->terrain->max_road <= 0)
@ -1458,8 +1465,6 @@ static void make_route(unit * u, order * ord, region_list ** routep)
static int movement_speed(unit * u)
{
int mp = BP_WALKING;
static const curse_type *speed_ct;
static bool init = false;
double dk = u_race(u)->speed;
assert(u->number);
@ -1477,15 +1482,14 @@ static int movement_speed(unit * u)
break;
}
if (!init) {
init = true;
speed_ct = ct_find("speed");
}
if (speed_ct) {
curse *c = get_curse(u->attribs, speed_ct);
if (c != NULL) {
int men = get_cursedmen(u, c);
dk *= 1.0 + (double)men / (double)u->number;
if (u->attribs) {
const curse_type *speed_ct = ct_find("speed");
if (speed_ct) {
curse *c = get_curse(u->attribs, speed_ct);
if (c != NULL) {
int men = get_cursedmen(u, c);
dk *= 1.0 + (double)men / (double)u->number;
}
}
}
@ -1540,6 +1544,7 @@ static arg_regions *var_copy_regions(const region_list * begin, int size)
assert(size > 0);
arg_regions *dst =
(arg_regions *)malloc(sizeof(arg_regions) + sizeof(region *) * (size_t)size);
assert_alloc(dst);
dst->nregions = size;
dst->regions = (region **)(dst + 1);
for (rsrc = begin; i != size; rsrc = rsrc->next) {

View File

@ -22,6 +22,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
/* kernel includes */
#include <kernel/unit.h>
#include <kernel/race.h>
#include <kernel/region.h>
#include <kernel/faction.h>
#include <kernel/race.h>
@ -31,8 +32,8 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
/* util includes */
#include <util/base36.h>
#include <util/bsdstring.h>
#include <util/functions.h>
#include <util/language.h>
#include <util/functions.h>
#include <util/rng.h>
#include <util/unicode.h>
@ -44,108 +45,113 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#include <stdio.h>
#include <string.h>
static const char *describe_braineater(unit * u, const struct locale *lang)
static const char *describe_race(const race * rc, const struct locale *lang)
{
return LOC(lang, "describe_braineater");
char zText[32];
sprintf(zText, "describe_%s", rc->_name);
return LOC(lang, zText);
}
static const char *make_names(const char *monster, int *num_postfix,
int pprefix, int *num_name, int *num_prefix, int ppostfix)
static void count_particles(const char *monster, int *num_prefix, int *num_name, int *num_postfix)
{
int uv, uu, un;
static char name[NAMESIZE + 1]; // FIXME: static return value
char zText[32];
const char *str;
if (*num_prefix == 0) {
for (*num_prefix = 0;; ++*num_prefix) {
sprintf(zText, "%s_prefix_%d", monster, *num_prefix);
str = locale_getstring(default_locale, zText);
if (str == NULL)
break;
}
for (*num_name = 0;; ++*num_name) {
sprintf(zText, "%s_name_%d", monster, *num_name);
str = locale_getstring(default_locale, zText);
if (str == NULL)
break;
}
for (*num_postfix = 0;; ++*num_postfix) {
sprintf(zText, "%s_postfix_%d", monster, *num_postfix);
str = locale_getstring(default_locale, zText);
if (str == NULL)
break;
}
for (*num_prefix = 0;; ++*num_prefix) {
sprintf(zText, "%s_prefix_%d", monster, *num_prefix);
str = locale_getstring(default_locale, zText);
if (str == NULL)
break;
}
for (*num_name = 0;; ++*num_name) {
sprintf(zText, "%s_name_%d", monster, *num_name);
str = locale_getstring(default_locale, zText);
if (str == NULL)
break;
}
for (*num_postfix = 0;; ++*num_postfix) {
sprintf(zText, "%s_postfix_%d", monster, *num_postfix);
str = locale_getstring(default_locale, zText);
if (str == NULL)
break;
}
}
static void make_name(unit *u, const char *monster, int *num_postfix,
int pprefix, int *num_name, int *num_prefix, int ppostfix)
{
if (*num_name == 0) {
return NULL;
count_particles(monster, num_prefix, num_name, num_postfix);
}
if (*num_name > 0) {
char name[NAMESIZE + 1];
char zText[32];
int uv = 0, uu = 0, un = 0;
const char *str;
/* nur 50% aller Namen haben "Vor-Teil" */
uv = rng_int() % (*num_prefix * pprefix);
uu = rng_int() % *num_name;
/* nur 50% aller Namen haben "Nach-Teil", wenn kein Vor-Teil */
if (*num_postfix > 0 && uv >= *num_prefix) {
un = rng_int() % *num_postfix;
}
else {
un = rng_int() % (*num_postfix * ppostfix);
}
name[0] = 0;
if (uv < *num_prefix) {
sprintf(zText, "%s_prefix_%d", monster, uv);
str = locale_getstring(default_locale, zText);
if (str) {
size_t sz = strlcpy(name, (const char *)str, sizeof(name));
strlcpy(name + sz, " ", sizeof(name) - sz);
if (*num_prefix > 0) {
uv = rng_int() % (*num_prefix * pprefix);
}
}
uu = rng_int() % *num_name;
sprintf(zText, "%s_name_%d", monster, uu);
str = locale_getstring(default_locale, zText);
if (str)
strlcat(name, (const char *)str, sizeof(name));
if (*num_postfix > 0 && uv >= *num_prefix) {
un = rng_int() % *num_postfix;
}
else {
un = rng_int() % (*num_postfix * ppostfix);
}
if (un < *num_postfix) {
sprintf(zText, "%s_postfix_%d", monster, un);
name[0] = 0;
if (uv < *num_prefix) {
sprintf(zText, "%s_prefix_%d", monster, uv);
str = locale_getstring(default_locale, zText);
if (str) {
size_t sz = strlcpy(name, (const char *)str, sizeof(name));
strlcpy(name + sz, " ", sizeof(name) - sz);
}
}
sprintf(zText, "%s_name_%d", monster, uu);
str = locale_getstring(default_locale, zText);
if (str) {
strlcat(name, " ", sizeof(name));
if (str)
strlcat(name, (const char *)str, sizeof(name));
if (un < *num_postfix) {
sprintf(zText, "%s_postfix_%d", monster, un);
str = locale_getstring(default_locale, zText);
if (str) {
strlcat(name, " ", sizeof(name));
strlcat(name, (const char *)str, sizeof(name));
}
}
unit_setname(u, name);
}
return name;
}
static const char *undead_name(const unit * u)
static void undead_name(unit * u)
{
static int num_postfix, num_name, num_prefix;
return make_names("undead", &num_postfix, 2, &num_name, &num_prefix, 2);
make_name(u, "undead", &num_postfix, 2, &num_name, &num_prefix, 2);
}
static const char *skeleton_name(const unit * u)
static void skeleton_name(unit * u)
{
static int num_postfix, num_name, num_prefix;
return make_names("skeleton", &num_postfix, 5, &num_name, &num_prefix, 2);
make_name(u, "skeleton", &num_postfix, 5, &num_name, &num_prefix, 2);
}
static const char *zombie_name(const unit * u)
static void zombie_name(unit * u)
{
static int num_postfix, num_name, num_prefix;
return make_names("zombie", &num_postfix, 5, &num_name, &num_prefix, 2);
make_name(u, "zombie", &num_postfix, 5, &num_name, &num_prefix, 2);
}
static const char *ghoul_name(const unit * u)
static void ghoul_name(unit * u)
{
static int num_postfix, num_name, num_prefix;
return make_names("ghoul", &num_postfix, 5, &num_name, &num_prefix, 4);
make_name(u, "ghoul", &num_postfix, 5, &num_name, &num_prefix, 4);
}
/* Drachen */
@ -213,15 +219,18 @@ const char *silbe3[SIL3] = {
"bus",
};
static const char *generic_name(const unit * u)
static void generic_name(unit * u)
{
const char * name = rc_name_s(u_race(u), (u->number == 1) ? NAME_SINGULAR : NAME_PLURAL);
return LOC(u->faction->locale, name);
name = LOC(u->faction->locale, name);
if (name) {
unit_setname(u, name);
}
}
static const char *dragon_name(const unit * u)
static void dragon_name(unit * u)
{
static char name[NAMESIZE + 1]; // FIXME: static return value
char name[NAMESIZE + 1];
int rnd, ter = 0;
int anzahl = 1;
static int num_postfix;
@ -262,7 +271,7 @@ static const char *dragon_name(const unit * u)
}
if (num_postfix <=0) {
return NULL;
return;
}
else if (num_postfix < 6) {
rnd = rng_int() % num_postfix;
@ -305,7 +314,7 @@ static const char *dragon_name(const unit * u)
}
}
return name;
unit_setname(u, name);
}
/* Dracoide */
@ -357,9 +366,9 @@ static const char *drac_suf[DRAC_SUF] = {
"k"
};
static const char *dracoid_name(const unit * u)
static void dracoid_name(unit * u)
{
static char name[NAMESIZE + 1]; // FIXME: static return value
static char name[NAMESIZE + 1];
int mid_syllabels;
size_t sz;
@ -377,7 +386,7 @@ static const char *dracoid_name(const unit * u)
sz += strlcat(name, drac_mid[rng_int() % DRAC_MID], sizeof(name));
}
sz += strlcat(name, drac_suf[rng_int() % DRAC_SUF], sizeof(name));
return name;
unit_setname(u, name);
}
/** returns an abbreviation of a string.
@ -473,15 +482,15 @@ const char *abkz(const char *s, char *buf, size_t buflen, size_t maxchars)
void register_names(void)
{
register_function((pf_generic)describe_braineater, "describe_braineater");
register_race_description_function(describe_race, "describe_race");
/* function name
* generate a name for a nonplayerunit
* race->generate_name() */
register_function((pf_generic)undead_name, "nameundead");
register_function((pf_generic)skeleton_name, "nameskeleton");
register_function((pf_generic)zombie_name, "namezombie");
register_function((pf_generic)ghoul_name, "nameghoul");
register_function((pf_generic)dragon_name, "namedragon");
register_function((pf_generic)dracoid_name, "namedracoid");
register_function((pf_generic)generic_name, "namegeneric");
register_race_name_function(undead_name, "nameundead");
register_race_name_function(skeleton_name, "nameskeleton");
register_race_name_function(zombie_name, "namezombie");
register_race_name_function(ghoul_name, "nameghoul");
register_race_name_function(dracoid_name, "namedracoid");
register_race_name_function(dragon_name, "namedragon");
register_race_name_function(generic_name, "namegeneric");
}

View File

@ -21,7 +21,9 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#ifdef __cplusplus
extern "C" {
#endif
extern void register_names(void);
struct unit;
void register_names(void);
const char *abkz(const char *s, char *buf, size_t size, size_t maxchars);
#ifdef __cplusplus

44
src/names.test.c Normal file
View File

@ -0,0 +1,44 @@
#include <platform.h>
#include "names.h"
#include <kernel/race.h>
#include <kernel/unit.h>
#include <util/language.h>
#include <util/functions.h>
#include <CuTest.h>
#include "tests.h"
static void test_names(CuTest * tc)
{
race_name_func foo;
unit *u;
race *rc;
test_cleanup();
register_names();
default_locale = test_create_locale();
u = test_create_unit(test_create_faction(0), test_create_region(0, 0, 0));
rc = test_create_race("undead");
locale_setstring(default_locale, "undead_name_0", "Graue");
locale_setstring(default_locale, "undead_postfix_0", "Kobolde");
CuAssertPtrNotNull(tc, foo = (race_name_func)get_function("nameundead"));
rc->generate_name = foo;
race_namegen(rc, u);
CuAssertStrEquals(tc, "Graue Kobolde", u->_name);
CuAssertPtrNotNull(tc, get_function("nameskeleton"));
CuAssertPtrNotNull(tc, get_function("namezombie"));
CuAssertPtrNotNull(tc, get_function("nameghoul"));
CuAssertPtrNotNull(tc, get_function("namedragon"));
CuAssertPtrNotNull(tc, get_function("namedracoid"));
CuAssertPtrNotNull(tc, get_function("namegeneric"));
CuAssertPtrNotNull(tc, get_function("describe_race"));
test_cleanup();
}
CuSuite *get_names_suite(void)
{
CuSuite *suite = CuSuiteNew();
SUITE_ADD_TEST(suite, test_names);
return suite;
}

View File

@ -6,7 +6,7 @@
#include <CuTest.h>
static void test_add_prefix(CuTest *tc) {
test_cleanup();
test_setup();
CuAssertPtrEquals(tc, 0, race_prefixes);
add_raceprefix("sea");
CuAssertPtrNotNull(tc, race_prefixes);
@ -26,4 +26,4 @@ CuSuite *get_prefix_suite(void)
CuSuite *suite = CuSuiteNew();
SUITE_ADD_TEST(suite, test_add_prefix);
return suite;
}
}

View File

@ -20,10 +20,10 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#include <kernel/config.h>
#include "randenc.h"
#include "volcano.h"
#include "economy.h"
#include "monster.h"
#include "move.h"
#include "alchemy.h"
#include "chaos.h"
#include "study.h"
@ -412,118 +412,6 @@ void encounters(void)
}
}
static int nb_armor(const unit * u, int index)
{
const item *itm;
int av = 0;
int s = 0, a = 0;
if (!(u_race(u)->battle_flags & BF_EQUIPMENT))
return 0;
/* Normale Rüstung */
for (itm = u->items; itm; itm = itm->next) {
const armor_type *atype = itm->type->rtype->atype;
if (atype != NULL) {
int *schutz = &a;
if (atype->flags & ATF_SHIELD)
schutz = &s;
if (*schutz <= index) {
*schutz += itm->number;
if (*schutz > index) {
av += atype->prot;
}
}
}
}
return av;
}
static int
damage_unit(unit * u, const char *dam, bool physical, bool magic)
{
int *hp, hpstack[20];
int h;
int i, dead = 0, hp_rem = 0, heiltrank;
double magres = magic_resistance(u);
assert(u->number);
if (fval(u_race(u), RCF_ILLUSIONARY) || u_race(u) == get_race(RC_SPELL)) {
return 0;
}
assert(u->number <= u->hp);
h = u->hp / u->number;
/* HP verteilen */
if (u->number < 20) {
hp = hpstack;
}
else {
hp = malloc(u->number * sizeof(int));
}
for (i = 0; i < u->number; i++)
hp[i] = h;
h = u->hp - (u->number * h);
for (i = 0; i < h; i++)
hp[i]++;
/* Schaden */
for (i = 0; i < u->number; i++) {
int damage = dice_rand(dam);
if (magic)
damage = (int)(damage * (1.0 - magres));
if (physical)
damage -= nb_armor(u, i);
hp[i] -= damage;
}
/* Auswirkungen */
for (i = 0; i < u->number; i++) {
if (hp[i] <= 0) {
heiltrank = 0;
/* Sieben Leben */
if (old_race(u_race(u)) == RC_CAT && (chance(1.0 / 7))) {
hp[i] = u->hp / u->number;
hp_rem += hp[i];
continue;
}
/* Heiltrank */
if (oldpotiontype[P_HEAL]) {
if (get_effect(u, oldpotiontype[P_HEAL]) > 0) {
change_effect(u, oldpotiontype[P_HEAL], -1);
heiltrank = 1;
}
else if (i_get(u->items, oldpotiontype[P_HEAL]->itype) > 0) {
i_change(&u->items, oldpotiontype[P_HEAL]->itype, -1);
change_effect(u, oldpotiontype[P_HEAL], 3);
heiltrank = 1;
}
if (heiltrank && (chance(0.50))) {
hp[i] = u->hp / u->number;
hp_rem += hp[i];
continue;
}
}
dead++;
}
else {
hp_rem += hp[i];
}
}
scale_number(u, u->number - dead);
u->hp = hp_rem;
if (hp != hpstack) {
free(hp);
}
return dead;
}
void drown(region * r)
{
if (fval(r->terrain, SEA_REGION)) {
@ -542,106 +430,6 @@ void drown(region * r)
}
}
region *rrandneighbour(region * r)
{
direction_t i;
region *rc = NULL;
int rr, c = 0;
/* Nachsehen, wieviele Regionen in Frage kommen */
for (i = 0; i != MAXDIRECTIONS; i++) {
c++;
}
/* Zufällig eine auswählen */
rr = rng_int() % c;
/* Durchzählen */
c = -1;
for (i = 0; i != MAXDIRECTIONS; i++) {
rc = rconnect(r, i);
c++;
if (c == rr)
break;
}
assert(i != MAXDIRECTIONS);
return rc;
}
static void
volcano_destruction(region * volcano, region * r, const char *damage)
{
attrib *a;
unit **up;
int percent = 25, time = 6 + rng_int() % 12;
rsettrees(r, 2, 0);
rsettrees(r, 1, 0);
rsettrees(r, 0, 0);
a = a_find(r->attribs, &at_reduceproduction);
if (!a) {
a = a_add(&r->attribs, make_reduceproduction(percent, time));
}
else {
/* Produktion vierteln ... */
a->data.sa[0] = (short)percent;
/* Für 6-17 Runden */
a->data.sa[1] = (short)(a->data.sa[1] + time);
}
/* Personen bekommen 4W10 Punkte Schaden. */
for (up = &r->units; *up;) {
unit *u = *up;
if (u->number) {
int dead = damage_unit(u, damage, true, false);
/* TODO create undead */
if (dead) {
ADDMSG(&u->faction->msgs, msg_message("volcano_dead",
"unit region dead", u, volcano, dead));
}
if (!fval(u->faction, FFL_SELECT)) {
fset(u->faction, FFL_SELECT);
ADDMSG(&u->faction->msgs, msg_message("volcanooutbreaknn",
"region", r));
}
}
if (u == *up) {
up = &u->next;
}
}
if (r != volcano) {
ADDMSG(&r->msgs, msg_message("volcanooutbreak",
"regionv regionn", volcano, r));
}
remove_empty_units_in_region(r);
}
void volcano_outbreak(region * r)
{
region *rn;
unit *u;
faction *f;
for (f = NULL, u = r->units; u; u = u->next) {
if (f != u->faction) {
f = u->faction;
freset(f, FFL_SELECT);
}
}
/* Zufällige Nachbarregion verwüsten */
rn = rrandneighbour(r);
volcano_destruction(r, r, "4d10");
if (rn) {
volcano_destruction(r, rn, "3d10");
}
}
static void melt_iceberg(region * r)
{
attrib *a;
@ -894,7 +682,7 @@ static void godcurse(void)
}
/** handles the "orcish" curse that makes units grow like old orks
* This would probably be better handled in an age-function for the curse,
* TODO: This would probably be better handled in an age-function for the curse,
* but it's now being called by randomevents()
*/
static void orc_growth(void)
@ -903,39 +691,36 @@ static void orc_growth(void)
for (r = regions; r; r = r->next) {
unit *u;
for (u = r->units; u; u = u->next) {
static bool init = false;
static const curse_type *ct_orcish = 0;
curse *c = 0;
if (!init) {
init = true;
ct_orcish = ct_find("orcish");
}
if (ct_orcish)
c = get_curse(u->attribs, ct_orcish);
if (c && !has_skill(u, SK_MAGIC) && !has_skill(u, SK_ALCHEMY)
if (u->attribs && !has_skill(u, SK_MAGIC) && !has_skill(u, SK_ALCHEMY)
&& !fval(u, UFL_HERO)) {
int n;
int increase = 0;
int num = get_cursedmen(u, c);
double prob = curse_geteffect(c);
const item_type * it_chastity = it_find("ao_chastity");
const curse_type *ct_orcish = ct_find("orcish");
if (it_chastity) {
num -= i_get(u->items, it_chastity);
}
for (n = num; n > 0; n--) {
if (chance(prob)) {
++increase;
if (ct_orcish) {
curse *c = get_curse(u->attribs, ct_orcish);
if (c) {
int n;
int increase = 0;
int num = get_cursedmen(u, c);
double prob = curse_geteffect(c);
const item_type * it_chastity = it_find("ao_chastity");
if (it_chastity) {
num -= i_get(u->items, it_chastity);
}
for (n = num; n > 0; n--) {
if (chance(prob)) {
++increase;
}
}
if (increase) {
unit *u2 = create_unit(r, u->faction, increase, u_race(u), 0, NULL, u);
transfermen(u2, u, u2->number);
ADDMSG(&u->faction->msgs, msg_message("orcgrowth",
"unit amount race", u, increase, u_race(u)));
}
}
}
if (increase) {
unit *u2 = create_unit(r, u->faction, increase, u_race(u), 0, NULL, u);
transfermen(u2, u, u2->number);
ADDMSG(&u->faction->msgs, msg_message("orcgrowth",
"unit amount race", u, increase, u_race(u)));
}
}
}
}
@ -1054,33 +839,8 @@ void randomevents(void)
}
}
}
/* Vulkane qualmen, brechen aus ... */
for (r = regions; r; r = r->next) {
if (r->terrain == newterrain(T_VOLCANO_SMOKING)) {
if (a_find(r->attribs, &at_reduceproduction)) {
ADDMSG(&r->msgs, msg_message("volcanostopsmoke", "region", r));
rsetterrain(r, T_VOLCANO);
}
else {
if (rng_int() % 100 < 12) {
ADDMSG(&r->msgs, msg_message("volcanostopsmoke", "region", r));
rsetterrain(r, T_VOLCANO);
}
else if (r->age > 20 && rng_int() % 100 < 8) {
volcano_outbreak(r);
rsetterrain(r, T_VOLCANO);
}
}
}
else if (r->terrain == newterrain(T_VOLCANO)) {
if (rng_int() % 100 < 4) {
ADDMSG(&r->msgs, msg_message("volcanostartsmoke", "region", r));
rsetterrain(r, T_VOLCANO_SMOKING);
}
}
}
volcano_update();
/* Monumente zerfallen, Schiffe verfaulen */
for (r = regions; r; r = r->next) {

View File

@ -265,16 +265,24 @@ static size_t buforder(char *buffer, size_t size, const order * ord, int mode)
* \param viewer: the faction looking at the items
*/
int
report_items(const item * items, item * result, int size, const unit * owner,
const faction * viewer)
report_items(const unit *u, item * result, int size, const unit * owner,
const faction * viewer)
{
const item *itm;
const item *itm, *items = u->items;
int n = 0; /* number of results */
assert(owner == NULL || viewer != owner->faction
|| !"not required for owner=viewer!");
assert(owner == NULL || viewer != owner->faction);
assert(size);
if (u->attribs) {
const curse_type *itemcloak_ct = ct_find("itemcloak");
if (itemcloak_ct) {
curse * cu = get_curse(u->attribs, itemcloak_ct);
if (cu && curse_active(cu)) {
return 0;
}
}
}
for (itm = items; itm; itm = itm->next) {
item *ishow;
const char *ic;
@ -344,16 +352,13 @@ void
report_building(const struct building *b, const char **name,
const char **illusion)
{
const struct building_type *bt_illusion;
if (name) {
*name = buildingtype(b->type, b, b->size);
}
if (illusion) {
*illusion = NULL;
bt_illusion = bt_find("illusioncastle");
if (bt_illusion && b->type == bt_illusion) {
if (is_building_type(b->type, "illusioncastle")) {
const attrib *a = a_find(b->attribs, &at_icastle);
if (a != NULL) {
*illusion = buildingtype(icastle_type(a), b, b->size);
@ -455,21 +460,12 @@ size_t size)
const char *pzTmp, *str;
building *b;
bool isbattle = (bool)(mode == see_battle);
int telepath_see = 0;
item *itm;
item *show;
item *itm, *show = NULL;
faction *fv = visible_faction(f, u);
char *bufp = buf;
bool itemcloak = false;
const curse_type *itemcloak_ct = 0;
int result = 0;
item results[MAX_INVENTORY];
itemcloak_ct = ct_find("itemcloak");
if (itemcloak_ct) {
itemcloak = curse_active(get_curse(u->attribs, itemcloak_ct));
}
bufp = STRLCPY(bufp, unitname(u), size);
if (!isbattle) {
@ -553,7 +549,7 @@ size_t size)
}
/* status */
if (u->number && (u->faction == f || telepath_see || isbattle)) {
if (u->number && (u->faction == f || isbattle)) {
const char *c = hp_status(u);
c = c ? LOC(f->locale, c) : 0;
bufp = STRLCPY(bufp, ", ", size);
@ -586,7 +582,7 @@ size_t size)
}
dh = 0;
if (u->faction == f || telepath_see) {
if (u->faction == f) {
skill *sv;
for (sv = u->skills; sv != u->skills + u->skill_size; ++sv) {
size_t bytes = spskill(bufp, size, f->locale, u, sv, &dh, 1);
@ -597,19 +593,15 @@ size_t size)
}
dh = 0;
if (f == u->faction || telepath_see || omniscient(f)) {
if (f == u->faction || omniscient(f)) {
show = u->items;
}
else if (!itemcloak && mode >= see_unit) {
int n = report_items(u->items, results, MAX_INVENTORY, u, f);
else if (mode >= see_unit) {
int n = report_items(u, results, MAX_INVENTORY, u, f);
assert(n >= 0);
if (n > 0)
if (n > 0) {
show = results;
else
show = NULL;
}
else {
show = NULL;
}
}
for (itm = show; itm; itm = itm->next) {
const char *ic;
@ -634,7 +626,7 @@ size_t size)
}
}
if (u->faction == f || telepath_see) {
if (u->faction == f) {
spellbook *book = unit_get_spellbook(u);
if (book) {
@ -761,11 +753,6 @@ size_t size)
return dh;
}
/* TODO: telepath_see wird nicht berücksichtigt: Parteien mit
* telepath_see sollten immer einzelne Einheiten zu sehen
* bekommen, alles andere ist darstellungsteschnisch kompliziert.
*/
size_t
spskill(char *buffer, size_t size, const struct locale * lang,
const struct unit * u, struct skill * sv, int *dh, int days)
@ -1764,11 +1751,9 @@ f_regionid(const region * r, const faction * f, char *buffer, size_t size)
static char *f_regionid_s(const region * r, const faction * f)
{
static int i = 0;
static char bufs[4][NAMESIZE + 20]; // FIXME: static return value
char *buf = bufs[(++i) % 4];
static char buf[NAMESIZE + 20]; // FIXME: static return value
f_regionid(r, f, buf, NAMESIZE + 20);
f_regionid(r, f, buf, sizeof(buf));
return buf;
}
@ -2176,26 +2161,6 @@ static void eval_int36(struct opstack **stack, const void *userdata)
/*** END MESSAGE RENDERING ***/
/* - String Listen --------------------------------------------- */
void addstrlist(strlist ** SP, const char *s)
{
strlist *slist = malloc(sizeof(strlist));
slist->next = NULL;
slist->s = _strdup(s);
addlist(SP, slist);
}
void freestrlist(strlist * s)
{
strlist *q, *p = s;
while (p) {
q = p->next;
free(p->s);
free(p);
p = q;
}
}
#include <util/nrmessage.h>
static void log_orders(const struct message *msg)

View File

@ -107,7 +107,7 @@ extern "C" {
void view_neighbours(struct seen_region **seen, struct region * r, struct faction * f);
int report_resources(const struct seen_region *sr,
struct resource_report *result, int size, const struct faction *viewer);
int report_items(const struct item *items, struct item *result, int size,
int report_items(const struct unit *u, struct item *result, int size,
const struct unit *owner, const struct faction *viewer);
void report_item(const struct unit *owner, const struct item *i,
const struct faction *viewer, const char **name, const char **basename,
@ -121,14 +121,7 @@ extern "C" {
size_t f_regionid(const struct region *r, const struct faction *f,
char *buffer, size_t size);
typedef struct strlist {
struct strlist *next;
char *s;
} strlist;
void addstrlist(strlist ** SP, const char *s);
void freestrlist(strlist * s);
void split_paragraph(strlist ** SP, const char *s, unsigned int indent, unsigned int width, char mark);
void split_paragraph(struct strlist ** SP, const char *s, unsigned int indent, unsigned int width, char mark);
int stream_printf(struct stream * out, const char *format, ...);

View File

@ -10,6 +10,7 @@
#include <kernel/building.h>
#include <kernel/faction.h>
#include <kernel/item.h>
#include <kernel/race.h>
#include <kernel/region.h>
#include <kernel/ship.h>
@ -18,6 +19,8 @@
#include <kernel/spellbook.h>
#include <util/language.h>
#include <util/lists.h>
#include <util/message.h>
#include <quicklist.h>
#include <stream.h>
@ -414,6 +417,39 @@ static void test_write_spell_syntax(CuTest *tc) {
cleanup_spell_fixture(&spell);
}
static void test_arg_resources(CuTest *tc) {
variant v1, v2;
arg_type *atype;
resource *res;
item_type *itype;
test_setup();
itype = test_create_itemtype("stone");
v1.v = res = malloc(sizeof(resource)*2);
res[0].number = 10;
res[0].type = itype->rtype;
res[0].next = &res[1];
res[1].number = 5;
res[1].type = itype->rtype;
res[1].next = NULL;
register_reports();
atype = find_argtype("resources");
CuAssertPtrNotNull(tc, atype);
v2 = atype->copy(v1);
free(v1.v);
CuAssertPtrNotNull(tc, v2.v);
res = (resource *)v2.v;
CuAssertPtrEquals(tc, itype->rtype, (void *)res->type);
CuAssertIntEquals(tc, 10, res->number);
CuAssertPtrNotNull(tc, res = res->next);
CuAssertPtrEquals(tc, itype->rtype, (void *)res->type);
CuAssertIntEquals(tc, 5, res->number);
CuAssertPtrEquals(tc, 0, res->next);
atype->release(v2);
test_cleanup();
}
CuSuite *get_reports_suite(void)
{
CuSuite *suite = CuSuiteNew();
@ -427,5 +463,6 @@ CuSuite *get_reports_suite(void)
SUITE_ADD_TEST(suite, test_write_travelthru);
SUITE_ADD_TEST(suite, test_write_unit);
SUITE_ADD_TEST(suite, test_write_spell_syntax);
SUITE_ADD_TEST(suite, test_arg_resources);
return suite;
}

View File

@ -58,6 +58,7 @@
#include <races/races.h>
/* util includes */
#include <util/assert.h>
#include <util/attrib.h>
#include <util/base36.h>
#include <util/event.h>
@ -80,7 +81,6 @@
#include <storage.h>
/* libc includes */
#include <assert.h>
#include <ctype.h>
#include <math.h>
#include <stdio.h>
@ -969,7 +969,7 @@ static int sp_blessstonecircle(castorder * co)
b = p->param[0]->data.b;
if (b->type != bt_find("stonecircle")) {
if (!is_building_type(b->type, "stonecircle")) {
ADDMSG(&mage->faction->msgs, msg_feedback(mage, co->order,
"error_notstonecircle", "building", b));
return 0;
@ -1263,6 +1263,7 @@ add_ironweapon(const struct item_type *type, const struct item_type *rusty,
float chance)
{
iron_weapon *iweapon = malloc(sizeof(iron_weapon));
assert_alloc(iweapon);
iweapon->type = type;
iweapon->rusty = rusty;
iweapon->chance = chance;
@ -2011,7 +2012,7 @@ static int sp_treewalkexit(castorder * co)
*/
static int sp_holyground(castorder * co)
{
static const curse_type *ctype = NULL;
const curse_type *ctype = NULL;
region *r = co_get_region(co);
unit *mage = co->magician.u;
int cast_level = co->level;
@ -2020,9 +2021,7 @@ static int sp_holyground(castorder * co)
report_spell(mage, r, msg);
msg_release(msg);
if (!ctype) {
ctype = ct_find("holyground");
}
ctype = ct_find("holyground");
create_curse(mage, &r->attribs, ctype, power * power, 1, zero_effect, 0);
a_removeall(&r->attribs, &at_deathcount);
@ -2053,7 +2052,7 @@ static int sp_homestone(castorder * co)
double force = co->force;
double effect;
message *msg;
if (!mage->building || mage->building->type != bt_find("castle")) {
if (!mage->building || !is_building_type(mage->building->type, "castle")) {
cmistake(mage, co->order, 197, MSG_MAGIC);
return 0;
}
@ -3205,15 +3204,14 @@ static int sp_magicboost(castorder * co)
double power = co->force;
double effect;
trigger *tsummon;
static const curse_type *ct_auraboost;
static const curse_type *ct_magicboost;
const curse_type *ct_auraboost;
const curse_type *ct_magicboost;
ct_auraboost = ct_find("auraboost");
ct_magicboost = ct_find("magicboost");
assert(ct_auraboost != NULL);
assert(ct_magicboost != NULL);
if (!ct_auraboost) {
ct_auraboost = ct_find("auraboost");
ct_magicboost = ct_find("magicboost");
assert(ct_auraboost != NULL);
assert(ct_magicboost != NULL);
}
/* fehler, wenn schon ein boost */
if (is_cursed(mage->attribs, C_MBOOST, 0)) {
report_failure(mage, co->order);
@ -5973,8 +5971,8 @@ int sp_movecastle(castorder * co)
u = unext;
}
if ((b->type == bt_find("caravan") || b->type == bt_find("dam")
|| b->type == bt_find("tunnel"))) {
if ((is_building_type(b->type, "caravan") || is_building_type(b->type, "dam")
|| is_building_type(b->type, "tunnel"))) {
direction_t d;
for (d = 0; d != MAXDIRECTIONS; ++d) {
if (rroad(r, d)) {

View File

@ -959,13 +959,7 @@ int sp_strong_wall(struct castorder * co)
unit *mage = fi->unit;
building *burg;
double effect;
static bool init = false;
message *msg;
static const curse_type *strongwall_ct;
if (!init) {
init = true;
strongwall_ct = ct_find("strongwall");
}
if (!mage->building) {
return 0;
@ -973,7 +967,7 @@ int sp_strong_wall(struct castorder * co)
burg = mage->building;
effect = power / 4;
create_curse(mage, &burg->attribs, strongwall_ct, power, 1, effect, 0);
create_curse(mage, &burg->attribs, ct_find("strongwall"), power, 1, effect, 0);
msg =
msg_message("sp_strongwalls_effect", "mage building", mage, mage->building);

View File

@ -148,29 +148,26 @@ bool flying_ship(const ship * sh)
static curse *shipcurse_flyingship(ship * sh, unit * mage, double power, int duration)
{
static const curse_type *ct_flyingship = NULL;
if (!ct_flyingship) {
ct_flyingship = ct_find("flyingship");
assert(ct_flyingship);
}
if (curse_active(get_curse(sh->attribs, ct_flyingship))) {
return NULL;
}
else if (is_cursed(sh->attribs, C_SHIP_SPEEDUP, 0)) {
return NULL;
}
else {
/* mit C_SHIP_NODRIFT haben wir kein Problem */
curse *c =
create_curse(mage, &sh->attribs, ct_flyingship, power, duration, 0.0, 0);
if (c) {
c->data.v = sh;
if (c->duration > 0) {
sh->flags |= SF_FLYING;
}
curse *c;
const curse_type *ct_flyingship = ct_find("flyingship");
assert(ct_flyingship);
if (sh->attribs) {
if (curse_active(get_curse(sh->attribs, ct_flyingship))) {
return NULL;
}
if (is_cursed(sh->attribs, C_SHIP_SPEEDUP, 0)) {
return NULL;
}
return c;
}
/* mit C_SHIP_NODRIFT haben wir kein Problem */
c = create_curse(mage, &sh->attribs, ct_flyingship, power, duration, 0.0, 0);
if (c) {
c->data.v = sh;
if (c->duration > 0) {
sh->flags |= SF_FLYING;
}
}
return c;
}
int levitate_ship(ship * sh, unit * mage, double power, int duration)

View File

@ -32,7 +32,7 @@ typedef struct {
} spy_fixture;
static void setup_spy(spy_fixture *fix) {
test_cleanup();
test_setup();
fix->r = test_create_region(0, 0, NULL);
fix->spy = test_create_unit(test_create_faction(NULL), fix->r);
fix->victim = test_create_unit(test_create_faction(NULL), fix->r);
@ -88,7 +88,7 @@ static void test_all_spy_message(CuTest *tc) {
static void setup_sabotage(void) {
struct locale *lang;
test_cleanup();
test_setup();
lang = get_or_create_locale("de");
locale_setstring(lang, parameters[P_SHIP], "SCHIFF");
locale_setstring(lang, parameters[P_ANY], "ALLE");

View File

@ -277,21 +277,20 @@ teach_unit(unit * teacher, unit * student, int nteaching, skill_t sk,
int teach_cmd(unit * u, struct order *ord)
{
static const curse_type *gbdream_ct = NULL;
plane *pl;
region *r = u->region;
skill_t sk_academy = NOSKILL;
int teaching, i, j, count, academy = 0;
if (gbdream_ct == 0)
gbdream_ct = ct_find("gbdream");
if (gbdream_ct) {
if (get_curse(u->region->attribs, gbdream_ct)) {
ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "gbdream_noteach", ""));
return 0;
if (u->region->attribs) {
const curse_type *gbdream_ct = ct_find("gbdream");
if (gbdream_ct) {
if (get_curse(u->region->attribs, gbdream_ct)) {
ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "gbdream_noteach", ""));
return 0;
}
}
}
if ((u_race(u)->flags & RCF_NOTEACH) || fval(u, UFL_WERE)) {
cmistake(u, ord, 274, MSG_EVENT);
return 0;

View File

@ -70,7 +70,7 @@ static void setup_study(study_fixture *fix, skill_t sk) {
struct locale *lang;
assert(fix);
test_cleanup();
test_setup();
config_set("study.random_progress", "0");
test_create_world();
r = findregion(0, 0);
@ -138,7 +138,7 @@ static void test_study_bug_2194(CuTest *tc) {
struct locale * loc;
building * b;
test_cleanup();
test_setup();
random_source_inject_constant(0.0);
init_resources();
loc = get_or_create_locale("de");
@ -195,7 +195,7 @@ static void test_produceexp(CuTest *tc) {
unit *u;
g_tc = tc;
test_cleanup();
test_setup();
u = test_create_unit(test_create_faction(0), test_create_region(0, 0, 0));
scale_number(u, 2);
config_set("study.produceexp", "20");
@ -210,7 +210,7 @@ static void test_academy_building(CuTest *tc) {
building * b;
message * msg;
test_cleanup();
test_setup();
mt_register(mt_new_va("teach_asgood", "unit:unit", "region:region", "command:order", "student:unit", 0));
random_source_inject_constant(0.0);
@ -253,7 +253,7 @@ static void test_academy_building(CuTest *tc) {
void test_learn_skill_single(CuTest *tc) {
unit *u;
skill *sv;
test_cleanup();
test_setup();
config_set("study.random_progress", "0");
u = test_create_unit(test_create_faction(0), test_create_region(0, 0, 0));
learn_skill(u, SK_ALCHEMY, STUDYDAYS);
@ -272,7 +272,7 @@ void test_learn_skill_single(CuTest *tc) {
void test_learn_skill_multi(CuTest *tc) {
unit *u;
skill *sv;
test_cleanup();
test_setup();
config_set("study.random_progress", "0");
u = test_create_unit(test_create_faction(0), test_create_region(0, 0, 0));
scale_number(u, 10);
@ -292,7 +292,7 @@ void test_learn_skill_multi(CuTest *tc) {
static void test_demon_skillchanges(CuTest *tc) {
unit * u;
race * rc;
test_cleanup();
test_setup();
rc = test_create_race("demon");
CuAssertPtrEquals(tc, rc, get_race(RC_DAEMON));
u = test_create_unit(test_create_faction(rc), 0);
@ -305,7 +305,7 @@ static void test_demon_skillchanges(CuTest *tc) {
static void test_study_cmd(CuTest *tc) {
unit *u;
test_cleanup();
test_setup();
init_resources();
u = test_create_unit(test_create_faction(0), test_create_region(0, 0, 0));
u->thisorder = create_order(K_STUDY, u->faction->locale, "CROSSBOW");
@ -321,7 +321,7 @@ static void test_study_cmd(CuTest *tc) {
static void test_study_cost(CuTest *tc) {
unit *u;
const struct item_type *itype;
test_cleanup();
test_setup();
init_resources();
itype = get_resourcetype(R_SILVER)->itype;
u = test_create_unit(test_create_faction(0), test_create_region(0, 0, 0));
@ -340,7 +340,7 @@ static void test_study_cost(CuTest *tc) {
static void test_teach_cmd(CuTest *tc) {
unit *u, *ut;
test_cleanup();
test_setup();
init_resources();
u = test_create_unit(test_create_faction(0), test_create_region(0, 0, 0));
scale_number(u, 10);
@ -360,7 +360,7 @@ static void test_teach_cmd(CuTest *tc) {
static void test_teach_two(CuTest *tc) {
unit *u1, *u2, *ut;
test_cleanup();
test_setup();
init_resources();
u1 = test_create_unit(test_create_faction(0), test_create_region(0, 0, 0));
scale_number(u1, 5);
@ -390,7 +390,7 @@ static void test_teach_two_skills(CuTest *tc) {
faction *f;
region *r;
test_cleanup();
test_setup();
init_resources();
f = test_create_faction(0);
r = test_create_region(0, 0, 0);
@ -420,7 +420,7 @@ static void test_teach_two_skills(CuTest *tc) {
static void test_teach_one_to_many(CuTest *tc) {
unit *u, *ut;
test_cleanup();
test_setup();
init_resources();
u = test_create_unit(test_create_faction(0), test_create_region(0, 0, 0));
scale_number(u, 20);
@ -440,7 +440,7 @@ static void test_teach_one_to_many(CuTest *tc) {
static void test_teach_many_to_one(CuTest *tc) {
unit *u, *u1, *u2;
test_cleanup();
test_setup();
init_resources();
u = test_create_unit(test_create_faction(0), test_create_region(0, 0, 0));
scale_number(u, 20);
@ -467,7 +467,7 @@ static void test_teach_many_to_many(CuTest *tc) {
region *r;
faction *f;
test_cleanup();
test_setup();
init_resources();
f = test_create_faction(0);
r = test_create_region(0, 0, 0);

View File

@ -111,7 +111,9 @@ int RunAllTests(int argc, char *argv[])
ADD_SUITE(messages);
/* gamecode */
ADD_SUITE(prefix);
ADD_SUITE(names);
ADD_SUITE(battle);
ADD_SUITE(volcano);
ADD_SUITE(donations);
ADD_SUITE(travelthru);
ADD_SUITE(economy);
@ -156,7 +158,6 @@ int RunAllTests(int argc, char *argv[])
}
int main(int argc, char ** argv) {
log_to_file(LOG_CPERROR, stderr);
++argv;
--argc;
if (argc > 0 && strcmp("--list", argv[0]) == 0) {

View File

@ -24,13 +24,14 @@
#include <util/bsdstring.h>
#include <util/functions.h>
#include <util/language.h>
#include <util/lists.h>
#include <util/message.h>
#include <util/log.h>
#include <util/rand.h>
#include <util/assert.h>
#include <CuTest.h>
#include <assert.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
@ -123,10 +124,43 @@ struct unit *test_create_unit(struct faction *f, struct region *r)
return create_unit(r, f, 1, rc ? rc : rc_get_or_create("human"), 0, 0, 0);
}
void test_cleanup(void)
{
int i;
static void log_list(void *udata, int flags, const char *module, const char *format, va_list args) {
strlist **slp = (strlist **)udata;
addstrlist(slp, format);
}
struct log_t * test_log_start(int flags, strlist **slist) {
return log_create(flags, slist, log_list);
}
void test_log_stop(struct log_t *log, struct strlist *slist) {
freestrlist(slist);
log_destroy(log);
}
void test_log_stderr(int flags) {
static struct log_t *stderrlog;
if (flags) {
if (stderrlog) {
log_error("stderr logging is still active. did you call test_cleanup?");
log_destroy(stderrlog);
}
stderrlog = log_to_file(flags, stderr);
}
else {
if (stderrlog) {
log_destroy(stderrlog);
}
else {
log_warning("stderr logging is inactive. did you call test_cleanup twice?");
}
stderrlog = 0;
}
}
static void test_reset(void) {
int i;
default_locale = 0;
free_gamedata();
free_terrains();
@ -158,6 +192,17 @@ void test_cleanup(void)
random_source_reset();
}
void test_setup(void) {
test_log_stderr(LOG_CPERROR);
test_reset();
}
void test_cleanup(void)
{
test_reset();
test_log_stderr(0);
}
terrain_type *
test_create_terrain(const char * name, unsigned int flags)
{
@ -191,6 +236,7 @@ ship_type * test_create_shiptype(const char * name)
stype->damage = 1;
if (!stype->construction) {
stype->construction = calloc(1, sizeof(construction));
assert_alloc(stype->construction);
stype->construction->maxsize = 5;
stype->construction->minskill = 1;
stype->construction->reqsize = 1;
@ -259,6 +305,7 @@ spell * test_create_spell(void)
sp = create_spell("testspell", 0);
sp->components = (spell_component *)calloc(4, sizeof(spell_component));
assert_alloc(sp->components);
sp->components[0].amount = 1;
sp->components[0].type = get_resourcetype(R_SILVER);
sp->components[0].cost = SPC_FIX;
@ -377,17 +424,30 @@ const char * test_get_messagetype(const message *msg) {
return name;
}
struct message * test_find_messagetype(struct message_list *msgs, const char *name) {
struct message * test_find_messagetype_ex(struct message_list *msgs, const char *name, struct message *prev)
{
struct mlist *ml;
if (!msgs) return 0;
for (ml = msgs->begin; ml; ml = ml->next) {
if (strcmp(name, test_get_messagetype(ml->msg)) == 0) {
return ml->msg;
if (prev) {
if (ml->msg == prev) {
prev = NULL;
}
}
else {
return ml->msg;
}
}
}
return 0;
}
struct message * test_find_messagetype(struct message_list *msgs, const char *name)
{
return test_find_messagetype_ex(msgs, name, NULL);
}
void test_clear_messages(faction *f) {
if (f->msgs) {
free_messagelist(f->msgs->begin);

View File

@ -26,10 +26,16 @@ extern "C" {
struct spellparameter;
struct spell;
struct locale;
struct strlist;
struct log_t;
struct CuTest;
void test_setup(void);
void test_cleanup(void);
void test_log_stderr(int on);
struct log_t * test_log_start(int flags, struct strlist **slist);
void test_log_stop(struct log_t *log, struct strlist *slist);
struct locale * test_create_locale(void);
struct terrain_type * test_create_terrain(const char * name, unsigned int flags);
@ -51,6 +57,7 @@ extern "C" {
int RunAllTests(void);
void test_translate_param(const struct locale *lang, param_t param, const char *text);
const char * test_get_messagetype(const struct message *msg);
struct message * test_find_messagetype_ex(struct message_list *msgs, const char *name, struct message *prev);
struct message * test_find_messagetype(struct message_list *msgs, const char *name);
struct message * test_get_last_message(struct message_list *mlist);
void test_clear_messages(struct faction *f);

View File

@ -12,8 +12,8 @@
static void test_shock(CuTest *tc) {
unit *u;
trigger *tt;
test_cleanup();
test_setup();
u = test_create_unit(test_create_faction(0), test_create_region(0, 0, 0));
create_mage(u, M_GRAY);
set_level(u, SK_MAGIC, 5);
@ -32,8 +32,8 @@ static void test_shock(CuTest *tc) {
static void test_shock_low(CuTest *tc) {
unit *u;
trigger *tt;
test_cleanup();
test_setup();
u = test_create_unit(test_create_faction(0), test_create_region(0, 0, 0));
create_mage(u, M_GRAY);
set_level(u, SK_MAGIC, 5);

View File

@ -58,27 +58,28 @@ static void help_feed(unit * donor, unit * u, int *need_p)
*need_p = need;
}
static const char *hunger_damage(const race *rc) {
const char * damage = get_param(rc->parameters, "hunger.damage");
if (!damage) {
damage = config_get("hunger.damage");
}
if (!damage) {
damage = "1d12+12";
}
return damage;
}
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;
const char *damage = 0;
if (!damage) {
damage = config_get("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);
}
damage = hunger_damage(u_race(u));
while (number--) {
int dam = dice_rand(rcdamage ? rcdamage : damage);
int dam = dice_rand(damage);
if (dam >= hp) {
++dead;
}

View File

@ -19,7 +19,7 @@ void test_upkeep_default(CuTest * tc)
faction *f1, *f2;
const item_type *i_silver;
test_cleanup();
test_setup();
test_create_world();
i_silver = it_find("money");
@ -50,7 +50,7 @@ void test_upkeep_hunger_damage(CuTest * tc)
faction *f1;
const item_type *i_silver;
test_cleanup();
test_setup();
test_create_world();
i_silver = it_find("money");
@ -75,7 +75,7 @@ void test_upkeep_from_pool(CuTest * tc)
unit *u1, *u2;
const item_type *i_silver;
test_cleanup();
test_setup();
test_create_world();
i_silver = it_find("money");
@ -108,7 +108,7 @@ void test_upkeep_from_friend(CuTest * tc)
faction *f1, *f2;
const item_type *i_silver;
test_cleanup();
test_setup();
test_create_world();
i_silver = it_find("money");
@ -142,7 +142,7 @@ void test_upkeep_free(CuTest * tc)
unit *u;
const item_type *i_silver;
test_cleanup();
test_setup();
test_create_world();
i_silver = it_find("money");

7
src/util/assert.h Normal file
View File

@ -0,0 +1,7 @@
#ifndef UTIL_ASSERT_H
#define UTIL_ASSERT_H
#include <assert.h>
#define assert_alloc(expr) assert((expr) || !"out of memory")
#endif

View File

@ -22,11 +22,11 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#include "log.h"
#include "strings.h"
#include "umlaut.h"
#include "assert.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include <critbit.h>
#define SMAXHASH 2048
@ -84,6 +84,7 @@ locale *get_or_create_locale(const char *name)
}
}
*lp = l = (locale *)calloc(sizeof(locale), 1);
assert_alloc(l);
l->hashkey = hkey;
l->name = _strdup(name);
l->index = nextlocaleindex++;

View File

@ -16,12 +16,13 @@ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
**/
#include <stdlib.h>
#include <assert.h>
#include <platform.h>
#include "lists.h"
#include <stdlib.h>
#include <string.h>
#include <assert.h>
typedef struct void_list {
struct void_list *next;
void *data;
@ -121,3 +122,22 @@ unsigned int listlen(void *l)
for (p = (void_list *)l, i = 0; p; p = p->next, i++);
return i;
}
/* - String Listen --------------------------------------------- */
void addstrlist(strlist ** SP, const char *s)
{
strlist *slist = malloc(sizeof(strlist));
slist->next = NULL;
slist->s = _strdup(s);
addlist(SP, slist);
}
void freestrlist(strlist * s)
{
strlist *q, *p = s;
while (p) {
q = p->next;
free(p->s);
free(p);
p = q;
}
}

View File

@ -24,6 +24,13 @@ extern "C" {
#include <stddef.h>
typedef struct strlist {
struct strlist *next;
char *s;
} strlist;
void addstrlist(strlist ** SP, const char *s);
void freestrlist(strlist * s);
void addlist(void *l1, void *p1);
void translist(void *l1, void *l2, void *p);
#ifndef MALLOCDBG

View File

@ -138,6 +138,7 @@ static int check_dupe(const char *format, int level)
static char last_message[32]; /* STATIC_XCALL: used across calls */
static int dupes = 0; /* STATIC_XCALL: used across calls */
if (strncmp(last_message, format, sizeof(last_message)) == 0) {
// TODO: C6054: String 'last_message' might not be zero - terminated.
++dupes;
return 1;
}

View File

@ -47,7 +47,7 @@ variant(*copy_arg) (variant), variant_type type)
argtypes = atype;
}
static arg_type *find_argtype(const char *name)
arg_type *find_argtype(const char *name)
{
arg_type *atype = argtypes;
while (atype != NULL) {
@ -83,7 +83,7 @@ message_type *mt_new(const char *name, const char *args[])
mtype->pnames = NULL;
mtype->types = NULL;
}
if (args != NULL)
if (args != NULL) {
for (i = 0; args[i]; ++i) {
const char *x = args[i];
const char *spos = strchr(x, ':');
@ -102,6 +102,7 @@ message_type *mt_new(const char *name, const char *args[])
assert(mtype->types[i]);
}
}
}
return mtype;
}

View File

@ -46,22 +46,23 @@ extern "C" {
/* mt_new("simple_sentence", "subject:string", "predicate:string",
* "object:string", "lang:locale", NULL); */
extern struct message *msg_create(const struct message_type *type,
struct message *msg_create(const struct message_type *type,
variant args[]);
/* msg_create(&mt_simplesentence, "enno", "eats", "chocolate", &locale_de);
* parameters must be in the same order as they were for mt_new! */
extern void msg_release(struct message *msg);
extern struct message *msg_addref(struct message *msg);
void msg_release(struct message *msg);
struct message *msg_addref(struct message *msg);
extern const char *mt_name(const struct message_type *mtype);
const char *mt_name(const struct message_type *mtype);
/** message_type registry (optional): **/
extern const struct message_type *mt_register(struct message_type *);
extern const struct message_type *mt_find(const char *);
const struct message_type *mt_register(struct message_type *);
const struct message_type *mt_find(const char *);
extern void register_argtype(const char *name, void(*free_arg) (variant),
void register_argtype(const char *name, void(*free_arg) (variant),
variant(*copy_arg) (variant), variant_type);
arg_type *find_argtype(const char *name);
void(*msg_log_create) (const struct message * msg);

View File

@ -33,7 +33,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
double normalvariate(double mu, double sigma)
{
static const double NV_MAGICCONST = 1.7155277699214135; /* STATIC_CONST: a constant */
static const double NV_MAGICCONST = 1.7155277699214135;
double z;
for (;;) {
double u1 = rng_double();

View File

@ -18,6 +18,9 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#include <platform.h>
#include "strings.h"
#include "assert.h"
/* libc includes */
#include <string.h>
#include <assert.h>
@ -34,7 +37,9 @@ char *set_string(char **s, const char *neu)
strcpy(*s, neu);
}
else {
*s = realloc(*s, strlen(neu) + 1);
char *rs = realloc(*s, strlen(neu) + 1);
assert_alloc(rs);
*s = rs;
strcpy(*s, neu);
}
return *s;

View File

@ -1,4 +1,4 @@
/*
/*
+-------------------+ Christian Schlittchen <corwin@amber.kn-bremen.de>
| | Enno Rehling <enno@eressea.de>
| Eressea PBEM host | Katja Zedel <katze@felidae.kn-bremen.de>
@ -16,9 +16,9 @@
#include "bsdstring.h"
#include "critbit.h"
#include "log.h"
#include "assert.h"
/* libc includes */
#include <assert.h>
/* libc includes */
#include <ctype.h>
#include <string.h>
#include <stdlib.h>
@ -48,6 +48,7 @@ void opstack_push(opstack ** stackp, variant data)
opstack *stack = *stackp;
if (stack == NULL) {
stack = (opstack *)malloc(sizeof(opstack));
assert_alloc(stack);
stack->size = 2;
stack->begin = malloc(sizeof(variant) * stack->size);
stack->top = stack->begin;
@ -58,10 +59,7 @@ void opstack_push(opstack ** stackp, variant data)
void *tmp;
stack->size += stack->size;
tmp = realloc(stack->begin, sizeof(variant) * stack->size);
if (!tmp) {
log_error("realloc out of memory");
abort();
}
assert_alloc(tmp);
stack->begin = (variant *)tmp;
stack->top = stack->begin + pos;
}

View File

@ -19,6 +19,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#include <platform.h>
#include "umlaut.h"
#include "assert.h"
#include "log.h"
#include "unicode.h"
@ -116,7 +117,7 @@ char * transliterate(char * out, size_t size, const char * in)
void addtoken(void ** root, const char *str, variant id)
{
tnode * tk;
static const struct replace { /* STATIC_CONST: constant value */
static const struct replace {
ucs4_t ucs;
const char str[3];
} replace[] = {
@ -183,6 +184,7 @@ void addtoken(void ** root, const char *str, variant id)
index = lcs % NODEHASHSIZE;
#endif
ref = (tref *)malloc(sizeof(tref));
assert_alloc(ref);
ref->ucs = lcs;
ref->node = node;
ref->nexthash = tk->next[index];

View File

@ -14,6 +14,7 @@
/* util includes */
#include "log.h"
#include "assert.h"
#ifdef USE_LIBXML2
#include <libxml/catalog.h>
@ -21,7 +22,6 @@
#endif
/* libc includes */
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@ -93,6 +93,7 @@ void xml_register_callback(xml_callback callback)
{
xml_reader *reader = (xml_reader *)malloc(sizeof(xml_reader));
xml_reader **insert = &xmlReaders;
assert_alloc(reader);
reader->callback = callback;
reader->next = NULL;

293
src/volcano.c Normal file
View File

@ -0,0 +1,293 @@
/*
Copyright (c) 1998-2015, 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 <kernel/config.h>
#include "volcano.h"
#include "alchemy.h"
/* kernel includes */
#include <kernel/faction.h>
#include <kernel/item.h>
#include <kernel/messages.h>
#include <kernel/order.h>
#include <kernel/race.h>
#include <kernel/region.h>
#include <kernel/unit.h>
#include <kernel/terrain.h>
/* attributes includes */
#include <attributes/reduceproduction.h>
/* util includes */
#include <util/attrib.h>
#include <util/log.h>
#include <util/rand.h>
#include <util/message.h>
#include <util/rng.h>
/* libc includes */
#include <assert.h>
#include <stdlib.h>
static int nb_armor(const unit * u, int index)
{
const item *itm;
int av = 0;
int s = 0, a = 0;
if (!(u_race(u)->battle_flags & BF_EQUIPMENT))
return 0;
/* Normale Rüstung */
for (itm = u->items; itm; itm = itm->next) {
const armor_type *atype = itm->type->rtype->atype;
if (atype != NULL) {
int *schutz = &a;
if (atype->flags & ATF_SHIELD)
schutz = &s;
if (*schutz <= index) {
*schutz += itm->number;
if (*schutz > index) {
av += atype->prot;
}
}
}
}
return av;
}
static int
damage_unit(unit * u, const char *dam, bool physical, bool magic)
{
int *hp, hpstack[20];
int h;
int i, dead = 0, hp_rem = 0, heiltrank;
double magres = magic_resistance(u);
assert(u->number);
if (fval(u_race(u), RCF_ILLUSIONARY) || u_race(u) == get_race(RC_SPELL)) {
return 0;
}
assert(u->number <= u->hp);
h = u->hp / u->number;
/* HP verteilen */
if (u->number < 20) {
hp = hpstack;
}
else {
hp = malloc(u->number * sizeof(int));
}
for (i = 0; i < u->number; i++)
hp[i] = h;
h = u->hp - (u->number * h);
for (i = 0; i < h; i++)
hp[i]++;
/* Schaden */
for (i = 0; i < u->number; i++) {
int damage = dice_rand(dam);
if (magic)
damage = (int)(damage * (1.0 - magres));
if (physical)
damage -= nb_armor(u, i);
hp[i] -= damage;
}
/* Auswirkungen */
for (i = 0; i < u->number; i++) {
if (hp[i] <= 0) {
heiltrank = 0;
/* Sieben Leben */
if (old_race(u_race(u)) == RC_CAT && (chance(1.0 / 7))) {
hp[i] = u->hp / u->number;
hp_rem += hp[i];
continue;
}
/* Heiltrank */
if (oldpotiontype[P_HEAL]) {
if (get_effect(u, oldpotiontype[P_HEAL]) > 0) {
change_effect(u, oldpotiontype[P_HEAL], -1);
heiltrank = 1;
}
else if (i_get(u->items, oldpotiontype[P_HEAL]->itype) > 0) {
i_change(&u->items, oldpotiontype[P_HEAL]->itype, -1);
change_effect(u, oldpotiontype[P_HEAL], 3);
heiltrank = 1;
}
if (heiltrank && (chance(0.50))) {
hp[i] = u->hp / u->number;
hp_rem += hp[i];
continue;
}
}
dead++;
}
else {
hp_rem += hp[i];
}
}
scale_number(u, u->number - dead);
u->hp = hp_rem;
if (hp != hpstack) {
free(hp);
}
return dead;
}
static region *rrandneighbour(region * r)
{
direction_t i;
region *rc = NULL;
int rr, c = 0;
/* Nachsehen, wieviele Regionen in Frage kommen */
for (i = 0; i != MAXDIRECTIONS; i++) {
c++;
}
/* Zufällig eine auswählen */
rr = rng_int() % c;
/* Durchzählen */
c = -1;
for (i = 0; i != MAXDIRECTIONS; i++) {
rc = rconnect(r, i);
c++;
if (c == rr)
break;
}
assert(i != MAXDIRECTIONS);
return rc;
}
static void
volcano_destruction(region * volcano, region * r, const char *damage)
{
attrib *a;
unit **up;
int percent = 25, time = 6 + rng_int() % 12;
rsettrees(r, 2, 0);
rsettrees(r, 1, 0);
rsettrees(r, 0, 0);
a = a_find(r->attribs, &at_reduceproduction);
if (!a) {
a = a_add(&r->attribs, make_reduceproduction(percent, time));
}
else {
/* Produktion vierteln ... */
a->data.sa[0] = (short)percent;
/* Für 6-17 Runden */
a->data.sa[1] = (short)(a->data.sa[1] + time);
}
/* Personen bekommen 4W10 Punkte Schaden. */
for (up = &r->units; *up;) {
unit *u = *up;
if (u->number) {
int dead = damage_unit(u, damage, true, false);
/* TODO create undead */
if (dead) {
ADDMSG(&u->faction->msgs, msg_message("volcano_dead",
"unit region dead", u, volcano, dead));
}
if (!fval(u->faction, FFL_SELECT)) {
fset(u->faction, FFL_SELECT);
ADDMSG(&u->faction->msgs, msg_message("volcanooutbreaknn",
"region", r));
}
}
if (u == *up) {
up = &u->next;
}
}
if (r != volcano) {
ADDMSG(&r->msgs, msg_message("volcanooutbreak",
"regionv regionn", volcano, r));
}
remove_empty_units_in_region(r);
}
void volcano_outbreak(region * r, region *rn)
{
unit *u;
faction *f;
for (f = NULL, u = r->units; u; u = u->next) {
if (f != u->faction) {
f = u->faction;
freset(f, FFL_SELECT);
}
}
volcano_destruction(r, r, "4d10");
if (rn) {
volcano_destruction(r, rn, "3d10");
}
}
void volcano_update(void)
{
region *r;
const struct terrain_type *t_active, *t_volcano;
t_volcano = get_terrain("volcano");
t_active = get_terrain("activevolcano");
/* Vulkane qualmen, brechen aus ... */
for (r = regions; r; r = r->next) {
if (r->terrain == t_active) {
if (a_find(r->attribs, &at_reduceproduction)) {
ADDMSG(&r->msgs, msg_message("volcanostopsmoke", "region", r));
r->terrain = t_volcano;
}
else {
if (rng_int() % 100 < 12) {
ADDMSG(&r->msgs, msg_message("volcanostopsmoke", "region", r));
r->terrain = t_volcano;
}
else if (r->uid == 1246051340 || (r->age > 20 && rng_int() % 100 < 8)) {
region *rn;
/* Zufällige Nachbarregion verwüsten */
rn = rrandneighbour(r);
volcano_outbreak(r, rn);
r->terrain = t_volcano;
}
}
}
else if (r->terrain == t_volcano) {
if (rng_int() % 100 < 4) {
ADDMSG(&r->msgs, msg_message("volcanostartsmoke", "region", r));
r->terrain = t_active;
}
}
}
}

View File

@ -1,3 +1,4 @@
#pragma once
/*
Copyright (c) 1998-2015, Enno Rehling <enno@eressea.de>
Katja Zedel <katze@felidae.kn-bremen.de
@ -16,14 +17,17 @@ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
**/
#ifndef H_ITM_PHOENIXCOMPASS
#define H_ITM_PHOENIXCOMPASS
#ifndef H_GC_VOLCANO
#define H_GC_VOLCANO
#ifdef __cplusplus
extern "C" {
#endif
extern void register_phoenixcompass(void);
struct region;
void volcano_outbreak(struct region * r, struct region *rn);
void volcano_update(void);
#ifdef __cplusplus
}
#endif

86
src/volcano.test.c Normal file
View File

@ -0,0 +1,86 @@
#include <platform.h>
#include <tests.h>
#include "volcano.h"
#include <kernel/faction.h>
#include <kernel/region.h>
#include <kernel/terrain.h>
#include <kernel/unit.h>
#include <kernel/messages.h>
#include <util/attrib.h>
#include <attributes/reduceproduction.h>
#include <CuTest.h>
static void test_volcano_update(CuTest *tc) {
region *r;
message *m;
const struct terrain_type *t_volcano, *t_active;
test_cleanup();
mt_register(mt_new_va("volcanostopsmoke", "region:region", 0));
t_volcano = test_create_terrain("volcano", LAND_REGION);
t_active = test_create_terrain("activevolcano", LAND_REGION);
r = test_create_region(0, 0, t_active);
a_add(&r->attribs, make_reduceproduction(25, 10));
volcano_update();
CuAssertPtrNotNull(tc, m = test_find_messagetype(r->msgs, "volcanostopsmoke"));
CuAssertPtrEquals(tc, r, m->parameters[0].v);
CuAssertPtrEquals(tc, (void *)t_volcano, (void *)r->terrain);
test_cleanup();
}
static void test_volcano_outbreak(CuTest *tc) {
region *r, *rn;
unit *u1, *u2;
faction *f;
message *m;
const struct terrain_type *t_volcano, *t_active;
test_cleanup();
mt_register(mt_new_va("volcanooutbreak", "regionv:region", "regionn:region", 0));
mt_register(mt_new_va("volcano_dead", "unit:unit", "region:region", "dead:int", 0));
t_volcano = test_create_terrain("volcano", LAND_REGION);
t_active = test_create_terrain("activevolcano", LAND_REGION);
r = test_create_region(0, 0, t_active);
rn = test_create_region(1, 0, t_volcano);
f = test_create_faction(0);
u1 = test_create_unit(f, r);
u1->hp = u1->number;
u2 = test_create_unit(f, rn);
u2->hp = u2->number;
volcano_outbreak(r, rn);
CuAssertPtrEquals(tc, (void *)t_active, (void *)r->terrain);
CuAssertIntEquals(tc, 0, rtrees(r, 0));
CuAssertIntEquals(tc, 0, rtrees(r, 1));
CuAssertIntEquals(tc, 0, rtrees(r, 2));
CuAssertPtrNotNull(tc, a_find(r->attribs, &at_reduceproduction));
CuAssertPtrNotNull(tc, a_find(rn->attribs, &at_reduceproduction));
CuAssertPtrNotNull(tc, m = test_find_messagetype(rn->msgs, "volcanooutbreak"));
CuAssertPtrEquals(tc, r, m->parameters[0].v);
CuAssertPtrEquals(tc, rn, m->parameters[1].v);
CuAssertPtrNotNull(tc, m = test_find_messagetype_ex(f->msgs, "volcano_dead", NULL));
CuAssertPtrEquals(tc, u1, m->parameters[0].v);
CuAssertPtrEquals(tc, r, m->parameters[1].v);
CuAssertIntEquals(tc, 1, m->parameters[2].i);
CuAssertPtrNotNull(tc, m = test_find_messagetype_ex(f->msgs, "volcano_dead", m));
CuAssertPtrEquals(tc, u2, m->parameters[0].v);
CuAssertPtrEquals(tc, r, m->parameters[1].v);
CuAssertIntEquals(tc, 1, m->parameters[2].i);
test_cleanup();
}
CuSuite *get_volcano_suite(void)
{
CuSuite *suite = CuSuiteNew();
SUITE_ADD_TEST(suite, test_volcano_update);
SUITE_ADD_TEST(suite, test_volcano_outbreak);
return suite;
}

View File

@ -22,7 +22,7 @@ static void test_move_to_vortex(CuTest *tc) {
unit *u;
struct locale *lang;
test_cleanup();
test_setup();
lang = get_or_create_locale("en");
locale_setstring(lang, "vortex", "wirbel");
init_locale(lang);

View File

@ -22,7 +22,7 @@ static void test_make_wormholes(CuTest *tc) {
terrain_type *t_plain;
building_type *btype;
test_cleanup();
test_setup();
t_plain = test_create_terrain("plain", LAND_REGION);
btype = test_create_buildingtype("wormhole");
match[0] = r1 = test_create_region(0, 0, t_plain);
@ -44,7 +44,7 @@ static void test_sort_wormhole_regions(CuTest *tc) {
terrain_type *t_plain;
quicklist *rlist = 0;
test_cleanup();
test_setup();
t_plain = test_create_terrain("plain", LAND_REGION);
r1 = test_create_region(0, 0, t_plain);
r2 = test_create_region(1, 0, t_plain);

View File

@ -2,6 +2,6 @@ cd c:\users\enno\documents\eressea\git\tests
"C:\Program Files (x86)\Dr. Memory\bin64\drmemory.exe" ..\build-vs14\eressea\Debug\eressea.exe -t184 test-turn.lua
del reports
del datum htpasswd parteien parteien.full passwd score turn
del /q reports
del /q datum htpasswd parteien parteien.full passwd score turn
pause