forked from github/server
Merge pull request #726 from ennorehling/develop
clone_men and familiars
This commit is contained in:
commit
4ac80d3e5b
|
@ -17,15 +17,18 @@ function test_bug_2361_forget_magic()
|
||||||
local r = region.create(0, 0, "plain")
|
local r = region.create(0, 0, "plain")
|
||||||
local f = faction.create("human")
|
local f = faction.create("human")
|
||||||
local u = unit.create(f, r, 1)
|
local u = unit.create(f, r, 1)
|
||||||
|
local uf = unit.create(f, r, 1)
|
||||||
u:clear_orders()
|
u:clear_orders()
|
||||||
u:add_order("VERGESSE Magie")
|
u:add_order("VERGESSE Magie")
|
||||||
u:set_skill('magic', 5)
|
u:set_skill('magic', 5)
|
||||||
u.race = 'unicorn'
|
uf.race = 'unicorn'
|
||||||
process_orders()
|
uf:clear_orders()
|
||||||
assert_equal(5, u:get_skill('magic'))
|
uf:add_order("VERGESSE Magie")
|
||||||
u.race = 'human'
|
uf:set_skill('magic', 5)
|
||||||
|
u.familiar = uf
|
||||||
process_orders()
|
process_orders()
|
||||||
assert_equal(0, u:get_skill('magic'))
|
assert_equal(0, u:get_skill('magic'))
|
||||||
|
assert_equal(5, uf:get_skill('magic'))
|
||||||
end
|
end
|
||||||
|
|
||||||
function test_mine_bonus()
|
function test_mine_bonus()
|
||||||
|
|
|
@ -663,8 +663,8 @@ static int forget_cmd(unit * u, order * ord)
|
||||||
|
|
||||||
sk = get_skill(s, u->faction->locale);
|
sk = get_skill(s, u->faction->locale);
|
||||||
if (sk != NOSKILL) {
|
if (sk != NOSKILL) {
|
||||||
if (sk == SK_MAGIC && (u_race(u)->flags & RCF_FAMILIAR)) {
|
if (sk == SK_MAGIC && is_familiar(u)) {
|
||||||
/* some races cannot forget their innate magical abilities */
|
/* some units cannot forget their innate magical abilities */
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
ADDMSG(&u->faction->msgs, msg_message("forget", "unit skill", u, sk));
|
ADDMSG(&u->faction->msgs, msg_message("forget", "unit skill", u, sk));
|
||||||
|
|
|
@ -991,6 +991,7 @@ void free_construction(struct construction *cons)
|
||||||
{
|
{
|
||||||
while (cons) {
|
while (cons) {
|
||||||
construction *next = cons->improvement;
|
construction *next = cons->improvement;
|
||||||
|
free(cons->name);
|
||||||
free(cons->materials);
|
free(cons->materials);
|
||||||
free(cons);
|
free(cons);
|
||||||
cons = next;
|
cons = next;
|
||||||
|
|
|
@ -517,6 +517,7 @@ static int icache_size;
|
||||||
#define ICACHE_MAX 100
|
#define ICACHE_MAX 100
|
||||||
|
|
||||||
void item_done(void) {
|
void item_done(void) {
|
||||||
|
icache_size = ICACHE_MAX;
|
||||||
i_freeall(&icache);
|
i_freeall(&icache);
|
||||||
icache_size = 0;
|
icache_size = 0;
|
||||||
}
|
}
|
||||||
|
@ -951,7 +952,7 @@ void write_items(struct storage *store, item * ilist)
|
||||||
|
|
||||||
static void free_itype(item_type *itype) {
|
static void free_itype(item_type *itype) {
|
||||||
assert(itype);
|
assert(itype);
|
||||||
free(itype->construction);
|
free_construction(itype->construction);
|
||||||
free(itype->_appearance[0]);
|
free(itype->_appearance[0]);
|
||||||
free(itype->_appearance[1]);
|
free(itype->_appearance[1]);
|
||||||
free(itype);
|
free(itype);
|
||||||
|
|
|
@ -29,6 +29,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
#include "faction.h"
|
#include "faction.h"
|
||||||
#include "group.h"
|
#include "group.h"
|
||||||
#include "item.h"
|
#include "item.h"
|
||||||
|
#include "magic.h"
|
||||||
#include "messages.h"
|
#include "messages.h"
|
||||||
#include "move.h"
|
#include "move.h"
|
||||||
#include "objtypes.h"
|
#include "objtypes.h"
|
||||||
|
@ -51,6 +52,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
#include <attributes/attributes.h>
|
#include <attributes/attributes.h>
|
||||||
#include <attributes/key.h>
|
#include <attributes/key.h>
|
||||||
#include <triggers/timeout.h>
|
#include <triggers/timeout.h>
|
||||||
|
#include <triggers/shock.h>
|
||||||
|
|
||||||
/* util includes */
|
/* util includes */
|
||||||
#include <util/assert.h>
|
#include <util/assert.h>
|
||||||
|
@ -1607,7 +1609,59 @@ ship *read_ship(struct gamedata *data)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int read_game(gamedata *data) {
|
static void fix_familiars(void) {
|
||||||
|
region *r;
|
||||||
|
for (r = regions; r; r = r->next) {
|
||||||
|
unit * u;
|
||||||
|
for (u = r->units; u; u = u->next) {
|
||||||
|
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? */
|
||||||
|
attrib * ae = a_find(u->attribs, &at_eventhandler);
|
||||||
|
if (ae) {
|
||||||
|
trigger **tlist;
|
||||||
|
tlist = get_triggers(ae, "destroy");
|
||||||
|
if (tlist) {
|
||||||
|
trigger *t;
|
||||||
|
unit *um = NULL;
|
||||||
|
for (t = *tlist; t; t = t->next) {
|
||||||
|
if (t->type == &tt_shock) {
|
||||||
|
um = (unit *)t->data.v;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (um) {
|
||||||
|
attrib *af = a_find(um->attribs, &at_familiar);
|
||||||
|
log_error("%s seems to be a broken familiar of %s.",
|
||||||
|
unitname(u), unitname(um));
|
||||||
|
if (af) {
|
||||||
|
unit * uf = (unit *)af->data.v;
|
||||||
|
log_error("%s already has a familiar: %s.",
|
||||||
|
unitname(um), unitname(uf));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
set_familiar(um, u);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
log_error("%s seems to be a broken familiar with no trigger.", unitname(u));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int read_game(gamedata *data)
|
||||||
|
{
|
||||||
int p, nread;
|
int p, nread;
|
||||||
faction *f, **fp;
|
faction *f, **fp;
|
||||||
region *r;
|
region *r;
|
||||||
|
@ -1783,6 +1837,11 @@ int read_game(gamedata *data) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (data->version < FAMILIAR_FIX_VERSION) {
|
||||||
|
fix_familiars();
|
||||||
|
}
|
||||||
|
|
||||||
if (loadplane || maxregions >= 0) {
|
if (loadplane || maxregions >= 0) {
|
||||||
remove_empty_factions();
|
remove_empty_factions();
|
||||||
}
|
}
|
||||||
|
|
|
@ -1060,7 +1060,7 @@ void clone_men(const unit * u, unit * dst, int n)
|
||||||
transfer_curse(u, dst, n);
|
transfer_curse(u, dst, n);
|
||||||
}
|
}
|
||||||
set_number(dst, dst->number + n);
|
set_number(dst, dst->number + n);
|
||||||
dst->hp += u->hp * dst->number / u->number;
|
dst->hp += u->hp * n / u->number;
|
||||||
assert(dst->hp >= dst->number);
|
assert(dst->hp >= dst->number);
|
||||||
/* TODO: Das ist schnarchlahm! und gehoert nicht hierhin */
|
/* TODO: Das ist schnarchlahm! und gehoert nicht hierhin */
|
||||||
a = a_find(dst->attribs, &at_effect);
|
a = a_find(dst->attribs, &at_effect);
|
||||||
|
|
|
@ -548,6 +548,27 @@ static void test_clone_men(CuTest *tc) {
|
||||||
test_cleanup();
|
test_cleanup();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void test_transfermen(CuTest *tc) {
|
||||||
|
unit *u1, *u2;
|
||||||
|
region *r;
|
||||||
|
faction *f;
|
||||||
|
test_setup();
|
||||||
|
r = test_create_region(0, 0, NULL);
|
||||||
|
f = test_create_faction(NULL);
|
||||||
|
u1 = test_create_unit(f, r);
|
||||||
|
scale_number(u1, 3500);
|
||||||
|
u2 = test_create_unit(f, r);
|
||||||
|
scale_number(u2, 3500);
|
||||||
|
CuAssertIntEquals(tc, 70000, u1->hp);
|
||||||
|
CuAssertIntEquals(tc, 70000, u2->hp);
|
||||||
|
transfermen(u1, u2, u1->number);
|
||||||
|
CuAssertIntEquals(tc, 7000, u2->number);
|
||||||
|
CuAssertIntEquals(tc, 140000, u2->hp);
|
||||||
|
CuAssertIntEquals(tc, 0, u1->number);
|
||||||
|
CuAssertIntEquals(tc, 0, u1->hp);
|
||||||
|
test_cleanup();
|
||||||
|
}
|
||||||
|
|
||||||
CuSuite *get_unit_suite(void)
|
CuSuite *get_unit_suite(void)
|
||||||
{
|
{
|
||||||
CuSuite *suite = CuSuiteNew();
|
CuSuite *suite = CuSuiteNew();
|
||||||
|
@ -557,6 +578,7 @@ CuSuite *get_unit_suite(void)
|
||||||
SUITE_ADD_TEST(suite, test_unit_name_from_race);
|
SUITE_ADD_TEST(suite, test_unit_name_from_race);
|
||||||
SUITE_ADD_TEST(suite, test_update_monster_name);
|
SUITE_ADD_TEST(suite, test_update_monster_name);
|
||||||
SUITE_ADD_TEST(suite, test_clone_men);
|
SUITE_ADD_TEST(suite, test_clone_men);
|
||||||
|
SUITE_ADD_TEST(suite, test_transfermen);
|
||||||
SUITE_ADD_TEST(suite, test_remove_unit);
|
SUITE_ADD_TEST(suite, test_remove_unit);
|
||||||
SUITE_ADD_TEST(suite, test_remove_empty_units);
|
SUITE_ADD_TEST(suite, test_remove_empty_units);
|
||||||
SUITE_ADD_TEST(suite, test_remove_units_without_faction);
|
SUITE_ADD_TEST(suite, test_remove_units_without_faction);
|
||||||
|
|
13
src/magic.c
13
src/magic.c
|
@ -2140,16 +2140,6 @@ void free_castorders(castorder * co)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ------------------------------------------------------------- */
|
|
||||||
/***
|
|
||||||
** at_familiarmage
|
|
||||||
**/
|
|
||||||
|
|
||||||
typedef struct familiar_data {
|
|
||||||
unit *mage;
|
|
||||||
unit *familiar;
|
|
||||||
} famililar_data;
|
|
||||||
|
|
||||||
bool is_familiar(const unit * u)
|
bool is_familiar(const unit * u)
|
||||||
{
|
{
|
||||||
attrib *a = a_find(u->attribs, &at_familiarmage);
|
attrib *a = a_find(u->attribs, &at_familiarmage);
|
||||||
|
@ -2182,7 +2172,7 @@ static int sm_familiar(const unit * u, const region * r, skill_t sk, int value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void set_familiar(unit * mage, unit * familiar)
|
void set_familiar(unit * mage, unit * familiar)
|
||||||
{
|
{
|
||||||
/* if the skill modifier for the mage does not yet exist, add it */
|
/* if the skill modifier for the mage does not yet exist, add it */
|
||||||
attrib *a = a_find(mage->attribs, &at_skillmod);
|
attrib *a = a_find(mage->attribs, &at_skillmod);
|
||||||
|
@ -2384,7 +2374,6 @@ static int read_clone(attrib * a, void *owner, struct gamedata *data)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* mages */
|
/* mages */
|
||||||
|
|
||||||
static int resolve_mage(variant data, void *addr)
|
static int resolve_mage(variant data, void *addr)
|
||||||
{
|
{
|
||||||
unit *mage;
|
unit *mage;
|
||||||
|
|
28
src/magic.h
28
src/magic.h
|
@ -38,6 +38,10 @@ extern "C" {
|
||||||
#define IRONGOLEM_CRUMBLE 15 /* monatlich Chance zu zerfallen */
|
#define IRONGOLEM_CRUMBLE 15 /* monatlich Chance zu zerfallen */
|
||||||
#define STONEGOLEM_CRUMBLE 10 /* monatlich Chance zu zerfallen */
|
#define STONEGOLEM_CRUMBLE 10 /* monatlich Chance zu zerfallen */
|
||||||
|
|
||||||
|
extern const char *magic_school[MAXMAGIETYP];
|
||||||
|
extern struct attrib_type at_familiar;
|
||||||
|
extern struct attrib_type at_familiarmage;
|
||||||
|
|
||||||
/* ------------------------------------------------------------- */
|
/* ------------------------------------------------------------- */
|
||||||
/* Spruchparameter
|
/* Spruchparameter
|
||||||
* Wir suchen beim Parsen des Befehls erstmal nach lokalen Objekten,
|
* Wir suchen beim Parsen des Befehls erstmal nach lokalen Objekten,
|
||||||
|
@ -82,11 +86,6 @@ extern "C" {
|
||||||
#define TARGET_RESISTS (1<<0)
|
#define TARGET_RESISTS (1<<0)
|
||||||
#define TARGET_NOTFOUND (1<<1)
|
#define TARGET_NOTFOUND (1<<1)
|
||||||
|
|
||||||
/* ------------------------------------------------------------- */
|
|
||||||
/* Magierichtungen */
|
|
||||||
|
|
||||||
extern const char *magic_school[MAXMAGIETYP];
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------- */
|
/* ------------------------------------------------------------- */
|
||||||
/* Magier:
|
/* Magier:
|
||||||
* - Magierichtung
|
* - Magierichtung
|
||||||
|
@ -324,16 +323,15 @@ extern "C" {
|
||||||
|
|
||||||
/* Sprüche in der struct region */
|
/* Sprüche in der struct region */
|
||||||
/* (sind in curse) */
|
/* (sind in curse) */
|
||||||
extern struct unit *get_familiar(const struct unit *u);
|
void set_familiar(struct unit * mage, struct unit * familiar);
|
||||||
extern struct unit *get_familiar_mage(const struct unit *u);
|
struct unit *get_familiar(const struct unit *u);
|
||||||
extern struct unit *get_clone(const struct unit *u);
|
struct unit *get_familiar_mage(const struct unit *u);
|
||||||
extern struct unit *get_clone_mage(const struct unit *u);
|
struct unit *get_clone(const struct unit *u);
|
||||||
extern struct attrib_type at_familiar;
|
struct unit *get_clone_mage(const struct unit *u);
|
||||||
extern struct attrib_type at_familiarmage;
|
void remove_familiar(struct unit *mage);
|
||||||
extern void remove_familiar(struct unit *mage);
|
bool create_newfamiliar(struct unit *mage, struct unit *familiar);
|
||||||
extern bool create_newfamiliar(struct unit *mage, struct unit *familiar);
|
void create_newclone(struct unit *mage, struct unit *familiar);
|
||||||
extern void create_newclone(struct unit *mage, struct unit *familiar);
|
struct unit *has_clone(struct unit *mage);
|
||||||
extern struct unit *has_clone(struct unit *mage);
|
|
||||||
|
|
||||||
const char *spell_info(const struct spell *sp,
|
const char *spell_info(const struct spell *sp,
|
||||||
const struct locale *lang);
|
const struct locale *lang);
|
||||||
|
|
|
@ -27,11 +27,12 @@ static void test_resources(CuTest *tc) {
|
||||||
rtype = rt_get_or_create("stone");
|
rtype = rt_get_or_create("stone");
|
||||||
CuAssertPtrEquals(tc, (void *)rtype, (void *)rt_find("stone"));
|
CuAssertPtrEquals(tc, (void *)rtype, (void *)rt_find("stone"));
|
||||||
CuAssertPtrEquals(tc, (void *)rtype, (void *)get_resourcetype(R_STONE));
|
CuAssertPtrEquals(tc, (void *)rtype, (void *)get_resourcetype(R_STONE));
|
||||||
test_cleanup();
|
free_resources();
|
||||||
CuAssertPtrEquals(tc, 0, rt_find("stone"));
|
CuAssertPtrEquals(tc, 0, rt_find("stone"));
|
||||||
CuAssertPtrEquals(tc, 0, rt_find("peasant"));
|
CuAssertPtrEquals(tc, 0, rt_find("peasant"));
|
||||||
rtype = rt_get_or_create("stone");
|
rtype = rt_get_or_create("stone");
|
||||||
CuAssertPtrEquals(tc, (void *)rtype, (void *)get_resourcetype(R_STONE));
|
CuAssertPtrEquals(tc, (void *)rtype, (void *)get_resourcetype(R_STONE));
|
||||||
|
test_cleanup();
|
||||||
}
|
}
|
||||||
|
|
||||||
CuSuite *get_tests_suite(void)
|
CuSuite *get_tests_suite(void)
|
||||||
|
|
|
@ -36,10 +36,11 @@
|
||||||
#define NOLANDITEM_VERSION 356 /* land_region has no items */
|
#define NOLANDITEM_VERSION 356 /* land_region has no items */
|
||||||
#define NORCSPELL_VERSION 357 /* data contains no RC_SPELL units */
|
#define NORCSPELL_VERSION 357 /* data contains no RC_SPELL units */
|
||||||
#define SORTKEYS_VERSION 358 /* at_keys is sorted */
|
#define SORTKEYS_VERSION 358 /* at_keys is sorted */
|
||||||
|
#define FAMILIAR_FIX_VERSION 359 /* at_keys is sorted */
|
||||||
/* unfinished: */
|
/* unfinished: */
|
||||||
#define CRYPT_VERSION 400 /* passwords are encrypted */
|
#define CRYPT_VERSION 400 /* passwords are encrypted */
|
||||||
|
|
||||||
#define RELEASE_VERSION SORTKEYS_VERSION /* current datafile */
|
#define RELEASE_VERSION FAMILIAR_FIX_VERSION /* current datafile */
|
||||||
#define MIN_VERSION INTPAK_VERSION /* minimal datafile we support */
|
#define MIN_VERSION INTPAK_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 */
|
#define MAX_VERSION RELEASE_VERSION /* change this if we can need to read the future datafile, and we can do so */
|
||||||
|
|
||||||
|
|
|
@ -9,6 +9,7 @@ static void test_mt_new(CuTest *tc)
|
||||||
message_type *mt;
|
message_type *mt;
|
||||||
test_setup();
|
test_setup();
|
||||||
mt = mt_new_va("test", "name:string", "number:int", NULL);
|
mt = mt_new_va("test", "name:string", "number:int", NULL);
|
||||||
|
mt_register(mt);
|
||||||
CuAssertPtrNotNull(tc, mt);
|
CuAssertPtrNotNull(tc, mt);
|
||||||
CuAssertStrEquals(tc, "test", mt->name);
|
CuAssertStrEquals(tc, "test", mt->name);
|
||||||
CuAssertIntEquals(tc, 2, mt->nparameters);
|
CuAssertIntEquals(tc, 2, mt->nparameters);
|
||||||
|
|
Loading…
Reference in New Issue