diff --git a/src/kernel/build.h b/src/kernel/build.h index e08e5f65e..4e3bbedaa 100644 --- a/src/kernel/build.h +++ b/src/kernel/build.h @@ -79,8 +79,7 @@ extern "C" { void sunhash(struct ship *sh); extern int roqf_factor(void); - extern int build(struct unit *u, const construction * ctype, int completed, - int want); + int build(struct unit *u, const construction * ctype, int completed, int want); extern int maxbuild(const struct unit *u, const construction * cons); extern struct message *msg_materials_required(struct unit *u, struct order *ord, const struct construction *ctype, int multi); diff --git a/src/kernel/build.test.c b/src/kernel/build.test.c index 0235fb0c6..1b3dda5fd 100644 --- a/src/kernel/build.test.c +++ b/src/kernel/build.test.c @@ -13,86 +13,110 @@ #include #include +#include #include -static void test_build_building_no_materials(CuTest *tc) { +typedef struct build_fixture { + faction *f; unit *u; region *r; - faction *f; race *rc; - const building_type *btype; +} build_fixture; +static unit * setup_build(build_fixture *bf) { test_cleanup(); test_create_world(); + bf->rc = test_create_race("human"); + bf->r = findregion(0, 0); + bf->f = test_create_faction(bf->rc); + assert(bf->rc && bf->f && bf->r); + bf->u = test_create_unit(bf->f, bf->r); + assert(bf->u); + return bf->u; +} - rc = test_create_race("human"); - r = findregion(0, 0); - f = test_create_faction(rc); - assert(rc && f && r); - u = test_create_unit(f, r); +static void test_build(CuTest *tc) { + build_fixture bf; + unit *u; + construction cons = { 0 }; + const struct resource_type *rtype; + + u = setup_build(&bf); + rtype = get_resourcetype(R_SILVER); + assert(rtype); + + cons.materials = calloc(2, sizeof(requirement)); + cons.materials[0].number = 1; + cons.materials[0].rtype = rtype; + cons.skill = SK_ARMORER; + cons.minskill = 2; + cons.reqsize = 1; + CuAssertIntEquals(tc, ENEEDSKILL, build(u, &cons, 1, 1)); + set_level(u, SK_ARMORER, 1); + CuAssertIntEquals(tc, ELOWSKILL, build(u, &cons, 1, 1)); + set_level(u, SK_ARMORER, 2); + CuAssertIntEquals(tc, ENOMATERIALS, build(u, &cons, 1, 1)); + i_change(&u->items, rtype->itype, 1); + CuAssertIntEquals(tc, 1, build(u, &cons, 1, 1)); + CuAssertIntEquals(tc, 0, i_get(u->items, rtype->itype)); + scale_number(u, 2); + i_change(&u->items, rtype->itype, 2); + CuAssertIntEquals(tc, 2, build(u, &cons, 2, 2)); + CuAssertIntEquals(tc, 0, i_get(u->items, rtype->itype)); + test_cleanup(); +} + +static void test_build_building_no_materials(CuTest *tc) { + const building_type *btype; + build_fixture bf = { 0 }; + unit *u; + + u = setup_build(&bf); btype = bt_find("castle"); - assert(u && btype); - set_level(u, SK_BUILDING, 1); - CuAssertIntEquals(tc, ENOMATERIALS, build_building(u, btype, 0, 4, 0)); - CuAssertPtrEquals(tc, 0, r->buildings); - CuAssertPtrEquals(tc, 0, u->building); + assert(btype); + set_level(bf.u, SK_BUILDING, 1); + CuAssertIntEquals(tc, ENOMATERIALS, build_building(bf.u, btype, 0, 4, 0)); + CuAssertPtrEquals(tc, 0, bf.r->buildings); + CuAssertPtrEquals(tc, 0, bf.u->building); } static void test_build_building_with_golem(CuTest *tc) { unit *u; - region *r; - faction *f; - race *rc; + build_fixture bf; const building_type *btype; - test_cleanup(); - test_create_world(); - - rc = test_create_race("stonegolem"); - rc->flags |= RCF_STONEGOLEM; + u = setup_build(&bf); + bf.rc->flags |= RCF_STONEGOLEM; btype = bt_find("castle"); - assert(btype && rc); + assert(btype); assert(btype->construction); - r = findregion(0, 0); - assert(!r->buildings); - f = test_create_faction(rc); - assert(r && f); - u = test_create_unit(f, r); - assert(u); - set_level(u, SK_BUILDING, 1); + + set_level(bf.u, SK_BUILDING, 1); CuAssertIntEquals(tc, 1, build_building(u, btype, 0, 4, 0)); - CuAssertPtrNotNull(tc, r->buildings); - CuAssertIntEquals(tc, 1, r->buildings->size); + CuAssertPtrNotNull(tc, u->region->buildings); + CuAssertIntEquals(tc, 1, u->region->buildings->size); CuAssertIntEquals(tc, 0, u->number); } static void test_build_building_success(CuTest *tc) { unit *u; - region *r; - faction *f; - race *rc; + build_fixture bf = { 0 }; const building_type *btype; const resource_type *rtype; - test_cleanup(); - test_create_world(); + u = setup_build(&bf); - rc = test_create_race("human"); rtype = get_resourcetype(R_STONE); btype = bt_find("castle"); - assert(btype && rc && rtype && rtype->itype); + assert(btype && rtype && rtype->itype); assert(btype->construction); - r = findregion(0, 0); - assert(!r->buildings); - f = test_create_faction(rc); - assert(r && f); - u = test_create_unit(f, r); - assert(u); - i_change(&u->items, rtype->itype, 1); + assert(!u->region->buildings); + + i_change(&bf.u->items, rtype->itype, 1); set_level(u, SK_BUILDING, 1); CuAssertIntEquals(tc, 1, build_building(u, btype, 0, 4, 0)); - CuAssertPtrNotNull(tc, r->buildings); - CuAssertPtrEquals(tc, r->buildings, u->building); + CuAssertPtrNotNull(tc, u->region->buildings); + CuAssertPtrEquals(tc, u->region->buildings, u->building); CuAssertIntEquals(tc, 1, u->building->size); CuAssertIntEquals(tc, 0, i_get(u->items, rtype->itype)); } @@ -100,6 +124,7 @@ static void test_build_building_success(CuTest *tc) { CuSuite *get_build_suite(void) { CuSuite *suite = CuSuiteNew(); + SUITE_ADD_TEST(suite, test_build); SUITE_ADD_TEST(suite, test_build_building_success); SUITE_ADD_TEST(suite, test_build_building_with_golem); SUITE_ADD_TEST(suite, test_build_building_no_materials); diff --git a/src/kernel/item.c b/src/kernel/item.c index 44588b7e7..0079b576c 100644 --- a/src/kernel/item.c +++ b/src/kernel/item.c @@ -101,24 +101,29 @@ static int res_changepeasants(unit * u, const resource_type * rtype, int delta) return u->region->land->peasants; } +static int golem_factor(const unit *u, const resource_type *rtype) { + if (rtype == get_resourcetype(R_STONE) && (u_race(u)->flags & RCF_STONEGOLEM)) { + return GOLEM_STONE; + } + if (rtype == get_resourcetype(R_IRON) && (u_race(u)->flags & RCF_IRONGOLEM)) { + return GOLEM_IRON; + } + return 0; +} + static int res_changeitem(unit * u, const resource_type * rtype, int delta) { int num; - if (rtype == get_resourcetype(R_STONE) && u_race(u) == get_race(RC_STONEGOLEM) - && delta <= 0) { - int reduce = delta / GOLEM_STONE; - if (delta % GOLEM_STONE != 0) - --reduce; - scale_number(u, u->number + reduce); - num = u->number * GOLEM_STONE; - } - else if (rtype == get_resourcetype(R_IRON) - && u_race(u) == get_race(RC_IRONGOLEM) && delta <= 0) { - int reduce = delta / GOLEM_IRON; - if (delta % GOLEM_IRON != 0) - --reduce; - scale_number(u, u->number + reduce); - num = u->number * GOLEM_IRON; + int gf = (delta>0) ? 0 : golem_factor(u, rtype); + if (gf>0) { + if (delta != 0) { + int reduce = delta / gf; + if (delta % gf != 0) { + --reduce; + } + if (reduce) scale_number(u, u->number + reduce); + } + num = u->number * gf; } else { const item_type *itype = resource2item(rtype); diff --git a/src/kernel/pool.c b/src/kernel/pool.c index 49219127d..6f8e378f7 100644 --- a/src/kernel/pool.c +++ b/src/kernel/pool.c @@ -1,7 +1,7 @@ /* Copyright (c) 1998-2010, Enno Rehling - Katja Zedel +Katja Zedel Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above @@ -39,212 +39,216 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. int get_resource(const unit * u, const resource_type * rtype) { - assert(rtype); - if (rtype->uget) { - /* this resource is probably special */ - int i = rtype->uget(u, rtype); - if (i >= 0) - return i; - } - else if (rtype->uchange) { - /* this resource is probably special */ - int i = rtype->uchange((unit *)u, rtype, 0); - if (i >= 0) - return i; - } - if (rtype->itype) { - if (rtype == get_resourcetype(R_STONE) && (u_race(u)->flags & RCF_STONEGOLEM)) { - return u->number * GOLEM_STONE; - } else if (rtype == get_resourcetype(R_IRON) && (u_race(u)->flags & RCF_IRONGOLEM)) { - return u->number * GOLEM_IRON; - } else { - return i_get(u->items, rtype->itype); + assert(rtype); + if (rtype->uget) { + /* this resource is probably special */ + int i = rtype->uget(u, rtype); + if (i >= 0) + return i; } - } - if (rtype == get_resourcetype(R_AURA)) - return get_spellpoints(u); - if (rtype == get_resourcetype(R_PERMAURA)) - return max_spellpoints(u->region, u); - log_error("trying to get unknown resource '%s'.\n", rtype->_name[0]); - return 0; + else if (rtype->uchange) { + /* this resource is probably special */ + int i = rtype->uchange((unit *)u, rtype, 0); + if (i >= 0) + return i; + } + if (rtype->itype) { + return i_get(u->items, rtype->itype); + } + if (rtype == get_resourcetype(R_AURA)) { + return get_spellpoints(u); + } + if (rtype == get_resourcetype(R_PERMAURA)) { + return max_spellpoints(u->region, u); + } + log_error("trying to get unknown resource '%s'.\n", rtype->_name[0]); + return 0; } int change_resource(unit * u, const resource_type * rtype, int change) { - int i = 0; + int i = 0; - if (rtype->uchange) - i = rtype->uchange(u, rtype, change); - else if (rtype == get_resourcetype(R_AURA)) - i = change_spellpoints(u, change); - else if (rtype == get_resourcetype(R_PERMAURA)) - i = change_maxspellpoints(u, change); - else - assert(!"undefined resource detected. rtype->uchange not initialized."); - assert(i==get_resource(u, rtype)); - assert(i >= 0); - if (i >= 100000000) { - log_warning("%s has %d %s\n", unitname(u), i, rtype->_name[0]); - } - return i; + if (rtype->uchange) + i = rtype->uchange(u, rtype, change); + else if (rtype == get_resourcetype(R_AURA)) + i = change_spellpoints(u, change); + else if (rtype == get_resourcetype(R_PERMAURA)) + i = change_maxspellpoints(u, change); + else + assert(!"undefined resource detected. rtype->uchange not initialized."); + assert(i == get_resource(u, rtype)); + assert(i >= 0); + if (i >= 100000000) { + log_warning("%s has %d %s\n", unitname(u), i, rtype->_name[0]); + } + return i; } int get_reservation(const unit * u, const resource_type * rtype) { - reservation *res = u->reservations; + reservation *res = u->reservations; - if (rtype == get_resourcetype(R_STONE) && (u_race(u)->flags & RCF_STONEGOLEM)) - return (u->number * GOLEM_STONE); - if (rtype == get_resourcetype(R_IRON) && (u_race(u)->flags & RCF_IRONGOLEM)) - return (u->number * GOLEM_IRON); - while (res && res->type != rtype) - res = res->next; - if (res) - return res->value; - return 0; + if (rtype == get_resourcetype(R_STONE) && (u_race(u)->flags & RCF_STONEGOLEM)) + return (u->number * GOLEM_STONE); + if (rtype == get_resourcetype(R_IRON) && (u_race(u)->flags & RCF_IRONGOLEM)) + return (u->number * GOLEM_IRON); + while (res && res->type != rtype) + res = res->next; + if (res) + return res->value; + return 0; } int change_reservation(unit * u, const resource_type * rtype, int value) { - reservation *res, **rp = &u->reservations; + reservation *res, **rp = &u->reservations; - if (!value) - return 0; + if (!value) + return 0; - while (*rp && (*rp)->type != rtype) - rp = &(*rp)->next; - res = *rp; - if (!res) { - *rp = res = calloc(sizeof(reservation), 1); - res->type = rtype; - res->value = value; - } else if (res && res->value + value <= 0) { - *rp = res->next; - free(res); - return 0; - } else { - res->value += value; - } - return res->value; + while (*rp && (*rp)->type != rtype) + rp = &(*rp)->next; + res = *rp; + if (!res) { + *rp = res = calloc(sizeof(reservation), 1); + res->type = rtype; + res->value = value; + } + else if (res && res->value + value <= 0) { + *rp = res->next; + free(res); + return 0; + } + else { + res->value += value; + } + return res->value; } int set_resvalue(unit * u, const resource_type * rtype, int value) { - reservation *res, **rp = &u->reservations; + reservation *res, **rp = &u->reservations; - while (*rp && (*rp)->type != rtype) - rp = &(*rp)->next; - res = *rp; - if (!res) { - if (!value) - return 0; - *rp = res = calloc(sizeof(reservation), 1); - res->type = rtype; - res->value = value; - } else if (res && value <= 0) { - *rp = res->next; - free(res); - return 0; - } else { - res->value = value; - } - return res->value; + while (*rp && (*rp)->type != rtype) + rp = &(*rp)->next; + res = *rp; + if (!res) { + if (!value) + return 0; + *rp = res = calloc(sizeof(reservation), 1); + res->type = rtype; + res->value = value; + } + else if (res && value <= 0) { + *rp = res->next; + free(res); + return 0; + } + else { + res->value = value; + } + return res->value; } int get_pooled(const unit * u, const resource_type * rtype, unsigned int mode, - int count) +int count) { - const faction *f = u->faction; - unit *v; - int use = 0; - region *r = u->region; - int have = get_resource(u, rtype); + const faction *f = u->faction; + unit *v; + int use = 0; + region *r = u->region; + int have = get_resource(u, rtype); - if ((u_race(u)->ec_flags & GETITEM) == 0) { - mode &= (GET_SLACK | GET_RESERVE); - } + if ((u_race(u)->ec_flags & GETITEM) == 0) { + mode &= (GET_SLACK | GET_RESERVE); + } - if ((mode & GET_SLACK) && (mode & GET_RESERVE)) - use = have; - else { - int reserve = get_reservation(u, rtype); - int slack = _max(0, have - reserve); - if (mode & GET_RESERVE) - use = have - slack; - else if (mode & GET_SLACK) - use = slack; - } - if (rtype->flags & RTF_POOLED && mode & ~(GET_SLACK | GET_RESERVE)) { - for (v = r->units; v && use < count; v = v->next) - if (u != v) { - int mask; + if ((mode & GET_SLACK) && (mode & GET_RESERVE)) + use = have; + else { + int reserve = get_reservation(u, rtype); + int slack = _max(0, have - reserve); + if (mode & GET_RESERVE) + use = have - slack; + else if (mode & GET_SLACK) + use = slack; + } + if (rtype->flags & RTF_POOLED && mode & ~(GET_SLACK | GET_RESERVE)) { + for (v = r->units; v && use < count; v = v->next) + if (u != v) { + int mask; - if (v->items == NULL && rtype->uget == NULL) - continue; - if ((urace(v)->ec_flags & GIVEITEM) == 0) - continue; + if (v->items == NULL && rtype->uget == NULL) + continue; + if ((urace(v)->ec_flags & GIVEITEM) == 0) + continue; - if (v->faction == f) { - mask = (mode >> 3) & (GET_SLACK | GET_RESERVE); - } else if (alliedunit(v, f, HELP_MONEY)) - mask = (mode >> 6) & (GET_SLACK | GET_RESERVE); - else - continue; - use += get_pooled(v, rtype, mask, count - use); - } - } - return use; + if (v->faction == f) { + mask = (mode >> 3) & (GET_SLACK | GET_RESERVE); + } + else if (alliedunit(v, f, HELP_MONEY)) + mask = (mode >> 6) & (GET_SLACK | GET_RESERVE); + else + continue; + use += get_pooled(v, rtype, mask, count - use); + } + } + return use; } int use_pooled(unit * u, const resource_type * rtype, unsigned int mode, int count) { - const faction *f = u->faction; - unit *v; - int use = count; - region *r = u->region; - int n = 0, have = get_resource(u, rtype); + const faction *f = u->faction; + unit *v; + int use = count; + region *r = u->region; + int n = 0, have = get_resource(u, rtype); - if ((u_race(u)->ec_flags & GETITEM) == 0) { - mode &= (GET_SLACK | GET_RESERVE); - } - - if ((mode & GET_SLACK) && (mode & GET_RESERVE)) { - n = _min(use, have); - } else { - int reserve = get_reservation(u, rtype); - int slack = _max(0, have - reserve); - if (mode & GET_RESERVE) { - n = have - slack; - n = _min(use, n); - change_reservation(u, rtype, -n); - } else if (mode & GET_SLACK) { - n = _min(use, slack); + if ((u_race(u)->ec_flags & GETITEM) == 0) { + mode &= (GET_SLACK | GET_RESERVE); } - } - if (n > 0) { - change_resource(u, rtype, -n); - use -= n; - } - if (rtype->flags & RTF_POOLED && mode & ~(GET_SLACK | GET_RESERVE)) { - for (v = r->units; use > 0 && v != NULL; v = v->next) - if (u != v) { - int mask; - if ((urace(v)->ec_flags & GIVEITEM) == 0) - continue; - if (v->items == NULL && rtype->uget == NULL) - continue; + if ((mode & GET_SLACK) && (mode & GET_RESERVE)) { + n = _min(use, have); + } + else { + int reserve = get_reservation(u, rtype); + int slack = _max(0, have - reserve); + if (mode & GET_RESERVE) { + n = have - slack; + n = _min(use, n); + change_reservation(u, rtype, -n); + } + else if (mode & GET_SLACK) { + n = _min(use, slack); + } + } + if (n > 0) { + change_resource(u, rtype, -n); + use -= n; + } - if (v->faction == f) { - mask = (mode >> 3) & (GET_SLACK | GET_RESERVE); - } else if (alliedunit(v, f, HELP_MONEY)) - mask = (mode >> 6) & (GET_SLACK | GET_RESERVE); - else - continue; - use -= use_pooled(v, rtype, mask, use); - } - } - return count - use; + if (rtype->flags & RTF_POOLED && mode & ~(GET_SLACK | GET_RESERVE)) { + for (v = r->units; use > 0 && v != NULL; v = v->next) + if (u != v) { + int mask; + if ((urace(v)->ec_flags & GIVEITEM) == 0) + continue; + if (v->items == NULL && rtype->uget == NULL) + continue; + + if (v->faction == f) { + mask = (mode >> 3) & (GET_SLACK | GET_RESERVE); + } + else if (alliedunit(v, f, HELP_MONEY)) + mask = (mode >> 6) & (GET_SLACK | GET_RESERVE); + else + continue; + use -= use_pooled(v, rtype, mask, use); + } + } + return count - use; } diff --git a/src/main.c b/src/main.c index a14be8040..123bccdbc 100644 --- a/src/main.c +++ b/src/main.c @@ -16,7 +16,6 @@ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. **/ -#include #include #include