static quicklist * get_island(region * root) { quicklist * ql, *result = 0; int qi = 0; fset(root, RF_MARK); ql_push(&result, root); for (ql = result, qi = 0; ql; ql_advance(&ql, &qi, 1)) { int dir; region *r = (region *)ql_get(ql, qi); region * next[MAXDIRECTIONS]; get_neighbours(r, next); for (dir = 0; dir != MAXDIRECTIONS; ++dir) { region *rn = next[dir]; if (rn != NULL && rn->land && !fval(rn, RF_MARK)) { fset(rn, RF_MARK); ql_push(&result, rn); } } } for (ql = result, qi = 0; ql; ql_advance(&ql, &qi, 1)) { region *r = (region *)ql_get(ql, qi); freset(r, RF_MARK); } return result; }
const ship_type *findshiptype(const char *name, const struct locale *lang) { local_names *sn = snames; variant var; while (sn) { if (sn->lang == lang) break; sn = sn->next; } if (!sn) { quicklist *ql; int qi; sn = (local_names *)calloc(sizeof(local_names), 1); sn->next = snames; sn->lang = lang; for (qi = 0, ql = shiptypes; ql; ql_advance(&ql, &qi, 1)) { ship_type *stype = (ship_type *)ql_get(ql, qi); variant var2; const char *n = LOC(lang, stype->_name); var2.v = (void *)stype; addtoken(&sn->names, n, var2); } snames = sn; } if (findtoken(sn->names, name, &var) == E_TOK_NOMATCH) return NULL; return (const ship_type *)var.v; }
/* Find the building type for a given localized name (as seen by the user). Useful for parsing * orders. The inverse of locale_string(lang, btype->_name), sort of. */ const building_type *findbuildingtype(const char *name, const struct locale *lang) { variant type; local_names *bn = bnames; while (bn) { if (bn->lang == lang) break; bn = bn->next; } if (!bn) { quicklist *ql = buildingtypes; int qi; bn = (local_names *)calloc(sizeof(local_names), 1); bn->next = bnames; bn->lang = lang; for (qi = 0, ql = buildingtypes; ql; ql_advance(&ql, &qi, 1)) { building_type *btype = (building_type *)ql_get(ql, qi); const char *n = LOC(lang, btype->_name); type.v = (void *)btype; addtoken(&bn->names, n, type); } bnames = bn; } if (findtoken(bn->names, name, &type) == E_TOK_NOMATCH) return NULL; return (const building_type *)type.v; }
static attrib *set_new_dragon_target(unit * u, region * r, int range) { int max_affinity = 0; region *max_region = NULL; quicklist *ql, *rlist = regions_in_range(r, range, allowed_dragon); int qi; for (qi = 0, ql = rlist; ql; ql_advance(&ql, &qi, 1)) { region *r2 = (region *)ql_get(ql, qi); int affinity = dragon_affinity_value(r2, u); if (affinity > max_affinity) { max_affinity = affinity; max_region = r2; } } ql_free(rlist); if (max_region && max_region != r) { attrib *a = a_find(u->attribs, &at_targetregion); if (!a) { a = a_add(&u->attribs, make_targetregion(max_region)); } else { a->data.v = max_region; } return a; } return NULL; }
void sort_wormhole_regions(quicklist *rlist, region **match, int count) { quicklist *ql; int qi, i = 0; for (ql = rlist, qi = 0; i != count; ql_advance(&ql, &qi, 1)) { match[i++] = (region *)ql_get(ql, qi); } qsort(match, count, sizeof(region *), cmp_age); }
static void get_island_info(region * root, int *size_p, int *inhabited_p, int *maxage_p) { int qi, size = 0, maxage = 0, inhabited = 0; quicklist *ql, *island = NULL; ql_push(&island, root); fset(root, RF_MARK); for (ql = island, qi = 0; ql; ql_advance(&ql, &qi, 1)) { int d; region *r = (region *)ql_get(ql, qi); if (r->units) { unit *u; for (u = r->units; u; u = u->next) { if (!fval(u->faction, FFL_NOIDLEOUT) && u->faction->age > maxage) { maxage = u->faction->age; } } ++inhabited; } ++size; for (d = 0; d != MAXDIRECTIONS; ++d) { region *rn = rconnect(r, d); if (rn && !fval(rn, RF_MARK) && rn->land) { ql_push(&island, rn); fset(rn, RF_MARK); } } } for (ql = island, qi = 0; ql; ql_advance(&ql, &qi, 1)) { region *r = (region *)ql_get(ql, qi); freset(r, RF_MARK); } ql_free(island); if (size_p) *size_p = size; if (inhabited_p) *inhabited_p = inhabited; if (maxage_p) *maxage_p = maxage; }
/* Feuersturm: Betrifft sehr viele Gegner (in der Regel alle), * macht nur vergleichsweise geringen Schaden */ int sp_immolation(struct castorder * co) { fighter * fi = co->magician.fig; int level = co->level; const spell * sp = co->sp; battle *b = fi->side->battle; troop at; int force, qi, killed = 0; const char *damage; quicklist *fgs, *ql; message *m; /* 2d4 HP */ damage = spell_damage(5); /* Betrifft alle Gegner */ force = 99999; if (!count_enemies(b, fi, FIGHT_ROW, AVOID_ROW, SELECT_ADVANCE | SELECT_FIND)) { message *m = msg_message("battle::out_of_range", "mage spell", fi->unit, sp); message_all(b, m); msg_release(m); return 0; } at.fighter = fi; at.index = 0; fgs = fighters(b, fi->side, FIGHT_ROW, AVOID_ROW, FS_ENEMY); for (qi = 0, ql = fgs; ql; ql_advance(&ql, &qi, 1)) { fighter *df = (fighter *)ql_get(ql, qi); int n = df->alive - df->removed; troop dt; dt.fighter = df; while (n != 0) { dt.index = --n; killed += terminate(dt, at, AT_COMBATSPELL, damage, false); if (--force == 0) break; } if (force == 0) break; } ql_free(fgs); m = msg_message("battle::combatspell", "mage spell killed", fi->unit, sp, killed); message_all(b, m); msg_release(m); return level; }
static void test_find(CuTest *tc) { struct quicklist *ql = 0; struct quicklist *il; int i; ql_push(&ql, (void *)data); ql_push(&ql, (void *)(data + 1)); ql_push(&ql, (void *)data); il = ql; i = 0; CuAssertIntEquals(tc, ql_true, ql_find(&il, &i, (void *)data, 0)); CuAssertIntEquals(tc, 0, i); ql_advance(&il, &i, 1); CuAssertIntEquals(tc, ql_true, ql_find(&il, &i, (void *)data, 0)); CuAssertIntEquals(tc, 2, i); ql_advance(&il, &i, 1); CuAssertIntEquals(tc, ql_false, ql_find(&il, &i, (void *)data, 0)); ql_free(ql); }
void spellbook_clear(spellbook *sb) { quicklist *ql; int qi; assert(sb); for (qi = 0, ql = sb->spells; ql; ql_advance(&ql, &qi, 1)) { spellbook_entry *sbe = (spellbook_entry *) ql_get(ql, qi); free(sbe); } ql_free(sb->spells); }
static void test_push_returns_end(CuTest * tc) { struct quicklist *result, *ql = NULL; int i = 0, qi = 0; do { result = ql_push(&ql, 0); i++; } while (result == ql); ql_advance(&ql, &qi, i - 1); CuAssertPtrEquals(tc, result, ql); ql_free(ql); }
static ship_type *st_find_i(const char *name) { quicklist *ql; int qi; for (qi = 0, ql = shiptypes; ql; ql_advance(&ql, &qi, 1)) { ship_type *stype = (ship_type *)ql_get(ql, qi); if (strcmp(stype->_name, name) == 0) { return stype; } } return NULL; }
/* Returns a building type for the (internal) name */ static building_type *bt_find_i(const char *name) { quicklist *ql; int qi; assert(name); for (qi = 0, ql = buildingtypes; ql; ql_advance(&ql, &qi, 1)) { building_type *btype = (building_type *)ql_get(ql, qi); if (strcmp(btype->_name, name) == 0) return btype; } return NULL; }
const message_type *mt_find(const char *name) { unsigned int hash = hashstring(name) % MT_MAXHASH; quicklist *ql = messagetypes[hash]; int qi; for (qi = 0; ql; ql_advance(&ql, &qi, 1)) { message_type *data = (message_type *)ql_get(ql, qi); if (strcmp(data->name, name) == 0) { return data; } } return 0; }
int spellbook_foreach(spellbook *sb, int (*callback)(spellbook_entry *, void *), void * data) { quicklist *ql; int qi; for (qi = 0, ql = sb->spells; ql; ql_advance(&ql, &qi, 1)) { spellbook_entry *sbe = (spellbook_entry *) ql_get(ql, qi); int result = callback(sbe, data); if (result) { return result; } } return 0; }
static void test_advance(CuTest * tc) { struct quicklist *ql = NULL, *qli; int i, n = 31; for (i = 0; i != 32; ++i) { ql_insert(&ql, 0, (void *)(data + i)); } for (i = 0, qli = ql; qli; ql_advance(&qli, &i, 1), n--) { void * g = ql_get(qli, i); CuAssertPtrEquals(tc, (void *)(data + n), g); } ql_free(ql); }
spellbook_entry * spellbook_get(spellbook *sb, const struct spell * sp) { if (sb) { quicklist *ql; int qi; for (qi = 0, ql = sb->spells; ql; ql_advance(&ql, &qi, 1)) { spellbook_entry *sbe = (spellbook_entry *) ql_get(ql, qi); if (sp==sbe->sp) { return sbe; } } } return 0; }
static void test_find_cb(CuTest *tc) { int a = 42; int b = 23; int c = 42; struct quicklist *ql = 0; struct quicklist *il; int i; ql_push(&ql, (void *)&a); ql_push(&ql, (void *)&b); ql_push(&ql, (void *)&c); il = ql; i = 0; CuAssertIntEquals(tc, ql_true, ql_find(&il, &i, (void *)&a, cb_match_int)); CuAssertIntEquals(tc, 0, i); ql_advance(&il, &i, 1); CuAssertIntEquals(tc, ql_true, ql_find(&il, &i, (void *)&a, cb_match_int)); CuAssertIntEquals(tc, 2, i); ql_advance(&il, &i, 1); CuAssertIntEquals(tc, ql_false, ql_find(&il, &i, (void *)&a, cb_match_int)); ql_free(ql); }
static void test_push_doesnt_invalidate_iterator(CuTest * tc) { struct quicklist *list = NULL, *ql = NULL; int i, qi = 0; ql_push(&list, (void*)data); ql = list; for (i = 0; i != 42; ++i) { void * n; n = ql_get(ql, qi); CuAssertPtrEquals(tc, (void *)(data + i), n); ql_push(&list, (void *)(data + (i * 2 + 1))); ql_advance(&ql, &qi, 1); ql_push(&list, (void *)(data + (i * 2 + 2))); } ql_free(ql); }
const curse_type *ct_find(const char *c) { unsigned int hash = tolower(c[0]); quicklist *ctl = cursetypes[hash]; int qi; for (qi = 0; ctl; ql_advance(&ctl, &qi, 1)) { curse_type *type = (curse_type *) ql_get(ctl, qi); if (strcmp(c, type->cname) == 0) { return type; } else { size_t k = _min(strlen(c), strlen(type->cname)); if (!_memicmp(c, type->cname, k)) { return type; } } } return NULL; }
static int heal_fighters(quicklist * fgs, int *power, bool heal_monsters) { int healhp = *power, healed = 0, qi; quicklist *ql; for (qi = 0, ql = fgs; ql; ql_advance(&ql, &qi, 1)) { fighter *df = (fighter *)ql_get(ql, qi); if (healhp <= 0) break; /* Untote kann man nicht heilen */ if (df->unit->number == 0 || (u_race(df->unit)->flags & RCF_NOHEAL)) continue; /* wir heilen erstmal keine Monster */ if (heal_monsters || playerrace(u_race(df->unit))) { int n, hp = df->unit->hp / df->unit->number; int rest = df->unit->hp % df->unit->number; for (n = 0; n < df->unit->number; n++) { int wound = hp - df->person[n].hp; if (rest > n) ++wound; if (wound > 0 && wound < hp) { int heal = _min(healhp, wound); assert(heal >= 0); df->person[n].hp += heal; healhp = _max(0, healhp - heal); ++healed; if (healhp <= 0) break; } } } } *power = healhp; return healed; }
void age_borders(void) { quicklist *deleted = NULL, *ql; int i; for (i = 0; i != BORDER_MAXHASH; ++i) { connection *bhash = borders[i]; for (; bhash; bhash = bhash->nexthash) { connection *b = bhash; for (; b; b = b->next) { if (b->type->age) { if (b->type->age(b) == AT_AGE_REMOVE) { ql_push(&deleted, b); } } } } } for (ql = deleted, i = 0; ql; ql_advance(&ql, &i, 1)) { connection *b = (connection *)ql_get(ql, i); erase_border(b); } ql_free(deleted); }
/** create new island with up to nsize players * returns the number of players placed on the new island. */ int autoseed(newfaction ** players, int nsize, int max_agediff) { region *r = NULL; region_list *rlist = NULL; int rsize = 0, tsize = 0; int isize = REGIONS_PER_FACTION; /* target size for the island */ int psize = 0; /* players on this island */ const terrain_type *volcano_terrain = get_terrain("volcano"); static int nterrains = -1; static const terrain_type **terrainarr = 0; static int *distribution; assert(players); if (nterrains < 0) { int n = 0; const terrain_type *terrain = terrains(); for (nterrains = 0; terrain; terrain = terrain->next) { if (terrain->distribution) { ++nterrains; } } terrainarr = malloc(sizeof(terrain_type *) * nterrains); distribution = malloc(sizeof(int) * nterrains); for (terrain = terrains(); terrain; terrain = terrain->next) { if (terrain->distribution) { terrainarr[n] = terrain; distribution[n++] = terrain->distribution; } } } frame_regions(16, newterrain(T_FIREWALL)); if (listlen(*players) < MINFACTIONS) return 0; if (max_agediff > 0) { region *rmin = NULL; plane *hplane = get_homeplane(); /* find a spot that's adjacent to the previous island, but virgin. * like the last land virgin ocean region adjacent to land. */ for (r = regions; r; r = r->next) { struct plane *pl = rplane(r); if (r->age <= max_agediff && r->terrain == newterrain(T_OCEAN) && pl == hplane && virgin_region(r)) { direction_t d; for (d = 0; d != MAXDIRECTIONS; ++d) { region *rn = rconnect(r, d); if (rn && rn->land && rn->age <= max_agediff && virgin_region(rn)) { /* only expand islands that aren't single-islands and not too big already */ int size, inhabitants, maxage; get_island_info(rn, &size, &inhabitants, &maxage); if (maxage <= max_agediff && size >= 2 && size < MAXISLANDSIZE) { rmin = rn; break; } } } } } if (rmin != NULL) { faction *f; quicklist *ql, *rlist = get_island(rmin); int qi; for (ql = rlist, qi = 0; ql; ql_advance(&ql, &qi, 1)) { region *r = (region *)ql_get(ql, qi); unit *u; for (u = r->units; u; u = u->next) { f = u->faction; if (!fval(f, FFL_MARK)) { ++psize; fset(f, FFL_MARK); } } } ql_free(rlist); if (psize > 0) { for (f = factions; f; f = f->next) { freset(f, FFL_MARK); } } if (psize < PLAYERS_PER_ISLAND) { r = rmin; } } } if (r == NULL) { region *rmin = NULL; direction_t dmin = MAXDIRECTIONS; plane *hplane = get_homeplane(); /* find an empty spot. * rmin = the youngest ocean region that has a missing neighbour * dmin = direction in which it's empty */ for (r = regions; r; r = r->next) { struct plane *pl = rplane(r); if (r->terrain == newterrain(T_OCEAN) && pl == hplane && (rmin == NULL || r->age <= max_agediff)) { direction_t d; for (d = 0; d != MAXDIRECTIONS; ++d) { region *rn = rconnect(r, d); if (rn == NULL) break; } if (d != MAXDIRECTIONS) { rmin = r; dmin = d; } } } /* create a new region where we found the empty spot, and make it the first * in our island. island regions are kept in rlist, so only new regions can * get populated, and old regions are not overwritten */ if (rmin != NULL) { plane *pl = rplane(rmin); int x = rmin->x + delta_x[dmin]; int y = rmin->y + delta_y[dmin]; pnormalize(&x, &y, pl); assert(virgin_region(rconnect(rmin, dmin))); r = new_region(x, y, pl, 0); terraform_region(r, newterrain(T_OCEAN)); } } if (r != NULL) { add_regionlist(&rlist, r); fset(r, RF_MARK); rsize = 1; } while (rsize && (nsize || isize >= REGIONS_PER_FACTION)) { int i = rng_int() % rsize; region_list **rnext = &rlist; region_list *rfind; direction_t d; while (i--) rnext = &(*rnext)->next; rfind = *rnext; r = rfind->data; freset(r, RF_MARK); *rnext = rfind->next; free(rfind); --rsize; for (d = 0; d != MAXDIRECTIONS; ++d) { region *rn = rconnect(r, d); if (rn && fval(rn, RF_MARK)) continue; if (rn == NULL) { plane *pl = rplane(r); int x = r->x + delta_x[d]; int y = r->y + delta_y[d]; pnormalize(&x, &y, pl); rn = new_region(x, y, pl, 0); terraform_region(rn, newterrain(T_OCEAN)); } if (virgin_region(rn)) { add_regionlist(&rlist, rn); fset(rn, RF_MARK); ++rsize; } } if (volcano_terrain != NULL && (rng_int() % VOLCANO_CHANCE == 0)) { terraform_region(r, volcano_terrain); } else if (nsize && (rng_int() % isize == 0 || rsize == 0)) { newfaction **nfp, *nextf = *players; faction *f; unit *u; isize += REGIONS_PER_FACTION; terraform_region(r, preferred_terrain(nextf->race)); prepare_starting_region(r); ++tsize; assert(r->land && r->units == 0); u = addplayer(r, addfaction(nextf->email, nextf->password, nextf->race, nextf->lang, nextf->subscription)); f = u->faction; fset(f, FFL_ISNEW); f->alliance = nextf->allies; /* remove duplicate email addresses */ nfp = &nextf->next; while (*nfp) { newfaction *nf = *nfp; if (strcmp(nextf->email, nf->email) == 0) { *nfp = nf->next; free_newfaction(nf); } else nfp = &nf->next; } *players = nextf->next; free_newfaction(nextf); ++psize; --nsize; --isize; if (psize >= PLAYERS_PER_ISLAND) break; } else { terraform_region(r, random_terrain(terrainarr, distribution, nterrains)); --isize; } } if (nsize != 0) { log_error( ("Could not place all factions on the same island as requested\n")); } if (rlist) { #define MINOCEANDIST 3 #define MAXOCEANDIST 6 #define MAXFILLDIST 10 #define SPECIALCHANCE 80 region_list **rbegin = &rlist; int special = 1; int oceandist = MINOCEANDIST + (rng_int() % (MAXOCEANDIST - MINOCEANDIST)); while (oceandist--) { region_list **rend = rbegin; while (*rend) rend = &(*rend)->next; while (rbegin != rend) { direction_t d; region *r = (*rbegin)->data; rbegin = &(*rbegin)->next; for (d = 0; d != MAXDIRECTIONS; ++d) { region *rn = rconnect(r, d); if (rn == NULL) { const struct terrain_type *terrain = newterrain(T_OCEAN); plane *pl = rplane(r); int x = r->x + delta_x[d]; int y = r->y + delta_y[d]; pnormalize(&x, &y, pl); rn = new_region(x, y, pl, 0); if (rng_int() % SPECIALCHANCE < special) { terrain = random_terrain(terrainarr, distribution, nterrains); special = SPECIALCHANCE / 3; /* 33% chance auf noch eines */ } else { special = 1; } terraform_region(rn, terrain); /* the new region has an extra 20% chance to have mallorn */ if (rng_int() % 100 < 20) fset(r, RF_MALLORN); add_regionlist(rend, rn); } } } } while (*rbegin) { region *r = (*rbegin)->data; plane *pl = rplane(r); direction_t d; rbegin = &(*rbegin)->next; for (d = 0; d != MAXDIRECTIONS; ++d) if (rconnect(r, d) == NULL) { int i; for (i = 1; i != MAXFILLDIST; ++i) { int x = r->x + delta_x[d] * i; int y = r->y + delta_y[d] * i; pnormalize(&x, &y, pl); if (findregion(x, y)) { break; } } if (i != MAXFILLDIST) { while (--i) { region *rn; int x = r->x + delta_x[d] * i; int y = r->y + delta_y[d] * i; pnormalize(&x, &y, pl); rn = new_region(x, y, pl, 0); terraform_region(rn, newterrain(T_OCEAN)); } } } } while (rlist) { region_list *self = rlist; rlist = rlist->next; freset(self->data, RF_MARK); free(self); } } return tsize; }
int sp_undeadhero(struct castorder * co) { fighter * fi = co->magician.fig; int level = co->level; double power = co->force; battle *b = fi->side->battle; unit *mage = fi->unit; region *r = b->region; quicklist *fgs, *ql; int qi, n, undead = 0; message *msg; int force = (int)get_force(power, 0); double c = 0.50 + 0.02 * power; /* Liste aus allen K�mpfern */ fgs = fighters(b, fi->side, FIGHT_ROW, AVOID_ROW, FS_ENEMY | FS_HELP); scramble_fighters(fgs); for (qi = 0, ql = fgs; ql; ql_advance(&ql, &qi, 1)) { fighter *df = (fighter *)ql_get(ql, qi); unit *du = df->unit; if (force <= 0) break; /* keine Monster */ if (!playerrace(u_race(du))) continue; if (df->alive + df->run.number < du->number) { int j = 0; /* Wieviele Untote k�nnen wir aus dieser Einheit wecken? */ for (n = df->alive + df->run.number; n != du->number; n++) { if (chance(c)) { ++j; if (--force <= 0) break; } } if (j > 0) { item **ilist; unit *u = create_unit(r, mage->faction, 0, get_race(RC_UNDEAD), 0, unit_getname(du), du); /* new units gets some stats from old unit */ if (du->display) { unit_setinfo(u, du->display); } else { unit_setinfo(u, NULL); } setstatus(u, du->status); setguard(u, false); for (ilist = &du->items; *ilist;) { item *itm = *ilist; int loot = itm->number * j / du->number; if (loot != itm->number) { int split = itm->number * j % du->number; if (split > 0 && (rng_int() % du->number) < split) { ++loot; } } i_change(&u->items, itm->type, loot); i_change(ilist, itm->type, -loot); if (*ilist == itm) { ilist = &itm->next; } } /* inherit stealth from magician */ if (mage->flags & UFL_ANON_FACTION) { u->flags |= UFL_ANON_FACTION; } /* transfer dead people to new unit, set hitpoints to those of old unit */ transfermen(du, u, j); u->hp = u->number * unit_max_hp(du); assert(j <= df->side->casualties); df->side->casualties -= j; df->side->dead -= j; /* counting total number of undead */ undead += j; } } } ql_free(fgs); level = _min(level, undead); if (undead == 0) { msg = msg_message("summonundead_effect_0", "mage region", mage, mage->region); } else { msg = msg_message("summonundead_effect_1", "mage region amount", mage, mage->region, undead); } message_all(b, msg); msg_release(msg); return level; }
/* Rosthauch */ int sp_combatrosthauch(struct castorder * co) { fighter * fi = co->magician.fig; int level = co->level; double power = co->force; battle *b = fi->side->battle; quicklist *ql, *fgs; int force = lovar(power * 15); int qi, k = 0; if (!count_enemies(b, fi, FIGHT_ROW, BEHIND_ROW - 1, SELECT_ADVANCE | SELECT_FIND)) { message *msg = msg_message("rust_effect_0", "mage", fi->unit); message_all(b, msg); msg_release(msg); return 0; } fgs = fighters(b, fi->side, FIGHT_ROW, BEHIND_ROW - 1, FS_ENEMY); scramble_fighters(fgs); for (qi = 0, ql = fgs; ql; ql_advance(&ql, &qi, 1)) { fighter *df = (fighter *)ql_get(ql, qi); if (df->alive == 0) continue; if (force <= 0) break; /* da n _min(force, x), sollte force maximal auf 0 sinken */ assert(force >= 0); if (df->weapons) { int w; for (w = 0; df->weapons[w].type != NULL; ++w) { weapon *wp = df->weapons; int n = _min(force, wp->used); if (n) { requirement *mat = wp->type->itype->construction->materials; bool iron = false; while (mat && mat->number > 0) { if (mat->rtype == get_resourcetype(R_IRON)) { iron = true; break; } mat++; } if (iron) { int p; force -= n; wp->used -= n; k += n; i_change(&df->unit->items, wp->type->itype, -n); for (p = 0; n && p != df->unit->number; ++p) { if (df->person[p].missile == wp) { df->person[p].missile = NULL; --n; } } for (p = 0; n && p != df->unit->number; ++p) { if (df->person[p].melee == wp) { df->person[p].melee = NULL; --n; } } } } } } } ql_free(fgs); if (k == 0) { /* keine Waffen mehr da, die zerst�rt werden k�nnten */ message *msg = msg_message("rust_effect_1", "mage", fi->unit); message_all(b, msg); msg_release(msg); fi->magic = 0; /* k�mpft nichtmagisch weiter */ level = 0; } else { message *msg = msg_message("rust_effect_2", "mage", fi->unit); message_all(b, msg); msg_release(msg); } return level; }
/** Spells: chaosrow / song of confusion. * German Title: 'Gesang der Verwirrung' */ int sp_chaosrow(struct castorder * co) { fighter * fi = co->magician.fig; int level = co->level; double power = co->force; const spell * sp = co->sp; battle *b = fi->side->battle; unit *mage = fi->unit; quicklist *fgs, *ql; message *m; const char *mtype; int qi, k = 0; if (!count_enemies(b, fi, FIGHT_ROW, NUMROWS, SELECT_ADVANCE | SELECT_FIND)) { m = msg_message("battle::out_of_range", "mage spell", fi->unit, sp); message_all(b, m); msg_release(m); return 0; } if (sp->id == SPL_CHAOSROW) power *= 40; else power = get_force(power, 5); fgs = fighters(b, fi->side, FIGHT_ROW, NUMROWS, FS_ENEMY); scramble_fighters(fgs); for (qi = 0, ql = fgs; ql; ql_advance(&ql, &qi, 1)) { fighter *df = (fighter *)ql_get(ql, qi); int n = df->unit->number; if (df->alive == 0) continue; if (power <= 0.0) break; /* force sollte wegen des _max(0,x) nicht unter 0 fallen k�nnen */ if (is_magic_resistant(mage, df->unit, 0)) continue; if (chance(power / n)) { int row = statusrow(df->status); df->side->size[row] -= df->alive; if (u_race(df->unit)->battle_flags & BF_NOBLOCK) { df->side->nonblockers[row] -= df->alive; } row = FIRST_ROW + (rng_int() % (NUMROWS - FIRST_ROW)); switch (row) { case FIGHT_ROW: df->status = ST_FIGHT; break; case BEHIND_ROW: df->status = ST_CHICKEN; break; case AVOID_ROW: df->status = ST_AVOID; break; case FLEE_ROW: df->status = ST_FLEE; break; default: assert(!"unknown combatrow"); } assert(statusrow(df->status) == row); df->side->size[row] += df->alive; if (u_race(df->unit)->battle_flags & BF_NOBLOCK) { df->side->nonblockers[row] += df->alive; } k += df->alive; } power = _max(0, power - n); } ql_free(fgs); if (sp->id == SPL_CHAOSROW) { mtype = (k > 0) ? "sp_chaosrow_effect_1" : "sp_chaosrow_effect_0"; } else { mtype = (k > 0) ? "sp_confusion_effect_1" : "sp_confusion_effect_0"; } m = msg_message(mtype, "mage", mage); message_all(b, m); msg_release(m); return level; }
void do_markets(void) { quicklist *traders = 0; unit *markets[MAX_MARKETS]; region *r; for (r = regions; r; r = r->next) { if (r->land) { faction *f = region_get_owner(r); const struct race *rc = f ? f->race : NULL; int p = rpeasants(r); int numlux = rc_luxury_trade(rc), numherbs = rc_herb_trade(rc); numlux = (p + numlux - MIN_PEASANTS) / numlux; numherbs = (p + numherbs - MIN_PEASANTS) / numherbs; if (numlux > 0 || numherbs > 0) { int d, nmarkets = 0; const item_type *lux = r_luxury(r); const item_type *herb = r->land->herbtype; nmarkets += get_markets(r, markets + nmarkets, MAX_MARKETS - nmarkets); for (d = 0; d != MAXDIRECTIONS; ++d) { region *r2 = rconnect(r, d); if (r2 && r2->buildings) { nmarkets += get_markets(r2, markets + nmarkets, MAX_MARKETS - nmarkets); } } if (nmarkets) { while (lux && numlux--) { int n = rng_int() % nmarkets; unit *u = markets[n]; item *items; attrib *a = a_find(u->attribs, &at_market); if (a == NULL) { a = a_add(&u->attribs, a_new(&at_market)); ql_push(&traders, u); } items = (item *)a->data.v; i_change(&items, lux, 1); a->data.v = items; /* give 1 luxury */ } while (herb && numherbs--) { int n = rng_int() % nmarkets; unit *u = markets[n]; item *items; attrib *a = a_find(u->attribs, &at_market); if (a == NULL) { a = a_add(&u->attribs, a_new(&at_market)); ql_push(&traders, u); } items = (item *)a->data.v; i_change(&items, herb, 1); a->data.v = items; /* give 1 herb */ } } } } } if (traders) { quicklist *qliter = traders; int qli = 0; for (qli = 0; qliter; ql_advance(&qliter, &qli, 1)) { unit *u = (unit *)ql_get(qliter, qli); attrib *a = a_find(u->attribs, &at_market); item *items = (item *)a->data.v; a->data.v = NULL; while (items) { item *itm = items; items = itm->next; if (itm->number) { ADDMSG(&u->faction->msgs, msg_message("buyamount", "unit amount resource", u, itm->number, itm->type->rtype)); itm->next = NULL; i_add(&u->items, itm); } else { i_free(itm); } } a_remove(&u->attribs, a); } ql_free(traders); } }
int sp_flee(struct castorder * co) { fighter * fi = co->magician.fig; int level = co->level; double power = co->force; const spell * sp = co->sp; battle *b = fi->side->battle; unit *mage = fi->unit; quicklist *fgs, *ql; int force, n, qi; int panik = 0; message *msg; switch (sp->id) { case SPL_FLEE: force = (int)get_force(power, 4); break; case SPL_SONG_OF_FEAR: force = (int)get_force(power, 3); break; case SPL_AURA_OF_FEAR: force = (int)get_force(power, 5); break; default: force = (int)get_force(power, 10); } if (!count_enemies(b, fi, FIGHT_ROW, AVOID_ROW, SELECT_ADVANCE | SELECT_FIND)) { msg = msg_message("sp_flee_effect_0", "mage spell", mage, sp); message_all(b, msg); msg_release(msg); return 0; } fgs = fighters(b, fi->side, FIGHT_ROW, AVOID_ROW, FS_ENEMY); scramble_fighters(fgs); for (qi = 0, ql = fgs; ql; ql_advance(&ql, &qi, 1)) { fighter *df = (fighter *)ql_get(ql, qi); for (n = 0; n != df->alive; ++n) { if (force < 0) break; if (df->person[n].flags & FL_PANICED) { /* bei SPL_SONG_OF_FEAR m�glich */ df->person[n].attack -= 1; --force; ++panik; } else if (!(df->person[n].flags & FL_COURAGE) || !(u_race(df->unit)->flags & RCF_UNDEAD)) { if (!is_magic_resistant(mage, df->unit, 0)) { df->person[n].flags |= FL_PANICED; ++panik; } --force; } } } ql_free(fgs); msg = msg_message("sp_flee_effect_1", "mage spell amount", mage, sp, panik); message_all(b, msg); msg_release(msg); return level; }