forked from github/server
Compare commits
22 Commits
develop
...
2706-maint
Author | SHA1 | Date |
---|---|---|
Enno Rehling | 585969bf98 | |
Enno Rehling | 220045f423 | |
Enno Rehling | c2754687dc | |
Enno Rehling | 43a0368fb4 | |
Enno Rehling | 65c05f37d2 | |
Enno Rehling | d7d3b5d730 | |
Enno Rehling | 912ce0f382 | |
Enno Rehling | 44ac1d5573 | |
Enno Rehling | 7af2735b7f | |
Enno Rehling | 7712dcc0f0 | |
Enno Rehling | b988dd0a7d | |
Enno Rehling | 0165dbf759 | |
Enno Rehling | a016ea9a14 | |
Enno Rehling | 1f1125f9fd | |
Enno Rehling | e61b8ad557 | |
Enno Rehling | 57b5e50db8 | |
Enno Rehling | 7c44ff2241 | |
Enno Rehling | b7aad91ffb | |
Enno Rehling | 85f1207af0 | |
Enno Rehling | c884138351 | |
Enno Rehling | 039d3ecc6b | |
Enno Rehling | 1c8248ee0c |
30
CHANGELOG.md
30
CHANGELOG.md
|
@ -1,12 +1,30 @@
|
|||
# Geplante Aenderungen in zukuenftigen Eressea-Versionen
|
||||
|
||||
Als Anhaltspunkt fuer die Empfaenger der woechentlichen Testauswertungnen
|
||||
will ich versuchen, die Liste meiner Aenderungen seit dem letzten Release
|
||||
zu dokumentieren.
|
||||
# 3.26
|
||||
|
||||
## Version 3.12.0
|
||||
- Akademien, Traenke und Verzauberungen wirken auch bei LERNE AUTO
|
||||
- Das lernen in einer Akademie erhoeht die Lernkosten. Koennen diese
|
||||
nicht bezahlt werden, wird ohne deren Bonus gelernt.
|
||||
- Lehrer muessen nicht mehr in der Akademie stehen, damit ihre Schueler
|
||||
den Bonus bekommen
|
||||
- Rohstoffe koennen jetzt bereits gesehen werden, wenn eine Einheit nur
|
||||
die Haelfte des zum Abbau noetigen Talentes hat (statt bisher
|
||||
Talent-1)
|
||||
- Mauern der Ewigkeit und Störe Astrale Integrität brauchen keine
|
||||
Stufenangabe, ihre Kosten sind nicht variabel [2651]
|
||||
|
||||
# 3.25
|
||||
|
||||
- Ab sofort ist es nicht mehr erlaubt, Befehle mit weniger als 3
|
||||
Zeichen abzukürzen.
|
||||
- Leuchttürme entdecken Seeschlangen und Drachen auf dem Ozean [2688]
|
||||
- Magieresistenz von Insekten und Goblins repariert [2685]
|
||||
- Getarnte Einheiten können wieder Eisen abbauen [2679]
|
||||
- Gestaltwandlung kann nur einmal auf die selbe Einheit wirken [2680]
|
||||
- Handel benötigt eine Burg mit Mindestgröße 2 [2678]
|
||||
- Geschützte Leerzeichen in Befehlen werden ignoriert [2670]
|
||||
|
||||
# 3.12
|
||||
|
||||
- [other] optimierte Berechnung der Sichtbarkeit von Leuchttuermen
|
||||
- [bug] Einheitenlimit bei GIB PERSON beachten
|
||||
- [bug] Einheitenlimit bei ALLIANCE JOIN beachten
|
||||
- [rule] Einheiten- und Personenzahl im Report beinhaltet *alle* Einheiten der Partei.
|
||||
|
|
|
@ -1,63 +1,64 @@
|
|||
{
|
||||
"include": [
|
||||
"config://conf/keywords.json",
|
||||
"config://conf/calendar.json",
|
||||
"config://conf/prefixes.json",
|
||||
"config://conf/e2/locales.json",
|
||||
"config://conf/e2/terrains.json",
|
||||
"config://conf/e2/items.json",
|
||||
"config://res/core/ships.xml",
|
||||
"config://res/core/common/buildings.xml",
|
||||
"config://res/eressea/buildings.xml",
|
||||
"config://res/buildings/castle.xml",
|
||||
"config://res/eressea/races.xml",
|
||||
"config://res/eressea/artrewards.xml",
|
||||
"config://res/eressea/spells.xml",
|
||||
"config://res/eressea/spellbooks/gray.xml",
|
||||
"config://res/eressea/spellbooks/gwyrrd.xml",
|
||||
"config://res/eressea/spellbooks/draig.xml",
|
||||
"config://res/eressea/spellbooks/illaun.xml",
|
||||
"config://res/eressea/spellbooks/cerddor.xml",
|
||||
"config://res/eressea/spellbooks/tybied.xml"
|
||||
],
|
||||
"disabled": [
|
||||
"jsreport"
|
||||
],
|
||||
"settings": {
|
||||
"game.name" : "Eressea",
|
||||
"game.mailcmd" : "ERESSEA",
|
||||
"game.id" : 2,
|
||||
"orders.default": "work",
|
||||
"NewbieImmunity": 8,
|
||||
"modules.market": false,
|
||||
"modules.astralspace": true,
|
||||
"modules.wormhole": true,
|
||||
"modules.iceberg": true,
|
||||
"modules.volcano": true,
|
||||
"monsters.spawn.chance": 50,
|
||||
"entertain.base": 0,
|
||||
"entertain.perlevel": 20,
|
||||
"taxing.perlevel": 20,
|
||||
"nmr.timeout": 5,
|
||||
"nmr.removenewbie": false,
|
||||
"GiveRestriction": 3,
|
||||
"hunger.long": false,
|
||||
"hunger.damage": "1d8+6",
|
||||
"init_spells": 0,
|
||||
"game.era": 2,
|
||||
"game.start": 184,
|
||||
"rules.reserve.twophase": true,
|
||||
"rules.give.max_men": -1,
|
||||
"rules.check_overload": false,
|
||||
"rules.limit.faction": 2500,
|
||||
"rules.maxskills.magic": 5,
|
||||
"rules.guard.base_stop_prob": 0.30,
|
||||
"rules.guard.skill_stop_prob": 0.05,
|
||||
"rules.guard.amulet_stop_prob": 0.10,
|
||||
"rules.guard.guard_number_stop_prob": 0.001,
|
||||
"rules.guard.castle_stop_prob": 0.05,
|
||||
"rules.guard.region_type_stop_prob": 0.05,
|
||||
"rules.economy.repopulate_maximum": 500,
|
||||
"rules.lighthouse.unit_capacity": true
|
||||
}
|
||||
"settings": {
|
||||
"game.name": "Eressea",
|
||||
"game.mailcmd": "ERESSEA",
|
||||
"game.id": 2,
|
||||
"orders.default": "work",
|
||||
"NewbieImmunity": 8,
|
||||
"modules.market": false,
|
||||
"modules.astralspace": true,
|
||||
"modules.wormhole": true,
|
||||
"modules.iceberg": true,
|
||||
"modules.volcano": true,
|
||||
"monsters.spawn.chance": 50,
|
||||
"entertain.base": 0,
|
||||
"entertain.perlevel": 20,
|
||||
"taxing.perlevel": 20,
|
||||
"nmr.timeout": 5,
|
||||
"nmr.removenewbie": false,
|
||||
"GiveRestriction": 3,
|
||||
"hunger.long": false,
|
||||
"hunger.damage": "1d8+6",
|
||||
"init_spells": 0,
|
||||
"game.era": 2,
|
||||
"game.start": 184,
|
||||
"rules.reserve.twophase": true,
|
||||
"rules.give.max_men": -1,
|
||||
"rules.check_overload": false,
|
||||
"rules.limit.faction": 2500,
|
||||
"rules.maxskills.magic": 5,
|
||||
"rules.guard.base_stop_prob": 0.30,
|
||||
"rules.guard.skill_stop_prob": 0.05,
|
||||
"rules.guard.amulet_stop_prob": 0.10,
|
||||
"rules.guard.guard_number_stop_prob": 0.001,
|
||||
"rules.guard.castle_stop_prob": 0.05,
|
||||
"rules.guard.region_type_stop_prob": 0.05,
|
||||
"rules.economy.repopulate_maximum": 500,
|
||||
"rules.lighthouse.unit_capacity": true,
|
||||
"resource.visibility.rule": 0
|
||||
},
|
||||
"disabled": [
|
||||
"jsreport"
|
||||
],
|
||||
"include": [
|
||||
"config://conf/keywords.json",
|
||||
"config://conf/calendar.json",
|
||||
"config://conf/prefixes.json",
|
||||
"config://conf/e2/locales.json",
|
||||
"config://conf/e2/terrains.json",
|
||||
"config://conf/e2/items.json",
|
||||
"config://res/core/ships.xml",
|
||||
"config://res/core/common/buildings.xml",
|
||||
"config://res/eressea/buildings.xml",
|
||||
"config://res/buildings/castle.xml",
|
||||
"config://res/eressea/races.xml",
|
||||
"config://res/eressea/artrewards.xml",
|
||||
"config://res/eressea/spells.xml",
|
||||
"config://res/eressea/spellbooks/gray.xml",
|
||||
"config://res/eressea/spellbooks/gwyrrd.xml",
|
||||
"config://res/eressea/spellbooks/draig.xml",
|
||||
"config://res/eressea/spellbooks/illaun.xml",
|
||||
"config://res/eressea/spellbooks/cerddor.xml",
|
||||
"config://res/eressea/spellbooks/tybied.xml"
|
||||
]
|
||||
}
|
||||
|
|
|
@ -67,7 +67,6 @@
|
|||
"init_spells": 0,
|
||||
"recruit.allow_merge": true,
|
||||
"study.expensivemigrants": true,
|
||||
"study.speedup": 2,
|
||||
"game.era": 3,
|
||||
"game.start": 1,
|
||||
"rules.reserve.twophase": true,
|
||||
|
|
|
@ -595,7 +595,7 @@
|
|||
<spell name="shockwave" rank="5" variable="true" combat="2">
|
||||
<resource name="aura" amount="1" cost="level"/>
|
||||
</spell>
|
||||
<spell name="eternal_walls" rank="5" parameters="b" ship="true" variable="true">
|
||||
<spell name="eternal_walls" rank="5" parameters="b" ship="true">
|
||||
<resource name="aura" amount="50" cost="fixed"/>
|
||||
<resource name="permaura" amount="1" cost="fixed"/>
|
||||
</spell>
|
||||
|
|
|
@ -214,7 +214,7 @@
|
|||
<spell name="view_reality" rank="5">
|
||||
<resource name="aura" amount="40" cost="fixed"/>
|
||||
</spell>
|
||||
<spell name="astral_disruption" rank="4" variable="true">
|
||||
<spell name="astral_disruption" rank="4">
|
||||
<resource name="aura" amount="140" cost="fixed"/>
|
||||
</spell>
|
||||
<spell name="seduction" rank="5" parameters="u" los="true">
|
||||
|
@ -422,7 +422,7 @@
|
|||
<resource name="aura" amount="1" cost="fixed"/>
|
||||
<resource name="permaura" amount="1" cost="fixed"/>
|
||||
</spell>
|
||||
<spell name="eternal_walls" rank="5" parameters="b" ship="true" variable="true">
|
||||
<spell name="eternal_walls" rank="5" parameters="b" ship="true">
|
||||
<resource name="aura" amount="50" cost="fixed"/>
|
||||
<resource name="permaura" amount="1" cost="fixed"/>
|
||||
</spell>
|
||||
|
|
|
@ -1161,7 +1161,7 @@ msgid "spyreport_faction"
|
|||
msgstr "\"$unit($target) gehört der Partei $faction($faction) an.\""
|
||||
|
||||
msgid "ship_drift"
|
||||
msgstr "\"Die $ship($ship) treibt nach $direction($dir).\""
|
||||
msgstr "\"Die $ship($ship) hat zu wenig Segler und treibt nach $direction($dir).\""
|
||||
|
||||
msgid "error_max_magicians"
|
||||
msgstr "\"$unit($unit) in $region($region): '$order($command)' - Es kann maximal $int($amount) Magier pro Partei geben.\""
|
||||
|
|
|
@ -1161,7 +1161,7 @@ msgid "spyreport_faction"
|
|||
msgstr "\"$unit($target) belongs to $faction($faction).\""
|
||||
|
||||
msgid "ship_drift"
|
||||
msgstr "\"The ship $ship($ship) drifts to the $direction($dir).\""
|
||||
msgstr "\"The ship $ship($ship) needs more sailors and drifts to the $direction($dir).\""
|
||||
|
||||
msgid "error_max_magicians"
|
||||
msgstr "\"$unit($unit) in $region($region): '$order($command)' - There may not be more than $int($amount) magicians in your faction.\""
|
||||
|
|
|
@ -34,8 +34,9 @@ function test_laen_needs_mine()
|
|||
assert_equal(1, f:count_msg_type("building_needed")) -- requires building
|
||||
|
||||
u.building = building.create(u.region, "mine")
|
||||
u.building.working = true
|
||||
u.building.size = 10
|
||||
u:add_item('money', 500) -- Unterhalt Bergwerk
|
||||
u.building.working = true
|
||||
turn_process()
|
||||
assert_equal(1, u:get_item('laen'))
|
||||
assert_equal(99, r:get_resource('laen'))
|
||||
|
@ -56,15 +57,19 @@ function test_mine_laen_bonus()
|
|||
u:add_order("MACHE Laen")
|
||||
u:set_skill('mining', 6)
|
||||
u.building = building.create(u.region, "mine")
|
||||
u.building.working = true
|
||||
|
||||
u.building.size = 10
|
||||
u.number = 2
|
||||
u:add_item('money', 500) -- Unterhalt Bergwerk
|
||||
u.building.working = true
|
||||
turn_process() -- T6 is not enough for laen
|
||||
assert_equal(0, u:get_item('laen'))
|
||||
assert_equal(100, r:get_resource('laen'))
|
||||
assert_equal(1, f:count_msg_type("manufacture_skills"))
|
||||
|
||||
u:set_skill('mining', 13)
|
||||
u:add_item('money', 500) -- Unterhalt Bergwerk
|
||||
u.building.working = true
|
||||
turn_process() -- T13 is enough, the +1 produces one extra Laen
|
||||
assert_equal(4, u:get_item('laen')) -- FAIL (3)
|
||||
assert_equal(96, r:get_resource('laen'))
|
||||
|
@ -86,13 +91,14 @@ function test_mine_iron_bonus()
|
|||
u:add_order("MACHE Eisen")
|
||||
u:set_skill('mining', 1)
|
||||
u.building = building.create(u.region, "mine")
|
||||
u.building.working = false
|
||||
|
||||
u.building.size = 10
|
||||
u.number = 2
|
||||
turn_process() -- iron can be made without a working mine
|
||||
assert_equal(2, u:get_item('iron'))
|
||||
assert_equal(98, r:get_resource('iron'))
|
||||
|
||||
u:add_item('money', 500) -- Unterhalt Bergwerk
|
||||
u.building.working = true
|
||||
turn_process()
|
||||
assert_equal(6, u:get_item('iron'))
|
||||
|
@ -115,12 +121,13 @@ function test_quarry_bonus()
|
|||
u:set_skill('quarrying', 1)
|
||||
u.number = 2
|
||||
u.building = building.create(u.region, 'quarry')
|
||||
u.building.working = false
|
||||
|
||||
u.building.size = 10
|
||||
turn_process()
|
||||
assert_equal(2, u:get_item('stone'))
|
||||
assert_equal(98, r:get_resource('stone'))
|
||||
|
||||
u:add_item('money', 250) -- Unterhalt Steinbruch
|
||||
u.building.working = true
|
||||
turn_process()
|
||||
assert_equal(6, u:get_item('stone'))
|
||||
|
@ -138,16 +145,18 @@ function test_smithy_no_bonus()
|
|||
|
||||
turn_begin()
|
||||
u.building = building.create(u.region, 'smithy')
|
||||
u.building.working = false
|
||||
|
||||
u.building.size = 10
|
||||
u.number = 5
|
||||
u:set_skill('cartmaking', 1) -- needs 1 min
|
||||
u:add_item('log', 100)
|
||||
u:add_order("MACHE Wagen")
|
||||
turn_process() -- building disabled
|
||||
turn_process() -- building disabled, money is missing
|
||||
assert_equal(5, u:get_item('cart'))
|
||||
assert_equal(75, u:get_item('log'))
|
||||
|
||||
u:add_item('money', 300) -- Unterhalt Schmiede
|
||||
u:add_item('log', 1)
|
||||
u.building.working = true
|
||||
turn_process() -- building active
|
||||
assert_equal(10, u:get_item('cart'))
|
||||
|
@ -164,7 +173,7 @@ function test_smithy_bonus_iron()
|
|||
|
||||
turn_begin()
|
||||
u.building = building.create(u.region, 'smithy')
|
||||
u.building.working = false
|
||||
|
||||
u.building.size = 10
|
||||
u:set_skill('weaponsmithing', 5) -- needs 3
|
||||
u:add_item('iron', 100)
|
||||
|
@ -173,6 +182,8 @@ function test_smithy_bonus_iron()
|
|||
assert_equal(1, u:get_item('sword'))
|
||||
assert_equal(99, u:get_item('iron'))
|
||||
|
||||
u:add_item('log', 1) -- Unterhalt Schmiede
|
||||
u:add_item('money', 300) -- Unterhalt Schmiede
|
||||
u.building.working = true
|
||||
turn_process() -- building active
|
||||
assert_equal(3, u:get_item('sword'))
|
||||
|
@ -190,7 +201,7 @@ function test_smithy_bonus_mixed()
|
|||
|
||||
turn_begin()
|
||||
u.building = building.create(u.region, 'smithy')
|
||||
u.building.working = false
|
||||
|
||||
u.building.size = 10
|
||||
u:set_skill('weaponsmithing', 5) -- needs 3
|
||||
u:add_item('iron', 100)
|
||||
|
@ -201,6 +212,8 @@ function test_smithy_bonus_mixed()
|
|||
assert_equal(99, u:get_item('iron'))
|
||||
assert_equal(99, u:get_item('log'))
|
||||
|
||||
u:add_item('money', 300) -- Unterhalt Schmiede
|
||||
u:add_item('log', 1) -- Unterhalt Schmiede
|
||||
u.building.working = true
|
||||
turn_process() -- building active
|
||||
assert_equal(3, u:get_item('axe'))
|
||||
|
|
|
@ -97,7 +97,7 @@ end
|
|||
function test_lighthouse()
|
||||
eressea.free_game()
|
||||
local r = region.create(0, 0, "mountain")
|
||||
local f = faction.create("human", "human@example.com")
|
||||
local f = faction.create("human", "lighthouse@example.com")
|
||||
local f2 = faction.create("dwarf")
|
||||
local r2 = region.create(1, 0, "mountain")
|
||||
unit.create(f2, r2, 1).name = 'The Babadook'
|
||||
|
@ -108,7 +108,6 @@ function test_lighthouse()
|
|||
local u = unit.create(f, r, 1)
|
||||
local b = building.create(r, "lighthouse")
|
||||
b.size = 100
|
||||
b.working = true
|
||||
u.building = b
|
||||
u:set_skill("perception", 9)
|
||||
u:add_item("money", 1000)
|
||||
|
|
|
@ -92,7 +92,6 @@ set (PARSER_SRC
|
|||
|
||||
set (ERESSEA_SRC
|
||||
vortex.c
|
||||
academy.c
|
||||
alchemy.c
|
||||
automate.c
|
||||
battle.c
|
||||
|
@ -168,6 +167,7 @@ set(SERVER_SRC
|
|||
bindings.c
|
||||
console.c
|
||||
helpers.c
|
||||
signals.c
|
||||
main.c
|
||||
)
|
||||
|
||||
|
@ -180,7 +180,9 @@ set (SERVER_SRC ${SERVER_SRC}
|
|||
endif(CURSES_FOUND)
|
||||
|
||||
find_program(IWYU_PATH NAMES include-what-you-use iwyu)
|
||||
if(NOT IWYU_PATH)
|
||||
if(IWYU_PATH)
|
||||
# set(C_INCLUDE_WHAT_YOU_USE "${IWYU_PATH} -Xiwyu --no_fwd_decls")
|
||||
else(IWYU_PATH)
|
||||
message(STATUS "Could not find the program include-what-you-use")
|
||||
endif()
|
||||
|
||||
|
@ -212,7 +214,6 @@ target_link_libraries(eressea
|
|||
)
|
||||
|
||||
set(TESTS_SRC
|
||||
academy.test.c
|
||||
alchemy.test.c
|
||||
automate.test.c
|
||||
battle.test.c
|
||||
|
|
|
@ -1,22 +0,0 @@
|
|||
#include "platform.h"
|
||||
#include "kernel/config.h"
|
||||
#include <kernel/unit.h>
|
||||
#include <kernel/building.h>
|
||||
#include <kernel/item.h>
|
||||
#include <kernel/pool.h>
|
||||
|
||||
#include "academy.h"
|
||||
#include "study.h"
|
||||
|
||||
void academy_teaching_bonus(struct unit *u, skill_t sk, int students) {
|
||||
if (students > 0 && sk != NOSKILL) {
|
||||
/* actually students * EXPERIENCEDAYS / MAX_STUDENTS */
|
||||
learn_skill(u, sk, students);
|
||||
}
|
||||
}
|
||||
|
||||
bool academy_can_teach(unit *teacher, unit *scholar, skill_t sk) {
|
||||
const struct building_type *btype = bt_find("academy");
|
||||
return (active_building(scholar, btype));
|
||||
}
|
||||
|
|
@ -1,16 +0,0 @@
|
|||
#ifndef H_ACADEMY
|
||||
#define H_ACADEMY
|
||||
|
||||
#include <skill.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct unit;
|
||||
void academy_teaching_bonus(struct unit *u, skill_t sk, int academy);
|
||||
bool academy_can_teach(struct unit *teacher, struct unit *scholar, skill_t sk);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
|
@ -1,52 +0,0 @@
|
|||
#include <platform.h>
|
||||
|
||||
#include "academy.h"
|
||||
#include "skill.h"
|
||||
|
||||
#include <kernel/config.h>
|
||||
#include <kernel/building.h>
|
||||
#include <kernel/faction.h>
|
||||
#include <kernel/unit.h>
|
||||
#include <kernel/item.h>
|
||||
#include <kernel/region.h>
|
||||
|
||||
#include <CuTest.h>
|
||||
#include "tests.h"
|
||||
|
||||
static void test_academy(CuTest * tc)
|
||||
{
|
||||
faction *f;
|
||||
unit *u, *u2;
|
||||
region *r;
|
||||
building *b;
|
||||
const item_type *it_silver;
|
||||
|
||||
test_setup();
|
||||
config_set_int("skills.cost.alchemy", 100);
|
||||
r = test_create_region(0, 0, NULL);
|
||||
f = test_create_faction(NULL);
|
||||
u = test_create_unit(f, r);
|
||||
b = test_create_building(r, test_create_buildingtype("academy"));
|
||||
u2 = test_create_unit(f, r);
|
||||
it_silver = test_create_silver();
|
||||
|
||||
CuAssert(tc, "teacher must be in academy", !academy_can_teach(u, u2, SK_CROSSBOW));
|
||||
u_set_building(u, b);
|
||||
CuAssert(tc, "student must be in academy", !academy_can_teach(u, u2, SK_CROSSBOW));
|
||||
u_set_building(u2, b);
|
||||
CuAssert(tc, "student must have 50 silver", !academy_can_teach(u, u2, SK_CROSSBOW));
|
||||
i_change(&u2->items, it_silver, 50);
|
||||
CuAssert(tc, "building must be maintained", !academy_can_teach(u, u2, SK_CROSSBOW));
|
||||
b->flags |= BLD_MAINTAINED;
|
||||
CuAssert(tc, "building must have capacity", !academy_can_teach(u, u2, SK_CROSSBOW));
|
||||
b->size = 2;
|
||||
CuAssertTrue(tc, academy_can_teach(u, u2, SK_CROSSBOW));
|
||||
test_teardown();
|
||||
}
|
||||
|
||||
CuSuite *get_academy_suite(void)
|
||||
{
|
||||
CuSuite *suite = CuSuiteNew();
|
||||
SUITE_ADD_TEST(suite, test_academy);
|
||||
return suite;
|
||||
}
|
|
@ -6,6 +6,8 @@
|
|||
#include "kernel/order.h"
|
||||
#include "kernel/region.h"
|
||||
#include "kernel/unit.h"
|
||||
#include "kernel/pool.h"
|
||||
#include "kernel/item.h"
|
||||
|
||||
#include "util/keyword.h"
|
||||
#include "util/log.h"
|
||||
|
@ -210,7 +212,12 @@ void do_autostudy(region *r)
|
|||
autostudy_run(scholars, nscholars);
|
||||
for (i = 0; i != nscholars; ++i) {
|
||||
int days = STUDYDAYS * scholars[i].learn;
|
||||
learn_skill(scholars[i].u, skill, days);
|
||||
int money = learn_skill(scholars[i].u, skill, days, 0);
|
||||
if (money > 0) {
|
||||
use_pooled(u, get_resourcetype(R_SILVER), GET_DEFAULT, money);
|
||||
ADDMSG(&u->faction->msgs, msg_message("studycost",
|
||||
"unit region cost skill", u, u->region, money, skill));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -899,7 +899,7 @@ void drain_exp(struct unit *u, int n)
|
|||
}
|
||||
}
|
||||
if (sk != NOSKILL) {
|
||||
reduce_skill_days(u, sk, n);
|
||||
change_skill_days(u, sk, -n);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -39,15 +39,15 @@ static int tolua_building_set_working(lua_State * L)
|
|||
{
|
||||
building *self = (building *)tolua_tousertype(L, 1, 0);
|
||||
bool flag = !!lua_toboolean(L, 2);
|
||||
if (flag) self->flags |= BLD_MAINTAINED;
|
||||
else self->flags &= ~BLD_MAINTAINED;
|
||||
return 1;
|
||||
if (flag) self->flags &= ~BLD_UNMAINTAINED;
|
||||
else self->flags |= BLD_UNMAINTAINED;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tolua_building_get_working(lua_State * L)
|
||||
{
|
||||
building *self = (building *)tolua_tousertype(L, 1, 0);
|
||||
bool flag = (self->flags&BLD_MAINTAINED) != 0;
|
||||
bool flag = (self->flags & BLD_UNMAINTAINED) == 0;
|
||||
lua_pushboolean(L, flag);
|
||||
return 1;
|
||||
}
|
||||
|
|
|
@ -310,18 +310,6 @@ static int tolua_create_curse(lua_State * L)
|
|||
return 1;
|
||||
}
|
||||
|
||||
static int tolua_learn_skill(lua_State * L)
|
||||
{
|
||||
unit *u = (unit *)tolua_tousertype(L, 1, 0);
|
||||
const char *skname = tolua_tostring(L, 2, 0);
|
||||
int days = (int)tolua_tonumber(L, 3, 0);
|
||||
skill_t sk = findskill(skname);
|
||||
if (sk != NOSKILL) {
|
||||
learn_skill(u, sk, days);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tolua_update_scores(lua_State * L)
|
||||
{
|
||||
UNUSED_ARG(L);
|
||||
|
@ -973,7 +961,6 @@ int tolua_bindings_open(lua_State * L, const dictionary *inifile)
|
|||
tolua_function(L, TOLUA_CAST "remove_empty_units", tolua_remove_empty_units);
|
||||
tolua_function(L, TOLUA_CAST "update_scores", tolua_update_scores);
|
||||
tolua_function(L, TOLUA_CAST "update_owners", tolua_update_owners);
|
||||
tolua_function(L, TOLUA_CAST "learn_skill", tolua_learn_skill);
|
||||
tolua_function(L, TOLUA_CAST "create_curse", tolua_create_curse);
|
||||
tolua_function(L, TOLUA_CAST "translate", &tolua_translate);
|
||||
tolua_function(L, TOLUA_CAST "spells", tolua_get_spells);
|
||||
|
|
|
@ -1363,9 +1363,11 @@ static void cr_output_region(FILE * F, report_context * ctx, region * r)
|
|||
fprintf(F, "%d;Rekruten\n", rpeasants(r) / RECRUITFRACTION);
|
||||
}
|
||||
if (max_production(r)) {
|
||||
int p_wage = wage(r, NULL, NULL, turn + 1);
|
||||
/* Im CR steht der Bauernlohn, der bei Trauer nur 10 ist */
|
||||
bool mourn = is_mourning(r, turn);
|
||||
int p_wage = peasant_wage(r, mourn);
|
||||
fprintf(F, "%d;Lohn\n", p_wage);
|
||||
if (is_mourning(r, turn + 1)) {
|
||||
if (mourn) {
|
||||
fputs("1;mourning\n", F);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -305,31 +305,34 @@ static int forget_cmd(unit * u, order * ord)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int maintain(building * b)
|
||||
static bool maintain(building * b)
|
||||
{
|
||||
int c;
|
||||
region *r = b->region;
|
||||
bool paid = true;
|
||||
unit *u;
|
||||
|
||||
if (fval(b, BLD_MAINTAINED) || b->type == NULL || b->type->maintenance == NULL) {
|
||||
return BLD_MAINTAINED;
|
||||
}
|
||||
if (fval(b, BLD_DONTPAY)) {
|
||||
return 0;
|
||||
if (b->type == NULL || b->type->maintenance == NULL) {
|
||||
return true;
|
||||
}
|
||||
u = building_owner(b);
|
||||
if (u == NULL) {
|
||||
/* no owner - send a message to the entire region */
|
||||
ADDMSG(&r->msgs, msg_message("maintenance_noowner", "building", b));
|
||||
return 0;
|
||||
return false;
|
||||
}
|
||||
/* If the owner is the region owner, check if dontpay flag is set for the building where he is in */
|
||||
if (config_token("rules.region_owner_pay_building", b->type->_name)) {
|
||||
if (fval(u->building, BLD_DONTPAY)) {
|
||||
return 0;
|
||||
/* If the owner is the region owner, check if dontpay flag is set for the building he is in */
|
||||
if (b != u->building) {
|
||||
if (!config_token("rules.region_owner_pay_building", b->type->_name)) {
|
||||
/* no owner - send a message to the entire region */
|
||||
ADDMSG(&r->msgs, msg_message("maintenance_noowner", "building", b));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (fval(u->building, BLD_DONTPAY)) {
|
||||
ADDMSG(&r->msgs, msg_message("maintenance_nowork", "building", b));
|
||||
return false;
|
||||
}
|
||||
for (c = 0; b->type->maintenance[c].number && paid; ++c) {
|
||||
const maintenance *m = b->type->maintenance + c;
|
||||
int need = m->number;
|
||||
|
@ -341,14 +344,10 @@ static int maintain(building * b)
|
|||
paid = false;
|
||||
}
|
||||
}
|
||||
if (fval(b, BLD_DONTPAY)) {
|
||||
ADDMSG(&r->msgs, msg_message("maintenance_nowork", "building", b));
|
||||
return 0;
|
||||
}
|
||||
if (!paid) {
|
||||
ADDMSG(&u->faction->msgs, msg_message("maintenancefail", "unit building", u, b));
|
||||
ADDMSG(&r->msgs, msg_message("maintenance_nowork", "building", b));
|
||||
return 0;
|
||||
return paid;
|
||||
}
|
||||
for (c = 0; b->type->maintenance[c].number; ++c) {
|
||||
const maintenance *m = b->type->maintenance + c;
|
||||
|
@ -363,7 +362,7 @@ static int maintain(building * b)
|
|||
assert(cost == 0);
|
||||
}
|
||||
ADDMSG(&u->faction->msgs, msg_message("maintenance", "unit building", u, b));
|
||||
return BLD_MAINTAINED;
|
||||
return true;
|
||||
}
|
||||
|
||||
void maintain_buildings(region * r)
|
||||
|
@ -371,12 +370,11 @@ void maintain_buildings(region * r)
|
|||
building **bp = &r->buildings;
|
||||
while (*bp) {
|
||||
building *b = *bp;
|
||||
int flags = BLD_MAINTAINED;
|
||||
|
||||
if (!curse_active(get_curse(b->attribs, &ct_nocostbuilding))) {
|
||||
flags = maintain(b);
|
||||
if (!maintain(b)) {
|
||||
fset(b, BLD_UNMAINTAINED);
|
||||
}
|
||||
}
|
||||
fset(b, flags);
|
||||
bp = &b->next;
|
||||
}
|
||||
}
|
||||
|
@ -1993,7 +1991,8 @@ expandwork(region * r, econ_request * work_begin, econ_request * work_end, int m
|
|||
/* n: verbleibende Einnahmen */
|
||||
/* fishes: maximale Arbeiter */
|
||||
int jobs = maxwork;
|
||||
int p_wage = wage(r, NULL, NULL, turn);
|
||||
bool mourn = is_mourning(r, turn);
|
||||
int p_wage = peasant_wage(r, mourn);
|
||||
int money = rmoney(r);
|
||||
if (total > 0 && !rule_autowork()) {
|
||||
econ_request *o;
|
||||
|
@ -2017,7 +2016,7 @@ expandwork(region * r, econ_request * work_begin, econ_request * work_end, int m
|
|||
|
||||
assert(workers >= 0);
|
||||
|
||||
u->n = workers * wage(u->region, u->faction, u_race(u), turn);
|
||||
u->n = workers * wage(u->region, u_race(u));
|
||||
|
||||
jobs -= workers;
|
||||
assert(jobs >= 0);
|
||||
|
@ -2061,7 +2060,7 @@ static int work_cmd(unit * u, order * ord, econ_request ** io_req)
|
|||
}
|
||||
return 0;
|
||||
}
|
||||
w = wage(r, u->faction, u_race(u), turn);
|
||||
w = wage(r, u_race(u));
|
||||
add_request(req++, ECON_WORK, u, ord, w * u->number);
|
||||
*io_req = req;
|
||||
return u->number;
|
||||
|
|
|
@ -497,7 +497,7 @@ static void test_maintain_buildings(CuTest *tc) {
|
|||
/* this building has no upkeep, it just works: */
|
||||
b->flags = 0;
|
||||
maintain_buildings(r);
|
||||
CuAssertIntEquals(tc, BLD_MAINTAINED, fval(b, BLD_MAINTAINED));
|
||||
CuAssertIntEquals(tc, 0, fval(b, BLD_UNMAINTAINED));
|
||||
CuAssertPtrEquals(tc, NULL, f->msgs);
|
||||
CuAssertPtrEquals(tc, NULL, r->msgs);
|
||||
|
||||
|
@ -509,7 +509,7 @@ static void test_maintain_buildings(CuTest *tc) {
|
|||
/* we cannot afford to pay: */
|
||||
b->flags = 0;
|
||||
maintain_buildings(r);
|
||||
CuAssertIntEquals(tc, 0, fval(b, BLD_MAINTAINED));
|
||||
CuAssertIntEquals(tc, BLD_UNMAINTAINED, fval(b, BLD_UNMAINTAINED));
|
||||
CuAssertPtrNotNull(tc, test_find_messagetype(f->msgs, "maintenancefail"));
|
||||
CuAssertPtrNotNull(tc, test_find_messagetype(r->msgs, "maintenance_nowork"));
|
||||
test_clear_messagelist(&f->msgs);
|
||||
|
@ -519,7 +519,7 @@ static void test_maintain_buildings(CuTest *tc) {
|
|||
i_change(&u->items, itype, 100);
|
||||
b->flags = 0;
|
||||
maintain_buildings(r);
|
||||
CuAssertIntEquals(tc, BLD_MAINTAINED, fval(b, BLD_MAINTAINED));
|
||||
CuAssertIntEquals(tc, 0, fval(b, BLD_UNMAINTAINED));
|
||||
CuAssertIntEquals(tc, 0, i_get(u->items, itype));
|
||||
CuAssertPtrEquals(tc, NULL, r->msgs);
|
||||
CuAssertPtrEquals(tc, NULL, test_find_messagetype(f->msgs, "maintenance_nowork"));
|
||||
|
@ -530,7 +530,7 @@ static void test_maintain_buildings(CuTest *tc) {
|
|||
u_set_building(u, NULL);
|
||||
b->flags = 0;
|
||||
maintain_buildings(r);
|
||||
CuAssertIntEquals(tc, 0, fval(b, BLD_MAINTAINED));
|
||||
CuAssertIntEquals(tc, BLD_UNMAINTAINED, fval(b, BLD_UNMAINTAINED));
|
||||
CuAssertPtrEquals(tc, NULL, f->msgs);
|
||||
CuAssertPtrNotNull(tc, test_find_messagetype(r->msgs, "maintenance_noowner"));
|
||||
test_clear_messagelist(&r->msgs);
|
||||
|
|
|
@ -37,7 +37,7 @@ struct order *ord)
|
|||
skill *sv = u->skills;
|
||||
while (sv != u->skills + u->skill_size) {
|
||||
/* only one person learns for 3 weeks */
|
||||
learn_skill(u, (skill_t)sv->id, STUDYDAYS * 3);
|
||||
change_skill_days(u, (skill_t)sv->id, STUDYDAYS * 3);
|
||||
++sv;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -52,17 +52,17 @@ static void test_skillpotion(CuTest *tc) {
|
|||
itype = test_create_itemtype("skillpotion");
|
||||
change_resource(u, itype->rtype, 2);
|
||||
|
||||
learn_skill(u, SK_ENTERTAINMENT, STUDYDAYS * u->number);
|
||||
change_skill_days(u, SK_ENTERTAINMENT, STUDYDAYS * u->number);
|
||||
pSkill = unit_skill(u, SK_ENTERTAINMENT);
|
||||
sk_set(pSkill, 5);
|
||||
initialWeeks_Entertainment = pSkill->weeks = 4;
|
||||
|
||||
learn_skill(u, SK_STAMINA, STUDYDAYS * u->number);
|
||||
change_skill_days(u, SK_STAMINA, STUDYDAYS * u->number);
|
||||
pSkill = unit_skill(u, SK_STAMINA);
|
||||
sk_set(pSkill, 5);
|
||||
initialWeeks_Stamina = pSkill->weeks = 4;
|
||||
|
||||
learn_skill(u, SK_MAGIC, STUDYDAYS * u->number);
|
||||
change_skill_days(u, SK_MAGIC, STUDYDAYS * u->number);
|
||||
pSkill = unit_skill(u, SK_MAGIC);
|
||||
sk_set(pSkill, 5);
|
||||
initialWeeks_Magic = pSkill->weeks = 4;
|
||||
|
|
|
@ -829,7 +829,6 @@ build_building(unit * u, const building_type * btype, int id, int want, order *
|
|||
/* build a new building */
|
||||
b = new_building(btype, r, lang, built);
|
||||
b->type = btype;
|
||||
fset(b, BLD_MAINTAINED);
|
||||
|
||||
/* Die Einheit befindet sich automatisch im Inneren der neuen Burg. */
|
||||
if (u->number && leave(u, false)) {
|
||||
|
@ -879,10 +878,6 @@ build_building(unit * u, const building_type * btype, int id, int want, order *
|
|||
}
|
||||
fset(b, BLD_EXPANDED);
|
||||
|
||||
if (is_lighthouse(btype)) {
|
||||
update_lighthouse(b);
|
||||
}
|
||||
|
||||
return built;
|
||||
}
|
||||
|
||||
|
|
|
@ -404,9 +404,6 @@ building *new_building(const struct building_type * btype, region * r,
|
|||
bptr = &(*bptr)->next;
|
||||
*bptr = b;
|
||||
|
||||
if (is_lighthouse(b->type)) {
|
||||
update_lighthouse(b);
|
||||
}
|
||||
bname = LOC(lang, btype->_name);
|
||||
if (!bname) {
|
||||
bname = LOC(lang, parameters[P_GEBAEUDE]);
|
||||
|
@ -445,9 +442,6 @@ void remove_building(building ** blist, building * b)
|
|||
if (u->building == b) leave(u, true);
|
||||
}
|
||||
|
||||
if (is_lighthouse(b->type)) {
|
||||
remove_lighthouse(b);
|
||||
}
|
||||
b->size = 0;
|
||||
bunhash(b);
|
||||
|
||||
|
@ -495,20 +489,22 @@ extern struct attrib_type at_icastle;
|
|||
/** returns the building's build stage (NOT size in people).
|
||||
* only makes sense for castles or similar buildings with multiple
|
||||
* stages */
|
||||
int buildingeffsize(const building * b, int img)
|
||||
int buildingeffsize(const building * b, bool imaginary)
|
||||
{
|
||||
const struct building_type *btype = NULL;
|
||||
|
||||
if (b == NULL)
|
||||
return 0;
|
||||
|
||||
btype = b->type;
|
||||
if (img) {
|
||||
if (imaginary) {
|
||||
const attrib *a = a_find(b->attribs, &at_icastle);
|
||||
if (a) {
|
||||
btype = (const struct building_type *)a->data.v;
|
||||
}
|
||||
}
|
||||
else {
|
||||
btype = b->type;
|
||||
}
|
||||
return bt_effsize(btype, b, b->size);
|
||||
}
|
||||
|
||||
|
@ -518,7 +514,7 @@ int bt_effsize(const building_type * btype, const building * b, int bsize)
|
|||
bsize = adjust_size(b, bsize);
|
||||
}
|
||||
|
||||
if (btype->stages) {
|
||||
if (btype && btype->stages) {
|
||||
int n = 0;
|
||||
const building_stage *stage = btype->stages;
|
||||
do {
|
||||
|
@ -637,7 +633,7 @@ buildingtype_exists(const region * r, const building_type * bt, bool working)
|
|||
building *b;
|
||||
|
||||
for (b = rbuildings(r); b; b = b->next) {
|
||||
if (b->type == bt && (!working || fval(b, BLD_MAINTAINED)) && building_finished(b)) {
|
||||
if (b->type == bt && !(working && fval(b, BLD_UNMAINTAINED)) && building_finished(b)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -650,7 +646,7 @@ bool building_finished(const struct building *b) {
|
|||
}
|
||||
|
||||
bool building_is_active(const struct building *b) {
|
||||
return b && fval(b, BLD_MAINTAINED) && building_finished(b);
|
||||
return b && !fval(b, BLD_UNMAINTAINED) && building_finished(b);
|
||||
}
|
||||
|
||||
building *active_building(const unit *u, const struct building_type *btype) {
|
||||
|
@ -728,7 +724,7 @@ static const int wagetable[7][3] = {
|
|||
};
|
||||
|
||||
static int
|
||||
default_wage(const region * r, const faction * f, const race * rc, int in_turn)
|
||||
default_wage(const region * r, const race * rc)
|
||||
{
|
||||
building *b = largestbuilding(r, cmp_wage, false);
|
||||
int esize = 0;
|
||||
|
@ -739,25 +735,23 @@ default_wage(const region * r, const faction * f, const race * rc, int in_turn)
|
|||
esize = buildingeffsize(b, false);
|
||||
}
|
||||
|
||||
if (f != NULL) {
|
||||
if (rc != NULL) {
|
||||
static const struct race *rc_orc, *rc_snotling;
|
||||
static int rc_cache;
|
||||
int index = 0;
|
||||
if (rc == get_race(RC_ORC) || rc == get_race(RC_SNOTLING)) {
|
||||
if (rc_changed(&rc_cache)) {
|
||||
rc_orc = get_race(RC_ORC);
|
||||
rc_snotling = get_race(RC_SNOTLING);
|
||||
}
|
||||
if (rc == rc_orc || rc == rc_snotling) {
|
||||
index = 1;
|
||||
}
|
||||
wage = wagetable[esize][index];
|
||||
}
|
||||
else {
|
||||
if (is_mourning(r, in_turn)) {
|
||||
wage = 10;
|
||||
}
|
||||
else if (fval(r->terrain, SEA_REGION)) {
|
||||
wage = 11;
|
||||
}
|
||||
else {
|
||||
wage = wagetable[esize][2];
|
||||
}
|
||||
if (r->attribs && rule_blessed_harvest() == HARVEST_WORK) {
|
||||
/* E1 rules */
|
||||
wage = wagetable[esize][2];
|
||||
if (rule_blessed_harvest() & HARVEST_WORK) {
|
||||
/* Geändert in E3 */
|
||||
wage += harvest_effect(r);
|
||||
}
|
||||
}
|
||||
|
@ -766,7 +760,7 @@ default_wage(const region * r, const faction * f, const race * rc, int in_turn)
|
|||
attrib *a;
|
||||
curse *c;
|
||||
variant vm;
|
||||
|
||||
|
||||
/* Godcurse: Income -10 */
|
||||
vm = frac_make(wage, 1);
|
||||
|
||||
|
@ -786,31 +780,37 @@ default_wage(const region * r, const faction * f, const race * rc, int in_turn)
|
|||
}
|
||||
|
||||
static int
|
||||
minimum_wage(const region * r, const faction * f, const race * rc, int in_turn)
|
||||
minimum_wage(const region * r, const race * rc)
|
||||
{
|
||||
if (f && rc) {
|
||||
if (rc) {
|
||||
return rc->maintenance;
|
||||
}
|
||||
return default_wage(r, f, rc, in_turn);
|
||||
return default_wage(r, rc);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gibt Arbeitslohn fuer entsprechende Rasse zurueck, oder fuer
|
||||
* die Bauern wenn f == NULL. */
|
||||
int wage(const region * r, const faction * f, const race * rc, int in_turn)
|
||||
* die Bauern wenn rc == NULL. */
|
||||
int wage(const region * r, const race * rc)
|
||||
{
|
||||
static int config;
|
||||
static int rule_wage;
|
||||
if (config_changed(&config)) {
|
||||
rule_wage = config_get_int("rules.wage.function", 1);
|
||||
}
|
||||
if (rule_wage==0) {
|
||||
if (rule_wage == 0) {
|
||||
return 0;
|
||||
}
|
||||
if (rule_wage==1) {
|
||||
return default_wage(r, f, rc, in_turn);
|
||||
|
||||
if (rule_wage == 1) {
|
||||
return default_wage(r, rc);
|
||||
}
|
||||
return minimum_wage(r, f, rc, in_turn);
|
||||
return minimum_wage(r, rc);
|
||||
}
|
||||
|
||||
int peasant_wage(const struct region *r, bool mourn)
|
||||
{
|
||||
return mourn ? 10 : wage(r, NULL);
|
||||
}
|
||||
|
||||
int cmp_wage(const struct building *b, const building * a)
|
||||
|
|
|
@ -79,7 +79,7 @@ extern "C" {
|
|||
bool in_safe_building(struct unit *u1, struct unit *u2);
|
||||
|
||||
#define BFL_NONE 0x00
|
||||
#define BLD_MAINTAINED 0x01 /* vital maintenance paid for */
|
||||
#define BLD_UNMAINTAINED 0x01 /* vital maintenance not paid for */
|
||||
#define BLD_DONTPAY 0x02 /* PAY NOT */
|
||||
#define BLD_UNGUARDED 0x04 /* you can enter this building anytime */
|
||||
#define BLD_EXPANDED 0x08 /* has been expanded this turn */
|
||||
|
@ -116,8 +116,8 @@ extern "C" {
|
|||
int id, int size, struct order *ord);
|
||||
bool building_finished(const struct building *b);
|
||||
|
||||
int wage(const struct region *r, const struct faction *f,
|
||||
const struct race *rc, int in_turn);
|
||||
int wage(const struct region *r, const struct race *rc);
|
||||
int peasant_wage(const struct region *r, bool mourn);
|
||||
|
||||
typedef int(*cmp_building_cb) (const struct building * b,
|
||||
const struct building * a);
|
||||
|
@ -130,7 +130,7 @@ extern "C" {
|
|||
int building_taxes(const building *b);
|
||||
|
||||
/* old functions, still in build.c: */
|
||||
int buildingeffsize(const building * b, int imaginary);
|
||||
int buildingeffsize(const building * b, bool imaginary);
|
||||
void bhash(struct building *b);
|
||||
void bunhash(struct building *b);
|
||||
int buildingcapacity(const struct building *b);
|
||||
|
|
|
@ -332,17 +332,16 @@ static void test_buildingtype_exists(CuTest * tc)
|
|||
|
||||
CuAssertTrue(tc, buildingtype_exists(r, btype, false));
|
||||
b->size = 9;
|
||||
fset(b, BLD_MAINTAINED);
|
||||
CuAssertTrue(tc, !buildingtype_exists(r, btype, false));
|
||||
btype->maxsize = 0;
|
||||
freset(b, BLD_MAINTAINED);
|
||||
fset(b, BLD_UNMAINTAINED);
|
||||
CuAssertTrue(tc, buildingtype_exists(r, btype, false));
|
||||
btype->maxsize = 10;
|
||||
b->size = 10;
|
||||
|
||||
fset(b, BLD_MAINTAINED);
|
||||
freset(b, BLD_UNMAINTAINED);
|
||||
CuAssertTrue(tc, buildingtype_exists(r, btype, true));
|
||||
freset(b, BLD_MAINTAINED);
|
||||
fset(b, BLD_UNMAINTAINED);
|
||||
CuAssertTrue(tc, !buildingtype_exists(r, btype, true));
|
||||
test_teardown();
|
||||
}
|
||||
|
@ -359,10 +358,7 @@ static void test_active_building(CuTest *tc) {
|
|||
assert(btype && btype->maxsize == -1);
|
||||
b = test_create_building(r = test_create_region(0, 0, NULL), btype);
|
||||
u = test_create_unit(test_create_faction(NULL), r);
|
||||
CuAssertIntEquals(tc, false, building_is_active(b));
|
||||
CuAssertPtrEquals(tc, NULL, active_building(u, btype));
|
||||
|
||||
b->flags |= BLD_MAINTAINED;
|
||||
CuAssertIntEquals(tc, true, building_is_active(b));
|
||||
CuAssertPtrEquals(tc, NULL, active_building(u, btype));
|
||||
u_set_building(u, b);
|
||||
|
@ -376,7 +372,7 @@ static void test_active_building(CuTest *tc) {
|
|||
CuAssertIntEquals(tc, false, building_is_active(b));
|
||||
CuAssertPtrEquals(tc, NULL, active_building(u, btype));
|
||||
btype->maxsize = -1;
|
||||
b->flags &= ~BLD_MAINTAINED;
|
||||
b->flags |= BLD_UNMAINTAINED;
|
||||
CuAssertIntEquals(tc, false, building_is_active(b));
|
||||
CuAssertPtrEquals(tc, NULL, active_building(u, btype));
|
||||
test_teardown();
|
||||
|
@ -434,6 +430,80 @@ static void test_cmp_castle_size(CuTest *tc) {
|
|||
test_teardown();
|
||||
}
|
||||
|
||||
static void test_wage(CuTest *tc) {
|
||||
region *r;
|
||||
building *b;
|
||||
building_type *btype;
|
||||
struct building_stage *stage;
|
||||
race *rc_orc, *rc_elf;
|
||||
test_setup();
|
||||
rc_orc = test_create_race("orc");
|
||||
rc_elf = test_create_race("elf");
|
||||
rc_elf->maintenance = 13;
|
||||
btype = test_create_buildingtype("castle");
|
||||
stage = btype->stages;
|
||||
stage->construction->maxsize = 2; /* site */
|
||||
stage = stage->next = calloc(1, sizeof(struct building_stage));
|
||||
stage->construction = calloc(1, sizeof(struct construction));
|
||||
stage->construction->maxsize = 8; /* tradepost */
|
||||
stage = stage->next = calloc(1, sizeof(struct building_stage));
|
||||
stage->construction = calloc(1, sizeof(struct construction));
|
||||
stage->construction->maxsize = 40; /* fortification */
|
||||
stage = stage->next = calloc(1, sizeof(struct building_stage));
|
||||
stage->construction = calloc(1, sizeof(struct construction));
|
||||
stage->construction->maxsize = 200; /* fortification */
|
||||
r = test_create_plain(0, 0);
|
||||
CuAssertIntEquals(tc, 10, wage(r, rc_elf));
|
||||
CuAssertIntEquals(tc, 10, wage(r, rc_orc));
|
||||
CuAssertIntEquals(tc, 11, peasant_wage(r, false));
|
||||
CuAssertIntEquals(tc, 10, peasant_wage(r, true));
|
||||
|
||||
b = test_create_building(r, btype);
|
||||
b->size = 1;
|
||||
CuAssertIntEquals(tc, 0, buildingeffsize(b, false));
|
||||
CuAssertIntEquals(tc, 10, wage(r, rc_elf));
|
||||
CuAssertIntEquals(tc, 10, wage(r, rc_orc));
|
||||
CuAssertIntEquals(tc, 11, peasant_wage(r, false));
|
||||
CuAssertIntEquals(tc, 10, peasant_wage(r, true));
|
||||
b->size = 2;
|
||||
CuAssertIntEquals(tc, 1, buildingeffsize(b, false));
|
||||
b->size = 9;
|
||||
CuAssertIntEquals(tc, 1, buildingeffsize(b, false));
|
||||
CuAssertIntEquals(tc, 10, wage(r, rc_elf));
|
||||
CuAssertIntEquals(tc, 10, wage(r, rc_orc));
|
||||
CuAssertIntEquals(tc, 11, peasant_wage(r, false));
|
||||
CuAssertIntEquals(tc, 10, peasant_wage(r, true));
|
||||
b->size = 10;
|
||||
CuAssertIntEquals(tc, 2, buildingeffsize(b, false));
|
||||
b->size = 49;
|
||||
CuAssertIntEquals(tc, 2, buildingeffsize(b, false));
|
||||
CuAssertIntEquals(tc, 11, wage(r, rc_elf));
|
||||
CuAssertIntEquals(tc, 11, wage(r, rc_orc));
|
||||
CuAssertIntEquals(tc, 12, peasant_wage(r, false));
|
||||
CuAssertIntEquals(tc, 10, peasant_wage(r, true));
|
||||
b->size = 50;
|
||||
CuAssertIntEquals(tc, 3, buildingeffsize(b, false));
|
||||
b->size = 249;
|
||||
CuAssertIntEquals(tc, 3, buildingeffsize(b, false));
|
||||
CuAssertIntEquals(tc, 12, wage(r, rc_elf));
|
||||
CuAssertIntEquals(tc, 11, wage(r, rc_orc));
|
||||
CuAssertIntEquals(tc, 13, peasant_wage(r, false));
|
||||
CuAssertIntEquals(tc, 10, peasant_wage(r, true));
|
||||
b->size = 250;
|
||||
CuAssertIntEquals(tc, 4, buildingeffsize(b, false));
|
||||
CuAssertIntEquals(tc, 13, wage(r, rc_elf));
|
||||
CuAssertIntEquals(tc, 12, wage(r, rc_orc));
|
||||
CuAssertIntEquals(tc, 14, peasant_wage(r, false));
|
||||
CuAssertIntEquals(tc, 10, peasant_wage(r, true));
|
||||
config_set_int("rules.wage.function", 1);
|
||||
CuAssertIntEquals(tc, 13, wage(r, rc_elf));
|
||||
config_set_int("rules.wage.function", 0);
|
||||
CuAssertIntEquals(tc, 0, wage(r, rc_elf));
|
||||
config_set_int("rules.wage.function", 2);
|
||||
CuAssertIntEquals(tc, rc_elf->maintenance, wage(r, rc_elf));
|
||||
test_teardown();
|
||||
}
|
||||
|
||||
static void test_cmp_wage(CuTest *tc) {
|
||||
region *r;
|
||||
building *b1, *b2;
|
||||
|
@ -619,6 +689,7 @@ CuSuite *get_building_suite(void)
|
|||
SUITE_ADD_TEST(suite, test_cmp_castle_size);
|
||||
SUITE_ADD_TEST(suite, test_cmp_taxes);
|
||||
SUITE_ADD_TEST(suite, test_cmp_wage);
|
||||
SUITE_ADD_TEST(suite, test_wage);
|
||||
SUITE_ADD_TEST(suite, test_cmp_current_owner);
|
||||
SUITE_ADD_TEST(suite, test_register_building);
|
||||
SUITE_ADD_TEST(suite, test_btype_defaults);
|
||||
|
|
|
@ -42,7 +42,7 @@ extern "C" {
|
|||
bool rule_stealth_anon(void); /* units can anonymize their faction, TARNE PARTEI [NICHT] */
|
||||
int rule_alliance_limit(void);
|
||||
int rule_faction_limit(void);
|
||||
#define HARVEST_WORK 0x00
|
||||
#define HARVEST_WORK 0x02
|
||||
#define HARVEST_TAXES 0x01
|
||||
int rule_blessed_harvest(void);
|
||||
#define GIVE_SELF 1
|
||||
|
|
|
@ -602,7 +602,7 @@ int rpeasants(const region * r)
|
|||
return value;
|
||||
}
|
||||
|
||||
void rsetpeasants(region * r, int value)
|
||||
int rsetpeasants(region * r, int value)
|
||||
{
|
||||
assert(r->land || value==0);
|
||||
assert(value >= 0);
|
||||
|
@ -612,7 +612,9 @@ void rsetpeasants(region * r, int value)
|
|||
value = USHRT_MAX;
|
||||
}
|
||||
r->land->peasants = (unsigned short)value;
|
||||
return r->land->peasants;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int rmoney(const region * r)
|
||||
|
@ -746,17 +748,16 @@ int rsettrees(const region * r, int ageclass, int value)
|
|||
{
|
||||
if (!r->land) {
|
||||
assert(value == 0);
|
||||
return 0;
|
||||
}
|
||||
assert(value >= 0);
|
||||
if (value < MAXTREES) {
|
||||
r->land->trees[ageclass] = value;
|
||||
}
|
||||
else {
|
||||
assert(value >= 0);
|
||||
if (value <= MAXTREES) {
|
||||
return r->land->trees[ageclass] = value;
|
||||
}
|
||||
else {
|
||||
r->land->trees[ageclass] = MAXTREES;
|
||||
}
|
||||
r->land->trees[ageclass] = MAXTREES;
|
||||
}
|
||||
return 0;
|
||||
return r->land->trees[ageclass];
|
||||
}
|
||||
|
||||
region *region_create(int uid)
|
||||
|
@ -1095,11 +1096,10 @@ void init_region(region *r)
|
|||
|
||||
if (!fval(r, RF_CHAOTIC)) {
|
||||
int peasants;
|
||||
int p_wage = 1 + peasant_wage(r, false) + rng_int() % 5;
|
||||
peasants = (region_maxworkers(r) * (20 + dice(6, 10))) / 100;
|
||||
if (peasants < 100) peasants = 100;
|
||||
rsetpeasants(r, peasants);
|
||||
rsetmoney(r, rpeasants(r) * ((wage(r, NULL, NULL,
|
||||
INT_MAX) + 1) + rng_int() % 5));
|
||||
rsetmoney(r, rsetpeasants(r, peasants) * p_wage);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -176,7 +176,7 @@ extern "C" {
|
|||
int rsettrees(const struct region *r, int ageclass, int value);
|
||||
|
||||
int rpeasants(const struct region *r);
|
||||
void rsetpeasants(struct region *r, int value);
|
||||
int rsetpeasants(struct region *r, int value);
|
||||
int rmoney(const struct region *r);
|
||||
void rsetmoney(struct region *r, int value);
|
||||
int rhorses(const struct region *r);
|
||||
|
|
|
@ -118,22 +118,34 @@ static void terraform_default(struct rawmaterial *res, const region * r)
|
|||
}
|
||||
|
||||
static int visible_default(const rawmaterial * res, int skilllevel)
|
||||
/* resources are visible, if skill equals minimum skill to mine them
|
||||
/* resources are visible if skill equals minimum skill to mine them
|
||||
* plus current level of difficulty */
|
||||
{
|
||||
const struct item_type *itype = res->rtype->itype;
|
||||
int level = res->level + itype->construction->minskill - 1;
|
||||
if (res->level <= 1
|
||||
&& res->level + itype->construction->minskill <= skilllevel + 1) {
|
||||
&& level <= skilllevel) {
|
||||
assert(res->amount > 0);
|
||||
return res->amount;
|
||||
}
|
||||
else if (res->level + itype->construction->minskill <= skilllevel + 2) {
|
||||
else if (level < skilllevel) {
|
||||
assert(res->amount > 0);
|
||||
return res->amount;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int visible_half_skill(const rawmaterial * res, int skilllevel)
|
||||
/* resources are visible if skill equals half as much as normal */
|
||||
{
|
||||
const struct item_type *itype = res->rtype->itype;
|
||||
int level = res->level + itype->construction->minskill - 1;
|
||||
if (2 * skilllevel >= level) {
|
||||
return res->amount;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void use_default(rawmaterial * res, const region * r, int amount)
|
||||
{
|
||||
assert(res->amount > 0 && amount >= 0 && amount <= res->amount);
|
||||
|
@ -171,13 +183,19 @@ struct rawmaterial_type *rmt_get(const struct resource_type *rtype)
|
|||
struct rawmaterial_type *rmt_create(struct resource_type *rtype)
|
||||
{
|
||||
if (!rtype->raw) {
|
||||
int rule = config_get_int("resource.visibility.rule", 0);
|
||||
rawmaterial_type *rmtype = rtype->raw = malloc(sizeof(rawmaterial_type));
|
||||
if (!rmtype) abort();
|
||||
rmtype->rtype = rtype;
|
||||
rmtype->terraform = terraform_default;
|
||||
rmtype->update = NULL;
|
||||
rmtype->use = use_default;
|
||||
rmtype->visible = visible_default;
|
||||
if (rule == 0) {
|
||||
rmtype->visible = visible_default;
|
||||
}
|
||||
else {
|
||||
rmtype->visible = visible_half_skill;
|
||||
}
|
||||
}
|
||||
return rtype->raw;
|
||||
}
|
||||
|
|
|
@ -1563,18 +1563,6 @@ static void read_regions(gamedata *data) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
log_debug("updating area information for lighthouses.");
|
||||
for (r = regions; r; r = r->next) {
|
||||
if (r->flags & RF_LIGHTHOUSE) {
|
||||
building *b;
|
||||
for (b = r->buildings; b; b = b->next) {
|
||||
if (is_lighthouse(b->type)) {
|
||||
update_lighthouse(b);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void init_factions(int data_version)
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
|
||||
#ifndef ERESSEA_VERSION
|
||||
/* the version number, if it was not passed to make with -D */
|
||||
#define ERESSEA_VERSION "3.25.0"
|
||||
#define ERESSEA_VERSION "3.26.0"
|
||||
#endif
|
||||
|
||||
const char *eressea_version(void) {
|
||||
|
|
|
@ -743,7 +743,8 @@ void immigration(void)
|
|||
/* if less than 50 are in the region and there is space and no monster or demon units in the region */
|
||||
if (repopulate) {
|
||||
int peasants = rpeasants(r);
|
||||
int income = wage(r, NULL, NULL, turn) - maintenance_cost(NULL) + 1;
|
||||
bool mourn = is_mourning(r, turn);
|
||||
int income = peasant_wage(r, mourn) - maintenance_cost(NULL) + 1;
|
||||
if (income >= 0 && r->land && (peasants < repopulate) && region_maxworkers(r) >(peasants + 30) * 2) {
|
||||
int badunit = 0;
|
||||
unit *u;
|
||||
|
@ -754,7 +755,7 @@ void immigration(void)
|
|||
}
|
||||
}
|
||||
if (badunit == 0) {
|
||||
peasants += (int)(rng_double()*income);
|
||||
peasants += (int)(rng_double() * income);
|
||||
rsetpeasants(r, peasants);
|
||||
}
|
||||
}
|
||||
|
@ -834,8 +835,10 @@ void demographics(void)
|
|||
|
||||
if (r->age > 20) {
|
||||
double mwp = fmax(region_maxworkers(r), 1);
|
||||
bool mourn = is_mourning(r, turn);
|
||||
int p_wage = peasant_wage(r, mourn);
|
||||
double prob =
|
||||
pow(rpeasants(r) / (mwp * wage(r, NULL, NULL, turn) * 0.13), 4.0)
|
||||
pow(rpeasants(r) / (mwp * p_wage * 0.13), 4.0)
|
||||
* PLAGUE_CHANCE;
|
||||
|
||||
if (rng_double() < prob) {
|
||||
|
|
|
@ -21,7 +21,12 @@ attrib_type at_lighthouse = {
|
|||
|
||||
bool is_lighthouse(const building_type *btype)
|
||||
{
|
||||
return is_building_type(btype, "lighthouse");
|
||||
static int config;
|
||||
static const building_type *bt_lighthouse;
|
||||
if (bt_changed(&config)) {
|
||||
bt_lighthouse = bt_find("lighthouse");
|
||||
}
|
||||
return btype == bt_lighthouse;
|
||||
}
|
||||
|
||||
/* update_lighthouse: call this function whenever the size of a lighthouse changes
|
||||
|
@ -54,8 +59,9 @@ void update_lighthouse(building * lh)
|
|||
a = a_find(r2->attribs, &at_lighthouse);
|
||||
while (a && a->type == &at_lighthouse) {
|
||||
building *b = (building *)a->data.v;
|
||||
if (b == lh)
|
||||
if (b == lh) {
|
||||
break;
|
||||
}
|
||||
a = a->next;
|
||||
}
|
||||
if (!a) {
|
||||
|
@ -67,21 +73,22 @@ void update_lighthouse(building * lh)
|
|||
}
|
||||
}
|
||||
|
||||
void remove_lighthouse(const building *lh) {
|
||||
building *b;
|
||||
region * r = lh->region;
|
||||
|
||||
r->flags &= ~RF_LIGHTHOUSE;
|
||||
for (b = r->buildings; b; b = b->next) {
|
||||
if (b != lh && is_lighthouse(b->type)) {
|
||||
update_lighthouse(b);
|
||||
bool update_lighthouses(region *r) {
|
||||
if ((r->flags & RF_LIGHTHOUSE) == 0) {
|
||||
building *b;
|
||||
for (b = r->buildings; b; b = b->next) {
|
||||
if (is_lighthouse(b->type)) {
|
||||
update_lighthouse(b);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
int lighthouse_range(const building * b)
|
||||
{
|
||||
if (b->size >= 10 && (b->flags & BLD_MAINTAINED)) {
|
||||
if (b->size >= 10) {
|
||||
return (int)log10(b->size) + 1;
|
||||
}
|
||||
return 0;
|
||||
|
@ -89,7 +96,7 @@ int lighthouse_range(const building * b)
|
|||
|
||||
int lighthouse_view_distance(const building * b, const unit *u)
|
||||
{
|
||||
if (b->size >= 10 && (b->flags & BLD_MAINTAINED)) {
|
||||
if (b->size >= 10 && building_is_active(b)) {
|
||||
int maxd = lighthouse_range(b);
|
||||
|
||||
if (maxd > 0 && u && skill_enabled(SK_PERCEPTION)) {
|
||||
|
@ -112,13 +119,19 @@ bool lighthouse_guarded(const region * r)
|
|||
for (a = a_find(r->attribs, &at_lighthouse); a && a->type == &at_lighthouse;
|
||||
a = a->next) {
|
||||
building *b = (building *)a->data.v;
|
||||
|
||||
assert(is_building_type(b->type, "lighthouse"));
|
||||
if ((b->flags & BLD_MAINTAINED) && b->size >= 10) {
|
||||
int maxd = (int)log10(b->size) + 1;
|
||||
int d = distance(r, b->region);
|
||||
assert(maxd >= d);
|
||||
return true;
|
||||
if (building_is_active(b)) {
|
||||
if (r == b->region) {
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
int maxd = lighthouse_range(b);
|
||||
if (maxd > 0) {
|
||||
int d = distance(r, b->region);
|
||||
if (maxd >= d) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -20,7 +20,7 @@ extern "C" {
|
|||
bool is_lighthouse(const struct building_type *btype);
|
||||
bool lighthouse_guarded(const struct region *r);
|
||||
void update_lighthouse(struct building *b);
|
||||
void remove_lighthouse(const struct building *lh);
|
||||
bool update_lighthouses(struct region *r);
|
||||
int lighthouse_range(const struct building *b);
|
||||
int lighthouse_view_distance(const struct building *b, const struct unit *u);
|
||||
|
||||
|
|
|
@ -30,8 +30,6 @@ static void test_lighthouse_range(CuTest * tc)
|
|||
b->size = 9;
|
||||
CuAssertIntEquals(tc, 0, lighthouse_range(b));
|
||||
b->size = 10;
|
||||
CuAssertIntEquals(tc, 0, lighthouse_range(b));
|
||||
b->flags |= BLD_MAINTAINED;
|
||||
CuAssertIntEquals(tc, 2, lighthouse_range(b));
|
||||
u1->building = b;
|
||||
u2->building = b;
|
||||
|
@ -53,6 +51,9 @@ static void test_lighthouse_range(CuTest * tc)
|
|||
b->size = 99;
|
||||
CuAssertIntEquals(tc, 2, lighthouse_view_distance(b, u1));
|
||||
|
||||
b->flags |= BLD_UNMAINTAINED;
|
||||
CuAssertIntEquals(tc, 0, lighthouse_view_distance(b, u1));
|
||||
|
||||
test_teardown();
|
||||
}
|
||||
|
||||
|
@ -70,7 +71,7 @@ static void test_lighthouse_update(CuTest * tc)
|
|||
r3 = test_create_region(2, 0, t_ocean);
|
||||
r4 = test_create_region(0, 1, t_plain);
|
||||
b = test_create_building(r1, test_create_buildingtype("lighthouse"));
|
||||
b->flags |= BLD_MAINTAINED;
|
||||
update_lighthouse(b);
|
||||
CuAssertIntEquals(tc, RF_LIGHTHOUSE, r1->flags&RF_LIGHTHOUSE);
|
||||
CuAssertPtrEquals(tc, NULL, r1->attribs);
|
||||
CuAssertPtrEquals(tc, NULL, r2->attribs);
|
||||
|
@ -112,7 +113,6 @@ static void test_lighthouse_guard(CuTest * tc) {
|
|||
r3 = test_create_region(2, 0, t_ocean);
|
||||
r4 = test_create_region(0, 1, t_plain);
|
||||
b = test_create_building(r1, test_create_buildingtype("lighthouse"));
|
||||
b->flags |= BLD_MAINTAINED;
|
||||
b->size = 10;
|
||||
CuAssertIntEquals(tc, 2, lighthouse_range(b));
|
||||
update_lighthouse(b);
|
||||
|
@ -126,6 +126,7 @@ static void test_lighthouse_guard(CuTest * tc) {
|
|||
CuAssertIntEquals(tc, true, lighthouse_guarded(r3));
|
||||
CuAssertIntEquals(tc, false, lighthouse_guarded(r4));
|
||||
b->size = 1; /* size can go down in destroy_cmd */
|
||||
update_lighthouse(b);
|
||||
CuAssertIntEquals(tc, false, lighthouse_guarded(r2));
|
||||
CuAssertIntEquals(tc, false, lighthouse_guarded(r3));
|
||||
test_teardown();
|
||||
|
|
34
src/main.c
34
src/main.c
|
@ -17,6 +17,7 @@
|
|||
#include "gmtool.h"
|
||||
#endif
|
||||
|
||||
#include "signals.h"
|
||||
#include "bindings.h"
|
||||
|
||||
#include <iniparser.h>
|
||||
|
@ -247,39 +248,6 @@ static int parse_args(int argc, char **argv)
|
|||
return 0;
|
||||
}
|
||||
|
||||
#ifdef HAVE_BACKTRACE
|
||||
#include <execinfo.h>
|
||||
#include <signal.h>
|
||||
static void *btrace[50];
|
||||
|
||||
static void report_segfault(int signo, siginfo_t * sinf, void *arg)
|
||||
{
|
||||
size_t size;
|
||||
int fd = fileno(stderr);
|
||||
|
||||
fflush(stdout);
|
||||
fputs("\n\nProgram received SIGSEGV, backtrace follows.\n", stderr);
|
||||
size = backtrace(btrace, 50);
|
||||
backtrace_symbols_fd(btrace, size, fd);
|
||||
abort();
|
||||
}
|
||||
|
||||
static int setup_signal_handler(void)
|
||||
{
|
||||
struct sigaction act;
|
||||
|
||||
act.sa_flags = SA_RESETHAND | SA_SIGINFO;
|
||||
act.sa_sigaction = report_segfault;
|
||||
sigfillset(&act.sa_mask);
|
||||
return sigaction(SIGSEGV, &act, NULL);
|
||||
}
|
||||
#else
|
||||
static int setup_signal_handler(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
void locale_init(void)
|
||||
{
|
||||
setlocale(LC_CTYPE, "");
|
||||
|
|
|
@ -65,7 +65,6 @@ static void test_market_curse(CuTest * tc)
|
|||
}
|
||||
r = findregion(1, 1);
|
||||
b = test_create_building(r, btype);
|
||||
b->flags |= BLD_MAINTAINED;
|
||||
b->size = b->type->maxsize;
|
||||
|
||||
f = test_create_faction(NULL);
|
||||
|
|
|
@ -124,7 +124,7 @@ order * ord)
|
|||
UNUSED_ARG(amount);
|
||||
|
||||
/* Pruefen ob in Eingangshalle */
|
||||
if (u->region->x != 9525 || u->region->y != 9525) {
|
||||
if (warden == NULL || u->region->x != 9525 || u->region->y != 9525) {
|
||||
cmistake(u, ord, 266, MSG_MAGIC);
|
||||
return 0;
|
||||
}
|
||||
|
|
19
src/move.c
19
src/move.c
|
@ -1157,12 +1157,19 @@ static bool can_move(const unit * u)
|
|||
return true;
|
||||
}
|
||||
|
||||
static void init_transportation(void)
|
||||
static void init_movement(void)
|
||||
{
|
||||
region *r;
|
||||
|
||||
for (r = regions; r; r = r->next) {
|
||||
unit *u;
|
||||
building *b;
|
||||
|
||||
for (b = r->buildings; b; b = b->next) {
|
||||
if (is_lighthouse(b->type)) {
|
||||
update_lighthouse(b);
|
||||
}
|
||||
}
|
||||
|
||||
/* This is just a simple check for non-corresponding K_TRANSPORT/
|
||||
* K_DRIVE. This is time consuming for an error check, but there
|
||||
|
@ -1612,9 +1619,9 @@ static const region_list *travel_route(unit * u,
|
|||
/* Berichte ueber Durchreiseregionen */
|
||||
|
||||
if (mode != TRAVEL_TRANSPORTED) {
|
||||
arg_regions ar;
|
||||
arg_regions *arp = NULL;
|
||||
if (steps > 1) {
|
||||
arg_regions ar;
|
||||
arp = &ar;
|
||||
var_create_regions(arp, route_begin, steps - 1);
|
||||
}
|
||||
|
@ -2192,8 +2199,8 @@ void move_cmd_ex(unit * u, order * ord, const char *directions)
|
|||
init_order(ord, u->faction->locale);
|
||||
}
|
||||
if (u->ship && u == ship_owner(u->ship)) {
|
||||
bool drifting = (getkeyword(ord) == K_MOVE);
|
||||
sail(u, ord, drifting);
|
||||
keyword_t kwd = getkeyword(ord);
|
||||
sail(u, ord, (kwd == K_MOVE || kwd == K_ROUTE));
|
||||
}
|
||||
else {
|
||||
travel(u, ord);
|
||||
|
@ -2409,8 +2416,8 @@ void movement(void)
|
|||
{
|
||||
int ships;
|
||||
|
||||
/* Initialize the additional encumbrance by transported units */
|
||||
init_transportation();
|
||||
/* Initialize lighthouses and additional encumbrance by transported units */
|
||||
init_movement();
|
||||
|
||||
/* Move ships in last phase, others first
|
||||
* This is to make sure you can't land someplace and then get off the ship
|
||||
|
|
|
@ -84,7 +84,6 @@ static void setup_harbor(move_fixture *mf) {
|
|||
r = test_create_region(0, 0, ttype);
|
||||
|
||||
b = test_create_building(r, btype);
|
||||
b->flags |= BLD_MAINTAINED;
|
||||
|
||||
u = test_create_unit(test_create_faction(NULL), r);
|
||||
u->ship = sh;
|
||||
|
|
|
@ -1182,11 +1182,13 @@ static void report_statistics(struct stream *out, const region * r, const factio
|
|||
if (max_production(r) && (!fval(r->terrain, SEA_REGION)
|
||||
|| f->race == get_race(RC_AQUARIAN))) {
|
||||
if (markets_module()) { /* hack */
|
||||
bool mourn = is_mourning(r, turn);
|
||||
int p_wage = peasant_wage(r, mourn);
|
||||
m =
|
||||
msg_message("nr_stat_salary_new", "max", wage(r, NULL, NULL, turn + 1));
|
||||
msg_message("nr_stat_salary_new", "max", p_wage);
|
||||
}
|
||||
else {
|
||||
m = msg_message("nr_stat_salary", "max", wage(r, f, f->race, turn + 1));
|
||||
m = msg_message("nr_stat_salary", "max", wage(r, f->race));
|
||||
}
|
||||
nr_render(m, f->locale, buf, sizeof(buf), f);
|
||||
paragraph(out, buf, 2, 2, 0);
|
||||
|
@ -1337,7 +1339,7 @@ report_template(const char *filename, report_context * ctx, const char *bom)
|
|||
}
|
||||
rps_nowrap(out, buf);
|
||||
newline(out);
|
||||
sprintf(buf, "; ECheck Lohn %d", wage(r, f, f->race, turn + 1));
|
||||
sprintf(buf, "; ECheck Lohn %d", wage(r, f->race));
|
||||
rps_nowrap(out, buf);
|
||||
newline(out);
|
||||
newline(out);
|
||||
|
|
|
@ -1652,9 +1652,13 @@ static void check_messages_exist(void) {
|
|||
int init_reports(void)
|
||||
{
|
||||
region *r;
|
||||
bool update = true;
|
||||
check_messages_exist();
|
||||
create_directories();
|
||||
for (r = regions; r; r = r->next) {
|
||||
if (update) {
|
||||
update = update_lighthouses(r);
|
||||
}
|
||||
reorder_units(r);
|
||||
}
|
||||
return 0;
|
||||
|
|
|
@ -503,7 +503,6 @@ void test_prepare_lighthouse_capacity(CuTest *tc) {
|
|||
r1 = test_create_region(0, 0, t_plain);
|
||||
r2 = test_create_region(1, 0, t_ocean);
|
||||
b = test_create_building(r1, btype);
|
||||
b->flags |= BLD_MAINTAINED;
|
||||
b->size = 10;
|
||||
update_lighthouse(b);
|
||||
u1 = test_create_unit(test_create_faction(NULL), r1);
|
||||
|
@ -561,7 +560,6 @@ static void test_prepare_lighthouse(CuTest *tc) {
|
|||
r4 = test_create_region(0, 1, t_plain);
|
||||
btype = test_create_buildingtype("lighthouse");
|
||||
b = test_create_building(r1, btype);
|
||||
b->flags |= BLD_MAINTAINED;
|
||||
b->size = 10;
|
||||
update_lighthouse(b);
|
||||
u = test_create_unit(f, r1);
|
||||
|
@ -605,7 +603,6 @@ static void test_prepare_lighthouse_owners(CuTest *tc)
|
|||
r3 = test_create_region(3, 0, t_ocean);
|
||||
btype = test_create_buildingtype("lighthouse");
|
||||
b = test_create_building(r1, btype);
|
||||
b->flags |= BLD_MAINTAINED;
|
||||
b->size = 10;
|
||||
update_lighthouse(b);
|
||||
test_create_unit(f, r1);
|
||||
|
|
|
@ -0,0 +1,35 @@
|
|||
#ifdef HAVE_BACKTRACE
|
||||
#include <execinfo.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <signal.h>
|
||||
static void *btrace[50];
|
||||
|
||||
static void report_segfault(int signo, siginfo_t * sinf, void *arg)
|
||||
{
|
||||
size_t size;
|
||||
int fd = fileno(stderr);
|
||||
|
||||
fflush(stdout);
|
||||
fputs("\n\nProgram received SIGSEGV, backtrace follows.\n", stderr);
|
||||
size = backtrace(btrace, 50);
|
||||
backtrace_symbols_fd(btrace, size, fd);
|
||||
abort();
|
||||
}
|
||||
|
||||
int setup_signal_handler(void)
|
||||
{
|
||||
struct sigaction act;
|
||||
|
||||
act.sa_flags = SA_RESETHAND | SA_SIGINFO;
|
||||
act.sa_sigaction = report_segfault;
|
||||
sigfillset(&act.sa_mask);
|
||||
return sigaction(SIGSEGV, &act, 0);
|
||||
}
|
||||
#else
|
||||
int setup_signal_handler(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
#pragma once
|
||||
|
||||
int setup_signal_handler(void);
|
||||
|
370
src/study.c
370
src/study.c
|
@ -8,7 +8,6 @@
|
|||
#include "move.h"
|
||||
#include "monsters.h"
|
||||
#include "alchemy.h"
|
||||
#include "academy.h"
|
||||
#include "kernel/calendar.h"
|
||||
|
||||
#include <spells/regioncurse.h>
|
||||
|
@ -154,37 +153,37 @@ const attrib_type at_learning = {
|
|||
|
||||
#define EXPERIENCEDAYS 10
|
||||
|
||||
static int study_days(unit * scholar, skill_t sk)
|
||||
static int study_days(unit * u, skill_t sk)
|
||||
{
|
||||
int speed = STUDYDAYS;
|
||||
if (u_race(scholar)->study_speed) {
|
||||
speed += u_race(scholar)->study_speed[sk];
|
||||
if (u_race(u)->study_speed) {
|
||||
speed += u_race(u)->study_speed[sk];
|
||||
if (speed < STUDYDAYS) {
|
||||
skill *sv = unit_skill(scholar, sk);
|
||||
skill *sv = unit_skill(u, sk);
|
||||
if (sv == 0) {
|
||||
speed = STUDYDAYS;
|
||||
}
|
||||
}
|
||||
}
|
||||
return scholar->number * speed;
|
||||
return u->number * speed;
|
||||
}
|
||||
|
||||
static int
|
||||
teach_unit(unit * teacher, unit * scholar, int nteaching, skill_t sk,
|
||||
teach_unit(unit * teacher, unit * student, int nteaching, skill_t sk,
|
||||
bool report, int *academy_students)
|
||||
{
|
||||
teaching_info *teach = NULL;
|
||||
attrib *a;
|
||||
int students;
|
||||
|
||||
if (magic_lowskill(scholar)) {
|
||||
if (magic_lowskill(student)) {
|
||||
cmistake(teacher, teacher->thisorder, 292, MSG_EVENT);
|
||||
return 0;
|
||||
}
|
||||
|
||||
students = scholar->number;
|
||||
students = student->number;
|
||||
/* subtract already taught students */
|
||||
a = a_find(scholar->attribs, &at_learning);
|
||||
a = a_find(student->attribs, &at_learning);
|
||||
if (a != NULL) {
|
||||
teach = (teaching_info *)a->data.v;
|
||||
students -= teach->students;
|
||||
|
@ -194,18 +193,16 @@ teach_unit(unit * teacher, unit * scholar, int nteaching, skill_t sk,
|
|||
|
||||
if (students > 0) {
|
||||
if (teach == NULL) {
|
||||
a = a_add(&scholar->attribs, a_new(&at_learning));
|
||||
a = a_add(&student->attribs, a_new(&at_learning));
|
||||
teach = (teaching_info *)a->data.v;
|
||||
}
|
||||
selist_push(&teach->teachers, teacher);
|
||||
teach->days += students * STUDYDAYS;
|
||||
teach->students += students;
|
||||
|
||||
if (scholar->building) {
|
||||
/* Solange Akademien groessenbeschraenkt sind, sollte Lehrer und
|
||||
* Student auch in unterschiedlichen Gebaeuden stehen duerfen */
|
||||
/* FIXME comment contradicts implementation */
|
||||
if (academy_can_teach(teacher, scholar, sk)) {
|
||||
if (student->building) {
|
||||
const struct building_type *btype = bt_find("academy");
|
||||
if (active_building(student, btype)) {
|
||||
/* Jeder Schueler zusaetzlich +10 Tage wenn in Uni. */
|
||||
teach->days += students * EXPERIENCEDAYS; /* learning erhoehen */
|
||||
/* Lehrer zusaetzlich +1 Tag pro Schueler. */
|
||||
|
@ -258,12 +255,12 @@ int teach_cmd(unit * teacher, struct order *ord)
|
|||
|
||||
count = 0;
|
||||
|
||||
#if TEACH_ALL
|
||||
init_order(ord, NULL);
|
||||
|
||||
#if TEACH_ALL
|
||||
if (getparam(teacher->faction->locale) == P_ANY) {
|
||||
skill_t sk;
|
||||
unit *scholar;
|
||||
unit *student;
|
||||
skill_t teachskill[MAXSKILLS];
|
||||
int t = 0;
|
||||
|
||||
|
@ -272,15 +269,15 @@ int teach_cmd(unit * teacher, struct order *ord)
|
|||
teachskill[t] = getskill(teacher->faction->locale);
|
||||
} while (sk != NOSKILL);
|
||||
|
||||
for (scholar = r->units; teaching > 0 && scholar; scholar = scholar->next) {
|
||||
if (LongHunger(scholar)) {
|
||||
for (student = r->units; teaching > 0 && student; student = student->next) {
|
||||
if (LongHunger(student)) {
|
||||
continue;
|
||||
}
|
||||
else if (scholar->faction == teacher->faction) {
|
||||
if (getkeyword(scholar->thisorder) == K_STUDY) {
|
||||
else if (student->faction == teacher->faction) {
|
||||
if (getkeyword(student->thisorder) == K_STUDY) {
|
||||
/* Input ist nun von student->thisorder !! */
|
||||
init_order(scholar->thisorder, scholar->faction->locale);
|
||||
sk = getskill(scholar->faction->locale);
|
||||
init_order(student->thisorder, student->faction->locale);
|
||||
sk = getskill(student->faction->locale);
|
||||
if (sk != NOSKILL && teachskill[0] != NOSKILL) {
|
||||
for (t = 0; teachskill[t] != NOSKILL; ++t) {
|
||||
if (sk == teachskill[t]) {
|
||||
|
@ -290,20 +287,20 @@ int teach_cmd(unit * teacher, struct order *ord)
|
|||
sk = teachskill[t];
|
||||
}
|
||||
if (sk != NOSKILL
|
||||
&& effskill_study(teacher, sk) - TEACHDIFFERENCE > effskill_study(scholar, sk)) {
|
||||
teaching -= teach_unit(teacher, scholar, teaching, sk, true, &academy_students);
|
||||
&& effskill_study(teacher, sk) - TEACHDIFFERENCE > effskill_study(student, sk)) {
|
||||
teaching -= teach_unit(teacher, student, teaching, sk, true, &academy_students);
|
||||
}
|
||||
}
|
||||
}
|
||||
#ifdef TEACH_FRIENDS
|
||||
else if (alliedunit(teacher, scholar->faction, HELP_GUARD)) {
|
||||
if (getkeyword(scholar->thisorder) == K_STUDY) {
|
||||
else if (alliedunit(teacher, student->faction, HELP_GUARD)) {
|
||||
if (getkeyword(student->thisorder) == K_STUDY) {
|
||||
/* Input ist nun von student->thisorder !! */
|
||||
init_order(scholar->thisorder, scholar->faction->locale);
|
||||
sk = getskill(scholar->faction->locale);
|
||||
init_order(student->thisorder, student->faction->locale);
|
||||
sk = getskill(student->faction->locale);
|
||||
if (sk != NOSKILL
|
||||
&& effskill_study(teacher, sk) - TEACHDIFFERENCE >= effskill(scholar, sk, NULL)) {
|
||||
teaching -= teach_unit(teacher, scholar, teaching, sk, true, &academy_students);
|
||||
&& effskill_study(teacher, sk) - TEACHDIFFERENCE >= effskill(student, sk, NULL)) {
|
||||
teaching -= teach_unit(teacher, student, teaching, sk, true, &academy_students);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -322,15 +319,15 @@ int teach_cmd(unit * teacher, struct order *ord)
|
|||
|
||||
while (!parser_end()) {
|
||||
skill_t sk;
|
||||
unit *scholar;
|
||||
unit *student;
|
||||
bool feedback;
|
||||
|
||||
getunit(r, teacher->faction, &scholar);
|
||||
getunit(r, teacher->faction, &student);
|
||||
++count;
|
||||
|
||||
/* Falls die Unit nicht gefunden wird, Fehler melden */
|
||||
|
||||
if (!scholar) {
|
||||
if (!student) {
|
||||
char tbuf[20];
|
||||
const char *uid;
|
||||
const char *token;
|
||||
|
@ -362,8 +359,8 @@ int teach_cmd(unit * teacher, struct order *ord)
|
|||
continue;
|
||||
}
|
||||
|
||||
feedback = teacher->faction == scholar->faction
|
||||
|| alliedunit(scholar, teacher->faction, HELP_GUARD);
|
||||
feedback = teacher->faction == student->faction
|
||||
|| alliedunit(student, teacher->faction, HELP_GUARD);
|
||||
|
||||
/* Neuen Befehl zusammenbauen. TEMP-Einheiten werden automatisch in
|
||||
* ihre neuen Nummern uebersetzt. */
|
||||
|
@ -371,102 +368,63 @@ int teach_cmd(unit * teacher, struct order *ord)
|
|||
strncat(zOrder, " ", sz - 1);
|
||||
--sz;
|
||||
}
|
||||
sz -= str_strlcpy(zOrder + 4096 - sz, itoa36(scholar->no), sz);
|
||||
sz -= str_strlcpy(zOrder + 4096 - sz, itoa36(student->no), sz);
|
||||
|
||||
if (getkeyword(scholar->thisorder) != K_STUDY) {
|
||||
if (getkeyword(student->thisorder) != K_STUDY) {
|
||||
ADDMSG(&teacher->faction->msgs,
|
||||
msg_feedback(teacher, ord, "teach_nolearn", "student", scholar));
|
||||
msg_feedback(teacher, ord, "teach_nolearn", "student", student));
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Input ist nun von student->thisorder !! */
|
||||
parser_pushstate();
|
||||
init_order(scholar->thisorder, scholar->faction->locale);
|
||||
sk = getskill(scholar->faction->locale);
|
||||
init_order(student->thisorder, student->faction->locale);
|
||||
sk = getskill(student->faction->locale);
|
||||
parser_popstate();
|
||||
|
||||
if (sk == NOSKILL) {
|
||||
ADDMSG(&teacher->faction->msgs,
|
||||
msg_feedback(teacher, ord, "teach_nolearn", "student", scholar));
|
||||
msg_feedback(teacher, ord, "teach_nolearn", "student", student));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (effskill_study(scholar, sk) > effskill_study(teacher, sk)
|
||||
if (effskill_study(student, sk) > effskill_study(teacher, sk)
|
||||
- TEACHDIFFERENCE) {
|
||||
if (feedback) {
|
||||
ADDMSG(&teacher->faction->msgs, msg_feedback(teacher, ord, "teach_asgood",
|
||||
"student", scholar));
|
||||
"student", student));
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (sk == SK_MAGIC) {
|
||||
/* ist der Magier schon spezialisiert, so versteht er nur noch
|
||||
* Lehrer seines Gebietes */
|
||||
magic_t mage2 = unit_get_magic(scholar);
|
||||
magic_t mage2 = unit_get_magic(student);
|
||||
if (mage2 != M_GRAY) {
|
||||
magic_t mage1 = unit_get_magic(teacher);
|
||||
if (mage1 != mage2) {
|
||||
if (feedback) {
|
||||
ADDMSG(&teacher->faction->msgs, msg_feedback(teacher, ord,
|
||||
"error_different_magic", "target", scholar));
|
||||
"error_different_magic", "target", student));
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
sk_academy = sk;
|
||||
teaching -= teach_unit(teacher, scholar, teaching, sk, false, &academy_students);
|
||||
teaching -= teach_unit(teacher, student, teaching, sk, false, &academy_students);
|
||||
}
|
||||
new_order = create_order(K_TEACH, teacher->faction->locale, "%s", zOrder);
|
||||
replace_order(&teacher->orders, ord, new_order);
|
||||
free_order(new_order); /* parse_order & set_order have each increased the refcount */
|
||||
}
|
||||
if (academy_students > 0 && sk_academy!=NOSKILL) {
|
||||
academy_teaching_bonus(teacher, sk_academy, academy_students);
|
||||
if (academy_students > 0 && sk_academy != NOSKILL) {
|
||||
change_skill_days(teacher, sk_academy, academy_students);
|
||||
}
|
||||
reset_order();
|
||||
return 0;
|
||||
}
|
||||
|
||||
typedef enum study_rule_t {
|
||||
STUDY_DEFAULT = 0,
|
||||
STUDY_FASTER = 1,
|
||||
STUDY_AUTOTEACH = 2
|
||||
} study_rule_t;
|
||||
|
||||
static double study_speedup(unit * u, skill_t s, study_rule_t rule)
|
||||
{
|
||||
#define MINTURN 16
|
||||
if (turn > MINTURN) {
|
||||
if (rule == STUDY_FASTER) {
|
||||
double learnweeks = 0;
|
||||
int i;
|
||||
for (i = 0; i != u->skill_size; ++i) {
|
||||
skill *sv = u->skills + i;
|
||||
if (sv->id == s) {
|
||||
learnweeks = sv->level * (sv->level + 1) / 2.0;
|
||||
if (learnweeks < turn / 3.0) {
|
||||
return 2.0;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 2.0; /* If the skill was not found it is the first study. */
|
||||
}
|
||||
if (rule == STUDY_AUTOTEACH) {
|
||||
double learnweeks = 0;
|
||||
int i;
|
||||
for (i = 0; i != u->skill_size; ++i) {
|
||||
skill *sv = u->skills + i;
|
||||
learnweeks += (sv->level * (sv->level + 1) / 2.0);
|
||||
}
|
||||
if (learnweeks < turn / 2.0) {
|
||||
return 2.0;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 1.0;
|
||||
}
|
||||
|
||||
static bool ExpensiveMigrants(void)
|
||||
{
|
||||
static bool rule;
|
||||
|
@ -552,17 +510,12 @@ bool check_student(const struct unit *u, struct order *ord, skill_t sk) {
|
|||
|
||||
int study_cmd(unit * u, order * ord)
|
||||
{
|
||||
region *r = u->region;
|
||||
int p;
|
||||
int l;
|
||||
int studycost, days;
|
||||
double multi = 1.0;
|
||||
attrib *a = NULL;
|
||||
teaching_info *teach = NULL;
|
||||
int money = 0;
|
||||
skill_t sk;
|
||||
int maxalchemy = 0;
|
||||
int speed_rule = (study_rule_t)config_get_int("study.speedup", 0);
|
||||
static const race *rc_snotling;
|
||||
static int rc_cache;
|
||||
|
||||
|
@ -585,7 +538,6 @@ int study_cmd(unit * u, order * ord)
|
|||
}
|
||||
}
|
||||
|
||||
p = studycost = study_cost(u, sk);
|
||||
a = a_find(u->attribs, &at_learning);
|
||||
if (a != NULL) {
|
||||
teach = (teaching_info *)a->data.v;
|
||||
|
@ -594,16 +546,13 @@ int study_cmd(unit * u, order * ord)
|
|||
/* keine kostenpflichtigen Talente fuer Migranten. Vertraute sind
|
||||
* keine Migranten, wird in is_migrant abgefangen. Vorsicht,
|
||||
* studycost darf hier noch nicht durch Akademie erhoeht sein */
|
||||
studycost = study_cost(u, sk);
|
||||
|
||||
if (studycost > 0 && !ExpensiveMigrants() && is_migrant(u)) {
|
||||
ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "error_migrants_nolearn",
|
||||
""));
|
||||
return -1;
|
||||
}
|
||||
/* Akademie: */
|
||||
if (active_building(u, bt_find("academy"))) {
|
||||
studycost = studycost * 2;
|
||||
if (studycost < 50) studycost = 50;
|
||||
}
|
||||
|
||||
if (sk == SK_MAGIC) {
|
||||
magic_t mtype;
|
||||
|
@ -684,71 +633,31 @@ int study_cmd(unit * u, order * ord)
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
days = teach ? teach->days : 0;
|
||||
days += study_days(u, sk);
|
||||
|
||||
if (studycost) {
|
||||
int cost = studycost * u->number;
|
||||
money = get_pooled(u, get_resourcetype(R_SILVER), GET_DEFAULT, cost);
|
||||
if (money > cost) money = cost;
|
||||
}
|
||||
if (money < studycost * u->number) {
|
||||
studycost = p; /* Ohne Univertreurung */
|
||||
if (money > studycost) money = studycost;
|
||||
if (p > 0 && money < studycost * u->number) {
|
||||
cmistake(u, ord, 65, MSG_EVENT);
|
||||
multi = money / (double)(studycost * u->number);
|
||||
if (money < studycost * u->number) {
|
||||
int cost = studycost * u->number;
|
||||
if (money > studycost) money = studycost;
|
||||
if (money < cost) {
|
||||
/* we cannot afford everyone, but use as much as we have */
|
||||
cmistake(u, ord, 65, MSG_EVENT);
|
||||
days = days * money / cost;
|
||||
}
|
||||
}
|
||||
}
|
||||
money += learn_skill(u, sk, days, studycost);
|
||||
|
||||
if (teach == NULL) {
|
||||
a = a_add(&u->attribs, a_new(&at_learning));
|
||||
teach = (teaching_info *)a->data.v;
|
||||
assert(teach);
|
||||
teach->teachers = NULL;
|
||||
}
|
||||
if (money > 0) {
|
||||
use_pooled(u, get_resourcetype(R_SILVER), GET_DEFAULT, money);
|
||||
ADDMSG(&u->faction->msgs, msg_message("studycost",
|
||||
"unit region cost skill", u, u->region, money, sk));
|
||||
}
|
||||
|
||||
if (get_effect(u, oldpotiontype[P_WISE])) {
|
||||
l = get_effect(u, oldpotiontype[P_WISE]);
|
||||
if (l > u->number) l = u->number;
|
||||
teach->days += l * EXPERIENCEDAYS;
|
||||
change_effect(u, oldpotiontype[P_WISE], -l);
|
||||
}
|
||||
if (get_effect(u, oldpotiontype[P_FOOL])) {
|
||||
l = get_effect(u, oldpotiontype[P_FOOL]);
|
||||
if (l > u->number) l = u->number;
|
||||
teach->days -= l * STUDYDAYS;
|
||||
change_effect(u, oldpotiontype[P_FOOL], -l);
|
||||
}
|
||||
|
||||
if (p != studycost) {
|
||||
/* ist_in_gebaeude(r, u, BT_UNIVERSITAET) == 1) { */
|
||||
/* p ist Kosten ohne Uni, studycost mit; wenn
|
||||
* p!=studycost, ist die Einheit zwangsweise
|
||||
* in einer Uni */
|
||||
teach->days += u->number * EXPERIENCEDAYS;
|
||||
}
|
||||
|
||||
if (is_cursed(r->attribs, &ct_badlearn)) {
|
||||
teach->days -= u->number * EXPERIENCEDAYS;
|
||||
}
|
||||
|
||||
multi *= study_speedup(u, sk, speed_rule);
|
||||
days = study_days(u, sk);
|
||||
days = (int)((days + teach->days) * multi);
|
||||
|
||||
/* the artacademy currently improves the learning of entertainment
|
||||
of all units in the region, to be able to make it cumulative with
|
||||
with an academy */
|
||||
|
||||
if (sk == SK_ENTERTAINMENT
|
||||
&& buildingtype_exists(r, bt_find("artacademy"), false)) {
|
||||
days *= 2;
|
||||
}
|
||||
|
||||
learn_skill(u, sk, days);
|
||||
if (a != NULL) {
|
||||
if (teach->teachers) {
|
||||
msg_teachers(teach->teachers, u, sk);
|
||||
|
@ -789,56 +698,133 @@ void produceexp_ex(struct unit *u, skill_t sk, int n, learn_fun learn)
|
|||
}
|
||||
}
|
||||
|
||||
void produceexp(struct unit *u, skill_t sk, int n)
|
||||
{
|
||||
produceexp_ex(u, sk, n, learn_skill);
|
||||
}
|
||||
|
||||
static learn_fun inject_learn_fun = 0;
|
||||
|
||||
void inject_learn(learn_fun fun) {
|
||||
inject_learn_fun = fun;
|
||||
}
|
||||
|
||||
/** days should be scaled by u->number; STUDYDAYS * u->number is one week worth of learning */
|
||||
void learn_skill(unit *u, skill_t sk, int days) {
|
||||
int leveldays = STUDYDAYS * u->number;
|
||||
int weeks = 0;
|
||||
static void increase_skill_days(unit *u, skill_t sk, int days) {
|
||||
assert(sk >= 0 && sk < MAXSKILLS && days >= 0);
|
||||
if (days > 0) {
|
||||
int leveldays = STUDYDAYS * u->number;
|
||||
int weeks = 0;
|
||||
if (inject_learn_fun) {
|
||||
inject_learn_fun(u, sk, days);
|
||||
return;
|
||||
}
|
||||
while (days >= leveldays) {
|
||||
++weeks;
|
||||
days -= leveldays;
|
||||
}
|
||||
if (days > 0 && rng_int() % leveldays < days) {
|
||||
++weeks;
|
||||
}
|
||||
if (weeks > 0) {
|
||||
increase_skill(u, sk, weeks);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void reduce_skill_days(unit *u, skill_t sk, int days) {
|
||||
if (days > 0) {
|
||||
skill *sv = unit_skill(u, sk);
|
||||
if (sv) {
|
||||
while (days > 0) {
|
||||
if (days >= STUDYDAYS * u->number) {
|
||||
reduce_skill(u, sv, 1);
|
||||
days -= STUDYDAYS;
|
||||
}
|
||||
else {
|
||||
if (chance(days / ((double)STUDYDAYS * u->number))) /* (rng_int() % (30 * u->number) < days)*/
|
||||
reduce_skill(u, sv, 1);
|
||||
days = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void produceexp(struct unit *u, skill_t sk, int n)
|
||||
{
|
||||
produceexp_ex(u, sk, n, increase_skill_days);
|
||||
}
|
||||
|
||||
/**
|
||||
* days should be scaled by u->number; STUDYDAYS * u->number is one week worth of learning
|
||||
* @return int
|
||||
* The additional spend, i.e. from an academy.
|
||||
*/
|
||||
int learn_skill(unit *u, skill_t sk, int days, int studycost) {
|
||||
region *r = u->region;
|
||||
int cost = 0;
|
||||
|
||||
if (r->buildings) {
|
||||
static const building_type *bt_artacademy;
|
||||
static const building_type *bt_academy;
|
||||
static int config;
|
||||
|
||||
if (bt_changed(&config)) {
|
||||
bt_artacademy = bt_find("artacademy");
|
||||
bt_academy = bt_find("academy");
|
||||
}
|
||||
|
||||
/* Akademie: */
|
||||
if (bt_academy && active_building(u, bt_academy)) {
|
||||
int avail, n = u->number;
|
||||
if (studycost < 50) studycost = 50;
|
||||
cost = studycost * u->number;
|
||||
avail = get_pooled(u, get_resourcetype(R_SILVER), GET_DEFAULT, studycost * u->number);
|
||||
if (avail < cost) {
|
||||
/* not all students can afford the academy */
|
||||
n = n * avail / cost;
|
||||
cost = n * studycost;
|
||||
}
|
||||
days += EXPERIENCEDAYS * n;
|
||||
}
|
||||
|
||||
/* the artacademy currently improves the learning of entertainment
|
||||
of all units in the region, to be able to make it cumulative with
|
||||
with an academy */
|
||||
|
||||
if (bt_artacademy && sk == SK_ENTERTAINMENT
|
||||
&& buildingtype_exists(r, bt_artacademy, false)) {
|
||||
days *= 2;
|
||||
}
|
||||
}
|
||||
|
||||
if (u->attribs) {
|
||||
if (get_effect(u, oldpotiontype[P_WISE])) {
|
||||
int effect = get_effect(u, oldpotiontype[P_WISE]);
|
||||
if (effect > u->number) effect = u->number;
|
||||
days += effect * EXPERIENCEDAYS;
|
||||
change_effect(u, oldpotiontype[P_WISE], -effect);
|
||||
}
|
||||
if (get_effect(u, oldpotiontype[P_FOOL])) {
|
||||
int effect = get_effect(u, oldpotiontype[P_FOOL]);
|
||||
if (effect > u->number) effect = u->number;
|
||||
days -= effect * STUDYDAYS;
|
||||
change_effect(u, oldpotiontype[P_FOOL], -effect);
|
||||
}
|
||||
}
|
||||
|
||||
if (is_cursed(r->attribs, &ct_badlearn)) {
|
||||
days -= EXPERIENCEDAYS * u->number;
|
||||
}
|
||||
|
||||
if (fval(u, UFL_HUNGER)) {
|
||||
days /= 2;
|
||||
}
|
||||
assert(sk >= 0 && sk < MAXSKILLS);
|
||||
if (inject_learn_fun) {
|
||||
inject_learn_fun(u, sk, days);
|
||||
return;
|
||||
}
|
||||
while (days >= leveldays) {
|
||||
++weeks;
|
||||
days -= leveldays;
|
||||
}
|
||||
if (days > 0 && rng_int() % leveldays < days) {
|
||||
++weeks;
|
||||
}
|
||||
if (weeks > 0) {
|
||||
increase_skill(u, sk, weeks);
|
||||
}
|
||||
increase_skill_days(u, sk, days);
|
||||
return cost;
|
||||
}
|
||||
|
||||
void reduce_skill_days(unit *u, skill_t sk, int days) {
|
||||
skill *sv = unit_skill(u, sk);
|
||||
if (sv) {
|
||||
while (days > 0) {
|
||||
if (days >= STUDYDAYS * u->number) {
|
||||
reduce_skill(u, sv, 1);
|
||||
days -= STUDYDAYS;
|
||||
}
|
||||
else {
|
||||
if (chance (days / ((double) STUDYDAYS * u->number))) /* (rng_int() % (30 * u->number) < days)*/
|
||||
reduce_skill(u, sv, 1);
|
||||
days = 0;
|
||||
}
|
||||
}
|
||||
void change_skill_days(unit *u, skill_t sk, int days) {
|
||||
if (days < 0) {
|
||||
reduce_skill_days(u, sk, -days);
|
||||
}
|
||||
else {
|
||||
increase_skill_days(u, sk, days);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -885,7 +871,7 @@ void demon_skillchange(unit *u)
|
|||
}
|
||||
}
|
||||
else {
|
||||
learn_skill(u, sv->id, STUDYDAYS * u->number * weeks);
|
||||
change_skill_days(u, sv->id, STUDYDAYS * u->number * weeks);
|
||||
}
|
||||
}
|
||||
++sv;
|
||||
|
|
|
@ -34,8 +34,8 @@ extern "C" {
|
|||
|
||||
typedef void(*learn_fun)(struct unit *u, skill_t sk, int days);
|
||||
|
||||
void learn_skill(struct unit *u, skill_t sk, int days);
|
||||
void reduce_skill_days(struct unit *u, skill_t sk, int days);
|
||||
int learn_skill(struct unit *u, skill_t sk, int days, int studycost);
|
||||
void change_skill_days(struct unit *u, skill_t sk, int days);
|
||||
|
||||
void produceexp(struct unit *u, skill_t sk, int n);
|
||||
void produceexp_ex(struct unit *u, skill_t sk, int n, learn_fun learn);
|
||||
|
|
|
@ -204,7 +204,6 @@ static void test_study_bug_2194(CuTest *tc) {
|
|||
u_set_building(u2, b);
|
||||
i_change(&u1->items, get_resourcetype(R_SILVER)->itype, 50);
|
||||
i_change(&u2->items, get_resourcetype(R_SILVER)->itype, 50);
|
||||
b->flags = BLD_MAINTAINED;
|
||||
learn_inject();
|
||||
teach_cmd(u, u->thisorder);
|
||||
learn_reset();
|
||||
|
@ -280,7 +279,6 @@ static void test_academy_building(CuTest *tc) {
|
|||
u_set_building(u2, b);
|
||||
i_change(&u1->items, get_resourcetype(R_SILVER)->itype, 50);
|
||||
i_change(&u2->items, get_resourcetype(R_SILVER)->itype, 50);
|
||||
b->flags = BLD_MAINTAINED;
|
||||
learn_inject();
|
||||
teach_cmd(u, u->thisorder);
|
||||
learn_reset();
|
||||
|
@ -335,7 +333,6 @@ static void test_academy_bonus(CuTest *tc) {
|
|||
scale_number(u1, 9);
|
||||
scale_number(u3, 2);
|
||||
i_change(&u1->items, get_resourcetype(R_SILVER)->itype, 5000);
|
||||
b->flags = BLD_MAINTAINED;
|
||||
|
||||
learn_inject();
|
||||
teach_cmd(u0, u0->thisorder);
|
||||
|
@ -364,14 +361,14 @@ void test_learn_skill_single(CuTest *tc) {
|
|||
setup_study();
|
||||
config_set("study.random_progress", "0");
|
||||
u = test_create_unit(test_create_faction(NULL), test_create_region(0, 0, NULL));
|
||||
learn_skill(u, SK_ALCHEMY, STUDYDAYS);
|
||||
CuAssertIntEquals(tc, 0, learn_skill(u, SK_ALCHEMY, STUDYDAYS, 0));
|
||||
CuAssertPtrNotNull(tc, sv = u->skills);
|
||||
CuAssertIntEquals(tc, SK_ALCHEMY, sv->id);
|
||||
CuAssertIntEquals(tc, 1, sv->level);
|
||||
CuAssertIntEquals(tc, 2, sv->weeks);
|
||||
learn_skill(u, SK_ALCHEMY, STUDYDAYS);
|
||||
CuAssertIntEquals(tc, 0, learn_skill(u, SK_ALCHEMY, STUDYDAYS, 0));
|
||||
CuAssertIntEquals(tc, 1, sv->weeks);
|
||||
learn_skill(u, SK_ALCHEMY, STUDYDAYS * 2);
|
||||
CuAssertIntEquals(tc, 0, learn_skill(u, SK_ALCHEMY, STUDYDAYS * 2, 0));
|
||||
CuAssertIntEquals(tc, 2, sv->level);
|
||||
CuAssertIntEquals(tc, 2, sv->weeks);
|
||||
test_teardown();
|
||||
|
@ -385,14 +382,14 @@ void test_learn_skill_multi(CuTest *tc) {
|
|||
config_set("study.random_progress", "0");
|
||||
u = test_create_unit(test_create_faction(NULL), test_create_region(0, 0, NULL));
|
||||
scale_number(u, 10);
|
||||
learn_skill(u, SK_ALCHEMY, STUDYDAYS * u->number);
|
||||
CuAssertIntEquals(tc, 0, learn_skill(u, SK_ALCHEMY, STUDYDAYS * u->number, 0));
|
||||
CuAssertPtrNotNull(tc, sv = u->skills);
|
||||
CuAssertIntEquals(tc, SK_ALCHEMY, sv->id);
|
||||
CuAssertIntEquals(tc, 1, sv->level);
|
||||
CuAssertIntEquals(tc, 2, sv->weeks);
|
||||
learn_skill(u, SK_ALCHEMY, STUDYDAYS * u->number);
|
||||
CuAssertIntEquals(tc, 0, learn_skill(u, SK_ALCHEMY, STUDYDAYS * u->number, 0));
|
||||
CuAssertIntEquals(tc, 1, sv->weeks);
|
||||
learn_skill(u, SK_ALCHEMY, STUDYDAYS * u->number * 2);
|
||||
CuAssertIntEquals(tc, 0, learn_skill(u, SK_ALCHEMY, STUDYDAYS * u->number * 2, 0));
|
||||
CuAssertIntEquals(tc, 2, sv->level);
|
||||
CuAssertIntEquals(tc, 2, sv->weeks);
|
||||
test_teardown();
|
||||
|
|
|
@ -93,7 +93,6 @@ int RunAllTests(int argc, char *argv[])
|
|||
/* items */
|
||||
ADD_SUITE(xerewards);
|
||||
/* kernel */
|
||||
ADD_SUITE(academy);
|
||||
ADD_SUITE(alliance);
|
||||
ADD_SUITE(ally);
|
||||
ADD_SUITE(building);
|
||||
|
|
Loading…
Reference in New Issue