Merge pull request #887 from ennorehling/develop

trees and seeds
This commit is contained in:
Enno Rehling 2020-01-18 21:11:55 +01:00 committed by GitHub
commit 010487ac8d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
22 changed files with 261 additions and 275 deletions

View File

@ -391,16 +391,6 @@
<arg name="id" type="int"/> <arg name="id" type="int"/>
</type> </type>
</message> </message>
<message name="curseinfo::godcurseocean" section="events">
<type>
<arg name="id" type="int"/>
</type>
</message>
<message name="curseinfo::godcurse" section="events">
<type>
<arg name="id" type="int"/>
</type>
</message>
<message name="curseinfo::disorientationzone" section="events"> <message name="curseinfo::disorientationzone" section="events">
<type> <type>
<arg name="id" type="int"/> <arg name="id" type="int"/>
@ -712,11 +702,6 @@
<arg name="password" type="string"/> <arg name="password" type="string"/>
</type> </type>
</message> </message>
<message name="godcurse_destroy_ship" section="events">
<type>
<arg name="ship" type="ship"/>
</type>
</message>
<message name="skillpotion_use" section="events"> <message name="skillpotion_use" section="events">
<type> <type>
<arg name="unit" type="unit"/> <arg name="unit" type="unit"/>

View File

@ -721,7 +721,7 @@
<attack type="4" damage="3d30"/> <attack type="4" damage="3d30"/>
<attack type="6" spell="icy_dragonbreath" level="6" /> <attack type="6" spell="icy_dragonbreath" level="6" />
</race> </race>
<race name="youngdragon" magres="50" maxaura="1.000000" regaura="1.000000" weight="20000" capacity="10000" speed="1.000000" hp="300" ac="4" damage="2d15" unarmedattack="0" unarmeddefense="0" attackmodifier="4" defensemodifier="4" fly="yes" walk="yes" teach="no" getitem="yes" resistbash="yes" unarmedguard="yes"> <race name="youngdragon" magres="50" maxaura="1.000000" regaura="1.000000" weight="20000" capacity="10000" speed="1.000000" hp="300" ac="4" damage="2d15" unarmedattack="0" unarmeddefense="0" attackmodifier="4" defensemodifier="4" fly="yes" walk="yes" teach="no" getitem="yes" resistbash="yes" unarmedguard="yes" dragon="yes">
<ai splitsize="6" killpeasants="yes" learn="yes" scarepeasants="yes"/> <ai splitsize="6" killpeasants="yes" learn="yes" scarepeasants="yes"/>
<skill name="magic" modifier="4"/> <skill name="magic" modifier="4"/>
<skill name="tactics" modifier="4"/> <skill name="tactics" modifier="4"/>

View File

@ -437,9 +437,6 @@ msgstr "\"$unit($unit) in $region($region): '$order($command)' - Pferde kann man
msgid "error307" msgid "error307"
msgstr "\"$unit($unit) in $region($region): '$order($command)' - Snotlinge sind zu dumm, um auf den Feldern zu arbeiten.\"" msgstr "\"$unit($unit) in $region($region): '$order($command)' - Snotlinge sind zu dumm, um auf den Feldern zu arbeiten.\""
msgid "godcurse_destroy_ship"
msgstr "\"Die Mannschaft krank vom vergifteten Wasser, Planken, Ruder und Segel zerfressen von den Wassern des verfluchten Meeres, ergibt sich die $ship($ship) in ihr Schicksal und sinkt.\""
msgid "too_many_units_in_faction" msgid "too_many_units_in_faction"
msgstr "\"$unit($unit) in $region($region): '$order($command)' - Eine Partei darf nicht aus mehr als $int($allowed) Einheiten bestehen.\"" msgstr "\"$unit($unit) in $region($region): '$order($command)' - Eine Partei darf nicht aus mehr als $int($allowed) Einheiten bestehen.\""
@ -1034,9 +1031,6 @@ msgstr "\"$unit($unit) in $region($region): '$order($command)' - Auf dem Schiff
msgid "sp_icastle_effect" msgid "sp_icastle_effect"
msgstr "\"Verwundert blicken die Bauern von $region($region) auf ein neues Gebäude.\"" msgstr "\"Verwundert blicken die Bauern von $region($region) auf ein neues Gebäude.\""
msgid "curseinfo::godcurse"
msgstr "\"Diese Region wurde von den Göttern verflucht. Stinkende Nebel ziehen über die tote Erde und furchtbare Kreaturen ziehen über das Land. Die Brunnen sind vergiftet, und die wenigen essbaren Früchte sind von einem rosa Pilz überzogen. Niemand kann hier lange überleben. ($int36($id))\""
msgid "recruit_archetype" msgid "recruit_archetype"
msgstr "\"$unit($unit) rekrutiert $int($amount) $localize($archetype).\"" msgstr "\"$unit($unit) rekrutiert $int($amount) $localize($archetype).\""
@ -2555,9 +2549,6 @@ msgstr "\"$unit($unit) in $region($region): '$order($command)' - Man benötigt m
msgid "error177" msgid "error177"
msgstr "\"$unit($unit) in $region($region): '$order($command)' - Diesen Spruch kann der Vertraute nicht zaubern.\"" msgstr "\"$unit($unit) in $region($region): '$order($command)' - Diesen Spruch kann der Vertraute nicht zaubern.\""
msgid "curseinfo::godcurseocean"
msgstr "\"Diese Region wurde von den Göttern verflucht. Das Meer ist eine ekelige Brühe, braunschwarze, stinkende Gase steigen aus den unergründlichen Tiefen hervor, und untote Seeungeheuer, Schiffe zerfressend und giftige grüne Galle geifernd, sind der Schrecken aller Seeleute, die diese Gewässer durchqueren. Niemand kann hier lange überleben. ($int36($id))\""
msgid "curseinfo::sparkle_4" msgid "curseinfo::sparkle_4"
msgstr "\"Ein schimmernder Lichterkranz umgibt $unit($unit). ($int36($id))\"" msgstr "\"Ein schimmernder Lichterkranz umgibt $unit($unit). ($int36($id))\""

View File

@ -437,9 +437,6 @@ msgstr "\"$unit($unit) in $region($region): '$order($command)' - You can only br
msgid "error307" msgid "error307"
msgstr "\"$unit($unit) in $region($region): '$order($command)' - We snotlings is too stupid fer dat!\"" msgstr "\"$unit($unit) in $region($region): '$order($command)' - We snotlings is too stupid fer dat!\""
msgid "godcurse_destroy_ship"
msgstr "\"Her sailors sick from the poisened ocean, planks, rudder und sails corroded by the waters of the cursed ocean, the $ship($ship) finally succumbs to her destiny and sinks.\""
msgid "too_many_units_in_faction" msgid "too_many_units_in_faction"
msgstr "\"$unit($unit) in $region($region): '$order($command)' - A faction may not consist of more than $int($allowed) units.\"" msgstr "\"$unit($unit) in $region($region): '$order($command)' - A faction may not consist of more than $int($allowed) units.\""
@ -1034,9 +1031,6 @@ msgstr "\"$unit($unit) in $region($region): '$order($command)' - There are not e
msgid "sp_icastle_effect" msgid "sp_icastle_effect"
msgstr "\"Flabbergasted, the peasants of $region($region) behold a new building.\"" msgstr "\"Flabbergasted, the peasants of $region($region) behold a new building.\""
msgid "curseinfo::godcurse"
msgstr "\"This region was cursed by the gods. Stinking vapors billow over the dead ground and hideous creatures move about the country. The wells are poisened and the edible plants are covered by a pink fungus. Noone can live here for long. ($int36($id))\""
msgid "recruit_archetype" msgid "recruit_archetype"
msgstr "\"$unit($unit) recruits $int($amount) $localize($archetype).\"" msgstr "\"$unit($unit) recruits $int($amount) $localize($archetype).\""
@ -1251,7 +1245,7 @@ msgid "error184"
msgstr "\"$unit($unit) in $region($region): '$order($command)' - The unit does not move.\"" msgstr "\"$unit($unit) in $region($region): '$order($command)' - The unit does not move.\""
msgid "income_entertainment" msgid "income_entertainment"
msgstr "\"$unit($unit) earns $int($amount) in $region($region) with entertainment.\"" msgstr "\"$unit($unit) earns $int($amount) in $region($region) from entertainment.\""
msgid "error180" msgid "error180"
msgstr "\"$unit($unit) in $region($region): '$order($command)' - The spell fails.\"" msgstr "\"$unit($unit) in $region($region): '$order($command)' - The spell fails.\""
@ -1620,7 +1614,7 @@ msgid "curseinfo::deathcloud"
msgstr "\"A poison elemental is spreading pestilence and death. ($int36($id))\"" msgstr "\"A poison elemental is spreading pestilence and death. ($int36($id))\""
msgid "income" msgid "income"
msgstr "\"$unit($unit) earns $int($amount)$if($eq($wanted,$amount),\"\",\" of $int($wanted)\") in $region($region) $if($eq($mode,1),\" by entertainment\",$if($eq($mode,2),\" by taxes\",$if($eq($mode,3),\" by trade\",$if($eq($mode,5),\" by stealing\",$if($eq($mode,6),\" by magic\",$if($eq($mode,7),\" by pillaging\",\"\")))))).\"" msgstr "\"$unit($unit) in $region($region) earns $int($amount)$if($eq($wanted,$amount),\"\",\" of $int($wanted)\") silver.\""
msgid "researchherb" msgid "researchherb"
msgstr "\"$unit($unit) discovers that $localize($amount) $resource($herb,0) grow in $region($region).\"" msgstr "\"$unit($unit) discovers that $localize($amount) $resource($herb,0) grow in $region($region).\""
@ -2115,7 +2109,7 @@ msgid "deathcloud_effect"
msgstr "\"$unit($mage) summons a poison elemental in $region($region).\"" msgstr "\"$unit($mage) summons a poison elemental in $region($region).\""
msgid "nr_population" msgid "nr_population"
msgstr "\"Your faction has $int($population) people in $int($units) of $int($limit) possible units.\"" msgstr "\"Your faction has $int($population) $if($eq($population,1), \"person\", \"persons\") in $int($units) of $int($limit) possible units.\""
msgid "curseinfo::shipdisorientation" msgid "curseinfo::shipdisorientation"
msgstr "This ship has lost its path. ($int36($id))" msgstr "This ship has lost its path. ($int36($id))"
@ -2223,7 +2217,7 @@ msgid "curseinfo::healingzone"
msgstr "Healing in this region is affected by magic. ($int36($id))" msgstr "Healing in this region is affected by magic. ($int36($id))"
msgid "income_entertainment_reduced" msgid "income_entertainment_reduced"
msgstr "\"In $region($region), $unit($unit) earns only $int($amount) instead of$if($eq($wanted,$amount),\"\",\" of$if($eq($wanted,$amount),\"\",\" of $int($wanted)\") \") with entertainment.\"" msgstr "\"In $region($region), $unit($unit) earns only $int($amount) instead of$if($eq($wanted,$amount),\"\",\" of$if($eq($wanted,$amount),\"\",\" of $int($wanted)\") \") from entertainment.\""
msgid "errusingpotion" msgid "errusingpotion"
msgstr "\"$unit($unit): '$order($command)' - The unit already uses $resource($using,0).\"" msgstr "\"$unit($unit): '$order($command)' - The unit already uses $resource($using,0).\""
@ -2555,9 +2549,6 @@ msgstr "\"$unit($unit) in $region($region): '$order($command)' - You need at lea
msgid "error177" msgid "error177"
msgstr "\"$unit($unit) in $region($region): '$order($command)' - The familiar cannot cast this spell.\"" msgstr "\"$unit($unit) in $region($region): '$order($command)' - The familiar cannot cast this spell.\""
msgid "curseinfo::godcurseocean"
msgstr "\"This region was cursed by the gods. The sea is a foul cesspool, noxious gases rise from the deep, undead seamonsters attack all ships. Noone can live here for long. ($int36($id))\""
msgid "curseinfo::sparkle_4" msgid "curseinfo::sparkle_4"
msgstr "\"A circle of shimmering lights surrounds $unit($unit). ($int36($id))\"" msgstr "\"A circle of shimmering lights surrounds $unit($unit). ($int36($id))\""

View File

@ -2331,10 +2331,6 @@ msgstr "Seelenfrieden"
msgid "list_and" msgid "list_and"
msgstr " und " msgstr " und "
msgctxt "spell"
msgid "godcursezone"
msgstr "Fluch der Götter"
msgid "sptype_postcombat" msgid "sptype_postcombat"
msgstr "Postkampfzauber" msgstr "Postkampfzauber"

View File

@ -1976,10 +1976,6 @@ msgstr " and "
msgid "h18_p" msgid "h18_p"
msgstr "ice begonias" msgstr "ice begonias"
msgctxt "spell"
msgid "godcursezone"
msgstr "Curse of the Gods"
msgid "sptype_postcombat" msgid "sptype_postcombat"
msgstr "post-combat spell" msgstr "post-combat spell"

View File

@ -130,8 +130,9 @@ function process(rules, orders)
end end
turn_begin() turn_begin()
-- create orders for monsters:
-- run the turn: plan_monsters()
-- read orders for players:
if eressea.read_orders(orders) ~= 0 then if eressea.read_orders(orders) ~= 0 then
print("could not read " .. orders) print("could not read " .. orders)
return -1 return -1
@ -140,8 +141,9 @@ function process(rules, orders)
if nmr_check(config.maxnmrs or 80)~=0 then if nmr_check(config.maxnmrs or 80)~=0 then
return -1 return -1
end end
plan_monsters()
callbacks(rules, 'init') callbacks(rules, 'init')
-- run the turn:
turn_process() turn_process()
callbacks(rules, 'update') callbacks(rules, 'update')
turn_end() -- ageing, etc. turn_end() -- ageing, etc.

View File

@ -1,3 +1,6 @@
require 'tests.e2.trees'
require 'tests.e2.allies'
require 'tests.e2.quit'
require 'tests.e2.movement' require 'tests.e2.movement'
require 'tests.e2.carts' require 'tests.e2.carts'
require 'tests.e2.quit' require 'tests.e2.quit'

134
scripts/tests/e2/trees.lua Normal file
View File

@ -0,0 +1,134 @@
require "lunit"
module("tests.e2.trees", package.seeall, lunit.testcase )
function setup()
eressea.game.reset()
eressea.settings.set("rules.food.flags", "4") -- food is free
eressea.settings.set("rules.treeseeds.chance", "0.0") -- trees make no seeds
eressea.settings.set("rules.grow.formula", "0") -- no tree or seed growth
eressea.settings.set("NewbieImmunity", "0")
end
function test_no_growth()
eressea.settings.set("rules.grow.formula", "2") -- E2 growth rules
set_turn(204)
assert_equal('spring', get_season())
local r = region.create(0, 0, 'plain')
r:set_resource('seed', 0)
r:set_resource('sapling', 0)
r:set_resource('tree', 0)
process_orders()
assert_equal(0, r:get_resource('seed'))
assert_equal(0, r:get_resource('sapling'))
assert_equal(0, r:get_resource('tree'))
end
function test_spring_growth()
eressea.settings.set("rules.grow.formula", "2") -- E2 growth rules
set_turn(204)
assert_equal('spring', get_season())
local r = region.create(0, 0, 'plain')
r:set_resource('seed', 6)
r:set_resource('sapling', 17)
r:set_resource('tree', 0)
process_orders()
assert_equal(5, r:get_resource('seed'))
assert_equal(16, r:get_resource('sapling'))
assert_equal(2, r:get_resource('tree'))
end
-- hebalism < T6 cannot plant
function test_plant_fail()
set_turn(184)
assert_equal('summer', get_season())
local f = faction.create('goblin')
local r = region.create(0, 0, 'plain')
r:set_resource('seed', 0)
r:set_resource('sapling', 0)
r:set_resource('tree', 0)
local u = unit.create(f, r)
u:set_skill('herbalism', 5)
u:add_item('seed', 40)
u:add_order("PFLANZE 20 Samen")
process_orders()
assert_equal(0, r:get_resource('seed'))
assert_equal(0, r:get_resource('sapling'))
assert_equal(0, r:get_resource('tree'))
assert_equal(40, u:get_item('seed'))
end
-- T6+ herbalism allows planting seeds at 1:1 rates
function test_plant_summer()
set_turn(184)
assert_equal('summer', get_season())
local f = faction.create('goblin')
local r = region.create(0, 0, 'plain')
r:set_resource('seed', 0)
r:set_resource('sapling', 0)
r:set_resource('tree', 0)
local u = unit.create(f, r)
u:set_skill('herbalism', 20)
u:add_item('seed', 40)
u:add_order("PFLANZE 20 Samen")
process_orders()
assert_equal(20, r:get_resource('seed'))
assert_equal(0, r:get_resource('sapling'))
assert_equal(0, r:get_resource('tree'))
assert_equal(20, u:get_item('seed'))
end
-- in spring, herbalism >= T12 plants saplings at 10:1 rate
function test_plant_spring_saplings()
set_turn(203)
assert_equal('spring', get_season())
local f = faction.create('goblin')
local r = region.create(0, 0, 'plain')
local u = unit.create(f, r)
r:set_resource('seed', 0)
r:set_resource('sapling', 0)
r:set_resource('tree', 0)
assert_equal('spring', get_season())
process_orders() -- to initialize at_germs
assert_equal(0, r:get_resource('sapling'))
assert_equal(0, r:get_resource('seed'))
assert_equal(0, r:get_resource('tree'))
assert_equal('spring', get_season())
u:set_skill('herbalism', 12)
u:add_item('seed', 20)
u:add_order("PFLANZE 20 Samen") -- limited by herbalism
process_orders()
assert_equal(1, r:get_resource('sapling'))
assert_equal(2, r:get_resource('seed'))
assert_equal(0, r:get_resource('tree'))
assert_equal(8, u:get_item('seed'))
end
-- herbalism < T12 means we are still planting seeds at 1:1
function test_plant_spring_seeds()
set_turn(204)
local f = faction.create('goblin')
local r = region.create(0, 0, 'plain')
local u = unit.create(f, r)
r:set_resource('seed', 0)
r:set_resource('sapling', 0)
r:set_resource('tree', 0)
assert_equal('spring', get_season())
process_orders() -- to initialize at_germs
assert_equal(0, r:get_resource('sapling'))
assert_equal(0, r:get_resource('seed'))
assert_equal(0, r:get_resource('tree'))
assert_equal('spring', get_season())
u:set_skill('herbalism', 10)
u:add_item('seed', 40)
u:add_order("PFLANZE 10 Samen")
process_orders()
assert_equal(0, r:get_resource('sapling'))
assert_equal(10, r:get_resource('seed'))
assert_equal(0, r:get_resource('tree'))
assert_equal(30, u:get_item('seed'))
end

View File

@ -260,7 +260,7 @@ static int tolua_dice_rand(lua_State * L)
static int tolua_get_season(lua_State * L) static int tolua_get_season(lua_State * L)
{ {
int turn_no = (int)tolua_tonumber(L, 1, 0); int turn_no = (int)tolua_tonumber(L, 1, turn);
season_t season = calendar_season(turn_no); season_t season = calendar_season(turn_no);
tolua_pushstring(L, seasonnames[season]); tolua_pushstring(L, seasonnames[season]);
return 1; return 1;

View File

@ -1495,7 +1495,7 @@ static bool sell(unit * u, econ_request ** sellorders, struct order *ord)
bool unlimited = true; bool unlimited = true;
const item_type *itype; const item_type *itype;
const luxury_type *ltype; const luxury_type *ltype;
int n, i; int n, k;
region *r = u->region; region *r = u->region;
const char *s; const char *s;
keyword_t kwd; keyword_t kwd;
@ -1546,8 +1546,9 @@ static bool sell(unit * u, econ_request ** sellorders, struct order *ord)
} }
/* Ein Haendler kann nur 10 Gueter pro Talentpunkt verkaufen. */ /* Ein Haendler kann nur 10 Gueter pro Talentpunkt verkaufen. */
i = u->number * 10 * effskill(u, SK_TRADE, NULL); /* Ein Haendler kann nur 10 Gueter pro Talentpunkt handeln. */
if (n > i) n = i; k = u->number * 10 * effskill(u, SK_TRADE, NULL);
if (n > k) n = k;
if (!n) { if (!n) {
cmistake(u, ord, 54, MSG_COMMERCE); cmistake(u, ord, 54, MSG_COMMERCE);
@ -1563,7 +1564,7 @@ static bool sell(unit * u, econ_request ** sellorders, struct order *ord)
else { else {
attrib *a; attrib *a;
econ_request *o; econ_request *o;
int k, available; int available;
if (!r->land || !r_demand(r, ltype)) { if (!r->land || !r_demand(r, ltype)) {
cmistake(u, ord, 263, MSG_COMMERCE); cmistake(u, ord, 263, MSG_COMMERCE);
@ -1594,9 +1595,6 @@ static bool sell(unit * u, econ_request ** sellorders, struct order *ord)
* produktion, wo fuer jedes produkt einzeln eine obere limite * produktion, wo fuer jedes produkt einzeln eine obere limite
* existiert, so dass man arrays von orders machen kann. */ * existiert, so dass man arrays von orders machen kann. */
/* Ein Haendler kann nur 10 Gueter pro Talentpunkt handeln. */
k = u->number * 10 * effskill(u, SK_TRADE, NULL);
/* hat der Haendler bereits gehandelt, muss die Menge der bereits /* hat der Haendler bereits gehandelt, muss die Menge der bereits
* verkauften/gekauften Gueter abgezogen werden */ * verkauften/gekauften Gueter abgezogen werden */
a = a_find(u->attribs, &at_trades); a = a_find(u->attribs, &at_trades);
@ -1682,84 +1680,41 @@ static void plant(unit * u, int raw)
u, r, planted, itype->rtype)); u, r, planted, itype->rtype));
} }
static void planttrees(unit * u, int raw) static void planttrees(region * r, int type, int n)
{ {
int n, i, skill, planted = 0; if (n > 0) {
const resource_type *rtype; rsettrees(r, type, rtrees(r, type) + n);
region * r = u->region;
if (!fval(r->terrain, LAND_REGION)) {
return;
} }
/* Mallornbaeume kann man nur in Mallornregionen zuechten */
rtype = get_resourcetype(fval(r, RF_MALLORN) ? R_MALLORN_SEED : R_SEED);
/* Skill pruefen */
skill = effskill(u, SK_HERBALISM, NULL);
if (skill < 6) {
ADDMSG(&u->faction->msgs,
msg_feedback(u, u->thisorder, "plant_skills",
"skill minskill product", SK_HERBALISM, 6, rtype, 1));
return;
}
if (fval(r, RF_MALLORN) && skill < 7) {
ADDMSG(&u->faction->msgs,
msg_feedback(u, u->thisorder, "plant_skills",
"skill minskill product", SK_HERBALISM, 7, rtype, 1));
return;
}
/* wenn eine Anzahl angegeben wurde, nur soviel verbrauchen */
if (raw > skill * u->number) raw = skill * u->number;
n = get_pooled(u, rtype, GET_DEFAULT, raw);
if (n == 0) {
ADDMSG(&u->faction->msgs,
msg_feedback(u, u->thisorder, "resource_missing", "missing", rtype));
return;
}
if (n > raw) n = raw;
/* Fuer jeden Samen Talent*10% Erfolgschance. */
for (i = n; i > 0; i--) {
if (rng_int() % 10 < skill)
planted++;
}
rsettrees(r, 0, rtrees(r, 0) + planted);
/* Alles ok. Abziehen. */
produceexp(u, SK_HERBALISM, u->number);
use_pooled(u, rtype, GET_DEFAULT, n);
ADDMSG(&u->faction->msgs, msg_message("plant",
"unit region amount herb", u, r, planted, rtype));
} }
/* zuechte baeume */ /* zuechte baeume */
static void breedtrees(unit * u, int raw) static void breedtrees(unit * u, int raw)
{ {
int n, i, skill, planted = 0; int n, i, skill;
const resource_type *rtype; const resource_type *rtype;
season_t current_season = calendar_season(turn); season_t current_season = calendar_season(turn);
region *r = u->region; region *r = u->region;
int minskill = 6;
/* Baeume zuechten geht nur im Fruehling */
if (current_season != SEASON_SPRING) {
planttrees(u, raw);
return;
}
if (!fval(r->terrain, LAND_REGION)) { if (!fval(r->terrain, LAND_REGION)) {
return; return;
} }
/* Mallornbaeume kann man nur in Mallornregionen zuechten */ /* Mallornbaeume kann man nur in Mallornregionen zuechten */
rtype = get_resourcetype(fval(r, RF_MALLORN) ? R_MALLORN_SEED : R_SEED); if (fval(r, RF_MALLORN)) {
++minskill;
rtype = get_resourcetype(R_MALLORN_SEED);
}
else {
rtype = get_resourcetype(R_SEED);
}
/* Skill pruefen */ /* Skill pruefen */
skill = effskill(u, SK_HERBALISM, NULL); skill = effskill(u, SK_HERBALISM, NULL);
if (skill < 12) { if (skill < minskill) {
planttrees(u, raw); ADDMSG(&u->faction->msgs,
msg_feedback(u, u->thisorder, "plant_skills",
"skill minskill product", SK_HERBALISM, 6, rtype, 1));
return; return;
} }
@ -1775,19 +1730,21 @@ static void breedtrees(unit * u, int raw)
} }
if (n > raw) n = raw; if (n > raw) n = raw;
/* Fuer jeden Samen Talent*5% Erfolgschance. */ if (skill >= 12 && current_season == SEASON_SPRING) {
for (i = n; i > 0; i--) { // Plant saplings for every 10 seeds
if (rng_int() % 100 < skill * 5) planttrees(r, 0, n % 10);
planted++; planttrees(r, 1, n / 10);
}
else {
planttrees(r, 0, n);
} }
rsettrees(r, 1, rtrees(r, 1) + planted);
/* Alles ok. Abziehen. */ /* Alles ok. Samen abziehen. */
produceexp(u, SK_HERBALISM, u->number); produceexp(u, SK_HERBALISM, u->number);
use_pooled(u, rtype, GET_DEFAULT, n); use_pooled(u, rtype, GET_DEFAULT, n);
ADDMSG(&u->faction->msgs, msg_message("plant", ADDMSG(&u->faction->msgs, msg_message("plant",
"unit region amount herb", u, r, planted, rtype)); "unit region amount herb", u, r, n, rtype));
} }
/* zuechte pferde */ /* zuechte pferde */

View File

@ -209,7 +209,7 @@ static void setup_terrains(CuTest *tc) {
static region *setup_trade_region(CuTest *tc, const struct terrain_type *terrain) { static region *setup_trade_region(CuTest *tc, const struct terrain_type *terrain) {
region *r; region *r;
item_type *it_luxury; item_type *it_luxury;
struct locale * lang = default_locale; struct locale * lang = test_create_locale();
new_luxurytype(it_luxury = test_create_itemtype("balm"), 5); new_luxurytype(it_luxury = test_create_itemtype("balm"), 5);
locale_setstring(lang, it_luxury->rtype->_name, it_luxury->rtype->_name); locale_setstring(lang, it_luxury->rtype->_name, it_luxury->rtype->_name);
@ -233,6 +233,36 @@ static unit *setup_trade_unit(CuTest *tc, region *r, const struct race *rc) {
return u; return u;
} }
static void test_trade_limits(CuTest *tc) {
region *r;
unit *u;
building *b;
const item_type *it_jewel, *it_balm;
test_setup();
setup_production();
setup_terrains(tc);
init_terrains();
r = setup_trade_region(tc, NULL);
b = test_create_building(r, test_create_buildingtype("castle"));
b->size = 2;
rsetpeasants(r, TRADE_FRACTION * 20);
it_jewel = it_find("jewel");
u = test_create_unit(test_create_faction(NULL), r);
set_level(u, SK_TRADE, 1);
i_change(&u->items, it_find("money"), 500);
unit_addorder(u, create_order(K_BUY, u->faction->locale, "5 %s",
LOC(u->faction->locale, resourcename(it_jewel->rtype, 0))));
it_balm = it_find("balm");
i_change(&u->items, it_balm, 10);
unit_addorder(u, create_order(K_SELL, u->faction->locale, "10 %s",
LOC(u->faction->locale, resourcename(it_balm->rtype, 0))));
produce(r);
CuAssertIntEquals(tc, 5, i_get(u->items, it_jewel));
CuAssertIntEquals(tc, 5, i_get(u->items, it_balm));
test_teardown();
}
static void test_trade_needs_castle(CuTest *tc) { static void test_trade_needs_castle(CuTest *tc) {
/* Handeln ist nur in Regionen mit Burgen möglich. */ /* Handeln ist nur in Regionen mit Burgen möglich. */
race *rc; race *rc;
@ -837,6 +867,7 @@ CuSuite *get_economy_suite(void)
SUITE_ADD_TEST(suite, test_heroes_dont_recruit); SUITE_ADD_TEST(suite, test_heroes_dont_recruit);
SUITE_ADD_TEST(suite, test_tax_cmd); SUITE_ADD_TEST(suite, test_tax_cmd);
SUITE_ADD_TEST(suite, test_buy_cmd); SUITE_ADD_TEST(suite, test_buy_cmd);
SUITE_ADD_TEST(suite, test_trade_limits);
SUITE_ADD_TEST(suite, test_trade_needs_castle); SUITE_ADD_TEST(suite, test_trade_needs_castle);
SUITE_ADD_TEST(suite, test_trade_insect); SUITE_ADD_TEST(suite, test_trade_insect);
SUITE_ADD_TEST(suite, test_maintain_buildings); SUITE_ADD_TEST(suite, test_maintain_buildings);

View File

@ -47,7 +47,7 @@
static int g_quit; static int g_quit;
int force_color = 0; int force_color = 0;
newfaction * new_players = 0; newfaction * new_players = NULL;
state *current_state = NULL; state *current_state = NULL;

View File

@ -746,10 +746,6 @@ default_wage(const region * r, const faction * f, const race * rc, int in_turn)
variant vm; variant vm;
/* Godcurse: Income -10 */ /* Godcurse: Income -10 */
c = get_curse(r->attribs, &ct_godcursezone);
if (c && curse_active(c)) {
wage = (wage < 10) ? 0 : (wage - 10);
}
vm = frac_make(wage, 1); vm = frac_make(wage, 1);
/* Bei einer Duerre verdient man nur noch ein Viertel */ /* Bei einer Duerre verdient man nur noch ein Viertel */

View File

@ -129,6 +129,7 @@ static int read_ccompat(const char *cursename, struct storage *store)
} *seek, old_curses[] = { } *seek, old_curses[] = {
{ "disorientationzone", "" }, { "disorientationzone", "" },
{ "shipdisorientation", "" }, { "shipdisorientation", "" },
{ "godcursezone", "" },
{ NULL, NULL } { NULL, NULL }
}; };
for (seek = old_curses; seek->name; ++seek) { for (seek = old_curses; seek->name; ++seek) {

View File

@ -463,10 +463,7 @@ static void horses(region * r)
maxhorses = region_maxworkers(r) / 10; maxhorses = region_maxworkers(r) / 10;
horses = rhorses(r); horses = rhorses(r);
if (horses > 0) { if (horses > 0) {
if (is_cursed(r->attribs, &ct_godcursezone)) { if (maxhorses > 0) {
rsethorses(r, (int)(horses * 0.9));
}
else if (maxhorses > 0) {
double growth = double growth =
(RESOURCE_QUANTITY * (HORSEGROWTH * 200.0 * ((double)maxhorses - (RESOURCE_QUANTITY * (HORSEGROWTH * 200.0 * ((double)maxhorses -
horses))) / (double)maxhorses; horses))) / (double)maxhorses;
@ -606,9 +603,9 @@ growing_trees(region * r, const season_t current_season, const season_t last_wee
{ {
int grownup_trees, i, seeds, sprout; int grownup_trees, i, seeds, sprout;
attrib *a; attrib *a;
double seedchance = config_get_flt("rules.treeseeds.chance", 0.01F) * RESOURCE_QUANTITY;
if (current_season == SEASON_SUMMER || current_season == SEASON_AUTUMN) { if (current_season == SEASON_SUMMER || current_season == SEASON_AUTUMN) {
double seedchance = 0.01F * RESOURCE_QUANTITY;
int mp, elves = count_race(r, get_race(RC_ELF)); int mp, elves = count_race(r, get_race(RC_ELF));
direction_t d; direction_t d;
@ -625,12 +622,6 @@ growing_trees(region * r, const season_t current_season, const season_t last_wee
a_removeall(&r->attribs, &at_germs); a_removeall(&r->attribs, &at_germs);
} }
if (is_cursed(r->attribs, &ct_godcursezone)) {
rsettrees(r, 1, (int)(rtrees(r, 1) * 0.9));
rsettrees(r, 2, (int)(rtrees(r, 2) * 0.9));
return;
}
mp = max_production(r); mp = max_production(r);
if (mp <= 0) if (mp <= 0)
return; return;
@ -662,32 +653,28 @@ growing_trees(region * r, const season_t current_season, const season_t last_wee
/* Gesamtzahl der Samen: /* Gesamtzahl der Samen:
* bis zu 6% (FORESTGROWTH*3) der Baeume samen in die Nachbarregionen */ * bis zu 6% (FORESTGROWTH*3) der Baeume samen in die Nachbarregionen */
seeds = (rtrees(r, 2) * FORESTGROWTH * 3) / 1000000; if (seedchance > 0) {
for (d = 0; d != MAXDIRECTIONS; ++d) { seeds = (rtrees(r, 2) * FORESTGROWTH * 3) / 1000000;
region *r2 = rconnect(r, d); for (d = 0; d != MAXDIRECTIONS; ++d) {
if (r2 && fval(r2->terrain, LAND_REGION) && r2->terrain->size) { region *r2 = rconnect(r, d);
/* Eine Landregion, wir versuchen Samen zu verteilen: if (r2 && fval(r2->terrain, LAND_REGION) && r2->terrain->size) {
* Die Chance, das Samen ein Stueck Boden finden, in dem sie /* Eine Landregion, wir versuchen Samen zu verteilen:
* keimen koennen, haengt von der Bewuchsdichte und der * Die Chance, das Samen ein Stueck Boden finden, in dem sie
* verfuegbaren Flaeche ab. In Gletschern gibt es weniger * keimen koennen, haengt von der Bewuchsdichte und der
* Moeglichkeiten als in Ebenen. */ * verfuegbaren Flaeche ab. In Gletschern gibt es weniger
sprout = 0; * Moeglichkeiten als in Ebenen. */
seedchance = (1000.0 * region_maxworkers(r2)) / r2->terrain->size; sprout = 0;
for (i = 0; i < seeds / MAXDIRECTIONS; i++) { seedchance = (1000.0 * region_maxworkers(r2)) / r2->terrain->size;
if (rng_int() % 10000 < seedchance) for (i = 0; i < seeds / MAXDIRECTIONS; i++) {
sprout++; if (rng_int() % 10000 < seedchance)
sprout++;
}
rsettrees(r2, 0, rtrees(r2, 0) + sprout);
} }
rsettrees(r2, 0, rtrees(r2, 0) + sprout);
} }
} }
} }
else if (current_season == SEASON_SPRING) { else if (current_season == SEASON_SPRING) {
int growth;
if (is_cursed(r->attribs, &ct_godcursezone))
return;
/* in at_germs merken uns die Zahl der Samen und Sproesslinge, die /* in at_germs merken uns die Zahl der Samen und Sproesslinge, die
* dieses Jahr aelter werden duerfen, damit nicht ein Same im selben * dieses Jahr aelter werden duerfen, damit nicht ein Same im selben
* Zyklus zum Baum werden kann */ * Zyklus zum Baum werden kann */
@ -697,49 +684,28 @@ growing_trees(region * r, const season_t current_season, const season_t last_wee
a->data.sa[0] = cap_short(rtrees(r, 0)); a->data.sa[0] = cap_short(rtrees(r, 0));
a->data.sa[1] = cap_short(rtrees(r, 1)); a->data.sa[1] = cap_short(rtrees(r, 1));
} }
/* wir haben 6 Wochen zum wachsen, jeder Same/Spross hat 18% Chance
* zu wachsen, damit sollten nach 5-6 Wochen alle gewachsen sein */
growth = 1800;
/* Samenwachstum */
/* Raubbau abfangen, es duerfen nie mehr Samen wachsen, als aktuell
* in der Region sind */
seeds = rtrees(r, 0);
if (seeds > a->data.sa[0]) seeds = a->data.sa[0];
sprout = 0;
for (i = 0; i < seeds; i++) {
if (rng_int() % 10000 < growth)
sprout++;
}
/* aus dem Samenpool dieses Jahres abziehen */
a->data.sa[0] = (short)(seeds - sprout);
/* aus dem gesamt Samenpool abziehen */
rsettrees(r, 0, rtrees(r, 0) - sprout);
/* zu den Sproesslinge hinzufuegen */
rsettrees(r, 1, rtrees(r, 1) + sprout);
/* Baumwachstum */ /* Baumwachstum */
/* hier gehen wir davon aus, das Jungbaeume nicht ohne weiteres aus
* der Region entfernt werden koennen, da Jungbaeume in der gleichen
* Runde nachwachsen, wir also nicht mehr zwischen diesjaehrigen und
* 'alten' Jungbaeumen unterscheiden koennten */
sprout = rtrees(r, 1); sprout = rtrees(r, 1);
if (sprout > a->data.sa[1]) sprout = a->data.sa[1]; if (sprout > a->data.sa[1]) sprout = a->data.sa[1];
grownup_trees = 0; grownup_trees = sprout / 6;
for (i = 0; i < sprout; i++) {
if (rng_int() % 10000 < growth)
grownup_trees++;
}
/* aus dem Sproesslingepool dieses Jahres abziehen */ /* aus dem Sproesslingepool dieses Jahres abziehen */
a->data.sa[1] = (short)(sprout - grownup_trees); a->data.sa[1] = (short)(sprout - grownup_trees);
/* aus dem gesamt Sproesslingepool abziehen */ /* aus dem gesamt Sproesslingepool abziehen */
rsettrees(r, 1, rtrees(r, 1) - grownup_trees); rsettrees(r, 1, rtrees(r, 1) - grownup_trees);
/* zu den Baeumen hinzufuegen */ /* zu den Baeumen hinzufuegen */
rsettrees(r, 2, rtrees(r, 2) + grownup_trees); rsettrees(r, 2, rtrees(r, 2) + grownup_trees);
/* Samenwachstum */
seeds = rtrees(r, 0);
if (seeds > a->data.sa[0]) seeds = a->data.sa[0];
sprout = seeds / 6;
/* aus dem Samenpool dieses Jahres abziehen */
a->data.sa[0] = (short)(seeds - sprout);
/* aus dem gesamt Samenpool abziehen */
rsettrees(r, 0, rtrees(r, 0) - sprout);
/* zu den Sproesslinge hinzufuegen */
rsettrees(r, 1, rtrees(r, 1) + sprout);
} }
} }

View File

@ -87,17 +87,17 @@ newfaction *read_newfactions(const char *filename)
if (fgets(buf, sizeof(buf), F) == NULL) if (fgets(buf, sizeof(buf), F) == NULL)
break; break;
if (buf[0] == '#') {
continue;
}
email[0] = '\0'; email[0] = '\0';
password[0] = '\0'; password[0] = '\0';
if (sscanf(buf, "%54s %19s %7s %15s %4d", email, race, lang, if (sscanf(buf, "%54s %19s %7s %15s %4d", email, race, lang,
password, &alliance) < 3) { password, &alliance) < 3) {
break; break;
} }
if (email[0] == '#') {
continue;
}
if (email[0] == '\0') { if (email[0] == '\0') {
break; break;
} }

View File

@ -214,10 +214,10 @@ int monster_attacks(unit * monster, bool rich_only)
return result; return result;
} }
static order *get_money_for_dragon(region * r, unit * udragon, int wanted) static order *get_money_for_dragon(region * r, unit * u, int wanted)
{ {
int money; int money;
bool attacks = attack_chance > 0.0; bool attacks = (attack_chance > 0.0) && armedmen(u, false);
/* falls genug geld in der region ist, treiben wir steuern ein. */ /* falls genug geld in der region ist, treiben wir steuern ein. */
if (rmoney(r) >= wanted) { if (rmoney(r) >= wanted) {
@ -231,8 +231,8 @@ static order *get_money_for_dragon(region * r, unit * udragon, int wanted)
/* falls der drache launisch ist, oder das regionssilber knapp, greift er alle an /* falls der drache launisch ist, oder das regionssilber knapp, greift er alle an
* und holt sich Silber von Einheiten, vorausgesetzt er bewacht bereits */ * und holt sich Silber von Einheiten, vorausgesetzt er bewacht bereits */
money = 0; money = 0;
if (attacks && is_guard(udragon)) { if (attacks && is_guard(u)) {
int m = monster_attacks(udragon, true); int m = monster_attacks(u, true);
if (m > 0) money += m; if (m > 0) money += m;
} }
@ -623,11 +623,11 @@ static order *plan_dragon(unit * u)
rc_wyrm = get_race(RC_WYRM); rc_wyrm = get_race(RC_WYRM);
} }
if (ta == NULL) { if (!move && ta == NULL) {
move |= (rpeasants(r) == 0); /* when no peasants, move */ move = (rpeasants(r) == 0); /* when no peasants, move */
move |= (rmoney(r) == 0); /* when no money, move */ move = move || (rmoney(r) == 0); /* when no money, move */
} }
move |= chance(0.04); /* 4% chance to change your mind */ move = move || chance(0.04); /* 4% chance to change your mind */
if (rc == rc_wyrm && !move) { if (rc == rc_wyrm && !move) {
unit *u2; unit *u2;
@ -739,6 +739,7 @@ void plan_monsters(faction * f)
attrib *ta; attrib *ta;
order *long_order = NULL; order *long_order = NULL;
bool can_move = true; bool can_move = true;
bool guarding;
/* Ab hier nur noch Befehle fuer NPC-Einheiten. */ /* Ab hier nur noch Befehle fuer NPC-Einheiten. */
if (u->faction != f || u->number <= 0) { if (u->faction != f || u->number <= 0) {
@ -763,8 +764,9 @@ void plan_monsters(faction * f)
/* Befehle muessen jede Runde neu gegeben werden: */ /* Befehle muessen jede Runde neu gegeben werden: */
free_orders(&u->orders); free_orders(&u->orders);
/* All monsters guard the region: */ guarding = is_guard(u);
if (u->status < ST_FLEE && !monster_is_waiting(u) && r->land) { /* All monsters want to guard the region: */
if (!guarding && u->status < ST_FLEE && !monster_is_waiting(u) && r->land) {
unit_addorder(u, create_order(K_GUARD, u->faction->locale, NULL)); unit_addorder(u, create_order(K_GUARD, u->faction->locale, NULL));
} }
@ -790,7 +792,7 @@ void plan_monsters(faction * f)
else else
a_remove(&u->attribs, ta); a_remove(&u->attribs, ta);
} }
else if (!r->land || is_guard(u)) { else if (!r->land || guarding) {
if (chance(attack_chance)) { if (chance(attack_chance)) {
int m = monster_attacks(u, false); int m = monster_attacks(u, false);
if (m >= 0) { if (m >= 0) {

View File

@ -380,44 +380,6 @@ static void create_icebergs(void)
} }
} }
static void godcurse(void)
{
region *r;
for (r = regions; r; r = r->next) {
if (is_cursed(r->attribs, &ct_godcursezone)) {
unit *u;
for (u = r->units; u; u = u->next) {
skill *sv = u->skills;
while (sv != u->skills + u->skill_size) {
int weeks = 1 + rng_int() % 3;
reduce_skill(u, sv, weeks);
++sv;
}
}
if (fval(r->terrain, SEA_REGION)) {
ship *sh;
for (sh = r->ships; sh;) {
ship *shn = sh->next;
double dmg = config_get_flt("rules.ship.damage.godcurse", 0.1);
damage_ship(sh, dmg);
if (sh->damage >= sh->size * DAMAGE_SCALE) {
unit *uo = ship_owner(sh);
if (uo) {
ADDMSG(&uo->faction->msgs,
msg_message("godcurse_destroy_ship", "ship", sh));
}
sink_ship(sh);
remove_ship(&sh->region->ships, sh);
}
sh = shn;
}
}
}
}
}
/** handles the "orcish" curse that makes units grow like old orks /** handles the "orcish" curse that makes units grow like old orks
* TODO: 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() * but it's now being called by randomevents()
@ -535,7 +497,6 @@ void randomevents(void)
for (r = regions; r; r = r->next) { for (r = regions; r; r = r->next) {
drown(r); drown(r);
} }
godcurse();
orc_growth(); orc_growth();
demon_skillchanges(); demon_skillchanges();
if (volcano_module()) { if (volcano_module()) {

View File

@ -56,7 +56,7 @@ int sp_flying_ship(castorder * co)
if (pa->param[0]->flag == TARGET_NOTFOUND) if (pa->param[0]->flag == TARGET_NOTFOUND)
return 0; return 0;
sh = pa->param[0]->data.sh; sh = pa->param[0]->data.sh;
if (sh->type->construction->maxsize > 50) { if (sh->number > 1 || sh->type->construction->maxsize > 50) {
ADDMSG(&caster->faction->msgs, msg_feedback(caster, co->order, ADDMSG(&caster->faction->msgs, msg_feedback(caster, co->order,
"error_flying_ship_too_big", "ship", sh)); "error_flying_ship_too_big", "ship", sh));
return 0; return 0;

View File

@ -22,30 +22,6 @@
#include <stdlib.h> #include <stdlib.h>
#include <assert.h> #include <assert.h>
/*
* godcursezone
*/
static message *cinfo_cursed_by_the_gods(const void *obj, objtype_t typ,
const curse * c, int self)
{
region *r = (region *)obj;
UNUSED_ARG(typ);
UNUSED_ARG(self);
assert(typ == TYP_REGION);
if (r->terrain->flags & SEA_REGION) {
return msg_message("curseinfo::godcurseocean", "id", c->no);
}
return msg_message("curseinfo::godcurse", "id", c->no);
}
const struct curse_type ct_godcursezone = {
"godcursezone",
CURSETYP_NORM, CURSE_IMMUNE, (NO_MERGE),
cinfo_cursed_by_the_gods,
};
/* --------------------------------------------------------------------- */ /* --------------------------------------------------------------------- */
/* /*
* C_GBDREAM * C_GBDREAM
@ -299,7 +275,6 @@ void register_regioncurse(void)
ct_register(&ct_badmagicresistancezone); ct_register(&ct_badmagicresistancezone);
ct_register(&ct_goodmagicresistancezone); ct_register(&ct_goodmagicresistancezone);
ct_register(&ct_riotzone); ct_register(&ct_riotzone);
ct_register(&ct_godcursezone);
ct_register(&ct_holyground); ct_register(&ct_holyground);
ct_register(&ct_healing); ct_register(&ct_healing);
} }

View File

@ -10,7 +10,6 @@ extern "C" {
extern const struct curse_type ct_peacezone; extern const struct curse_type ct_peacezone;
extern const struct curse_type ct_drought; extern const struct curse_type ct_drought;
extern const struct curse_type ct_blessedharvest; extern const struct curse_type ct_blessedharvest;
extern const struct curse_type ct_godcursezone;
extern const struct curse_type ct_gbdream; extern const struct curse_type ct_gbdream;
extern const struct curse_type ct_healing; extern const struct curse_type ct_healing;
extern const struct curse_type ct_antimagiczone; extern const struct curse_type ct_antimagiczone;