void free_ship(ship * s) { while (s->attribs) a_remove(&s->attribs, s->attribs); free(s->name); free(s->display); free(s); }
void free_region(region * r) { if (last == r) last = NULL; free(r->display); if (r->land) free_land(r->land); if (r->msgs) { free_messagelist(r->msgs->begin); free(r->msgs); r->msgs = 0; } while (r->individual_messages) { struct individual_message *msg = r->individual_messages; r->individual_messages = msg->next; if (msg->msgs) { free_messagelist(msg->msgs->begin); free(msg->msgs); } free(msg); } while (r->attribs) a_remove(&r->attribs, r->attribs); while (r->resources) { rawmaterial *res = r->resources; r->resources = res->next; free(res); } while (r->units) { unit *u = r->units; r->units = u->next; uunhash(u); free_unit(u); free(u); } while (r->buildings) { building *b = r->buildings; assert(b->region == r); r->buildings = b->next; bunhash(b); /* must be done here, because remove_building does it, and wasn't called */ free_building(b); } while (r->ships) { ship *s = r->ships; assert(s->region == r); r->ships = s->next; sunhash(s); free_ship(s); } free(r); }
static void test_attrib_new(CuTest * tc) { attrib_type at_test = { "test" }; attrib * a; CuAssertPtrNotNull(tc, (a = a_new(&at_test))); CuAssertPtrEquals(tc, 0, a->next); CuAssertPtrEquals(tc, 0, a->nexttype); CuAssertPtrEquals(tc, (void *)a->type, (void *)&at_test); a_remove(&a, a); CuAssertPtrEquals(tc, 0, a); }
static void test_attrib_remove_self(CuTest * tc) { attrib_type at_foo = { "foo" }; attrib *a, *alist = 0; CuAssertPtrNotNull(tc, a_add(&alist, a_new(&at_foo))); CuAssertPtrNotNull(tc, a = a_add(&alist, a_new(&at_foo))); CuAssertPtrEquals(tc, a, alist->next); CuAssertPtrEquals(tc, 0, alist->nexttype); CuAssertIntEquals(tc, 1, a_remove(&alist, alist)); CuAssertPtrEquals(tc, a, alist); a_removeall(&alist, NULL); }
static int clonedied_handle(trigger * t, void *data) { /* destroy the unit */ unit *u = (unit *) t->data.v; if (u) { attrib *a = a_find(u->attribs, &at_clone); if (a) a_remove(&u->attribs, a); } else log_error("could not perform clonedied::handle()\n"); unused_arg(data); return 0; }
void usetprivate(unit * u, const char *str) { attrib *a = a_find(u->attribs, &at_private); if (str == NULL) { if (a) a_remove(&u->attribs, a); return; } if (!a) a = a_add(&u->attribs, a_new(&at_private)); if (a->data.v) free(a->data.v); a->data.v = _strdup((const char *)str); }
void add_chaoscount(region * r, int fallen) { attrib *a; if (fallen == 0) return; a = a_find(r->attribs, &at_chaoscount); if (!a) a = a_add(&r->attribs, a_new(&at_chaoscount)); a->data.i += fallen; if (a->data.i <= 0) a_remove(&r->attribs, a); }
void usettarget(unit * u, const unit * t) { attrib *a = a_find(u->attribs, &at_target); if (!a && t) a = a_add(&u->attribs, a_new(&at_target)); if (a) { if (!t) { a_remove(&u->attribs, a); freset(u, UFL_TARGET); } else { a->data.v = (void *)t; fset(u, UFL_TARGET); } } }
void usetsiege(unit * u, const struct building *t) { attrib *a = a_find(u->attribs, &at_siege); if (!a && t) a = a_add(&u->attribs, a_new(&at_siege)); if (a) { if (!t) { a_remove(&u->attribs, a); freset(u, UFL_SIEGE); } else { a->data.v = (void *)t; fset(u, UFL_SIEGE); } } }
static int tolua_region_setkey(lua_State * L) { region *self = (region *) tolua_tousertype(L, 1, 0); const char *name = tolua_tostring(L, 2, 0); int value = tolua_toboolean(L, 3, 0); int flag = atoi36(name); attrib *a = find_key(self->attribs, flag); if (a == NULL && value) { add_key(&self->attribs, flag); } else if (a != NULL && !value) { a_remove(&self->attribs, a); } return 0; }
static int removecurse_handle(trigger * t, void *data) { /* call an event handler on removecurse. * data.v -> ( variant event, int timer ) */ removecurse_data *td = (removecurse_data *) t->data.v; if (td->curse && td->target) { attrib *a = a_select(td->target->attribs, td->curse, cmp_curse); if (a) { a_remove(&td->target->attribs, a); } else log_error("could not perform removecurse::handle()\n"); } unused_arg(data); return 0; }
static void test_curse(CuTest * tc) { attrib *attrs = NULL; curse *c, *result; int cid; curse_type ct_dummy = { "dummy", CURSETYP_NORM, 0, M_SUMEFFECT, NULL }; c = create_curse(NULL, &attrs, &ct_dummy, 1.0, 1, 1, 1); cid = c->no; result = findcurse(cid); CuAssertPtrEquals(tc, c, result); a_remove(&attrs, attrs); result = findcurse(cid); CuAssertPtrEquals(tc, NULL, result); test_cleanup(); }
int a_age(attrib ** p) { attrib **ap = p; /* Attribute altern, und die Entfernung (age()==0) eines Attributs * hat Einfluß auf den Besitzer */ while (*ap) { attrib *a = *ap; if (a->type->age) { int result = a->type->age(a); assert(result >= 0 || !"age() returned a negative value"); if (result == AT_AGE_REMOVE) { a_remove(p, a); continue; } } ap = &a->next; } return (*p != NULL); }
/** remove the faction from memory. * this frees all memory that's only accessible through the faction, * but you should still call funhash and remove the faction from the * global list. */ static void free_faction(faction * f) { funhash(f); if (f->msgs) { free_messagelist(f->msgs->begin); free(f->msgs); } while (f->battles) { struct bmsg *bm = f->battles; f->battles = bm->next; if (bm->msgs) { free_messagelist(bm->msgs->begin); free(bm->msgs); } free(bm); } if (f->spellbook) { free_spellbook(f->spellbook); } while (f->groups) { group *g = f->groups; f->groups = g->next; free_group(g); } freelist(f->allies); free(f->email); free(f->name); if (f->seen_factions) { selist_free(f->seen_factions); f->seen_factions = 0; } while (f->attribs) { a_remove(&f->attribs, f->attribs); } i_freeall(&f->items); freelist(f->origin); }
void deathcounts(region * r, int fallen) { attrib *a; static const curse_type *ctype = NULL; if (fallen == 0) return; if (!ctype) ctype = ct_find("holyground"); if (ctype && curse_active(get_curse(r->attribs, ctype))) return; a = a_find(r->attribs, &at_deathcount); if (!a) a = a_add(&r->attribs, a_new(&at_deathcount)); a->data.i += fallen; if (a->data.i <= 0) a_remove(&r->attribs, a); }
void u_seteffstealth(unit * u, int value) { if (skill_enabled[SK_STEALTH]) { attrib *a = NULL; if (fval(u, UFL_STEALTH)) { a = a_find(u->attribs, &at_stealth); } if (value < 0) { if (a != NULL) { freset(u, UFL_STEALTH); a_remove(&u->attribs, a); } return; } if (a == NULL) { a = a_add(&u->attribs, a_new(&at_stealth)); fset(u, UFL_STEALTH); } a->data.i = value; } }
/** remove the unit from memory. * this frees all memory that's only accessible through the unit, * and you should already have called uunhash and removed the unit from the * region. */ void free_unit(unit * u) { free(u->name); free(u->display); free_order(u->thisorder); free_orders(&u->orders); if (u->skills) free(u->skills); while (u->items) { item *it = u->items->next; u->items->next = NULL; i_free(u->items); u->items = it; } while (u->attribs) a_remove(&u->attribs, u->attribs); while (u->reservations) { struct reservation *res = u->reservations; u->reservations = res->next; free(res); } }
int study_cmd(unit * u, order * ord) { region *r = u->region; int p; int l; int studycost, days; double multi = 1.0; attrib *a = NULL; teaching_info *teach = NULL; int money = 0; skill_t sk; int maxalchemy = 0; int speed_rule = (study_rule_t)config_get_int("study.speedup", 0); static const race *rc_snotling; static int rc_cache; if (rc_changed(&rc_cache)) { rc_snotling = get_race(RC_SNOTLING); } (void)init_order(ord, u->faction->locale); sk = getskill(u->faction->locale); if (!check_student(u, ord, sk)) { return -1; } /* snotlings koennen Talente nur bis T8 lernen */ if (u_race(u) == rc_snotling) { if (get_level(u, sk) >= 8) { cmistake(u, ord, 308, MSG_EVENT); return -1; } } p = studycost = study_cost(u, sk); a = a_find(u->attribs, &at_learning); if (a != NULL) { teach = (teaching_info *)a->data.v; } /* keine kostenpflichtigen Talente fuer Migranten. Vertraute sind * keine Migranten, wird in is_migrant abgefangen. Vorsicht, * studycost darf hier noch nicht durch Akademie erhoeht sein */ if (studycost > 0 && !ExpensiveMigrants() && is_migrant(u)) { ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "error_migrants_nolearn", "")); return -1; } /* Akademie: */ if (active_building(u, bt_find("academy"))) { studycost = studycost * 2; if (studycost < 50) studycost = 50; } if (sk == SK_MAGIC) { magic_t mtype; if (u->number > 1) { cmistake(u, ord, 106, MSG_MAGIC); return -1; } if (is_familiar(u)) { /* Vertraute zaehlen nicht zu den Magiern einer Partei, * koennen aber nur Graue Magie lernen */ mtype = M_GRAY; } else if (!has_skill(u, SK_MAGIC)) { int mmax = faction_skill_limit(u->faction, SK_MAGIC); /* Die Einheit ist noch kein Magier */ if (faction_count_skill(u->faction, SK_MAGIC) + u->number > mmax) { ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "error_max_magicians", "amount", mmax)); return -1; } mtype = getmagicskill(u->faction->locale); if (mtype == M_NONE || mtype == M_GRAY) { /* wurde kein Magiegebiet angegeben, wird davon * ausgegangen, dass das normal gelernt werden soll */ if (u->faction->magiegebiet != 0) { mtype = u->faction->magiegebiet; } else { /* Es wurde kein Magiegebiet angegeben und die Partei * hat noch keins gewaehlt. */ mtype = getmagicskill(u->faction->locale); if (mtype == M_NONE) { cmistake(u, ord, 178, MSG_MAGIC); return -1; } } } if (mtype != u->faction->magiegebiet) { /* Es wurde versucht, ein anderes Magiegebiet zu lernen * als das der Partei */ if (u->faction->magiegebiet != 0) { cmistake(u, ord, 179, MSG_MAGIC); return -1; } else { /* Lernt zum ersten mal Magie und legt damit das * Magiegebiet der Partei fest */ u->faction->magiegebiet = mtype; } } create_mage(u, mtype); } else { /* ist schon ein Magier und kein Vertrauter */ if (u->faction->magiegebiet == 0) { /* die Partei hat noch kein Magiegebiet gewaehlt. */ mtype = getmagicskill(u->faction->locale); if (mtype == M_NONE) { mtype = getmagicskill(u->faction->locale); if (mtype == M_NONE) { cmistake(u, ord, 178, MSG_MAGIC); return -1; } } /* Legt damit das Magiegebiet der Partei fest */ u->faction->magiegebiet = mtype; } } } if (sk == SK_ALCHEMY) { maxalchemy = effskill(u, SK_ALCHEMY, NULL); if (!has_skill(u, SK_ALCHEMY)) { int amax = faction_skill_limit(u->faction, SK_ALCHEMY); if (faction_count_skill(u->faction, SK_ALCHEMY) + u->number > amax) { ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "error_max_alchemists", "amount", amax)); return -1; } } } if (studycost) { int cost = studycost * u->number; money = get_pooled(u, get_resourcetype(R_SILVER), GET_DEFAULT, cost); if (money > cost) money = cost; } if (money < studycost * u->number) { studycost = p; /* Ohne Univertreurung */ if (money > studycost) money = studycost; if (p > 0 && money < studycost * u->number) { cmistake(u, ord, 65, MSG_EVENT); multi = money / (double)(studycost * u->number); } } if (teach == NULL) { a = a_add(&u->attribs, a_new(&at_learning)); teach = (teaching_info *)a->data.v; assert(teach); teach->teachers = NULL; } if (money > 0) { use_pooled(u, get_resourcetype(R_SILVER), GET_DEFAULT, money); ADDMSG(&u->faction->msgs, msg_message("studycost", "unit region cost skill", u, u->region, money, sk)); } if (get_effect(u, oldpotiontype[P_WISE])) { l = get_effect(u, oldpotiontype[P_WISE]); if (l > u->number) l = u->number; teach->days += l * EXPERIENCEDAYS; change_effect(u, oldpotiontype[P_WISE], -l); } if (get_effect(u, oldpotiontype[P_FOOL])) { l = get_effect(u, oldpotiontype[P_FOOL]); if (l > u->number) l = u->number; teach->days -= l * STUDYDAYS; change_effect(u, oldpotiontype[P_FOOL], -l); } if (p != studycost) { /* ist_in_gebaeude(r, u, BT_UNIVERSITAET) == 1) { */ /* p ist Kosten ohne Uni, studycost mit; wenn * p!=studycost, ist die Einheit zwangsweise * in einer Uni */ teach->days += u->number * EXPERIENCEDAYS; } if (is_cursed(r->attribs, &ct_badlearn)) { teach->days -= u->number * EXPERIENCEDAYS; } multi *= study_speedup(u, sk, speed_rule); days = study_days(u, sk); days = (int)((days + teach->days) * multi); /* the artacademy currently improves the learning of entertainment of all units in the region, to be able to make it cumulative with with an academy */ if (sk == SK_ENTERTAINMENT && buildingtype_exists(r, bt_find("artacademy"), false)) { days *= 2; } learn_skill(u, sk, days); if (a != NULL) { if (teach->teachers) { msg_teachers(teach->teachers, u, sk); } a_remove(&u->attribs, a); a = NULL; } u->flags |= (UFL_LONGACTION | UFL_NOTMOVING); /* Anzeigen neuer Traenke */ /* Spruchlistenaktualiesierung ist in Regeneration */ if (sk == SK_ALCHEMY) { faction *f = u->faction; int skill = effskill(u, SK_ALCHEMY, NULL); if (skill > maxalchemy) { show_potions(f, skill); } } init_order(NULL, NULL); return 0; }
int read_borders(gamedata *data) { struct storage *store = data->store; for (;;) { int bid = 0; char zText[32]; region *from, *to; border_type *type; READ_TOK(store, zText, sizeof(zText)); if (!strcmp(zText, "end")) break; READ_INT(store, &bid); if (data->version < UIDHASH_VERSION) { int fx, fy, tx, ty; READ_INT(store, &fx); READ_INT(store, &fy); READ_INT(store, &tx); READ_INT(store, &ty); from = findregion(fx, fy); to = findregion(tx, ty); } else { int fid, tid; READ_INT(store, &fid); READ_INT(store, &tid); from = findregionbyid(fid); to = findregionbyid(tid); if (!to || !from) { log_warning("%s connection between incomplete regions %d and %d", zText, fid, tid); continue; } } type = find_bordertype(zText); if (type == NULL) { log_error("[read_borders] unknown connection type '%s' in %s\n", zText, regionname(from, NULL)); assert(type || !"connection type not registered"); } if (to == from && type && from) { direction_t dir = (direction_t)(rng_int() % MAXDIRECTIONS); region *r = rconnect(from, dir); log_error("[read_borders] invalid %s in %s\n", type->__name, regionname(from, NULL)); if (r != NULL) to = r; } if ((type->read && !type->write)) { log_warning("ignore invalid border '%s' between '%s' and '%s'\n", zText, regionname(from, 0), regionname(to, 0)); } else { connection *b = new_border(type, from, to); nextborder--; /* new_border erhöht den Wert */ b->id = bid; assert(bid <= nextborder); if (type->read) { type->read(b, data); } if (data->version < NOBORDERATTRIBS_VERSION) { attrib *a = NULL; int result = read_attribs(data, &a, b); if (border_convert_cb) { border_convert_cb(b, a); } while (a) { a_remove(&a, a); } if (result < 0) { return result; } } } } return 0; }
void plan_monsters(faction * f) { region *r; assert(f); attack_chance = get_param_flt(global.parameters, "rules.monsters.attack_chance", 0.4); f->lastorders = turn; for (r = regions; r; r = r->next) { unit *u; bool attacking = false; for (u = r->units; u; u = u->next) { attrib *ta; order *long_order = NULL; /* Ab hier nur noch Befehle für NPC-Einheiten. */ if (!is_monsters(u->faction)) continue; /* Befehle müssen jede Runde neu gegeben werden: */ free_orders(&u->orders); if (skill_enabled(SK_PERCEPTION)) { /* Monster bekommen jede Runde ein paar Tage Wahrnehmung dazu */ /* TODO: this only works for playerrace */ produceexp(u, SK_PERCEPTION, u->number); } if (!attacking) { if (chance(attack_chance)) attacking = true; } if (u->status > ST_BEHIND) { setstatus(u, ST_FIGHT); /* all monsters fight */ } if (attacking && (!r->land || is_guard(u, GUARD_TAX))) { monster_attacks(u); } /* units with a plan to kill get ATTACK orders: */ ta = a_find(u->attribs, &at_hate); if (ta && !monster_is_waiting(u)) { unit *tu = (unit *)ta->data.v; if (tu && tu->region == r) { order * ord = monster_attack(u, tu); if (ord) { addlist(&u->orders, ord); } } else if (tu) { tu = findunitg(ta->data.i, NULL); if (tu != NULL) { long_order = make_movement_order(u, tu->region, 2, allowed_walk); } } else a_remove(&u->attribs, ta); } /* All monsters guard the region: */ if (!monster_is_waiting(u) && r->land) { addlist(&u->orders, create_order(K_GUARD, u->faction->locale, NULL)); } /* Einheiten mit Bewegungsplan kriegen ein NACH: */ if (long_order == NULL) { attrib *ta = a_find(u->attribs, &at_targetregion); if (ta) { if (u->region == (region *)ta->data.v) { a_remove(&u->attribs, ta); } } else if (u_race(u)->flags & RCF_MOVERANDOM) { if (rng_int() % 100 < MOVECHANCE || check_overpopulated(u)) { long_order = monster_move(r, u); } } } if (long_order == NULL && unit_can_study(u)) { /* Einheiten, die Waffenlosen Kampf lernen könnten, lernen es um * zu bewachen: */ if (u_race(u)->bonus[SK_WEAPONLESS] != -99) { if (effskill(u, SK_WEAPONLESS, 0) < 1) { long_order = create_order(K_STUDY, f->locale, "'%s'", skillname(SK_WEAPONLESS, f->locale)); } } } if (long_order == NULL) { /* Ab hier noch nicht generalisierte Spezialbehandlungen. */ if (!u->orders) { handle_event(u->attribs, "ai_move", u); } switch (old_race(u_race(u))) { case RC_SEASERPENT: long_order = create_order(K_PIRACY, f->locale, NULL); break; #ifdef TODO_ALP case RC_ALP: long_order = monster_seeks_target(r, u); break; #endif case RC_FIREDRAGON: case RC_DRAGON: case RC_WYRM: long_order = plan_dragon(u); break; default: if (u_race(u)->flags & RCF_LEARN) { long_order = monster_learn(u); } break; } } if (long_order) { addlist(&u->orders, long_order); } } } pathfinder_cleanup(); }
static void move_iceberg(region * r) { attrib *a; direction_t dir; region *rc; a = a_find(r->attribs, &at_iceberg); if (!a) { dir = (direction_t) (rng_int() % MAXDIRECTIONS); a = a_add(&r->attribs, make_iceberg(dir)); } else { if (rng_int() % 100 < 20) { dir = (direction_t) (rng_int() % MAXDIRECTIONS); a->data.i = dir; } else { dir = (direction_t) a->data.i; } } rc = rconnect(r, dir); if (rc && !fval(rc->terrain, ARCTIC_REGION)) { if (fval(rc->terrain, SEA_REGION)) { /* Eisberg treibt */ ship *sh, *shn; unit *u; int x, y; for (u = r->units; u; u = u->next) freset(u->faction, FFL_SELECT); for (u = r->units; u; u = u->next) if (!fval(u->faction, FFL_SELECT)) { fset(u->faction, FFL_SELECT); ADDMSG(&u->faction->msgs, msg_message("iceberg_drift", "region dir", r, dir)); } x = r->x; y = r->y; runhash(r); runhash(rc); r->x = rc->x; r->y = rc->y; rc->x = x; rc->y = y; rhash(rc); rhash(r); /* rc ist der Ozean (Ex-Eisberg), r der Eisberg (Ex-Ozean) */ /* Schiffe aus dem Zielozean werden in den Eisberg transferiert * und nehmen Schaden. */ for (sh = r->ships; sh; sh = sh->next) freset(sh, SF_SELECT); for (sh = r->ships; sh; sh = sh->next) { /* Meldung an Kapitän */ float dmg = get_param_flt(global.parameters, "rules.ship.damage.intoiceberg", 0.10F); damage_ship(sh, dmg); fset(sh, SF_SELECT); } /* Personen, Schiffe und Gebäude verschieben */ while (rc->buildings) { rc->buildings->region = r; translist(&rc->buildings, &r->buildings, rc->buildings); } while (rc->ships) { float dmg = get_param_flt(global.parameters, "rules.ship.damage.withiceberg", 0.10F); fset(rc->ships, SF_SELECT); damage_ship(rc->ships, dmg); move_ship(rc->ships, rc, r, NULL); } while (rc->units) { building *b = rc->units->building; u = rc->units; u->building = 0; /* prevent leaving in move_unit */ move_unit(rc->units, r, NULL); u_set_building(u, b); /* undo leave-prevention */ } /* Beschädigte Schiffe können sinken */ for (sh = r->ships; sh;) { shn = sh->next; if (fval(sh, SF_SELECT)) { u = ship_owner(sh); if (sh->damage >= sh->size * DAMAGE_SCALE) { if (u != NULL) { ADDMSG(&u->faction->msgs, msg_message("overrun_by_iceberg_des", "ship", sh)); } remove_ship(&sh->region->ships, sh); } else if (u != NULL) { ADDMSG(&u->faction->msgs, msg_message("overrun_by_iceberg", "ship", sh)); } } sh = shn; } } else if (rng_int() % 100 < 20) { /* Eisberg bleibt als Gletscher liegen */ unit *u; rsetterrain(r, T_GLACIER); a_remove(&r->attribs, a); for (u = r->units; u; u = u->next) freset(u->faction, FFL_SELECT); for (u = r->units; u; u = u->next) if (!fval(u->faction, FFL_SELECT)) { fset(u->faction, FFL_SELECT); ADDMSG(&u->faction->msgs, msg_message("iceberg_land", "region", r)); } } } }
void randomevents(void) { region *r; faction *monsters = get_monsters(); icebergs(); godcurse(); orc_growth(); demon_skillchanges(); /* Orkifizierte Regionen mutieren und mutieren zurück */ for (r = regions; r; r = r->next) { if (fval(r, RF_ORCIFIED)) { direction_t dir; double probability = 0.0; for (dir = 0; dir < MAXDIRECTIONS; dir++) { region *rc = rconnect(r, dir); if (rc && rpeasants(rc) > 0 && !fval(rc, RF_ORCIFIED)) probability += 0.02; } if (chance(probability)) { ADDMSG(&r->msgs, msg_message("deorcified", "region", r)); freset(r, RF_ORCIFIED); } } else { attrib *a = a_find(r->attribs, &at_orcification); if (a != NULL) { double probability = 0.0; if (rpeasants(r) <= 0) continue; probability = a->data.i / (double)rpeasants(r); if (chance(probability)) { fset(r, RF_ORCIFIED); a_remove(&r->attribs, a); ADDMSG(&r->msgs, msg_message("orcified", "region", r)); } else { a->data.i -= _max(10, a->data.i / 10); if (a->data.i <= 0) a_remove(&r->attribs, a); } } } } /* Vulkane qualmen, brechen aus ... */ for (r = regions; r; r = r->next) { if (r->terrain == newterrain(T_VOLCANO_SMOKING)) { if (a_find(r->attribs, &at_reduceproduction)) { ADDMSG(&r->msgs, msg_message("volcanostopsmoke", "region", r)); rsetterrain(r, T_VOLCANO); } else { if (rng_int() % 100 < 12) { ADDMSG(&r->msgs, msg_message("volcanostopsmoke", "region", r)); rsetterrain(r, T_VOLCANO); } else if (r->age > 20 && rng_int() % 100 < 8) { volcano_outbreak(r); } } } else if (r->terrain == newterrain(T_VOLCANO)) { if (rng_int() % 100 < 4) { ADDMSG(&r->msgs, msg_message("volcanostartsmoke", "region", r)); rsetterrain(r, T_VOLCANO_SMOKING); } } } /* Monumente zerfallen, Schiffe verfaulen */ for (r = regions; r; r = r->next) { building **blist = &r->buildings; while (*blist) { building *b = *blist; if (fval(b->type, BTF_DECAY) && !building_owner(b)) { b->size -= _max(1, (b->size * 20) / 100); if (b->size == 0) { remove_building(blist, r->buildings); } } if (*blist == b) blist = &b->next; } } /* monster-einheiten desertieren */ if (monsters) { for (r = regions; r; r = r->next) { unit *u; for (u = r->units; u; u = u->next) { if (u->faction && !is_monsters(u->faction) && (u_race(u)->flags & RCF_DESERT)) { if (fval(u, UFL_ISNEW)) continue; if (rng_int() % 100 < 5) { ADDMSG(&u->faction->msgs, msg_message("desertion", "unit region", u, r)); u_setfaction(u, monsters); } } } } } /* Chaos */ for (r = regions; r; r = r->next) { int i; if (fval(r, RF_CHAOTIC)) { chaos(r); } i = chaoscount(r); if (i) { chaoscounts(r, -(int)(i * ((double)(rng_int() % 10)) / 100.0)); } } #ifdef HERBS_ROT rotting_herbs(); #endif dissolve_units(); }
/* ------------------------------------------------------------- */ void remove_curse(attrib ** ap, const curse * c) { attrib *a = a_select(*ap, c, cmp_curse); if (a) a_remove(ap, a); }
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 learn_cmd(unit * u, order * ord) { region *r = u->region; int p; magic_t mtyp; int l; int studycost, days; double multi = 1.0; attrib *a = NULL; teaching_info *teach = NULL; int money = 0; skill_t sk; int maxalchemy = 0; int speed_rule = (study_rule_t)get_param_int(global.parameters, "study.speedup", 0); static int learn_newskills = -1; if (learn_newskills < 0) { const char *str = get_param(global.parameters, "study.newskills"); if (str && strcmp(str, "false") == 0) learn_newskills = 0; else learn_newskills = 1; } if (!unit_can_study(u)) { ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "error_race_nolearn", "race", u_race(u))); return 0; } init_order(ord); sk = getskill(u->faction->locale); if (sk < 0) { cmistake(u, ord, 77, MSG_EVENT); return 0; } if (SkillCap(sk) && SkillCap(sk) <= effskill(u, sk)) { cmistake(u, ord, 771, MSG_EVENT); return 0; } /* Hack: Talente mit Malus -99 koennen nicht gelernt werden */ if (u_race(u)->bonus[sk] == -99) { cmistake(u, ord, 771, MSG_EVENT); return 0; } if (learn_newskills == 0) { skill *sv = unit_skill(u, sk); if (sv == NULL) { /* we can only learn skills we already have */ cmistake(u, ord, 771, MSG_EVENT); return 0; } } /* snotlings koennen Talente nur bis T8 lernen */ if (u_race(u) == get_race(RC_SNOTLING)) { if (get_level(u, sk) >= 8) { cmistake(u, ord, 308, MSG_EVENT); return 0; } } p = studycost = study_cost(u, sk); a = a_find(u->attribs, &at_learning); if (a != NULL) { teach = (teaching_info *)a->data.v; } /* keine kostenpflichtigen Talente fuer Migranten. Vertraute sind * keine Migranten, wird in is_migrant abgefangen. Vorsicht, * studycost darf hier noch nicht durch Akademie erhoeht sein */ if (studycost > 0 && !ExpensiveMigrants() && is_migrant(u)) { ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "error_migrants_nolearn", "")); return 0; } /* Akademie: */ { struct building *b = inside_building(u); const struct building_type *btype = b ? b->type : NULL; if (btype && btype == bt_find("academy")) { studycost = _max(50, studycost * 2); } } if (sk == SK_MAGIC) { if (u->number > 1) { cmistake(u, ord, 106, MSG_MAGIC); return 0; } if (is_familiar(u)) { /* Vertraute zaehlen nicht zu den Magiern einer Partei, * koennen aber nur Graue Magie lernen */ mtyp = M_GRAY; if (!is_mage(u)) create_mage(u, mtyp); } else if (!has_skill(u, SK_MAGIC)) { int mmax = skill_limit(u->faction, SK_MAGIC); /* Die Einheit ist noch kein Magier */ if (count_skill(u->faction, SK_MAGIC) + u->number > mmax) { ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "error_max_magicians", "amount", mmax)); return 0; } mtyp = getmagicskill(u->faction->locale); if (mtyp == M_NONE || mtyp == M_GRAY) { /* wurde kein Magiegebiet angegeben, wird davon * ausgegangen, dass das normal gelernt werden soll */ if (u->faction->magiegebiet != 0) { mtyp = u->faction->magiegebiet; } else { /* Es wurde kein Magiegebiet angegeben und die Partei * hat noch keins gewaehlt. */ mtyp = getmagicskill(u->faction->locale); if (mtyp == M_NONE) { cmistake(u, ord, 178, MSG_MAGIC); return 0; } } } if (mtyp != u->faction->magiegebiet) { /* Es wurde versucht, ein anderes Magiegebiet zu lernen * als das der Partei */ if (u->faction->magiegebiet != 0) { cmistake(u, ord, 179, MSG_MAGIC); return 0; } else { /* Lernt zum ersten mal Magie und legt damit das * Magiegebiet der Partei fest */ u->faction->magiegebiet = mtyp; } } if (!is_mage(u)) create_mage(u, mtyp); } else { /* ist schon ein Magier und kein Vertrauter */ if (u->faction->magiegebiet == 0) { /* die Partei hat noch kein Magiegebiet gewaehlt. */ mtyp = getmagicskill(u->faction->locale); if (mtyp == M_NONE) { mtyp = getmagicskill(u->faction->locale); if (mtyp == M_NONE) { cmistake(u, ord, 178, MSG_MAGIC); return 0; } } /* Legt damit das Magiegebiet der Partei fest */ u->faction->magiegebiet = mtyp; } } } if (sk == SK_ALCHEMY) { maxalchemy = eff_skill(u, SK_ALCHEMY, r); if (!has_skill(u, SK_ALCHEMY)) { int amax = skill_limit(u->faction, SK_ALCHEMY); if (count_skill(u->faction, SK_ALCHEMY) + u->number > amax) { ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "error_max_alchemists", "amount", amax)); return 0; } } } if (studycost) { int cost = studycost * u->number; money = get_pooled(u, get_resourcetype(R_SILVER), GET_DEFAULT, cost); money = _min(money, cost); } if (money < studycost * u->number) { studycost = p; /* Ohne Univertreurung */ money = _min(money, studycost); if (p > 0 && money < studycost * u->number) { cmistake(u, ord, 65, MSG_EVENT); multi = money / (double)(studycost * u->number); } } if (teach == NULL) { a = a_add(&u->attribs, a_new(&at_learning)); teach = (teaching_info *)a->data.v; teach->teachers[0] = 0; } if (money > 0) { use_pooled(u, get_resourcetype(R_SILVER), GET_DEFAULT, money); ADDMSG(&u->faction->msgs, msg_message("studycost", "unit region cost skill", u, u->region, money, sk)); } if (get_effect(u, oldpotiontype[P_WISE])) { l = _min(u->number, get_effect(u, oldpotiontype[P_WISE])); teach->value += l * 10; change_effect(u, oldpotiontype[P_WISE], -l); } if (get_effect(u, oldpotiontype[P_FOOL])) { l = _min(u->number, get_effect(u, oldpotiontype[P_FOOL])); teach->value -= l * 30; change_effect(u, oldpotiontype[P_FOOL], -l); } if (p != studycost) { /* ist_in_gebaeude(r, u, BT_UNIVERSITAET) == 1) { */ /* p ist Kosten ohne Uni, studycost mit; wenn * p!=studycost, ist die Einheit zwangsweise * in einer Uni */ teach->value += u->number * 10; } if (is_cursed(r->attribs, C_BADLEARN, 0)) { teach->value -= u->number * 10; } multi *= study_speedup(u, sk, speed_rule); days = study_days(u, sk); days = (int)((days + teach->value) * multi); /* the artacademy currently improves the learning of entertainment of all units in the region, to be able to make it cumulative with with an academy */ if (sk == SK_ENTERTAINMENT && buildingtype_exists(r, bt_find("artacademy"), false)) { days *= 2; } if (fval(u, UFL_HUNGER)) days /= 2; while (days) { if (days >= u->number * 30) { learn_skill(u, sk, 1.0); days -= u->number * 30; } else { double chance = (double)days / u->number / 30; learn_skill(u, sk, chance); days = 0; } } if (a != NULL) { if (teach != NULL) { int index = 0; while (teach->teachers[index] && index != MAXTEACHERS) { unit *teacher = teach->teachers[index++]; if (teacher->faction != u->faction) { bool feedback = alliedunit(u, teacher->faction, HELP_GUARD); if (feedback) { ADDMSG(&teacher->faction->msgs, msg_message("teach_teacher", "teacher student skill level", teacher, u, sk, effskill(u, sk))); } ADDMSG(&u->faction->msgs, msg_message("teach_student", "teacher student skill", teacher, u, sk)); } } } a_remove(&u->attribs, a); a = NULL; } fset(u, UFL_LONGACTION | UFL_NOTMOVING); /* Anzeigen neuer Traenke */ /* Spruchlistenaktualiesierung ist in Regeneration */ if (sk == SK_ALCHEMY) { const potion_type *ptype; faction *f = u->faction; int skill = eff_skill(u, SK_ALCHEMY, r); if (skill > maxalchemy) { for (ptype = potiontypes; ptype; ptype = ptype->next) { if (skill == ptype->level * 2) { attrib *a = a_find(f->attribs, &at_showitem); while (a && a->type == &at_showitem && a->data.v != ptype) a = a->next; if (a == NULL || a->type != &at_showitem) { a = a_add(&f->attribs, a_new(&at_showitem)); a->data.v = (void *)ptype->itype; } } } } } else if (sk == SK_MAGIC) { sc_mage *mage = get_mage(u); if (!mage) { mage = create_mage(u, u->faction->magiegebiet); } } return 0; }