diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index c2551cc45..037898ed9 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -208,6 +208,7 @@ set(TESTS_SRC spy.test.c study.test.c upkeep.test.c + spells/flyingship.test.c spells/magicresistance.test.c ${ATTRIBUTES_TESTS} ${UTIL_TESTS} diff --git a/src/bind_monsters.c b/src/bind_monsters.c index a106ec638..6589e002a 100644 --- a/src/bind_monsters.c +++ b/src/bind_monsters.c @@ -9,6 +9,8 @@ #include #include +#include + #include #include diff --git a/src/move.c b/src/move.c index 951fd33f3..13f0e3f0e 100644 --- a/src/move.c +++ b/src/move.c @@ -48,6 +48,8 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include #include +#include + #include "direction.h" #include "calendar.h" #include "skill.h" @@ -674,15 +676,6 @@ int check_ship_allowed(struct ship *sh, const region * r) return SA_NO_COAST; } -static bool flying_ship(const ship * sh) -{ - if (sh->type->flags & SFL_FLY) - return true; - if (sh->flags & SF_FLYING) - return true; - return false; -} - static void set_coast(ship * sh, region * r, region * rnext) { if (sh->type->flags & SFL_NOCOAST) { diff --git a/src/spells.c b/src/spells.c index 9498a5a1f..48b86a9b4 100644 --- a/src/spells.c +++ b/src/spells.c @@ -30,6 +30,7 @@ #include #include #include +#include /* kernel includes */ #include @@ -5994,72 +5995,6 @@ int sp_movecastle(castorder * co) return cast_level; } -/* ------------------------------------------------------------- */ -/* Name: Luftschiff - * Stufe: 6 - * - * Wirkung: - * Laeßt ein Schiff eine Runde lang fliegen. Wirkt nur auf Boote und - * Langboote. - * Kombinierbar mit "Guenstige Winde", aber nicht mit "Sturmwind". - * - * Flag: - * (ONSHIPCAST | SHIPSPELL | TESTRESISTANCE) - */ -int sp_flying_ship(castorder * co) -{ - ship *sh; - unit *u; - region *r = co_get_region(co); - unit *mage = co->magician.u; - int cast_level = co->level; - double power = co->force; - spellparameter *pa = co->par; - message *m = NULL; - int cno; - - /* wenn kein Ziel gefunden, Zauber abbrechen */ - if (pa->param[0]->flag == TARGET_NOTFOUND) - return 0; - sh = pa->param[0]->data.sh; - if (sh->type->construction->maxsize > 50) { - ADDMSG(&mage->faction->msgs, msg_feedback(mage, co->order, - "error_flying_ship_too_big", "ship", sh)); - return 0; - } - - /* Duration = 1, nur diese Runde */ - - cno = levitate_ship(sh, mage, power, 1); - if (cno == 0) { - if (is_cursed(sh->attribs, C_SHIP_FLYING, 0)) { - /* Auf dem Schiff befindet liegt bereits so ein Zauber. */ - cmistake(mage, co->order, 211, MSG_MAGIC); - } - else if (is_cursed(sh->attribs, C_SHIP_SPEEDUP, 0)) { - /* Es ist zu gefaehrlich, ein sturmgepeitschtes Schiff fliegen zu lassen. */ - cmistake(mage, co->order, 210, MSG_MAGIC); - } - return 0; - } - sh->coast = NODIRECTION; - - /* melden, 1x pro Partei */ - for (u = r->units; u; u = u->next) - freset(u->faction, FFL_SELECT); - for (u = r->units; u; u = u->next) { - /* das sehen natuerlich auch die Leute an Land */ - if (!fval(u->faction, FFL_SELECT)) { - fset(u->faction, FFL_SELECT); - if (!m) - m = msg_message("flying_ship_result", "mage ship", mage, sh); - add_message(&u->faction->msgs, m); - } - } - if (m) - msg_release(m); - return cast_level; -} /* ------------------------------------------------------------- */ /* Name: Stehle Aura @@ -6796,4 +6731,6 @@ void register_spells(void) register_shipcurse(); register_buildingcurse(); register_magicresistance(); + + register_flyingship(); } diff --git a/src/spells.test.c b/src/spells.test.c index 471a043de..58886d991 100644 --- a/src/spells.test.c +++ b/src/spells.test.c @@ -19,16 +19,6 @@ #include #include - -static void test_create_castorder(castorder *co, unit *u, int level, float force, int range) { - struct locale * lang; - order *ord; - - lang = get_or_create_locale("en"); - create_castorder(co, u, NULL, NULL, u->region, level, force, range, ord = create_order(K_CAST, lang, ""), NULL); - free_order(ord); -} - static void test_good_dreams(CuTest *tc) { struct region *r; struct faction *f1, *f2; @@ -44,7 +34,7 @@ static void test_good_dreams(CuTest *tc) { u1 = test_create_unit(f1, r); u2 = test_create_unit(f2, r); - test_create_castorder(&co, u1, 10, 10., 0); + test_create_castorder(&co, u1, 10, 10., 0, NULL); level = sp_gooddreams(&co); CuAssertIntEquals(tc, 10, level); @@ -73,7 +63,7 @@ static void test_dreams(CuTest *tc) { u1 = test_create_unit(f1, r); u2 = test_create_unit(f2, r); - test_create_castorder(&co, u1, 10, 10., 0); + test_create_castorder(&co, u1, 10, 10., 0, NULL); sp_gooddreams(&co); sp_baddreams(&co); @@ -100,7 +90,7 @@ static void test_bad_dreams(CuTest *tc) { u1 = test_create_unit(f1, r); u2 = test_create_unit(f2, r); - test_create_castorder(&co, u1, 10, 10., 0); + test_create_castorder(&co, u1, 10, 10., 0, NULL); level = sp_baddreams(&co); CuAssertIntEquals(tc, 10, level); diff --git a/src/spells/CMakeLists.txt b/src/spells/CMakeLists.txt index 335189c21..6219708d4 100644 --- a/src/spells/CMakeLists.txt +++ b/src/spells/CMakeLists.txt @@ -8,6 +8,7 @@ regioncurse.c shipcurse.c unitcurse.c magicresistance.c +flyingship.c ) FOREACH(_FILE ${_FILES}) LIST(APPEND _SOURCES ${PROJECT_NAME}/${_FILE}) diff --git a/src/spells/flyingship.c b/src/spells/flyingship.c new file mode 100644 index 000000000..7751451ed --- /dev/null +++ b/src/spells/flyingship.c @@ -0,0 +1,173 @@ +#include +#include +#include +#include "flyingship.h" + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +#include + +/* libc includes */ +#include + + +/* ------------------------------------------------------------- */ +/* Name: Luftschiff +* Stufe: 6 +* +* Wirkung: +* Laeßt ein Schiff eine Runde lang fliegen. Wirkt nur auf Boote +* bis Kapazität 50. +* Kombinierbar mit "Guenstige Winde", aber nicht mit "Sturmwind". +* +* Flag: +* (ONSHIPCAST | SHIPSPELL | TESTRESISTANCE) +*/ +int sp_flying_ship(castorder * co) +{ + ship *sh; + unit *u; + region *r = co_get_region(co); + unit *mage = co->magician.u; + int cast_level = co->level; + double power = co->force; + spellparameter *pa = co->par; + message *m = NULL; + int cno; + + /* wenn kein Ziel gefunden, Zauber abbrechen */ + if (pa->param[0]->flag == TARGET_NOTFOUND) + return 0; + sh = pa->param[0]->data.sh; + if (sh->type->construction->maxsize > 50) { + ADDMSG(&mage->faction->msgs, msg_feedback(mage, co->order, + "error_flying_ship_too_big", "ship", sh)); + return 0; + } + + /* Duration = 1, nur diese Runde */ + + cno = levitate_ship(sh, mage, power, 1); + if (cno == 0) { + if (is_cursed(sh->attribs, C_SHIP_FLYING, 0)) { + /* Auf dem Schiff befindet liegt bereits so ein Zauber. */ + cmistake(mage, co->order, 211, MSG_MAGIC); + } + else if (is_cursed(sh->attribs, C_SHIP_SPEEDUP, 0)) { + /* Es ist zu gefaehrlich, ein sturmgepeitschtes Schiff fliegen zu lassen. */ + cmistake(mage, co->order, 210, MSG_MAGIC); + } + return 0; + } + sh->coast = NODIRECTION; + + /* melden, 1x pro Partei */ + for (u = r->units; u; u = u->next) + freset(u->faction, FFL_SELECT); + for (u = r->units; u; u = u->next) { + /* das sehen natuerlich auch die Leute an Land */ + if (!fval(u->faction, FFL_SELECT)) { + fset(u->faction, FFL_SELECT); + if (!m) + m = msg_message("flying_ship_result", "mage ship", mage, sh); + add_message(&u->faction->msgs, m); + } + } + if (m) + msg_release(m); + return cast_level; +} + +static int flyingship_read(storage * store, curse * c, void *target) +{ + ship *sh = (ship *)target; + c->data.v = sh; + if (global.data_version < FOSS_VERSION) { + sh->flags |= SF_FLYING; + return 0; + } + assert(sh->flags & SF_FLYING); + return 0; +} + +static int flyingship_write(storage * store, const curse * c, + const void *target) +{ + const ship *sh = (const ship *)target; + assert(sh->flags & SF_FLYING); + return 0; +} + +static int flyingship_age(curse * c) +{ + ship *sh = (ship *)c->data.v; + if (sh && c->duration == 1) { + freset(sh, SF_FLYING); + return 1; + } + return 0; +} + +static struct curse_type ct_flyingship = { "flyingship", +CURSETYP_NORM, 0, NO_MERGE, cinfo_ship, NULL, flyingship_read, +flyingship_write, NULL, flyingship_age +}; + +void register_flyingship(void) +{ + ct_register(&ct_flyingship); +} + +bool flying_ship(const ship * sh) +{ + if (sh->type->flags & SFL_FLY) + return true; + if (sh->flags & SF_FLYING) + return true; + return false; +} + +static curse *shipcurse_flyingship(ship * sh, unit * mage, double power, int duration) +{ + static const curse_type *ct_flyingship = NULL; + if (!ct_flyingship) { + ct_flyingship = ct_find("flyingship"); + assert(ct_flyingship); + } + if (curse_active(get_curse(sh->attribs, ct_flyingship))) { + return NULL; + } + else if (is_cursed(sh->attribs, C_SHIP_SPEEDUP, 0)) { + return NULL; + } + else { + /* mit C_SHIP_NODRIFT haben wir kein Problem */ + curse *c = + create_curse(mage, &sh->attribs, ct_flyingship, power, duration, 0.0, 0); + c->data.v = sh; + if (c && c->duration > 0) { + sh->flags |= SF_FLYING; + } + return c; + } +} + +int levitate_ship(ship * sh, unit * mage, double power, int duration) +{ + curse *c = shipcurse_flyingship(sh, mage, power, duration); + if (c) { + return c->no; + } + return 0; +} + diff --git a/src/spells/flyingship.h b/src/spells/flyingship.h new file mode 100644 index 000000000..087357b9e --- /dev/null +++ b/src/spells/flyingship.h @@ -0,0 +1,25 @@ +#pragma once + +#ifndef FLYINGSHIP_H +#define FLYINGSHIP_H + +#ifdef __cplusplus +extern "C" { +#endif + + struct castorder; + struct ship; + struct unit; + + int sp_flying_ship(struct castorder * co); + + void register_flyingship(void); + bool flying_ship(const struct ship * sh); + int levitate_ship(struct ship *sh, struct unit *mage, double power, + int duration); + +#ifdef __cplusplus +} +#endif + +#endif \ No newline at end of file diff --git a/src/spells/flyingship.test.c b/src/spells/flyingship.test.c new file mode 100644 index 000000000..00199e971 --- /dev/null +++ b/src/spells/flyingship.test.c @@ -0,0 +1,69 @@ +#include +#include "flyingship.h" + +#include +#include +#include +#include +#include + +#include + +#include +#include +#include + +static void test_flyingship(CuTest * tc) +{ + castorder co; + spellparameter par; + spllprm par_data; + spllprm *par_data_ptr = &par_data; + + region *r; + faction *f; + unit *u; + ship_type *shipType1, *shipType2; + ship *sh1, *sh2; + + par.param = &par_data_ptr; + par_data.typ = SPP_SHIP; + + test_cleanup(); + test_create_world(); + + r = findregion(0, 0); + f = test_create_faction(test_create_race("human")); + u = test_create_unit(f, r); + + shipType1 = test_create_shiptype("boot"); + shipType1->construction->maxsize = 50; + + shipType2 = test_create_shiptype("schiff"); + shipType2->construction->maxsize = 51; + + sh1 = test_create_ship(r, shipType1); + par_data.data.sh = sh1; + test_create_castorder(&co, u, 10, 10.0, 0, &par); + + CuAssertTrue(tc, !flying_ship(sh1)); + CuAssertIntEquals(tc, 10, sp_flying_ship(&co)); + CuAssertTrue(tc, flying_ship(sh1)); + + sh2 = test_create_ship(r, shipType2); + par_data.data.sh = sh2; + test_create_castorder(&co, u, 10, 10.0, 0, &par); + + CuAssertTrue(tc, !flying_ship(sh2)); + CuAssertIntEquals(tc, 0, sp_flying_ship(&co)); + CuAssertTrue(tc, !flying_ship(sh2)); +} + +CuSuite *get_flyingship_suite(void) +{ + CuSuite *suite = CuSuiteNew(); + + SUITE_ADD_TEST(suite, test_flyingship); + + return suite; +} diff --git a/src/spells/shipcurse.c b/src/spells/shipcurse.c index 4b0dd9b30..75e07a4ca 100644 --- a/src/spells/shipcurse.c +++ b/src/spells/shipcurse.c @@ -78,41 +78,6 @@ static struct curse_type ct_stormwind = { "stormwind", CURSETYP_NORM, 0, NO_MERGE, cinfo_ship }; -static int flyingship_read(storage * store, curse * c, void *target) -{ - ship *sh = (ship *)target; - c->data.v = sh; - if (global.data_version < FOSS_VERSION) { - sh->flags |= SF_FLYING; - return 0; - } - assert(sh->flags & SF_FLYING); - return 0; -} - -static int flyingship_write(storage * store, const curse * c, - const void *target) -{ - const ship *sh = (const ship *)target; - assert(sh->flags & SF_FLYING); - return 0; -} - -static int flyingship_age(curse * c) -{ - ship *sh = (ship *)c->data.v; - if (sh && c->duration == 1) { - freset(sh, SF_FLYING); - return 1; - } - return 0; -} - -static struct curse_type ct_flyingship = { "flyingship", -CURSETYP_NORM, 0, NO_MERGE, cinfo_ship, NULL, flyingship_read, -flyingship_write, NULL, flyingship_age -}; - static struct curse_type ct_nodrift = { "nodrift", CURSETYP_NORM, 0, (M_DURATION | M_VIGOUR), cinfo_shipnodrift }; @@ -121,46 +86,9 @@ static struct curse_type ct_shipspeedup = { "shipspeedup", CURSETYP_NORM, 0, 0, cinfo_ship }; -curse *shipcurse_flyingship(ship * sh, unit * mage, double power, int duration) -{ - static const curse_type *ct_flyingship = NULL; - if (!ct_flyingship) { - ct_flyingship = ct_find("flyingship"); - assert(ct_flyingship); - } - if (curse_active(get_curse(sh->attribs, ct_flyingship))) { - return NULL; - } - else if (is_cursed(sh->attribs, C_SHIP_SPEEDUP, 0)) { - return NULL; - } - else { - /* mit C_SHIP_NODRIFT haben wir kein Problem */ - curse *c = - create_curse(mage, &sh->attribs, ct_flyingship, power, duration, 0.0, 0); - if (c) { - c->data.v = sh; - if (c->duration > 0) { - sh->flags |= SF_FLYING; - } - } - return c; - } -} - -int levitate_ship(ship * sh, unit * mage, double power, int duration) -{ - curse *c = shipcurse_flyingship(sh, mage, power, duration); - if (c) { - return c->no; - } - return 0; -} - void register_shipcurse(void) { ct_register(&ct_stormwind); - ct_register(&ct_flyingship); ct_register(&ct_nodrift); ct_register(&ct_shipspeedup); } diff --git a/src/spells/shipcurse.h b/src/spells/shipcurse.h index 676cd7344..9ac57b142 100644 --- a/src/spells/shipcurse.h +++ b/src/spells/shipcurse.h @@ -19,19 +19,12 @@ extern "C" { #endif - struct locale; struct message; - struct ship; - struct unit; struct curse; struct message *cinfo_ship(const void *obj, objtype_t typ, const struct curse *c, int self); void register_shipcurse(void); - struct curse *shipcurse_flyingship(struct ship *sh, struct unit *mage, - double power, int duration); - int levitate_ship(struct ship *sh, struct unit *mage, double power, - int duration); #ifdef __cplusplus } diff --git a/src/test_eressea.c b/src/test_eressea.c index aad65c539..2a0bf04eb 100644 --- a/src/test_eressea.c +++ b/src/test_eressea.c @@ -114,6 +114,7 @@ int RunAllTests(int argc, char *argv[]) ADD_SUITE(donations); ADD_SUITE(travelthru); ADD_SUITE(economy); + ADD_SUITE(flyingship); ADD_SUITE(give); ADD_SUITE(laws); ADD_SUITE(market); diff --git a/src/tests.c b/src/tests.c index 347418ce5..4e0206189 100644 --- a/src/tests.c +++ b/src/tests.c @@ -179,6 +179,15 @@ item_type * test_create_itemtype(const char * name) { return itype; } +void test_create_castorder(castorder *co, unit *u, int level, float force, int range, spellparameter *par) { + struct locale * lang; + order *ord; + + lang = get_or_create_locale("en"); + create_castorder(co, u, NULL, NULL, u->region, level, force, range, ord = create_order(K_CAST, lang, ""), par); + free_order(ord); +} + void test_translate_param(const struct locale *lang, param_t param, const char *text) { struct critbit_tree **cb; diff --git a/src/tests.h b/src/tests.h index a458e4eab..ba33dd5a7 100644 --- a/src/tests.h +++ b/src/tests.h @@ -20,6 +20,8 @@ extern "C" { struct building_type; struct ship_type; struct terrain_type; + struct castorder; + struct spellparameter; struct CuTest; @@ -37,6 +39,7 @@ extern "C" { struct item_type * test_create_itemtype(const char * name); struct ship_type *test_create_shiptype(const char * name); struct building_type *test_create_buildingtype(const char *name); + void test_create_castorder(struct castorder *co, struct unit *u, int level, float force, int range, struct spellparameter *par); int RunAllTests(void); void test_translate_param(const struct locale *lang, param_t param, const char *text);