From d58173774415af9f21fa2eaf04fff9dd00e18352 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Tue, 24 Jun 2014 07:42:45 -0700 Subject: [PATCH] optimization: caching resource types in get_resourcetype. eliminate some it_find calls. eliminate static variables, they make testing hard. --- core/res/de/strings.xml | 10 -- src/economy.c | 169 +++++++++++++------------- src/give.c | 4 +- src/items/weapons.c | 131 ++++++++++---------- src/kernel/battle.c | 59 +++++---- src/kernel/config.c | 13 +- src/kernel/item.c | 262 +++++++++++++++++++++++----------------- src/kernel/item.h | 17 +-- src/kernel/item.test.c | 2 +- src/kernel/magic.c | 22 ++-- src/kernel/move.c | 59 +++++---- src/kernel/region.c | 12 +- src/kernel/reports.c | 6 +- src/kernel/unit.c | 54 +++++---- src/laws.c | 162 ++++++++++++------------- src/report.c | 3 +- src/spells/spells.c | 16 +-- src/summary.c | 6 +- 18 files changed, 509 insertions(+), 498 deletions(-) diff --git a/core/res/de/strings.xml b/core/res/de/strings.xml index 01071ec61..ccc56b5ab 100644 --- a/core/res/de/strings.xml +++ b/core/res/de/strings.xml @@ -6879,16 +6879,6 @@ this item, use the CLAIM and SHOW commands). - - Gral - grail - - - - Grale - grails - - Lerntrank brain boost diff --git a/src/economy.c b/src/economy.c index 71900a38c..a933e617e 100644 --- a/src/economy.c +++ b/src/economy.c @@ -999,10 +999,12 @@ void add_spende(faction * f1, faction * f2, int amount, region * r) static bool maintain(building * b, bool first) /* first==false -> take money from wherever you can */ { - int c; - region *r = b->region; - bool paid = true, work = first; - unit *u; + const resource_type *rsilver = get_resourcetype(R_SILVER); + int c; + region *r = b->region; + bool paid = true, work = first; + unit *u; + if (fval(b, BLD_MAINTAINED) || b->type == NULL || b->type->maintenance == NULL || is_cursed(b->attribs, C_NOCOST, 0)) { fset(b, BLD_MAINTAINED); @@ -1094,7 +1096,7 @@ static bool maintain(building * b, bool first) continue; cost -= give; fset(ua->faction, FFL_SELECT); - if (m->rtype == r_silver) + if (m->rtype == rsilver) add_spende(ua->faction, u->faction, give, r); if (cost <= 0) break; @@ -1818,16 +1820,17 @@ const attrib_type at_luxuries = { static void expandbuying(region * r, request * buyorders) { - int max_products; - unit *u; - static struct trade { - const luxury_type *type; - int number; - int multi; - } *trades, *trade; - static int ntrades = 0; - int i, j; - const luxury_type *ltype; + const resource_type *rsilver = get_resourcetype(R_SILVER); + int max_products; + unit *u; + static struct trade { + const luxury_type *type; + int number; + int multi; + } *trades, *trade; + static int ntrades = 0; + int i, j; + const luxury_type *ltype; if (ntrades == 0) { for (ltype = luxurytypes; ltype; ltype = ltype->next) @@ -1869,7 +1872,7 @@ static void expandbuying(region * r, request * buyorders) multi = trade->multi; price = ltype->price * multi; - if (get_pooled(oa[j].unit, get_resourcetype(R_SILVER), GET_DEFAULT, + if (get_pooled(oa[j].unit, rsilver, GET_DEFAULT, price) >= price) { unit *u = oa[j].unit; item *items; @@ -1886,7 +1889,7 @@ static void expandbuying(region * r, request * buyorders) i_change(&items, ltype->itype, 1); a->data.v = items; i_change(&oa[j].unit->items, ltype->itype, 1); - use_pooled(u, get_resourcetype(R_SILVER), GET_DEFAULT, price); + use_pooled(u, rsilver, GET_DEFAULT, price); if (u->n < 0) u->n = 0; u->n += price; @@ -2371,11 +2374,13 @@ static bool sell(unit * u, request ** sellorders, struct order *ord) static void expandstealing(region * r, request * stealorders) { - int i; + const resource_type *rsilver = get_resourcetype(R_SILVER); + int i; + + assert(rsilver); - expandorders(r, stealorders); - if (!norders) - return; + expandorders(r, stealorders); + if (!norders) return; /* Für jede unit in der Region wird Geld geklaut, wenn sie Opfer eines * Beklauen-Orders ist. Jedes Opfer muß einzeln behandelt werden. @@ -2387,7 +2392,7 @@ static void expandstealing(region * r, request * stealorders) unit *u = findunitg(oa[i].no, r); int n = 0; if (u && u->region == r) { - n = get_pooled(u, r_silver, GET_ALL, INT_MAX); + n = get_pooled(u, rsilver, GET_ALL, INT_MAX); } #ifndef GOBLINKILL if (oa[i].type.goblin) { /* Goblin-Spezialklau */ @@ -2409,7 +2414,7 @@ static void expandstealing(region * r, request * stealorders) } if (n > 0) { n = _min(n, oa[i].unit->wants); - use_pooled(u, r_silver, GET_ALL, n); + use_pooled(u, rsilver, GET_ALL, n); oa[i].unit->n = n; change_money(oa[i].unit, n); ADDMSG(&u->faction->msgs, msg_message("stealeffect", "unit region amount", @@ -2424,60 +2429,58 @@ static void expandstealing(region * r, request * stealorders) /* ------------------------------------------------------------- */ static void plant(region * r, unit * u, int raw) { - int n, i, skill, planted = 0; - const item_type *itype; - static const resource_type *rt_water = NULL; - if (rt_water == NULL) - rt_water = rt_find("p2"); + int n, i, skill, planted = 0; + const item_type *itype; + const resource_type *rt_water = get_resourcetype(R_WATER_OF_LIFE); - assert(rt_water != NULL); - if (!fval(r->terrain, LAND_REGION)) { - return; - } - if (rherbtype(r) == NULL) { - cmistake(u, u->thisorder, 108, MSG_PRODUCE); - return; - } - - /* Skill prüfen */ - skill = eff_skill(u, SK_HERBALISM, r); - itype = rherbtype(r); - if (skill < 6) { - ADDMSG(&u->faction->msgs, - msg_feedback(u, u->thisorder, "plant_skills", - "skill minskill product", SK_HERBALISM, 6, itype->rtype, 1)); - return; - } - /* Wasser des Lebens prüfen */ - if (get_pooled(u, rt_water, GET_DEFAULT, 1) == 0) { - ADDMSG(&u->faction->msgs, - msg_feedback(u, u->thisorder, "resource_missing", "missing", rt_water)); - return; - } - n = get_pooled(u, itype->rtype, GET_DEFAULT, skill * u->number); - /* Kräuter prüfen */ - if (n == 0) { - ADDMSG(&u->faction->msgs, - msg_feedback(u, u->thisorder, "resource_missing", "missing", - itype->rtype)); - return; - } - - n = _min(skill * u->number, n); - n = _min(raw, n); - /* Für jedes Kraut Talent*10% Erfolgschance. */ - for (i = n; i > 0; i--) { - if (rng_int() % 10 < skill) - planted++; - } - produceexp(u, SK_HERBALISM, u->number); - - /* Alles ok. Abziehen. */ - use_pooled(u, rt_water, GET_DEFAULT, 1); - use_pooled(u, itype->rtype, GET_DEFAULT, n); - rsetherbs(r, rherbs(r) + planted); - ADDMSG(&u->faction->msgs, msg_message("plant", "unit region amount herb", - u, r, planted, itype->rtype)); + assert(rt_water != NULL); + if (!fval(r->terrain, LAND_REGION)) { + return; + } + if (rherbtype(r) == NULL) { + cmistake(u, u->thisorder, 108, MSG_PRODUCE); + return; + } + + /* Skill prüfen */ + skill = eff_skill(u, SK_HERBALISM, r); + itype = rherbtype(r); + if (skill < 6) { + ADDMSG(&u->faction->msgs, + msg_feedback(u, u->thisorder, "plant_skills", + "skill minskill product", SK_HERBALISM, 6, itype->rtype, 1)); + return; + } + /* Wasser des Lebens prüfen */ + if (get_pooled(u, rt_water, GET_DEFAULT, 1) == 0) { + ADDMSG(&u->faction->msgs, + msg_feedback(u, u->thisorder, "resource_missing", "missing", rt_water)); + return; + } + n = get_pooled(u, itype->rtype, GET_DEFAULT, skill * u->number); + /* Kräuter prüfen */ + if (n == 0) { + ADDMSG(&u->faction->msgs, + msg_feedback(u, u->thisorder, "resource_missing", "missing", + itype->rtype)); + return; + } + + n = _min(skill * u->number, n); + n = _min(raw, n); + /* Für jedes Kraut Talent*10% Erfolgschance. */ + for (i = n; i > 0; i--) { + if (rng_int() % 10 < skill) + planted++; + } + produceexp(u, SK_HERBALISM, u->number); + + /* Alles ok. Abziehen. */ + use_pooled(u, rt_water, GET_DEFAULT, 1); + use_pooled(u, itype->rtype, GET_DEFAULT, n); + rsetherbs(r, rherbs(r) + planted); + ADDMSG(&u->faction->msgs, msg_message("plant", "unit region amount herb", + u, r, planted, itype->rtype)); } static void planttrees(region * r, unit * u, int raw) @@ -2607,22 +2610,24 @@ static void breedhorses(region * r, unit * u) int n, c, breed = 0; struct building *b = inside_building(u); const struct building_type *btype = b ? b->type : NULL; - const struct item_type *ihorse = it_find("horse"); - - assert(ihorse); + const struct resource_type *rhorse = get_resourcetype(R_HORSE); + int horses; + assert(rhorse && rhorse->itype); if (btype != bt_find("stables")) { cmistake(u, u->thisorder, 122, MSG_PRODUCE); return; } - if (i_get(u->items, ihorse) < 2) { + horses = i_get(u->items, rhorse->itype); + if (horses < 2) { cmistake(u, u->thisorder, 107, MSG_PRODUCE); return; } - n = _min(u->number * eff_skill(u, SK_HORSE_TRAINING, r), i_get(u->items, ihorse)); + n = u->number * eff_skill(u, SK_HORSE_TRAINING, r); + n = _min(n, horses); for (c = 0; c < n; c++) { if (rng_int() % 100 < eff_skill(u, SK_HORSE_TRAINING, r)) { - i_change(&u->items, ihorse, 1); + i_change(&u->items, rhorse->itype, 1); ++breed; } } diff --git a/src/give.c b/src/give.c index 1124c2dd8..8c91e8f2a 100644 --- a/src/give.c +++ b/src/give.c @@ -89,7 +89,7 @@ add_give(unit * u, unit * u2, int given, int received, static bool limited_give(const item_type * type) { /* trade only money 2:1, if at all */ - return (type == i_silver); + return (type->rtype == get_resourcetype(R_SILVER)); } int give_quota(const unit * src, const unit * dst, const item_type * type, @@ -426,7 +426,7 @@ void give_unit(unit * u, unit * u2, order * ord) cmistake(u, ord, 156, MSG_COMMERCE); return; } - add_give(u, u2, 1, 1, r_unit, ord, 0); + add_give(u, u2, 1, 1, get_resourcetype(R_UNIT), ord, 0); u_setfaction(u, u2->faction); u2->faction->newbies += n; } diff --git a/src/items/weapons.c b/src/items/weapons.c index 02d6abff4..acb14fb18 100644 --- a/src/items/weapons.c +++ b/src/items/weapons.c @@ -88,79 +88,78 @@ static bool attack_catapult(const troop * at, const struct weapon_type *wtype, int *casualties) { - fighter *af = at->fighter; - unit *au = af->unit; - battle *b = af->side->battle; - troop dt; - int d = 0, enemies; - weapon *wp = af->person[at->index].missile; - static item_type *it_catapultammo = NULL; - if (it_catapultammo == NULL) { + fighter *af = at->fighter; + unit *au = af->unit; + battle *b = af->side->battle; + troop dt; + int d = 0, enemies; + weapon *wp = af->person[at->index].missile; + item_type *it_catapultammo = NULL; + + assert(wp->type == wtype); + assert(af->person[at->index].reload == 0); + it_catapultammo = it_find("catapultammo"); - } - - assert(wp->type == wtype); - assert(af->person[at->index].reload == 0); - - if (it_catapultammo != NULL) { - if (get_pooled(au, it_catapultammo->rtype, - GET_SLACK | GET_RESERVE | GET_POOLED_SLACK, 1) <= 0) { - /* No ammo. Use other weapon if available. */ - return true; + if (it_catapultammo != NULL) { + if (get_pooled(au, it_catapultammo->rtype, + GET_SLACK | GET_RESERVE | GET_POOLED_SLACK, 1) <= 0) { + /* No ammo. Use other weapon if available. */ + return true; + } } - } - enemies = count_enemies(b, af, FIGHT_ROW, FIGHT_ROW, SELECT_ADVANCE); - enemies = _min(enemies, CATAPULT_ATTACKS); - if (enemies == 0) { - return true; /* allow further attacks */ - } - - if (af->catmsg == -1) { - int i, k = 0; - message *msg; - - for (i = 0; i <= at->index; ++i) { - if (af->person[i].reload == 0 && af->person[i].missile == wp) - ++k; + enemies = count_enemies(b, af, FIGHT_ROW, FIGHT_ROW, SELECT_ADVANCE); + enemies = _min(enemies, CATAPULT_ATTACKS); + if (enemies == 0) { + return true; /* allow further attacks */ } - msg = msg_message("battle::usecatapult", "amount unit", k, au); - message_all(b, msg); - msg_release(msg); - af->catmsg = 0; - } - - if (it_catapultammo != NULL) { - use_pooled(au, it_catapultammo->rtype, - GET_SLACK | GET_RESERVE | GET_POOLED_SLACK, 1); - } - - while (--enemies >= 0) { - /* Select defender */ - dt = select_enemy(af, FIGHT_ROW, FIGHT_ROW, SELECT_ADVANCE); - if (!dt.fighter) - break; - - /* If battle succeeds */ - if (hits(*at, dt, wp)) { - d += terminate(dt, *at, AT_STANDARD, wp->type->damage[0], true); + + if (af->catmsg == -1) { + int i, k = 0; + message *msg; + + for (i = 0; i <= at->index; ++i) { + if (af->person[i].reload == 0 && af->person[i].missile == wp) + ++k; + } + msg = msg_message("battle::usecatapult", "amount unit", k, au); + message_all(b, msg); + msg_release(msg); + af->catmsg = 0; + } + + if (it_catapultammo != NULL) { + use_pooled(au, it_catapultammo->rtype, + GET_SLACK | GET_RESERVE | GET_POOLED_SLACK, 1); + } + + while (--enemies >= 0) { + /* Select defender */ + dt = select_enemy(af, FIGHT_ROW, FIGHT_ROW, SELECT_ADVANCE); + if (!dt.fighter) + break; + + /* If battle succeeds */ + if (hits(*at, dt, wp)) { + d += terminate(dt, *at, AT_STANDARD, wp->type->damage[0], true); #ifdef CATAPULT_STRUCTURAL_DAMAGE - if (dt.fighter->unit->building && rng_int() % 100 < 5) { - float dmg = - get_param_flt(global.parameters, "rules.building.damage.catapult", 1); - damage_building(b, dt.fighter->unit->building, dmg); - } else if (dt.fighter->unit->ship && rng_int() % 100 < 5) { - float dmg = - get_param_flt(global.parameters, "rules.ship.damage.catapult", 0.01); - damage_ship(dt.fighter->unit->ship, dmg) - } + if (dt.fighter->unit->building && rng_int() % 100 < 5) { + float dmg = + get_param_flt(global.parameters, "rules.building.damage.catapult", 1); + damage_building(b, dt.fighter->unit->building, dmg); + } else if (dt.fighter->unit->ship && rng_int() % 100 < 5) { + float dmg = + get_param_flt(global.parameters, "rules.ship.damage.catapult", 0.01); + damage_ship(dt.fighter->unit->ship, dmg) + } #endif + } } - } - - if (casualties) - *casualties = d; - return false; /* keine weitren attacken */ + + if (casualties) { + *casualties = d; + } + return false; /* keine weitren attacken */ } void register_weapons(void) diff --git a/src/kernel/battle.c b/src/kernel/battle.c index db2a73cd4..b0bc49e39 100644 --- a/src/kernel/battle.c +++ b/src/kernel/battle.c @@ -2314,40 +2314,35 @@ static void add_tactics(tactics * ta, fighter * fig, int value) static double horsebonus(const unit * u) { - static const item_type *it_horse = 0; - static const item_type *it_elvenhorse = 0; - static const item_type *it_charger = 0; - region *r = u->region; - int n1 = 0, n2 = 0, n3 = 0; - item *itm = u->items; - int skl = eff_skill(u, SK_RIDING, r); + const item_type *it_horse, *it_elvenhorse, *it_charger; + int n1 = 0, n2 = 0, n3 = 0; + item *itm; + int skl = eff_skill(u, SK_RIDING, u->region); + const resource_type *rtype; + + if (skl < 1) return 0.0; + + it_horse = (rtype = get_resourcetype(R_HORSE)) ? rtype->itype : 0; + it_elvenhorse = (rtype = get_resourcetype(R_UNICORN)) ? rtype->itype : 0; + it_charger = (rtype = get_resourcetype(R_CHARGER)) ? rtype->itype : 0; - if (skl < 1) - return 0.0; - - if (it_horse == 0) { - it_horse = it_find("horse"); - it_elvenhorse = it_find("elvenhorse"); - it_charger = it_find("charger"); - } - - for (; itm; itm = itm->next) { - if (itm->type->flags & ITF_ANIMAL) { - if (itm->type == it_elvenhorse) - n3 += itm->number; - else if (itm->type == it_charger) - n2 += itm->number; - else if (itm->type == it_horse) - n1 += itm->number; + for (itm=u->items; itm; itm = itm->next) { + if (itm->type->flags & ITF_ANIMAL) { + if (itm->type == it_elvenhorse) + n3 += itm->number; + else if (itm->type == it_charger) + n2 += itm->number; + else if (itm->type == it_horse) + n1 += itm->number; + } } - } - if (skl >= 5 && n3 >= u->number) - return 0.30; - if (skl >= 3 && n2 + n3 >= u->number) - return 0.20; - if (skl >= 1 && n1 + n2 + n3 >= u->number) - return 0.10; - return 0.0F; + if (skl >= 5 && n3 >= u->number) + return 0.30; + if (skl >= 3 && n2 + n3 >= u->number) + return 0.20; + if (skl >= 1 && n1 + n2 + n3 >= u->number) + return 0.10; + return 0.0F; } double fleechance(unit * u) diff --git a/src/kernel/config.c b/src/kernel/config.c index b0e904320..bb7d1e19b 100644 --- a/src/kernel/config.c +++ b/src/kernel/config.c @@ -830,15 +830,8 @@ cansee(const faction * f, const region * r, const unit * u, int modifier) /* und es muss niemand aus f in der region sein, wenn sie vom Turm * erblickt wird */ { - int stealth, rings; - unit *u2 = r->units; - static const item_type *itype_grail; - static bool init; - - if (!init) { - init = true; - itype_grail = it_find("grail"); - } + int stealth, rings; + unit *u2 = r->units; if (u->faction == f || omniscient(f)) { return true; @@ -856,8 +849,6 @@ cansee(const faction * f, const region * r, const unit * u, int modifier) if (leftship(u)) return true; - if (itype_grail != NULL && i_get(u->items, itype_grail)) - return true; while (u2 && u2->faction != f) u2 = u2->next; diff --git a/src/kernel/item.c b/src/kernel/item.c index e0a72453b..4fae67893 100644 --- a/src/kernel/item.c +++ b/src/kernel/item.c @@ -190,22 +190,24 @@ void it_register(item_type * itype) item_type *new_itemtype(resource_type * rtype, int iflags, int weight, int capacity) { - item_type *itype; - assert(resource2item(rtype) == NULL); - assert(rtype->flags & RTF_ITEM); + item_type *itype; - itype = calloc(sizeof(item_type), 1); - - itype->rtype = rtype; - rtype->itype = itype; - itype->weight = weight; - itype->capacity = capacity; - itype->flags |= iflags; - it_register(itype); - - rtype->uchange = res_changeitem; - - return itype; + assert(!rtype->itype); + assert(!rtype->uchange || rtype->uchange==res_changeitem); + + itype = calloc(sizeof(item_type), 1); + + itype->rtype = rtype; + itype->weight = weight; + itype->capacity = capacity; + itype->flags |= iflags; + it_register(itype); + + rtype->itype = itype; + rtype->flags |= RTF_ITEM; + rtype->uchange = res_changeitem; + + return itype; } static void lt_register(luxury_type * ltype) @@ -295,15 +297,18 @@ potion_type *new_potiontype(item_type * itype, int level) return ptype; } +static int num_resources; + void rt_register(resource_type * rtype) { - char buffer[64]; - const char * name = rtype->_name[0]; - size_t len = strlen(name); - - assert(len_name[0]; + size_t len = strlen(name); + + assert(lenuchange = res_changepeasants; + + // R_SILVER + rtype = rt_find(names[0]); + if (!rtype) { + rtype = new_resourcetype(&names[0], NULL, RTF_ITEM | RTF_POOLED); + rt_register(rtype); + } + rtype->uchange = res_changeitem; + itype = rtype->itype; + if (!itype) { + itype = new_itemtype(rtype, ITF_NONE, 1 /*weight */ , 0); + } + itype->give = give_money; - rtype = new_resourcetype(names + 8, NULL, RTF_NONE); - rtype->uchange = res_changepeasants; - rt_register(rtype); + // R_PERMAURA + rtype = rt_find(names[4]); + if (!rtype) { + rtype = new_resourcetype(&names[4], NULL, RTF_NONE); + rt_register(rtype); + } + rtype->uchange = res_changepermaura; + + // R_LIFE + rtype = rt_find(names[6]); + if (!rtype) { + rtype = new_resourcetype(&names[6], NULL, RTF_NONE); + rt_register(rtype); + } + rtype->uchange = res_changehp; + + // R_AURA + rtype = rt_find(names[10]); + if (!rtype) { + rtype = new_resourcetype(&names[10], NULL, RTF_NONE); + rt_register(rtype); + } + rtype->uchange = res_changeaura; - r_silver = new_resourcetype(&names[0], NULL, RTF_ITEM | RTF_POOLED); - i_silver = new_itemtype(r_silver, ITF_NONE, 1 /*weight */ , 0); - r_silver->uchange = res_changeitem; - i_silver->give = give_money; - rt_register(r_silver); - - r_permaura = new_resourcetype(&names[4], NULL, RTF_NONE); - r_permaura->uchange = res_changepermaura; - rt_register(r_permaura); - - r_hp = new_resourcetype(&names[6], NULL, RTF_NONE); - r_hp->uchange = res_changehp; - rt_register(r_hp); - - r_aura = new_resourcetype(&names[10], NULL, RTF_NONE); - r_aura->uchange = res_changeaura; - rt_register(r_aura); - - r_unit = new_resourcetype(&names[12], NULL, RTF_NONE); - r_unit->uchange = res_changeperson; - rt_register(r_unit); - - /* alte typen registrieren: */ - init_oldpotions(); + // R_UNIT + rtype = rt_find(names[12]); + if (!rtype) { + rtype = new_resourcetype(&names[12], NULL, RTF_NONE); + rt_register(rtype); + } + rtype->uchange = res_changeperson; + + /* alte typen registrieren: */ + init_oldpotions(); } int get_money(const unit * u) { - const item *i = u->items; - while (i && i->type != i_silver) - i = i->next; - if (i == NULL) - return 0; - return i->number; + const struct resource_type *rtype = get_resourcetype(R_SILVER); + const item *i = u->items; + while (i && i->type->rtype != rtype) { + i = i->next; + } + return i ? i->number : 0; } int set_money(unit * u, int v) { - item **ip = &u->items; - while (*ip && (*ip)->type != i_silver) - ip = &(*ip)->next; - if ((*ip) == NULL && v) { - i_add(&u->items, i_new(i_silver, v)); + const struct resource_type *rtype = get_resourcetype(R_SILVER); + item **ip = &u->items; + while (*ip && (*ip)->type->rtype != rtype) { + ip = &(*ip)->next; + } + if ((*ip) == NULL && v) { + i_add(&u->items, i_new(rtype->itype, v)); + return v; + } + if ((*ip) != NULL) { + if (v) { + (*ip)->number = v; + assert((*ip)->number >= 0); + } else { + i_remove(ip, *ip); + } + } return v; - } - if ((*ip) != NULL) { - if (v) { - (*ip)->number = v; - assert((*ip)->number >= 0); - } else - i_remove(ip, *ip); - } - return v; } int change_money(unit * u, int v) { - item **ip = &u->items; - while (*ip && (*ip)->type != i_silver) - ip = &(*ip)->next; - if ((*ip) == NULL && v) { - i_add(&u->items, i_new(i_silver, v)); - return v; - } - if ((*ip) != NULL) { - item *i = *ip; - if (i->number + v != 0) { - i->number += v; - assert(i->number >= 0); - return i->number; - } else - i_free(i_remove(ip, *ip)); - } - return 0; + const struct resource_type *rtype = get_resourcetype(R_SILVER); + item **ip = &u->items; + while (*ip && (*ip)->type->rtype != rtype) { + ip = &(*ip)->next; + } + if ((*ip) == NULL && v) { + i_add(&u->items, i_new(rtype->itype, v)); + return v; + } + if ((*ip) != NULL) { + item *i = *ip; + if (i->number + v != 0) { + i->number += v; + assert(i->number >= 0); + return i->number; + } else { + i_free(i_remove(ip, *ip)); + } + } + return 0; } static int add_resourcename_cb(const void * match, const void * key, size_t keylen, void *data) @@ -1187,21 +1223,19 @@ int free_rtype_cb(const void * match, const void * key, size_t keylen, void *cbd void test_clear_resources(void) { - int i; + int i; - memset((void *)oldpotiontype, 0, sizeof(oldpotiontype)); - - cb_foreach(&cb_items, "", 0, free_itype_cb, 0); - cb_clear(&cb_items); - cb_foreach(&cb_resources, "", 0, free_rtype_cb, 0); - cb_clear(&cb_resources); - - r_hp = r_silver = r_aura = r_permaura = r_unit = 0; - i_silver = 0; - - for (i=0; i!=MAXLOCALES; ++i) { - cb_clear(inames+i); - } + memset((void *)oldpotiontype, 0, sizeof(oldpotiontype)); + + cb_foreach(&cb_items, "", 0, free_itype_cb, 0); + cb_clear(&cb_items); + cb_foreach(&cb_resources, "", 0, free_rtype_cb, 0); + cb_clear(&cb_resources); + ++num_resources; + + for (i=0; i!=MAXLOCALES; ++i) { + cb_clear(inames+i); + } } #endif diff --git a/src/kernel/item.h b/src/kernel/item.h index 6e2427d6d..50eb8959d 100644 --- a/src/kernel/item.h +++ b/src/kernel/item.h @@ -265,20 +265,12 @@ extern "C" { double magres, int prot, unsigned int flags); extern potion_type *new_potiontype(item_type * itype, int level); -/* for lack of another file: */ - -/* sonstige resourcen */ - extern resource_type *r_silver; - extern resource_type *r_aura; - extern resource_type *r_permaura; - extern resource_type *r_unit; - typedef enum { /* ITEMS: */ R_IRON, R_STONE, R_HORSE, - /**/ R_AMULET_OF_HEALING, + R_AMULET_OF_HEALING, R_AMULET_OF_TRUE_SEEING, R_RING_OF_INVISIBILITY, R_RING_OF_POWER, @@ -288,6 +280,7 @@ extern "C" { R_BIRTHDAYAMULET, R_PEGASUS, R_UNICORN, + R_CHARGER, R_DOLPHIN, R_RING_OF_NIMBLEFINGER, R_TROLLBELT, @@ -296,11 +289,15 @@ extern "C" { R_BAG_OF_HOLDING, R_SACK_OF_CONSERVATION, R_TACTICCRYSTAL, + R_WATER_OF_LIFE, /* SONSTIGE */ R_SILVER, R_AURA, /* Aura */ R_PERMAURA, /* Permanente Aura */ + R_LIFE, + R_UNIT, + R_PEASANT, MAX_RESOURCES, /* do not use outside item.c ! */ NORESOURCE = -1 @@ -326,8 +323,6 @@ extern "C" { extern void register_item_useonother(int (*foo) (struct unit *, int, const struct item_type *, int, struct order *), const char *name); - extern struct item_type *i_silver; - #ifndef DISABLE_TESTS void test_clear_resources(void); #endif diff --git a/src/kernel/item.test.c b/src/kernel/item.test.c index db4acff26..e33cc3015 100644 --- a/src/kernel/item.test.c +++ b/src/kernel/item.test.c @@ -45,7 +45,7 @@ void test_change_person(CuTest * tc) test_create_world(); u = test_create_unit(0, 0); - test_uchange(tc, u, r_unit); + test_uchange(tc, u, get_resourcetype(R_UNIT)); } void test_resource_type(CuTest * tc) diff --git a/src/kernel/magic.c b/src/kernel/magic.c index d95519687..9b1682bfa 100644 --- a/src/kernel/magic.c +++ b/src/kernel/magic.c @@ -777,8 +777,9 @@ int countspells(unit * u, int step) */ int spellcost(unit * u, const spell * sp) { - int k, aura = 0; - int count = countspells(u, 0); + int k, aura = 0; + int count = countspells(u, 0); + const resource_type *r_aura = get_resourcetype(R_AURA); for (k = 0; sp->components[k].type; k++) { if (sp->components[k].type == r_aura) { @@ -826,8 +827,9 @@ static int spl_costtyp(const spell * sp) * */ int eff_spelllevel(unit * u, const spell * sp, int cast_level, int range) { - int k, maxlevel, needplevel; - int costtyp = SPC_FIX; + const resource_type *r_aura = get_resourcetype(R_AURA); + int k, maxlevel, needplevel; + int costtyp = SPC_FIX; for (k = 0; sp->components[k].type; k++) { if (cast_level == 0) @@ -888,8 +890,9 @@ int eff_spelllevel(unit * u, const spell * sp, int cast_level, int range) */ void pay_spell(unit * u, const spell * sp, int cast_level, int range) { - int k; - int resuse; + const resource_type *r_aura = get_resourcetype(R_AURA); + int k; + int resuse; assert(cast_level>0); for (k = 0; sp->components[k].type; k++) { @@ -934,9 +937,10 @@ bool knowsspell(const region * r, const unit * u, const spell * sp) bool cancast(unit * u, const spell * sp, int level, int range, struct order * ord) { - int k; - int itemanz; - resource *reslist = NULL; + const resource_type *r_aura = get_resourcetype(R_AURA); + int k; + int itemanz; + resource *reslist = NULL; if (!knowsspell(u->region, u, sp)) { /* Diesen Zauber kennt die Einheit nicht */ diff --git a/src/kernel/move.c b/src/kernel/move.c index e0c3b5fbd..2dfebc02e 100644 --- a/src/kernel/move.c +++ b/src/kernel/move.c @@ -412,18 +412,15 @@ bool canswim(unit * u) static int canride(unit * u) { - int horses = 0, maxhorses, unicorns = 0, maxunicorns; - int skill = effskill(u, SK_RIDING); - item *itm; - static const item_type *it_horse = 0; - static const item_type *it_elvenhorse = 0; - static const item_type *it_charger = 0; + int horses = 0, maxhorses, unicorns = 0, maxunicorns; + int skill = effskill(u, SK_RIDING); + item *itm; + const item_type *it_horse, *it_elvenhorse, *it_charger; + const resource_type *rtype; - if (it_horse == 0) { - it_horse = it_find("horse"); - it_elvenhorse = it_find("elvenhorse"); - it_charger = it_find("charger"); - } + it_horse = (rtype = get_resourcetype(R_HORSE)) ? rtype->itype : 0; + it_elvenhorse = (rtype = get_resourcetype(R_UNICORN)) ? rtype->itype : 0; + it_charger = (rtype = get_resourcetype(R_CHARGER)) ? rtype->itype : 0; for (itm = u->items; itm; itm = itm->next) { if (itm->type == it_horse || itm->type == it_charger) { @@ -839,26 +836,26 @@ static void caught_target(region * r, unit * u) static unit *bewegung_blockiert_von(unit * reisender, region * r) { - unit *u; - double prob = 0.0; - bool contact = false; - unit *guard = NULL; - int stealth = eff_stealth(reisender, r); - static int gamecookie = -1; - static double base_prob = -999; - static double skill_prob = -999; - static double amulet_prob = -999; - const struct item_type *iamulet = it_find("aots"); + unit *u; + double prob = 0.0; + bool contact = false; + unit *guard = NULL; + int stealth = eff_stealth(reisender, r); + static int gamecookie = -1; + static double base_prob = -999; + static double skill_prob = -999; + static double amulet_prob = -999; + const struct resource_type *ramulet = get_resourcetype(R_AMULET_OF_TRUE_SEEING); - if (gamecookie < 0 || gamecookie != global.cookie) { - base_prob = - get_param_flt(global.parameters, "rules.guard.base_stop_prob", .3); - skill_prob = - get_param_flt(global.parameters, "rules.guard.skill_stop_prob", .1); - amulet_prob = - get_param_flt(global.parameters, "rules.guard.amulet_stop_prob", .1); - gamecookie = global.cookie; - } + if (gamecookie < 0 || gamecookie != global.cookie) { + base_prob = + get_param_flt(global.parameters, "rules.guard.base_stop_prob", .3); + skill_prob = + get_param_flt(global.parameters, "rules.guard.skill_stop_prob", .1); + amulet_prob = + get_param_flt(global.parameters, "rules.guard.amulet_stop_prob", .1); + gamecookie = global.cookie; + } if (fval(u_race(reisender), RCF_ILLUSIONARY)) return NULL; @@ -876,7 +873,7 @@ static unit *bewegung_blockiert_von(unit * reisender, region * r) else if (sk >= stealth) { double prob_u = (sk - stealth) * skill_prob; /* amulet counts at most once */ - prob_u += _min (1, _min(u->number, i_get(u->items, iamulet))) * amulet_prob; + prob_u += _min (1, _min(u->number, i_get(u->items, ramulet->itype))) * amulet_prob; if (prob_u >= prob) { prob = prob_u; guard = u; diff --git a/src/kernel/region.c b/src/kernel/region.c index d7eeea3c2..5ce29b6c8 100644 --- a/src/kernel/region.c +++ b/src/kernel/region.c @@ -1015,11 +1015,11 @@ void region_setresource(region * r, const resource_type * rtype, int value) rm = rm->next; } if (!rm) { - if (rtype == rt_find("money")) + if (rtype == get_resourcetype(R_SILVER)) rsetmoney(r, value); - else if (rtype == rt_find("peasant")) + else if (rtype == get_resourcetype(R_PEASANT)) rsetpeasants(r, value); - else if (rtype == rt_find("horse")) + else if (rtype == get_resourcetype(R_HORSE)) rsethorses(r, value); else { int i; @@ -1042,11 +1042,11 @@ int region_getresource(const region * r, const resource_type * rtype) return rm->amount; } } - if (rtype == rt_find("money")) + if (rtype == get_resourcetype(R_SILVER)) return rmoney(r); - if (rtype == rt_find("horse")) + if (rtype == get_resourcetype(R_HORSE)) return rhorses(r); - if (rtype == rt_find("peasant")) + if (rtype == get_resourcetype(R_PEASANT)) return rpeasants(r); return 0; } diff --git a/src/kernel/reports.c b/src/kernel/reports.c index fb6633be3..2817763b5 100644 --- a/src/kernel/reports.c +++ b/src/kernel/reports.c @@ -140,7 +140,9 @@ void report_item(const unit * owner, const item * i, const faction * viewer, const char **name, const char **basename, int *number, bool singular) { - assert(!owner || owner->number); + const resource_type *rsilver = get_resourcetype(R_SILVER); + + assert(!owner || owner->number); if (owner && owner->faction == viewer) { if (name) *name = @@ -150,7 +152,7 @@ report_item(const unit * owner, const item * i, const faction * viewer, *basename = resourcename(i->type->rtype, 0); if (number) *number = i->number; - } else if (owner && i->type->rtype == r_silver) { + } else if (owner && i->type->rtype == rsilver) { int pp = i->number / owner->number; if (number) *number = 1; diff --git a/src/kernel/unit.c b/src/kernel/unit.c index 6cda1943d..7b11c7175 100644 --- a/src/kernel/unit.c +++ b/src/kernel/unit.c @@ -220,28 +220,29 @@ static buddy *get_friends(const unit * u, int *numfriends) */ int gift_items(unit * u, int flags) { - region *r = u->region; - item **itm_p = &u->items; - int retval = 0; - int rule = rule_give(); + const struct resource_type *rsilver = get_resourcetype(R_SILVER); + region *r = u->region; + item **itm_p = &u->items; + int retval = 0; + int rule = rule_give(); + + assert(u->region); + assert(u->faction); - assert(u->region); - assert(u->faction); - - if ((u->faction->flags & FFL_QUIT) == 0 || (rule & GIVE_ONDEATH) == 0) { - if ((rule & GIVE_ALLITEMS) == 0 && (flags & GIFT_FRIENDS)) - flags -= GIFT_FRIENDS; - if ((rule & GIVE_PEASANTS) == 0 && (flags & GIFT_PEASANTS)) - flags -= GIFT_PEASANTS; - if ((rule & GIVE_SELF) == 0 && (flags & GIFT_SELF)) - flags -= GIFT_SELF; - } - - if (u->items == NULL || fval(u_race(u), RCF_ILLUSIONARY)) - return 0; - if ((u_race(u)->ec_flags & GIVEITEM) == 0) - return 0; + if ((u->faction->flags & FFL_QUIT) == 0 || (rule & GIVE_ONDEATH) == 0) { + if ((rule & GIVE_ALLITEMS) == 0 && (flags & GIFT_FRIENDS)) + flags -= GIFT_FRIENDS; + if ((rule & GIVE_PEASANTS) == 0 && (flags & GIFT_PEASANTS)) + flags -= GIFT_PEASANTS; + if ((rule & GIVE_SELF) == 0 && (flags & GIFT_SELF)) + flags -= GIFT_SELF; + } + if (u->items == NULL || fval(u_race(u), RCF_ILLUSIONARY)) + return 0; + if ((u_race(u)->ec_flags & GIVEITEM) == 0) + return 0; + /* at first, I should try giving my crap to my own units in this region */ if (u->faction && (u->faction->flags & FFL_QUIT) == 0 && (flags & GIFT_SELF)) { unit *u2, *u3 = NULL; @@ -303,7 +304,7 @@ int gift_items(unit * u, int flags) if (flags & GIFT_PEASANTS) { if (!fval(u->region->terrain, SEA_REGION)) { - if (itm->type == i_silver) { + if (itm->type->rtype == rsilver) { rsetmoney(r, rmoney(r) + itm->number); itm->number = 0; } @@ -1220,13 +1221,14 @@ static int item_modification(const unit * u, skill_t sk, int val) #endif } #if NEWATSROI == 1 - if (sk == SK_PERCEPTION) { - if (i_get(u->items, it_find("aots")) >= u->number) { - val += ATSBONUS; + if (sk == SK_PERCEPTION) { + const struct resource_type *rtype = get_resourcetype(R_AMULET_OF_TRUE_SEEING); + if (i_get(u->items, rtype->itype) >= u->number) { + val += ATSBONUS; + } } - } #endif - return val; + return val; } static int att_modification(const unit * u, skill_t sk) diff --git a/src/laws.c b/src/laws.c index c9a08ed30..9d2bf7398 100755 --- a/src/laws.c +++ b/src/laws.c @@ -292,13 +292,12 @@ void get_food(region * r) int hungry = u->number; /* use peasantblood before eating the peasants themselves */ - static const struct potion_type *pt_blood; - if (pt_blood == NULL) { - const item_type *it_blood = it_find("peasantblood"); - if (it_blood) + const struct potion_type *pt_blood = 0; + const item_type *it_blood = it_find("peasantblood"); + if (it_blood) { pt_blood = it_blood->rtype->ptype; } - if (pt_blood != NULL) { + if (pt_blood) { /* always start with the unit itself, then the first known unit that may have some blood */ unit *donor = u; while (donor != NULL && hungry > 0) { @@ -2694,6 +2693,7 @@ static void reshow(unit * u, struct order *ord, const char *s, param_t p) int promotion_cmd(unit * u, struct order *ord) { + const struct resource_type *rsilver = get_resourcetype(R_SILVER); int money, people; if (fval(u, UFL_HERO)) { @@ -2713,14 +2713,14 @@ int promotion_cmd(unit * u, struct order *ord) return 0; } people = count_all(u->faction) * u->number; - money = get_pooled(u, i_silver->rtype, GET_ALL, people); + money = get_pooled(u, rsilver, GET_ALL, people); if (people > money) { ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "heroes_cost", "cost have", people, money)); return 0; } - use_pooled(u, i_silver->rtype, GET_ALL, people); + use_pooled(u, rsilver, GET_ALL, people); fset(u, UFL_HERO); ADDMSG(&u->faction->msgs, msg_message("hero_promotion", "unit cost", u, people)); @@ -4327,86 +4327,82 @@ void process(void) int siege_cmd(unit * u, order * ord) { - region *r = u->region; - building *b; - int d, pooled; - int bewaffnete, katapultiere = 0; - static bool init = false; - static const curse_type *magicwalls_ct; - static item_type *it_catapultammo = NULL; - static item_type *it_catapult = NULL; - if (!init) { - init = true; + region *r = u->region; + building *b; + int d, pooled; + int bewaffnete, katapultiere = 0; + const curse_type *magicwalls_ct; + item_type *it_catapultammo = NULL; + item_type *it_catapult = NULL; + + init_tokens(ord); + skip_token(); + b = getbuilding(r); + + if (!b) { + cmistake(u, ord, 31, MSG_BATTLE); + return 31; + } + + if (!playerrace(u_race(u))) { + /* keine Drachen, Illusionen, Untote etc */ + cmistake(u, ord, 166, MSG_BATTLE); + return 166; + } + /* schaden durch katapulte */ + magicwalls_ct = ct_find("magicwalls"); it_catapultammo = it_find("catapultammo"); it_catapult = it_find("catapult"); - } - /* gibt es ueberhaupt Burgen? */ - init_tokens(ord); - skip_token(); - b = getbuilding(r); - - if (!b) { - cmistake(u, ord, 31, MSG_BATTLE); - return 31; - } - - if (!playerrace(u_race(u))) { - /* keine Drachen, Illusionen, Untote etc */ - cmistake(u, ord, 166, MSG_BATTLE); - return 166; - } - /* schaden durch katapulte */ - - d = i_get(u->items, it_catapult); - d = _min(u->number, d); - pooled = get_pooled(u, it_catapultammo->rtype, GET_DEFAULT, d); - d = _min(pooled, d); - if (eff_skill(u, SK_CATAPULT, r) >= 1) { - katapultiere = d; - d *= eff_skill(u, SK_CATAPULT, r); - } else { - d = 0; - } - - bewaffnete = armedmen(u, true); - if (d == 0 && bewaffnete == 0) { - /* abbruch, falls unbewaffnet oder unfaehig, katapulte zu benutzen */ - cmistake(u, ord, 80, MSG_EVENT); - return 80; - } - - if (!is_guard(u, GUARD_TRAVELTHRU)) { - /* abbruch, wenn die einheit nicht vorher die region bewacht - als - * warnung fuer alle anderen! */ - cmistake(u, ord, 81, MSG_EVENT); - return 81; - } - /* einheit und burg markieren - spart zeit beim behandeln der einheiten - * in der burg, falls die burg auch markiert ist und nicht alle - * einheiten wieder abgesucht werden muessen! */ - - usetsiege(u, b); - b->besieged += _max(bewaffnete, katapultiere); - - /* definitiver schaden eingeschraenkt */ - - d = _min(d, b->size - 1); - - /* meldung, schaden anrichten */ - if (d && !curse_active(get_curse(b->attribs, magicwalls_ct))) { - b->size -= d; - use_pooled(u, it_catapultammo->rtype, - GET_SLACK | GET_RESERVE | GET_POOLED_SLACK, d); - /* send message to the entire region */ - ADDMSG(&r->msgs, msg_message("siege_catapults", - "unit building destruction", u, b, d)); - } else { - /* send message to the entire region */ - ADDMSG(&r->msgs, msg_message("siege", "unit building", u, b)); - } - return 0; + d = i_get(u->items, it_catapult); + d = _min(u->number, d); + pooled = get_pooled(u, it_catapultammo->rtype, GET_DEFAULT, d); + d = _min(pooled, d); + if (eff_skill(u, SK_CATAPULT, r) >= 1) { + katapultiere = d; + d *= eff_skill(u, SK_CATAPULT, r); + } else { + d = 0; + } + + bewaffnete = armedmen(u, true); + if (d == 0 && bewaffnete == 0) { + /* abbruch, falls unbewaffnet oder unfaehig, katapulte zu benutzen */ + cmistake(u, ord, 80, MSG_EVENT); + return 80; + } + + if (!is_guard(u, GUARD_TRAVELTHRU)) { + /* abbruch, wenn die einheit nicht vorher die region bewacht - als + * warnung fuer alle anderen! */ + cmistake(u, ord, 81, MSG_EVENT); + return 81; + } + /* einheit und burg markieren - spart zeit beim behandeln der einheiten + * in der burg, falls die burg auch markiert ist und nicht alle + * einheiten wieder abgesucht werden muessen! */ + + usetsiege(u, b); + b->besieged += _max(bewaffnete, katapultiere); + + /* definitiver schaden eingeschraenkt */ + + d = _min(d, b->size - 1); + + /* meldung, schaden anrichten */ + if (d && !curse_active(get_curse(b->attribs, magicwalls_ct))) { + b->size -= d; + use_pooled(u, it_catapultammo->rtype, + GET_SLACK | GET_RESERVE | GET_POOLED_SLACK, d); + /* send message to the entire region */ + ADDMSG(&r->msgs, msg_message("siege_catapults", + "unit building destruction", u, b, d)); + } else { + /* send message to the entire region */ + ADDMSG(&r->msgs, msg_message("siege", "unit building", u, b)); + } + return 0; } void do_siege(region * r) diff --git a/src/report.c b/src/report.c index 6215c4e1c..c7b97e566 100644 --- a/src/report.c +++ b/src/report.c @@ -1450,6 +1450,7 @@ static int buildingmaintenance(const building * b, const resource_type * rtype) static int report_template(const char *filename, report_context * ctx, const char *charset) { + const resource_type *rsilver = get_resourcetype(R_SILVER); faction *f = ctx->f; region *r; FILE *F = fopen(filename, "wt"); @@ -1538,7 +1539,7 @@ report_template(const char *filename, report_context * ctx, const char *charset) WARN_STATIC_BUFFER(); if (u->building && building_owner(u->building)==u) { building *b = u->building; - int cost = buildingmaintenance(b, r_silver); + int cost = buildingmaintenance(b, rsilver); if (cost > 0) { bytes = (int)strlcpy(bufp, ",U", size); diff --git a/src/spells/spells.c b/src/spells/spells.c index cd2d6d03a..f983728d8 100644 --- a/src/spells/spells.c +++ b/src/spells/spells.c @@ -4087,13 +4087,13 @@ static int sp_pump(castorder * co) */ static int sp_seduce(castorder * co) { - item *items = NULL; - unit *target; - item **itmp; - unit *mage = co->magician.u; - spellparameter *pa = co->par; - int cast_level = co->level; - float force = co->force; + const resource_type *rsilver = get_resourcetype(R_SILVER); + unit *target; + item **itmp, *items = 0;; + unit *mage = co->magician.u; + spellparameter *pa = co->par; + int cast_level = co->level; + float force = co->force; /* wenn kein Ziel gefunden, Zauber abbrechen */ if (pa->param[0]->flag == TARGET_NOTFOUND) @@ -4113,7 +4113,7 @@ static int sp_seduce(castorder * co) while (*itmp) { item *itm = *itmp; int loot; - if (itm->type == i_silver) { + if (itm->type->rtype == rsilver) { loot = _min(cast_level * 1000, get_money(target) - (maintenance_cost(target))); loot = _max(loot, 0); diff --git a/src/summary.c b/src/summary.c index 0b4bebbcb..da851c2e1 100644 --- a/src/summary.c +++ b/src/summary.c @@ -314,7 +314,7 @@ summary *make_summary(void) region *r; unit *u; summary *s = calloc(1, sizeof(summary)); - const struct item_type *ihorse = it_find("horse"); + const struct resource_type *rhorse = get_resourcetype(R_HORSE); for (f = factions; f; f = f->next) { const struct locale *lang = f->locale; @@ -384,7 +384,7 @@ summary *make_summary(void) if (u->flags & UFL_HERO) { s->heroes += u->number; } - s->spielerpferde += i_get(u->items, ihorse); + s->spielerpferde += i_get(u->items, rhorse->itype); s->playermoney += get_money(u); s->armed_men += armedmen(u, true); for (itm = u->items; itm; itm = itm->next) { @@ -396,7 +396,7 @@ summary *make_summary(void) } } - s->spielerpferde += i_get(u->items, ihorse); + s->spielerpferde += i_get(u->items, rhorse->itype); for (sv = u->skills; sv != u->skills + u->skill_size; ++sv) { skill_t sk = sv->id;