Merge pull request #731 from ennorehling/develop

BUG 2367, 2368: familiars
This commit is contained in:
Enno Rehling 2017-10-07 18:52:45 +02:00 committed by GitHub
commit 0ca0543c6e
35 changed files with 672 additions and 364 deletions

2
clibs

@ -1 +1 @@
Subproject commit da2c0cc39b27c98ed8d31b0503426788fc236bd8
Subproject commit 147584ad70b220abf6a4e97ca76e785729b9ac32

View File

@ -273,7 +273,7 @@ static int tolua_unit_set_guard(lua_State * L)
static const char *unit_getmagic(const unit * u)
{
sc_mage *mage = get_mage(u);
sc_mage *mage = get_mage_depr(u);
return mage ? magic_school[mage->magietyp] : NULL;
}
@ -286,7 +286,7 @@ static int tolua_unit_get_magic(lua_State * L)
static void unit_setmagic(unit * u, const char *type)
{
sc_mage *mage = get_mage(u);
sc_mage *mage = get_mage_depr(u);
int mtype;
for (mtype = 0; mtype != MAXMAGIETYP; ++mtype) {
if (strcmp(magic_school[mtype], type) == 0)
@ -638,8 +638,14 @@ static int tolua_unit_get_familiar(lua_State * L)
static int tolua_unit_set_familiar(lua_State * L)
{
unit *self = (unit *)tolua_tousertype(L, 1, 0);
create_newfamiliar(self, (unit *)tolua_tousertype(L, 2, 0));
unit *mag = (unit *)tolua_tousertype(L, 1, NULL);
unit *fam = (unit *)tolua_tousertype(L, 2, NULL);
if (fam) {
set_familiar(mag, fam);
}
else {
remove_familiar(mag);
}
return 0;
}
@ -747,7 +753,7 @@ static int tolua_unit_get_items(lua_State * L)
static int tolua_unit_get_spells(lua_State * L)
{
unit *self = (unit *) tolua_tousertype(L, 1, 0);
sc_mage *mage = self ? get_mage(self) : 0;
sc_mage *mage = self ? get_mage_depr(self) : 0;
spellbook *sb = mage ? mage->spellbook : 0;
selist *slist = 0;
if (sb) {

View File

@ -954,7 +954,7 @@ void cr_output_unit(stream *out, const region * r, const faction * f,
}
/* spells that this unit can cast */
mage = get_mage(u);
mage = get_mage_depr(u);
if (mage) {
int i, maxlevel = effskill(u, SK_MAGIC, 0);
cr_output_spells(out, u, maxlevel);

View File

@ -591,7 +591,7 @@ void give_unit(unit * u, unit * u2, order * ord)
cmistake(u, ord, 155, MSG_COMMERCE);
return;
}
mage = get_mage(u);
mage = get_mage_depr(u);
if (!mage || u2->faction->magiegebiet != mage->magietyp) {
cmistake(u, ord, 157, MSG_COMMERCE);
return;

View File

@ -121,7 +121,7 @@ void equip_unit_mask(struct unit *u, const struct equipment *eq, int mask)
if (eq->spells) {
selist * ql = eq->spells;
int qi;
sc_mage * mage = get_mage(u);
sc_mage * mage = get_mage_depr(u);
for (qi = 0; ql; selist_advance(&ql, &qi, 1)) {
lazy_spell *sbe = (lazy_spell *)selist_get(ql, qi);

View File

@ -39,7 +39,7 @@ static void test_equipment(CuTest * tc)
CuAssertIntEquals(tc, 1, i_get(u->items, it_horses));
CuAssertIntEquals(tc, 5, get_level(u, SK_MAGIC));
mage = get_mage(u);
mage = get_mage_depr(u);
CuAssertPtrNotNull(tc, mage);
CuAssertPtrNotNull(tc, mage->spellbook);
CuAssertTrue(tc, u_hasspell(u, sp));

View File

@ -83,7 +83,7 @@ struct message *msg_feedback(const struct unit *u, struct order *ord,
variant var;
memset(args, 0, sizeof(args));
if (ord && ord->_noerror) {
if (ord && is_silent(ord)) {
return NULL;
}

View File

@ -79,8 +79,8 @@ static void test_noerror(CuTest *tc) {
lang = test_create_locale();
u = test_create_unit(test_create_faction(NULL), test_create_region(0, 0, NULL));
u->thisorder = parse_order("!@move", lang);
CuAssertTrue(tc, u->thisorder->_persistent);
CuAssertTrue(tc, u->thisorder->_noerror);
CuAssertIntEquals(tc, K_MOVE | CMD_QUIET | CMD_PERSIST, u->thisorder->command);
CuAssertTrue(tc, !is_persistent(u->thisorder));
CuAssertPtrEquals(tc, NULL, msg_error(u, u->thisorder, 100));
CuAssertPtrEquals(tc, NULL, msg_feedback(u, u->thisorder, "error_unit_not_found", NULL));
test_cleanup();

View File

@ -30,12 +30,12 @@
#include <stdlib.h>
#include <string.h>
# define ORD_KEYWORD(ord) (ord)->data->_keyword
# define ORD_KEYWORD(ord) (keyword_t)((ord)->command & 0xFFFF)
# define ORD_LOCALE(ord) locale_array[(ord)->data->_lindex]->lang
# define ORD_STRING(ord) (ord)->data->_str
typedef struct locale_data {
struct order_data *short_orders[MAXKEYWORDS];
struct order_data *short_orders;
struct order_data *study_orders[MAXSKILLS];
const struct locale *lang;
} locale_data;
@ -46,7 +46,6 @@ typedef struct order_data {
const char *_str;
int _refcount;
int _lindex;
keyword_t _keyword;
} order_data;
static void release_data(order_data * data)
@ -94,7 +93,7 @@ char* get_command(const order *ord, char *sbuffer, size_t size) {
keyword_t kwd = ORD_KEYWORD(ord);
int bytes;
if (ord->_noerror) {
if (ord->command & CMD_QUIET) {
if (size > 0) {
*bufp++ = '!';
--size;
@ -103,7 +102,7 @@ char* get_command(const order *ord, char *sbuffer, size_t size) {
WARN_STATIC_BUFFER();
}
}
if (ord->_persistent) {
if (ord->command & CMD_PERSIST) {
if (size > 0) {
*bufp++ = '@';
--size;
@ -162,8 +161,7 @@ order *copy_order(const order * src)
if (src != NULL) {
order *ord = (order *)malloc(sizeof(order));
ord->next = NULL;
ord->_persistent = src->_persistent;
ord->_noerror = src->_noerror;
ord->command = src->command;
ord->data = src->data;
++ord->data->_refcount;
return ord;
@ -189,13 +187,12 @@ void free_orders(order ** olist)
}
}
static char *mkdata(order_data **pdata, size_t len, keyword_t kwd, int lindex, const char *str)
static char *mkdata(order_data **pdata, size_t len, int lindex, const char *str)
{
order_data *data;
char *result;
data = malloc(sizeof(order_data) + len + 1);
result = (char *)(data + 1);
data->_keyword = kwd;
data->_lindex = lindex;
data->_refcount = 0;
data->_str = 0;
@ -229,7 +226,7 @@ static order_data *create_data(keyword_t kwd, const char *sptr, int lindex)
const char *skname = skillname(sk, lang);
const char *spc = strchr(skname, ' ');
size_t len = strlen(skname);
char *dst = mkdata(&data, len + (spc ? 3 : 0), kwd, lindex, spc ? 0 : skname);
char *dst = mkdata(&data, len + (spc ? 3 : 0), lindex, spc ? 0 : skname);
locale_array[lindex]->study_orders[sk] = data;
if (spc) {
dst[0] = '\"';
@ -246,26 +243,24 @@ static order_data *create_data(keyword_t kwd, const char *sptr, int lindex)
/* orders with no parameter, only one order_data per order required */
else if (kwd != NOKEYWORD && *sptr == 0) {
data = locale_array[lindex]->short_orders[kwd];
data = locale_array[lindex]->short_orders;
if (data == NULL) {
mkdata(&data, 0, kwd, lindex, 0);
mkdata(&data, 0, lindex, 0);
data->_refcount = 1;
locale_array[lindex]->short_orders[kwd] = data;
locale_array[lindex]->short_orders = data;
}
++data->_refcount;
return data;
}
mkdata(&data, s ? strlen(s) : 0, kwd, lindex, s);
mkdata(&data, s ? strlen(s) : 0, lindex, s);
data->_refcount = 1;
return data;
}
static void clear_localedata(int lindex) {
int i;
for (i = 0; i != MAXKEYWORDS; ++i) {
release_data(locale_array[lindex]->short_orders[i]);
locale_array[lindex]->short_orders[i] = 0;
}
release_data(locale_array[lindex]->short_orders);
locale_array[lindex]->short_orders = NULL;
for (i = 0; i != MAXSKILLS; ++i) {
release_data(locale_array[lindex]->study_orders[i]);
locale_array[lindex]->study_orders[i] = 0;
@ -284,12 +279,12 @@ void close_orders(void) {
}
}
static order *create_order_i(keyword_t kwd, const char *sptr, bool persistent,
static order *create_order_i(order *ord, keyword_t kwd, const char *sptr, bool persistent,
bool noerror, const struct locale *lang)
{
order *ord = NULL;
int lindex;
assert(ord);
if (kwd == NOKEYWORD || keyword_disabled(kwd)) {
log_error("trying to create an order for disabled keyword %s.", keyword(kwd));
return NULL;
@ -316,11 +311,12 @@ static order *create_order_i(keyword_t kwd, const char *sptr, bool persistent,
}
locale_array[lindex]->lang = lang;
ord = (order *)malloc(sizeof(order));
ord->_persistent = persistent;
ord->_noerror = noerror;
ord->command = (int)kwd;
if (persistent) ord->command |= CMD_PERSIST;
if (noerror) ord->command |= CMD_QUIET;
ord->next = NULL;
while (isspace(*(unsigned char *)sptr)) ++sptr;
ord->data = create_data(kwd, sptr, lindex);
return ord;
@ -329,6 +325,7 @@ static order *create_order_i(keyword_t kwd, const char *sptr, bool persistent,
order *create_order(keyword_t kwd, const struct locale * lang,
const char *params, ...)
{
order *ord;
char zBuffer[DISPLAYSIZE];
if (params) {
char *bufp = zBuffer;
@ -379,42 +376,40 @@ order *create_order(keyword_t kwd, const struct locale * lang,
else {
zBuffer[0] = 0;
}
return create_order_i(kwd, zBuffer, false, false, lang);
ord = (order *)malloc(sizeof(order));
return create_order_i(ord, kwd, zBuffer, false, false, lang);
}
order *parse_order(const char *s, const struct locale * lang)
{
assert(lang);
assert(s);
while (*s && !isalnum(*(unsigned char *)s) && !ispunct(*(unsigned char *)s)) {
++s;
}
if (*s != 0) {
keyword_t kwd;
const char *sptr;
keyword_t kwd = NOKEYWORD;
const char *sptr = s;
bool persistent = false, noerror = false;
const char * p;
while (*s == '!' || *s=='@') {
if (*s=='!') noerror = true;
else if (*s == '@') persistent = true;
++s;
}
sptr = s;
p = *sptr ? parse_token_depr(&sptr) : 0;
kwd = p ? get_keyword(p, lang) : NOKEYWORD;
if (p) {
while (*p == '!' || *p == '@') {
if (*p == '!') noerror = true;
else if (*p == '@') persistent = true;
++p;
}
kwd = get_keyword(p, lang);
}
if (kwd == K_MAKE) {
const char *s, *sp = sptr;
s = parse_token_depr(&sp);
if (s && isparam(s, lang, P_TEMP)) {
const char *sp = sptr;
p = parse_token_depr(&sp);
if (p && isparam(p, lang, P_TEMP)) {
kwd = K_MAKETEMP;
sptr = sp;
}
}
if (kwd != NOKEYWORD) {
while (isspace(*(unsigned char *)sptr)) ++sptr;
s = sptr;
return create_order_i(kwd, s, persistent, noerror, lang);
order *ord = (order *)malloc(sizeof(order));
return create_order_i(ord, kwd, sptr, persistent, noerror, lang);
}
}
return NULL;
@ -561,10 +556,15 @@ bool is_persistent(const order * ord)
case K_KOMMENTAR:
return true;
default:
return ord->_persistent || is_repeated(kwd);
return (ord->command & CMD_PERSIST) || is_repeated(kwd);
}
}
bool is_silent(const order * ord)
{
return (ord->command & CMD_QUIET) != 0;
}
char *write_order(const order * ord, char *buffer, size_t size)
{
if (ord == 0) {
@ -595,5 +595,5 @@ keyword_t init_order(const struct order *ord)
{
assert(ord && ord->data);
init_tokens_str(ord->data->_str);
return ord->data->_keyword;
return ORD_KEYWORD(ord);
}

View File

@ -32,32 +32,36 @@ extern "C" {
struct order_data;
#define CMD_QUIET 0x010000
#define CMD_PERSIST 0x020000
#define CMD_DEFAULT 0x040000
typedef struct order {
struct order *next;
/* do not access this data: */
struct order_data *data;
bool _persistent;
bool _noerror;
int command;
} order;
/* constructor */
extern order *create_order(keyword_t kwd, const struct locale *lang,
order *create_order(keyword_t kwd, const struct locale *lang,
const char *params, ...);
extern order *parse_order(const char *s, const struct locale *lang);
extern void replace_order(order ** dst, order * orig, const order * src);
order *parse_order(const char *s, const struct locale *lang);
void replace_order(order ** dst, order * orig, const order * src);
/* reference counted copies of orders: */
extern order *copy_order(const order * ord);
extern void free_order(order * ord);
extern void free_orders(order ** olist);
order *copy_order(const order * ord);
void free_order(order * ord);
void free_orders(order ** olist);
extern void push_order(struct order **olist, struct order *ord);
void push_order(struct order **olist, struct order *ord);
/* access functions for orders */
keyword_t getkeyword(const order * ord);
void set_order(order ** destp, order * src);
char* get_command(const order *ord, char *buffer, size_t size);
bool is_persistent(const order * ord);
bool is_silent(const order * ord);
bool is_exclusive(const order * ord);
bool is_repeated(keyword_t kwd);
bool is_long(keyword_t kwd);

View File

@ -38,8 +38,7 @@ static void test_parse_order(CuTest *tc) {
ord = parse_order("MOVE NORTH", lang);
CuAssertPtrNotNull(tc, ord);
CuAssertTrue(tc, !ord->_noerror);
CuAssertTrue(tc, !ord->_persistent);
CuAssertIntEquals(tc, K_MOVE, ord->command);
CuAssertIntEquals(tc, K_MOVE, getkeyword(ord));
CuAssertStrEquals(tc, "move NORTH", get_command(ord, cmd, sizeof(cmd)));
@ -49,26 +48,37 @@ static void test_parse_order(CuTest *tc) {
ord = parse_order("!MOVE NORTH", lang);
CuAssertPtrNotNull(tc, ord);
CuAssertTrue(tc, ord->_noerror);
CuAssertTrue(tc, !ord->_persistent);
CuAssertPtrNotNull(tc, ord->data);
CuAssertIntEquals(tc, K_MOVE, getkeyword(ord));
CuAssertIntEquals(tc, K_MOVE | CMD_QUIET, ord->command);
free_order(ord);
ord = parse_order("@MOVE NORTH", lang);
CuAssertPtrNotNull(tc, ord);
CuAssertTrue(tc, !ord->_noerror);
CuAssertTrue(tc, ord->_persistent);
free_order(ord);
ord = parse_order("@!MOVE NORTH", lang);
CuAssertPtrNotNull(tc, ord);
CuAssertTrue(tc, ord->_noerror);
CuAssertTrue(tc, ord->_persistent);
CuAssertPtrNotNull(tc, ord->data);
CuAssertIntEquals(tc, K_MOVE, getkeyword(ord));
CuAssertIntEquals(tc, K_MOVE | CMD_PERSIST, ord->command);
free_order(ord);
ord = parse_order("!@MOVE NORTH", lang);
CuAssertPtrNotNull(tc, ord);
CuAssertTrue(tc, ord->_noerror);
CuAssertTrue(tc, ord->_persistent);
CuAssertPtrNotNull(tc, ord->data);
CuAssertIntEquals(tc, K_MOVE, getkeyword(ord));
CuAssertIntEquals(tc, K_MOVE | CMD_PERSIST | CMD_QUIET, ord->command);
free_order(ord);
ord = parse_order("@!MOVE NORTH", lang);
CuAssertPtrNotNull(tc, ord);
CuAssertPtrNotNull(tc, ord->data);
CuAssertIntEquals(tc, K_MOVE, getkeyword(ord));
CuAssertIntEquals(tc, K_MOVE | CMD_PERSIST | CMD_QUIET, ord->command);
free_order(ord);
ord = parse_order(" !@MOVE NORTH", lang);
CuAssertPtrNotNull(tc, ord);
CuAssertPtrNotNull(tc, ord->data);
CuAssertIntEquals(tc, K_MOVE, getkeyword(ord));
CuAssertIntEquals(tc, K_MOVE | CMD_PERSIST | CMD_QUIET, ord->command);
free_order(ord);
test_cleanup();
@ -204,16 +214,84 @@ static void test_get_command(CuTest *tc) {
lang = test_create_locale();
ord = create_order(K_MAKE, lang, "iron");
CuAssertStrEquals(tc, "make iron", get_command(ord, buf, sizeof(buf)));
ord->_noerror = true;
ord->command |= CMD_QUIET;
CuAssertStrEquals(tc, "!make iron", get_command(ord, buf, sizeof(buf)));
ord->_persistent = true;
ord->command |= CMD_PERSIST;
CuAssertStrEquals(tc, "!@make iron", get_command(ord, buf, sizeof(buf)));
ord->_noerror = false;
ord->command = K_MAKE | CMD_PERSIST;
CuAssertStrEquals(tc, "@make iron", get_command(ord, buf, sizeof(buf)));
free_order(ord);
test_cleanup();
}
static void test_is_persistent(CuTest *tc) {
order *ord;
struct locale *lang;
test_setup();
lang = test_create_locale();
ord = parse_order("@invalid", lang);
CuAssertPtrEquals(tc, NULL, ord);
ord = parse_order("give", lang);
CuAssertIntEquals(tc, K_GIVE, ord->command);
CuAssertTrue(tc, !is_persistent(ord));
free_order(ord);
ord = parse_order("@give", lang);
CuAssertTrue(tc, !is_repeated(K_GIVE));
CuAssertIntEquals(tc, K_GIVE | CMD_PERSIST, ord->command);
CuAssertTrue(tc, is_persistent(ord));
free_order(ord);
ord = parse_order("make", lang);
CuAssertTrue(tc, is_repeated(K_MAKE));
CuAssertIntEquals(tc, K_MAKE , ord->command);
CuAssertTrue(tc, is_persistent(ord));
free_order(ord);
ord = parse_order("@move", lang);
CuAssertIntEquals(tc, K_MOVE | CMD_PERSIST, ord->command);
CuAssertTrue(tc, !is_persistent(ord));
free_order(ord);
ord = parse_order("// comment", lang);
CuAssertTrue(tc, is_persistent(ord));
CuAssertIntEquals(tc, K_KOMMENTAR, ord->command);
free_order(ord);
test_cleanup();
}
static void test_is_silent(CuTest *tc) {
order *ord;
struct locale *lang;
test_setup();
lang = test_create_locale();
ord = parse_order("make", lang);
CuAssertIntEquals(tc, K_MAKE, ord->command);
CuAssertTrue(tc, !is_silent(ord));
free_order(ord);
ord = parse_order("!make", lang);
CuAssertIntEquals(tc, K_MAKE | CMD_QUIET, ord->command);
CuAssertTrue(tc, is_silent(ord));
free_order(ord);
ord = parse_order("@invalid", lang);
CuAssertPtrEquals(tc, NULL, ord);
ord = parse_order("// comment", lang);
CuAssertTrue(tc, is_persistent(ord));
CuAssertIntEquals(tc, K_KOMMENTAR, ord->command);
free_order(ord);
test_cleanup();
}
CuSuite *get_order_suite(void)
{
CuSuite *suite = CuSuiteNew();
@ -227,5 +305,7 @@ CuSuite *get_order_suite(void)
SUITE_ADD_TEST(suite, test_skip_token);
SUITE_ADD_TEST(suite, test_getstrtoken);
SUITE_ADD_TEST(suite, test_get_command);
SUITE_ADD_TEST(suite, test_is_persistent);
SUITE_ADD_TEST(suite, test_is_silent);
return suite;
}

View File

@ -24,8 +24,9 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#include "alchemy.h"
#include "alliance.h"
#include "ally.h"
#include "connection.h"
#include "building.h"
#include "connection.h"
#include "equipment.h"
#include "faction.h"
#include "group.h"
#include "item.h"
@ -1599,11 +1600,31 @@ static void fix_familiars(void) {
if (u->_race != u->faction->race && (u->_race->flags & RCF_FAMILIAR)) {
/* unit is potentially a familiar */
attrib * a = a_find(u->attribs, &at_mage);
if (a) {
/* unit is magical */
attrib * am = a_find(u->attribs, &at_familiarmage);
if (!am) {
/* but it is not a familiar? */
if (am) {
sc_mage *mage = a ? (sc_mage *)a->data.v : NULL;
/* a familiar */
if (!mage) {
log_error("%s seems to be a familiar with no magic.",
unitname(u));
mage = create_mage(u, M_GRAY);
}
if (!mage->spellbook) {
char eqname[32];
equipment *eq;
snprintf(eqname, sizeof(eqname), "fam_%s", u->_race->_name);
eq = get_equipment(eqname);
if (eq && eq->spells) {
log_error("%s seems to be a familiar with no spells.",
unitname(u));
/* magical familiar, no spells */
equip_unit_mask(u, eq, EQUIP_SPELLS);
}
}
}
else if (a) {
/* not a familiar, but magical */
attrib * ae = a_find(u->attribs, &at_eventhandler);
if (ae) {
trigger **tlist;
@ -1639,7 +1660,6 @@ static void fix_familiars(void) {
}
}
}
}
}
int read_game(gamedata *data)
@ -1790,7 +1810,7 @@ int read_game(gamedata *data)
else {
for (u = f->units; u; u = u->nextF) {
if (data->version < SPELL_LEVEL_VERSION) {
sc_mage *mage = get_mage(u);
sc_mage *mage = get_mage_depr(u);
if (mage) {
faction *f = u->faction;
int skl = effskill(u, SK_MAGIC, 0);

View File

@ -1492,14 +1492,6 @@ unit *create_unit(region * r, faction * f, int number, const struct race *urace,
if (f) {
assert(faction_alive(f));
u_setfaction(u, f);
if (f->locale) {
order *deford = default_order(f->locale);
if (deford) {
set_order(&u->thisorder, NULL);
addlist(&u->orders, deford);
}
}
}
set_number(u, number);
@ -1822,7 +1814,7 @@ void u_setrace(struct unit *u, const struct race *rc)
void unit_add_spell(unit * u, sc_mage * m, struct spell * sp, int level)
{
sc_mage *mage = m ? m : get_mage(u);
sc_mage *mage = m ? m : get_mage_depr(u);
if (!mage) {
log_debug("adding new spell %s to a previously non-mage unit %s\n", sp->sname, unitname(u));
@ -1836,7 +1828,7 @@ void unit_add_spell(unit * u, sc_mage * m, struct spell * sp, int level)
struct spellbook * unit_get_spellbook(const struct unit * u)
{
sc_mage * mage = get_mage(u);
sc_mage * mage = get_mage_depr(u);
if (mage) {
if (mage->spellbook) {
return mage->spellbook;

View File

@ -274,7 +274,7 @@ static void test_skill_familiar(CuTest *tc) {
CuAssertIntEquals(tc, 6, effskill(mag, SK_PERCEPTION, 0));
/* make them mage and familiar to each other */
CuAssertIntEquals(tc, true, create_newfamiliar(mag, fam));
create_newfamiliar(mag, fam);
/* when they are in the same region, the mage gets half their skill as a bonus */
CuAssertIntEquals(tc, 6, effskill(fam, SK_PERCEPTION, 0));
@ -287,33 +287,11 @@ static void test_skill_familiar(CuTest *tc) {
test_cleanup();
}
static void test_age_familiar(CuTest *tc) {
unit *mag, *fam;
test_cleanup();
mag = test_create_unit(test_create_faction(0), test_create_region(0, 0, 0));
fam = test_create_unit(mag->faction, test_create_region(0, 0, 0));
CuAssertPtrEquals(tc, 0, get_familiar(mag));
CuAssertPtrEquals(tc, 0, get_familiar_mage(fam));
CuAssertIntEquals(tc, true, create_newfamiliar(mag, fam));
CuAssertPtrEquals(tc, fam, get_familiar(mag));
CuAssertPtrEquals(tc, mag, get_familiar_mage(fam));
a_age(&fam->attribs, fam);
a_age(&mag->attribs, mag);
CuAssertPtrEquals(tc, fam, get_familiar(mag));
CuAssertPtrEquals(tc, mag, get_familiar_mage(fam));
set_number(fam, 0);
a_age(&mag->attribs, mag);
CuAssertPtrEquals(tc, 0, get_familiar(mag));
test_cleanup();
}
static void test_inside_building(CuTest *tc) {
unit *u;
building *b;
test_cleanup();
test_setup();
u = test_create_unit(test_create_faction(0), test_create_region(0, 0, 0));
b = test_create_building(u->region, 0);
@ -631,7 +609,6 @@ CuSuite *get_unit_suite(void)
SUITE_ADD_TEST(suite, test_skillmod);
SUITE_ADD_TEST(suite, test_skill_hunger);
SUITE_ADD_TEST(suite, test_skill_familiar);
SUITE_ADD_TEST(suite, test_age_familiar);
SUITE_ADD_TEST(suite, test_inside_building);
SUITE_ADD_TEST(suite, test_skills);
SUITE_ADD_TEST(suite, test_limited_skills);

View File

@ -3007,10 +3007,100 @@ int checkunitnumber(const faction * f, int add)
return 0;
}
void maketemp_cmd(unit *u, order **olist)
{
order *makeord;
int err = checkunitnumber(u->faction, 1);
makeord = *olist;
if (err) {
if (err == 1) {
ADDMSG(&u->faction->msgs,
msg_feedback(u, makeord,
"too_many_units_in_alliance",
"allowed", maxunits(u->faction)));
}
else {
ADDMSG(&u->faction->msgs,
msg_feedback(u, makeord,
"too_many_units_in_faction",
"allowed", maxunits(u->faction)));
}
*olist = makeord->next;
makeord->next = NULL;
free_order(makeord);
while (*olist) {
keyword_t kwd;
order * ord = *olist;
*olist = ord->next;
ord->next = NULL;
kwd = getkeyword(ord);
free_order(ord);
if (kwd == K_END) {
break;
}
}
}
else {
char token[128];
const char *s;
int alias;
ship *sh;
unit *u2;
order **ordp, **oinsert;
#ifndef NDEBUG
keyword_t kwd = init_order(makeord);
assert(kwd == K_MAKETEMP);
#endif
alias = getid();
s = gettoken(token, sizeof(token));
if (s && s[0] == '\0') {
/* empty name? => generate one */
s = NULL;
}
u2 = create_unit(u->region, u->faction, 0, u->faction->race, alias, s, u);
fset(u2, UFL_ISNEW);
a_add(&u2->attribs, a_new(&at_alias))->data.i = alias;
sh = leftship(u);
if (sh) {
set_leftship(u2, sh);
}
setstatus(u2, u->status);
/* copy orders until K_END from u to u2 */
ordp = &makeord->next;
oinsert = &u2->orders;
while (*ordp) {
order *ord = *ordp;
*ordp = ord->next;
if (getkeyword(ord) == K_END) {
ord->next = NULL;
free_order(ord);
break;
}
*oinsert = ord;
oinsert = &ord->next;
*oinsert = NULL;
}
*olist = *ordp;
makeord->next = NULL;
free_order(makeord);
if (!u2->orders) {
order *deford = default_order(u2->faction->locale);
if (deford) {
set_order(&u2->thisorder, NULL);
addlist(&u2->orders, deford);
}
}
}
}
void new_units(void)
{
region *r;
unit *u, *u2;
unit *u;
/* neue einheiten werden gemacht und ihre befehle (bis zum "ende" zu
* ihnen rueberkopiert, damit diese einheiten genauso wie die alten
@ -3028,73 +3118,13 @@ void new_units(void)
}
while (*ordp) {
order *makeord = *ordp;
if (getkeyword(makeord) == K_MAKETEMP) {
char token[128], *name = NULL;
const char *s;
int alias;
ship *sh;
order **newordersp;
int err = checkunitnumber(u->faction, 1);
if (err) {
if (err == 1) {
ADDMSG(&u->faction->msgs,
msg_feedback(u, makeord,
"too_many_units_in_alliance",
"allowed", maxunits(u->faction)));
order *ord = *ordp;
if (getkeyword(ord) == K_MAKETEMP) {
maketemp_cmd(u, ordp);
}
else {
ADDMSG(&u->faction->msgs,
msg_feedback(u, makeord,
"too_many_units_in_faction",
"allowed", maxunits(u->faction)));
ordp = &ord->next;
}
ordp = &makeord->next;
while (*ordp) {
order *ord = *ordp;
if (getkeyword(ord) == K_END)
break;
*ordp = ord->next;
ord->next = NULL;
free_order(ord);
}
continue;
}
init_order(makeord);
alias = getid();
s = gettoken(token, sizeof(token));
if (s && s[0]) {
name = strdup(s);
}
u2 = create_unit(r, u->faction, 0, u->faction->race, alias, name, u);
if (name != NULL)
free(name); /* TODO: use a buffer on the stack instead? */
fset(u2, UFL_ISNEW);
a_add(&u2->attribs, a_new(&at_alias))->data.i = alias;
sh = leftship(u);
if (sh) {
set_leftship(u2, sh);
}
setstatus(u2, u->status);
ordp = &makeord->next;
newordersp = &u2->orders;
while (*ordp) {
order *ord = *ordp;
if (getkeyword(ord) == K_END)
break;
*ordp = ord->next;
ord->next = NULL;
*newordersp = ord;
newordersp = &ord->next;
}
}
if (*ordp == makeord)
ordp = &makeord->next;
}
}
}
@ -3357,7 +3387,7 @@ static int faction_getmages(faction * f, unit ** results, int numresults)
for (u = f->units; u; u = u->nextF) {
if (u->number > 0) {
sc_mage *mage = get_mage(u);
sc_mage *mage = get_mage_depr(u);
if (mage) {
int level = effskill(u, SK_MAGIC, 0);
if (level > maxlevel) {
@ -3416,7 +3446,7 @@ static void update_spells(void)
show_new_spells(f, maxlevel, faction_get_spellbook(f));
for (i = 0; i != MAXMAGES && mages[i]; ++i) {
unit * u = mages[i];
sc_mage *mage = get_mage(u);
sc_mage *mage = get_mage_depr(u);
if (mage && mage->spellbook) {
int level = effskill(u, SK_MAGIC, 0);
show_new_spells(f, level, mage->spellbook);

View File

@ -428,6 +428,63 @@ static void test_unit_limit(CuTest * tc)
test_cleanup();
}
static void test_maketemp(CuTest * tc)
{
faction *f;
unit *u, *u2;
test_setup();
f = test_create_faction(NULL);
u = test_create_unit(f, test_create_region(0, 0, NULL));
u->orders = create_order(K_MAKETEMP, f->locale, "1");
u->orders->next = create_order(K_ENTERTAIN, f->locale, NULL);
u->orders->next->next = create_order(K_END, f->locale, NULL);
u->orders->next->next->next = create_order(K_TAX, f->locale, NULL);
new_units();
CuAssertIntEquals(tc, 2, f->num_units);
CuAssertPtrNotNull(tc, u2 = u->next);
CuAssertPtrNotNull(tc, u2->orders);
CuAssertPtrEquals(tc, NULL, u2->orders->next);
CuAssertIntEquals(tc, K_ENTERTAIN, getkeyword(u2->orders));
CuAssertPtrNotNull(tc, u->orders);
CuAssertPtrEquals(tc, NULL, u->orders->next);
CuAssertIntEquals(tc, K_TAX, getkeyword(u->orders));
test_cleanup();
}
static void test_maketemp_default_order(CuTest * tc)
{
faction *f;
unit *u, *u2;
test_setup();
config_set("orders.default", "work");
f = test_create_faction(NULL);
u = test_create_unit(f, test_create_region(0, 0, NULL));
new_units();
CuAssertIntEquals(tc, 1, f->num_units);
u->orders = create_order(K_MAKETEMP, f->locale, "1");
u->orders->next = create_order(K_END, f->locale, NULL);
u->orders->next->next = create_order(K_TAX, f->locale, NULL);
new_units();
CuAssertIntEquals(tc, 2, f->num_units);
CuAssertPtrNotNull(tc, u2 = u->next);
CuAssertPtrNotNull(tc, u2->orders);
CuAssertPtrEquals(tc, NULL, u2->orders->next);
CuAssertIntEquals(tc, K_WORK, getkeyword(u2->orders));
CuAssertPtrNotNull(tc, u->orders);
CuAssertPtrEquals(tc, NULL, u->orders->next);
CuAssertIntEquals(tc, K_TAX, getkeyword(u->orders));
test_cleanup();
}
static void test_limit_new_units(CuTest * tc)
{
faction *f;
@ -449,6 +506,8 @@ static void test_limit_new_units(CuTest * tc)
CuAssertPtrNotNull(tc, u->next);
CuAssertIntEquals(tc, 2, f->num_units);
CuAssertPtrEquals(tc, NULL, u->orders);
u->orders = create_order(K_MAKETEMP, f->locale, "1");
new_units();
CuAssertIntEquals(tc, 2, f->num_units);
CuAssertPtrNotNull(tc, test_find_messagetype(f->msgs, "too_many_units_in_faction"));
@ -458,6 +517,8 @@ static void test_limit_new_units(CuTest * tc)
config_set("rules.limit.faction", "3");
config_set("rules.limit.alliance", "2");
CuAssertPtrEquals(tc, NULL, u->orders);
u->orders = create_order(K_MAKETEMP, f->locale, "1");
new_units();
CuAssertIntEquals(tc, 2, f->num_units);
CuAssertPtrNotNull(tc, test_find_messagetype(f->msgs, "too_many_units_in_alliance"));
@ -466,6 +527,8 @@ static void test_limit_new_units(CuTest * tc)
u = test_create_unit(test_create_faction(NULL), u->region);
setalliance(u->faction, al);
CuAssertPtrEquals(tc, NULL, u->orders);
u->orders = create_order(K_MAKETEMP, f->locale, "1");
new_units();
CuAssertIntEquals(tc, 2, f->num_units);
CuAssertPtrNotNull(tc, test_find_messagetype(f->msgs, "too_many_units_in_alliance"));
@ -1555,6 +1618,8 @@ static void test_armedmen(CuTest *tc) {
CuSuite *get_laws_suite(void)
{
CuSuite *suite = CuSuiteNew();
SUITE_ADD_TEST(suite, test_maketemp_default_order);
SUITE_ADD_TEST(suite, test_maketemp);
SUITE_ADD_TEST(suite, test_nmr_warnings);
SUITE_ADD_TEST(suite, test_ally_cmd);
SUITE_ADD_TEST(suite, test_name_cmd);

View File

@ -42,6 +42,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#include <kernel/building.h>
#include <kernel/callbacks.h>
#include <kernel/curse.h>
#include <kernel/equipment.h>
#include <kernel/faction.h>
#include <kernel/item.h>
#include <kernel/messages.h>
@ -322,10 +323,19 @@ attrib_type at_mage = {
bool is_mage(const unit * u)
{
return get_mage(u) != NULL;
return get_mage_depr(u) != NULL;
}
sc_mage *get_mage(const unit * u)
{
attrib *a = a_find(u->attribs, &at_mage);
if (a) {
return (sc_mage *)a->data.v;
}
return NULL;
}
sc_mage *get_mage_depr(const unit * u)
{
if (has_skill(u, SK_MAGIC)) {
attrib *a = a_find(u->attribs, &at_mage);
@ -333,7 +343,7 @@ sc_mage *get_mage(const unit * u)
return (sc_mage *)a->data.v;
}
}
return (sc_mage *)NULL;
return NULL;
}
/* ------------------------------------------------------------- */
@ -506,7 +516,7 @@ int u_hasspell(const unit *u, const struct spell *sp)
int get_combatspelllevel(const unit * u, int nr)
{
sc_mage *m = get_mage(u);
sc_mage *m = get_mage_depr(u);
assert(nr < MAXCOMBATSPELLS);
if (m) {
@ -524,7 +534,7 @@ const spell *get_combatspell(const unit * u, int nr)
sc_mage *m;
assert(nr < MAXCOMBATSPELLS);
m = get_mage(u);
m = get_mage_depr(u);
if (m) {
return m->combatspells[nr].sp;
}
@ -533,7 +543,7 @@ const spell *get_combatspell(const unit * u, int nr)
void set_combatspell(unit * u, spell * sp, struct order *ord, int level)
{
sc_mage *mage = get_mage(u);
sc_mage *mage = get_mage_depr(u);
int i = -1;
assert(mage || !"trying to set a combat spell for non-mage");
@ -573,7 +583,7 @@ void unset_combatspell(unit * u, spell * sp)
int nr = 0;
int i;
m = get_mage(u);
m = get_mage_depr(u);
if (!m)
return;
@ -609,7 +619,7 @@ int get_spellpoints(const unit * u)
{
sc_mage *m;
m = get_mage(u);
m = get_mage_depr(u);
if (!m)
return 0;
@ -620,7 +630,7 @@ void set_spellpoints(unit * u, int sp)
{
sc_mage *m;
m = get_mage(u);
m = get_mage_depr(u);
if (!m)
return;
@ -637,7 +647,7 @@ int change_spellpoints(unit * u, int mp)
sc_mage *m;
int sp;
m = get_mage(u);
m = get_mage_depr(u);
if (!m) {
return 0;
}
@ -656,7 +666,7 @@ static int get_spchange(const unit * u)
{
sc_mage *m;
m = get_mage(u);
m = get_mage_depr(u);
if (!m)
return 0;
@ -710,7 +720,7 @@ int change_maxspellpoints(unit * u, int csp)
{
sc_mage *m;
m = get_mage(u);
m = get_mage_depr(u);
if (!m) {
return 0;
}
@ -728,7 +738,7 @@ int countspells(unit * u, int step)
sc_mage *m;
int count;
m = get_mage(u);
m = get_mage_depr(u);
if (!m)
return 0;
@ -1312,7 +1322,7 @@ bool fumble(region * r, unit * u, const spell * sp, int cast_grade)
}
/* CHAOSPATZERCHANCE 10 : +10% Chance zu Patzern */
mage = get_mage(u);
mage = get_mage_depr(u);
if (mage->magietyp == M_DRAIG) {
fumble_chance += CHAOSPATZERCHANCE;
}
@ -2181,10 +2191,8 @@ void set_familiar(unit * mage, unit * familiar)
a = a->next;
}
if (a == NULL) {
attrib *an = a_add(&mage->attribs, a_new(&at_skillmod));
skillmod_data *smd = (skillmod_data *)an->data.v;
smd->special = sm_familiar;
smd->skill = NOSKILL;
a = make_skillmod(NOSKILL, sm_familiar, 0.0, 0);
a_add(&mage->attribs, a);
}
a = a_find(mage->attribs, &at_familiar);
@ -2192,17 +2200,19 @@ void set_familiar(unit * mage, unit * familiar)
a = a_add(&mage->attribs, a_new(&at_familiar));
a->data.v = familiar;
}
else
else {
assert(!a->data.v || a->data.v == familiar);
/* TODO: Diese Attribute beim Tod des Familiars entfernen: */
}
/* TODO: Diese Attribute beim Tod des Familiars entfernen: */
a = a_find(familiar->attribs, &at_familiarmage);
if (a == NULL) {
a = a_add(&familiar->attribs, a_new(&at_familiarmage));
a->data.v = mage;
}
else
else {
assert(!a->data.v || a->data.v == mage);
}
}
void remove_familiar(unit * mage)
@ -2218,48 +2228,35 @@ void remove_familiar(unit * mage)
while (a && a->type == &at_skillmod) {
an = a->next;
smd = (skillmod_data *)a->data.v;
if (smd->special == sm_familiar)
if (smd->special == sm_familiar) {
a_remove(&mage->attribs, a);
}
a = an;
}
}
bool create_newfamiliar(unit * mage, unit * familiar)
void create_newfamiliar(unit * mage, unit * fam)
{
/* if the skill modifier for the mage does not yet exist, add it */
attrib *a;
attrib *afam = a_find(mage->attribs, &at_familiar);
attrib *amage = a_find(familiar->attribs, &at_familiarmage);
/* skills and spells: */
const struct equipment *eq;
char eqname[64];
const race *rc = u_race(fam);
if (afam == NULL) {
afam = a_add(&mage->attribs, a_new(&at_familiar));
}
afam->data.v = familiar;
if (amage == NULL) {
amage = a_add(&familiar->attribs, a_new(&at_familiarmage));
}
amage->data.v = mage;
set_familiar(mage, fam);
snprintf(eqname, sizeof(eqname), "fam_%s", rc->_name);
eq = get_equipment(eqname);
if (eq != NULL) {
equip_unit(fam, eq);
}
else {
log_info("could not perform initialization for familiar %s.\n", rc->_name);
}
/* TODO: Diese Attribute beim Tod des Familiars entfernen: */
/* Wenn der Magier stirbt, dann auch der Vertraute */
add_trigger(&mage->attribs, "destroy", trigger_killunit(familiar));
add_trigger(&mage->attribs, "destroy", trigger_killunit(fam));
/* Wenn der Vertraute stirbt, dann bekommt der Magier einen Schock */
add_trigger(&familiar->attribs, "destroy", trigger_shock(mage));
a = a_find(mage->attribs, &at_skillmod);
while (a && a->type == &at_skillmod) {
skillmod_data *smd = (skillmod_data *)a->data.v;
if (smd->special == sm_familiar)
break;
a = a->next;
}
if (a == NULL) {
attrib *an = a_add(&mage->attribs, a_new(&at_skillmod));
skillmod_data *smd = (skillmod_data *)an->data.v;
smd->special = sm_familiar;
smd->skill = NOSKILL;
}
return true;
add_trigger(&fam->attribs, "destroy", trigger_shock(mage));
}
static void * resolve_familiar(int id, void *data) {

View File

@ -221,6 +221,7 @@ extern "C" {
/* macht die struct unit zu einem neuen Magier: legt die struct u->mage an
* und initialisiert den Magiertypus mit mtyp. */
sc_mage *get_mage(const struct unit *u);
sc_mage *get_mage_depr(const struct unit *u);
/* gibt u->mage zurück, bei nicht-Magiern *NULL */
bool is_mage(const struct unit *u);
/* gibt true, wenn u->mage gesetzt. */
@ -329,7 +330,7 @@ extern "C" {
struct unit *get_clone(const struct unit *u);
struct unit *get_clone_mage(const struct unit *u);
void remove_familiar(struct unit *mage);
bool create_newfamiliar(struct unit *mage, struct unit *familiar);
void create_newfamiliar(struct unit *mage, struct unit *familiar);
void create_newclone(struct unit *mage, struct unit *familiar);
struct unit *has_clone(struct unit *mage);

View File

@ -6,6 +6,7 @@
#include <kernel/building.h>
#include <kernel/race.h>
#include <kernel/equipment.h>
#include <kernel/faction.h>
#include <kernel/order.h>
#include <kernel/item.h>
@ -477,9 +478,131 @@ static void test_illusioncastle(CuTest *tc)
test_cleanup();
}
static void test_is_mage(CuTest *tc) {
unit *u;
sc_mage *mage;
test_setup();
u = test_create_unit(test_create_faction(0), test_create_region(0, 0, 0));
CuAssertPtrEquals(tc, NULL, get_mage(u));
CuAssertTrue(tc, !is_mage(u));
set_level(u, SK_MAGIC, 1);
CuAssertTrue(tc, !is_mage(u));
CuAssertPtrEquals(tc, NULL, get_mage(u));
CuAssertPtrNotNull(tc, mage = create_mage(u, M_CERDDOR));
CuAssertPtrEquals(tc, mage, get_mage(u));
CuAssertTrue(tc, is_mage(u));
test_cleanup();
}
static void test_get_mage(CuTest *tc) {
unit *u;
sc_mage *mage;
test_setup();
u = test_create_unit(test_create_faction(0), test_create_region(0, 0, 0));
CuAssertPtrEquals(tc, NULL, get_mage(u));
CuAssertPtrEquals(tc, NULL, get_mage_depr(u));
CuAssertPtrNotNull(tc, mage = create_mage(u, M_CERDDOR));
CuAssertPtrEquals(tc, mage, get_mage(u));
CuAssertPtrEquals(tc, NULL, get_mage_depr(u));
set_level(u, SK_MAGIC, 1);
CuAssertPtrEquals(tc, mage, get_mage(u));
CuAssertPtrEquals(tc, mage, get_mage_depr(u));
test_cleanup();
}
static void test_familiar_set(CuTest *tc) {
unit *mag, *fam;
test_setup();
mag = test_create_unit(test_create_faction(0), test_create_region(0, 0, 0));
fam = test_create_unit(mag->faction, test_create_region(0, 0, 0));
CuAssertPtrEquals(tc, NULL, get_familiar(mag));
CuAssertPtrEquals(tc, NULL, get_familiar_mage(fam));
CuAssertPtrEquals(tc, NULL, a_find(mag->attribs, &at_skillmod));
set_familiar(mag, fam);
CuAssertPtrEquals(tc, fam, get_familiar(mag));
CuAssertPtrEquals(tc, mag, get_familiar_mage(fam));
CuAssertPtrNotNull(tc, a_find(mag->attribs, &at_skillmod));
remove_familiar(mag);
CuAssertPtrEquals(tc, NULL, get_familiar(mag));
CuAssertPtrEquals(tc, NULL, a_find(mag->attribs, &at_skillmod));
test_cleanup();
}
static void test_familiar_age(CuTest *tc) {
unit *mag, *fam;
test_setup();
mag = test_create_unit(test_create_faction(0), test_create_region(0, 0, 0));
fam = test_create_unit(mag->faction, test_create_region(0, 0, 0));
set_familiar(mag, fam);
CuAssertPtrEquals(tc, fam, get_familiar(mag));
CuAssertPtrEquals(tc, mag, get_familiar_mage(fam));
a_age(&fam->attribs, fam);
a_age(&mag->attribs, mag);
CuAssertPtrEquals(tc, fam, get_familiar(mag));
CuAssertPtrEquals(tc, mag, get_familiar_mage(fam));
set_number(fam, 0);
a_age(&mag->attribs, mag);
CuAssertPtrEquals(tc, NULL, get_familiar(mag));
test_cleanup();
}
static void test_familiar_equip(CuTest *tc) {
unit *mag, *u;
equipment *eq;
const item_type * itype;
spell *sp;
sc_mage * mage;
test_setup();
itype = test_create_itemtype("horse");
CuAssertPtrNotNull(tc, itype);
sp = create_spell("testspell");
CuAssertPtrNotNull(tc, sp);
eq = get_or_create_equipment("fam_human");
equipment_setitem(eq, itype, "1");
equipment_setskill(eq, SK_ENTERTAINMENT, "5");
equipment_addspell(eq, sp->sname, 1);
mag = test_create_unit(test_create_faction(0), test_create_region(0, 0, 0));
u = test_create_unit(mag->faction, test_create_region(0, 0, 0));
set_familiar(mag, u);
create_newfamiliar(mag, u);
CuAssertIntEquals(tc, 1, i_get(u->items, itype));
CuAssertIntEquals(tc, 5, get_level(u, SK_ENTERTAINMENT));
CuAssertIntEquals(tc, 0, get_level(u, SK_MAGIC));
mage = get_mage(u);
CuAssertPtrNotNull(tc, mage);
CuAssertPtrNotNull(tc, mage->spellbook);
set_level(u, SK_MAGIC, 1);
CuAssertPtrEquals(tc, mage, get_mage_depr(u));
CuAssertTrue(tc, u_hasspell(u, sp));
test_cleanup();
}
CuSuite *get_familiar_suite(void)
{
CuSuite *suite = CuSuiteNew();
SUITE_ADD_TEST(suite, test_familiar_equip);
SUITE_ADD_TEST(suite, test_familiar_set);
SUITE_ADD_TEST(suite, test_familiar_age);
return suite;
}
CuSuite *get_magic_suite(void)
{
CuSuite *suite = CuSuiteNew();
SUITE_ADD_TEST(suite, test_is_mage);
SUITE_ADD_TEST(suite, test_get_mage);
SUITE_ADD_TEST(suite, test_multi_cast);
SUITE_ADD_TEST(suite, test_updatespells);
SUITE_ADD_TEST(suite, test_spellbooks);

View File

@ -147,8 +147,7 @@ newfaction *read_newfactions(const char *filename)
faction *f;
char race[20], email[64], lang[8], password[16];
newfaction *nf, **nfi;
int bonus = 0, subscription = 0;
int alliance = 0;
int alliance = 0, subscription = 0;
if (fgets(buf, sizeof(buf), F) == NULL)
break;
@ -156,8 +155,8 @@ newfaction *read_newfactions(const char *filename)
email[0] = '\0';
password[0] = '\0';
if (sscanf(buf, "%54s %20s %8s %d %d %16s %d", email, race, lang, &bonus,
&subscription, password, &alliance) < 3) {
if (sscanf(buf, "%54s %20s %8s %16s %d %d", email, race, lang,
password, &subscription, &alliance) < 3) {
break;
}
if (email[0] == '#') {
@ -228,7 +227,6 @@ newfaction *read_newfactions(const char *filename)
}
}
nf->lang = get_locale(lang);
nf->bonus = bonus;
assert(nf->race && nf->email && nf->lang);
nfi = &newfactions;
while (*nfi) {

View File

@ -24,7 +24,6 @@ extern "C" {
char *password;
const struct locale *lang;
const struct race *race;
int bonus;
int subscription;
bool oldregions;
struct alliance *allies;

View File

@ -89,14 +89,6 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#include <limits.h>
#include <float.h>
/* Bewegungsweiten: */
#define BP_WALKING 4
#define BP_RIDING 6
#define BP_UNICORN 9
#define BP_DRAGON 4
#define BP_NORMAL 3
#define BP_ROAD 2
int *storms;
typedef struct traveldir {
@ -265,7 +257,7 @@ get_transporters(const item * itm, int *p_animals, int *p_acap, int *p_vehicles,
*p_acap = acap;
}
static int ridingcapacity(unit * u)
static int ridingcapacity(const unit * u)
{
int vehicles = 0, vcap = 0;
int animals = 0, acap = 0;
@ -433,7 +425,7 @@ bool canswim(unit * u)
return false;
}
static int canride(unit * u)
static int canride(const unit * u)
{
int horses = 0, maxhorses, unicorns = 0, maxunicorns;
int skill = effskill(u, SK_RIDING, 0);
@ -460,17 +452,17 @@ static int canride(unit * u)
if (!(u_race(u)->flags & RCF_HORSE)
&& ((horses == 0 && unicorns == 0)
|| horses > maxhorses || unicorns > maxunicorns)) {
return 0;
return BP_WALKING;
}
if (ridingcapacity(u) - eff_weight(u) >= 0) {
if (horses == 0 && unicorns >= u->number && !(u_race(u)->flags & RCF_HORSE)) {
return 2;
return BP_UNICORN;
}
return 1;
return BP_RIDING;
}
return 0;
return BP_WALKING;
}
static bool cansail(const region * r, ship * sh)
@ -1399,9 +1391,9 @@ static void make_route(unit * u, order * ord, region_list ** routep)
* Normalerweise verliert man 3 BP pro Region, bei Straßen nur 2 BP.
* Außerdem: Wenn Einheit transportiert, nur halbe BP
*/
static int movement_speed(unit * u)
int movement_speed(const unit * u)
{
int mp = BP_WALKING;
int mp = 0;
const race *rc = u_race(u);
double dk = rc->speed;
assert(u->number);
@ -1415,6 +1407,10 @@ static int movement_speed(unit * u)
mp = BP_DRAGON;
break;
default:
mp = canride(u);
if (mp>=BP_RIDING) {
dk = 1.0;
}
break;
}
@ -1426,22 +1422,6 @@ static int movement_speed(unit * u)
}
}
switch (canride(u)) {
case 1: /* Pferd */
mp = BP_RIDING;
break;
case 2: /* Einhorn */
mp = BP_UNICORN;
break;
default:
/* Siebenmeilentee */
if (get_effect(u, oldpotiontype[P_FAST]) >= u->number) {
mp *= 2;
change_effect(u, oldpotiontype[P_FAST], -u->number);
}
/* unicorn in inventory */
if (u->number <= i_get(u->items, it_find("fairyboot"))) {
mp *= 2;
@ -1449,15 +1429,15 @@ static int movement_speed(unit * u)
/* Im Astralraum sind Tyb und Ill-Magier doppelt so schnell.
* Nicht kumulativ mit anderen Beschleunigungen! */
if (mp * dk <= BP_WALKING * u_race(u)->speed && is_astral(u->region)
&& is_mage(u)) {
if (mp * dk <= BP_WALKING * u_race(u)->speed && is_astral(u->region)) {
sc_mage *mage = get_mage(u);
if (mage->magietyp == M_TYBIED || mage->magietyp == M_ILLAUN) {
if (mage && (mage->magietyp == M_TYBIED || mage->magietyp == M_ILLAUN)) {
if (has_skill(u, SK_MAGIC)) {
mp *= 2;
}
}
break;
}
return (int)(dk * mp);
}
@ -2044,7 +2024,7 @@ static const region_list *travel_i(unit * u, const region_list * route_begin,
const region_list * route_end, order * ord, int mode, follower ** followers)
{
region *r = u->region;
int mp;
if (u->building && !can_leave(u)) {
cmistake(u, u->thisorder, 150, MSG_MOVE);
return route_begin;
@ -2060,7 +2040,15 @@ static const region_list *travel_i(unit * u, const region_list * route_begin,
cmistake(u, ord, 42, MSG_MOVE);
return route_begin;
}
route_end = cap_route(r, route_begin, route_end, movement_speed(u));
mp = movement_speed(u);
/* Siebenmeilentee */
if (get_effect(u, oldpotiontype[P_FAST]) >= u->number) {
mp *= 2;
change_effect(u, oldpotiontype[P_FAST], -u->number);
}
route_end = cap_route(r, route_begin, route_end, mp);
route_end = travel_route(u, route_begin, route_end, ord, mode);
if (u->flags&UFL_FOLLOWED) {

View File

@ -36,6 +36,14 @@ extern "C" {
extern struct attrib_type at_shiptrail;
extern int *storms;
/* Bewegungsweiten: */
#define BP_WALKING 4
#define BP_RIDING 6
#define BP_UNICORN 9
#define BP_DRAGON 4
#define BP_NORMAL 3
#define BP_ROAD 2
/* die Zahlen sind genau äquivalent zu den race Flags */
#define MV_CANNOTMOVE (1<<5)
#define MV_FLY (1<<7) /* kann fliegen */
@ -70,6 +78,7 @@ extern "C" {
struct ship *move_ship(struct ship *sh, struct region *from,
struct region *to, struct region_list *route);
int walkingcapacity(const struct unit *u);
int movement_speed(const struct unit * u);
void follow_unit(struct unit *u);
struct unit *owner_buildingtyp(const struct region *r,
const struct building_type *bt);

View File

@ -522,9 +522,33 @@ static void test_ship_leave_trail(CuTest *tc) {
test_cleanup();
}
static void test_movement_speed(CuTest *tc) {
unit * u;
race * rc;
const struct item_type *it_horse;
test_setup();
it_horse = test_create_horse();
rc = test_create_race(NULL);
u = test_create_unit(test_create_faction(rc), test_create_region(0, 0, NULL));
rc->speed = 1.0;
CuAssertIntEquals(tc, BP_WALKING, movement_speed(u));
rc->speed = 2.0;
CuAssertIntEquals(tc, 2 * BP_WALKING, movement_speed(u));
set_level(u, SK_RIDING, 1);
i_change(&u->items, it_horse, 1);
CuAssertIntEquals(tc, BP_RIDING, movement_speed(u));
test_cleanup();
}
CuSuite *get_move_suite(void)
{
CuSuite *suite = CuSuiteNew();
SUITE_ADD_TEST(suite, test_movement_speed);
SUITE_ADD_TEST(suite, test_walkingcapacity);
SUITE_ADD_TEST(suite, test_ship_not_allowed_in_coast);
SUITE_ADD_TEST(suite, test_ship_leave_trail);

View File

@ -1090,6 +1090,9 @@ void report_region(struct stream *out, const region * r, faction * f)
message *msg;
if (owner != NULL) {
bytes = (int)strlcpy(bufp, " ", size);
if (wrptr(&bufp, &size, bytes) != 0)
WARN_STATIC_BUFFER();
msg = msg_message("nr_region_owner", "faction", owner);
bytes = (int)nr_render(msg, f->locale, bufp, size, f);
msg_release(msg);

View File

@ -819,8 +819,9 @@ spskill(char *buffer, size_t size, const struct locale * lang,
bufp = STRLCPY(bufp, " ", size);
if (sv->id == SK_MAGIC) {
sc_mage *mage = get_mage(u);
if (mage && mage->magietyp != M_GRAY) {
sc_mage *mage = get_mage_depr(u);
assert(mage);
if (mage->magietyp != M_GRAY) {
bufp = STRLCPY(bufp, LOC(lang, mkname("school",
magic_school[mage->magietyp])), size);
bufp = STRLCPY(bufp, " ", size);

View File

@ -39,7 +39,6 @@
#include <kernel/building.h>
#include <kernel/curse.h>
#include <kernel/connection.h>
#include <kernel/equipment.h>
#include <kernel/faction.h>
#include <kernel/item.h>
#include <kernel/messages.h>
@ -513,32 +512,26 @@ static const race *select_familiar(const race * magerace, magic_t magiegebiet)
/* ------------------------------------------------------------- */
/* der Vertraue des Magiers */
static void make_familiar(unit * familiar, unit * mage)
static unit * make_familiar(unit * mage, region *r, const race *rc, const char *name)
{
/* skills and spells: */
const struct equipment *eq;
char eqname[64];
const race * rc = u_race(familiar);
snprintf(eqname, sizeof(eqname), "fam_%s", rc->_name);
eq = get_equipment(eqname);
if (eq != NULL) {
equip_items(&familiar->items, eq);
}
else {
log_info("could not perform initialization for familiar %s.\n", rc->_name);
}
unit *fam;
fam = create_unit(r, mage->faction, 1, rc, 0, name, mage);
setstatus(fam, ST_FLEE);
fset(fam, UFL_LOCKED);
/* triggers: */
create_newfamiliar(mage, familiar);
create_newfamiliar(mage, fam);
/* Hitpoints nach Talenten korrigieren, sonst starten vertraute
* mit Ausdauerbonus verwundet */
familiar->hp = unit_max_hp(familiar);
fam->hp = unit_max_hp(fam);
return fam;
}
static int sp_summon_familiar(castorder * co)
{
unit *familiar;
region *r = co_get_region(co);
unit *mage = co->magician.u;
int cast_level = co->level;
@ -586,10 +579,7 @@ static int sp_summon_familiar(castorder * co)
msg = msg_message("familiar_name", "unit", mage);
nr_render(msg, mage->faction->locale, zText, sizeof(zText), mage->faction);
msg_release(msg);
familiar = create_unit(r, mage->faction, 1, rc, 0, zText, mage);
setstatus(familiar, ST_FLEE);
fset(familiar, UFL_LOCKED);
make_familiar(familiar, mage);
make_familiar(mage, r, rc, zText);
dh = 0;
dh1 = 0;
@ -740,7 +730,7 @@ static int sp_transferaura(castorder * co)
int cast_level = co->level;
spellparameter *pa = co->par;
unit *u;
sc_mage *scm_dst, *scm_src = get_mage(mage);
sc_mage *scm_dst, *scm_src = get_mage_depr(mage);
/* wenn kein Ziel gefunden, Zauber abbrechen */
if (pa->param[0]->flag == TARGET_NOTFOUND)
@ -754,7 +744,7 @@ static int sp_transferaura(castorder * co)
/* Wieviel Transferieren? */
aura = pa->param[1]->data.i;
u = pa->param[0]->data.u;
scm_dst = get_mage(u);
scm_dst = get_mage_depr(u);
if (scm_dst == NULL) {
/* "Zu dieser Einheit kann ich keine Aura uebertragen." */
@ -5822,7 +5812,7 @@ int sp_permtransfer(castorder * co)
change_maxspellpoints(mage, -aura);
change_spellpoints(mage, -aura);
if (get_mage(tu)->magietyp == get_mage(mage)->magietyp) {
if (get_mage_depr(tu)->magietyp == get_mage_depr(mage)->magietyp) {
change_maxspellpoints(tu, aura / 2);
}
else {
@ -5945,18 +5935,18 @@ int sp_stealaura(castorder * co)
/* Zieleinheit */
u = pa->param[0]->data.u;
if (!get_mage(u)) {
if (!get_mage_depr(u)) {
ADDMSG(&mage->faction->msgs, msg_message("stealaura_fail", "unit target",
mage, u));
ADDMSG(&u->faction->msgs, msg_message("stealaura_fail_detect", "unit", u));
return 0;
}
taura = (get_mage(u)->spellpoints * (rng_int() % (int)(3 * power) + 1)) / 100;
taura = (get_mage_depr(u)->spellpoints * (rng_int() % (int)(3 * power) + 1)) / 100;
if (taura > 0) {
get_mage(u)->spellpoints -= taura;
get_mage(mage)->spellpoints += taura;
get_mage_depr(u)->spellpoints -= taura;
get_mage_depr(mage)->spellpoints += taura;
/* sprintf(buf, "%s entzieht %s %d Aura.", unitname(mage), unitname(u),
taura); */
ADDMSG(&mage->faction->msgs, msg_message("stealaura_success",

View File

@ -68,7 +68,7 @@ void spy_message(int spy, const unit * u, const unit * target)
ADDMSG(&u->faction->msgs, msg_message("spyreport", "spy target status", u,
target, status));
if (spy > 20) {
sc_mage *mage = get_mage(target);
sc_mage *mage = get_mage_depr(target);
/* for mages, spells and magic school */
if (mage) {
ADDMSG(&u->faction->msgs, msg_message("spyreport_mage", "spy target type", u,

View File

@ -427,8 +427,8 @@ int teach_cmd(unit * teacher, struct order *ord)
if (sk == SK_MAGIC) {
/* ist der Magier schon spezialisiert, so versteht er nur noch
* Lehrer seines Gebietes */
sc_mage *mage1 = get_mage(teacher);
sc_mage *mage2 = get_mage(student);
sc_mage *mage1 = get_mage_depr(teacher);
sc_mage *mage2 = get_mage_depr(student);
if (mage2 && mage1 && mage2->magietyp != M_GRAY
&& mage1->magietyp != mage2->magietyp) {
if (feedback) {
@ -782,7 +782,7 @@ int study_cmd(unit * u, order * ord)
}
}
else if (sk == SK_MAGIC) {
sc_mage *mage = get_mage(u);
sc_mage *mage = get_mage_depr(u);
if (!mage) {
mage = create_mage(u, u->faction->magiegebiet);
}

View File

@ -409,11 +409,11 @@ static void test_study_magic(CuTest *tc) {
study_cmd(u, u->thisorder);
CuAssertIntEquals(tc, M_GWYRRD, f->magiegebiet);
CuAssertIntEquals(tc, 0, i_get(u->items, rtype->itype));
CuAssertPtrNotNull(tc, get_mage(u));
CuAssertPtrNotNull(tc, get_mage_depr(u));
CuAssertPtrEquals(tc, 0, test_find_messagetype(f->msgs, "error65"));
CuAssertIntEquals(tc, M_GWYRRD, get_mage(u)->magietyp);
CuAssertIntEquals(tc, M_GWYRRD, get_mage_depr(u)->magietyp);
/* the static cost array in study_cost prevents this test:
/* TODO: the static cost array in study_cost prevents this test:
test_clear_messages(f);
config_set("skills.cost.magic", "50");
i_change(&u->items, rtype->itype, 50);

View File

@ -101,6 +101,7 @@ int RunAllTests(int argc, char *argv[])
ADD_SUITE(pool);
ADD_SUITE(curse);
ADD_SUITE(equipment);
ADD_SUITE(familiar);
ADD_SUITE(item);
ADD_SUITE(magic);
ADD_SUITE(alchemy);

View File

@ -39,7 +39,7 @@
struct race *test_create_race(const char *name)
{
race *rc = rc_get_or_create(name);
race *rc = rc_get_or_create(name ? name : "smurf");
rc->maintenance = 10;
rc->hitpoints = 20;
rc->maxaura = 100;

View File

@ -396,7 +396,6 @@ int a_age(attrib ** p, void *owner)
static critbit_tree cb_deprecated = { 0 };
typedef struct deprecated_s {
unsigned int hash;
int(*reader)(attrib *, void *, struct gamedata *);

View File

@ -39,7 +39,7 @@
/* unfinished: */
#define CRYPT_VERSION 400 /* passwords are encrypted */
#define RELEASE_VERSION SKILLSORT_VERSION /* current datafile */
#define RELEASE_VERSION LANDDISPLAY_VERSION /* current datafile */
#define MIN_VERSION UIDHASH_VERSION /* minimal datafile we support */
#define MAX_VERSION RELEASE_VERSION /* change this if we can need to read the future datafile, and we can do so */

View File

@ -18,7 +18,7 @@ assert_grep_count() {
file=$1
expr=$2
expect=$3
count=`grep -cE $expr $file`
count=`grep -cE "$expr" $file`
[ $count -eq $expect ] || quit 1 "expected $expect counts of $expr in $file, got $count"
echo "PASS: $expr is $expect"
}
@ -33,7 +33,7 @@ setup
cleanup
VALGRIND=`which valgrind`
SERVER=../Debug/eressea/eressea
set -e
#set -e
if [ -n "$VALGRIND" ]; then
SUPP=../share/ubuntu-12_04.supp
SERVER="$VALGRIND --track-origins=yes --gen-suppressions=all --suppressions=$SUPP --error-exitcode=1 --leak-check=no $SERVER"
@ -62,5 +62,6 @@ assert_grep_count reports/185-heg.cr '"lighthouse";visibility' 6
assert_grep_count reports/185-heg.cr '"neighbour";visibility' 11
assert_grep_count reports/185-6rLo.cr '^EINHEIT' 2
assert_grep_count reports/185-6rLo.cr '^REGION' 13
assert_grep_count reports/185-6rLo.cr "Befehl ist unbekannt" 0
echo "integration tests: PASS"
cleanup