diff --git a/src/economy.c b/src/economy.c index ae5be2c77..dc7e6148b 100644 --- a/src/economy.c +++ b/src/economy.c @@ -426,6 +426,59 @@ static int recruit_cost(const faction * f, const race * rc) return -1; } +message *can_recruit(unit *u, const race *rc, order *ord, int now) +{ + region *r = u->region; + + /* this is a very special case because the recruiting unit may be empty + * at this point and we have to look at the creating unit instead. This + * is done in cansee, which is called indirectly by is_guarded(). */ + if (is_guarded(r, u)) { + return msg_error(u, ord, 70); + } + + if (rc == get_race(RC_INSECT)) { + gamedate date; + get_gamedate(now, &date); + if (date.season == SEASON_WINTER && r->terrain != newterrain(T_DESERT)) { + bool usepotion = false; + unit *u2; + + for (u2 = r->units; u2; u2 = u2->next) { + if (fval(u2, UFL_WARMTH)) { + usepotion = true; + break; + } + } + if (!usepotion) { + return msg_error(u, ord, 98); + } + } + /* in Gletschern, Eisbergen gar nicht rekrutieren */ + if (r_insectstalled(r)) { + return msg_error(u, ord, 97); + } + } + if (is_cursed(r->attribs, &ct_riotzone)) { + /* Die Region befindet sich in Aufruhr */ + return msg_error(u, ord, 237); + } + + if (rc && !playerrace(rc)) { + return msg_error(u, ord, 139); + } + + if (fval(u, UFL_HERO)) { + return msg_feedback(u, ord, "error_herorecruit", ""); + } + if (has_skill(u, SK_MAGIC)) { + /* error158;de;{unit} in {region}: '{command}' - Magier arbeiten + * grunds�tzlich nur alleine! */ + return msg_error(u, ord, 158); + } + return NULL; +} + static void recruit(unit * u, struct order *ord, econ_request ** recruitorders) { region *r = u->region; @@ -434,6 +487,7 @@ static void recruit(unit * u, struct order *ord, econ_request ** recruitorders) const faction *f = u->faction; const struct race *rc = u_race(u); int n; + message *msg; init_order_depr(ord); n = getint(); @@ -456,6 +510,7 @@ static void recruit(unit * u, struct order *ord, econ_request ** recruitorders) } } } + if (recruitcost < 0) { rc = u_race(u); recruitcost = recruit_cost(f, rc); @@ -463,95 +518,46 @@ static void recruit(unit * u, struct order *ord, econ_request ** recruitorders) recruitcost = INT_MAX; } } - assert(rc); - u_setrace(u, rc); - /* this is a very special case because the recruiting unit may be empty - * at this point and we have to look at the creating unit instead. This - * is done in cansee, which is called indirectly by is_guarded(). */ - if (is_guarded(r, u)) { - cmistake(u, ord, 70, MSG_EVENT); - return; - } - - if (rc == get_race(RC_INSECT)) { - gamedate date; - get_gamedate(turn, &date); - if (date.season == SEASON_WINTER && r->terrain != newterrain(T_DESERT)) { - bool usepotion = false; - unit *u2; - - for (u2 = r->units; u2; u2 = u2->next) - if (fval(u2, UFL_WARMTH)) { - usepotion = true; - break; - } - if (!usepotion) - { - cmistake(u, ord, 98, MSG_EVENT); - return; - } - } - /* in Gletschern, Eisbergen gar nicht rekrutieren */ - if (r_insectstalled(r)) { - cmistake(u, ord, 97, MSG_EVENT); - return; - } - } - if (is_cursed(r->attribs, &ct_riotzone)) { - /* Die Region befindet sich in Aufruhr */ - cmistake(u, ord, 237, MSG_EVENT); - return; - } - - if (recruitcost) { + if (recruitcost > 0) { + int pool; plane *pl = getplane(r); - if (pl && fval(pl, PFL_NORECRUITS)) { + + if (pl && (pl->flags & PFL_NORECRUITS)) { ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "error_pflnorecruit", "")); return; } - if (get_pooled(u, get_resourcetype(R_SILVER), GET_DEFAULT, - recruitcost) < recruitcost) { + pool = get_pooled(u, get_resourcetype(R_SILVER), GET_DEFAULT, recruitcost * n); + if (pool < recruitcost) { cmistake(u, ord, 142, MSG_EVENT); return; } + pool /= recruitcost; + if (n > pool) n = pool; } - if (!playerrace(rc)) { - cmistake(u, ord, 139, MSG_EVENT); - return; - } - - if (fval(u, UFL_HERO)) { - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "error_herorecruit", "")); - return; - } - if (has_skill(u, SK_MAGIC)) { - /* error158;de;{unit} in {region}: '{command}' - Magier arbeiten - * grunds�tzlich nur alleine! */ - cmistake(u, ord, 158, MSG_EVENT); - return; - } - if (has_skill(u, SK_ALCHEMY) - && count_skill(u->faction, SK_ALCHEMY) + n > - skill_limit(u->faction, SK_ALCHEMY)) { - cmistake(u, ord, 156, MSG_EVENT); - return; - } - if (recruitcost > 0) { - int pooled = - get_pooled(u, get_resourcetype(R_SILVER), GET_DEFAULT, recruitcost * n); - int pr = pooled / recruitcost; - if (n > pr) n = pr; - } - - u->wants = n; if (!n) { cmistake(u, ord, 142, MSG_EVENT); return; } + if (has_skill(u, SK_ALCHEMY)) { + if (count_skill(u->faction, SK_ALCHEMY) + n > skill_limit(u->faction, SK_ALCHEMY)) { + cmistake(u, ord, 156, MSG_EVENT); + return; + } + } + assert(rc); + msg = can_recruit(u, rc, ord, turn); + if (msg) { + add_message(&u->faction->msgs, msg); + msg_release(msg); + return; + } + + u_setrace(u, rc); + u->wants = n; o = (econ_request *)calloc(1, sizeof(econ_request)); o->qty = n; o->unit = u; diff --git a/src/economy.h b/src/economy.h index 67762b513..9456a4c93 100644 --- a/src/economy.h +++ b/src/economy.h @@ -44,6 +44,7 @@ extern "C" { #define MAXNEWBIES 5 struct unit; + struct race; struct region; struct faction; struct order; @@ -94,6 +95,7 @@ extern "C" { void steal_cmd(struct unit * u, struct order *ord, struct econ_request ** stealorders); void expandstealing(struct region * r, struct econ_request * stealorders); + struct message *can_recruit(struct unit *u, const struct race *rc, struct order *ord, int now); void add_recruits(struct unit * u, int number, int wanted); #ifdef __cplusplus diff --git a/src/economy.test.c b/src/economy.test.c index 91d462770..90a4bd260 100644 --- a/src/economy.test.c +++ b/src/economy.test.c @@ -480,6 +480,35 @@ static void test_recruit(CuTest *tc) { test_teardown(); } +static void test_recruit_insect(CuTest *tc) { + unit *u; + faction *f; + message * msg; + + test_setup(); + test_create_calendar(); + f = test_create_faction(test_create_race("insect")); + u = test_create_unit(f, test_create_region(0, 0, NULL)); + u->thisorder = create_order(K_RECRUIT, f->locale, "%d", 1); + + msg = can_recruit(u, f->race, u->thisorder, 1083); /* Autumn */ + CuAssertPtrEquals(tc, NULL, msg); + + msg = can_recruit(u, f->race, u->thisorder, 1084); /* Insects, Winter */ + CuAssertPtrNotNull(tc, msg); + msg_release(msg); + + u->flags |= UFL_WARMTH; + msg = can_recruit(u, f->race, u->thisorder, 1084); /* Insects, potion, Winter */ + CuAssertPtrEquals(tc, NULL, msg); + + u->flags = 0; + msg = can_recruit(u, NULL, u->thisorder, 1084); /* Other races, Winter */ + CuAssertPtrEquals(tc, NULL, msg); + + test_teardown(); +} + static void test_income(CuTest *tc) { race *rc; @@ -764,6 +793,7 @@ CuSuite *get_economy_suite(void) SUITE_ADD_TEST(suite, test_trade_insect); SUITE_ADD_TEST(suite, test_maintain_buildings); SUITE_ADD_TEST(suite, test_recruit); + SUITE_ADD_TEST(suite, test_recruit_insect); SUITE_ADD_TEST(suite, test_loot); SUITE_ADD_TEST(suite, test_expand_production); return suite; diff --git a/src/reports.test.c b/src/reports.test.c index 703abc232..65b5b06b0 100644 --- a/src/reports.test.c +++ b/src/reports.test.c @@ -785,27 +785,12 @@ static void test_stealth_modifier(CuTest *tc) { test_teardown(); } -static void setup_calendar(void) { - months_per_year = 9; - month_season = malloc(sizeof(int) * months_per_year); - month_season[0] = SEASON_SUMMER; - month_season[1] = SEASON_AUTUMN; - month_season[2] = SEASON_AUTUMN; - month_season[3] = SEASON_WINTER; - month_season[4] = SEASON_WINTER; - month_season[5] = SEASON_WINTER; - month_season[6] = SEASON_SPRING; - month_season[7] = SEASON_SPRING; - month_season[8] = SEASON_SUMMER; -} - static void test_insect_warnings(CuTest *tc) { faction *f; gamedate gd; test_setup(); - setup_calendar(); - config_set_int("game.start", 184); + test_create_calendar(); test_inject_messagetypes(); f = test_create_faction(test_create_race("insect")); diff --git a/src/tests.c b/src/tests.c index 09f533a9f..4ee38d195 100644 --- a/src/tests.c +++ b/src/tests.c @@ -260,6 +260,21 @@ static void test_reset(void) { } } +void test_create_calendar(void) { + config_set_int("game.start", 184); + months_per_year = 9; + month_season = malloc(sizeof(int) * months_per_year); + month_season[0] = SEASON_SUMMER; + month_season[1] = SEASON_AUTUMN; + month_season[2] = SEASON_AUTUMN; + month_season[3] = SEASON_WINTER; + month_season[4] = SEASON_WINTER; + month_season[5] = SEASON_WINTER; + month_season[6] = SEASON_SPRING; + month_season[7] = SEASON_SPRING; + month_season[8] = SEASON_SUMMER; +} + void test_inject_messagetypes(void) { message_handle_missing(MESSAGE_MISSING_REPLACE); diff --git a/src/tests.h b/src/tests.h index dd8bed3c8..441db9e16 100644 --- a/src/tests.h +++ b/src/tests.h @@ -40,6 +40,7 @@ extern "C" { struct log_t * test_log_start(int flags, struct strlist **slist); void test_log_stop(struct log_t *log, struct strlist *slist); + void test_create_calendar(void); struct locale * test_create_locale(void); struct terrain_type * test_create_terrain(const char * name, int flags); struct race *test_create_race(const char *name);