void test_buildingowner_goes_to_empty_unit_after_leave(CuTest * tc) { struct region *r; struct building *bld; struct unit *u1, *u2, *u3; struct faction *f1; test_setup(); f1 = test_create_faction(NULL); r = test_create_plain(0, 0); bld = test_create_building(r, NULL); CuAssertPtrNotNull(tc, bld); u1 = test_create_unit(f1, r); u2 = test_create_unit(f1, r); u3 = test_create_unit(f1, r); u_set_building(u1, bld); u_set_building(u2, bld); u_set_building(u3, bld); CuAssertPtrEquals(tc, u1, building_owner(bld)); u2->number = 0; leave_building(u1); CuAssertPtrEquals(tc, u3, building_owner(bld)); leave_building(u3); CuAssertPtrEquals(tc, NULL, building_owner(bld)); u2->number = 1; CuAssertPtrEquals(tc, u2, building_owner(bld)); test_teardown(); }
static void test_buildingowner_goes_to_other_when_empty(CuTest * tc) { struct region *r; struct building *bld; struct unit *u, *u2; struct faction *f; test_setup(); f = test_create_faction(NULL); r = test_create_plain(0, 0); bld = test_create_building(r, NULL); CuAssertPtrNotNull(tc, bld); u2 = test_create_unit(f, r); u = test_create_unit(f, r); CuAssertPtrNotNull(tc, u); u_set_building(u, bld); CuAssertPtrEquals(tc, u, building_owner(bld)); u_set_building(u2, bld); CuAssertPtrEquals(tc, u, building_owner(bld)); u->number = 0; CuAssertPtrEquals(tc, u2, building_owner(bld)); test_teardown(); }
static void test_buildingowner_goes_to_same_faction_after_leave(CuTest * tc) { struct region *r; struct building *bld; struct unit *u, *u2, *u3; struct faction *f1, *f2; test_setup(); f1 = test_create_faction(NULL); f2 = test_create_faction(NULL); r = test_create_plain(0, 0); bld = test_create_building(r, NULL); CuAssertPtrNotNull(tc, bld); u2 = test_create_unit(f2, r); u3 = test_create_unit(f1, r); u = test_create_unit(f1, r); CuAssertPtrNotNull(tc, u); u_set_building(u, bld); u_set_building(u2, bld); u_set_building(u3, bld); CuAssertPtrEquals(tc, u, building_owner(bld)); leave_building(u); CuAssertPtrEquals(tc, u3, building_owner(bld)); leave_building(u3); CuAssertPtrEquals(tc, u2, building_owner(bld)); leave_building(u2); CuAssertPtrEquals(tc, NULL, building_owner(bld)); test_teardown(); }
static unit *building_owner_ex(const building * bld, const struct faction * last_owner) { unit *u, *heir = 0; /* Eigentümer tot oder kein Eigentümer vorhanden. Erste lebende Einheit * nehmen. */ for (u = bld->region->units; u; u = u->next) { if (u->building == bld) { if (u->number > 0) { if (heir && last_owner && heir->faction != last_owner && u->faction == last_owner) { heir = u; break; /* we found someone from the same faction who is not dead. let's take this guy */ } else if (!heir) { heir = u; /* you'll do in an emergency */ } } } } if (!heir && config_token("rules.region_owner_pay_building", bld->type->_name)) { if (rule_region_owners()) { u = building_owner(largestbuilding(bld->region, &cmp_taxes, false)); } else { u = building_owner(largestbuilding(bld->region, &cmp_wage, false)); } if (u) { heir = u; } } return heir; }
int bt_effsize(const building_type * btype, const building * b, int bsize) { int i = bsize, n = 0; const construction *cons = btype->construction; /* TECH DEBT: simplest thing that works for E3 dwarf/halfling faction rules */ if (b && config_get_int("rules.dwarf_castles", 0) && strcmp(btype->_name, "castle") == 0) { unit *u = building_owner(b); if (u && u->faction->race == get_race(RC_HALFLING)) { i = bsize * 10 / 8; } } if (!cons || !cons->improvement) { return 0; } while (cons && cons->maxsize != -1 && i >= cons->maxsize) { i -= cons->maxsize; cons = cons->improvement; ++n; } return n; }
static int tolua_building_get_owner(lua_State * L) { building *b = (building *)tolua_tousertype(L, 1, 0); unit *u = b ? building_owner(b) : NULL; tolua_pushusertype(L, u, TOLUA_CAST "unit"); return 1; }
static void test_give_control_building(CuTest * tc) { unit *u1, *u2; building *b; struct faction *f; region *r; test_cleanup(); f = test_create_faction(0); r = test_create_region(0, 0, 0); b = test_create_building(r, 0); u1 = test_create_unit(f, r); u_set_building(u1, b); u2 = test_create_unit(f, r); u_set_building(u2, b); CuAssertPtrEquals(tc, u1, building_owner(b)); give_control(u1, u2); CuAssertPtrEquals(tc, u2, building_owner(b)); test_cleanup(); }
void randomevents(void) { region *r; faction *monsters = get_monsters(); icebergs(); godcurse(); orc_growth(); demon_skillchanges(); volcano_update(); /* Monumente zerfallen, Schiffe verfaulen */ for (r = regions; r; r = r->next) { building **blist = &r->buildings; while (*blist) { building *b = *blist; if (fval(b->type, BTF_DECAY) && !building_owner(b)) { b->size -= _max(1, (b->size * 20) / 100); if (b->size == 0) { remove_building(blist, r->buildings); } } if (*blist == b) blist = &b->next; } } /* monster-einheiten desertieren */ if (monsters) { for (r = regions; r; r = r->next) { unit *u; for (u = r->units; u; u = u->next) { if (u->faction && !is_monsters(u->faction) && (u_race(u)->flags & RCF_DESERT)) { if (fval(u, UFL_ISNEW)) continue; if (rng_int() % 100 < 5) { ADDMSG(&u->faction->msgs, msg_message("desertion", "unit region", u, r)); u_setfaction(u, monsters); } } } } } chaos_update(); #ifdef HERBS_ROT rotting_herbs(); #endif dissolve_units(); }
faction *update_owners(region * r) { faction *f = NULL; assert(rule_region_owners()); if (r->land) { building *bowner = largestbuilding(r, &cmp_current_owner, false); building *blargest = largestbuilding(r, &cmp_taxes, false); if (blargest) { if (!bowner || bowner->size < blargest->size) { /* region owners update? */ unit *u = building_owner(blargest); f = region_get_owner(r); if (u == NULL) { if (f) { region_set_owner(r, NULL, turn); r->land->ownership->flags |= OWNER_MOURNING; f = NULL; } } else if (u->faction != f) { if (!r->land->ownership) { /* there has never been a prior owner */ region_set_morale(r, MORALE_DEFAULT, turn); } else { alliance *al = region_get_alliance(r); if (al && u->faction->alliance == al) { int morale = _max(0, r->land->morale - MORALE_TRANSFER); region_set_morale(r, morale, turn); } else { region_set_morale(r, MORALE_TAKEOVER, turn); if (f) { r->land->ownership->flags |= OWNER_MOURNING; } } } region_set_owner(r, u->faction, turn); f = u->faction; } } } else if (r->land->ownership && r->land->ownership->owner) { r->land->ownership->flags |= OWNER_MOURNING; region_set_owner(r, NULL, turn); f = NULL; } } return f; }
static void test_building_set_owner(CuTest * tc) { struct region *r; struct building *bld; struct unit *u1, *u2; struct faction *f; test_setup(); f = test_create_faction(NULL); r = test_create_region(0, 0, NULL); bld = test_create_building(r, NULL); u1 = test_create_unit(f, r); u_set_building(u1, bld); CuAssertPtrEquals(tc, u1, building_owner(bld)); u2 = test_create_unit(f, r); u_set_building(u2, bld); CuAssertPtrEquals(tc, u1, building_owner(bld)); building_set_owner(u2); CuAssertPtrEquals(tc, u2, building_owner(bld)); test_teardown(); }
bool can_leave(unit * u) { static int gamecookie = -1; static int rule_leave = -1; if (!u->building) { return true; } if (rule_leave < 0 || gamecookie != global.cookie) { gamecookie = global.cookie; rule_leave = get_param_int(global.parameters, "rules.move.owner_leave", 0); } if (rule_leave && u->building && u == building_owner(u->building)) { return false; } return true; }
static bool is_guardian_r(const unit * guard) { if (guard->number == 0) return false; if (besieged(guard)) return false; /* if region_owners exist then they may be guardians: */ if (guard->building && rule_region_owners() && guard == building_owner(guard->building)) { faction *owner = region_get_owner(guard->region); if (owner == guard->faction) { building *bowner = largestbuilding(guard->region, &cmp_taxes, false); if (bowner == guard->building) { return true; } } } if ((guard->flags & UFL_GUARD) == 0) return false; return fval(u_race(guard), RCF_UNARMEDGUARD) || is_monsters(guard->faction) || (armedmen(guard, true) > 0); }
int lighthouse_range(const building * b, const faction * f) { int d = 0; if (fval(b, BLD_MAINTAINED) && b->size >= 10) { int maxd = (int)log10(b->size) + 1; if (skill_enabled(SK_PERCEPTION)) { region *r = b->region; int c = 0; int cap = buildingcapacity(b); unit *u, *uown = building_owner(b); for (u = r->units; u; u = u->next) { if (u->building == b || u == uown) { c += u->number; if (c > cap) { break; } else if (f == NULL || u->faction == f) { int sk = effskill(u, SK_PERCEPTION, 0) / 3; d = _max(d, sk); d = _min(maxd, d); if (d == maxd) break; } } else if (c) break; /* first unit that's no longer in the house ends the search */ } } else { /* E3A rule: no perception req'd */ return maxd; } } return d; }
static unsigned int get_markets(region * r, unit ** results, size_t size) { unsigned int n = 0; building *b; const building_type *btype = bt_find("market"); if (!btype) return 0; for (b = r->buildings; n < size && b; b = b->next) { if (b->type == btype && building_is_active(b)) { unit *u = building_owner(b); /* I decided to omit check for inside_building(u) */ unsigned int i; for (i = 0; u && i != n; ++i) { /* only one market per faction */ if (results[i]->faction == u->faction) u = NULL; } if (u) { results[n++] = u; } } } return n; }
static unsigned int get_markets(region * r, unit ** results, size_t size) { unsigned int n = 0; building *b; const building_type *btype = bt_find("market"); if (!btype) return 0; for (b = r->buildings; n < size && b; b = b->next) { if (b->type == btype && (b->flags & BLD_WORKING) && b->size >= b->type->maxsize) { unit *u = building_owner(b); unsigned int i; for (i = 0; u && i != n; ++i) { /* only one market per faction */ if (results[i]->faction == u->faction) u = NULL; } if (u) { results[n++] = u; } } } return n; }
int build_building(unit * u, const building_type * btype, int id, int want, order * ord) { region *r = u->region; int n = want, built = 0; building *b = NULL; /* einmalige Korrektur */ const char *btname; order *new_order = NULL; const struct locale *lang = u->faction->locale; static int rule_other = -1; assert(u->number); assert(btype->construction); if (eff_skill(u, SK_BUILDING, r) == 0) { cmistake(u, ord, 101, MSG_PRODUCE); return 0; } /* Falls eine Nummer angegeben worden ist, und ein Gebaeude mit der * betreffenden Nummer existiert, ist b nun gueltig. Wenn keine Burg * gefunden wurde, dann wird nicht einfach eine neue erbaut. Ansonsten * baut man an der eigenen burg weiter. */ /* Wenn die angegebene Nummer falsch ist, KEINE Burg bauen! */ if (id > 0) { /* eine Nummer angegeben, keine neue Burg bauen */ b = findbuilding(id); if (!b || b->region != u->region) { /* eine Burg mit dieser Nummer gibt es hier nicht */ /* vieleicht Tippfehler und die eigene Burg ist gemeint? */ if (u->building && u->building->type == btype) { b = u->building; } else { /* keine neue Burg anfangen wenn eine Nummer angegeben war */ cmistake(u, ord, 6, MSG_PRODUCE); return 0; } } } else if (u->building && u->building->type == btype) { b = u->building; } if (b) btype = b->type; if (fval(btype, BTF_UNIQUE) && buildingtype_exists(r, btype, false)) { /* only one of these per region */ cmistake(u, ord, 93, MSG_PRODUCE); return 0; } if (besieged(u)) { /* units under siege can not build */ cmistake(u, ord, 60, MSG_PRODUCE); return 0; } if (btype->flags & BTF_NOBUILD) { /* special building, cannot be built */ cmistake(u, ord, 221, MSG_PRODUCE); return 0; } if ((r->terrain->flags & LAND_REGION) == 0) { /* special terrain, cannot build */ cmistake(u, ord, 221, MSG_PRODUCE); return 0; } if (btype->flags & BTF_ONEPERTURN) { if (b && fval(b, BLD_EXPANDED)) { cmistake(u, ord, 318, MSG_PRODUCE); return 0; } n = 1; } if (b) { if (rule_other < 0) { rule_other = get_param_int(global.parameters, "rules.build.other_buildings", 1); } if (!rule_other) { unit *owner = building_owner(b); if (!owner || owner->faction != u->faction) { cmistake(u, ord, 1222, MSG_PRODUCE); return 0; } } } if (b) built = b->size; if (n <= 0 || n == INT_MAX) { if (b == NULL) { if (btype->maxsize > 0) { n = btype->maxsize - built; } else { n = INT_MAX; } } else { if (b->type->maxsize > 0) { n = b->type->maxsize - built; } else { n = INT_MAX; } } } built = build(u, btype->construction, built, n); switch (built) { case ECOMPLETE: /* the building is already complete */ cmistake(u, ord, 4, MSG_PRODUCE); break; case ENOMATERIALS: ADDMSG(&u->faction->msgs, msg_materials_required(u, ord, btype->construction, want)); break; case ELOWSKILL: case ENEEDSKILL: /* no skill, or not enough skill points to build */ cmistake(u, ord, 50, MSG_PRODUCE); break; } if (built <= 0) { return built; } /* at this point, the building size is increased. */ if (b == NULL) { /* build a new building */ b = new_building(btype, r, lang); b->type = btype; fset(b, BLD_MAINTAINED | BLD_WORKING); /* Die Einheit befindet sich automatisch im Inneren der neuen Burg. */ if (u->number && leave(u, false)) { u_set_building(u, b); } } btname = LOC(lang, btype->_name); if (want - built <= 0) { /* gebäude fertig */ new_order = default_order(lang); } else if (want != INT_MAX) { /* reduzierte restgröße */ const char *hasspace = strchr(btname, ' '); if (hasspace) { new_order = create_order(K_MAKE, lang, "%d \"%s\" %i", n - built, btname, b->no); } else { new_order = create_order(K_MAKE, lang, "%d %s %i", n - built, btname, b->no); } } else if (btname) { /* Neues Haus, Befehl mit Gebäudename */ const char *hasspace = strchr(btname, ' '); if (hasspace) { new_order = create_order(K_MAKE, lang, "\"%s\" %i", btname, b->no); } else { new_order = create_order(K_MAKE, lang, "%s %i", btname, b->no); } } if (new_order) { replace_order(&u->orders, ord, new_order); free_order(new_order); } b->size += built; fset(b, BLD_EXPANDED); update_lighthouse(b); ADDMSG(&u->faction->msgs, msg_message("buildbuilding", "building unit size", b, u, built)); return built; }
int destroy_cmd(unit * u, struct order *ord) { char token[128]; ship *sh; unit *u2; region *r = u->region; const construction *con = NULL; int size = 0; const char *s; int n = INT_MAX; if (u->number < 1) return 0; init_order(ord); s = gettoken(token, sizeof(token)); if (findparam(s, u->faction->locale) == P_ROAD) { destroy_road(u, INT_MAX, ord); return 0; } if (s && *s) { n = atoi((const char *)s); if (n <= 0) { cmistake(u, ord, 288, MSG_PRODUCE); return 0; } } if (getparam(u->faction->locale) == P_ROAD) { destroy_road(u, n, ord); return 0; } if (u->building) { building *b = u->building; if (u != building_owner(b)) { cmistake(u, ord, 138, MSG_PRODUCE); return 0; } if (fval(b->type, BTF_INDESTRUCTIBLE)) { cmistake(u, ord, 138, MSG_PRODUCE); return 0; } if (n >= b->size) { /* destroy completly */ /* all units leave the building */ for (u2 = r->units; u2; u2 = u2->next) { if (u2->building == b) { leave_building(u2); } } ADDMSG(&u->faction->msgs, msg_message("destroy", "building unit", b, u)); con = b->type->construction; remove_building(&r->buildings, b); } else { /* partial destroy */ b->size -= n; ADDMSG(&u->faction->msgs, msg_message("destroy_partial", "building unit", b, u)); } } else if (u->ship) { sh = u->ship; if (u != ship_owner(sh)) { cmistake(u, ord, 138, MSG_PRODUCE); return 0; } if (fval(r->terrain, SEA_REGION)) { cmistake(u, ord, 14, MSG_EVENT); return 0; } if (n >= (sh->size * 100) / sh->type->construction->maxsize) { /* destroy completly */ /* all units leave the ship */ for (u2 = r->units; u2; u2 = u2->next) { if (u2->ship == sh) { leave_ship(u2); } } ADDMSG(&u->faction->msgs, msg_message("shipdestroy", "unit region ship", u, r, sh)); con = sh->type->construction; remove_ship(&sh->region->ships, sh); } else { /* partial destroy */ sh->size -= (sh->type->construction->maxsize * n) / 100; ADDMSG(&u->faction->msgs, msg_message("shipdestroy_partial", "unit region ship", u, r, sh)); } } else { cmistake(u, ord, 138, MSG_PRODUCE); return 0; } if (con) { /* TODO: Nicht an ZERSTÖRE mit Punktangabe angepaßt! */ int c; for (c = 0; con->materials[c].number; ++c) { const requirement *rq = con->materials + c; int recycle = (rq->number * size / con->reqsize) / 2; if (recycle) { change_resource(u, rq->rtype, recycle); } } } return 0; }
void randomevents(void) { region *r; faction *monsters = get_monsters(); icebergs(); godcurse(); orc_growth(); demon_skillchanges(); /* Orkifizierte Regionen mutieren und mutieren zurück */ for (r = regions; r; r = r->next) { if (fval(r, RF_ORCIFIED)) { direction_t dir; double probability = 0.0; for (dir = 0; dir < MAXDIRECTIONS; dir++) { region *rc = rconnect(r, dir); if (rc && rpeasants(rc) > 0 && !fval(rc, RF_ORCIFIED)) probability += 0.02; } if (chance(probability)) { ADDMSG(&r->msgs, msg_message("deorcified", "region", r)); freset(r, RF_ORCIFIED); } } else { attrib *a = a_find(r->attribs, &at_orcification); if (a != NULL) { double probability = 0.0; if (rpeasants(r) <= 0) continue; probability = a->data.i / (double)rpeasants(r); if (chance(probability)) { fset(r, RF_ORCIFIED); a_remove(&r->attribs, a); ADDMSG(&r->msgs, msg_message("orcified", "region", r)); } else { a->data.i -= _max(10, a->data.i / 10); if (a->data.i <= 0) a_remove(&r->attribs, a); } } } } /* Vulkane qualmen, brechen aus ... */ for (r = regions; r; r = r->next) { if (r->terrain == newterrain(T_VOLCANO_SMOKING)) { if (a_find(r->attribs, &at_reduceproduction)) { ADDMSG(&r->msgs, msg_message("volcanostopsmoke", "region", r)); rsetterrain(r, T_VOLCANO); } else { if (rng_int() % 100 < 12) { ADDMSG(&r->msgs, msg_message("volcanostopsmoke", "region", r)); rsetterrain(r, T_VOLCANO); } else if (r->age > 20 && rng_int() % 100 < 8) { volcano_outbreak(r); } } } else if (r->terrain == newterrain(T_VOLCANO)) { if (rng_int() % 100 < 4) { ADDMSG(&r->msgs, msg_message("volcanostartsmoke", "region", r)); rsetterrain(r, T_VOLCANO_SMOKING); } } } /* Monumente zerfallen, Schiffe verfaulen */ for (r = regions; r; r = r->next) { building **blist = &r->buildings; while (*blist) { building *b = *blist; if (fval(b->type, BTF_DECAY) && !building_owner(b)) { b->size -= _max(1, (b->size * 20) / 100); if (b->size == 0) { remove_building(blist, r->buildings); } } if (*blist == b) blist = &b->next; } } /* monster-einheiten desertieren */ if (monsters) { for (r = regions; r; r = r->next) { unit *u; for (u = r->units; u; u = u->next) { if (u->faction && !is_monsters(u->faction) && (u_race(u)->flags & RCF_DESERT)) { if (fval(u, UFL_ISNEW)) continue; if (rng_int() % 100 < 5) { ADDMSG(&u->faction->msgs, msg_message("desertion", "unit region", u, r)); u_setfaction(u, monsters); } } } } } /* Chaos */ for (r = regions; r; r = r->next) { int i; if (fval(r, RF_CHAOTIC)) { chaos(r); } i = chaoscount(r); if (i) { chaoscounts(r, -(int)(i * ((double)(rng_int() % 10)) / 100.0)); } } #ifdef HERBS_ROT rotting_herbs(); #endif dissolve_units(); }