/* * C_SLAVE */ static message *cinfo_slave(const void *obj, objtype_t typ, const curse * c, int self) { unit *u; unused_arg(typ); assert(typ == TYP_UNIT); u = (unit *) obj; if (self != 0) { return msg_message("curseinfo::slave_1", "unit duration id", u, c->duration, c->no); } return NULL; }
static int age_reduceproduction(attrib * a, void *owner) { region * r = (region *)owner; int reduce = 100 - (5 * --a->data.sa[1]); assert(r); if (reduce < 10) { reduce = 10; } a->data.sa[0] = (short)reduce; if (a->data.sa[1] > 0) { ADDMSG(&r->msgs, msg_message("reduced_production", "")); return AT_AGE_KEEP; } return AT_AGE_REMOVE; }
static int use_wand_of_tears(unit * user, const struct item_type *itype, int amount, order * ord) { int n; unused_arg(ord); for (n = 0; n != amount; ++n) { unit *u; for (u = user->region->units; u; u = u->next) { if (u->faction != user->faction) { int i; for (i = 0; i != u->skill_size; ++i) { if (rng_int() % 3) reduce_skill(u, u->skills + i, 1); } ADDMSG(&u->faction->msgs, msg_message("wand_of_tears_effect", "unit", u)); } } } ADDMSG(&user->region->msgs, msg_message("wand_of_tears_usage", "unit", user)); return 0; }
static message *cinfo_antimagiczone(const void *obj, objtype_t typ, const curse * c, int self) { unused_arg(typ); unused_arg(self); unused_arg(obj); assert(typ == TYP_REGION); /* Magier spüren eine Antimagiezone */ if (self != 0) { return msg_message("curseinfo::antimagiczone", "id", c->no); } return NULL; }
struct message *msg_feedback(const struct unit *u, struct order *ord, const char *name, const char *sig, ...) { va_list marker; const message_type *mtype = mt_find(name); char paramname[64]; const char *ic = sig; variant args[16]; variant var; memset(args, 0, sizeof(args)); if (ord == NULL) ord = u->thisorder; if (!mtype) { log_error("trying to create message of unknown type \"%s\"\n", name); return msg_message("missing_feedback", "unit region command name", u, u->region, ord, name); } var.v = (void *)u; arg_set(args, mtype, "unit", var); var.v = (void *)u->region; arg_set(args, mtype, "region", var); var.v = (void *)ord; arg_set(args, mtype, "command", var); va_start(marker, sig); while (*ic && !isalnum(*ic)) ic++; while (*ic) { char *oc = paramname; int i; while (isalnum(*ic)) *oc++ = *ic++; *oc = '\0'; for (i = 0; i != mtype->nparameters; ++i) { if (!strcmp(paramname, mtype->pnames[i])) break; } if (i != mtype->nparameters) { if (mtype->types[i]->vtype == VAR_VOIDPTR) { args[i].v = va_arg(marker, void *); } else if (mtype->types[i]->vtype == VAR_INT) { args[i].i = va_arg(marker, int); } else {
int sp_berserk(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; int at_bonus = 0; int df_malus = 0; int force = 0; int allies = 0; int targets = 0; message *m; at_bonus = level / 3; if (at_bonus < 1) at_bonus = 1; df_malus = 2; force = (int)get_force(power, 2); allies = count_allies(fi->side, FIGHT_ROW, BEHIND_ROW - 1, SELECT_ADVANCE, ALLY_ANY); /* maximal 2*allies Versuche ein Opfer zu finden, ansonsten bestuende * die Gefahr eine Endlosschleife*/ allies *= 2; while (force && allies) { troop dt = select_ally(fi, FIGHT_ROW, BEHIND_ROW - 1, ALLY_ANY); fighter *df = dt.fighter; --allies; if (df) { if (!(df->person[dt.index].flags & FL_COURAGE)) { df->person[dt.index].attack += at_bonus; df->person[dt.index].defense -= df_malus; df->person[dt.index].flags = df->person[dt.index].flags | FL_COURAGE; targets++; --force; } } } m = msg_message("cast_berserk_effect", "mage spell amount", fi->unit, sp, targets); message_all(b, m); msg_release(m); return level; }
static void get_villagers(region * r, unit * u) { unit *newunit; message *msg = msg_message("encounter_villagers", "unit", u); const char *name = LOC(u->faction->locale, "villagers"); r_addmessage(r, u->faction, msg); msg_release(msg); newunit = create_unit(r, u->faction, rng_int() % 20 + 3, u->faction->race, 0, name, u); leave(newunit, true); fset(newunit, UFL_ISNEW | UFL_MOVED); equip_unit(newunit, get_equipment("random_villagers")); }
int sp_keeploot(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; message *m = msg_message("cast_spell_effect", "mage spell", fi->unit, sp); message_all(b, m); msg_release(m); b->keeploot = (int)fmax(25, b->keeploot + 5 * power); return level; }
void drown(region * r) { if (fval(r->terrain, SEA_REGION)) { unit **up = &r->units; while (*up) { unit *u = *up; if (!(u->ship || u_race(u) == get_race(RC_SPELL) || u->number == 0 || canswim(u) || canfly(u))) { scale_number(u, 0); ADDMSG(&u->faction->msgs, msg_message("drown", "unit region", u, r)); } up = &u->next; } remove_empty_units_in_region(r); } }
/** handles the "orcish" curse that makes units grow like old orks * This would probably be better handled in an age-function for the curse, * but it's now being called by randomevents() */ static void orc_growth(void) { region *r; for (r = regions; r; r = r->next) { unit *u; for (u = r->units; u; u = u->next) { static bool init = false; static const curse_type *ct_orcish = 0; curse *c = 0; if (!init) { init = true; ct_orcish = ct_find("orcish"); } if (ct_orcish) c = get_curse(u->attribs, ct_orcish); if (c && !has_skill(u, SK_MAGIC) && !has_skill(u, SK_ALCHEMY) && !fval(u, UFL_HERO)) { int n; int increase = 0; int num = get_cursedmen(u, c); double prob = curse_geteffect(c); const item_type * it_chastity = it_find("ao_chastity"); if (it_chastity) { num -= i_get(u->items, it_chastity); } for (n = num; n > 0; n--) { if (chance(prob)) { ++increase; } } if (increase) { unit *u2 = create_unit(r, u->faction, increase, u_race(u), 0, NULL, u); transfermen(u2, u, u2->number); ADDMSG(&u->faction->msgs, msg_message("orcgrowth", "unit amount race", u, increase, u_race(u))); } } } } }
int sp_summon_alp(struct castorder *co) { unit *alp, *opfer; region *r = co_get_region(co); unit *mage = co->magician.u; int cast_level = co->level; spellparameter *pa = co->par; const struct race *rc = get_race(RC_ALP); struct faction *f = get_monsters(); struct message *msg; opfer = pa->param[0]->data.u; /* Der Alp gehört den Monstern, darum erhält der Magier auch keine * Regionsberichte von ihm. Er erhält aber später eine Mitteilung, * sobald der Alp sein Opfer erreicht hat. */ alp = create_unit(r, f, 1, rc, 0, NULL, NULL); set_level(alp, SK_STEALTH, 7); setstatus(alp, ST_FLEE); /* flieht */ { attrib *a = a_add(&alp->attribs, a_new(&at_alp)); alp_data *ad = (alp_data *) a->data.v; ad->mage = mage; ad->target = opfer; } { /* Wenn der Alp stirbt, den Magier nachrichtigen */ add_trigger(&alp->attribs, "destroy", trigger_unitmessage(mage, "trigger_alp_destroy", MSG_EVENT, ML_INFO)); /* Wenn Opfer oder Magier nicht mehr existieren, dann stirbt der Alp */ add_trigger(&mage->attribs, "destroy", trigger_killunit(alp)); add_trigger(&opfer->attribs, "destroy", trigger_killunit(alp)); } msg = msg_message("summon_alp_effect", "mage alp target", mage, alp, opfer); r_addmessage(r, mage->faction, msg); msg_release(msg); return cast_level; }
static void absorbed_by_monster(unit * u) { int n; switch (old_race(u_race(u))) { default: n = rng_int() % (u->number / 20 + 1); } if (n > 0) { n = lovar(n); n = _min(rpeasants(u->region), n); if (n > 0) { rsetpeasants(u->region, rpeasants(u->region) - n); scale_number(u, u->number + n); ADDMSG(&u->region->msgs, msg_message("absorbpeasants", "unit race amount", u, u_race(u), n)); } } }
/** ** GM: TELL REGION <x> <y> <string> ** requires: permission-key "gmmsgr" **/ static void gm_messageregion(const void *tnext, struct unit *u, struct order *ord) { const struct plane *p = rplane(u->region); int x = rel_to_abs(p, u->faction, getint(), 0); int y = rel_to_abs(p, u->faction, getint(), 1); const char *msg = getstrtoken(); region *r = findregion(x, y); if (r == NULL || p != rplane(r)) { mistake(u, ord, "region is in another plane."); } else { /* checking permissions */ attrib *permissions = a_find(u->faction->attribs, &at_permissions); if (!permissions || !has_permission(permissions, atoi36("gmmsgr"))) { mistake(u, ord, "permission denied."); } else { add_message(&r->msgs, msg_message("msg_event", "string", msg)); } } }
/** ** GM: KILL UNIT <id> <string> ** requires: permission-key "gmkill" **/ static void gm_killunit(const void *tnext, struct unit *u, struct order *ord) { const struct plane *p = rplane(u->region); unit *target = findunit(getid()); const char *msg = getstrtoken(); region *r = target->region; if (r == NULL || p != rplane(r)) { mistake(u, ord, "region is in another plane."); } else { /* checking permissions */ attrib *permissions = a_find(u->faction->attribs, &at_permissions); if (!permissions || !has_permission(permissions, atoi36("gmkill"))) { mistake(u, ord, "permission denied."); } else { scale_number(target, 0); ADDMSG(&target->faction->msgs, msg_message("killedbygm", "region unit string", r, target, msg)); } } }
static int begin_potion(unit * u, const potion_type * ptype, struct order *ord) { static int rule_multipotion = -1; assert(ptype != NULL); if (rule_multipotion < 0) { /* should we allow multiple different potions to be used the same turn? */ rule_multipotion = get_param_int(global.parameters, "rules.magic.multipotion", 0); } if (!rule_multipotion) { const potion_type *use = ugetpotionuse(u); if (use != NULL && use != ptype) { ADDMSG(&u->faction->msgs, msg_message("errusingpotion", "unit using command", u, use->itype->rtype, ord)); return ECUSTOM; } } return 0; }
int armor_spell(struct castorder * co, int per_level, int time_multi) { fighter * fi = co->magician.fig; int level = co->level; double power = co->force; const spell * sp = co->sp; int effect; int duration; battle *b = fi->side->battle; message *m = msg_message("cast_spell_effect", "mage spell", fi->unit, sp); message_all(b, m); msg_release(m); /* gibt Ruestung +effect fuer duration Treffer */ effect = level / per_level; duration = (int)(time_multi * power * power); do_meffect(fi, SHIELD_ARMOR, effect, duration); return level; }
int sp_fumbleshield(struct castorder * co) { fighter * fi = co->magician.fig; int level = co->level; const spell * sp = co->sp; int effect; int duration; battle *b = fi->side->battle; message *m = msg_message("cast_spell_effect", "mage spell", fi->unit, sp); message_all(b, m); msg_release(m); /* der erste Zauber schlaegt mit 100% fehl */ duration = 100; effect = 25 - level; if (effect < 1) effect = 1; do_meffect(fi, SHIELD_BLOCK, effect, duration); return level; }
int sp_wolfhowl(struct castorder * co) { fighter * fi = co->magician.fig; int level = co->level; double power = co->force; battle *b = fi->side->battle; region *r = b->region; unit *mage = fi->unit; attrib *a; message *msg; int force = (int)(get_force(power, 3) / 2); const race * rc = new_race[RC_WOLF]; if (force>0) { unit *u = create_unit(r, mage->faction, force, rc, 0, NULL, mage); leave(u, true); setstatus(u, ST_FIGHT); set_level(u, SK_WEAPONLESS, (int)(power / 3)); set_level(u, SK_STAMINA, (int)(power / 3)); u->hp = u->number * unit_max_hp(u); if (fval(mage, UFL_ANON_FACTION)) { fset(u, UFL_ANON_FACTION); } a = a_new(&at_unitdissolve); a->data.ca[0] = 0; a->data.ca[1] = 100; a_add(&u->attribs, a); make_fighter(b, u, fi->side, is_attacker(fi)); } msg = msg_message("sp_wolfhowl_effect", "mage amount race", mage, force, rc); message_all(b, msg); msg_release(msg); return level; }
int sp_speed(struct castorder * co) { fighter * fi = co->magician.fig; double power = co->force; const spell * sp = co->sp; battle *b = fi->side->battle; int force; int allies; int targets = 0; message *m; force = lovar(power * power * 5); allies = count_allies(fi->side, FIGHT_ROW, BEHIND_ROW, SELECT_ADVANCE, ALLY_ANY); /* maximal 2*allies Versuche ein Opfer zu finden, ansonsten bestuende * die Gefahr eine Endlosschleife*/ allies *= 2; while (force && allies) { troop dt = select_ally(fi, FIGHT_ROW, BEHIND_ROW, ALLY_ANY); fighter *df = dt.fighter; --allies; if (df) { if (df->person[dt.index].speed == 1) { df->person[dt.index].speed++; targets++; --force; } } } m = msg_message("cast_speed_effect", "mage spell amount", fi->unit, sp, targets); message_all(b, m); msg_release(m); return 1; }
void plagues(region * r) { int peasants; int i; int dead = 0; peasants = rpeasants(r); dead = (int)(0.5 + PLAGUE_VICTIMS * peasants); for (i = dead; i != 0; i--) { if (rng_double() < PLAGUE_HEALCHANCE && rmoney(r) >= PLAGUE_HEALCOST) { rsetmoney(r, rmoney(r) - PLAGUE_HEALCOST); --dead; } } if (dead > 0) { message *msg = add_message(&r->msgs, msg_message("pest", "dead", dead)); msg_release(msg); deathcounts(r, dead); rsetpeasants(r, peasants - dead); } }
void create_icebergs(void) { region *r; for (r = regions; r; r = r->next) { if (r->terrain == newterrain(T_ICEBERG_SLEEP) && chance(0.05)) { bool has_ocean_neighbour = false; direction_t dir; region *rc; unit *u; freset(r, RF_SELECT); for (dir = 0; dir < MAXDIRECTIONS; dir++) { rc = rconnect(r, dir); if (rc && fval(rc->terrain, SEA_REGION)) { has_ocean_neighbour = true; break; } } if (!has_ocean_neighbour) continue; rsetterrain(r, T_ICEBERG); fset(r, RF_SELECT); move_iceberg(r); 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_create", "region", r)); } } } } }
/** Drachen und Seeschlangen können entstehen */ void spawn_dragons(void) { region *r; faction *monsters = get_or_create_monsters(); for (r = regions; r; r = r->next) { unit *u; if (fval(r->terrain, SEA_REGION) && rng_int() % 10000 < 1) { u = create_unit(r, monsters, 1, get_race(RC_SEASERPENT), 0, NULL, NULL); fset(u, UFL_ISNEW | UFL_MOVED); equip_unit(u, get_equipment("monster_seaserpent")); } if ((r->terrain == newterrain(T_GLACIER) || r->terrain == newterrain(T_SWAMP) || r->terrain == newterrain(T_DESERT)) && rng_int() % 10000 < (5 + 100 * chaosfactor(r))) { if (chance(0.80)) { u = create_unit(r, monsters, nrand(60, 20) + 1, get_race(RC_FIREDRAGON), 0, NULL, NULL); } else { u = create_unit(r, monsters, nrand(30, 20) + 1, get_race(RC_DRAGON), 0, NULL, NULL); } fset(u, UFL_ISNEW | UFL_MOVED); equip_unit(u, get_equipment("monster_dragon")); log_debug("spawning %d %s in %s.\n", u->number, LOC(default_locale, rc_name_s(u_race(u), (u->number == 1) ? NAME_SINGULAR : NAME_PLURAL)), regionname(r, NULL)); name_unit(u); /* add message to the region */ ADDMSG(&r->msgs, msg_message("sighting", "region race number", r, u_race(u), u->number)); } } }
int sp_reduceshield(struct castorder * co) { fighter * fi = co->magician.fig; int level = co->level; double power = co->force; const spell * sp = co->sp; int effect; int duration; battle *b = fi->side->battle; message *m = msg_message("cast_spell_effect", "mage spell", fi->unit, sp); message_all(b, m); msg_release(m); /* jeder Schaden wird um effect% reduziert bis der Schild duration * Trefferpunkte aufgefangen hat */ effect = 50; duration = (int)(50 * power * power); do_meffect(fi, SHIELD_REDUCE, effect, duration); return level; }
void alp_findet_opfer(unit * alp, region * r) { curse *c; attrib *a = a_find(alp->attribs, &at_alp); alp_data *ad = (alp_data *) a->data.v; unit *mage = ad->mage; unit *opfer = ad->target; float effect; message *msg; assert(opfer); assert(mage); /* Magier und Opfer Bescheid geben */ msg = msg_message("alp_success", "target", opfer); add_message(&mage->faction->msgs, msg); r_addmessage(opfer->region, opfer->faction, msg); msg_release(msg); /* Relations werden in destroy_unit(alp) automatisch gelöscht. * Die Aktionen, die beim Tod des Alps ausgelöst werden sollen, * müssen jetzt aber deaktiviert werden, sonst werden sie gleich * beim destroy_unit(alp) ausgelöst. */ a_removeall(&alp->attribs, &at_eventhandler); /* Alp umwandeln in Curse */ effect = -2; c = create_curse(mage, &opfer->attribs, ct_find("worse"), 2, 2, effect, opfer->number); /* solange es noch keine spezielle alp-Antimagie gibt, reagiert der * auch auf normale */ set_number(alp, 0); /* wenn der Magier stirbt, wird der Curse wieder vom Opfer genommen */ add_trigger(&mage->attribs, "destroy", trigger_removecurse(c, opfer)); }
void test_message(CuTest *tc) { message *msg; message_type *mtype; test_setup(); mtype = mt_create(mt_new("custom", NULL), NULL, 0); CuAssertPtrEquals(tc, mtype, (void *)mt_find("custom")); CuAssertIntEquals(tc, 0, mtype->nparameters); CuAssertPtrEquals(tc, NULL, (void *)mtype->pnames); CuAssertPtrEquals(tc, NULL, (void *)mtype->types); msg = msg_message("custom", ""); CuAssertPtrNotNull(tc, msg); CuAssertIntEquals(tc, 1, msg->refcount); CuAssertPtrEquals(tc, NULL, msg->parameters); CuAssertPtrEquals(tc, mtype, (void *)msg->type); CuAssertPtrEquals(tc, msg, msg_addref(msg)); CuAssertIntEquals(tc, 2, msg->refcount); msg_release(msg); CuAssertIntEquals(tc, 1, msg->refcount); msg_release(msg); test_teardown(); }
int sp_shadowknights(struct castorder * co) { fighter * fi = co->magician.fig; int level = co->level; double power = co->force; unit *u; battle *b = fi->side->battle; region *r = b->region; unit *mage = fi->unit; attrib *a; int force = (int)fmax(1, get_force(power, 3)); message *msg; u = create_unit(r, mage->faction, force, get_race(RC_SHADOWKNIGHT), 0, NULL, mage); unit_setstatus(u, ST_FIGHT); u->hp = u->number * unit_max_hp(u); if (mage->flags & UFL_ANON_FACTION) { u->flags |= UFL_ANON_FACTION; } a = a_new(&at_unitdissolve); a->data.ca[0] = 0; a->data.ca[1] = 100; a_add(&u->attribs, a); make_fighter(b, u, fi->side, is_attacker(fi)); msg = msg_message("sp_shadowknights_effect", "mage", mage); message_all(b, msg); msg_release(msg); return level; }
static void godcurse(void) { region *r; for (r = regions; r; r = r->next) { if (is_cursed(r->attribs, C_CURSED_BY_THE_GODS, 0)) { unit *u; for (u = r->units; u; u = u->next) { skill *sv = u->skills; while (sv != u->skills + u->skill_size) { int weeks = 1 + rng_int() % 3; reduce_skill(u, sv, weeks); ++sv; } } if (fval(r->terrain, SEA_REGION)) { ship *sh; for (sh = r->ships; sh;) { ship *shn = sh->next; float dmg = get_param_flt(global.parameters, "rules.ship.damage.godcurse", 0.10F); damage_ship(sh, dmg); if (sh->damage >= sh->size * DAMAGE_SCALE) { unit *u = ship_owner(sh); if (u) ADDMSG(&u->faction->msgs, msg_message("godcurse_destroy_ship", "ship", sh)); remove_ship(&sh->region->ships, sh); } sh = shn; } } } } }
static void do_shock(unit * u, const char *reason) { int i; if (u->number > 0) { /* HP - Verlust */ u->hp = (unit_max_hp(u) * u->number) / 10; u->hp = _max(1, u->hp); } /* Aura - Verlust */ if (is_mage(u)) { set_spellpoints(u, max_spellpoints(u->region, u) / 10); } /* Evt. Talenttageverlust */ for (i = 0; i != u->skill_size; ++i) if (rng_int() % 5 == 0) { skill *sv = u->skills + i; int weeks = (sv->level * sv->level - sv->level) / 2; int change = (weeks + 9) / 10; reduce_skill(u, sv, change); } /* Dies ist ein Hack, um das skillmod und familiar-Attribut beim Mage * zu löschen wenn der Familiar getötet wird. Da sollten wir über eine * saubere Implementation nachdenken. */ if (strcmp(reason, "trigger") == 0) { remove_familiar(u); } if (u->faction != NULL) { ADDMSG(&u->faction->msgs, msg_message("shock", "mage reason", u, _strdup(reason))); } }
static int leave_fail(unit * u) { ADDMSG(&u->faction->msgs, msg_message("arena_leave_fail", "unit", u)); return 1; }
static int enter_fail(unit * u) { ADDMSG(&u->faction->msgs, msg_message("arena_enter_fail", "region unit", u->region, u)); return 1; }