forked from github/server
Merge pull request #499 from ennorehling/feature/bug-2194-academy-refactoring
academy refactoring for bug 2194
This commit is contained in:
commit
95b0a0ad9c
2
critbit
2
critbit
|
@ -1 +1 @@
|
||||||
Subproject commit 934c2dd94d41da19637a76a1a8b3dfeb7aa8524d
|
Subproject commit ee7a32b9b8986bf2ea6b287975f9ef0ec997b7a3
|
|
@ -83,6 +83,7 @@ set (ERESSEA_SRC
|
||||||
spells.c
|
spells.c
|
||||||
battle.c
|
battle.c
|
||||||
alchemy.c
|
alchemy.c
|
||||||
|
academy.c
|
||||||
upkeep.c
|
upkeep.c
|
||||||
vortex.c
|
vortex.c
|
||||||
names.c
|
names.c
|
||||||
|
|
|
@ -0,0 +1,45 @@
|
||||||
|
/*
|
||||||
|
Copyright (c) 1998-2015, Enno Rehling <enno@eressea.de>
|
||||||
|
Katja Zedel <katze@felidae.kn-bremen.de
|
||||||
|
Christian Schlittchen <corwin@amber.kn-bremen.de>
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
purpose with or without fee is hereby granted, provided that the above
|
||||||
|
copyright notice and this permission notice appear in all copies.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
**/
|
||||||
|
|
||||||
|
#include <platform.h>
|
||||||
|
#include <kernel/config.h>
|
||||||
|
#include <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 academy) {
|
||||||
|
if (academy && sk != NOSKILL) {
|
||||||
|
academy = academy / 30; /* anzahl gelehrter wochen, max. 10 */
|
||||||
|
learn_skill(u, sk, academy / 30.0 / TEACHNUMBER);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool academy_can_teach(unit *teacher, unit *student, 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);
|
||||||
|
j = _max(50, j * 2);
|
||||||
|
/* kann Einheit das zahlen? */
|
||||||
|
return get_pooled(student, get_resourcetype(R_SILVER), GET_DEFAULT, j) >= j;
|
||||||
|
/* sonst nehmen sie nicht am Unterricht teil */
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
|
@ -0,0 +1,16 @@
|
||||||
|
#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 *student, skill_t sk);
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#endif
|
|
@ -21,6 +21,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
#include "alchemy.h"
|
#include "alchemy.h"
|
||||||
#include "move.h"
|
#include "move.h"
|
||||||
#include "skill.h"
|
#include "skill.h"
|
||||||
|
#include "study.h"
|
||||||
|
|
||||||
#include <kernel/item.h>
|
#include <kernel/item.h>
|
||||||
#include <kernel/faction.h>
|
#include <kernel/faction.h>
|
||||||
|
|
|
@ -53,10 +53,14 @@ static int a_readkey(attrib *a, void *owner, struct gamedata *data) {
|
||||||
return (res != AT_READ_FAIL) ? AT_READ_DEPR : res;
|
return (res != AT_READ_FAIL) ? AT_READ_DEPR : res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void a_freekeys(attrib *a) {
|
||||||
|
free(a->data.v);
|
||||||
|
}
|
||||||
|
|
||||||
attrib_type at_keys = {
|
attrib_type at_keys = {
|
||||||
"keys",
|
"keys",
|
||||||
NULL,
|
NULL,
|
||||||
NULL,
|
a_freekeys,
|
||||||
NULL,
|
NULL,
|
||||||
a_writekeys,
|
a_writekeys,
|
||||||
a_readkeys,
|
a_readkeys,
|
||||||
|
|
|
@ -39,6 +39,7 @@ static void test_upgrade(CuTest *tc) {
|
||||||
CuAssertTrue(tc, key_get(alist, 42));
|
CuAssertTrue(tc, key_get(alist, 42));
|
||||||
CuAssertTrue(tc, key_get(alist, 43));
|
CuAssertTrue(tc, key_get(alist, 43));
|
||||||
CuAssertTrue(tc, key_get(alist, 44));
|
CuAssertTrue(tc, key_get(alist, 44));
|
||||||
|
a_removeall(&alist, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
CuSuite *get_key_suite(void)
|
CuSuite *get_key_suite(void)
|
||||||
|
|
|
@ -27,6 +27,7 @@ without prior permission by the authors of Eressea.
|
||||||
#include "console.h"
|
#include "console.h"
|
||||||
#include "reports.h"
|
#include "reports.h"
|
||||||
#include "seen.h"
|
#include "seen.h"
|
||||||
|
#include "study.h"
|
||||||
#include "calendar.h"
|
#include "calendar.h"
|
||||||
|
|
||||||
#include <kernel/config.h>
|
#include <kernel/config.h>
|
||||||
|
|
|
@ -28,6 +28,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
#include "laws.h"
|
#include "laws.h"
|
||||||
#include "randenc.h"
|
#include "randenc.h"
|
||||||
#include "spy.h"
|
#include "spy.h"
|
||||||
|
#include "study.h"
|
||||||
#include "move.h"
|
#include "move.h"
|
||||||
#include "monster.h"
|
#include "monster.h"
|
||||||
#include "morale.h"
|
#include "morale.h"
|
||||||
|
|
|
@ -21,6 +21,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
#include "xerewards.h"
|
#include "xerewards.h"
|
||||||
|
|
||||||
#include "magic.h"
|
#include "magic.h"
|
||||||
|
#include "study.h"
|
||||||
|
|
||||||
/* kernel includes */
|
/* kernel includes */
|
||||||
#include <kernel/item.h>
|
#include <kernel/item.h>
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
#include <platform.h>
|
#include <platform.h>
|
||||||
|
|
||||||
#include "xerewards.h"
|
#include "xerewards.h"
|
||||||
|
#include "study.h"
|
||||||
|
|
||||||
#include <kernel/unit.h>
|
#include <kernel/unit.h>
|
||||||
#include <kernel/item.h>
|
#include <kernel/item.h>
|
||||||
|
|
|
@ -23,6 +23,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
#include "alchemy.h"
|
#include "alchemy.h"
|
||||||
#include "direction.h"
|
#include "direction.h"
|
||||||
#include "move.h"
|
#include "move.h"
|
||||||
|
#include "study.h"
|
||||||
#include "laws.h"
|
#include "laws.h"
|
||||||
#include "skill.h"
|
#include "skill.h"
|
||||||
#include "lighthouse.h"
|
#include "lighthouse.h"
|
||||||
|
|
|
@ -318,7 +318,7 @@ bool checkpasswd(const faction * f, const char *passwd)
|
||||||
{
|
{
|
||||||
if (!passwd) return false;
|
if (!passwd) return false;
|
||||||
|
|
||||||
if (password_verify(f->_password, passwd) == VERIFY_FAIL) {
|
if (f->_password && password_verify(f->_password, passwd) == VERIFY_FAIL) {
|
||||||
log_warning("password check failed: %s", factionname(f));
|
log_warning("password check failed: %s", factionname(f));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -342,7 +342,7 @@ static faction *dead_factions;
|
||||||
|
|
||||||
void free_flist(faction **fp) {
|
void free_flist(faction **fp) {
|
||||||
faction * flist = *fp;
|
faction * flist = *fp;
|
||||||
for (flist = factions; flist;) {
|
while (flist) {
|
||||||
faction *f = flist;
|
faction *f = flist;
|
||||||
flist = f->next;
|
flist = f->next;
|
||||||
free_faction(f);
|
free_faction(f);
|
||||||
|
@ -681,8 +681,6 @@ void remove_empty_factions(void)
|
||||||
if (!(f->_alive && f->units!=NULL) && !fval(f, FFL_NOIDLEOUT)) {
|
if (!(f->_alive && f->units!=NULL) && !fval(f, FFL_NOIDLEOUT)) {
|
||||||
log_debug("dead: %s", factionname(f));
|
log_debug("dead: %s", factionname(f));
|
||||||
destroyfaction(fp);
|
destroyfaction(fp);
|
||||||
free_faction(f);
|
|
||||||
free(f);
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
fp = &(*fp)->next;
|
fp = &(*fp)->next;
|
||||||
|
|
|
@ -132,6 +132,9 @@ void free_group(group * g)
|
||||||
assert(*g_ptr == g);
|
assert(*g_ptr == g);
|
||||||
*g_ptr = g->nexthash;
|
*g_ptr = g->nexthash;
|
||||||
|
|
||||||
|
if (g->attribs) {
|
||||||
|
a_removeall(&g->attribs, NULL);
|
||||||
|
}
|
||||||
while (g->allies) {
|
while (g->allies) {
|
||||||
ally *a = g->allies;
|
ally *a = g->allies;
|
||||||
g->allies = a->next;
|
g->allies = a->next;
|
||||||
|
|
|
@ -1203,13 +1203,16 @@ static void free_wtype(weapon_type *wtype) {
|
||||||
int free_rtype_cb(const void * match, const void * key, size_t keylen, void *cbdata) {
|
int free_rtype_cb(const void * match, const void * key, size_t keylen, void *cbdata) {
|
||||||
resource_type *rtype;
|
resource_type *rtype;
|
||||||
cb_get_kv(match, &rtype, sizeof(rtype));
|
cb_get_kv(match, &rtype, sizeof(rtype));
|
||||||
free(rtype->_name);
|
|
||||||
if (rtype->itype) {
|
|
||||||
free_itype(rtype->itype);
|
|
||||||
}
|
|
||||||
if (rtype->wtype) {
|
if (rtype->wtype) {
|
||||||
free_wtype(rtype->wtype);
|
free_wtype(rtype->wtype);
|
||||||
}
|
}
|
||||||
|
if (rtype->atype) {
|
||||||
|
free(rtype->atype);
|
||||||
|
}
|
||||||
|
if (rtype->itype) {
|
||||||
|
free_itype(rtype->itype);
|
||||||
|
}
|
||||||
|
free(rtype->_name);
|
||||||
free(rtype);
|
free(rtype);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -141,6 +141,7 @@ void racelist_insert(struct race_list **rl, const struct race *r)
|
||||||
void free_races(void) {
|
void free_races(void) {
|
||||||
while (races) {
|
while (races) {
|
||||||
race * rc = races->next;
|
race * rc = races->next;
|
||||||
|
free_params(&races->parameters);
|
||||||
free(races->_name);
|
free(races->_name);
|
||||||
free(races->def_damage);
|
free(races->def_damage);
|
||||||
free(races);
|
free(races);
|
||||||
|
|
|
@ -296,6 +296,7 @@ static void test_read_password_external(CuTest *tc) {
|
||||||
fclose(F);
|
fclose(F);
|
||||||
_test_read_password(&data, f);
|
_test_read_password(&data, f);
|
||||||
CuAssertPtrNotNull(tc, f->_password);
|
CuAssertPtrNotNull(tc, f->_password);
|
||||||
|
mstream_done(&data.strm);
|
||||||
gamedata_done(&data);
|
gamedata_done(&data);
|
||||||
CuAssertTrue(tc, checkpasswd(f, "secret"));
|
CuAssertTrue(tc, checkpasswd(f, "secret"));
|
||||||
CuAssertIntEquals(tc, 0, remove(pwfile));
|
CuAssertIntEquals(tc, 0, remove(pwfile));
|
||||||
|
|
|
@ -28,7 +28,6 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
#include "curse.h"
|
#include "curse.h"
|
||||||
#include "item.h"
|
#include "item.h"
|
||||||
#include "move.h"
|
#include "move.h"
|
||||||
#include "monster.h"
|
|
||||||
#include "order.h"
|
#include "order.h"
|
||||||
#include "plane.h"
|
#include "plane.h"
|
||||||
#include "race.h"
|
#include "race.h"
|
||||||
|
@ -1130,30 +1129,6 @@ void set_number(unit * u, int count)
|
||||||
u->number = (unsigned short)count;
|
u->number = (unsigned short)count;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool learn_skill(unit * u, skill_t sk, double learn_chance)
|
|
||||||
{
|
|
||||||
skill *sv = u->skills;
|
|
||||||
if (learn_chance < 1.0 && rng_int() % 10000 >= learn_chance * 10000)
|
|
||||||
if (!chance(learn_chance))
|
|
||||||
return false;
|
|
||||||
while (sv != u->skills + u->skill_size) {
|
|
||||||
assert(sv->weeks > 0);
|
|
||||||
if (sv->id == sk) {
|
|
||||||
if (sv->weeks <= 1) {
|
|
||||||
sk_set(sv, sv->level + 1);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
sv->weeks--;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
++sv;
|
|
||||||
}
|
|
||||||
sv = add_skill(u, sk);
|
|
||||||
sk_set(sv, 1);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void remove_skill(unit * u, skill_t sk)
|
void remove_skill(unit * u, skill_t sk)
|
||||||
{
|
{
|
||||||
skill *sv = u->skills;
|
skill *sv = u->skills;
|
||||||
|
@ -1892,25 +1867,6 @@ bool unit_can_study(const unit *u) {
|
||||||
return !((u_race(u)->flags & RCF_NOLEARN) || fval(u, UFL_WERE));
|
return !((u_race(u)->flags & RCF_NOLEARN) || fval(u, UFL_WERE));
|
||||||
}
|
}
|
||||||
|
|
||||||
static double produceexp_chance(void) {
|
|
||||||
return config_get_flt("study.from_use", 1.0 / 3);
|
|
||||||
}
|
|
||||||
|
|
||||||
void produceexp_ex(struct unit *u, skill_t sk, int n, bool(*learn)(unit *, skill_t, double))
|
|
||||||
{
|
|
||||||
if (n != 0 && (is_monsters(u->faction) || playerrace(u_race(u)))) {
|
|
||||||
double chance = produceexp_chance();
|
|
||||||
if (chance > 0.0F) {
|
|
||||||
learn(u, sk, (n * chance) / u->number);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void produceexp(struct unit *u, skill_t sk, int n)
|
|
||||||
{
|
|
||||||
produceexp_ex(u, sk, n, learn_skill);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ID's für Einheiten und Zauber */
|
/* ID's für Einheiten und Zauber */
|
||||||
int newunitid(void)
|
int newunitid(void)
|
||||||
{
|
{
|
||||||
|
|
|
@ -162,9 +162,6 @@ extern "C" {
|
||||||
struct skill *unit_skill(const struct unit *u, skill_t id);
|
struct skill *unit_skill(const struct unit *u, skill_t id);
|
||||||
bool has_skill(const unit * u, skill_t sk);
|
bool has_skill(const unit * u, skill_t sk);
|
||||||
int effskill(const struct unit *u, skill_t sk, const struct region *r);
|
int effskill(const struct unit *u, skill_t sk, const struct region *r);
|
||||||
int SkillCap(skill_t sk);
|
|
||||||
void produceexp(struct unit *u, skill_t sk, int n);
|
|
||||||
void produceexp_ex(struct unit *u, skill_t sk, int n, bool (*learn)(unit *, skill_t, double));
|
|
||||||
|
|
||||||
void set_level(struct unit *u, skill_t id, int level);
|
void set_level(struct unit *u, skill_t id, int level);
|
||||||
int get_level(const struct unit *u, skill_t id);
|
int get_level(const struct unit *u, skill_t id);
|
||||||
|
@ -209,8 +206,6 @@ extern "C" {
|
||||||
void u_setfaction(struct unit *u, struct faction *f);
|
void u_setfaction(struct unit *u, struct faction *f);
|
||||||
void set_number(struct unit *u, int count);
|
void set_number(struct unit *u, int count);
|
||||||
|
|
||||||
bool learn_skill(struct unit *u, skill_t sk, double chance);
|
|
||||||
|
|
||||||
int invisible(const struct unit *target, const struct unit *viewer);
|
int invisible(const struct unit *target, const struct unit *viewer);
|
||||||
void free_unit(struct unit *u);
|
void free_unit(struct unit *u);
|
||||||
|
|
||||||
|
|
|
@ -341,32 +341,6 @@ static void test_age_familiar(CuTest *tc) {
|
||||||
test_cleanup();
|
test_cleanup();
|
||||||
}
|
}
|
||||||
|
|
||||||
static CuTest *g_tc;
|
|
||||||
|
|
||||||
static bool cb_learn_one(unit *u, skill_t sk, double chance) {
|
|
||||||
CuAssertIntEquals(g_tc, SK_ALCHEMY, sk);
|
|
||||||
CuAssertDblEquals(g_tc, 0.5 / u->number, chance, 0.01);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool cb_learn_two(unit *u, skill_t sk, double chance) {
|
|
||||||
CuAssertIntEquals(g_tc, SK_ALCHEMY, sk);
|
|
||||||
CuAssertDblEquals(g_tc, 2 * 0.5 / u->number, chance, 0.01);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void test_produceexp(CuTest *tc) {
|
|
||||||
unit *u;
|
|
||||||
|
|
||||||
g_tc = tc;
|
|
||||||
test_cleanup();
|
|
||||||
u = test_create_unit(test_create_faction(0), test_create_region(0, 0, 0));
|
|
||||||
config_set("study.from_use", "0.5");
|
|
||||||
produceexp_ex(u, SK_ALCHEMY, 1, cb_learn_one);
|
|
||||||
produceexp_ex(u, SK_ALCHEMY, 2, cb_learn_two);
|
|
||||||
test_cleanup();
|
|
||||||
}
|
|
||||||
|
|
||||||
static void test_inside_building(CuTest *tc) {
|
static void test_inside_building(CuTest *tc) {
|
||||||
unit *u;
|
unit *u;
|
||||||
building *b;
|
building *b;
|
||||||
|
@ -433,7 +407,6 @@ CuSuite *get_unit_suite(void)
|
||||||
SUITE_ADD_TEST(suite, test_skill_familiar);
|
SUITE_ADD_TEST(suite, test_skill_familiar);
|
||||||
SUITE_ADD_TEST(suite, test_age_familiar);
|
SUITE_ADD_TEST(suite, test_age_familiar);
|
||||||
SUITE_ADD_TEST(suite, test_inside_building);
|
SUITE_ADD_TEST(suite, test_inside_building);
|
||||||
SUITE_ADD_TEST(suite, test_produceexp);
|
|
||||||
SUITE_ADD_TEST(suite, test_limited_skills);
|
SUITE_ADD_TEST(suite, test_limited_skills);
|
||||||
return suite;
|
return suite;
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,7 +32,7 @@
|
||||||
#define EXPLICIT_CURSE_ISNEW_VERSION 347 /* CURSE_ISNEW is not reset in read/write, but in age() */
|
#define EXPLICIT_CURSE_ISNEW_VERSION 347 /* CURSE_ISNEW is not reset in read/write, but in age() */
|
||||||
#define SPELL_LEVEL_VERSION 348 /* f->max_spelllevel gets stored, not calculated */
|
#define SPELL_LEVEL_VERSION 348 /* f->max_spelllevel gets stored, not calculated */
|
||||||
#define OWNER_3_VERSION 349 /* regions store last owner, not last alliance */
|
#define OWNER_3_VERSION 349 /* regions store last owner, not last alliance */
|
||||||
#define ATTRIBOWNER_VERSION 350 /* all attrib_type functions know who owns the attribute */
|
#define ATTRIBOWNER_VERSION 351 /* all attrib_type functions know who owns the attribute */
|
||||||
#define BADCRYPT_VERSION 351 /* passwords are encrypted, poorly */
|
#define BADCRYPT_VERSION 351 /* passwords are encrypted, poorly */
|
||||||
#define ATHASH_VERSION 352 /* attribute-type hash, not name */
|
#define ATHASH_VERSION 352 /* attribute-type hash, not name */
|
||||||
#define NOWATCH_VERSION 353 /* plane->watchers is gone */
|
#define NOWATCH_VERSION 353 /* plane->watchers is gone */
|
||||||
|
|
|
@ -22,6 +22,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
#include "magic.h"
|
#include "magic.h"
|
||||||
|
|
||||||
#include "skill.h"
|
#include "skill.h"
|
||||||
|
#include "study.h"
|
||||||
#include "laws.h"
|
#include "laws.h"
|
||||||
|
|
||||||
#include <kernel/ally.h>
|
#include <kernel/ally.h>
|
||||||
|
|
|
@ -26,6 +26,7 @@
|
||||||
#include "monster.h"
|
#include "monster.h"
|
||||||
#include "laws.h"
|
#include "laws.h"
|
||||||
#include "keyword.h"
|
#include "keyword.h"
|
||||||
|
#include "study.h"
|
||||||
|
|
||||||
/* triggers includes */
|
/* triggers includes */
|
||||||
#include <triggers/removecurse.h>
|
#include <triggers/removecurse.h>
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
#include "monster.h"
|
#include "monster.h"
|
||||||
#include "guard.h"
|
#include "guard.h"
|
||||||
#include "skill.h"
|
#include "skill.h"
|
||||||
|
#include "study.h"
|
||||||
|
|
||||||
#include <util/language.h>
|
#include <util/language.h>
|
||||||
|
|
||||||
|
|
|
@ -22,6 +22,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
#include "move.h"
|
#include "move.h"
|
||||||
#include "laws.h"
|
#include "laws.h"
|
||||||
#include "reports.h"
|
#include "reports.h"
|
||||||
|
#include "study.h"
|
||||||
#include "alchemy.h"
|
#include "alchemy.h"
|
||||||
#include "travelthru.h"
|
#include "travelthru.h"
|
||||||
#include "vortex.h"
|
#include "vortex.h"
|
||||||
|
|
|
@ -38,6 +38,7 @@ static void test_ship_not_allowed_in_coast(CuTest * tc)
|
||||||
ttype = test_create_terrain("glacier", LAND_REGION | ARCTIC_REGION | WALK_INTO | SAIL_INTO);
|
ttype = test_create_terrain("glacier", LAND_REGION | ARCTIC_REGION | WALK_INTO | SAIL_INTO);
|
||||||
otype = test_create_terrain("ocean", SEA_REGION | SAIL_INTO);
|
otype = test_create_terrain("ocean", SEA_REGION | SAIL_INTO);
|
||||||
stype = test_create_shiptype("derp");
|
stype = test_create_shiptype("derp");
|
||||||
|
free(stype->coasts);
|
||||||
stype->coasts = (struct terrain_type **)calloc(2, sizeof(struct terrain_type *));
|
stype->coasts = (struct terrain_type **)calloc(2, sizeof(struct terrain_type *));
|
||||||
|
|
||||||
r1 = test_create_region(0, 0, ttype);
|
r1 = test_create_region(0, 0, ttype);
|
||||||
|
|
|
@ -47,6 +47,7 @@ static void setup_pirate(unit **pirate, int p_r_flags, int p_rc_flags, const cha
|
||||||
if (v_shiptype) {
|
if (v_shiptype) {
|
||||||
st_boat = st_get_or_create(v_shiptype);
|
st_boat = st_get_or_create(v_shiptype);
|
||||||
u_set_ship(*victim, test_create_ship((*victim)->region, st_boat));
|
u_set_ship(*victim, test_create_ship((*victim)->region, st_boat));
|
||||||
|
free(st_boat->coasts);
|
||||||
st_boat->coasts = (struct terrain_type **)calloc(2, sizeof(struct terrain_type *));
|
st_boat->coasts = (struct terrain_type **)calloc(2, sizeof(struct terrain_type *));
|
||||||
st_boat->coasts[0] = vterrain;
|
st_boat->coasts[0] = vterrain;
|
||||||
st_boat->coasts[1] = 0;
|
st_boat->coasts[1] = 0;
|
||||||
|
@ -59,6 +60,7 @@ static void setup_pirate(unit **pirate, int p_r_flags, int p_rc_flags, const cha
|
||||||
if (p_shiptype) {
|
if (p_shiptype) {
|
||||||
st_boat = st_get_or_create(p_shiptype);
|
st_boat = st_get_or_create(p_shiptype);
|
||||||
u_set_ship(*pirate, test_create_ship((*pirate)->region, st_boat));
|
u_set_ship(*pirate, test_create_ship((*pirate)->region, st_boat));
|
||||||
|
free(st_boat->coasts);
|
||||||
st_boat->coasts = (struct terrain_type **)calloc(2, sizeof(struct terrain_type *));
|
st_boat->coasts = (struct terrain_type **)calloc(2, sizeof(struct terrain_type *));
|
||||||
st_boat->coasts[0] = vterrain;
|
st_boat->coasts[0] = vterrain;
|
||||||
st_boat->coasts[1] = 0;
|
st_boat->coasts[1] = 0;
|
||||||
|
|
|
@ -25,6 +25,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
#include "move.h"
|
#include "move.h"
|
||||||
#include "alchemy.h"
|
#include "alchemy.h"
|
||||||
#include "chaos.h"
|
#include "chaos.h"
|
||||||
|
#include "study.h"
|
||||||
|
|
||||||
/* kernel includes */
|
/* kernel includes */
|
||||||
#include <kernel/building.h>
|
#include <kernel/building.h>
|
||||||
|
|
|
@ -405,7 +405,8 @@ static void test_write_spell_syntax(CuTest *tc) {
|
||||||
set_parameter(spell, "kc+");
|
set_parameter(spell, "kc+");
|
||||||
check_spell_syntax(tc, "kc+", &spell,
|
check_spell_syntax(tc, "kc+", &spell,
|
||||||
" ZAUBERE \"Testzauber\" ( REGION | EINHEIT <enr> [<enr> ...] | SCHIFF <snr>\n [<snr> ...] | BURG <bnr> [<bnr> ...] )");
|
" ZAUBERE \"Testzauber\" ( REGION | EINHEIT <enr> [<enr> ...] | SCHIFF <snr>\n [<snr> ...] | BURG <bnr> [<bnr> ...] )");
|
||||||
|
spellbook_clear(spell.spb);
|
||||||
|
free(spell.spb);
|
||||||
test_cleanup();
|
test_cleanup();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -44,19 +44,23 @@ static void test_flyingship(CuTest * tc)
|
||||||
|
|
||||||
sh1 = test_create_ship(r, shipType1);
|
sh1 = test_create_ship(r, shipType1);
|
||||||
par_data.data.sh = sh1;
|
par_data.data.sh = sh1;
|
||||||
test_create_castorder(&co, u, 10, 10.0, 0, &par);
|
|
||||||
|
|
||||||
|
test_create_castorder(&co, u, 10, 10.0, 0, &par);
|
||||||
CuAssertTrue(tc, !flying_ship(sh1));
|
CuAssertTrue(tc, !flying_ship(sh1));
|
||||||
CuAssertIntEquals(tc, 10, sp_flying_ship(&co));
|
CuAssertIntEquals(tc, 10, sp_flying_ship(&co));
|
||||||
CuAssertTrue(tc, flying_ship(sh1));
|
CuAssertTrue(tc, flying_ship(sh1));
|
||||||
|
co.par = 0;
|
||||||
|
free_castorder(&co);
|
||||||
|
|
||||||
sh2 = test_create_ship(r, shipType2);
|
sh2 = test_create_ship(r, shipType2);
|
||||||
par_data.data.sh = sh2;
|
par_data.data.sh = sh2;
|
||||||
test_create_castorder(&co, u, 10, 10.0, 0, &par);
|
|
||||||
|
|
||||||
|
test_create_castorder(&co, u, 10, 10.0, 0, &par);
|
||||||
CuAssertTrue(tc, !flying_ship(sh2));
|
CuAssertTrue(tc, !flying_ship(sh2));
|
||||||
CuAssertIntEquals(tc, 0, sp_flying_ship(&co));
|
CuAssertIntEquals(tc, 0, sp_flying_ship(&co));
|
||||||
CuAssertTrue(tc, !flying_ship(sh2));
|
CuAssertTrue(tc, !flying_ship(sh2));
|
||||||
|
co.par = 0;
|
||||||
|
free_castorder(&co);
|
||||||
test_cleanup();
|
test_cleanup();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -22,6 +22,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
#include "laws.h"
|
#include "laws.h"
|
||||||
#include "move.h"
|
#include "move.h"
|
||||||
#include "reports.h"
|
#include "reports.h"
|
||||||
|
#include "study.h"
|
||||||
|
|
||||||
/* kernel includes */
|
/* kernel includes */
|
||||||
#include <kernel/item.h>
|
#include <kernel/item.h>
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
#include <platform.h>
|
#include <platform.h>
|
||||||
|
|
||||||
#include <magic.h>
|
#include <magic.h>
|
||||||
|
#include <kernel/config.h>
|
||||||
#include <kernel/types.h>
|
#include <kernel/types.h>
|
||||||
#include <kernel/region.h>
|
#include <kernel/region.h>
|
||||||
#include <kernel/unit.h>
|
#include <kernel/unit.h>
|
||||||
|
@ -90,7 +91,8 @@ static void setup_sabotage(void) {
|
||||||
test_cleanup();
|
test_cleanup();
|
||||||
lang = get_or_create_locale("de");
|
lang = get_or_create_locale("de");
|
||||||
locale_setstring(lang, parameters[P_SHIP], "SCHIFF");
|
locale_setstring(lang, parameters[P_SHIP], "SCHIFF");
|
||||||
test_create_world();
|
locale_setstring(lang, parameters[P_ANY], "ALLE");
|
||||||
|
init_parameters(lang);
|
||||||
init_locales();
|
init_locales();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -100,7 +102,7 @@ static void test_sabotage_self(CuTest *tc) {
|
||||||
order *ord;
|
order *ord;
|
||||||
|
|
||||||
setup_sabotage();
|
setup_sabotage();
|
||||||
r = findregion(0, 0);
|
r = test_create_region(0, 0, 0);
|
||||||
assert(r);
|
assert(r);
|
||||||
u = test_create_unit(test_create_faction(NULL), r);
|
u = test_create_unit(test_create_faction(NULL), r);
|
||||||
assert(u && u->faction && u->region == r);
|
assert(u && u->faction && u->region == r);
|
||||||
|
@ -122,7 +124,7 @@ static void test_sabotage_other_fail(CuTest *tc) {
|
||||||
message *msg;
|
message *msg;
|
||||||
|
|
||||||
setup_sabotage();
|
setup_sabotage();
|
||||||
r = findregion(0, 0);
|
r = test_create_region(0, 0, 0);
|
||||||
assert(r);
|
assert(r);
|
||||||
u = test_create_unit(test_create_faction(NULL), r);
|
u = test_create_unit(test_create_faction(NULL), r);
|
||||||
u2 = test_create_unit(test_create_faction(NULL), r);
|
u2 = test_create_unit(test_create_faction(NULL), r);
|
||||||
|
@ -151,7 +153,7 @@ static void test_sabotage_other_success(CuTest *tc) {
|
||||||
order *ord;
|
order *ord;
|
||||||
|
|
||||||
setup_sabotage();
|
setup_sabotage();
|
||||||
r = findregion(0, 0);
|
r = test_create_region(0, 0, 0);
|
||||||
assert(r);
|
assert(r);
|
||||||
u = test_create_unit(test_create_faction(NULL), r);
|
u = test_create_unit(test_create_faction(NULL), r);
|
||||||
u2 = test_create_unit(test_create_faction(NULL), r);
|
u2 = test_create_unit(test_create_faction(NULL), r);
|
||||||
|
|
80
src/study.c
80
src/study.c
|
@ -23,7 +23,9 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
#include <kernel/config.h>
|
#include <kernel/config.h>
|
||||||
#include "study.h"
|
#include "study.h"
|
||||||
#include "move.h"
|
#include "move.h"
|
||||||
|
#include "monster.h"
|
||||||
#include "alchemy.h"
|
#include "alchemy.h"
|
||||||
|
#include "academy.h"
|
||||||
|
|
||||||
#include <kernel/ally.h>
|
#include <kernel/ally.h>
|
||||||
#include <kernel/building.h>
|
#include <kernel/building.h>
|
||||||
|
@ -47,6 +49,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
#include <util/log.h>
|
#include <util/log.h>
|
||||||
#include <util/parser.h>
|
#include <util/parser.h>
|
||||||
#include <util/rand.h>
|
#include <util/rand.h>
|
||||||
|
#include <util/rng.h>
|
||||||
#include <util/umlaut.h>
|
#include <util/umlaut.h>
|
||||||
|
|
||||||
/* libc includes */
|
/* libc includes */
|
||||||
|
@ -57,8 +60,6 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
|
|
||||||
#define TEACHNUMBER 10
|
|
||||||
|
|
||||||
static skill_t getskill(const struct locale *lang)
|
static skill_t getskill(const struct locale *lang)
|
||||||
{
|
{
|
||||||
char token[128];
|
char token[128];
|
||||||
|
@ -206,7 +207,6 @@ teach_unit(unit * teacher, unit * student, int nteaching, skill_t sk,
|
||||||
n = _min(n, nteaching);
|
n = _min(n, nteaching);
|
||||||
|
|
||||||
if (n != 0) {
|
if (n != 0) {
|
||||||
const struct building_type *btype = bt_find("academy");
|
|
||||||
int index = 0;
|
int index = 0;
|
||||||
|
|
||||||
if (teach == NULL) {
|
if (teach == NULL) {
|
||||||
|
@ -227,21 +227,18 @@ teach_unit(unit * teacher, unit * student, int nteaching, skill_t sk,
|
||||||
}
|
}
|
||||||
teach->value += n;
|
teach->value += n;
|
||||||
|
|
||||||
|
if (student->building && teacher->building == student->building) {
|
||||||
/* Solange Akademien groessenbeschraenkt sind, sollte Lehrer und
|
/* Solange Akademien groessenbeschraenkt sind, sollte Lehrer und
|
||||||
* Student auch in unterschiedlichen Gebaeuden stehen duerfen */
|
* Student auch in unterschiedlichen Gebaeuden stehen duerfen */
|
||||||
if (active_building(teacher, btype) && active_building(student, btype)) {
|
if (academy_can_teach(teacher, student, sk)) {
|
||||||
int j = study_cost(student, sk);
|
|
||||||
j = _max(50, j * 2);
|
|
||||||
/* kann Einheit das zahlen? */
|
|
||||||
if (get_pooled(student, get_resourcetype(R_SILVER), GET_DEFAULT, j) >= j) {
|
|
||||||
/* Jeder Schueler zusaetzlich +10 Tage wenn in Uni. */
|
/* Jeder Schueler zusaetzlich +10 Tage wenn in Uni. */
|
||||||
teach->value += (n / 30) * 10; /* learning erhoehen */
|
teach->value += (n / 30) * 10; /* learning erhoehen */
|
||||||
/* Lehrer zusaetzlich +1 Tag pro Schueler. */
|
/* Lehrer zusaetzlich +1 Tag pro Schueler. */
|
||||||
if (academy)
|
if (academy) {
|
||||||
*academy += n;
|
*academy += n;
|
||||||
} /* sonst nehmen sie nicht am Unterricht teil */
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
/* Teaching ist die Anzahl Leute, denen man noch was beibringen kann. Da
|
/* Teaching ist die Anzahl Leute, denen man noch was beibringen kann. Da
|
||||||
* hier nicht n verwendet wird, werden die Leute gezaehlt und nicht die
|
* hier nicht n verwendet wird, werden die Leute gezaehlt und nicht die
|
||||||
* effektiv gelernten Tage. -> FALSCH ? (ENNO)
|
* effektiv gelernten Tage. -> FALSCH ? (ENNO)
|
||||||
|
@ -482,9 +479,8 @@ int teach_cmd(unit * u, struct order *ord)
|
||||||
replace_order(&u->orders, ord, new_order);
|
replace_order(&u->orders, ord, new_order);
|
||||||
free_order(new_order); /* parse_order & set_order have each increased the refcount */
|
free_order(new_order); /* parse_order & set_order have each increased the refcount */
|
||||||
}
|
}
|
||||||
if (academy && sk != NOSKILL) {
|
if (academy) {
|
||||||
academy = academy / 30; /* anzahl gelehrter wochen, max. 10 */
|
academy_teaching_bonus(u, sk, academy);
|
||||||
learn_skill(u, sk, academy / 30.0 / TEACHNUMBER);
|
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -803,3 +799,59 @@ int study_cmd(unit * u, order * ord)
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static double produceexp_chance(void) {
|
||||||
|
return config_get_flt("study.from_use", 1.0 / 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
void produceexp_ex(struct unit *u, skill_t sk, int n, bool(*learn)(unit *, skill_t, double))
|
||||||
|
{
|
||||||
|
if (n != 0 && (is_monsters(u->faction) || playerrace(u_race(u)))) {
|
||||||
|
double chance = produceexp_chance();
|
||||||
|
if (chance > 0.0F) {
|
||||||
|
learn(u, sk, (n * chance) / u->number);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void produceexp(struct unit *u, skill_t sk, int n)
|
||||||
|
{
|
||||||
|
produceexp_ex(u, sk, n, learn_skill);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifndef NO_TESTS
|
||||||
|
static learn_fun inject_learn_fun = 0;
|
||||||
|
|
||||||
|
void inject_learn(learn_fun fun) {
|
||||||
|
inject_learn_fun = fun;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
bool learn_skill(unit * u, skill_t sk, double learn_chance)
|
||||||
|
{
|
||||||
|
skill *sv = u->skills;
|
||||||
|
#ifndef NO_TESTS
|
||||||
|
if (inject_learn_fun) {
|
||||||
|
return inject_learn_fun(u, sk, learn_chance);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
if (learn_chance < 1.0 && rng_int() % 10000 >= learn_chance * 10000)
|
||||||
|
if (!chance(learn_chance))
|
||||||
|
return false;
|
||||||
|
while (sv != u->skills + u->skill_size) {
|
||||||
|
assert(sv->weeks > 0);
|
||||||
|
if (sv->id == sk) {
|
||||||
|
if (sv->weeks <= 1) {
|
||||||
|
sk_set(sv, sv->level + 1);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
sv->weeks--;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
++sv;
|
||||||
|
}
|
||||||
|
sv = add_skill(u, sk);
|
||||||
|
sk_set(sv, 1);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
22
src/study.h
22
src/study.h
|
@ -26,14 +26,25 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
extern int teach_cmd(struct unit *u, struct order *ord);
|
struct unit;
|
||||||
extern int study_cmd(struct unit *u, struct order *ord);
|
|
||||||
|
|
||||||
extern magic_t getmagicskill(const struct locale *lang);
|
int teach_cmd(struct unit *u, struct order *ord);
|
||||||
extern bool is_migrant(struct unit *u);
|
int study_cmd(struct unit *u, struct order *ord);
|
||||||
extern int study_cost(struct unit *u, skill_t talent);
|
|
||||||
|
|
||||||
|
magic_t getmagicskill(const struct locale *lang);
|
||||||
|
bool is_migrant(struct unit *u);
|
||||||
|
int study_cost(struct unit *u, skill_t talent);
|
||||||
|
|
||||||
|
#ifndef NO_TESTS
|
||||||
|
typedef bool(*learn_fun)(struct unit *u, skill_t sk, double ch);
|
||||||
|
void inject_learn(learn_fun fun);
|
||||||
|
#endif
|
||||||
|
bool learn_skill(struct unit *u, skill_t sk, double chance);
|
||||||
|
|
||||||
|
void produceexp(struct unit *u, skill_t sk, int n);
|
||||||
|
void produceexp_ex(struct unit *u, skill_t sk, int n, bool(*learn)(struct unit *, skill_t, double));
|
||||||
#define MAXTEACHERS 20
|
#define MAXTEACHERS 20
|
||||||
|
#define TEACHNUMBER 10
|
||||||
typedef struct teaching_info {
|
typedef struct teaching_info {
|
||||||
struct unit *teachers[MAXTEACHERS];
|
struct unit *teachers[MAXTEACHERS];
|
||||||
int value;
|
int value;
|
||||||
|
@ -41,6 +52,7 @@ extern "C" {
|
||||||
|
|
||||||
extern const struct attrib_type at_learning;
|
extern const struct attrib_type at_learning;
|
||||||
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
149
src/study.test.c
149
src/study.test.c
|
@ -5,8 +5,11 @@
|
||||||
#include <kernel/config.h>
|
#include <kernel/config.h>
|
||||||
#include <kernel/unit.h>
|
#include <kernel/unit.h>
|
||||||
#include <kernel/faction.h>
|
#include <kernel/faction.h>
|
||||||
|
#include <kernel/item.h>
|
||||||
#include <kernel/order.h>
|
#include <kernel/order.h>
|
||||||
#include <kernel/region.h>
|
#include <kernel/region.h>
|
||||||
|
#include <kernel/building.h>
|
||||||
|
#include <util/rand.h>
|
||||||
#include <util/message.h>
|
#include <util/message.h>
|
||||||
#include <util/language.h>
|
#include <util/language.h>
|
||||||
#include <util/base36.h>
|
#include <util/base36.h>
|
||||||
|
@ -21,6 +24,17 @@ typedef struct {
|
||||||
unit *teachers[2];
|
unit *teachers[2];
|
||||||
} study_fixture;
|
} study_fixture;
|
||||||
|
|
||||||
|
static void setup_locale(struct locale *lang) {
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < MAXSKILLS; ++i) {
|
||||||
|
if (!locale_getstring(lang, mkname("skill", skillnames[i])))
|
||||||
|
locale_setstring(lang, mkname("skill", skillnames[i]), skillnames[i]);
|
||||||
|
}
|
||||||
|
locale_setstring(lang, parameters[P_ANY], "ALLE");
|
||||||
|
init_parameters(lang);
|
||||||
|
init_skills(lang);
|
||||||
|
}
|
||||||
|
|
||||||
static void setup_study(study_fixture *fix, skill_t sk) {
|
static void setup_study(study_fixture *fix, skill_t sk) {
|
||||||
struct region * r;
|
struct region * r;
|
||||||
struct faction *f;
|
struct faction *f;
|
||||||
|
@ -33,8 +47,7 @@ static void setup_study(study_fixture *fix, skill_t sk) {
|
||||||
r = findregion(0, 0);
|
r = findregion(0, 0);
|
||||||
f = test_create_faction(0);
|
f = test_create_faction(0);
|
||||||
lang = get_or_create_locale(locale_name(f->locale));
|
lang = get_or_create_locale(locale_name(f->locale));
|
||||||
locale_setstring(lang, mkname("skill", skillnames[sk]), skillnames[sk]);
|
setup_locale(lang);
|
||||||
init_skills(lang);
|
|
||||||
fix->u = test_create_unit(f, r);
|
fix->u = test_create_unit(f, r);
|
||||||
assert(fix->u);
|
assert(fix->u);
|
||||||
fix->u->thisorder = create_order(K_STUDY, f->locale, "%s", skillnames[sk]);
|
fix->u->thisorder = create_order(K_STUDY, f->locale, "%s", skillnames[sk]);
|
||||||
|
@ -80,12 +93,10 @@ static void test_study_with_teacher(CuTest *tc) {
|
||||||
static void test_study_with_bad_teacher(CuTest *tc) {
|
static void test_study_with_bad_teacher(CuTest *tc) {
|
||||||
study_fixture fix;
|
study_fixture fix;
|
||||||
skill *sv;
|
skill *sv;
|
||||||
message *msg;
|
|
||||||
|
|
||||||
setup_study(&fix, SK_CROSSBOW);
|
setup_study(&fix, SK_CROSSBOW);
|
||||||
teach_cmd(fix.teachers[0], fix.teachers[0]->thisorder);
|
teach_cmd(fix.teachers[0], fix.teachers[0]->thisorder);
|
||||||
CuAssertPtrNotNull(tc, msg = test_get_last_message(fix.u->faction->msgs));
|
CuAssertPtrNotNull(tc, test_find_messagetype(fix.u->faction->msgs, "teach_asgood"));
|
||||||
CuAssertStrEquals(tc, "teach_asgood", test_get_messagetype(msg));
|
|
||||||
study_cmd(fix.u, fix.u->thisorder);
|
study_cmd(fix.u, fix.u->thisorder);
|
||||||
CuAssertPtrNotNull(tc, sv = unit_skill(fix.u, SK_CROSSBOW));
|
CuAssertPtrNotNull(tc, sv = unit_skill(fix.u, SK_CROSSBOW));
|
||||||
CuAssertIntEquals(tc, 1, sv->level);
|
CuAssertIntEquals(tc, 1, sv->level);
|
||||||
|
@ -93,11 +104,139 @@ static void test_study_with_bad_teacher(CuTest *tc) {
|
||||||
test_cleanup();
|
test_cleanup();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void test_study_bug_2194(CuTest *tc) {
|
||||||
|
unit *u, *u1, *u2;
|
||||||
|
struct locale * loc;
|
||||||
|
building * b;
|
||||||
|
|
||||||
|
test_cleanup();
|
||||||
|
random_source_inject_constant(0.0);
|
||||||
|
init_resources();
|
||||||
|
loc = get_or_create_locale("de");
|
||||||
|
setup_locale(loc);
|
||||||
|
u = test_create_unit(test_create_faction(0), test_create_region(0, 0, 0));
|
||||||
|
scale_number(u, 2);
|
||||||
|
set_level(u, SK_CROSSBOW, TEACHDIFFERENCE);
|
||||||
|
u->faction->locale = loc;
|
||||||
|
u1 = test_create_unit(u->faction, u->region);
|
||||||
|
scale_number(u1, 17);
|
||||||
|
u1->thisorder = create_order(K_STUDY, loc, skillnames[SK_CROSSBOW]);
|
||||||
|
u2 = test_create_unit(u->faction, u->region);
|
||||||
|
scale_number(u2, 3);
|
||||||
|
u2->thisorder = create_order(K_STUDY, loc, skillnames[SK_MAGIC]);
|
||||||
|
u->thisorder = create_order(K_TEACH, loc, "%s %s", itoa36(u1->no), itoa36(u2->no));
|
||||||
|
b = test_create_building(u->region, test_create_buildingtype("academy"));
|
||||||
|
b->size = 22;
|
||||||
|
u_set_building(u, b);
|
||||||
|
u_set_building(u1, b);
|
||||||
|
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_WORKING;
|
||||||
|
teach_cmd(u, u->thisorder);
|
||||||
|
CuAssertPtrNotNull(tc, test_find_messagetype(u->faction->msgs, "teach_asgood"));
|
||||||
|
test_cleanup();
|
||||||
|
}
|
||||||
|
|
||||||
|
static CuTest *g_tc;
|
||||||
|
|
||||||
|
static bool cb_learn_one(unit *u, skill_t sk, double chance) {
|
||||||
|
CuAssertIntEquals(g_tc, SK_ALCHEMY, sk);
|
||||||
|
CuAssertDblEquals(g_tc, 0.5 / u->number, chance, 0.01);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool cb_learn_two(unit *u, skill_t sk, double chance) {
|
||||||
|
CuAssertIntEquals(g_tc, SK_ALCHEMY, sk);
|
||||||
|
CuAssertDblEquals(g_tc, 2 * 0.5 / u->number, chance, 0.01);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_produceexp(CuTest *tc) {
|
||||||
|
unit *u;
|
||||||
|
|
||||||
|
g_tc = tc;
|
||||||
|
test_cleanup();
|
||||||
|
u = test_create_unit(test_create_faction(0), test_create_region(0, 0, 0));
|
||||||
|
config_set("study.from_use", "0.5");
|
||||||
|
produceexp_ex(u, SK_ALCHEMY, 1, cb_learn_one);
|
||||||
|
produceexp_ex(u, SK_ALCHEMY, 2, cb_learn_two);
|
||||||
|
test_cleanup();
|
||||||
|
}
|
||||||
|
|
||||||
|
#define MAXLOG 4
|
||||||
|
typedef struct log_entry {
|
||||||
|
unit *u;
|
||||||
|
skill_t sk;
|
||||||
|
double ch;
|
||||||
|
} log_entry;
|
||||||
|
|
||||||
|
static log_entry log_learners[MAXLOG];
|
||||||
|
static int log_size;
|
||||||
|
|
||||||
|
static bool log_learn(unit *u, skill_t sk, double ch) {
|
||||||
|
if (log_size < MAXLOG) {
|
||||||
|
log_entry * entry = &log_learners[log_size++];
|
||||||
|
entry->u = u;
|
||||||
|
entry->sk = sk;
|
||||||
|
entry->ch = ch;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_academy_building(CuTest *tc) {
|
||||||
|
unit *u, *u1, *u2;
|
||||||
|
struct locale * loc;
|
||||||
|
building * b;
|
||||||
|
message * msg;
|
||||||
|
|
||||||
|
test_cleanup();
|
||||||
|
mt_register(mt_new_va("teach_asgood", "unit:unit", "region:region", "command:order", "student:unit", 0));
|
||||||
|
|
||||||
|
random_source_inject_constant(0.0);
|
||||||
|
init_resources();
|
||||||
|
loc = get_or_create_locale("de");
|
||||||
|
setup_locale(loc);
|
||||||
|
u = test_create_unit(test_create_faction(0), test_create_region(0, 0, 0));
|
||||||
|
scale_number(u, 2);
|
||||||
|
set_level(u, SK_CROSSBOW, TEACHDIFFERENCE);
|
||||||
|
u->faction->locale = loc;
|
||||||
|
u1 = test_create_unit(u->faction, u->region);
|
||||||
|
scale_number(u1, 15);
|
||||||
|
u1->thisorder = create_order(K_STUDY, loc, skillnames[SK_CROSSBOW]);
|
||||||
|
u2 = test_create_unit(u->faction, u->region);
|
||||||
|
scale_number(u2, 5);
|
||||||
|
u2->thisorder = create_order(K_STUDY, loc, skillnames[SK_CROSSBOW]);
|
||||||
|
set_level(u2, SK_CROSSBOW, 1);
|
||||||
|
u->thisorder = create_order(K_TEACH, loc, "%s %s", itoa36(u1->no), itoa36(u2->no));
|
||||||
|
b = test_create_building(u->region, test_create_buildingtype("academy"));
|
||||||
|
b->size = 22;
|
||||||
|
u_set_building(u, b);
|
||||||
|
u_set_building(u1, b);
|
||||||
|
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_WORKING;
|
||||||
|
inject_learn(log_learn);
|
||||||
|
teach_cmd(u, u->thisorder);
|
||||||
|
inject_learn(0);
|
||||||
|
CuAssertPtrNotNull(tc, msg = test_find_messagetype(u->faction->msgs, "teach_asgood"));
|
||||||
|
CuAssertPtrEquals(tc, u, (unit *)(msg)->parameters[0].v);
|
||||||
|
CuAssertPtrEquals(tc, u2, (unit *)(msg)->parameters[3].v);
|
||||||
|
CuAssertPtrEquals(tc, u, log_learners[0].u);
|
||||||
|
CuAssertIntEquals(tc, SK_CROSSBOW, log_learners[0].sk);
|
||||||
|
CuAssertDblEquals(tc, 0.05, log_learners[0].ch, 0.001);
|
||||||
|
test_cleanup();
|
||||||
|
}
|
||||||
|
|
||||||
CuSuite *get_study_suite(void)
|
CuSuite *get_study_suite(void)
|
||||||
{
|
{
|
||||||
CuSuite *suite = CuSuiteNew();
|
CuSuite *suite = CuSuiteNew();
|
||||||
SUITE_ADD_TEST(suite, test_study_no_teacher);
|
SUITE_ADD_TEST(suite, test_study_no_teacher);
|
||||||
SUITE_ADD_TEST(suite, test_study_with_teacher);
|
SUITE_ADD_TEST(suite, test_study_with_teacher);
|
||||||
SUITE_ADD_TEST(suite, test_study_with_bad_teacher);
|
SUITE_ADD_TEST(suite, test_study_with_bad_teacher);
|
||||||
|
SUITE_ADD_TEST(suite, test_produceexp);
|
||||||
|
SUITE_ADD_TEST(suite, test_academy_building);
|
||||||
|
DISABLE_TEST(suite, test_study_bug_2194);
|
||||||
return suite;
|
return suite;
|
||||||
}
|
}
|
||||||
|
|
|
@ -154,11 +154,13 @@ ship_type * test_create_shiptype(const char * name)
|
||||||
stype->construction->skill = SK_SHIPBUILDING;
|
stype->construction->skill = SK_SHIPBUILDING;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (stype->coasts) {
|
||||||
|
free(stype->coasts);
|
||||||
|
}
|
||||||
stype->coasts =
|
stype->coasts =
|
||||||
(terrain_type **)malloc(sizeof(terrain_type *) * 2);
|
(terrain_type **)malloc(sizeof(terrain_type *) * 2);
|
||||||
stype->coasts[0] = test_create_terrain("plain", LAND_REGION | FOREST_REGION | WALK_INTO | CAVALRY_REGION | SAIL_INTO | FLY_INTO);
|
stype->coasts[0] = test_create_terrain("plain", LAND_REGION | FOREST_REGION | WALK_INTO | CAVALRY_REGION | SAIL_INTO | FLY_INTO);
|
||||||
stype->coasts[1] = NULL;
|
stype->coasts[1] = NULL;
|
||||||
|
|
||||||
if (default_locale) {
|
if (default_locale) {
|
||||||
locale_setstring(default_locale, name, name);
|
locale_setstring(default_locale, name, name);
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,6 +24,8 @@ static void test_shock(CuTest *tc) {
|
||||||
CuAssertIntEquals(tc, 2, u->hp);
|
CuAssertIntEquals(tc, 2, u->hp);
|
||||||
CuAssertIntEquals(tc, 2, get_spellpoints(u));
|
CuAssertIntEquals(tc, 2, get_spellpoints(u));
|
||||||
CuAssertPtrNotNull(tc, test_find_messagetype(u->faction->msgs, "shock"));
|
CuAssertPtrNotNull(tc, test_find_messagetype(u->faction->msgs, "shock"));
|
||||||
|
t_free(tt);
|
||||||
|
free(tt);
|
||||||
test_cleanup();
|
test_cleanup();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -41,6 +43,8 @@ static void test_shock_low(CuTest *tc) {
|
||||||
tt->type->handle(tt, u);
|
tt->type->handle(tt, u);
|
||||||
CuAssertIntEquals(tc, 1, u->hp);
|
CuAssertIntEquals(tc, 1, u->hp);
|
||||||
CuAssertIntEquals(tc, 1, get_spellpoints(u));
|
CuAssertIntEquals(tc, 1, get_spellpoints(u));
|
||||||
|
t_free(tt);
|
||||||
|
free(tt);
|
||||||
test_cleanup();
|
test_cleanup();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -49,6 +49,7 @@ static void test_attrib_remove_self(CuTest * tc) {
|
||||||
CuAssertPtrEquals(tc, 0, alist->nexttype);
|
CuAssertPtrEquals(tc, 0, alist->nexttype);
|
||||||
CuAssertIntEquals(tc, 1, a_remove(&alist, alist));
|
CuAssertIntEquals(tc, 1, a_remove(&alist, alist));
|
||||||
CuAssertPtrEquals(tc, a, alist);
|
CuAssertPtrEquals(tc, a, alist);
|
||||||
|
a_removeall(&alist, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -63,6 +63,7 @@ int read_triggers(struct gamedata *data, trigger ** tp)
|
||||||
break;
|
break;
|
||||||
case AT_READ_FAIL:
|
case AT_READ_FAIL:
|
||||||
t_free(*tp);
|
t_free(*tp);
|
||||||
|
free(*tp);
|
||||||
*tp = NULL;
|
*tp = NULL;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
@ -107,6 +108,7 @@ int handle_triggers(trigger ** triggers, void *param)
|
||||||
if (t->type->handle(t, param) != 0) {
|
if (t->type->handle(t, param) != 0) {
|
||||||
*tp = t->next;
|
*tp = t->next;
|
||||||
t_free(t);
|
t_free(t);
|
||||||
|
free(t);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
tp = &t->next;
|
tp = &t->next;
|
||||||
|
@ -260,6 +262,7 @@ const trigger_type * tt)
|
||||||
if (t->type == tt) {
|
if (t->type == tt) {
|
||||||
*tp = t->next;
|
*tp = t->next;
|
||||||
t_free(t);
|
t_free(t);
|
||||||
|
free(t);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
tp = &t->next;
|
tp = &t->next;
|
||||||
|
|
|
@ -23,11 +23,6 @@ void gamedata_init(gamedata *data, storage *store, int version) {
|
||||||
binstore_init(data->store, &data->strm);
|
binstore_init(data->store, &data->strm);
|
||||||
}
|
}
|
||||||
|
|
||||||
void gamedata_close(gamedata *data) {
|
|
||||||
gamedata_done(data);
|
|
||||||
fstream_done(&data->strm);
|
|
||||||
}
|
|
||||||
|
|
||||||
int gamedata_openfile(gamedata *data, const char *filename, const char *mode, int version) {
|
int gamedata_openfile(gamedata *data, const char *filename, const char *mode, int version) {
|
||||||
FILE *F = fopen(filename, mode);
|
FILE *F = fopen(filename, mode);
|
||||||
if (F) {
|
if (F) {
|
||||||
|
@ -70,3 +65,9 @@ gamedata *gamedata_open(const char *filename, const char *mode, int version) {
|
||||||
}
|
}
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void gamedata_close(gamedata *data) {
|
||||||
|
gamedata_done(data);
|
||||||
|
fstream_done(&data->strm);
|
||||||
|
free(data->store);
|
||||||
|
}
|
||||||
|
|
|
@ -11,9 +11,11 @@ static void test_gamedata(CuTest * tc)
|
||||||
data = gamedata_open("test.dat", "wb", 0);
|
data = gamedata_open("test.dat", "wb", 0);
|
||||||
CuAssertPtrNotNull(tc, data);
|
CuAssertPtrNotNull(tc, data);
|
||||||
gamedata_close(data);
|
gamedata_close(data);
|
||||||
|
free(data);
|
||||||
data = gamedata_open("test.dat", "rb", 0);
|
data = gamedata_open("test.dat", "rb", 0);
|
||||||
CuAssertPtrNotNull(tc, data);
|
CuAssertPtrNotNull(tc, data);
|
||||||
gamedata_close(data);
|
gamedata_close(data);
|
||||||
|
free(data);
|
||||||
CuAssertIntEquals(tc, 0, remove("test.dat"));
|
CuAssertIntEquals(tc, 0, remove("test.dat"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -171,7 +171,6 @@ void addtoken(void ** root, const char *str, variant id)
|
||||||
|
|
||||||
ref = (tref *)malloc(sizeof(tref));
|
ref = (tref *)malloc(sizeof(tref));
|
||||||
ref->ucs = ucs;
|
ref->ucs = ucs;
|
||||||
ref->node = 0;
|
|
||||||
ref->node = node;
|
ref->node = node;
|
||||||
ref->nexthash = tk->next[index];
|
ref->nexthash = tk->next[index];
|
||||||
tk->next[index] = ref;
|
tk->next[index] = ref;
|
||||||
|
|
Loading…
Reference in New Issue