diff --git a/src/items.c b/src/items.c index 41c913f1f..e585e14d6 100644 --- a/src/items.c +++ b/src/items.c @@ -292,15 +292,8 @@ struct order *ord) rcfailure = rc_find("toad"); } if (rcfailure) { - trigger *trestore = trigger_changerace(u, u_race(u), u->irace); - if (trestore) { - int duration = 2 + rng_int() % 8; - - add_trigger(&u->attribs, "timer", trigger_timeout(duration, - trestore)); - u->irace = NULL; - u_setrace(u, rcfailure); - } + int duration = 2 + rng_int() % 8; + change_race(u, duration, rcfailure, NULL); } } use_pooled(u, itype->rtype, GET_SLACK | GET_RESERVE | GET_POOLED_SLACK, diff --git a/src/magic.c b/src/magic.c index 5642db417..4e0582a3c 100644 --- a/src/magic.c +++ b/src/magic.c @@ -1273,10 +1273,12 @@ static void do_fumble(castorder * co) unit *caster = co_get_caster(co); const spell *sp = co->sp; int level = co->level; - int duration; double effect; static int rc_cache; + static const race *rc_toad = NULL; fumble_f fun; + trigger *trestore; + int duration; ADDMSG(&caster->faction->msgs, msg_message("patzer", "unit region spell", caster, r, sp)); @@ -1293,32 +1295,26 @@ static void do_fumble(castorder * co) break; case 1: /* toad */ - { - /* one or two things will happen: the toad changes her race back, + /* one or two things will happen: the toad changes its race back, * and may or may not get toadslime. * The list of things to happen are attached to a timeout - * trigger and that's added to the triggerlit of the mage gone toad. + * trigger and that's added to the triggerlist of the mage gone toad. */ - static const race *rc_toad; - trigger *trestore = trigger_changerace(mage, u_race(mage), mage->irace); - if (chance(0.7)) { - const resource_type *rtype = rt_find("toadslime"); - if (rtype) { - t_add(&trestore, trigger_giveitem(mage, rtype->itype, 1)); - } - } - duration = rng_int() % level / 2; - if (duration < 2) duration = 2; - add_trigger(&mage->attribs, "timer", trigger_timeout(duration, trestore)); if (rc_changed(&rc_cache)) { rc_toad = get_race(RC_TOAD); } - u_setrace(mage, rc_toad); - mage->irace = NULL; - ADDMSG(&r->msgs, msg_message("patzer6", "unit region spell", mage, r, sp)); + duration = rng_int() % level / 2; + trestore = change_race(mage, duration, rc_toad, NULL); + if (trestore) { + if (chance(0.7)) { + const resource_type *rtype = rt_find("toadslime"); + if (rtype) { + t_add(&trestore, trigger_giveitem(mage, rtype->itype, 1)); + } + } + ADDMSG(&r->msgs, msg_message("patzer6", "unit region spell", mage, r, sp)); + } break; - } - /* fall-through is intentional! */ case 2: /* temporary skill loss */ @@ -1330,6 +1326,7 @@ static void do_fumble(castorder * co) c->data.i = SK_MAGIC; ADDMSG(&caster->faction->msgs, msg_message("patzer2", "unit region", caster, r)); break; + case 3: case 4: /* Spruch schlaegt fehl, alle Magiepunkte weg */ diff --git a/src/spells.c b/src/spells.c index e5f1a3b53..51c150bf7 100644 --- a/src/spells.c +++ b/src/spells.c @@ -4551,13 +4551,13 @@ int sp_illusionary_shapeshift(castorder * co) return 0; } - add_trigger(&u->attribs, "timer", trigger_timeout((int)power + 3, - trigger_changerace(u, NULL, irace))); - u->irace = rc; - + if (NULL == change_race(u, 3 + (int)power, NULL, irace)) { + ADDMSG(&mage->faction->msgs, msg_feedback(mage, co->order, + "sp_shapeshift_fail", "target race", u, rc)); + return 0; + } ADDMSG(&mage->faction->msgs, msg_message("shapeshift_effect", "mage target race", mage, u, rc)); - return cast_level; } diff --git a/src/spells.test.c b/src/spells.test.c index af107cee0..aa5fd78d4 100644 --- a/src/spells.test.c +++ b/src/spells.test.c @@ -5,6 +5,7 @@ #include #include +#include #include #include #include @@ -19,6 +20,9 @@ #include +#include +#include + #include #include @@ -280,6 +284,38 @@ static void test_watch_region(CuTest *tc) { test_teardown(); } +static void test_change_race(CuTest *tc) { + unit *u; + race *rctoad; + trigger **tp, *tr; + timeout_data *td; + changerace_data *crd; + + test_setup(); + rctoad = test_create_race("toad"); + u = test_create_unit(test_create_faction(), test_create_plain(0, 0)); + CuAssertPtrEquals(tc, (void *)u->faction->race, (void *)u->_race); + CuAssertPtrNotNull(tc, change_race(u, 2, rctoad, NULL)); + CuAssertPtrEquals(tc, (void *)rctoad, (void *)u->_race); + CuAssertPtrEquals(tc, NULL, (void *)u->irace); + CuAssertPtrNotNull(tc, u->attribs); + tp = get_triggers(u->attribs, "timer"); + CuAssertPtrNotNull(tc, tp); + CuAssertPtrNotNull(tc, tr = *tp); + CuAssertPtrEquals(tc, &tt_timeout, tr->type); + td = (timeout_data *)tr->data.v; + CuAssertPtrNotNull(tc, td); + CuAssertIntEquals(tc, 2, td->timer); + CuAssertPtrNotNull(tc, td->triggers); + CuAssertPtrEquals(tc, &tt_changerace, td->triggers->type); + CuAssertPtrEquals(tc, NULL, td->triggers->next); + crd = (changerace_data *)td->triggers->data.v; + CuAssertPtrEquals(tc, (void *)u->faction->race, (void *)crd->race); + CuAssertPtrEquals(tc, NULL, (void *)crd->irace); + + test_teardown(); +} + CuSuite *get_spells_suite(void) { CuSuite *suite = CuSuiteNew(); @@ -289,5 +325,6 @@ CuSuite *get_spells_suite(void) SUITE_ADD_TEST(suite, test_good_dreams); SUITE_ADD_TEST(suite, test_bad_dreams); SUITE_ADD_TEST(suite, test_dreams); + SUITE_ADD_TEST(suite, test_change_race); return suite; } diff --git a/src/triggers/changerace.c b/src/triggers/changerace.c index 173b20d77..9011b1660 100644 --- a/src/triggers/changerace.c +++ b/src/triggers/changerace.c @@ -1,5 +1,6 @@ #include #include "changerace.h" +#include "timeout.h" /* kernel includes */ #include @@ -26,12 +27,6 @@ ** restore a mage that was turned into a toad **/ -typedef struct changerace_data { - struct unit *u; - const struct race *race; - const struct race *irace; -} changerace_data; - static void changerace_init(trigger * t) { t->data.v = calloc(1, sizeof(changerace_data)); @@ -97,3 +92,13 @@ trigger *trigger_changerace(unit * u, const race * prace, const race * irace) td->irace = irace; return t; } + +extern struct trigger *change_race(struct unit *u, int duration, const struct race *urace, const struct race *irace) { + trigger *trestore = trigger_changerace(u, u_race(u), u->irace); + if (trestore) { + add_trigger(&u->attribs, "timer", trigger_timeout(duration, trestore)); + u->irace = irace; + u_setrace(u, urace); + } + return trestore; +} diff --git a/src/triggers/changerace.h b/src/triggers/changerace.h index 950f04784..a3ca744ca 100644 --- a/src/triggers/changerace.h +++ b/src/triggers/changerace.h @@ -10,11 +10,15 @@ extern "C" { struct unit; struct race; + typedef struct changerace_data { + struct unit *u; + const struct race *race; + const struct race *irace; + } changerace_data; + extern struct trigger_type tt_changerace; - extern struct trigger *trigger_changerace(struct unit *u, - const struct race *urace, const struct race *irace); - + extern struct trigger *change_race(struct unit *u, int duration, const struct race *urace, const struct race *irace); #ifdef __cplusplus } #endif diff --git a/src/triggers/timeout.c b/src/triggers/timeout.c index fa4cbc46b..f36bc8c31 100644 --- a/src/triggers/timeout.c +++ b/src/triggers/timeout.c @@ -16,12 +16,6 @@ ** timeout **/ -typedef struct timeout_data { - trigger *triggers; - int timer; - variant trigger_data; -} timeout_data; - static void timeout_init(trigger * t) { t->data.v = calloc(1, sizeof(timeout_data)); diff --git a/src/triggers/timeout.h b/src/triggers/timeout.h index dc8c22d92..498b52192 100644 --- a/src/triggers/timeout.h +++ b/src/triggers/timeout.h @@ -7,6 +7,11 @@ extern "C" { struct trigger_type; struct trigger; + typedef struct timeout_data { + struct trigger *triggers; + int timer; + } timeout_data; + extern struct trigger_type tt_timeout; extern struct trigger *trigger_timeout(int time, struct trigger *callbacks);