Esempio n. 1
0
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;
}
Esempio n. 2
0
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;
}
Esempio n. 3
0
/* 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;
}
Esempio n. 4
0
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;
}
Esempio n. 5
0
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);
}
Esempio n. 6
0
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;
}
Esempio n. 7
0
/* 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;
}
Esempio n. 8
0
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);
}
Esempio n. 9
0
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);
}
Esempio n. 10
0
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);
}
Esempio n. 11
0
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;
}
Esempio n. 12
0
/* 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;
}
Esempio n. 13
0
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;
}
Esempio n. 14
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;
}
Esempio n. 15
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);
}
Esempio n. 16
0
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;
}
Esempio n. 17
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);
}
Esempio n. 18
0
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);
}
Esempio n. 19
0
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;
}
Esempio n. 20
0
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;
}
Esempio n. 21
0
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);
}
Esempio n. 22
0
/** 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;
}
Esempio n. 23
0
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;
}
Esempio n. 24
0
/* 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;
}
Esempio n. 25
0
/** 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;
}
Esempio n. 26
0
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);
    }
}
Esempio n. 27
0
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;
}