forked from github/server
Merge branch 'develop' of github.com:ennorehling/eressea into develop
This commit is contained in:
commit
8fdfe9fab4
|
@ -28,6 +28,9 @@ if [ -e orders.$TURN ]; then
|
|||
files="$files orders.$TURN"
|
||||
fi
|
||||
echo "backup turn $TURN, game $GAME, files: $files"
|
||||
if [ -d reports ] ; then
|
||||
tar cjf backup/$TURN-reports.tar.bz2 reports
|
||||
fi
|
||||
tar cjf backup/$TURN.tar.bz2 $files
|
||||
echo "uploading game-$GAME/$TURN.tar.bz2"
|
||||
curl -s -n -T backup/$TURN.tar.bz2 https://dav.box.com/dav/Eressea/game-$GAME/$TURN.tar.bz2
|
||||
|
|
|
@ -25,6 +25,6 @@ addr=$1
|
|||
subj=$2
|
||||
shift 2
|
||||
|
||||
mutt -F "$ERESSEA/etc/muttrc" -s "$subj" -a "$@" -- "$addr" \
|
||||
mutt -s "$subj" -a "$@" -- "$addr" \
|
||||
< "$ERESSEA/server/etc/$TEMPLATE"
|
||||
|
||||
|
|
|
@ -44,6 +44,6 @@ addr=$1
|
|||
subject=$2
|
||||
shift 2
|
||||
|
||||
mutt -F "$ERESSEA/etc/muttrc" -s "$subject" -a "$@" -- "$addr" \
|
||||
mutt -s "$subject" -a "$@" -- "$addr" \
|
||||
< "$TEMPLATE" || echo "Sending failed for email/report: $2/$3"
|
||||
|
||||
|
|
|
@ -30,7 +30,7 @@
|
|||
</type>
|
||||
</message>
|
||||
|
||||
<message name="target_region_invalid">
|
||||
<message name="target_region_invalid" section="errors">
|
||||
<type>
|
||||
<arg name="unit" type="unit"/>
|
||||
<arg name="region" type="region"/>
|
||||
|
@ -38,7 +38,7 @@
|
|||
</type>
|
||||
</message>
|
||||
|
||||
<message name="missing_direction">
|
||||
<message name="missing_direction" section="errors">
|
||||
<type>
|
||||
<arg name="unit" type="unit"/>
|
||||
<arg name="region" type="region"/>
|
||||
|
@ -46,7 +46,7 @@
|
|||
</type>
|
||||
</message>
|
||||
|
||||
<message name="target_region_not_empty">
|
||||
<message name="target_region_not_empty" section="errors">
|
||||
<type>
|
||||
<arg name="unit" type="unit"/>
|
||||
<arg name="region" type="region"/>
|
||||
|
|
|
@ -2864,6 +2864,9 @@ msgstr "der Schatten"
|
|||
msgid "ALLES"
|
||||
msgstr "ALLES"
|
||||
|
||||
msgid "AUTO"
|
||||
msgstr "AUTO"
|
||||
|
||||
msgid "undead_postfix_2"
|
||||
msgstr "der Finsternis"
|
||||
|
||||
|
@ -5958,6 +5961,10 @@ msgctxt "keyword"
|
|||
msgid "maketemp"
|
||||
msgstr "MACHE TEMP"
|
||||
|
||||
msgctxt "keyword"
|
||||
msgid "autostudy"
|
||||
msgstr "LERNE AUTO"
|
||||
|
||||
msgctxt "spell"
|
||||
msgid "reanimate"
|
||||
msgstr "Wiederbelebung"
|
||||
|
|
|
@ -2510,6 +2510,9 @@ msgstr "halfling foot"
|
|||
msgid "ALLES"
|
||||
msgstr "ALL"
|
||||
|
||||
msgid "AUTO"
|
||||
msgstr "AUTO"
|
||||
|
||||
msgctxt "race"
|
||||
msgid "songdragon_d"
|
||||
msgstr "song dragons"
|
||||
|
@ -5268,7 +5271,11 @@ msgstr "berserkers blood potions"
|
|||
|
||||
msgctxt "keyword"
|
||||
msgid "maketemp"
|
||||
msgstr "MAKETEMP"
|
||||
msgstr "MAKE TEMP"
|
||||
|
||||
msgctxt "keyword"
|
||||
msgid "autostudy"
|
||||
msgstr "LEARN AUTO"
|
||||
|
||||
msgctxt "spell"
|
||||
msgid "reanimate"
|
||||
|
|
|
@ -93,7 +93,7 @@ email=$(grep "faction=$1:" reports.txt | cut -d: -f2 | sed 's/email=//')
|
|||
echo "sending reports to $1 / $email"
|
||||
info=/dev/null
|
||||
[ -e ../email.txt ] && info=../email.txt
|
||||
cat $info | mutt -F $ERESSEA/etc/muttrc -s "Testauswertung Spiel $game Partei $1" -a $zip -- $email
|
||||
cat $info | mutt -s "Testauswertung Spiel $game Partei $1" -a $zip -- $email
|
||||
}
|
||||
|
||||
game=0
|
||||
|
|
|
@ -12,6 +12,30 @@ function setup()
|
|||
eressea.settings.set("rules.peasants.growth.factor", "0")
|
||||
end
|
||||
|
||||
function test_study_auto()
|
||||
local r = region.create(0, 0, "plain")
|
||||
local f = faction.create("human")
|
||||
local u = unit.create(f, r, 1)
|
||||
u:add_order("LERN AUT Waffenbau")
|
||||
assert_equal("LERNE AUTO Waffenbau", u:get_order(0))
|
||||
process_orders()
|
||||
assert_equal(1, u:get_skill("weaponsmithing"))
|
||||
end
|
||||
|
||||
function test_study_auto_expensive()
|
||||
local r = region.create(0, 0, "plain")
|
||||
local f = faction.create("human")
|
||||
local u = unit.create(f, r, 1)
|
||||
u:add_order("LERNE AUTO Magie")
|
||||
assert_equal("LERNE Magie", u:get_order(0))
|
||||
u:clear_orders()
|
||||
u:add_order("LERN AUT Taktik")
|
||||
assert_equal("LERNE Taktik", u:get_order(0))
|
||||
u:clear_orders()
|
||||
u:add_order("LERN AUT Waffenbau")
|
||||
assert_equal("LERNE AUTO Waffenbau", u:get_order(0))
|
||||
end
|
||||
|
||||
function test_calendar()
|
||||
assert_equal("winter", get_season(1011))
|
||||
assert_equal("spring", get_season(1012))
|
||||
|
|
|
@ -42,7 +42,8 @@ function test_build_watch()
|
|||
process_orders()
|
||||
assert_not_nil(u.building)
|
||||
if 5 ~= u.building.size then
|
||||
for k,v in f.messages do
|
||||
-- debug logging to find intermittent errors
|
||||
for k,v in ipairs(f.messages) do
|
||||
print(v)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -24,7 +24,7 @@ end
|
|||
|
||||
function test_study()
|
||||
local r = region.create(0, 0, "plain")
|
||||
local f = faction.create("human", "test@example.com", "de")
|
||||
local f = faction.create("human")
|
||||
local u = unit.create(f, r, 1)
|
||||
u:add_order("LERNEN Armbrust")
|
||||
process_orders()
|
||||
|
@ -33,7 +33,7 @@ end
|
|||
|
||||
function test_study_expensive()
|
||||
local r = region.create(0, 0, "plain")
|
||||
local f = faction.create("human", "test@example.com", "de")
|
||||
local f = faction.create("human")
|
||||
local u = unit.create(f, r, 1)
|
||||
eressea.settings.set("skills.cost.alchemy", "50")
|
||||
u:add_order("LERNEN Alchemie")
|
||||
|
@ -45,7 +45,7 @@ end
|
|||
|
||||
function test_unit_spells()
|
||||
local r = region.create(0, 0, "plain")
|
||||
local f = faction.create("human", "test@example.com", "de")
|
||||
local f = faction.create("human")
|
||||
local u = unit.create(f, r, 1)
|
||||
u.magic = "gray"
|
||||
u:set_skill("magic", 1)
|
||||
|
@ -75,7 +75,7 @@ end
|
|||
|
||||
function test_study_no_teacher()
|
||||
local r = region.create(0, 0, "plain")
|
||||
local f = faction.create("human", "test@example.com", "de")
|
||||
local f = faction.create("human")
|
||||
local u1 = make_student(f, r, 1)
|
||||
u1:set_skill("crossbow", 1)
|
||||
process_orders()
|
||||
|
@ -84,7 +84,7 @@ end
|
|||
|
||||
function test_study_with_teacher()
|
||||
local r = region.create(0, 0, "plain")
|
||||
local f = faction.create("human", "test@example.com", "de")
|
||||
local f = faction.create("human")
|
||||
local u1 = make_student(f, r, 1)
|
||||
|
||||
make_teacher(u1)
|
||||
|
@ -95,7 +95,7 @@ end
|
|||
|
||||
function test_study_too_many_students()
|
||||
local r = region.create(0, 0, "plain")
|
||||
local f = faction.create("human", "test@example.com", "de")
|
||||
local f = faction.create("human")
|
||||
local u1 = make_student(f, r, 20, "Taktik")
|
||||
u1.name = "Student"
|
||||
u1:add_item("money", 201*u1.number)
|
||||
|
@ -106,7 +106,7 @@ end
|
|||
|
||||
function test_study_multiple_teachers()
|
||||
local r = region.create(0, 0, "plain")
|
||||
local f = faction.create("human", "test@example.com", "de")
|
||||
local f = faction.create("human")
|
||||
local u1 = make_student(f, r, 20, "Taktik")
|
||||
u1.name = "Student"
|
||||
u1:add_item("money", 201*u1.number)
|
||||
|
|
Binary file not shown.
|
@ -86,6 +86,7 @@ ENDIF()
|
|||
|
||||
set (ERESSEA_SRC
|
||||
vortex.c
|
||||
automate.c
|
||||
move.c
|
||||
piracy.c
|
||||
spells.c
|
||||
|
@ -187,6 +188,7 @@ set(TESTS_SRC
|
|||
tests.c
|
||||
academy.test.c
|
||||
alchemy.test.c
|
||||
automate.test.c
|
||||
battle.test.c
|
||||
creport.test.c
|
||||
direction.test.c
|
||||
|
|
|
@ -33,13 +33,13 @@ void academy_teaching_bonus(struct unit *u, skill_t sk, int students) {
|
|||
}
|
||||
}
|
||||
|
||||
bool academy_can_teach(unit *teacher, unit *student, skill_t sk) {
|
||||
bool academy_can_teach(unit *teacher, unit *scholar, skill_t sk) {
|
||||
const struct building_type *btype = bt_find("academy");
|
||||
if (active_building(teacher, btype) && active_building(student, btype)) {
|
||||
int j = study_cost(student, sk) * 2;
|
||||
if (active_building(teacher, btype) && active_building(scholar, btype)) {
|
||||
int j = study_cost(scholar, sk) * 2;
|
||||
if (j < 50) j = 50;
|
||||
/* kann Einheit das zahlen? */
|
||||
return get_pooled(student, get_resourcetype(R_SILVER), GET_DEFAULT, j) >= j;
|
||||
return get_pooled(scholar, get_resourcetype(R_SILVER), GET_DEFAULT, j) >= j;
|
||||
/* sonst nehmen sie nicht am Unterricht teil */
|
||||
}
|
||||
return false;
|
||||
|
|
|
@ -9,7 +9,7 @@ extern "C" {
|
|||
|
||||
struct unit;
|
||||
void academy_teaching_bonus(struct unit *u, skill_t sk, int academy);
|
||||
bool academy_can_teach(struct unit *teacher, struct unit *student, skill_t sk);
|
||||
bool academy_can_teach(struct unit *teacher, struct unit *scholar, skill_t sk);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -0,0 +1,161 @@
|
|||
#include <platform.h>
|
||||
|
||||
#include "kernel/faction.h"
|
||||
#include "kernel/messages.h"
|
||||
#include "kernel/order.h"
|
||||
#include "kernel/region.h"
|
||||
#include "kernel/unit.h"
|
||||
|
||||
#include "util/log.h"
|
||||
|
||||
#include "automate.h"
|
||||
#include "keyword.h"
|
||||
#include "laws.h"
|
||||
#include "study.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
|
||||
static int cmp_scholars(const void *lhs, const void *rhs)
|
||||
{
|
||||
const scholar *a = (const scholar *)lhs;
|
||||
const scholar *b = (const scholar *)rhs;
|
||||
if (a->sk == b->sk) {
|
||||
/* sort by level, descending: */
|
||||
return b->level - a->level;
|
||||
}
|
||||
/* order by skill */
|
||||
return (int)a->sk - (int)b->sk;
|
||||
}
|
||||
|
||||
int autostudy_init(scholar scholars[], int max_scholars, region *r)
|
||||
{
|
||||
unit *u;
|
||||
int nscholars = 0;
|
||||
|
||||
for (u = r->units; u; u = u->next) {
|
||||
keyword_t kwd = getkeyword(u->thisorder);
|
||||
if (kwd == K_AUTOSTUDY) {
|
||||
if (long_order_allowed(u) && unit_can_study(u)) {
|
||||
scholar * st = scholars + nscholars;
|
||||
init_order(u->thisorder, u->faction->locale);
|
||||
st->sk = getskill(u->faction->locale);
|
||||
st->level = effskill_study(u, st->sk);
|
||||
st->learn = 0;
|
||||
st->u = u;
|
||||
if (++nscholars == max_scholars) {
|
||||
log_fatal("you must increase MAXSCHOLARS");
|
||||
}
|
||||
}
|
||||
else {
|
||||
ADDMSG(&u->faction->msgs, msg_feedback(u, u->thisorder, "error_race_nolearn", "race",
|
||||
u_race(u)));
|
||||
}
|
||||
}
|
||||
}
|
||||
if (nscholars > 0) {
|
||||
qsort(scholars, nscholars, sizeof(scholar), cmp_scholars);
|
||||
}
|
||||
return nscholars;
|
||||
}
|
||||
|
||||
static void teaching(scholar *s, int n) {
|
||||
assert(n <= s->u->number);
|
||||
s->learn += n;
|
||||
s->u->flags |= UFL_LONGACTION;
|
||||
}
|
||||
|
||||
static void learning(scholar *s, int n) {
|
||||
assert(n <= s->u->number);
|
||||
s->learn += n;
|
||||
s->u->flags |= UFL_LONGACTION;
|
||||
}
|
||||
|
||||
void autostudy_run(scholar scholars[], int nscholars)
|
||||
{
|
||||
int ti = 0;
|
||||
while (ti != nscholars) {
|
||||
skill_t sk = scholars[ti].sk;
|
||||
int t, s, se, ts = 0, tt = 0, si = ti;
|
||||
for (se = ti; se != nscholars && scholars[se].sk == sk; ++se) {
|
||||
int mint;
|
||||
ts += scholars[se].u->number; /* count total scholars */
|
||||
mint = (ts + 10) / 11; /* need a minimum of ceil(ts/11) teachers */
|
||||
for (; mint > tt && si != nscholars; ++si) {
|
||||
tt += scholars[si].u->number;
|
||||
}
|
||||
}
|
||||
/* now si splits the teachers and students 1:10 */
|
||||
/* first student must be 2 levels below first teacher: */
|
||||
for (; si != se && scholars[ti].level - TEACHDIFFERENCE > scholars[si].level; ++si) {
|
||||
tt += scholars[si].u->number;
|
||||
}
|
||||
if (si == se) {
|
||||
/* there are no students, so standard learning only */
|
||||
for (t = ti; t != se; ++t) {
|
||||
learning(scholars + t, scholars[t].u->number);
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* invariant: unit ti can still teach i students */
|
||||
int i = scholars[ti].u->number * STUDENTS_PER_TEACHER;
|
||||
/* invariant: unit si has n students that can still be taught */
|
||||
int n = scholars[si].u->number;
|
||||
for (t = ti, s = si; t != si && s != se; ) {
|
||||
if (i > n) {
|
||||
/* t has more than enough teaching capacity for s */
|
||||
i -= n;
|
||||
teaching(scholars + s, n);
|
||||
learning(scholars + s, scholars[s].u->number);
|
||||
/* next student, please: */
|
||||
if (++s == se) {
|
||||
continue;
|
||||
}
|
||||
n = scholars[s].u->number;
|
||||
}
|
||||
else {
|
||||
/* s gets partial credit and we need a new teacher */
|
||||
teaching(scholars + s, i);
|
||||
|
||||
/* we are done with this teacher. any remaining people are regular learners: */
|
||||
if (scholars[t].u->number > 1) {
|
||||
/* remain = number - ceil(taught/10); */
|
||||
int remain = (STUDENTS_PER_TEACHER * scholars[t].u->number - i + STUDENTS_PER_TEACHER - 1) / STUDENTS_PER_TEACHER;
|
||||
learning(scholars + t, remain);
|
||||
}
|
||||
|
||||
/* we want a new teacher for s. if any exists, it's next in the sequence. */
|
||||
if (++t == si) {
|
||||
continue;
|
||||
}
|
||||
if (scholars[t].level - TEACHDIFFERENCE < scholars[s].level) {
|
||||
/* next teacher cannot teach, we must skip students. */
|
||||
do {
|
||||
learning(scholars + s, (n - i));
|
||||
i = 0;
|
||||
if (++s == se) {
|
||||
continue;
|
||||
}
|
||||
n = scholars[s].u->number;
|
||||
} while (scholars[t].level - TEACHDIFFERENCE < scholars[s].level);
|
||||
}
|
||||
i = scholars[t].u->number * STUDENTS_PER_TEACHER;
|
||||
}
|
||||
}
|
||||
}
|
||||
ti = se;
|
||||
}
|
||||
}
|
||||
|
||||
#define MAXSCHOLARS 128
|
||||
|
||||
void do_autostudy(region *r)
|
||||
{
|
||||
scholar scholars[MAXSCHOLARS];
|
||||
int i, nscholars = autostudy_init(scholars, MAXSCHOLARS, r);
|
||||
autostudy_run(scholars, nscholars);
|
||||
for (i = 0; i != nscholars; ++i) {
|
||||
int days = STUDYDAYS * scholars[i].learn;
|
||||
learn_skill(scholars[i].u, scholars[i].sk, days);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
Copyright (c) 1998-2018, Enno Rehling <enno@eressea.de>
|
||||
Katja Zedel <katze@felidae.kn-bremen.de
|
||||
Christian Schlittchen <corwin@amber.kn-bremen.de>
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
**/
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef H_GC_AUTOMATE
|
||||
#define H_GC_AUTOMATE
|
||||
|
||||
#include "skill.h"
|
||||
|
||||
struct region;
|
||||
struct unit;
|
||||
|
||||
typedef struct scholar {
|
||||
struct unit *u;
|
||||
skill_t sk;
|
||||
int level;
|
||||
int learn;
|
||||
} scholar;
|
||||
|
||||
#define STUDENTS_PER_TEACHER 10
|
||||
|
||||
void do_autostudy(struct region *r);
|
||||
|
||||
int autostudy_init(scholar scholars[], int max_scholars, struct region *r);
|
||||
void autostudy_run(scholar scholars[], int nscholars);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,114 @@
|
|||
#ifdef _MSC_VER
|
||||
#include <platform.h>
|
||||
#endif
|
||||
|
||||
#include "automate.h"
|
||||
|
||||
#include "kernel/faction.h"
|
||||
#include "kernel/order.h"
|
||||
#include "kernel/region.h"
|
||||
#include "kernel/unit.h"
|
||||
|
||||
#include "tests.h"
|
||||
|
||||
#include <CuTest.h>
|
||||
|
||||
static void test_autostudy_init(CuTest *tc) {
|
||||
scholar scholars[4];
|
||||
unit *u1, *u2, *u3;
|
||||
faction *f;
|
||||
region *r;
|
||||
|
||||
test_setup();
|
||||
r = test_create_plain(0, 0);
|
||||
f = test_create_faction(NULL);
|
||||
u1 = test_create_unit(f, r);
|
||||
u1->thisorder = create_order(K_AUTOSTUDY, f->locale, skillnames[SK_ENTERTAINMENT]);
|
||||
test_create_unit(f, r);
|
||||
u2 = test_create_unit(f, r);
|
||||
u2->thisorder = create_order(K_AUTOSTUDY, f->locale, skillnames[SK_ENTERTAINMENT]);
|
||||
set_level(u2, SK_ENTERTAINMENT, 2);
|
||||
u3 = test_create_unit(f, r);
|
||||
u3->thisorder = create_order(K_AUTOSTUDY, f->locale, skillnames[SK_PERCEPTION]);
|
||||
scholars[3].u = NULL;
|
||||
CuAssertIntEquals(tc, 3, autostudy_init(scholars, 4, r));
|
||||
CuAssertPtrEquals(tc, u2, scholars[0].u);
|
||||
CuAssertIntEquals(tc, 2, scholars[0].level);
|
||||
CuAssertIntEquals(tc, 0, scholars[0].learn);
|
||||
CuAssertIntEquals(tc, SK_ENTERTAINMENT, scholars[0].sk);
|
||||
CuAssertPtrEquals(tc, u1, scholars[1].u);
|
||||
CuAssertIntEquals(tc, 0, scholars[1].level);
|
||||
CuAssertIntEquals(tc, 0, scholars[1].learn);
|
||||
CuAssertIntEquals(tc, SK_ENTERTAINMENT, scholars[1].sk);
|
||||
CuAssertPtrEquals(tc, u3, scholars[2].u);
|
||||
CuAssertIntEquals(tc, 0, scholars[2].level);
|
||||
CuAssertIntEquals(tc, 0, scholars[2].learn);
|
||||
CuAssertIntEquals(tc, SK_PERCEPTION, scholars[2].sk);
|
||||
CuAssertPtrEquals(tc, NULL, scholars[3].u);
|
||||
test_teardown();
|
||||
}
|
||||
|
||||
static void test_autostudy_run(CuTest *tc) {
|
||||
scholar scholars[4];
|
||||
unit *u1, *u2, *u3;
|
||||
faction *f;
|
||||
region *r;
|
||||
|
||||
test_setup();
|
||||
r = test_create_plain(0, 0);
|
||||
f = test_create_faction(NULL);
|
||||
u1 = test_create_unit(f, r);
|
||||
u1->thisorder = create_order(K_AUTOSTUDY, f->locale, skillnames[SK_ENTERTAINMENT]);
|
||||
set_number(u1, 2);
|
||||
set_level(u1, SK_ENTERTAINMENT, 2);
|
||||
u2 = test_create_unit(f, r);
|
||||
u2->thisorder = create_order(K_AUTOSTUDY, f->locale, skillnames[SK_ENTERTAINMENT]);
|
||||
set_number(u2, 10);
|
||||
u3 = test_create_unit(f, r);
|
||||
u3->thisorder = create_order(K_AUTOSTUDY, f->locale, skillnames[SK_PERCEPTION]);
|
||||
set_number(u3, 15);
|
||||
scholars[3].u = NULL;
|
||||
CuAssertIntEquals(tc, 3, autostudy_init(scholars, 4, r));
|
||||
autostudy_run(scholars, 3);
|
||||
CuAssertIntEquals(tc, 0, scholars[0].learn);
|
||||
CuAssertIntEquals(tc, 20, scholars[1].learn);
|
||||
CuAssertIntEquals(tc, 15, scholars[2].learn);
|
||||
test_teardown();
|
||||
}
|
||||
|
||||
static void test_autostudy_run_noteachers(CuTest *tc) {
|
||||
scholar scholars[4];
|
||||
unit *u1, *u2, *u3;
|
||||
faction *f;
|
||||
region *r;
|
||||
|
||||
test_setup();
|
||||
r = test_create_plain(0, 0);
|
||||
f = test_create_faction(NULL);
|
||||
u1 = test_create_unit(f, r);
|
||||
u1->thisorder = create_order(K_AUTOSTUDY, f->locale, skillnames[SK_LUMBERJACK]);
|
||||
set_number(u1, 2);
|
||||
set_level(u1, SK_ENTERTAINMENT, 2);
|
||||
u2 = test_create_unit(f, r);
|
||||
u2->thisorder = create_order(K_AUTOSTUDY, f->locale, skillnames[SK_ENTERTAINMENT]);
|
||||
set_number(u2, 10);
|
||||
u3 = test_create_unit(f, r);
|
||||
u3->thisorder = create_order(K_AUTOSTUDY, f->locale, skillnames[SK_PERCEPTION]);
|
||||
set_number(u3, 15);
|
||||
scholars[3].u = NULL;
|
||||
CuAssertIntEquals(tc, 3, autostudy_init(scholars, 4, r));
|
||||
autostudy_run(scholars, 3);
|
||||
CuAssertIntEquals(tc, 2, scholars[0].learn);
|
||||
CuAssertIntEquals(tc, 10, scholars[1].learn);
|
||||
CuAssertIntEquals(tc, 15, scholars[2].learn);
|
||||
test_teardown();
|
||||
}
|
||||
|
||||
CuSuite *get_automate_suite(void)
|
||||
{
|
||||
CuSuite *suite = CuSuiteNew();
|
||||
SUITE_ADD_TEST(suite, test_autostudy_init);
|
||||
SUITE_ADD_TEST(suite, test_autostudy_run);
|
||||
SUITE_ADD_TEST(suite, test_autostudy_run_noteachers);
|
||||
return suite;
|
||||
}
|
|
@ -100,9 +100,7 @@ typedef enum combatmagic {
|
|||
#define MINSPELLRANGE 1
|
||||
#define MAXSPELLRANGE 7
|
||||
|
||||
#ifndef ROW_FACTOR
|
||||
# define ROW_FACTOR 10
|
||||
#endif
|
||||
#define ROW_FACTOR 3 /* factor for combat row advancement rule */
|
||||
#define EFFECT_PANIC_SPELL 0.25
|
||||
#define TROLL_REGENERATION 0.10
|
||||
|
||||
|
@ -161,7 +159,7 @@ static void init_rules(void)
|
|||
skill_formula = config_get_int("rules.combat.skill_formula",
|
||||
FORMULA_ORIG);
|
||||
/* maximum number of combat turns */
|
||||
max_turns = config_get_int("rules.combat.turns", COMBAT_TURNS);
|
||||
max_turns = config_get_int("rules.combat.turns", 5);
|
||||
/* damage calculation */
|
||||
if (config_get_int("rules.combat.critical", 1)) {
|
||||
rule_damage |= DAMAGE_CRITICAL;
|
||||
|
|
|
@ -645,6 +645,7 @@ static void cr_output_building(struct stream *out, building *b,
|
|||
const unit *owner, int fno, faction *f)
|
||||
{
|
||||
const char *bname, *billusion;
|
||||
int i;
|
||||
|
||||
stream_printf(out, "BURG %d\n", b->no);
|
||||
|
||||
|
@ -673,9 +674,12 @@ static void cr_output_building(struct stream *out, building *b,
|
|||
if (fno >= 0) {
|
||||
stream_printf(out, "%d;Partei\n", fno);
|
||||
}
|
||||
if (b->besieged) {
|
||||
stream_printf(out, "%d;Belagerer\n", b->besieged);
|
||||
|
||||
i = building_get_siege(b);
|
||||
if (i) {
|
||||
stream_printf(out, "%d;Belagerer\n", i);
|
||||
}
|
||||
|
||||
cr_output_curses(out, f, b, TYP_BUILDING);
|
||||
}
|
||||
|
||||
|
|
|
@ -103,6 +103,8 @@ static void recruit_init(void)
|
|||
}
|
||||
}
|
||||
|
||||
#define ENTERTAINFRACTION 20
|
||||
|
||||
int entertainmoney(const region * r)
|
||||
{
|
||||
double n;
|
||||
|
@ -1666,7 +1668,7 @@ static void buy(unit * u, econ_request ** buyorders, struct order *ord)
|
|||
return;
|
||||
}
|
||||
}
|
||||
if (r_demand(r, ltype)) {
|
||||
if (!r->land || r_demand(r, ltype)) {
|
||||
ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "luxury_notsold", ""));
|
||||
return;
|
||||
}
|
||||
|
@ -1708,6 +1710,7 @@ static void expandselling(region * r, econ_request * sellorders, int limit)
|
|||
static int bt_cache;
|
||||
static const struct building_type *castle_bt, *harbour_bt, *caravan_bt;
|
||||
|
||||
assert(r->land);
|
||||
if (bt_changed(&bt_cache)) {
|
||||
castle_bt = bt_find("castle");
|
||||
harbour_bt = bt_find("harbour");
|
||||
|
@ -1977,7 +1980,7 @@ static bool sell(unit * u, econ_request ** sellorders, struct order *ord)
|
|||
econ_request *o;
|
||||
int k, available;
|
||||
|
||||
if (!r_demand(r, ltype)) {
|
||||
if (!r->land || !r_demand(r, ltype)) {
|
||||
cmistake(u, ord, 263, MSG_COMMERCE);
|
||||
return false;
|
||||
}
|
||||
|
|
442
src/exparse.c
442
src/exparse.c
File diff suppressed because it is too large
Load Diff
|
@ -870,3 +870,14 @@ int cmp_current_owner(const building * b, const building * a)
|
|||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int building_get_siege(const struct building *b)
|
||||
{
|
||||
return b->_besieged;
|
||||
}
|
||||
|
||||
int building_add_siege(struct building *b, int delta)
|
||||
{
|
||||
b->_besieged += delta;
|
||||
return b->_besieged;
|
||||
}
|
||||
|
|
|
@ -118,7 +118,7 @@ extern "C" {
|
|||
int no;
|
||||
int size;
|
||||
int sizeleft; /* is only used during battle. should be a temporary attribute */
|
||||
int besieged; /* should be an attribute */
|
||||
int _besieged; /* should be an attribute */
|
||||
int flags;
|
||||
} building;
|
||||
|
||||
|
@ -134,6 +134,9 @@ extern "C" {
|
|||
int id, int size, struct order *ord);
|
||||
bool building_finished(const struct building *b);
|
||||
|
||||
int building_get_siege(const struct building *b);
|
||||
int building_add_siege(struct building *b, int delta);
|
||||
|
||||
int wage(const struct region *r, const struct faction *f,
|
||||
const struct race *rc, int in_turn);
|
||||
|
||||
|
|
|
@ -135,7 +135,8 @@ const char *parameters[MAXPARAMS] = {
|
|||
"GRUPPE",
|
||||
"PARTEITARNUNG",
|
||||
"BAEUME",
|
||||
"ALLIANZ"
|
||||
"ALLIANZ",
|
||||
"AUTO"
|
||||
};
|
||||
|
||||
int findoption(const char *s, const struct locale *lang)
|
||||
|
|
|
@ -84,7 +84,7 @@ char* get_command(const order *ord, const struct locale *lang, char *sbuffer, si
|
|||
sbs_strcat(&sbs, str);
|
||||
if (ord->id < 0) {
|
||||
skill_t sk = (skill_t)(100+ord->id);
|
||||
assert(kwd == K_STUDY && sk != SK_MAGIC && sk < MAXSKILLS);
|
||||
assert((kwd == K_STUDY || kwd == K_AUTOSTUDY) && sk != SK_MAGIC && sk < MAXSKILLS);
|
||||
str = skillname(sk, lang);
|
||||
if (str) {
|
||||
if (strchr(str, ' ') == NULL) {
|
||||
|
@ -141,7 +141,8 @@ int stream_order(struct stream *out, const struct order *ord, const struct local
|
|||
if (ord->id < 0) {
|
||||
skill_t sk = (skill_t)(100 + ord->id);
|
||||
|
||||
assert(kwd == K_STUDY && sk != SK_MAGIC && sk < MAXSKILLS);
|
||||
assert(kwd == K_AUTOSTUDY || kwd == K_STUDY);
|
||||
assert(sk != SK_MAGIC && sk < MAXSKILLS);
|
||||
text = skillname(sk, lang);
|
||||
if (strchr(text, ' ') != NULL) {
|
||||
swrite(" '", 1, 2, out);
|
||||
|
@ -214,12 +215,12 @@ static int create_data(keyword_t kwd, const char *s,
|
|||
order_data *data;
|
||||
int id;
|
||||
|
||||
assert(kwd!=NOKEYWORD);
|
||||
assert(kwd != NOKEYWORD);
|
||||
|
||||
if (!s || *s == 0) {
|
||||
return 0;
|
||||
}
|
||||
if (kwd==K_STUDY) {
|
||||
if (kwd == K_STUDY || kwd == K_AUTOSTUDY) {
|
||||
const char * sptr = s;
|
||||
skill_t sk = get_skill(parse_token_depr(&sptr), lang);
|
||||
if (sk != SK_MAGIC && sk != NOSKILL) {
|
||||
|
@ -310,12 +311,13 @@ order *parse_order(const char *s, const struct locale * lang)
|
|||
assert(lang);
|
||||
assert(s);
|
||||
if (*s != 0) {
|
||||
char token[32];
|
||||
keyword_t kwd = NOKEYWORD;
|
||||
const char *sptr = s;
|
||||
bool persistent = false, noerror = false;
|
||||
const char * p;
|
||||
char * p;
|
||||
|
||||
p = *sptr ? parse_token_depr(&sptr) : 0;
|
||||
p = parse_token(&sptr, token, sizeof(token));
|
||||
if (p) {
|
||||
while (*p == '!' || *p == '@') {
|
||||
if (*p == '!') noerror = true;
|
||||
|
@ -326,12 +328,25 @@ order *parse_order(const char *s, const struct locale * lang)
|
|||
}
|
||||
if (kwd == K_MAKE) {
|
||||
const char *sp = sptr;
|
||||
p = parse_token_depr(&sp);
|
||||
p = parse_token(&sp, token, sizeof(token));
|
||||
if (p && isparam(p, lang, P_TEMP)) {
|
||||
kwd = K_MAKETEMP;
|
||||
sptr = sp;
|
||||
}
|
||||
}
|
||||
else if (kwd == K_STUDY) {
|
||||
const char *sp = sptr;
|
||||
p = parse_token(&sp, token, sizeof(token));
|
||||
if (p && isparam(p, lang, P_AUTO)) {
|
||||
skill_t sk;
|
||||
sptr = sp;
|
||||
p = parse_token(&sp, token, sizeof(token));
|
||||
sk = get_skill(p, lang);
|
||||
if (!expensive_skill(sk)) {
|
||||
kwd = K_AUTOSTUDY;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (kwd != NOKEYWORD) {
|
||||
order *ord = (order *)malloc(sizeof(order));
|
||||
create_order_i(ord, kwd, sptr, persistent, noerror, lang);
|
||||
|
@ -366,6 +381,7 @@ bool is_repeated(keyword_t kwd)
|
|||
case K_STEAL:
|
||||
case K_SABOTAGE:
|
||||
case K_STUDY:
|
||||
case K_AUTOSTUDY:
|
||||
case K_TEACH:
|
||||
case K_GROW:
|
||||
case K_PLANT:
|
||||
|
@ -406,6 +422,7 @@ bool is_exclusive(const order * ord)
|
|||
case K_STEAL:
|
||||
case K_SABOTAGE:
|
||||
case K_STUDY:
|
||||
case K_AUTOSTUDY:
|
||||
case K_TEACH:
|
||||
case K_GROW:
|
||||
case K_PLANT:
|
||||
|
@ -447,6 +464,7 @@ bool is_long(keyword_t kwd)
|
|||
case K_STEAL:
|
||||
case K_SABOTAGE:
|
||||
case K_STUDY:
|
||||
case K_AUTOSTUDY:
|
||||
case K_TEACH:
|
||||
case K_GROW:
|
||||
case K_PLANT:
|
||||
|
@ -541,7 +559,7 @@ keyword_t init_order(const struct order *ord, const struct locale *lang)
|
|||
|
||||
assert(sk < MAXSKILLS);
|
||||
assert(lang);
|
||||
assert(kwd == K_STUDY);
|
||||
assert(kwd == K_STUDY || kwd == K_AUTOSTUDY);
|
||||
str = skillname(sk, lang);
|
||||
if (strchr(str, ' ') == NULL) {
|
||||
init_tokens_str(str);
|
||||
|
@ -575,7 +593,7 @@ keyword_t init_order_depr(const struct order *ord)
|
|||
{
|
||||
if (ord) {
|
||||
keyword_t kwd = ORD_KEYWORD(ord);
|
||||
assert(kwd != K_STUDY);
|
||||
assert(kwd != K_STUDY && kwd != K_AUTOSTUDY);
|
||||
}
|
||||
return init_order(ord, NULL);
|
||||
}
|
||||
|
|
|
@ -113,6 +113,43 @@ static void test_parse_make(CuTest *tc) {
|
|||
test_teardown();
|
||||
}
|
||||
|
||||
static void test_parse_autostudy(CuTest *tc) {
|
||||
char cmd[32];
|
||||
order *ord;
|
||||
struct locale * lang;
|
||||
|
||||
test_setup();
|
||||
lang = get_or_create_locale("en");
|
||||
locale_setstring(lang, mkname("skill", skillnames[SK_ENTERTAINMENT]), "Entertainment");
|
||||
locale_setstring(lang, mkname("skill", skillnames[SK_MAGIC]), "Magic");
|
||||
locale_setstring(lang, mkname("skill", skillnames[SK_TACTICS]), "Tactics");
|
||||
locale_setstring(lang, keyword(K_STUDY), "STUDY");
|
||||
locale_setstring(lang, keyword(K_AUTOSTUDY), "AUTOSTUDY");
|
||||
locale_setstring(lang, parameters[P_AUTO], "AUTO");
|
||||
init_locale(lang);
|
||||
|
||||
ord = parse_order("STUDY AUTO Entertainment", lang);
|
||||
CuAssertPtrNotNull(tc, ord);
|
||||
CuAssertIntEquals(tc, K_AUTOSTUDY, getkeyword(ord));
|
||||
CuAssertStrEquals(tc, "AUTOSTUDY Entertainment", get_command(ord, lang, cmd, sizeof(cmd)));
|
||||
|
||||
CuAssertIntEquals(tc, K_AUTOSTUDY, init_order(ord, lang));
|
||||
CuAssertStrEquals(tc, "Entertainment", getstrtoken());
|
||||
free_order(ord);
|
||||
|
||||
ord = parse_order("STUDY AUTO Magic", lang);
|
||||
CuAssertIntEquals(tc, K_STUDY, getkeyword(ord));
|
||||
CuAssertStrEquals(tc, "STUDY Magic", get_command(ord, lang, cmd, sizeof(cmd)));
|
||||
free_order(ord);
|
||||
|
||||
ord = parse_order("STUDY AUTO Tactics", lang);
|
||||
CuAssertIntEquals(tc, K_STUDY, getkeyword(ord));
|
||||
CuAssertStrEquals(tc, "STUDY Tactics", get_command(ord, lang, cmd, sizeof(cmd)));
|
||||
free_order(ord);
|
||||
|
||||
test_teardown();
|
||||
}
|
||||
|
||||
static void test_parse_make_temp(CuTest *tc) {
|
||||
char cmd[32];
|
||||
order *ord;
|
||||
|
@ -130,7 +167,7 @@ static void test_parse_make_temp(CuTest *tc) {
|
|||
CuAssertIntEquals(tc, K_MAKETEMP, getkeyword(ord));
|
||||
CuAssertStrEquals(tc, "MAKETEMP herp", get_command(ord, lang, cmd, sizeof(cmd)));
|
||||
|
||||
CuAssertIntEquals(tc, K_MAKETEMP, init_order_depr(ord));
|
||||
CuAssertIntEquals(tc, K_MAKETEMP, init_order(ord, lang));
|
||||
CuAssertStrEquals(tc, "herp", getstrtoken());
|
||||
free_order(ord);
|
||||
test_teardown();
|
||||
|
@ -153,7 +190,7 @@ static void test_parse_maketemp(CuTest *tc) {
|
|||
CuAssertPtrNotNull(tc, ord);
|
||||
CuAssertStrEquals(tc, "MAKETEMP herp", get_command(ord, lang, cmd, sizeof(cmd)));
|
||||
CuAssertIntEquals(tc, K_MAKETEMP, getkeyword(ord));
|
||||
CuAssertIntEquals(tc, K_MAKETEMP, init_order_depr(ord));
|
||||
CuAssertIntEquals(tc, K_MAKETEMP, init_order(ord, lang));
|
||||
CuAssertStrEquals(tc, "herp", getstrtoken());
|
||||
free_order(ord);
|
||||
test_teardown();
|
||||
|
@ -167,7 +204,7 @@ static void test_init_order(CuTest *tc) {
|
|||
|
||||
lang = get_or_create_locale("en");
|
||||
ord = create_order(K_MAKETEMP, lang, "hurr durr");
|
||||
CuAssertIntEquals(tc, K_MAKETEMP, init_order_depr(ord));
|
||||
CuAssertIntEquals(tc, K_MAKETEMP, init_order(ord, lang));
|
||||
CuAssertStrEquals(tc, "hurr", getstrtoken());
|
||||
CuAssertStrEquals(tc, "durr", getstrtoken());
|
||||
free_order(ord);
|
||||
|
@ -548,6 +585,7 @@ CuSuite *get_order_suite(void)
|
|||
SUITE_ADD_TEST(suite, test_study_order_quoted);
|
||||
SUITE_ADD_TEST(suite, test_parse_order);
|
||||
SUITE_ADD_TEST(suite, test_parse_make);
|
||||
SUITE_ADD_TEST(suite, test_parse_autostudy);
|
||||
SUITE_ADD_TEST(suite, test_parse_make_temp);
|
||||
SUITE_ADD_TEST(suite, test_parse_maketemp);
|
||||
SUITE_ADD_TEST(suite, test_init_order);
|
||||
|
|
|
@ -716,7 +716,10 @@ const item_type *r_luxury(const region * r)
|
|||
|
||||
int r_demand(const region * r, const luxury_type * ltype)
|
||||
{
|
||||
struct demand *d = r->land->demands;
|
||||
struct demand *d;
|
||||
|
||||
assert(r && r->land);
|
||||
d = r->land->demands;
|
||||
while (d && d->type != ltype)
|
||||
d = d->next;
|
||||
if (!d)
|
||||
|
|
|
@ -130,6 +130,7 @@ typedef enum {
|
|||
P_FACTIONSTEALTH,
|
||||
P_TREES,
|
||||
P_ALLIANCE,
|
||||
P_AUTO,
|
||||
MAXPARAMS,
|
||||
NOPARAM
|
||||
} param_t;
|
||||
|
|
|
@ -1310,13 +1310,12 @@ int eff_skill(const unit * u, const skill *sv, const region *r)
|
|||
return 0;
|
||||
}
|
||||
|
||||
int effskill_study(const unit * u, skill_t sk, const region * r)
|
||||
int effskill_study(const unit * u, skill_t sk)
|
||||
{
|
||||
skill *sv = unit_skill(u, sk);
|
||||
if (sv && sv->level > 0) {
|
||||
int mlevel = sv->level;
|
||||
if (!r) r = u->region;
|
||||
mlevel += get_modifier(u, sv->id, sv->level, r, true);
|
||||
mlevel += get_modifier(u, sv->id, sv->level, u->region, true);
|
||||
if (mlevel > 0)
|
||||
return mlevel;
|
||||
}
|
||||
|
@ -1918,9 +1917,11 @@ int getunit(const region * r, const faction * f, unit **uresult)
|
|||
int besieged(const unit * u)
|
||||
{
|
||||
/* belagert kann man in schiffen und burgen werden */
|
||||
return (u && !keyword_disabled(K_BESIEGE)
|
||||
&& u->building && u->building->besieged
|
||||
&& u->building->besieged >= u->building->size * SIEGEFACTOR);
|
||||
if (u && !keyword_disabled(K_BESIEGE) && u->building) {
|
||||
building * b = u->building;
|
||||
return building_get_siege(b) >= b->size * SIEGEFACTOR;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool has_horses(const unit * u)
|
||||
|
|
|
@ -163,7 +163,7 @@ extern "C" {
|
|||
void clone_men(const struct unit *src, struct unit *dst, int n); /* like transfer, but do not subtract from src */
|
||||
|
||||
int eff_skill(const struct unit *u, const struct skill *sv, const struct region *r);
|
||||
int effskill_study(const struct unit *u, skill_t sk, const struct region *r);
|
||||
int effskill_study(const struct unit *u, skill_t sk);
|
||||
|
||||
int get_modifier(const struct unit *u, skill_t sk, int level,
|
||||
const struct region *r, bool noitem);
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
|
||||
#ifndef ERESSEA_VERSION
|
||||
/* the version number, if it was not passed to make with -D */
|
||||
#define ERESSEA_VERSION "3.17.0"
|
||||
#define ERESSEA_VERSION "3.18.0"
|
||||
#endif
|
||||
|
||||
const char *eressea_version(void) {
|
||||
|
|
|
@ -149,5 +149,6 @@ const char *keywords[MAXKEYWORDS] = {
|
|||
"promote",
|
||||
"pay",
|
||||
"loot",
|
||||
"autostudy",
|
||||
};
|
||||
|
||||
|
|
|
@ -72,6 +72,7 @@ extern "C"
|
|||
K_PROMOTION,
|
||||
K_PAY,
|
||||
K_LOOT,
|
||||
K_AUTOSTUDY,
|
||||
MAXKEYWORDS,
|
||||
NOKEYWORD
|
||||
} keyword_t;
|
||||
|
|
42
src/laws.c
42
src/laws.c
|
@ -26,6 +26,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|||
#include <modules/gmcmd.h>
|
||||
|
||||
#include "alchemy.h"
|
||||
#include "automate.h"
|
||||
#include "battle.h"
|
||||
#include "economy.h"
|
||||
#include "keyword.h"
|
||||
|
@ -305,6 +306,11 @@ static void calculate_emigration(region * r)
|
|||
}
|
||||
}
|
||||
|
||||
/* Vermehrungsrate Bauern in 1/10000.
|
||||
* TODO: Evt. Berechnungsfehler, reale Vermehrungsraten scheinen hoeher. */
|
||||
#define PEASANTGROWTH 10
|
||||
#define PEASANTLUCK 10
|
||||
#define PEASANTFORCE 0.75 /* Chance einer Vermehrung trotz 90% Auslastung */
|
||||
|
||||
static double peasant_growth_factor(void)
|
||||
{
|
||||
|
@ -907,7 +913,7 @@ static int slipthru(const region * r, const unit * u, const building * b)
|
|||
int n, o;
|
||||
|
||||
/* b ist die burg, in die man hinein oder aus der man heraus will. */
|
||||
if (b == NULL || b->besieged < b->size * SIEGEFACTOR) {
|
||||
if (b == NULL || building_get_siege(b) < b->size * SIEGEFACTOR) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -3636,6 +3642,24 @@ void add_proc_unit(int priority, void(*process) (unit *), const char *name)
|
|||
}
|
||||
}
|
||||
|
||||
bool long_order_allowed(const unit *u)
|
||||
{
|
||||
const region *r = u->region;
|
||||
if (fval(u, UFL_LONGACTION)) {
|
||||
/* this message was already given in laws.update_long_order
|
||||
cmistake(u, ord, 52, MSG_PRODUCE);
|
||||
*/
|
||||
return false;
|
||||
}
|
||||
else if (fval(r->terrain, SEA_REGION)
|
||||
&& u_race(u) != get_race(RC_AQUARIAN)
|
||||
&& !(u_race(u)->flags & RCF_SWIM)) {
|
||||
/* error message disabled by popular demand */
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/* per priority, execute processors in order from PR_GLOBAL down to PR_ORDER */
|
||||
void process(void)
|
||||
{
|
||||
|
@ -3705,16 +3729,7 @@ void process(void)
|
|||
cmistake(u, ord, 224, MSG_MAGIC);
|
||||
ord = NULL;
|
||||
}
|
||||
else if (fval(u, UFL_LONGACTION)) {
|
||||
/* this message was already given in laws.update_long_order
|
||||
cmistake(u, ord, 52, MSG_PRODUCE);
|
||||
*/
|
||||
ord = NULL;
|
||||
}
|
||||
else if (fval(r->terrain, SEA_REGION)
|
||||
&& u_race(u) != get_race(RC_AQUARIAN)
|
||||
&& !(u_race(u)->flags & RCF_SWIM)) {
|
||||
/* error message disabled by popular demand */
|
||||
else if (!long_order_allowed(u)) {
|
||||
ord = NULL;
|
||||
}
|
||||
}
|
||||
|
@ -3847,7 +3862,7 @@ int siege_cmd(unit * u, order * ord)
|
|||
|
||||
usetsiege(u, b);
|
||||
if (katapultiere < bewaffnete) katapultiere = bewaffnete;
|
||||
b->besieged += katapultiere;
|
||||
building_add_siege(b, katapultiere);
|
||||
|
||||
/* definitiver schaden eingeschraenkt */
|
||||
if (d > b->size - 1) d = b->size - 1;
|
||||
|
@ -4001,6 +4016,7 @@ void init_processor(void)
|
|||
}
|
||||
|
||||
p += 10;
|
||||
add_proc_region(p, do_autostudy, "study automation");
|
||||
add_proc_order(p, K_TEACH, teach_cmd, PROC_THISORDER | PROC_LONGORDER,
|
||||
"Lehren");
|
||||
p += 10;
|
||||
|
@ -4155,7 +4171,7 @@ void update_subscriptions(void)
|
|||
/** determine if unit can be seen by faction
|
||||
* @param f -- the observiong faction
|
||||
* @param u -- the unit that is observed
|
||||
* @param r -- the region that u is obesrved in (see below)
|
||||
* @param r -- the region that u is obesrved from (see below)
|
||||
* @param m -- terrain modifier to stealth
|
||||
*
|
||||
* r kann != u->region sein, wenn es um Durchreisen geht,
|
||||
|
|
|
@ -66,6 +66,7 @@ extern "C" {
|
|||
void update_long_order(struct unit *u);
|
||||
void sinkships(struct region * r);
|
||||
void do_enter(struct region *r, bool is_final_attempt);
|
||||
bool long_order_allowed(const struct unit *u);
|
||||
|
||||
int password_cmd(struct unit *u, struct order *ord);
|
||||
int banner_cmd(struct unit *u, struct order *ord);
|
||||
|
|
|
@ -113,7 +113,8 @@ static void test_contact(CuTest * tc)
|
|||
u3 = test_create_unit(test_create_faction(NULL), r);
|
||||
set_level(u3, SK_PERCEPTION, 2);
|
||||
usetsiege(u3, b);
|
||||
b->besieged = 1;
|
||||
building_add_siege(b, 1);
|
||||
CuAssertIntEquals(tc, 1, building_get_siege(b));
|
||||
CuAssertIntEquals(tc, 1, can_contact(r, u1, u2));
|
||||
|
||||
u_set_building(u1, b);
|
||||
|
@ -1759,6 +1760,34 @@ static void test_nmr_timeout(CuTest *tc) {
|
|||
test_teardown();
|
||||
}
|
||||
|
||||
static void test_long_orders(CuTest *tc) {
|
||||
unit *u;
|
||||
|
||||
test_setup();
|
||||
u = test_create_unit(test_create_faction(NULL), test_create_plain(0, 0));
|
||||
CuAssertTrue(tc, long_order_allowed(u));
|
||||
u->flags |= UFL_LONGACTION;
|
||||
CuAssertTrue(tc, !long_order_allowed(u));
|
||||
test_teardown();
|
||||
}
|
||||
|
||||
static void test_long_order_on_ocean(CuTest *tc) {
|
||||
unit *u;
|
||||
race * rc;
|
||||
|
||||
test_setup();
|
||||
rc = test_create_race("pikachu");
|
||||
u = test_create_unit(test_create_faction(rc), test_create_ocean(0, 0));
|
||||
CuAssertTrue(tc, !long_order_allowed(u));
|
||||
rc->flags |= RCF_SWIM;
|
||||
CuAssertTrue(tc, long_order_allowed(u));
|
||||
|
||||
rc = test_create_race("aquarian");
|
||||
u = test_create_unit(test_create_faction(rc), u->region);
|
||||
CuAssertTrue(tc, long_order_allowed(u));
|
||||
test_teardown();
|
||||
}
|
||||
|
||||
CuSuite *get_laws_suite(void)
|
||||
{
|
||||
CuSuite *suite = CuSuiteNew();
|
||||
|
@ -1831,6 +1860,8 @@ CuSuite *get_laws_suite(void)
|
|||
SUITE_ADD_TEST(suite, test_cansee_ring);
|
||||
SUITE_ADD_TEST(suite, test_cansee_sphere);
|
||||
SUITE_ADD_TEST(suite, test_nmr_timeout);
|
||||
SUITE_ADD_TEST(suite, test_long_orders);
|
||||
SUITE_ADD_TEST(suite, test_long_order_on_ocean);
|
||||
|
||||
return suite;
|
||||
}
|
||||
|
|
|
@ -1016,37 +1016,42 @@ static void eaten_by_monster(unit * u)
|
|||
{
|
||||
/* adjustment for smaller worlds */
|
||||
double multi = RESOURCE_QUANTITY * newterrain(T_PLAIN)->size / 10000.0;
|
||||
int n = 0;
|
||||
int horse = -1;
|
||||
const resource_type *rhorse = get_resourcetype(R_HORSE);
|
||||
const race *rc = u_race(u);
|
||||
int scare;
|
||||
int p = rpeasants(u->region);
|
||||
|
||||
scare = rc_scare(rc);
|
||||
if (scare>0) {
|
||||
n = rng_int() % scare * u->number;
|
||||
} else {
|
||||
n = rng_int() % (u->number / 20 + 1);
|
||||
horse = 0;
|
||||
}
|
||||
horse = horse ? i_get(u->items, rhorse->itype) : 0;
|
||||
if (p > 0) {
|
||||
int horse = -1;
|
||||
int scare = rc_scare(rc);
|
||||
int n = 0;
|
||||
|
||||
n = (int)(n * multi);
|
||||
if (n > 0) {
|
||||
|
||||
n = lovar(n);
|
||||
|
||||
if (n > 0) {
|
||||
int p = rpeasants(u->region);
|
||||
if (p < n) n = p;
|
||||
deathcounts(u->region, n);
|
||||
rsetpeasants(u->region, rpeasants(u->region) - n);
|
||||
ADDMSG(&u->region->msgs, msg_message("eatpeasants", "unit amount", u, n));
|
||||
if (scare > 0) {
|
||||
n = rng_int() % scare * u->number;
|
||||
}
|
||||
else {
|
||||
n = rng_int() % (u->number / 20 + 1);
|
||||
horse = 0;
|
||||
}
|
||||
|
||||
horse = horse ? i_get(u->items, rhorse->itype) : 0;
|
||||
if (horse > 0) {
|
||||
i_change(&u->items, rhorse->itype, -horse);
|
||||
ADDMSG(&u->region->msgs, msg_message("eathorse", "unit amount", u, horse));
|
||||
}
|
||||
|
||||
n = (int)(n * multi);
|
||||
if (n > 0) {
|
||||
n = lovar(n);
|
||||
|
||||
if (p < n) n = p;
|
||||
if (n > 0) {
|
||||
if (n > 0) {
|
||||
deathcounts(u->region, n);
|
||||
rsetpeasants(u->region, rpeasants(u->region) - n);
|
||||
ADDMSG(&u->region->msgs, msg_message("eatpeasants", "unit amount", u, n));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (horse > 0) {
|
||||
i_change(&u->items, rhorse->itype, -horse);
|
||||
ADDMSG(&u->region->msgs, msg_message("eathorse", "unit amount", u, horse));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1059,10 +1064,12 @@ static void absorbed_by_monster(unit * u)
|
|||
if (n > 0) {
|
||||
int p = rpeasants(u->region);
|
||||
if (p < n) n = p;
|
||||
rsetpeasants(u->region, rpeasants(u->region) - n);
|
||||
scale_number(u, u->number + n);
|
||||
ADDMSG(&u->region->msgs, msg_message("absorbpeasants",
|
||||
"unit race amount", u, u_race(u), n));
|
||||
if (n > 0) {
|
||||
rsetpeasants(u->region, rpeasants(u->region) - n);
|
||||
scale_number(u, u->number + n);
|
||||
ADDMSG(&u->region->msgs, msg_message("absorbpeasants",
|
||||
"unit race amount", u, u_race(u), n));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
16
src/report.c
16
src/report.c
|
@ -1853,14 +1853,16 @@ nr_building(struct stream *out, const region *r, const building *b, const factio
|
|||
sbs_strcat(&sbs, LOC(lang, "nr_building_inprogress"));
|
||||
}
|
||||
|
||||
if (b->besieged > 0 && r->seen.mode >= seen_lighthouse) {
|
||||
msg = msg_message("nr_building_besieged", "soldiers diff", b->besieged,
|
||||
b->besieged - b->size * SIEGEFACTOR);
|
||||
if (!keyword_disabled(K_BESIEGE) && r->seen.mode >= seen_lighthouse) {
|
||||
int s = building_get_siege(b);
|
||||
if (s > 0) {
|
||||
msg = msg_message("nr_building_besieged", "soldiers diff", s,
|
||||
s - b->size * SIEGEFACTOR);
|
||||
size = nr_render(msg, lang, sbs.end, sbs.size - (sbs.end - sbs.begin), f);
|
||||
sbs.end += size;
|
||||
|
||||
size = nr_render(msg, lang, sbs.end, sbs.size - (sbs.end - sbs.begin), f);
|
||||
sbs.end += size;
|
||||
|
||||
msg_release(msg);
|
||||
msg_release(msg);
|
||||
}
|
||||
}
|
||||
i = 0;
|
||||
if (b->display && b->display[0]) {
|
||||
|
|
|
@ -10,23 +10,11 @@
|
|||
without prior permission by the authors of Eressea.
|
||||
*/
|
||||
|
||||
#define ENTERTAINFRACTION 20
|
||||
#define TEACHDIFFERENCE 2
|
||||
#define RESOURCE_QUANTITY 0.5
|
||||
#define RECRUITFRACTION 40 /* 100/RECRUITFRACTION% */
|
||||
#define COMBAT_TURNS 5
|
||||
#undef NEWATSROI
|
||||
|
||||
/* Vermehrungsrate Bauern in 1/10000.
|
||||
* TODO: Evt. Berechnungsfehler, reale Vermehrungsraten scheinen hoeher. */
|
||||
#define PEASANTGROWTH 10
|
||||
#define PEASANTLUCK 10
|
||||
|
||||
#define ROW_FACTOR 3 /* factor for combat row advancement rule */
|
||||
|
||||
/* TODO: move these settings to settings.h or into configuration files */
|
||||
#define TREESIZE (8) /* space used by trees (in #peasants) */
|
||||
#define PEASANTFORCE 0.75 /* Chance einer Vermehrung trotz 90% Auslastung */
|
||||
|
||||
/* Gebaeudegroesse = Minimalbelagerer */
|
||||
#define SIEGEFACTOR 2
|
||||
|
|
35
src/skill.c
35
src/skill.c
|
@ -113,3 +113,38 @@ skill_t get_skill(const char *s, const struct locale * lang)
|
|||
return result;
|
||||
}
|
||||
|
||||
int skill_cost(skill_t sk) {
|
||||
static int config;
|
||||
static int costs[MAXSKILLS];
|
||||
int cost;
|
||||
switch (sk) {
|
||||
case SK_SPY:
|
||||
cost = 100;
|
||||
break;
|
||||
case SK_TACTICS:
|
||||
case SK_HERBALISM:
|
||||
case SK_ALCHEMY:
|
||||
cost = 200;
|
||||
break;
|
||||
default:
|
||||
cost = -1;
|
||||
}
|
||||
|
||||
if (config_changed(&config)) {
|
||||
memset(costs, 0, sizeof(costs));
|
||||
}
|
||||
|
||||
if (costs[sk] == 0) {
|
||||
char buffer[256];
|
||||
sprintf(buffer, "skills.cost.%s", skillnames[sk]);
|
||||
costs[sk] = config_get_int(buffer, cost);
|
||||
}
|
||||
if (costs[sk] >= 0) {
|
||||
return costs[sk];
|
||||
}
|
||||
return (cost > 0) ? cost : 0;
|
||||
}
|
||||
|
||||
bool expensive_skill(skill_t sk) {
|
||||
return (sk == SK_MAGIC) || skill_cost(sk) > 0;
|
||||
}
|
||||
|
|
|
@ -49,5 +49,7 @@ void init_skills(const struct locale *lang);
|
|||
void init_skill(const struct locale *lang, skill_t kwd, const char *str);
|
||||
void enable_skill(skill_t sk, bool enabled);
|
||||
bool skill_enabled(skill_t sk);
|
||||
int skill_cost(skill_t sk);
|
||||
bool expensive_skill(skill_t sk);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
#include <platform.h>
|
||||
#include "skill.h"
|
||||
|
||||
#include "kernel/config.h"
|
||||
#include "util/language.h"
|
||||
#include "skill.h"
|
||||
#include "tests.h"
|
||||
|
||||
#include <CuTest.h>
|
||||
|
@ -38,12 +40,34 @@ static void test_get_skill(CuTest *tc) {
|
|||
test_teardown();
|
||||
}
|
||||
|
||||
static void test_skill_cost(CuTest *tc) {
|
||||
test_setup();
|
||||
CuAssertTrue(tc, expensive_skill(SK_MAGIC));
|
||||
CuAssertTrue(tc, expensive_skill(SK_TACTICS));
|
||||
CuAssertTrue(tc, expensive_skill(SK_SPY));
|
||||
CuAssertTrue(tc, expensive_skill(SK_ALCHEMY));
|
||||
CuAssertTrue(tc, expensive_skill(SK_HERBALISM));
|
||||
CuAssertTrue(tc, !expensive_skill(SK_CROSSBOW));
|
||||
|
||||
CuAssertIntEquals(tc, 100, skill_cost(SK_SPY));
|
||||
CuAssertIntEquals(tc, 200, skill_cost(SK_TACTICS));
|
||||
CuAssertIntEquals(tc, 200, skill_cost(SK_ALCHEMY));
|
||||
CuAssertIntEquals(tc, 200, skill_cost(SK_HERBALISM));
|
||||
CuAssertIntEquals(tc, 0, skill_cost(SK_CROSSBOW));
|
||||
|
||||
config_set_int("skills.cost.crossbow", 300);
|
||||
CuAssertIntEquals(tc, 300, skill_cost(SK_CROSSBOW));
|
||||
CuAssertTrue(tc, expensive_skill(SK_CROSSBOW));
|
||||
test_teardown();
|
||||
}
|
||||
|
||||
CuSuite *get_skill_suite(void)
|
||||
{
|
||||
CuSuite *suite = CuSuiteNew();
|
||||
SUITE_ADD_TEST(suite, test_init_skill);
|
||||
SUITE_ADD_TEST(suite, test_init_skills);
|
||||
SUITE_ADD_TEST(suite, test_get_skill);
|
||||
SUITE_ADD_TEST(suite, test_skill_cost);
|
||||
return suite;
|
||||
}
|
||||
|
||||
|
|
140
src/study.c
140
src/study.c
|
@ -69,7 +69,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|||
#define TEACH_ALL 1
|
||||
#define TEACH_FRIENDS
|
||||
|
||||
static skill_t getskill(const struct locale *lang)
|
||||
skill_t getskill(const struct locale *lang)
|
||||
{
|
||||
char token[128];
|
||||
const char * s = gettoken(token, sizeof(token));
|
||||
|
@ -130,47 +130,23 @@ bool magic_lowskill(unit * u)
|
|||
return u_race(u) == toad_rc;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------- */
|
||||
|
||||
int study_cost(struct unit *u, skill_t sk)
|
||||
{
|
||||
static int config;
|
||||
static int costs[MAXSKILLS];
|
||||
int cost = -1;
|
||||
|
||||
if (sk == SK_MAGIC) {
|
||||
int next_level = 1 + (u ? get_level(u, sk) : 0);
|
||||
static int config;
|
||||
static int cost;
|
||||
/* Die Magiekosten betragen 50+Summe(50*Stufe) */
|
||||
/* 'Stufe' ist dabei die naechste zu erreichende Stufe */
|
||||
cost = config_get_int("skills.cost.magic", 50);
|
||||
return cost * (1 + ((next_level + next_level * next_level) / 2));
|
||||
if (config_changed(&config)) {
|
||||
cost = config_get_int("skills.cost.magic", 50);
|
||||
}
|
||||
if (cost > 0) {
|
||||
int next_level = 1 + (u ? get_level(u, sk) : 0);
|
||||
return cost * (1 + ((next_level + next_level * next_level) / 2));
|
||||
}
|
||||
return cost;
|
||||
}
|
||||
else switch (sk) {
|
||||
case SK_SPY:
|
||||
cost = 100;
|
||||
break;
|
||||
case SK_TACTICS:
|
||||
case SK_HERBALISM:
|
||||
case SK_ALCHEMY:
|
||||
cost = 200;
|
||||
break;
|
||||
default:
|
||||
cost = -1;
|
||||
}
|
||||
|
||||
if (config_changed(&config)) {
|
||||
memset(costs, 0, sizeof(costs));
|
||||
}
|
||||
|
||||
if (costs[sk] == 0) {
|
||||
char buffer[256];
|
||||
sprintf(buffer, "skills.cost.%s", skillnames[sk]);
|
||||
costs[sk] = config_get_int(buffer, cost);
|
||||
}
|
||||
if (costs[sk] >= 0) {
|
||||
return costs[sk];
|
||||
}
|
||||
return (cost > 0) ? cost : 0;
|
||||
return skill_cost(sk);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------- */
|
||||
|
@ -195,37 +171,37 @@ const attrib_type at_learning = {
|
|||
|
||||
#define EXPERIENCEDAYS 10
|
||||
|
||||
static int study_days(unit * student, skill_t sk)
|
||||
static int study_days(unit * scholar, skill_t sk)
|
||||
{
|
||||
int speed = STUDYDAYS;
|
||||
if (u_race(student)->study_speed) {
|
||||
speed += u_race(student)->study_speed[sk];
|
||||
if (u_race(scholar)->study_speed) {
|
||||
speed += u_race(scholar)->study_speed[sk];
|
||||
if (speed < STUDYDAYS) {
|
||||
skill *sv = unit_skill(student, sk);
|
||||
skill *sv = unit_skill(scholar, sk);
|
||||
if (sv == 0) {
|
||||
speed = STUDYDAYS;
|
||||
}
|
||||
}
|
||||
}
|
||||
return student->number * speed;
|
||||
return scholar->number * speed;
|
||||
}
|
||||
|
||||
static int
|
||||
teach_unit(unit * teacher, unit * student, int nteaching, skill_t sk,
|
||||
teach_unit(unit * teacher, unit * scholar, int nteaching, skill_t sk,
|
||||
bool report, int *academy_students)
|
||||
{
|
||||
teaching_info *teach = NULL;
|
||||
attrib *a;
|
||||
int students;
|
||||
|
||||
if (magic_lowskill(student)) {
|
||||
if (magic_lowskill(scholar)) {
|
||||
cmistake(teacher, teacher->thisorder, 292, MSG_EVENT);
|
||||
return 0;
|
||||
}
|
||||
|
||||
students = student->number;
|
||||
students = scholar->number;
|
||||
/* subtract already taught students */
|
||||
a = a_find(student->attribs, &at_learning);
|
||||
a = a_find(scholar->attribs, &at_learning);
|
||||
if (a != NULL) {
|
||||
teach = (teaching_info *)a->data.v;
|
||||
students -= teach->students;
|
||||
|
@ -235,18 +211,18 @@ teach_unit(unit * teacher, unit * student, int nteaching, skill_t sk,
|
|||
|
||||
if (students > 0) {
|
||||
if (teach == NULL) {
|
||||
a = a_add(&student->attribs, a_new(&at_learning));
|
||||
a = a_add(&scholar->attribs, a_new(&at_learning));
|
||||
teach = (teaching_info *)a->data.v;
|
||||
}
|
||||
selist_push(&teach->teachers, teacher);
|
||||
teach->days += students * STUDYDAYS;
|
||||
teach->students += students;
|
||||
|
||||
if (student->building && teacher->building == student->building) {
|
||||
if (scholar->building && teacher->building == 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, student, sk)) {
|
||||
if (academy_can_teach(teacher, scholar, sk)) {
|
||||
/* Jeder Schueler zusaetzlich +10 Tage wenn in Uni. */
|
||||
teach->days += students * EXPERIENCEDAYS; /* learning erhoehen */
|
||||
/* Lehrer zusaetzlich +1 Tag pro Schueler. */
|
||||
|
@ -304,7 +280,7 @@ int teach_cmd(unit * teacher, struct order *ord)
|
|||
#if TEACH_ALL
|
||||
if (getparam(teacher->faction->locale) == P_ANY) {
|
||||
skill_t sk;
|
||||
unit *student;
|
||||
unit *scholar;
|
||||
skill_t teachskill[MAXSKILLS];
|
||||
int t = 0;
|
||||
|
||||
|
@ -313,15 +289,15 @@ int teach_cmd(unit * teacher, struct order *ord)
|
|||
teachskill[t] = getskill(teacher->faction->locale);
|
||||
} while (sk != NOSKILL);
|
||||
|
||||
for (student = r->units; teaching > 0 && student; student = student->next) {
|
||||
if (LongHunger(student)) {
|
||||
for (scholar = r->units; teaching > 0 && scholar; scholar = scholar->next) {
|
||||
if (LongHunger(scholar)) {
|
||||
continue;
|
||||
}
|
||||
else if (student->faction == teacher->faction) {
|
||||
if (getkeyword(student->thisorder) == K_STUDY) {
|
||||
else if (scholar->faction == teacher->faction) {
|
||||
if (getkeyword(scholar->thisorder) == K_STUDY) {
|
||||
/* Input ist nun von student->thisorder !! */
|
||||
init_order(student->thisorder, student->faction->locale);
|
||||
sk = getskill(student->faction->locale);
|
||||
init_order(scholar->thisorder, scholar->faction->locale);
|
||||
sk = getskill(scholar->faction->locale);
|
||||
if (sk != NOSKILL && teachskill[0] != NOSKILL) {
|
||||
for (t = 0; teachskill[t] != NOSKILL; ++t) {
|
||||
if (sk == teachskill[t]) {
|
||||
|
@ -331,20 +307,20 @@ int teach_cmd(unit * teacher, struct order *ord)
|
|||
sk = teachskill[t];
|
||||
}
|
||||
if (sk != NOSKILL
|
||||
&& effskill_study(teacher, sk, 0) - TEACHDIFFERENCE > effskill_study(student, sk, 0)) {
|
||||
teaching -= teach_unit(teacher, student, teaching, sk, true, &academy_students);
|
||||
&& effskill_study(teacher, sk) - TEACHDIFFERENCE > effskill_study(scholar, sk)) {
|
||||
teaching -= teach_unit(teacher, scholar, teaching, sk, true, &academy_students);
|
||||
}
|
||||
}
|
||||
}
|
||||
#ifdef TEACH_FRIENDS
|
||||
else if (alliedunit(teacher, student->faction, HELP_GUARD)) {
|
||||
if (getkeyword(student->thisorder) == K_STUDY) {
|
||||
else if (alliedunit(teacher, scholar->faction, HELP_GUARD)) {
|
||||
if (getkeyword(scholar->thisorder) == K_STUDY) {
|
||||
/* Input ist nun von student->thisorder !! */
|
||||
init_order(student->thisorder, student->faction->locale);
|
||||
sk = getskill(student->faction->locale);
|
||||
init_order(scholar->thisorder, scholar->faction->locale);
|
||||
sk = getskill(scholar->faction->locale);
|
||||
if (sk != NOSKILL
|
||||
&& effskill_study(teacher, sk, 0) - TEACHDIFFERENCE >= effskill(student, sk, 0)) {
|
||||
teaching -= teach_unit(teacher, student, teaching, sk, true, &academy_students);
|
||||
&& effskill_study(teacher, sk) - TEACHDIFFERENCE >= effskill(scholar, sk, NULL)) {
|
||||
teaching -= teach_unit(teacher, scholar, teaching, sk, true, &academy_students);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -363,15 +339,15 @@ int teach_cmd(unit * teacher, struct order *ord)
|
|||
|
||||
while (!parser_end()) {
|
||||
skill_t sk;
|
||||
unit *student;
|
||||
unit *scholar;
|
||||
bool feedback;
|
||||
|
||||
getunit(r, teacher->faction, &student);
|
||||
getunit(r, teacher->faction, &scholar);
|
||||
++count;
|
||||
|
||||
/* Falls die Unit nicht gefunden wird, Fehler melden */
|
||||
|
||||
if (!student) {
|
||||
if (!scholar) {
|
||||
char tbuf[20];
|
||||
const char *uid;
|
||||
const char *token;
|
||||
|
@ -403,8 +379,8 @@ int teach_cmd(unit * teacher, struct order *ord)
|
|||
continue;
|
||||
}
|
||||
|
||||
feedback = teacher->faction == student->faction
|
||||
|| alliedunit(student, teacher->faction, HELP_GUARD);
|
||||
feedback = teacher->faction == scholar->faction
|
||||
|| alliedunit(scholar, teacher->faction, HELP_GUARD);
|
||||
|
||||
/* Neuen Befehl zusammenbauen. TEMP-Einheiten werden automatisch in
|
||||
* ihre neuen Nummern uebersetzt. */
|
||||
|
@ -412,31 +388,31 @@ int teach_cmd(unit * teacher, struct order *ord)
|
|||
strncat(zOrder, " ", sz - 1);
|
||||
--sz;
|
||||
}
|
||||
sz -= str_strlcpy(zOrder + 4096 - sz, itoa36(student->no), sz);
|
||||
sz -= str_strlcpy(zOrder + 4096 - sz, itoa36(scholar->no), sz);
|
||||
|
||||
if (getkeyword(student->thisorder) != K_STUDY) {
|
||||
if (getkeyword(scholar->thisorder) != K_STUDY) {
|
||||
ADDMSG(&teacher->faction->msgs,
|
||||
msg_feedback(teacher, ord, "teach_nolearn", "student", student));
|
||||
msg_feedback(teacher, ord, "teach_nolearn", "student", scholar));
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Input ist nun von student->thisorder !! */
|
||||
parser_pushstate();
|
||||
init_order(student->thisorder, student->faction->locale);
|
||||
sk = getskill(student->faction->locale);
|
||||
init_order(scholar->thisorder, scholar->faction->locale);
|
||||
sk = getskill(scholar->faction->locale);
|
||||
parser_popstate();
|
||||
|
||||
if (sk == NOSKILL) {
|
||||
ADDMSG(&teacher->faction->msgs,
|
||||
msg_feedback(teacher, ord, "teach_nolearn", "student", student));
|
||||
msg_feedback(teacher, ord, "teach_nolearn", "student", scholar));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (effskill_study(student, sk, 0) > effskill_study(teacher, sk, 0)
|
||||
if (effskill_study(scholar, sk) > effskill_study(teacher, sk)
|
||||
- TEACHDIFFERENCE) {
|
||||
if (feedback) {
|
||||
ADDMSG(&teacher->faction->msgs, msg_feedback(teacher, ord, "teach_asgood",
|
||||
"student", student));
|
||||
"student", scholar));
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
@ -444,18 +420,18 @@ int teach_cmd(unit * teacher, struct order *ord)
|
|||
/* ist der Magier schon spezialisiert, so versteht er nur noch
|
||||
* Lehrer seines Gebietes */
|
||||
sc_mage *mage1 = get_mage_depr(teacher);
|
||||
sc_mage *mage2 = get_mage_depr(student);
|
||||
sc_mage *mage2 = get_mage_depr(scholar);
|
||||
if (mage2 && mage1 && mage2->magietyp != M_GRAY
|
||||
&& mage1->magietyp != mage2->magietyp) {
|
||||
if (feedback) {
|
||||
ADDMSG(&teacher->faction->msgs, msg_feedback(teacher, ord,
|
||||
"error_different_magic", "target", student));
|
||||
"error_different_magic", "target", scholar));
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
sk_academy = sk;
|
||||
teaching -= teach_unit(teacher, student, teaching, sk, false, &academy_students);
|
||||
teaching -= teach_unit(teacher, scholar, teaching, sk, false, &academy_students);
|
||||
}
|
||||
new_order = create_order(K_TEACH, teacher->faction->locale, "%s", zOrder);
|
||||
replace_order(&teacher->orders, ord, new_order);
|
||||
|
@ -766,9 +742,6 @@ int study_cmd(unit * u, order * ord)
|
|||
days *= 2;
|
||||
}
|
||||
|
||||
if (fval(u, UFL_HUNGER))
|
||||
days /= 2;
|
||||
|
||||
learn_skill(u, sk, days);
|
||||
if (a != NULL) {
|
||||
if (teach->teachers) {
|
||||
|
@ -832,6 +805,9 @@ void learn_skill(unit *u, skill_t sk, int days) {
|
|||
int leveldays = STUDYDAYS * u->number;
|
||||
int weeks = 0;
|
||||
|
||||
if (fval(u, UFL_HUNGER)) {
|
||||
days /= 2;
|
||||
}
|
||||
assert(sk >= 0 && sk < MAXSKILLS);
|
||||
if (inject_learn_fun) {
|
||||
inject_learn_fun(u, sk, days);
|
||||
|
|
37
src/study.h
37
src/study.h
|
@ -29,25 +29,10 @@ extern "C" {
|
|||
struct unit;
|
||||
struct selist;
|
||||
|
||||
int teach_cmd(struct unit *u, struct order *ord);
|
||||
int study_cmd(struct unit *u, struct order *ord);
|
||||
|
||||
magic_t getmagicskill(const struct locale *lang);
|
||||
bool is_migrant(struct unit *u);
|
||||
int study_cost(struct unit *u, skill_t talent);
|
||||
|
||||
typedef void(*learn_fun)(struct unit *u, skill_t sk, int days);
|
||||
|
||||
#define STUDYDAYS 30
|
||||
void learn_skill(struct unit *u, skill_t sk, int days);
|
||||
void reduce_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);
|
||||
|
||||
void demon_skillchange(struct unit *u);
|
||||
|
||||
#define TEACHNUMBER 10
|
||||
#define TEACHDIFFERENCE 2
|
||||
|
||||
typedef struct teaching_info {
|
||||
struct selist *teachers;
|
||||
int students;
|
||||
|
@ -56,6 +41,24 @@ extern "C" {
|
|||
|
||||
extern const struct attrib_type at_learning;
|
||||
|
||||
int teach_cmd(struct unit *u, struct order *ord);
|
||||
int study_cmd(struct unit *u, struct order *ord);
|
||||
|
||||
magic_t getmagicskill(const struct locale *lang);
|
||||
skill_t getskill(const struct locale *lang);
|
||||
bool is_migrant(struct unit *u);
|
||||
int study_cost(struct unit *u, skill_t sk);
|
||||
|
||||
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);
|
||||
|
||||
void produceexp(struct unit *u, skill_t sk, int n);
|
||||
void produceexp_ex(struct unit *u, skill_t sk, int n, learn_fun learn);
|
||||
|
||||
void demon_skillchange(struct unit *u);
|
||||
|
||||
void inject_learn(learn_fun fun);
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
|
|
@ -89,15 +89,15 @@ static void setup_teacher(study_fixture *fix, skill_t sk) {
|
|||
setup_locale(lang);
|
||||
fix->u = test_create_unit(f, r);
|
||||
assert(fix->u);
|
||||
fix->u->thisorder = create_order(K_STUDY, f->locale, "%s", skillnames[sk]);
|
||||
fix->u->thisorder = create_order(K_STUDY, f->locale, skillnames[sk]);
|
||||
|
||||
fix->teachers[0] = test_create_unit(f, r);
|
||||
assert(fix->teachers[0]);
|
||||
fix->teachers[0]->thisorder = create_order(K_TEACH, f->locale, "%s", itoa36(fix->u->no));
|
||||
fix->teachers[0]->thisorder = create_order(K_TEACH, f->locale, itoa36(fix->u->no));
|
||||
|
||||
fix->teachers[1] = test_create_unit(f, r);
|
||||
assert(fix->teachers[1]);
|
||||
fix->teachers[1]->thisorder = create_order(K_TEACH, f->locale, "%s", itoa36(fix->u->no));
|
||||
fix->teachers[1]->thisorder = create_order(K_TEACH, f->locale, itoa36(fix->u->no));
|
||||
test_clear_messages(f);
|
||||
}
|
||||
|
||||
|
@ -110,7 +110,7 @@ static void test_study_no_teacher(CuTest *tc) {
|
|||
CuAssertPtrNotNull(tc, sv = unit_skill(fix.u, SK_CROSSBOW));
|
||||
CuAssertIntEquals(tc, 1, sv->level);
|
||||
CuAssertIntEquals(tc, 2, sv->weeks);
|
||||
CuAssertPtrEquals(tc, 0, test_get_last_message(fix.u->faction->msgs));
|
||||
CuAssertPtrEquals(tc, NULL, test_get_last_message(fix.u->faction->msgs));
|
||||
test_teardown();
|
||||
}
|
||||
|
||||
|
@ -121,7 +121,7 @@ static void test_study_with_teacher(CuTest *tc) {
|
|||
setup_teacher(&fix, SK_CROSSBOW);
|
||||
set_level(fix.teachers[0], SK_CROSSBOW, TEACHDIFFERENCE);
|
||||
teach_cmd(fix.teachers[0], fix.teachers[0]->thisorder);
|
||||
CuAssertPtrEquals(tc, 0, test_get_last_message(fix.u->faction->msgs));
|
||||
CuAssertPtrEquals(tc, NULL, test_get_last_message(fix.u->faction->msgs));
|
||||
study_cmd(fix.u, fix.u->thisorder);
|
||||
CuAssertPtrNotNull(tc, sv = unit_skill(fix.u, SK_CROSSBOW));
|
||||
CuAssertIntEquals(tc, 1, sv->level);
|
||||
|
@ -288,7 +288,7 @@ static void test_academy_bonus(CuTest *tc) {
|
|||
u1 = test_create_unit(u->faction, u->region);
|
||||
u3 = test_create_unit(u->faction, u->region);
|
||||
u0->thisorder = create_order(K_TEACH, loc, "%s %s", itoa36(u3->no), itoa36(u1->no));
|
||||
u->thisorder = create_order(K_TEACH, loc, "%s", itoa36(u1->no));
|
||||
u->thisorder = create_order(K_TEACH, loc, itoa36(u1->no));
|
||||
u1->thisorder = create_order(K_STUDY, loc, skillnames[SK_CROSSBOW]);
|
||||
u3->thisorder = create_order(K_STUDY, loc, skillnames[SK_CROSSBOW]);
|
||||
|
||||
|
@ -405,7 +405,7 @@ static void test_study_magic(CuTest *tc) {
|
|||
f = test_create_faction(NULL);
|
||||
lang = f->locale;
|
||||
u = test_create_unit(f, test_create_region(0, 0, NULL));
|
||||
u->thisorder = create_order(K_STUDY, lang, "%s", skillnames[SK_MAGIC]);
|
||||
u->thisorder = create_order(K_STUDY, lang, skillnames[SK_MAGIC]);
|
||||
itype = test_create_silver();
|
||||
|
||||
CuAssertIntEquals(tc, -1, study_cmd(u, u->thisorder));
|
||||
|
@ -423,7 +423,7 @@ static void test_study_magic(CuTest *tc) {
|
|||
CuAssertIntEquals(tc, M_GWYRRD, f->magiegebiet);
|
||||
CuAssertIntEquals(tc, 0, i_get(u->items, itype));
|
||||
CuAssertPtrNotNull(tc, get_mage_depr(u));
|
||||
CuAssertPtrEquals(tc, 0, test_find_messagetype(f->msgs, "error65"));
|
||||
CuAssertPtrEquals(tc, NULL, test_find_messagetype(f->msgs, "error65"));
|
||||
CuAssertIntEquals(tc, M_GWYRRD, get_mage_depr(u)->magietyp);
|
||||
|
||||
test_teardown();
|
||||
|
@ -491,12 +491,12 @@ static void test_teach_magic(CuTest *tc) {
|
|||
f = test_create_faction(NULL);
|
||||
f->magiegebiet = M_GWYRRD;
|
||||
u = test_create_unit(f, test_create_region(0, 0, NULL));
|
||||
u->thisorder = create_order(K_STUDY, f->locale, "%s", skillnames[SK_MAGIC]);
|
||||
u->thisorder = create_order(K_STUDY, f->locale, skillnames[SK_MAGIC]);
|
||||
i_change(&u->items, itype, study_cost(u, SK_MAGIC));
|
||||
ut = test_create_unit(f, u->region);
|
||||
set_level(ut, SK_MAGIC, TEACHDIFFERENCE);
|
||||
create_mage(ut, M_GWYRRD);
|
||||
ut->thisorder = create_order(K_TEACH, f->locale, "%s", itoa36(u->no));
|
||||
ut->thisorder = create_order(K_TEACH, f->locale, itoa36(u->no));
|
||||
learn_inject();
|
||||
teach_cmd(ut, ut->thisorder);
|
||||
study_cmd(u, u->thisorder);
|
||||
|
|
|
@ -93,7 +93,6 @@ int RunAllTests(int argc, char *argv[])
|
|||
ADD_SUITE(xerewards);
|
||||
/* kernel */
|
||||
ADD_SUITE(academy);
|
||||
ADD_SUITE(alchemy);
|
||||
ADD_SUITE(alliance);
|
||||
ADD_SUITE(ally);
|
||||
ADD_SUITE(building);
|
||||
|
@ -121,6 +120,8 @@ int RunAllTests(int argc, char *argv[])
|
|||
ADD_SUITE(spells);
|
||||
ADD_SUITE(unit);
|
||||
/* gamecode */
|
||||
ADD_SUITE(alchemy);
|
||||
ADD_SUITE(automate);
|
||||
ADD_SUITE(battle);
|
||||
ADD_SUITE(calendar);
|
||||
ADD_SUITE(creport);
|
||||
|
|
Binary file not shown.
|
@ -66,6 +66,7 @@ int pofile_read(const char *filename, int (*callback)(const char *msgid, const c
|
|||
|
||||
if (!F) {
|
||||
log_error("could not open %s", filename);
|
||||
return -1;
|
||||
}
|
||||
|
||||
msgctxt[0] = 0;
|
||||
|
@ -106,10 +107,10 @@ int pofile_read(const char *filename, int (*callback)(const char *msgid, const c
|
|||
line = read_line(F);
|
||||
}
|
||||
}
|
||||
if (ferror(F)) {
|
||||
log_error("read error in %s:%d.", filename, po_lineno);
|
||||
return -1;
|
||||
}
|
||||
err = ferror(F);
|
||||
fclose(F);
|
||||
if (err) {
|
||||
log_error("read error %d in %s:%d.", err, filename, po_lineno);
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
|
|
@ -12,7 +12,6 @@
|
|||
|
||||
#include <platform.h>
|
||||
#include <kernel/config.h>
|
||||
#include "settings.h"
|
||||
|
||||
#include "wormhole.h"
|
||||
|
||||
|
|
Loading…
Reference in New Issue