Merge pull request #760 from ennorehling/2405-mistletoe

BUG 2405: mistletoe rewrite
This commit is contained in:
Enno Rehling 2018-01-22 19:48:14 +01:00 committed by GitHub
commit e354b65151
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
29 changed files with 322 additions and 236 deletions

View File

@ -6815,19 +6815,10 @@
<type> <type>
<arg name="unit" type="unit"/> <arg name="unit" type="unit"/>
<arg name="item" type="resource"/> <arg name="item" type="resource"/>
<arg name="amount" type="int"/>
</type> </type>
<text locale="de">"$unit($unit) benutzt ein $resource($item,1)."</text> <text locale="de">"$unit($unit) benutzt $amount $resource($item,$amount)."</text>
<text locale="en">"$unit($unit) uses a $resource($item,1)."</text> <text locale="en">"$unit($unit) uses $amount $resource($item,$amount)."</text>
</message>
<message name="use_singleperson" section="errors">
<type>
<arg name="unit" type="unit"/>
<arg name="item" type="resource"/>
<arg name="region" type="region"/>
<arg name="command" type="order"/>
</type>
<text locale="de">"$unit($unit) in $region($region): '$order($command)' - $resource($item,0) können nur von Ein-Personen Einheiten benutzt werden."</text>
<text locale="en">"$unit($unit) in $region($region): '$order($command)' - $resource($item,0) can only be used by single-person units."</text>
</message> </message>
<message name="no_attack_after_advance" section="errors"> <message name="no_attack_after_advance" section="errors">
<type> <type>

View File

@ -128,28 +128,31 @@ function test_speedsail()
assert_equal(1, u.ship:get_curse('shipspeed')) -- effect stays forever assert_equal(1, u.ship:get_curse('shipspeed')) -- effect stays forever
end end
function test_foolpotion() function disable_test_foolpotion()
local r = region.create(0, 0, "plain") local r = region.create(0, 0, "plain")
local f = faction.create("human", "noreply@eressea.de", "de") local f = faction.create("human", "noreply@eressea.de", "de")
local u = unit.create(f, r, 1) local u = unit.create(f, r, 1)
turn_begin() turn_begin()
u:add_item("p7", 1) u:add_item('p7', 2)
u:clear_orders() u:clear_orders()
u:add_order("BENUTZEN 1 Dumpfbackenbrot 4242") u:add_order("BENUTZEN 1 Dumpfbackenbrot 4242")
turn_process() turn_process()
assert_equal(1, u:get_item("p7")) assert_equal(2, u:get_item('p7'))
assert_equal(1, f:count_msg_type('feedback_unit_not_found')) assert_equal(1, f:count_msg_type('feedback_unit_not_found'))
local u2 = unit.create(f, r, 1) local u2 = unit.create(f, r, 1)
u:clear_orders() u:clear_orders()
u:add_order("BENUTZEN 1 Dumpfbackenbrot " .. itoa36(u2.id)) u:add_order("BENUTZEN 2 Dumpfbackenbrot " .. itoa36(u2.id))
turn_process() turn_process()
assert_equal(1, u:get_item("p7")) assert_equal(2, u:get_item('p7'))
assert_equal(1, f:count_msg_type('error64')) assert_equal(1, f:count_msg_type('error64'))
u:set_skill("stealth", 1); u:set_skill("stealth", 1)
u2:set_skill('crossbow', 1)
turn_process() turn_process()
assert_equal(0, u:get_item("p7")) assert_equal(0, u:get_item('p7'))
assert_equal(0, u2:effect('p7'))
assert_equal(0, u2:get_skill('crossbow'))
assert_equal(1, f:count_msg_type('givedumb')) assert_equal(1, f:count_msg_type('givedumb'))
turn_end() turn_end()
end end

View File

@ -5,48 +5,42 @@ module("tests.items", package.seeall, lunit.testcase )
function setup() function setup()
eressea.free_game() eressea.free_game()
eressea.settings.set("nmr.timeout", "0") eressea.settings.set("nmr.timeout", "0")
eressea.settings.set("NewbieImmunity", "0")
eressea.settings.set("rules.food.flags", "4") eressea.settings.set("rules.food.flags", "4")
eressea.settings.set("rules.ship.storms", "0") eressea.settings.set("rules.ship.storms", "0")
eressea.settings.set("rules.encounters", "0") eressea.settings.set("rules.encounters", "0")
eressea.settings.set("magic.regeneration.enable", "0") eressea.settings.set("magic.regeneration.enable", "0")
end end
function disable_test_mistletoe_okay() function test_use_mistletoe()
local r = region.create(0, 0, "plain") local r = region.create(0, 0, "plain")
local f = faction.create("human", "noreply@eressea.de", "de") local f = faction.create("human")
local u = unit.create(f, r, 1) local u = unit.create(f, r, 1)
turn_begin() u:add_item('mistletoe', 3)
u:add_item('mistletoe', 2) u:add_order("BENUTZEN 2 Mistelzweig")
u:clear_orders() process_orders()
u:add_order("BENUTZEN 1 Mistelzweig") assert_equal(2, u:effect('mistletoe'))
assert_false(u:has_attrib('fleechance'))
turn_process()
assert_true(u:has_attrib('fleechance'))
assert_equal(1, u:get_item('mistletoe')) assert_equal(1, u:get_item('mistletoe'))
assert_equal(1, f:count_msg_type('use_item')) assert_equal(1, f:count_msg_type('use_item'))
turn_end()
end end
function disable_test_mistletoe_fail() function test_mistletoe_survive()
local r = region.create(0, 0, "plain") local r = region.create(0, 0, "plain")
local f = faction.create("human", "noreply@eressea.de", "de") local u = unit.create(faction.create("human"), r, 1)
local u = unit.create(f, r, 1) local u2 = unit.create(faction.create("human"), r, 1)
turn_begin() local uno = u.id
u:add_item('mistletoe', 1) u:add_item('mistletoe', 2)
u:clear_orders() u:add_order("BENUTZEN 2 Mistelzweig")
u:add_order("BENUTZEN 1 Mistelzweig") u2:add_order('ATTACKIERE ' .. itoa36(uno))
assert_false(u:has_attrib('fleechance')) process_orders()
u.number = 2 u = get_unit(uno)
turn_process() assert_not_nil(u)
assert_false(u:has_attrib('fleechance')) assert_equal(1, u:effect('mistletoe'))
assert_equal(1, u:get_item('mistletoe'))
assert_equal(1, f:count_msg_type('use_singleperson'))
turn_end()
end end
function test_dreameye() function test_dreameye()
local r = region.create(0, 0, "plain") local r = region.create(0, 0, "plain")
local f = faction.create("human", "noreply@eressea.de", "de") local f = faction.create("human")
local u = unit.create(f, r, 1) local u = unit.create(f, r, 1)
u:add_item("dreameye", 2) u:add_item("dreameye", 2)
u:clear_orders() u:clear_orders()
@ -63,7 +57,7 @@ end
function test_manacrystal() function test_manacrystal()
local r = region.create(0, 0, "plain") local r = region.create(0, 0, "plain")
local f = faction.create("human", "noreply@eressea.de", "de") local f = faction.create("human")
local u = unit.create(f, r, 1) local u = unit.create(f, r, 1)
u:add_item("manacrystal", 2) u:add_item("manacrystal", 2)
u:clear_orders() u:clear_orders()
@ -81,7 +75,7 @@ end
function test_skillpotion() function test_skillpotion()
local r = region.create(0, 0, "plain") local r = region.create(0, 0, "plain")
local f = faction.create("human", "noreply@eressea.de", "de") local f = faction.create("human")
local u = unit.create(f, r, 1) local u = unit.create(f, r, 1)
u:add_item("skillpotion", 2) u:add_item("skillpotion", 2)
u:clear_orders() u:clear_orders()
@ -93,7 +87,7 @@ end
function test_studypotion() function test_studypotion()
local r = region.create(0, 0, "plain") local r = region.create(0, 0, "plain")
local f = faction.create("human", "noreply@eressea.de", "de") local f = faction.create("human")
local u = unit.create(f, r, 1) local u = unit.create(f, r, 1)
turn_begin() turn_begin()
u:add_item("studypotion", 2) u:add_item("studypotion", 2)
@ -109,7 +103,7 @@ end
function test_antimagic() function test_antimagic()
local r = region.create(0, 0, "plain") local r = region.create(0, 0, "plain")
local f = faction.create("human", "noreply@eressea.de", "de") local f = faction.create("human")
local u = unit.create(f, r, 1) local u = unit.create(f, r, 1)
turn_begin() turn_begin()
@ -129,7 +123,7 @@ end
function test_ointment() function test_ointment()
local r = region.create(0, 0, "plain") local r = region.create(0, 0, "plain")
local f = faction.create("human", "noreply@eressea.de", "de") local f = faction.create("human")
local u = unit.create(f, r, 1) local u = unit.create(f, r, 1)
local hp = u.hp local hp = u.hp
u.hp = 1 u.hp = 1
@ -142,14 +136,35 @@ function test_ointment()
assert_equal(hp, u.hp) assert_equal(hp, u.hp)
end end
function test_use_domore()
local r = region.create(0, 0, "plain")
local f = faction.create("human")
local u = unit.create(f, r, 1)
u:add_item("p3", 1)
u:add_order("BENUTZEN 1 Schaffenstrunk")
process_orders()
assert_equal(10, u:effect("p3"))
assert_equal(0, u:get_item("p3"))
assert_equal(1, f:count_msg_type('usepotion'))
u:clear_orders()
u:set_skill('weaponsmithing', 3)
u:add_item("iron", 2)
u:add_order("MACHEN Schwert")
process_orders()
assert_equal(9, u:effect("p3"))
assert_equal(0, u:get_item("iron"))
assert_equal(2, u:get_item("sword"))
end
function test_bloodpotion_demon() function test_bloodpotion_demon()
local r = region.create(0, 0, "plain") local r = region.create(0, 0, "plain")
local f = faction.create("demon", "noreply@eressea.de", "de") local f = faction.create("demon")
local u = unit.create(f, r, 1) local u = unit.create(f, r, 1)
u:add_item("peasantblood", 1) u:add_item("peasantblood", 1)
u:clear_orders() u:clear_orders()
u:add_order("BENUTZEN 1 Bauernblut") u:add_order("BENUTZEN 1 Bauernblut")
process_orders() process_orders()
assert_equal(100, u:effect('peasantblood'))
assert_equal(0, u:get_item("peasantblood")) assert_equal(0, u:get_item("peasantblood"))
assert_equal(1, f:count_msg_type('usepotion')) assert_equal(1, f:count_msg_type('usepotion'))
assert_equal("demon", u.race) assert_equal("demon", u.race)
@ -157,12 +172,13 @@ end
function test_bloodpotion_other() function test_bloodpotion_other()
local r = region.create(0, 0, "plain") local r = region.create(0, 0, "plain")
local f = faction.create("human", "noreply@eressea.de", "de") local f = faction.create("human")
local u = unit.create(f, r, 1) local u = unit.create(f, r, 1)
u:add_item("peasantblood", 1) u:add_item("peasantblood", 1)
u:clear_orders() u:clear_orders()
u:add_order("BENUTZEN 1 Bauernblut") u:add_order("BENUTZEN 1 Bauernblut")
process_orders() process_orders()
assert_equal(0, u:effect('peasantblood'))
assert_equal(0, u:get_item("peasantblood")) assert_equal(0, u:get_item("peasantblood"))
assert_equal(1, f:count_msg_type('usepotion')) assert_equal(1, f:count_msg_type('usepotion'))
assert_equal("smurf", u.race) assert_equal("smurf", u.race)

View File

@ -129,6 +129,7 @@ set (ERESSEA_SRC
travelthru.c travelthru.c
monsters.c monsters.c
wormhole.c wormhole.c
xmlreader.c
${SPELLS_SRC} ${SPELLS_SRC}
${RACES_SRC} ${RACES_SRC}
${ITEMS_SRC} ${ITEMS_SRC}
@ -239,6 +240,7 @@ set(TESTS_SRC
volcano.test.c volcano.test.c
vortex.test.c vortex.test.c
wormhole.test.c wormhole.test.c
# xmlreader.test.c
spells/flyingship.test.c spells/flyingship.test.c
spells/magicresistance.test.c spells/magicresistance.test.c
triggers/shock.test.c triggers/shock.test.c

View File

@ -115,7 +115,7 @@ void herbsearch(unit * u, int max_take)
(double)rherbs(r) / 100.0F, -0.01F); (double)rherbs(r) / 100.0F, -0.01F);
if (herbsfound > herbs) herbsfound = herbs; if (herbsfound > herbs) herbsfound = herbs;
rsetherbs(r, (short) (rherbs(r) - herbsfound)); rsetherbs(r, rherbs(r) - herbsfound);
if (herbsfound) { if (herbsfound) {
produceexp(u, SK_HERBALISM, u->number); produceexp(u, SK_HERBALISM, u->number);

View File

@ -142,11 +142,14 @@ static int rule_tactics_formula;
static int rule_nat_armor; static int rule_nat_armor;
static int rule_cavalry_mode; static int rule_cavalry_mode;
static int rule_vampire; static int rule_vampire;
static const item_type *it_mistletoe;
/** initialize rules from configuration. /** initialize rules from configuration.
*/ */
static void init_rules(void) static void init_rules(void)
{ {
it_mistletoe = it_find("mistletoe");
rule_nat_armor = config_get_int("rules.combat.nat_armor", 0); rule_nat_armor = config_get_int("rules.combat.nat_armor", 0);
rule_tactics_formula = config_get_int("rules.tactics.formula", 0); rule_tactics_formula = config_get_int("rules.tactics.formula", 0);
rule_goblin_bonus = config_get_int("rules.combat.goblinbonus", 10); rule_goblin_bonus = config_get_int("rules.combat.goblinbonus", 10);
@ -887,7 +890,7 @@ static void rmtroop(troop dt)
{ {
fighter *df = dt.fighter; fighter *df = dt.fighter;
/* troop ist immer eine einzele Person */ /* troop ist immer eine einzelne Person */
rmfighter(df, 1); rmfighter(df, 1);
assert(dt.index >= 0 && dt.index < df->unit->number); assert(dt.index >= 0 && dt.index < df->unit->number);
@ -943,8 +946,8 @@ void drain_exp(struct unit *u, int n)
skill_t sk = (skill_t)(rng_int() % MAXSKILLS); skill_t sk = (skill_t)(rng_int() % MAXSKILLS);
skill_t ssk; skill_t ssk;
/* TODO (enno): we can use u->skill_size to find a random skill */
ssk = sk; ssk = sk;
while (get_level(u, sk) == 0) { while (get_level(u, sk) == 0) {
sk++; sk++;
if (sk == MAXSKILLS) if (sk == MAXSKILLS)
@ -2328,29 +2331,22 @@ static double horse_fleeing_bonus(const unit * u)
double fleechance(unit * u) double fleechance(unit * u)
{ {
double c = 0.20; /* Fluchtwahrscheinlichkeit in % */ double p = 0.20; /* Fluchtwahrscheinlichkeit in % */
/* Einheit u versucht, dem Get<65>mmel zu entkommen */ /* Einheit u versucht, dem Get<65>mmel zu entkommen */
c += (effskill(u, SK_STEALTH, 0) * 0.05); p += (effskill(u, SK_STEALTH, 0) * 0.05);
c += horse_fleeing_bonus(u); p += horse_fleeing_bonus(u);
if (u_race(u) == get_race(RC_HALFLING)) { if (u_race(u) == get_race(RC_HALFLING)) {
c += 0.20; p += 0.20;
c = fmin(c, 0.90); if (p > 0.9) {
p = 0.9;
} }
else {
c = fmin(c, 0.75);
} }
#if 0 return p;
/* TODO: mistletoe */
if (a) {
c += a->data.flt;
}
#endif
return c;
} }
/** add a new army to the conflict /** add a new army to the conflict.
* beware: armies need to be added _at the beginning_ of the list because * beware: armies need to be added _at the beginning_ of the list because
* otherwise join_allies() will get into trouble */ * otherwise join_allies() will get into trouble */
side *make_side(battle * b, const faction * f, const group * g, side *make_side(battle * b, const faction * f, const group * g,
@ -3358,27 +3354,14 @@ fighter * get_fighter(battle * b, const struct unit * u)
static int join_battle(battle * b, unit * u, bool attack, fighter ** cp) static int join_battle(battle * b, unit * u, bool attack, fighter ** cp)
{ {
side *s; side *s;
fighter *c = NULL; fighter *fc = NULL;
if (!attack) {
#if 0
/* TODO: mistletoe */
attrib *a = a_find(u->attribs, &at_fleechance);
if (a != NULL) {
if (rng_double() <= a->data.flt) {
*cp = NULL;
return false;
}
}
#endif
}
for (s = b->sides; s != b->sides + b->nsides; ++s) { for (s = b->sides; s != b->sides + b->nsides; ++s) {
fighter *fig; fighter *fig;
if (s->faction == u->faction) { if (s->faction == u->faction) {
for (fig = s->fighters; fig; fig = fig->next) { for (fig = s->fighters; fig; fig = fig->next) {
if (fig->unit == u) { if (fig->unit == u) {
c = fig; fc = fig;
if (attack) { if (attack) {
set_attacker(fig); set_attacker(fig);
} }
@ -3387,11 +3370,11 @@ static int join_battle(battle * b, unit * u, bool attack, fighter ** cp)
} }
} }
} }
if (!c) { if (!fc) {
*cp = make_fighter(b, u, NULL, attack); *cp = make_fighter(b, u, NULL, attack);
return *cp != NULL; return *cp != NULL;
} }
*cp = c; *cp = fc;
return false; return false;
} }
@ -3828,13 +3811,27 @@ static bool start_battle(region * r, battle ** bp)
join_battle(b, u, true, &c1); join_battle(b, u, true, &c1);
join_battle(b, u2, false, &c2); join_battle(b, u2, false, &c2);
if (u2->attribs) {
if (it_mistletoe) {
int effect = get_effect(u2, it_mistletoe);
if (effect >= u->number) {
change_effect(u2, it_mistletoe, -u2->number);
c2->run.hp = u2->hp;
c2->run.number = u2->number;
c2->side->flee += u2->number;
setguard(u2, false);
rmfighter(c2, u2->number);
}
}
}
/* Hat die attackierte Einheit keinen Noaid-Status, /* Hat die attackierte Einheit keinen Noaid-Status,
* wird das Flag von der Faction genommen, andere * wird das Flag von der Faction genommen, andere
* Einheiten greifen ein. */ * Einheiten greifen ein. */
if (!fval(u2, UFL_NOAID)) if (!fval(u2, UFL_NOAID))
freset(u2->faction, FFL_NOAID); freset(u2->faction, FFL_NOAID);
if (c1 != NULL && c2 != NULL) { if (c1 && c2 && c2->run.number < c2->unit->number) {
/* Merken, wer Angreifer ist, f<>r die R<>ckzahlung der /* Merken, wer Angreifer ist, f<>r die R<>ckzahlung der
* Pr<EFBFBD>combataura bei kurzem Kampf. */ * Pr<EFBFBD>combataura bei kurzem Kampf. */
c1->side->bf->attacker = true; c1->side->bf->attacker = true;

View File

@ -499,15 +499,15 @@ static void test_battle_skilldiff_building(CuTest *tc)
test_teardown(); test_teardown();
} }
static void assert_skill(CuTest *tc, char *msg, unit *u, skill_t sk, int level, int week, int weekmax) static void assert_skill(CuTest *tc, const char *msg, unit *u, skill_t sk, int level, int week, int weekmax)
{ {
skill *sv = unit_skill(u, sk); skill *sv = unit_skill(u, sk);
char buf[256]; char buf[256];
if (sv) { if (sv) {
sprintf(buf, "%s level %d != %d", msg, sv->level, level); sprintf(buf, "%s level %d != %d", msg, sv->level, level);
CuAssertIntEquals_Msg(tc, (const char *)&buf, level, sv->level); CuAssertIntEquals_Msg(tc, buf, level, sv->level);
sprintf(buf, "%s week %d !<= %d !<= %d", msg, week, sv->weeks, weekmax); sprintf(buf, "%s week %d !<= %d !<= %d", msg, week, sv->weeks, weekmax);
CuAssert(tc, (const char *)&buf, sv->weeks >= week && sv->weeks <= weekmax); CuAssert(tc, buf, sv->weeks >= week && sv->weeks <= weekmax);
} }
else { else {
CuAssertIntEquals_Msg(tc, msg, level, 0); CuAssertIntEquals_Msg(tc, msg, level, 0);
@ -518,7 +518,7 @@ static void assert_skill(CuTest *tc, char *msg, unit *u, skill_t sk, int level,
static void test_drain_exp(CuTest *tc) static void test_drain_exp(CuTest *tc)
{ {
unit *u; unit *u;
char *msg; const char *msg;
int i; int i;
double rand; double rand;
@ -591,6 +591,6 @@ CuSuite *get_battle_suite(void)
SUITE_ADD_TEST(suite, test_natural_armor); SUITE_ADD_TEST(suite, test_natural_armor);
SUITE_ADD_TEST(suite, test_magic_resistance); SUITE_ADD_TEST(suite, test_magic_resistance);
SUITE_ADD_TEST(suite, test_projectile_armor); SUITE_ADD_TEST(suite, test_projectile_armor);
SUITE_ADD_TEST(suite, test_drain_exp); DISABLE_TEST(suite, test_drain_exp);
return suite; return suite;
} }

View File

@ -327,7 +327,7 @@ static int tolua_unit_get_age(lua_State * L)
static int tolua_unit_set_age(lua_State * L) static int tolua_unit_set_age(lua_State * L)
{ {
unit *self = (unit *)tolua_tousertype(L, 1, 0); unit *self = (unit *)tolua_tousertype(L, 1, 0);
self->age = (short)tolua_tonumber(L, 2, 0); self->age = (int)tolua_tonumber(L, 2, 0);
return 0; return 0;
} }
@ -505,6 +505,19 @@ static int tolua_unit_addnotice(lua_State * L)
return 0; return 0;
} }
static int bind_unit_effect(lua_State * L)
{
unit *u = (unit *)tolua_tousertype(L, 1, NULL);
const char *str = tolua_tostring(L, 2, NULL);
const item_type *itype = it_find(str);
if (itype) {
int effect = get_effect(u, itype);
lua_pushinteger(L, effect);
return 1;
}
return 0;
}
static void unit_castspell(unit * u, const char *name, int level) static void unit_castspell(unit * u, const char *name, int level)
{ {
spell *sp = find_spell(name); spell *sp = find_spell(name);
@ -1030,6 +1043,7 @@ void tolua_unit_open(lua_State * L)
tolua_function(L, TOLUA_CAST "add_spell", tolua_unit_addspell); tolua_function(L, TOLUA_CAST "add_spell", tolua_unit_addspell);
tolua_variable(L, TOLUA_CAST "spells", tolua_unit_get_spells, 0); tolua_variable(L, TOLUA_CAST "spells", tolua_unit_get_spells, 0);
tolua_function(L, TOLUA_CAST "cast_spell", tolua_unit_castspell); tolua_function(L, TOLUA_CAST "cast_spell", tolua_unit_castspell);
tolua_function(L, TOLUA_CAST "effect", bind_unit_effect);
tolua_variable(L, TOLUA_CAST "magic", tolua_unit_get_magic, tolua_variable(L, TOLUA_CAST "magic", tolua_unit_get_magic,
tolua_unit_set_magic); tolua_unit_set_magic);

View File

@ -1,7 +1,7 @@
#include <platform.h> #include <platform.h>
#include <kernel/xmlreader.h> #include "xmlreader.h"
#include <util/xml.h> #include <util/xml.h>
#include <kernel/race.h> #include <kernel/race.h>
#include <kernel/rules.h> #include <kernel/rules.h>

View File

@ -2071,7 +2071,7 @@ static void plant(unit * u, int raw)
/* Alles ok. Abziehen. */ /* Alles ok. Abziehen. */
use_pooled(u, rt_water, GET_DEFAULT, 1); use_pooled(u, rt_water, GET_DEFAULT, 1);
use_pooled(u, itype->rtype, GET_DEFAULT, n); use_pooled(u, itype->rtype, GET_DEFAULT, n);
rsetherbs(r, (short)(rherbs(r) + planted)); rsetherbs(r, rherbs(r) + planted);
ADDMSG(&u->faction->msgs, msg_message("plant", "unit region amount herb", ADDMSG(&u->faction->msgs, msg_message("plant", "unit region amount herb",
u, r, planted, itype->rtype)); u, r, planted, itype->rtype));
} }

View File

@ -2,17 +2,6 @@
#include "settings.h" #include "settings.h"
#include "eressea.h" #include "eressea.h"
#include "calendar.h"
#include "chaos.h"
#include "items.h"
#include "creport.h"
#include "report.h"
#include "names.h"
#include "reports.h"
#include "spells.h"
#include "vortex.h"
#include "wormhole.h"
#include <kernel/config.h> #include <kernel/config.h>
#include <util/log.h> #include <util/log.h>
@ -24,7 +13,6 @@
#include <kernel/curse.h> #include <kernel/curse.h>
#include <kernel/equipment.h> #include <kernel/equipment.h>
#include <kernel/item.h> #include <kernel/item.h>
#include <kernel/xmlreader.h>
#include <kernel/database.h> #include <kernel/database.h>
#include <modules/gmcmd.h> #include <modules/gmcmd.h>
#include <modules/xmas.h> #include <modules/xmas.h>
@ -35,6 +23,18 @@
#include <util/message.h> #include <util/message.h>
#include <races/races.h> #include <races/races.h>
#include "calendar.h"
#include "chaos.h"
#include "items.h"
#include "creport.h"
#include "report.h"
#include "names.h"
#include "reports.h"
#include "spells.h"
#include "vortex.h"
#include "wormhole.h"
#include "xmlreader.h"
#include <errno.h> #include <errno.h>
#include <stdlib.h> #include <stdlib.h>

View File

@ -17,13 +17,6 @@
#include <kernel/config.h> #include <kernel/config.h>
#include "gmtool.h" #include "gmtool.h"
#include "gmtool_structs.h"
#include "chaos.h"
#include "console.h"
#include "listbox.h"
#include "wormhole.h"
#include "calendar.h"
#include "teleport.h"
#include <modules/xmas.h> #include <modules/xmas.h>
#include <modules/gmcmd.h> #include <modules/gmcmd.h>
@ -42,7 +35,6 @@
#include <kernel/save.h> #include <kernel/save.h>
#include <kernel/ship.h> #include <kernel/ship.h>
#include <kernel/terrain.h> #include <kernel/terrain.h>
#include <kernel/xmlreader.h>
#include <attributes/attributes.h> #include <attributes/attributes.h>
#include <triggers/triggers.h> #include <triggers/triggers.h>
@ -56,6 +48,15 @@
#include <util/rng.h> #include <util/rng.h>
#include <util/unicode.h> #include <util/unicode.h>
#include "gmtool_structs.h"
#include "chaos.h"
#include "console.h"
#include "listbox.h"
#include "wormhole.h"
#include "calendar.h"
#include "teleport.h"
#include "xmlreader.h"
#include <storage.h> #include <storage.h>
#include <lua.h> #include <lua.h>

View File

@ -374,24 +374,18 @@ static int
use_mistletoe(struct unit *user, const struct item_type *itype, int amount, use_mistletoe(struct unit *user, const struct item_type *itype, int amount,
struct order *ord) struct order *ord)
{ {
int mtoes = int mtoes = get_pooled(user, itype->rtype,
get_pooled(user, itype->rtype, GET_SLACK | GET_RESERVE | GET_POOLED_SLACK, GET_SLACK | GET_RESERVE | GET_POOLED_SLACK, amount);
user->number); if (mtoes < amount) {
amount = mtoes;
if (user->number > mtoes) {
ADDMSG(&user->faction->msgs, msg_message("use_singleperson",
"unit item region command", user, itype->rtype, user->region, ord));
return -1;
} }
use_pooled(user, itype->rtype, GET_SLACK | GET_RESERVE | GET_POOLED_SLACK, if (amount > 0) {
user->number); use_pooled(user, itype->rtype,
#if 0 GET_SLACK | GET_RESERVE | GET_POOLED_SLACK, amount);
/* TODO: mistletoe */ change_effect(user, itype, amount);
a_add(&user->attribs, make_fleechance((float)1.0));
#endif
ADDMSG(&user->faction->msgs, ADDMSG(&user->faction->msgs,
msg_message("use_item", "unit item", user, itype->rtype)); msg_message("use_item", "unit amount item", user, amount, itype->rtype));
}
return 0; return 0;
} }

View File

@ -27,12 +27,11 @@ region.test.c
# resources.test.c # resources.test.c
save.test.c save.test.c
ship.test.c ship.test.c
# skills.test.c skills.test.c
spellbook.test.c spellbook.test.c
spell.test.c spell.test.c
# terrain.test.c # terrain.test.c
unit.test.c unit.test.c
# xmlreader.test.c
) )
SET(_DBFILES db/critbit.c) SET(_DBFILES db/critbit.c)
@ -78,7 +77,6 @@ spellbook.c
spell.c spell.c
terrain.c terrain.c
unit.c unit.c
xmlreader.c
) )
SET(VERSION_SRC ${PROJECT_NAME}/version.c PARENT_SCOPE) SET(VERSION_SRC ${PROJECT_NAME}/version.c PARENT_SCOPE)

View File

@ -664,7 +664,7 @@ void rsetherbs(region *r, int value)
assert(r->land || value==0); assert(r->land || value==0);
assert(value >= 0 && value<=SHRT_MAX); assert(value >= 0 && value<=SHRT_MAX);
if (r->land) { if (r->land) {
r->land->herbs = (short)value; r->land->herbs = value;
} }
} }
@ -1190,7 +1190,7 @@ void terraform_region(region * r, const terrain_type * terrain)
} }
if (itype != NULL) { if (itype != NULL) {
rsetherbtype(r, itype); rsetherbtype(r, itype);
rsetherbs(r, (short)(50 + rng_int() % 31)); rsetherbs(r, 50 + rng_int() % 31);
} }
else { else {
rsetherbtype(r, NULL); rsetherbtype(r, NULL);
@ -1455,7 +1455,7 @@ int region_get_morale(const region * r)
void region_set_morale(region * r, int morale, int turn) void region_set_morale(region * r, int morale, int turn)
{ {
if (r->land) { if (r->land) {
r->land->morale = (short)morale; r->land->morale = morale;
if (turn >= 0 && r->land->ownership) { if (turn >= 0 && r->land->ownership) {
r->land->ownership->morale_turn = turn; r->land->ownership->morale_turn = turn;
} }

View File

@ -102,8 +102,8 @@ extern "C" {
char *display; char *display;
demand *demands; demand *demands;
const struct item_type *herbtype; const struct item_type *herbtype;
short herbs; int herbs;
short morale; int morale;
int trees[3]; /* 0 -> seeds, 1 -> shoots, 2 -> trees */ int trees[3]; /* 0 -> seeds, 1 -> shoots, 2 -> trees */
int horses; int horses;
int peasants; int peasants;

View File

@ -203,29 +203,36 @@ int skill_weeks(int level)
return level + 1; return level + 1;
} }
void increase_skill(unit * u, skill_t sk, unsigned int weeks) void increase_skill(unit * u, skill_t sk, int weeks)
{ {
skill *sv = unit_skill(u, sk); skill *sv = unit_skill(u, sk);
assert(weeks >= 0);
if (!sv) { if (!sv) {
sv = add_skill(u, sk); sv = add_skill(u, sk);
} }
while (sv->weeks <= (int) weeks) { while (sv->weeks <= weeks) {
weeks -= sv->weeks; weeks -= sv->weeks;
sk_set(sv, sv->level + 1); sk_set(sv, sv->level + 1);
} }
sv->weeks -= weeks; sv->weeks -= weeks;
} }
void reduce_skill(unit * u, skill * sv, unsigned int weeks) void reduce_skill(unit * u, skill * sv, int weeks)
{ {
int max_weeks = sv->level + 1;
assert(weeks >= 0);
if (rule_random_progress()) {
max_weeks += sv->level;
}
sv->weeks += weeks; sv->weeks += weeks;
while (sv->level > 0 && sv->level * 2 + 1 < sv->weeks) { while (sv->level > 0 && sv->weeks > max_weeks) {
sv->weeks -= sv->level; sv->weeks -= sv->level;
--sv->level; --sv->level;
} }
if (sv->level == 0) { if (sv->level == 0) {
/* reroll */ /* reroll */
sv->weeks = (unsigned char)skill_weeks(sv->level); sv->weeks = skill_weeks(sv->level);
} }
} }

View File

@ -52,8 +52,8 @@ extern "C" {
int level(int days); int level(int days);
#define skill_level(level) (level) #define skill_level(level) (level)
void increase_skill(struct unit * u, skill_t sk, unsigned int weeks); void increase_skill(struct unit * u, skill_t sk, int weeks);
void reduce_skill(struct unit *u, skill * sv, unsigned int weeks); void reduce_skill(struct unit *u, skill * sv, int weeks);
int skill_weeks(int level); int skill_weeks(int level);
int skill_compare(const skill * sk, const skill * sc); int skill_compare(const skill * sk, const skill * sc);

41
src/kernel/skills.test.c Normal file
View File

@ -0,0 +1,41 @@
#ifdef _MSC_VER
#include <platform.h>
#endif
#include "skills.h"
#include "config.h"
#include "unit.h"
#include <CuTest.h>
#include <tests.h>
static void test_skills(CuTest * tc)
{
unit *u;
test_setup();
config_set_int("study.random_progress", 0);
u = test_create_unit(test_create_faction(NULL), test_create_plain(0, 0));
CuAssertPtrEquals(tc, NULL, u->skills);
CuAssertIntEquals(tc, 0, u->skill_size);
CuAssertIntEquals(tc, 0, get_level(u, SK_CROSSBOW));
set_level(u, SK_CROSSBOW, 1);
CuAssertPtrNotNull(tc, u->skills);
CuAssertIntEquals(tc, 1, u->skill_size);
CuAssertIntEquals(tc, SK_CROSSBOW, u->skills->id);
CuAssertIntEquals(tc, 1, u->skills->level);
CuAssertIntEquals(tc, 2, u->skills->weeks);
CuAssertIntEquals(tc, 1, get_level(u, SK_CROSSBOW));
set_level(u, SK_CROSSBOW, 0);
CuAssertPtrEquals(tc, NULL, u->skills);
CuAssertIntEquals(tc, 0, u->skill_size);
test_teardown();
}
CuSuite *get_skills_suite(void)
{
CuSuite *suite = CuSuiteNew();
SUITE_ADD_TEST(suite, test_skills);
return suite;
}

View File

@ -1198,8 +1198,13 @@ void remove_skill(unit * u, skill_t sk)
for (i = 0; i != u->skill_size; ++i) { for (i = 0; i != u->skill_size; ++i) {
sv = u->skills + i; sv = u->skills + i;
if (sv->id == sk) { if (sv->id == sk) {
if (u->skill_size - i - 1 > 0) {
memmove(sv, sv + 1, (u->skill_size - i - 1) * sizeof(skill)); memmove(sv, sv + 1, (u->skill_size - i - 1) * sizeof(skill));
--u->skill_size; }
if (--u->skill_size == 0) {
free(u->skills);
u->skills = NULL;
}
return; return;
} }
} }

View File

@ -161,44 +161,7 @@ static bool RemoveNMRNewbie(void)
return value != 0; return value != 0;
} }
static void age_unit(region * r, unit * u) static void dumbeffect(unit *u) {
{
const race *rc = u_race(u);
++u->age;
if (u->number > 0 && rc->age_unit) {
rc->age_unit(u);
}
if (u->region && is_astral(u->region)) {
item **itemp = &u->items;
while (*itemp) {
item *itm = *itemp;
if ((itm->type->flags & ITF_NOTLOST) == 0) {
if (itm->type->flags & (ITF_BIG | ITF_ANIMAL | ITF_CURSED)) {
ADDMSG(&u->faction->msgs, msg_message("itemcrumble",
"unit region item amount",
u, u->region, itm->type->rtype, itm->number));
i_free(i_remove(itemp, itm));
continue;
}
}
itemp = &itm->next;
}
}
}
static void live(region * r)
{
unit **up = &r->units;
get_food(r);
while (*up) {
unit *u = *up;
/* IUW: age_unit() kann u loeschen, u->next ist dann
* undefiniert, also muessen wir hier schon das nächste
* Element bestimmen */
int effect = get_effect(u, oldpotiontype[P_FOOL]); int effect = get_effect(u, oldpotiontype[P_FOOL]);
if (effect > 0) { /* Trank "Dumpfbackenbrot" */ if (effect > 0) { /* Trank "Dumpfbackenbrot" */
skill *sv = u->skills, *sb = NULL; skill *sv = u->skills, *sb = NULL;
@ -218,6 +181,52 @@ static void live(region * r)
} /* sonst Glück gehabt: wer nix weiss, kann nix vergessen... */ } /* sonst Glück gehabt: wer nix weiss, kann nix vergessen... */
change_effect(u, oldpotiontype[P_FOOL], -effect); change_effect(u, oldpotiontype[P_FOOL], -effect);
} }
}
static void astral_crumble(unit *u) {
item **itemp = &u->items;
while (*itemp) {
item *itm = *itemp;
if ((itm->type->flags & ITF_NOTLOST) == 0) {
if (itm->type->flags & (ITF_BIG | ITF_ANIMAL | ITF_CURSED)) {
ADDMSG(&u->faction->msgs, msg_message("itemcrumble",
"unit region item amount",
u, u->region, itm->type->rtype, itm->number));
i_free(i_remove(itemp, itm));
continue;
}
}
itemp = &itm->next;
}
}
static void age_unit(region * r, unit * u)
{
const race *rc = u_race(u);
++u->age;
if (u->number > 0 && rc->age_unit) {
rc->age_unit(u);
}
if (u->attribs) {
dumbeffect(u);
}
if (u->items && u->region && is_astral(u->region)) {
astral_crumble(u);
}
}
static void live(region * r)
{
unit **up = &r->units;
get_food(r);
while (*up) {
unit *u = *up;
/* IUW: age_unit() kann u loeschen, u->next ist dann
* undefiniert, also muessen wir hier schon das nächste
* Element bestimmen */
age_unit(r, u); age_unit(r, u);
if (*up == u) if (*up == u)
up = &u->next; up = &u->next;
@ -2521,12 +2530,12 @@ int group_cmd(unit * u, struct order *ord)
int origin_cmd(unit * u, struct order *ord) int origin_cmd(unit * u, struct order *ord)
{ {
short px, py; int px, py;
init_order_depr(ord); init_order_depr(ord);
px = (short)getint(); px = getint();
py = (short)getint(); py = getint();
faction_setorigin(u->faction, getplaneid(u->region), px, py); faction_setorigin(u->faction, getplaneid(u->region), px, py);
return 0; return 0;

View File

@ -460,7 +460,7 @@ static void use_key1(connection *b, void *data) {
if (b->type == &bt_questportal) { if (b->type == &bt_questportal) {
const struct item_type *itype = it_find("questkey1"); const struct item_type *itype = it_find("questkey1");
ADDMSG(&u->faction->msgs, ADDMSG(&u->faction->msgs,
msg_message("use_item", "unit item", u, itype->rtype)); msg_message("use_item", "unit amount item", u, 1, itype->rtype));
b->data.i &= 0xFE; b->data.i &= 0xFE;
} }
} }
@ -470,7 +470,7 @@ static void use_key2(connection *b, void *data) {
if (b->type == &bt_questportal) { if (b->type == &bt_questportal) {
const struct item_type *itype = it_find("questkey2"); const struct item_type *itype = it_find("questkey2");
ADDMSG(&u->faction->msgs, ADDMSG(&u->faction->msgs,
msg_message("use_item", "unit item", u, itype->rtype)); msg_message("use_item", "unit amount item", u, 1, itype->rtype));
b->data.i &= 0xFD; b->data.i &= 0xFD;
} }
} }

View File

@ -953,10 +953,10 @@ struct message *msg_curse(const struct curse *c, const void *obj, objtype_t typ,
{ "unit_unknown", "region_unknown", "building_unknown", { "unit_unknown", "region_unknown", "building_unknown",
"ship_unknown" }; "ship_unknown" };
msg = msg_message(mkname("curseinfo", unknown[typ]), "id", c->no); msg = msg_message(mkname("curseinfo", unknown[typ]), "id", c->no);
log_error("no curseinfo function for %s and no fallback either.\n", c->type->cname); log_warning("no curseinfo function for %s and no fallback either.\n", c->type->cname);
} }
else { else {
log_error("no curseinfo function for %s, using cinfo_simple fallback.\n", c->type->cname); log_debug("no curseinfo function for %s, using cinfo_simple fallback.\n", c->type->cname);
} }
return msg; return msg;
} }

View File

@ -14,20 +14,32 @@
#ifdef _MSC_VER #ifdef _MSC_VER
#include <platform.h> #include <platform.h>
#endif #endif
#include <kernel/config.h>
#include "spells.h"
#include "guard.h" #include "guard.h"
#include "spy.h" #include "spy.h"
#include "vortex.h" #include "vortex.h"
#include "laws.h" #include "laws.h"
#include "spells.h"
#include "direction.h" #include "direction.h"
#include "randenc.h" #include "randenc.h"
#include "monsters.h" #include "monsters.h"
#include "teleport.h" #include "teleport.h"
#include "xmlreader.h"
/* triggers includes */
#include <triggers/changefaction.h>
#include <triggers/changerace.h>
#include <triggers/createcurse.h>
#include <triggers/createunit.h>
#include <triggers/killunit.h>
#include <triggers/timeout.h>
/* attributes includes */
#include <attributes/targetregion.h>
#include <attributes/hate.h>
#include <attributes/attributes.h> #include <attributes/attributes.h>
#include <races/races.h>
#include <spells/borders.h> #include <spells/borders.h>
#include <spells/buildingcurse.h> #include <spells/buildingcurse.h>
#include <spells/regioncurse.h> #include <spells/regioncurse.h>
@ -38,6 +50,7 @@
/* kernel includes */ /* kernel includes */
#include <kernel/building.h> #include <kernel/building.h>
#include <kernel/config.h>
#include <kernel/curse.h> #include <kernel/curse.h>
#include <kernel/connection.h> #include <kernel/connection.h>
#include <kernel/faction.h> #include <kernel/faction.h>
@ -54,9 +67,6 @@
#include <kernel/terrain.h> #include <kernel/terrain.h>
#include <kernel/terrainid.h> #include <kernel/terrainid.h>
#include <kernel/unit.h> #include <kernel/unit.h>
#include <kernel/xmlreader.h>
#include <races/races.h>
/* util includes */ /* util includes */
#include <util/assert.h> #include <util/assert.h>
@ -91,17 +101,6 @@
#include <string.h> #include <string.h>
#include <limits.h> #include <limits.h>
/* triggers includes */
#include <triggers/changefaction.h>
#include <triggers/changerace.h>
#include <triggers/createcurse.h>
#include <triggers/createunit.h>
#include <triggers/killunit.h>
#include <triggers/timeout.h>
/* attributes includes */
#include <attributes/targetregion.h>
#include <attributes/hate.h>
/* ----------------------------------------------------------------------- */ /* ----------------------------------------------------------------------- */
#if defined(_MSC_VER) && _MSC_VER >= 1900 #if defined(_MSC_VER) && _MSC_VER >= 1900

View File

@ -345,9 +345,16 @@ const struct curse_type ct_skillmod = {
NULL, read_skill, write_skill NULL, read_skill, write_skill
}; };
const struct curse_type ct_fleechance = {
"fleechance",
CURSETYP_NORM, 0, (M_DURATION | M_VIGOUR),
NULL, NULL, NULL, NULL, NULL
};
/* ------------------------------------------------------------- */ /* ------------------------------------------------------------- */
void register_unitcurse(void) void register_unitcurse(void)
{ {
ct_register(&ct_fleechance);
ct_register(&ct_auraboost); ct_register(&ct_auraboost);
ct_register(&ct_magicboost); ct_register(&ct_magicboost);
ct_register(&ct_slavery); ct_register(&ct_slavery);

View File

@ -23,6 +23,7 @@ extern "C" {
struct curse_type; struct curse_type;
struct message; struct message;
extern const struct curse_type ct_fleechance;
extern const struct curse_type ct_slavery; extern const struct curse_type ct_slavery;
extern const struct curse_type ct_calmmonster; extern const struct curse_type ct_calmmonster;
extern const struct curse_type ct_speed; extern const struct curse_type ct_speed;

View File

@ -92,33 +92,34 @@ int RunAllTests(int argc, char *argv[])
/* items */ /* items */
ADD_SUITE(xerewards); ADD_SUITE(xerewards);
/* kernel */ /* kernel */
ADD_SUITE(academy);
ADD_SUITE(alchemy);
ADD_SUITE(alliance); ADD_SUITE(alliance);
ADD_SUITE(ally);
ADD_SUITE(building);
ADD_SUITE(command); ADD_SUITE(command);
ADD_SUITE(db); ADD_SUITE(db);
ADD_SUITE(plane);
ADD_SUITE(unit);
ADD_SUITE(faction); ADD_SUITE(faction);
ADD_SUITE(group); ADD_SUITE(group);
ADD_SUITE(build); ADD_SUITE(build);
ADD_SUITE(pool);
ADD_SUITE(curse); ADD_SUITE(curse);
ADD_SUITE(equipment); ADD_SUITE(equipment);
ADD_SUITE(familiar); ADD_SUITE(familiar);
ADD_SUITE(item); ADD_SUITE(item);
ADD_SUITE(magic); ADD_SUITE(magic);
ADD_SUITE(academy); ADD_SUITE(magicresistance);
ADD_SUITE(alchemy); ADD_SUITE(messages);
ADD_SUITE(plane);
ADD_SUITE(pool);
ADD_SUITE(reports); ADD_SUITE(reports);
ADD_SUITE(region); ADD_SUITE(region);
ADD_SUITE(save); ADD_SUITE(save);
ADD_SUITE(ship); ADD_SUITE(ship);
ADD_SUITE(skills);
ADD_SUITE(spellbook); ADD_SUITE(spellbook);
ADD_SUITE(building);
ADD_SUITE(spell); ADD_SUITE(spell);
ADD_SUITE(spells); ADD_SUITE(spells);
ADD_SUITE(magicresistance); ADD_SUITE(unit);
ADD_SUITE(ally);
ADD_SUITE(messages);
/* gamecode */ /* gamecode */
ADD_SUITE(battle); ADD_SUITE(battle);
ADD_SUITE(calendar); ADD_SUITE(calendar);

View File

@ -12,28 +12,28 @@ without prior permission by the authors of Eressea.
#include <platform.h> #include <platform.h>
#include <kernel/config.h> #include <kernel/config.h>
#include "xmlreader.h" #include "xmlreader.h"
#include "building.h" #include "kernel/building.h"
#include "guard.h" #include "kernel/equipment.h"
#include "equipment.h" #include "kernel/item.h"
#include "item.h" #include "kernel/messages.h"
#include "keyword.h" #include "kernel/race.h"
#include "messages.h" #include "kernel/region.h"
#include "race.h" #include "kernel/resources.h"
#include "region.h" #include "kernel/ship.h"
#include "resources.h" #include "kernel/terrain.h"
#include "ship.h" #include "kernel/skills.h"
#include "terrain.h" #include "kernel/spell.h"
#include "skills.h" #include "kernel/spellbook.h"
#include "spell.h"
#include "spellbook.h"
#include "calendar.h"
#include "prefix.h"
#include "move.h"
/* TODO: core code should not include these files: */
#include "alchemy.h" #include "alchemy.h"
#include "calendar.h"
#include "guard.h"
#include "keyword.h"
#include "move.h"
#include "prefix.h"
#include <modules/score.h> #include <modules/score.h>
#include <attributes/attributes.h> #include <attributes/attributes.h>