forked from github/server
Merge branch 'develop' of github.com:ennorehling/eressea into develop
This commit is contained in:
commit
8e9f8be007
|
@ -96,7 +96,6 @@ function test_follow_ship()
|
|||
local f = faction.create("human", "test@example.com", "de")
|
||||
local u1 = unit.create(f, r1, 1)
|
||||
local u2 = unit.create(f, r1, 1)
|
||||
u2.name = 'Xolgrim'
|
||||
u1:add_item("money", 100)
|
||||
u2:add_item("money", 100)
|
||||
u1.ship = ship.create(r1, "boat")
|
||||
|
|
|
@ -10,6 +10,7 @@ function setup()
|
|||
eressea.settings.set("rules.food.flags", "4")
|
||||
eressea.settings.set("rules.peasants.growth.factor", "0")
|
||||
eressea.settings.set("magic.fumble.enable", "0")
|
||||
eressea.settings.set("magic.regeneration.enable", "0")
|
||||
end
|
||||
|
||||
function test_shapeshift()
|
||||
|
@ -104,6 +105,52 @@ function test_earn_silver()
|
|||
assert_equal(0, r:get_resource("money"))
|
||||
end
|
||||
|
||||
function test_familiar_cast()
|
||||
local r = region.create(0, 0, "plain")
|
||||
r:set_resource("money", 350)
|
||||
r:set_resource("peasant", 0)
|
||||
local f = faction.create("human")
|
||||
local u = unit.create(f, r)
|
||||
u.magic = "gwyrrd"
|
||||
u:set_skill("magic", 10)
|
||||
u.aura = 200
|
||||
u:add_spell("earn_silver#gwyrrd")
|
||||
u:add_order('ARBEITE')
|
||||
local uf = unit.create(f, r)
|
||||
uf.race = "lynx"
|
||||
uf:set_skill("magic", 5)
|
||||
uf:add_order('ZAUBER STUFE 1 Viehheilung')
|
||||
u.familiar = uf
|
||||
process_orders()
|
||||
assert_equal(198, u.aura) -- Fremdzauber, Kosten verdoppelt
|
||||
assert_equal(10, u:get_item('money')) -- von ARBEITE
|
||||
assert_equal(50, uf:get_item('money')) -- von Zauber
|
||||
assert_equal(300, uf.region:get_resource("money"))
|
||||
end
|
||||
|
||||
function test_familiar_mage_actions()
|
||||
local r = region.create(0, 0, "plain")
|
||||
r:set_resource("money", 350)
|
||||
r:set_resource("peasant", 0)
|
||||
local f = faction.create("human")
|
||||
local u = unit.create(f, r)
|
||||
u.magic = "gwyrrd"
|
||||
u:set_skill("magic", 10)
|
||||
u.aura = 200
|
||||
u:add_spell("earn_silver#gwyrrd")
|
||||
u:add_order('ZAUBER STUFE 1 Viehheilung')
|
||||
local uf = unit.create(f, r)
|
||||
uf.race = "lynx"
|
||||
uf:set_skill("magic", 5)
|
||||
uf:add_order('ZAUBER STUFE 1 Viehheilung')
|
||||
u.familiar = uf
|
||||
process_orders()
|
||||
assert_equal(50, u:get_item('money'))
|
||||
assert_equal(50, uf:get_item('money'))
|
||||
assert_equal(250, uf.region:get_resource("money"))
|
||||
assert_equal(197, u.aura)
|
||||
end
|
||||
|
||||
function test_familiar()
|
||||
local r = region.create(0, 0, "mountain")
|
||||
local f = faction.create("human")
|
||||
|
@ -148,3 +195,55 @@ function test_bug_2480()
|
|||
process_orders()
|
||||
assert_equal(0, u1.number);
|
||||
end
|
||||
|
||||
function test_bug_2517()
|
||||
local r = region.create(0, 0, "plain")
|
||||
local f = faction.create("elf")
|
||||
local um = unit.create(f, r, 1)
|
||||
local uf = nil
|
||||
eressea.settings.set("magic.familiar.race", "lynx")
|
||||
f.magic = 'gwyrrd'
|
||||
um.name = 'Xolgrim'
|
||||
um.magic = 'gwyrrd'
|
||||
um.race = 'elf'
|
||||
um:set_skill('magic', 10)
|
||||
um:add_spell('summon_familiar')
|
||||
um:add_spell('earn_silver#gwyrrd')
|
||||
um:add_order('ZAUBERE Vertrauten~rufen')
|
||||
um.aura = 200
|
||||
process_orders()
|
||||
uf = um.familiar
|
||||
assert_not_nil(uf)
|
||||
assert_equal('lynx', uf.race)
|
||||
assert_nil(uf.magic)
|
||||
uf:add_order('LERNE Magie')
|
||||
um:clear_orders()
|
||||
um:add_order('ARBEITEN')
|
||||
process_orders()
|
||||
assert_nil(uf.magic)
|
||||
uf:add_order('ZAUBERE STUFE 1 Viehheilung')
|
||||
process_orders()
|
||||
assert_equal(50, uf:get_item('money'))
|
||||
end
|
||||
|
||||
function test_familiar_school()
|
||||
local r = region.create(0, 0, "plain")
|
||||
r:set_resource("money", 350)
|
||||
r:set_resource("peasant", 0)
|
||||
local f = faction.create("human")
|
||||
local u = unit.create(f, r)
|
||||
u.magic = "draig"
|
||||
u:set_skill("magic", 10)
|
||||
u.aura = 200
|
||||
u:add_spell("fireball")
|
||||
local uf = unit.create(f, r)
|
||||
uf.race = "lynx"
|
||||
u.familiar = uf
|
||||
|
||||
assert_nil(uf.magic)
|
||||
uf:set_skill("magic", 5)
|
||||
assert_nil(uf.magic)
|
||||
uf.aura = 10
|
||||
assert_equal(0, uf.aura)
|
||||
assert_nil(uf.magic)
|
||||
end
|
||||
|
|
|
@ -67,6 +67,7 @@ void new_potiontype(item_type * itype, int level)
|
|||
potion_type *ptype;
|
||||
|
||||
ptype = (potion_type *)calloc(1, sizeof(potion_type));
|
||||
assert(ptype);
|
||||
itype->flags |= ITF_POTION;
|
||||
ptype->itype = itype;
|
||||
ptype->level = level;
|
||||
|
|
72
src/battle.c
72
src/battle.c
|
@ -134,6 +134,7 @@ static int rule_cavalry_skill;
|
|||
static int rule_population_damage;
|
||||
static int rule_hero_speed;
|
||||
static bool rule_anon_battle;
|
||||
static bool rule_igjarjuk_curse;
|
||||
static int rule_goblin_bonus;
|
||||
static int rule_tactics_formula;
|
||||
static int rule_nat_armor;
|
||||
|
@ -156,6 +157,7 @@ static void init_rules(void)
|
|||
rule_hero_speed = config_get_int("rules.combat.herospeed", 10);
|
||||
rule_population_damage = config_get_int("rules.combat.populationdamage", 20);
|
||||
rule_anon_battle = config_get_int("rules.stealth.anon_battle", 1) != 0;
|
||||
rule_igjarjuk_curse = config_get_int("rules.combat.igjarjuk_curse", 0) != 0;
|
||||
rule_cavalry_mode = config_get_int("rules.cavalry.mode", 1);
|
||||
rule_cavalry_skill = config_get_int("rules.cavalry.skill", 2);
|
||||
rule_vampire = config_get_int("rules.combat.demon_vampire", 0);
|
||||
|
@ -486,7 +488,7 @@ contest_classic(int skilldiff, const armor_type * ar, const armor_type * sh)
|
|||
mod *= (1 + ar->penalty);
|
||||
if (sh != NULL)
|
||||
mod *= (1 + sh->penalty);
|
||||
vw = (int)(100 - ((100 - vw) * mod));
|
||||
vw = (int)(100.0 - ((100.0 - (double)vw) * mod));
|
||||
|
||||
do {
|
||||
p = (int)(rng_int() % 100);
|
||||
|
@ -1224,7 +1226,7 @@ static void calculate_attack_type(troop dt, troop at, int type, bool missile,
|
|||
static int crit_damage(int attskill, int defskill, const char *damage_formula) {
|
||||
int damage = 0;
|
||||
if (rule_damage & DAMAGE_CRITICAL) {
|
||||
double kritchance = (attskill * 3 - defskill) / 200.0;
|
||||
double kritchance = ((double)attskill * 3.0 - (double)defskill) / 200.0;
|
||||
int maxk = 4;
|
||||
|
||||
kritchance = fmax(kritchance, 0.005);
|
||||
|
@ -1748,13 +1750,14 @@ void do_combatmagic(battle * b, combatmagic_t was)
|
|||
|
||||
memset(spellranks, 0, sizeof(spellranks));
|
||||
|
||||
if (was == DO_PRECOMBATSPELL) {
|
||||
if (rule_igjarjuk_curse && was == DO_PRECOMBATSPELL) {
|
||||
summon_igjarjuk(b, spellranks);
|
||||
}
|
||||
for (s = b->sides; s != b->sides + b->nsides; ++s) {
|
||||
fighter *fig;
|
||||
for (fig = s->fighters; fig; fig = fig->next) {
|
||||
unit *mage = fig->unit;
|
||||
unit *caster = mage;
|
||||
|
||||
if (fig->alive <= 0)
|
||||
continue; /* fighter kann im Kampf get<65>tet worden sein */
|
||||
|
@ -1788,7 +1791,7 @@ void do_combatmagic(battle * b, combatmagic_t was)
|
|||
continue;
|
||||
}
|
||||
|
||||
level = eff_spelllevel(mage, sp, level, 1);
|
||||
level = eff_spelllevel(mage, caster, sp, level, 1);
|
||||
if (sl > 0 && sl < level) {
|
||||
level = sl;
|
||||
}
|
||||
|
@ -1802,11 +1805,11 @@ void do_combatmagic(battle * b, combatmagic_t was)
|
|||
free_order(ord);
|
||||
if (power <= 0) { /* Effekt von Antimagie */
|
||||
report_failed_spell(b, mage, sp);
|
||||
pay_spell(mage, sp, level, 1);
|
||||
pay_spell(mage, NULL, sp, level, 1);
|
||||
}
|
||||
else if (fumble(r, mage, sp, level)) {
|
||||
report_failed_spell(b, mage, sp);
|
||||
pay_spell(mage, sp, level, 1);
|
||||
pay_spell(mage, NULL, sp, level, 1);
|
||||
}
|
||||
else {
|
||||
co = create_castorder_combat(0, fig, sp, level, power);
|
||||
|
@ -1822,7 +1825,7 @@ void do_combatmagic(battle * b, combatmagic_t was)
|
|||
|
||||
level = cast_spell(co);
|
||||
if (level > 0) {
|
||||
pay_spell(fig->unit, sp, level, 1);
|
||||
pay_spell(fig->unit, NULL, sp, level, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1839,7 +1842,7 @@ static int cast_combatspell(troop at, const spell * sp, int level, double force)
|
|||
level = cast_spell(&co);
|
||||
free_castorder(&co);
|
||||
if (level > 0) {
|
||||
pay_spell(at.fighter->unit, sp, level, 1);
|
||||
pay_spell(at.fighter->unit, NULL, sp, level, 1);
|
||||
}
|
||||
return level;
|
||||
}
|
||||
|
@ -1848,7 +1851,7 @@ static void do_combatspell(troop at)
|
|||
{
|
||||
const spell *sp;
|
||||
fighter *fi = at.fighter;
|
||||
unit *caster = fi->unit;
|
||||
unit *mage = fi->unit;
|
||||
battle *b = fi->side->battle;
|
||||
region *r = b->region;
|
||||
selist *ql;
|
||||
|
@ -1857,28 +1860,28 @@ static void do_combatspell(troop at)
|
|||
int fumblechance = 0;
|
||||
order *ord;
|
||||
int sl;
|
||||
const struct locale *lang = caster->faction->locale;
|
||||
const struct locale *lang = mage->faction->locale;
|
||||
|
||||
sp = get_combatspell(caster, 1);
|
||||
sp = get_combatspell(mage, 1);
|
||||
if (sp == NULL) {
|
||||
fi->magic = 0; /* Hat keinen Kampfzauber, k<>mpft nichtmagisch weiter */
|
||||
return;
|
||||
}
|
||||
ord = create_order(K_CAST, lang, "'%s'", spell_name(sp, lang));
|
||||
if (!cancast(caster, sp, 1, 1, ord)) {
|
||||
if (!cancast(mage, sp, 1, 1, ord)) {
|
||||
fi->magic = 0; /* Kann nicht mehr Zaubern, k<>mpft nichtmagisch weiter */
|
||||
return;
|
||||
}
|
||||
|
||||
level = eff_spelllevel(caster, sp, fi->magic, 1);
|
||||
sl = get_combatspelllevel(caster, 1);
|
||||
level = eff_spelllevel(mage, mage, sp, fi->magic, 1);
|
||||
sl = get_combatspelllevel(mage, 1);
|
||||
if (sl > 0 && sl < level) {
|
||||
level = sl;
|
||||
}
|
||||
|
||||
if (fumble(r, caster, sp, level)) {
|
||||
report_failed_spell(b, caster, sp);
|
||||
pay_spell(caster, sp, level, 1);
|
||||
if (fumble(r, mage, sp, level)) {
|
||||
report_failed_spell(b, mage, sp);
|
||||
pay_spell(mage, NULL, sp, level, 1);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1894,16 +1897,16 @@ static void do_combatspell(troop at)
|
|||
|
||||
/* Antimagie die Fehlschlag erh<72>ht */
|
||||
if (rng_int() % 100 < fumblechance) {
|
||||
report_failed_spell(b, caster, sp);
|
||||
pay_spell(caster, sp, level, 1);
|
||||
report_failed_spell(b, mage, sp);
|
||||
pay_spell(mage, NULL, sp, level, 1);
|
||||
free_order(ord);
|
||||
return;
|
||||
}
|
||||
power = spellpower(r, caster, sp, level, ord);
|
||||
power = spellpower(r, mage, sp, level, ord);
|
||||
free_order(ord);
|
||||
if (power <= 0) { /* Effekt von Antimagie */
|
||||
report_failed_spell(b, caster, sp);
|
||||
pay_spell(caster, sp, level, 1);
|
||||
report_failed_spell(b, mage, sp);
|
||||
pay_spell(mage, NULL, sp, level, 1);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -2076,6 +2079,7 @@ void dazzle(battle * b, troop * td)
|
|||
|
||||
void damage_building(battle * b, building * bldg, int damage_abs)
|
||||
{
|
||||
assert(bldg);
|
||||
bldg->size = MAX(1, bldg->size - damage_abs);
|
||||
|
||||
/* Wenn Burg, dann gucken, ob die Leute alle noch in das Geb<65>ude passen. */
|
||||
|
@ -3425,11 +3429,12 @@ int join_battle(battle * b, unit * u, bool attack, fighter ** cp)
|
|||
|
||||
battle *make_battle(region * r)
|
||||
{
|
||||
battle *b = (battle *)calloc(1, sizeof(battle));
|
||||
unit *u;
|
||||
bfaction *bf;
|
||||
building * bld;
|
||||
battle *b = (battle *)calloc(1, sizeof(battle));
|
||||
|
||||
assert(b);
|
||||
/* Alle Mann raus aus der Burg! */
|
||||
for (bld = r->buildings; bld != NULL; bld = bld->next)
|
||||
bld->sizeleft = bld->size;
|
||||
|
@ -3447,6 +3452,7 @@ battle *make_battle(region * r)
|
|||
}
|
||||
if (!bf) {
|
||||
bf = (bfaction *)calloc(1, sizeof(bfaction));
|
||||
assert(bf);
|
||||
++b->nfactions;
|
||||
bf->faction = u->faction;
|
||||
bf->next = b->factions;
|
||||
|
@ -3470,14 +3476,15 @@ static void free_side(side * si)
|
|||
|
||||
static void free_fighter(fighter * fig)
|
||||
{
|
||||
armor **ap = &fig->armors;
|
||||
while (*ap) {
|
||||
armor *a = *ap;
|
||||
*ap = a->next;
|
||||
free(a);
|
||||
}
|
||||
while (fig->loot) {
|
||||
i_free(i_remove(&fig->loot, fig->loot));
|
||||
}
|
||||
while (fig->armors) {
|
||||
armor *a = fig->armors;
|
||||
fig->armors = a->next;
|
||||
free(a);
|
||||
}
|
||||
free(fig->person);
|
||||
free(fig->weapons);
|
||||
|
||||
|
@ -3489,13 +3496,14 @@ static void battle_free(battle * b) {
|
|||
assert(b);
|
||||
|
||||
for (s = b->sides; s != b->sides + b->nsides; ++s) {
|
||||
fighter *fnext = s->fighters;
|
||||
while (fnext) {
|
||||
fighter *fig = fnext;
|
||||
fnext = fig->next;
|
||||
fighter **fp = &s->fighters;
|
||||
while (*fp) {
|
||||
fighter *fig = *fp;
|
||||
*fp = fig->next;
|
||||
free_fighter(fig);
|
||||
free(fig);
|
||||
}
|
||||
s->fighters = NULL;
|
||||
free_side(s);
|
||||
}
|
||||
free(b);
|
||||
|
|
|
@ -5,7 +5,6 @@
|
|||
#include "bind_process.h"
|
||||
|
||||
#include "battle.h"
|
||||
#include "contact.h"
|
||||
#include "economy.h"
|
||||
#include "laws.h"
|
||||
#include "magic.h"
|
||||
|
|
|
@ -52,7 +52,6 @@
|
|||
#include <util/language.h>
|
||||
#include <util/log.h>
|
||||
#include <util/macros.h>
|
||||
#include <util/message.h>
|
||||
#include <util/rand.h>
|
||||
#include <util/rng.h>
|
||||
|
||||
|
|
|
@ -607,7 +607,7 @@ struct spellbook * faction_get_spellbook(struct faction *f)
|
|||
if (f->magiegebiet != M_GRAY) {
|
||||
return get_spellbook(magic_school[f->magiegebiet]);
|
||||
}
|
||||
return 0;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int allied_skillcount(const faction * f, skill_t sk)
|
||||
|
|
|
@ -39,8 +39,9 @@
|
|||
#define FIXATKEYS_VERSION 361 /* remove global.attribs, fix at_keys */
|
||||
#define FACTION_UID_VERSION 362 /* f->uid contains a database id */
|
||||
#define CRYPT_VERSION 363 /* passwords are encrypted */
|
||||
#define FAMILIAR_FIXMAGE_VERSION 364 /* familiar links are fixed */
|
||||
|
||||
#define RELEASE_VERSION CRYPT_VERSION /* current datafile */
|
||||
#define RELEASE_VERSION FAMILIAR_FIXMAGE_VERSION /* current datafile */
|
||||
#define MIN_VERSION UIDHASH_VERSION /* minimal datafile we support */
|
||||
#define MAX_VERSION RELEASE_VERSION /* change this if we can need to read the future datafile, and we can do so */
|
||||
|
||||
|
|
|
@ -26,7 +26,6 @@ extern "C" {
|
|||
#include <util/message.h>
|
||||
|
||||
struct faction;
|
||||
struct msglevel;
|
||||
|
||||
typedef struct mlist {
|
||||
struct mlist *next;
|
||||
|
@ -39,13 +38,6 @@ extern "C" {
|
|||
|
||||
void free_messagelist(struct mlist *msgs);
|
||||
|
||||
typedef struct msglevel {
|
||||
/* used to set specialized msg-levels */
|
||||
struct msglevel *next;
|
||||
const struct message_type *type;
|
||||
int level;
|
||||
} msglevel;
|
||||
|
||||
#define MESSAGE_MISSING_IGNORE 0
|
||||
#define MESSAGE_MISSING_ERROR 1
|
||||
#define MESSAGE_MISSING_REPLACE 2
|
||||
|
|
|
@ -1293,50 +1293,63 @@ ship *read_ship(gamedata *data)
|
|||
return sh;
|
||||
}
|
||||
|
||||
static void fix_fam_mage(unit *u) {
|
||||
sc_mage *m = get_mage(u);
|
||||
if (m && m->magietyp != M_GRAY) {
|
||||
/* unit should be a familiar that has aura and a spell-list */
|
||||
if (!m->spellbook) {
|
||||
m->magietyp = M_GRAY;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void fix_familiars(void) {
|
||||
static void fix_fam_triggers(unit *u) {
|
||||
attrib * a = a_find(u->attribs, &at_mage);
|
||||
attrib * am = a_find(u->attribs, &at_familiarmage);
|
||||
if (!am && a) {
|
||||
/* not a familiar, but magical */
|
||||
attrib * ae = a_find(u->attribs, &at_eventhandler);
|
||||
if (ae) {
|
||||
trigger **tlist;
|
||||
tlist = get_triggers(ae, "destroy");
|
||||
if (tlist) {
|
||||
trigger *t;
|
||||
unit *um = NULL;
|
||||
for (t = *tlist; t; t = t->next) {
|
||||
if (t->type == &tt_shock) {
|
||||
um = (unit *)t->data.v;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (um) {
|
||||
attrib *af = a_find(um->attribs, &at_familiar);
|
||||
log_error("%s seems to be a broken familiar of %s.",
|
||||
unitname(u), unitname(um));
|
||||
if (af) {
|
||||
unit * uf = (unit *)af->data.v;
|
||||
log_error("%s already has a familiar: %s.",
|
||||
unitname(um), unitname(uf));
|
||||
}
|
||||
else {
|
||||
set_familiar(um, u);
|
||||
}
|
||||
}
|
||||
else {
|
||||
log_error("%s seems to be a broken familiar with no trigger.", unitname(u));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void fix_familiars(void (*callback)(unit *)) {
|
||||
region *r;
|
||||
for (r = regions; r; r = r->next) {
|
||||
unit * u;
|
||||
for (u = r->units; u; u = u->next) {
|
||||
if (u->_race != u->faction->race && (u->_race->flags & RCF_FAMILIAR)) {
|
||||
/* unit is potentially a familiar */
|
||||
attrib * a = a_find(u->attribs, &at_mage);
|
||||
attrib * am = a_find(u->attribs, &at_familiarmage);
|
||||
if (!am && a) {
|
||||
/* not a familiar, but magical */
|
||||
attrib * ae = a_find(u->attribs, &at_eventhandler);
|
||||
if (ae) {
|
||||
trigger **tlist;
|
||||
tlist = get_triggers(ae, "destroy");
|
||||
if (tlist) {
|
||||
trigger *t;
|
||||
unit *um = NULL;
|
||||
for (t = *tlist; t; t = t->next) {
|
||||
if (t->type == &tt_shock) {
|
||||
um = (unit *)t->data.v;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (um) {
|
||||
attrib *af = a_find(um->attribs, &at_familiar);
|
||||
log_error("%s seems to be a broken familiar of %s.",
|
||||
unitname(u), unitname(um));
|
||||
if (af) {
|
||||
unit * uf = (unit *)af->data.v;
|
||||
log_error("%s already has a familiar: %s.",
|
||||
unitname(um), unitname(uf));
|
||||
}
|
||||
else {
|
||||
set_familiar(um, u);
|
||||
}
|
||||
}
|
||||
else {
|
||||
log_error("%s seems to be a broken familiar with no trigger.", unitname(u));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
callback(u);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1524,7 +1537,10 @@ int read_game(gamedata *data)
|
|||
}
|
||||
|
||||
if (data->version < FAMILIAR_FIX_VERSION) {
|
||||
fix_familiars();
|
||||
fix_familiars(fix_fam_triggers);
|
||||
}
|
||||
if (data->version < FAMILIAR_FIXMAGE_VERSION) {
|
||||
fix_familiars(fix_fam_mage);
|
||||
}
|
||||
|
||||
log_debug("Done loading turn %d.", turn);
|
||||
|
|
|
@ -208,6 +208,7 @@ static buddy *get_friends(const unit * u, int *numfriends)
|
|||
nf = *fr;
|
||||
if (nf == NULL || nf->faction != u2->faction) {
|
||||
nf = malloc(sizeof(buddy));
|
||||
assert(nf);
|
||||
nf->next = *fr;
|
||||
nf->faction = u2->faction;
|
||||
nf->unit = u2;
|
||||
|
@ -1004,11 +1005,15 @@ skill *add_skill(unit * u, skill_t sk)
|
|||
skill *sv;
|
||||
int i;
|
||||
|
||||
assert(u);
|
||||
for (i = 0; i != u->skill_size; ++i) {
|
||||
sv = u->skills + i;
|
||||
if (sv->id >= sk) break;
|
||||
}
|
||||
u->skills = realloc(u->skills, (1 + u->skill_size) * sizeof(skill));
|
||||
sv = realloc(u->skills, (1 + u->skill_size) * sizeof(skill));
|
||||
assert(sv);
|
||||
u->skills = sv;
|
||||
|
||||
sv = u->skills + i;
|
||||
if (i < u->skill_size) {
|
||||
assert(sv->id != sk);
|
||||
|
@ -1244,24 +1249,30 @@ int invisible(const unit * target, const unit * viewer)
|
|||
*/
|
||||
void free_unit(unit * u)
|
||||
{
|
||||
struct reservation **pres = &u->reservations;
|
||||
|
||||
assert(!u->region);
|
||||
free(u->_name);
|
||||
free_order(u->thisorder);
|
||||
free_orders(&u->orders);
|
||||
if (u->skills)
|
||||
|
||||
while (*pres) {
|
||||
struct reservation *res = *pres;
|
||||
*pres = res->next;
|
||||
free(res);
|
||||
}
|
||||
if (u->skills) {
|
||||
free(u->skills);
|
||||
u->skills = NULL;
|
||||
}
|
||||
while (u->items) {
|
||||
item *it = u->items->next;
|
||||
u->items->next = NULL;
|
||||
i_free(u->items);
|
||||
u->items = it;
|
||||
}
|
||||
while (u->attribs)
|
||||
while (u->attribs) {
|
||||
a_remove(&u->attribs, u->attribs);
|
||||
while (u->reservations) {
|
||||
struct reservation *res = u->reservations;
|
||||
u->reservations = res->next;
|
||||
free(res);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1671,7 +1682,7 @@ struct spellbook * unit_get_spellbook(const struct unit * u)
|
|||
return faction_get_spellbook(u->faction);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int effskill(const unit * u, skill_t sk, const region *r)
|
||||
|
|
261
src/magic.c
261
src/magic.c
|
@ -657,8 +657,6 @@ int change_maxspellpoints(unit * u, int csp)
|
|||
|
||||
/* ------------------------------------------------------------- */
|
||||
/* Counter für die bereits gezauberte Anzahl Sprüche pro Runde.
|
||||
* Um nur die Zahl der bereits gezauberten Sprüche zu ermitteln mit
|
||||
* step = 0 aufrufen.
|
||||
*/
|
||||
int countspells(unit * u, int step)
|
||||
{
|
||||
|
@ -666,36 +664,60 @@ int countspells(unit * u, int step)
|
|||
int count;
|
||||
|
||||
m = get_mage_depr(u);
|
||||
if (!m)
|
||||
if (!m) {
|
||||
return 0;
|
||||
|
||||
if (step == 0)
|
||||
}
|
||||
if (step == 0) {
|
||||
return m->spellcount;
|
||||
|
||||
}
|
||||
count = m->spellcount + step;
|
||||
|
||||
m->spellcount = (count > 0) ? count : 0;
|
||||
return m->spellcount;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------- */
|
||||
/* Die für den Spruch benötigte Aura pro Stufe.
|
||||
* Die Grundkosten pro Stufe werden hier um 2^count erhöht. Der
|
||||
* Parameter count ist dabei die Anzahl der bereits gezauberten Sprüche
|
||||
int spellcount(const unit *u) {
|
||||
sc_mage *m = get_mage_depr(u);
|
||||
if (m) {
|
||||
return m->spellcount;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Die Grundkosten pro Stufe werden um 2^count erhöht. countspells(u)
|
||||
* ist dabei die Anzahl der bereits gezauberten Sprüche
|
||||
*/
|
||||
int spellcost(unit * u, const spell * sp)
|
||||
int aura_multiplier(const unit * u) {
|
||||
int count = spellcount(u);
|
||||
return (1 << count);
|
||||
}
|
||||
|
||||
int spellcost(const unit * caster, const struct spell_component *spc)
|
||||
{
|
||||
int k, aura = 0;
|
||||
int count = countspells(u, 0);
|
||||
const resource_type *r_aura = get_resourcetype(R_AURA);
|
||||
|
||||
for (k = 0; sp->components && sp->components[k].type; k++) {
|
||||
if (sp->components[k].type == r_aura) {
|
||||
aura = sp->components[k].amount;
|
||||
if (spc->type == r_aura) {
|
||||
return spc->amount * aura_multiplier(caster);
|
||||
}
|
||||
return spc->amount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Die für den Spruch benötigte Aura pro Stufe.
|
||||
*/
|
||||
int auracost(const unit *caster, const spell *sp) {
|
||||
const resource_type *r_aura = get_resourcetype(R_AURA);
|
||||
if (sp->components) {
|
||||
int k;
|
||||
for (k = 0; sp->components[k].type; ++k) {
|
||||
const struct spell_component *spc = sp->components + k;
|
||||
if (r_aura == spc->type) {
|
||||
return spc->amount * aura_multiplier(caster);
|
||||
}
|
||||
}
|
||||
}
|
||||
aura *= (1 << count);
|
||||
return aura;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------- */
|
||||
|
@ -726,17 +748,17 @@ static int spl_costtyp(const spell * sp)
|
|||
return costtyp;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------- */
|
||||
/* durch Komponenten und cast_level begrenzter maximal möglicher
|
||||
* Level
|
||||
/**
|
||||
* Durch Komponenten und cast_level begrenzter maximal möglicherLevel.
|
||||
*
|
||||
* Da die Funktion nicht alle Komponenten durchprobiert sondern beim
|
||||
* ersten Fehler abbricht, muss die Fehlermeldung später mit cancast()
|
||||
* generiert werden.
|
||||
* */
|
||||
int eff_spelllevel(unit * u, const spell * sp, int cast_level, int range)
|
||||
*/
|
||||
int eff_spelllevel(unit * u, unit *caster, const spell * sp, int cast_level, int range)
|
||||
{
|
||||
const resource_type *r_aura = get_resourcetype(R_AURA);
|
||||
int k, maxlevel, needplevel;
|
||||
int k, maxlevel;
|
||||
int costtyp = SPC_FIX;
|
||||
|
||||
for (k = 0; sp->components && sp->components[k].type; k++) {
|
||||
|
@ -744,17 +766,15 @@ int eff_spelllevel(unit * u, const spell * sp, int cast_level, int range)
|
|||
return 0;
|
||||
|
||||
if (sp->components[k].amount > 0) {
|
||||
/* Die Kosten für Aura sind auch von der Zahl der bereits
|
||||
* gezauberten Sprüche abhängig */
|
||||
int level_cost = sp->components[k].amount * range;
|
||||
if (sp->components[k].type == r_aura) {
|
||||
needplevel = spellcost(u, sp) * range;
|
||||
}
|
||||
else {
|
||||
needplevel = sp->components[k].amount * range;
|
||||
/* Die Kosten fuer Aura sind auch von der Zahl der bereits
|
||||
* gezauberten Sprueche abhaengig */
|
||||
level_cost *= aura_multiplier(caster);
|
||||
}
|
||||
maxlevel =
|
||||
get_pooled(u, sp->components[k].type, GET_DEFAULT,
|
||||
needplevel * cast_level) / needplevel;
|
||||
level_cost * cast_level) / level_cost;
|
||||
|
||||
/* sind die Kosten fix, so muss die Komponente nur einmal vorhanden
|
||||
* sein und der cast_level ändert sich nicht */
|
||||
|
@ -803,27 +823,20 @@ int eff_spelllevel(unit * u, const spell * sp, int cast_level, int range)
|
|||
* Je nach Kostenart werden dann die Komponenten noch mit cast_level
|
||||
* multipliziert.
|
||||
*/
|
||||
void pay_spell(unit * u, const spell * sp, int cast_level, int range)
|
||||
void pay_spell(unit * mage, const unit *caster, const spell * sp, int cast_level, int range)
|
||||
{
|
||||
const resource_type *r_aura = get_resourcetype(R_AURA);
|
||||
int k;
|
||||
int resuse;
|
||||
|
||||
assert(cast_level > 0);
|
||||
for (k = 0; sp->components && sp->components[k].type; k++) {
|
||||
if (sp->components[k].type == r_aura) {
|
||||
resuse = spellcost(u, sp) * range;
|
||||
}
|
||||
else {
|
||||
resuse = sp->components[k].amount * range;
|
||||
}
|
||||
const struct spell_component *spc = sp->components + k;
|
||||
int resuse = spellcost(caster ? caster : mage, spc) * range;
|
||||
|
||||
if (sp->components[k].cost == SPC_LINEAR
|
||||
|| sp->components[k].cost == SPC_LEVEL) {
|
||||
if (spc->cost == SPC_LINEAR || spc->cost == SPC_LEVEL) {
|
||||
resuse *= cast_level;
|
||||
}
|
||||
|
||||
use_pooled(u, sp->components[k].type, GET_DEFAULT, resuse);
|
||||
use_pooled(mage, spc->type, GET_DEFAULT, resuse);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -851,9 +864,7 @@ bool knowsspell(const region * r, const unit * u, const spell * sp)
|
|||
bool
|
||||
cancast(unit * u, const spell * sp, int level, int range, struct order * ord)
|
||||
{
|
||||
const resource_type *r_aura = get_resourcetype(R_AURA);
|
||||
int k;
|
||||
int itemanz;
|
||||
resource *reslist = NULL;
|
||||
|
||||
if (!knowsspell(u->region, u, sp)) {
|
||||
|
@ -869,22 +880,18 @@ cancast(unit * u, const spell * sp, int level, int range, struct order * ord)
|
|||
}
|
||||
|
||||
for (k = 0; sp->components && sp->components[k].type; ++k) {
|
||||
if (sp->components[k].amount > 0) {
|
||||
const resource_type *rtype = sp->components[k].type;
|
||||
int itemhave;
|
||||
const struct spell_component *spc = sp->components + k;
|
||||
if (spc->amount > 0) {
|
||||
const resource_type *rtype = spc->type;
|
||||
int itemhave, itemanz;
|
||||
|
||||
/* Die Kosten für Aura sind auch von der Zahl der bereits
|
||||
* gezauberten Sprüche abhängig */
|
||||
if (rtype == r_aura) {
|
||||
itemanz = spellcost(u, sp) * range;
|
||||
}
|
||||
else {
|
||||
itemanz = sp->components[k].amount * range;
|
||||
}
|
||||
itemanz = spellcost(u, spc) * range;
|
||||
|
||||
/* sind die Kosten stufenabhängig, so muss itemanz noch mit dem
|
||||
* level multipliziert werden */
|
||||
switch (sp->components[k].cost) {
|
||||
switch (spc->cost) {
|
||||
case SPC_LEVEL:
|
||||
case SPC_LINEAR:
|
||||
itemanz *= level;
|
||||
|
@ -897,6 +904,7 @@ cancast(unit * u, const spell * sp, int level, int range, struct order * ord)
|
|||
itemhave = get_pooled(u, rtype, GET_DEFAULT, itemanz);
|
||||
if (itemhave < itemanz) {
|
||||
resource *res = malloc(sizeof(resource));
|
||||
assert(res);
|
||||
res->number = itemanz - itemhave;
|
||||
res->type = rtype;
|
||||
res->next = reslist;
|
||||
|
@ -1254,8 +1262,8 @@ bool fumble(region * r, unit * u, const spell * sp, int cast_grade)
|
|||
}
|
||||
|
||||
/* CHAOSPATZERCHANCE 10 : +10% Chance zu Patzern */
|
||||
mage = get_mage_depr(u);
|
||||
if (mage->magietyp == M_DRAIG) {
|
||||
mage = get_mage(u);
|
||||
if (mage && mage->magietyp == M_DRAIG) {
|
||||
fumble_chance += CHAOSPATZERCHANCE;
|
||||
}
|
||||
if (is_cursed(u->attribs, &ct_magicboost)) {
|
||||
|
@ -1276,11 +1284,11 @@ bool fumble(region * r, unit * u, const spell * sp, int cast_grade)
|
|||
}
|
||||
|
||||
/* ------------------------------------------------------------- */
|
||||
/* Dummy-Zauberpatzer, Platzhalter für speziel auf die Sprüche
|
||||
/* Dummy-Zauberpatzer, Platzhalter für speziell auf die Sprüche
|
||||
* zugeschnittene Patzer */
|
||||
static void fumble_default(castorder * co)
|
||||
{
|
||||
unit *mage = co->magician.u;
|
||||
unit *mage = co_get_magician(co);
|
||||
|
||||
cmistake(mage, co->order, 180, MSG_MAGIC);
|
||||
|
||||
|
@ -1295,7 +1303,8 @@ static void do_fumble(castorder * co)
|
|||
{
|
||||
curse *c;
|
||||
region *r = co_get_region(co);
|
||||
unit *u = co->magician.u;
|
||||
unit *mage = co_get_magician(co);
|
||||
unit *caster = co_get_caster(co);
|
||||
const spell *sp = co->sp;
|
||||
int level = co->level;
|
||||
int duration;
|
||||
|
@ -1304,8 +1313,8 @@ static void do_fumble(castorder * co)
|
|||
static int rc_cache;
|
||||
fumble_f fun;
|
||||
|
||||
ADDMSG(&u->faction->msgs,
|
||||
msg_message("patzer", "unit region spell", u, r, sp));
|
||||
ADDMSG(&mage->faction->msgs,
|
||||
msg_message("patzer", "unit region spell", mage, r, sp));
|
||||
switch (rng_int() % 10) {
|
||||
case 0:
|
||||
/* wenn vorhanden spezieller Patzer, ansonsten nix */
|
||||
|
@ -1325,22 +1334,22 @@ static void do_fumble(castorder * co)
|
|||
* The list of things to happen are attached to a timeout
|
||||
* trigger and that's added to the triggerlit of the mage gone toad.
|
||||
*/
|
||||
trigger *trestore = trigger_changerace(u, u_race(u), u->irace);
|
||||
trigger *trestore = trigger_changerace(mage, u_race(mage), mage->irace);
|
||||
if (chance(0.7)) {
|
||||
const resource_type *rtype = rt_find("toadslime");
|
||||
if (rtype) {
|
||||
t_add(&trestore, trigger_giveitem(u, rtype->itype, 1));
|
||||
t_add(&trestore, trigger_giveitem(mage, rtype->itype, 1));
|
||||
}
|
||||
}
|
||||
duration = rng_int() % level / 2;
|
||||
if (duration < 2) duration = 2;
|
||||
add_trigger(&u->attribs, "timer", trigger_timeout(duration, trestore));
|
||||
add_trigger(&mage->attribs, "timer", trigger_timeout(duration, trestore));
|
||||
if (rc_changed(&rc_cache)) {
|
||||
rc_toad = get_race(RC_TOAD);
|
||||
}
|
||||
u_setrace(u, rc_toad);
|
||||
u->irace = NULL;
|
||||
ADDMSG(&r->msgs, msg_message("patzer6", "unit region spell", u, r, sp));
|
||||
u_setrace(mage, rc_toad);
|
||||
mage->irace = NULL;
|
||||
ADDMSG(&r->msgs, msg_message("patzer6", "unit region spell", mage, r, sp));
|
||||
break;
|
||||
}
|
||||
/* fall-through is intentional! */
|
||||
|
@ -1350,26 +1359,26 @@ static void do_fumble(castorder * co)
|
|||
duration = rng_int() % level / 2;
|
||||
if (duration < 2) duration = 2;
|
||||
effect = level / -2.0;
|
||||
c = create_curse(u, &u->attribs, &ct_skillmod, level,
|
||||
c = create_curse(mage, &mage->attribs, &ct_skillmod, level,
|
||||
duration, effect, 1);
|
||||
c->data.i = SK_MAGIC;
|
||||
ADDMSG(&u->faction->msgs, msg_message("patzer2", "unit region", u, r));
|
||||
ADDMSG(&mage->faction->msgs, msg_message("patzer2", "unit region", mage, r));
|
||||
break;
|
||||
case 3:
|
||||
case 4:
|
||||
/* Spruch schlägt fehl, alle Magiepunkte weg */
|
||||
set_spellpoints(u, 0);
|
||||
ADDMSG(&u->faction->msgs, msg_message("patzer3", "unit region spell",
|
||||
u, r, sp));
|
||||
set_spellpoints(mage, 0);
|
||||
ADDMSG(&mage->faction->msgs, msg_message("patzer3", "unit region spell",
|
||||
mage, r, sp));
|
||||
break;
|
||||
|
||||
case 5:
|
||||
case 6:
|
||||
/* Spruch gelingt, aber alle Magiepunkte weg */
|
||||
co->level = cast_spell(co);
|
||||
set_spellpoints(u, 0);
|
||||
ADDMSG(&u->faction->msgs, msg_message("patzer4", "unit region spell",
|
||||
u, r, sp));
|
||||
set_spellpoints(mage, 0);
|
||||
ADDMSG(&mage->faction->msgs, msg_message("patzer4", "unit region spell",
|
||||
mage, r, sp));
|
||||
break;
|
||||
|
||||
case 7:
|
||||
|
@ -1378,9 +1387,9 @@ static void do_fumble(castorder * co)
|
|||
default:
|
||||
/* Spruch gelingt, alle nachfolgenden Sprüche werden 2^4 so teuer */
|
||||
co->level = cast_spell(co);
|
||||
ADDMSG(&u->faction->msgs, msg_message("patzer5", "unit region spell",
|
||||
u, r, sp));
|
||||
countspells(u, 3);
|
||||
ADDMSG(&mage->faction->msgs, msg_message("patzer5", "unit region spell",
|
||||
mage, r, sp));
|
||||
countspells(caster, 3);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1591,7 +1600,7 @@ verify_unit(region * r, unit * mage, const spell * sp, spllprm * spobj,
|
|||
static void
|
||||
verify_targets(castorder * co, int *invalid, int *resist, int *success)
|
||||
{
|
||||
unit *mage = co->magician.u;
|
||||
unit *mage = co_get_magician(co);
|
||||
const spell *sp = co->sp;
|
||||
region *target_r = co_get_region(co);
|
||||
spellparameter *sa = co->par;
|
||||
|
@ -2038,6 +2047,10 @@ struct unit * co_get_caster(const struct castorder * co) {
|
|||
return co->_familiar ? co->_familiar : co->magician.u;
|
||||
}
|
||||
|
||||
struct unit * co_get_magician(const struct castorder * co) {
|
||||
return co->magician.u;
|
||||
}
|
||||
|
||||
struct region * co_get_region(const struct castorder * co) {
|
||||
return co->_rtarget;
|
||||
}
|
||||
|
@ -2432,7 +2445,7 @@ static castorder *cast_cmd(unit * u, order * ord)
|
|||
spell *sp = 0;
|
||||
plane *pl;
|
||||
spellparameter *args = NULL;
|
||||
unit * caster = u;
|
||||
unit * mage = u;
|
||||
param_t param;
|
||||
|
||||
if (LongHunger(u)) {
|
||||
|
@ -2502,15 +2515,15 @@ static castorder *cast_cmd(unit * u, order * ord)
|
|||
* können. unit_getspell findet aber nur jene Sprüche, die
|
||||
* die Einheit beherrscht. */
|
||||
if (!sp && is_familiar(u)) {
|
||||
caster = get_familiar_mage(u);
|
||||
if (caster) {
|
||||
mage = get_familiar_mage(u);
|
||||
if (mage) {
|
||||
familiar = u;
|
||||
sp = unit_getspell(caster, s, caster->faction->locale);
|
||||
sp = unit_getspell(mage, s, mage->faction->locale);
|
||||
}
|
||||
else {
|
||||
/* somehow, this familiar has no mage! */
|
||||
log_error("cast_cmd: familiar %s is without a mage?\n", unitname(u));
|
||||
caster = u;
|
||||
mage = u;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2597,24 +2610,22 @@ static castorder *cast_cmd(unit * u, order * ord)
|
|||
cmistake(u, ord, 177, MSG_MAGIC);
|
||||
return 0;
|
||||
}
|
||||
if (caster != familiar) { /* Magier zaubert durch Vertrauten */
|
||||
if (mage != familiar) { /* Magier zaubert durch Vertrauten */
|
||||
int sk;
|
||||
if (range > 1) { /* Fehler! Versucht zu Farcasten */
|
||||
ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "familiar_farcast",
|
||||
"mage", caster));
|
||||
"mage", mage));
|
||||
return 0;
|
||||
}
|
||||
sk = effskill(caster, SK_MAGIC, 0);
|
||||
if (distance(caster->region, r) > sk) {
|
||||
sk = effskill(mage, SK_MAGIC, 0);
|
||||
if (distance(mage->region, r) > sk) {
|
||||
ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "familiar_toofar",
|
||||
"mage", caster));
|
||||
"mage", mage));
|
||||
return 0;
|
||||
}
|
||||
/* mage auf magier setzen, level anpassen, range für Erhöhung
|
||||
* der Spruchkosten nutzen, langen Befehl des Magiers
|
||||
* löschen, zaubern kann er noch */
|
||||
* der Spruchkosten nutzen */
|
||||
range *= 2;
|
||||
set_order(&caster->thisorder, NULL);
|
||||
sk /= 2;
|
||||
if (level > sk) level = sk;
|
||||
}
|
||||
|
@ -2635,7 +2646,7 @@ static castorder *cast_cmd(unit * u, order * ord)
|
|||
unitname(u), MAX_PARAMETERS, sp->sname);
|
||||
}
|
||||
args =
|
||||
add_spellparameter(target_r, caster, sp->parameter,
|
||||
add_spellparameter(target_r, mage, sp->parameter,
|
||||
(const char *const *)params, p, ord);
|
||||
for (i = 0; i != p; ++i) {
|
||||
free(params[i]);
|
||||
|
@ -2645,7 +2656,7 @@ static castorder *cast_cmd(unit * u, order * ord)
|
|||
return 0;
|
||||
}
|
||||
}
|
||||
return create_castorder(0, caster, familiar, sp, target_r, level, 0, range, ord,
|
||||
return create_castorder(0, mage, familiar, sp, target_r, level, 0, range, ord,
|
||||
args);
|
||||
}
|
||||
|
||||
|
@ -2718,16 +2729,17 @@ void magic(void)
|
|||
order *ord = co->order;
|
||||
int invalid, resist, success, cast_level = co->level;
|
||||
bool fumbled = false;
|
||||
unit *u = co->magician.u;
|
||||
unit *mage = co_get_magician(co);
|
||||
unit *caster = co_get_caster(co);
|
||||
const spell *sp = co->sp;
|
||||
region *target_r = co_get_region(co);
|
||||
|
||||
/* reichen die Komponenten nicht, wird der Level reduziert. */
|
||||
co->level = eff_spelllevel(u, sp, cast_level, co->distance);
|
||||
co->level = eff_spelllevel(mage, caster, sp, cast_level, co->distance);
|
||||
|
||||
if (co->level < 1) {
|
||||
/* Fehlermeldung mit Komponenten generieren */
|
||||
cancast(u, sp, cast_level, co->distance, ord);
|
||||
cancast(mage, sp, cast_level, co->distance, ord);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -2735,24 +2747,24 @@ void magic(void)
|
|||
/* Sprüche mit Fixkosten werden immer auf Stufe des Spruchs
|
||||
* gezaubert, co->level ist aber defaultmäßig Stufe des Magiers */
|
||||
if (spl_costtyp(sp) != SPC_FIX) {
|
||||
ADDMSG(&u->faction->msgs, msg_message("missing_components",
|
||||
"unit spell level", u, sp, cast_level));
|
||||
ADDMSG(&mage->faction->msgs, msg_message("missing_components",
|
||||
"unit spell level", mage, sp, cast_level));
|
||||
}
|
||||
}
|
||||
|
||||
/* Prüfen, ob die realen Kosten für die gewünschten Stufe bezahlt
|
||||
* werden können */
|
||||
if (!cancast(u, sp, co->level, co->distance, ord)) {
|
||||
if (!cancast(mage, sp, co->level, co->distance, ord)) {
|
||||
/* die Fehlermeldung wird in cancast generiert */
|
||||
continue;
|
||||
}
|
||||
|
||||
co->force = MagicPower(spellpower(target_r, u, sp, co->level, ord));
|
||||
co->force = MagicPower(spellpower(target_r, mage, sp, co->level, ord));
|
||||
/* die Stärke kann durch Antimagie auf 0 sinken */
|
||||
if (co->force <= 0) {
|
||||
co->force = 0;
|
||||
ADDMSG(&u->faction->msgs, msg_message("missing_force",
|
||||
"unit spell level", u, sp, co->level));
|
||||
ADDMSG(&mage->faction->msgs, msg_message("missing_force",
|
||||
"unit spell level", mage, sp, co->level));
|
||||
}
|
||||
|
||||
/* Ziele auf Existenz prüfen und Magieresistenz feststellen. Wurde
|
||||
|
@ -2772,15 +2784,15 @@ void magic(void)
|
|||
co->force = 0;
|
||||
/* zwar wurde mindestens ein Ziel gefunden, das widerstand
|
||||
* jedoch dem Zauber. Kosten abziehen und abbrechen. */
|
||||
ADDMSG(&u->faction->msgs, msg_message("spell_resist",
|
||||
"unit region spell", u, r, sp));
|
||||
ADDMSG(&mage->faction->msgs, msg_message("spell_resist",
|
||||
"unit region spell", mage, r, sp));
|
||||
}
|
||||
}
|
||||
|
||||
/* Auch für Patzer gibt es Erfahrung, müssen die Spruchkosten
|
||||
* bezahlt werden und die nachfolgenden Sprüche werden teurer */
|
||||
if (co->force > 0) {
|
||||
if (fumble(target_r, u, sp, co->level)) {
|
||||
if (fumble(target_r, mage, sp, co->level)) {
|
||||
/* zuerst bezahlen, dann evt in do_fumble alle Aura verlieren */
|
||||
fumbled = true;
|
||||
}
|
||||
|
@ -2794,12 +2806,12 @@ void magic(void)
|
|||
}
|
||||
/* erst bezahlen, dann Kostenzähler erhöhen */
|
||||
if (co->level > 0) {
|
||||
pay_spell(u, sp, co->level, co->distance);
|
||||
pay_spell(mage, caster, sp, co->level, co->distance);
|
||||
}
|
||||
if (fumbled) {
|
||||
do_fumble(co);
|
||||
}
|
||||
countspells(u, 1);
|
||||
countspells(caster, 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2807,9 +2819,9 @@ void magic(void)
|
|||
for (r = regions; r; r = r->next) {
|
||||
unit *u;
|
||||
for (u = r->units; u; u = u->next) {
|
||||
if (is_mage(u) && countspells(u, 0) > 0) {
|
||||
if (is_mage(u) && spellcount(u) > 0) {
|
||||
produceexp(u, SK_MAGIC, u->number);
|
||||
/* Spruchlistenaktualiesierung ist in Regeneration */
|
||||
/* Spruchlistenaktualisierung ist in Regeneration */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2859,33 +2871,22 @@ static void select_spellbook(void **tokens, spellbook *sb, const struct locale *
|
|||
|
||||
spell *unit_getspell(struct unit *u, const char *name, const struct locale * lang)
|
||||
{
|
||||
void * tokens = 0;
|
||||
spellbook *sb;
|
||||
|
||||
sb = unit_get_spellbook(u);
|
||||
if (sb) {
|
||||
void * tokens = NULL;
|
||||
select_spellbook(&tokens, sb, lang);
|
||||
}
|
||||
#if 0 /* TODO: some familiars can cast spells from the mage's spellbook? */
|
||||
u = get_familiar_mage(u);
|
||||
if (u) {
|
||||
sb = unit_get_spellbook(u);
|
||||
if (sb) {
|
||||
select_spellbook(&tokens, sb, lang);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (tokens) {
|
||||
variant token;
|
||||
if (findtoken(tokens, name, &token) != E_TOK_NOMATCH) {
|
||||
if (tokens) {
|
||||
variant token;
|
||||
if (findtoken(tokens, name, &token) != E_TOK_NOMATCH) {
|
||||
freetokens(tokens);
|
||||
return (spell *)token.v;
|
||||
}
|
||||
freetokens(tokens);
|
||||
return (spell *)token.v;
|
||||
}
|
||||
freetokens(tokens);
|
||||
}
|
||||
|
||||
return 0;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int cast_spell(struct castorder *co)
|
||||
|
|
11
src/magic.h
11
src/magic.h
|
@ -140,6 +140,7 @@ extern "C" {
|
|||
} castorder;
|
||||
|
||||
struct unit * co_get_caster(const struct castorder * co);
|
||||
struct unit * co_get_magician(const struct castorder * co);
|
||||
struct region * co_get_region(const struct castorder * co);
|
||||
|
||||
typedef struct spell_component {
|
||||
|
@ -288,9 +289,11 @@ extern "C" {
|
|||
|
||||
/* Prüfroutinen für Zaubern */
|
||||
int countspells(struct unit *u, int step);
|
||||
int spellcount(const struct unit *u);
|
||||
/* erhöht den Counter für Zaubersprüche um 'step' und gibt die neue
|
||||
* Anzahl der gezauberten Sprüche zurück. */
|
||||
int spellcost(struct unit *u, const struct spell * sp);
|
||||
int auracost(const struct unit *caster, const struct spell *sp);
|
||||
int spellcost(const struct unit *caster, const struct spell_component *spc);
|
||||
/* gibt die für diesen Spruch derzeit notwendigen Magiepunkte auf der
|
||||
* geringstmöglichen Stufe zurück, schon um den Faktor der bereits
|
||||
* zuvor gezauberten Sprüche erhöht */
|
||||
|
@ -298,12 +301,12 @@ extern "C" {
|
|||
int distance, struct order *ord);
|
||||
/* true, wenn Einheit alle Komponenten des Zaubers (incl. MP) für die
|
||||
* geringstmögliche Stufe hat und den Spruch beherrscht */
|
||||
void pay_spell(struct unit *u, const struct spell * sp, int eff_stufe, int distance);
|
||||
void pay_spell(struct unit *mage, const struct unit *caster, const struct spell * sp, int eff_stufe, int distance);
|
||||
/* zieht die Komponenten des Zaubers aus dem Inventory der Einheit
|
||||
* ab. Die effektive Stufe des gezauberten Spruchs ist wichtig für
|
||||
* die korrekte Bestimmung der Magiepunktkosten */
|
||||
int eff_spelllevel(struct unit *u, const struct spell * sp, int cast_level,
|
||||
int distance);
|
||||
int eff_spelllevel(struct unit *mage, struct unit *caster,
|
||||
const struct spell * sp, int cast_level, int distance);
|
||||
/* ermittelt die effektive Stufe des Zaubers. Dabei ist cast_level
|
||||
* die gewünschte maximale Stufe (im Normalfall Stufe des Magiers,
|
||||
* bei Farcasting Stufe*2^Entfernung) */
|
||||
|
|
|
@ -123,9 +123,9 @@ void test_pay_spell(CuTest * tc)
|
|||
change_resource(u, get_resourcetype(R_AURA), 3);
|
||||
change_resource(u, get_resourcetype(R_HORSE), 3);
|
||||
|
||||
level = eff_spelllevel(u, sp, 3, 1);
|
||||
level = eff_spelllevel(u, u, sp, 3, 1);
|
||||
CuAssertIntEquals(tc, 3, level);
|
||||
pay_spell(u, sp, level, 1);
|
||||
pay_spell(u, NULL, sp, level, 1);
|
||||
CuAssertIntEquals(tc, 0, get_resource(u, get_resourcetype(R_SILVER)));
|
||||
CuAssertIntEquals(tc, 0, get_resource(u, get_resourcetype(R_AURA)));
|
||||
CuAssertIntEquals(tc, 0, get_resource(u, get_resourcetype(R_HORSE)));
|
||||
|
@ -157,16 +157,16 @@ void test_pay_spell_failure(CuTest * tc)
|
|||
CuAssertIntEquals(tc, 2, change_resource(u, get_resourcetype(R_AURA), 2));
|
||||
CuAssertIntEquals(tc, 3, change_resource(u, get_resourcetype(R_HORSE), 3));
|
||||
|
||||
level = eff_spelllevel(u, sp, 3, 1);
|
||||
level = eff_spelllevel(u, u, sp, 3, 1);
|
||||
CuAssertIntEquals(tc, 2, level);
|
||||
pay_spell(u, sp, level, 1);
|
||||
pay_spell(u, NULL, sp, level, 1);
|
||||
CuAssertIntEquals(tc, 1, change_resource(u, get_resourcetype(R_SILVER), 1));
|
||||
CuAssertIntEquals(tc, 3, change_resource(u, get_resourcetype(R_AURA), 3));
|
||||
CuAssertIntEquals(tc, 2, change_resource(u, get_resourcetype(R_HORSE), 1));
|
||||
|
||||
CuAssertIntEquals(tc, 0, eff_spelllevel(u, sp, 3, 1));
|
||||
CuAssertIntEquals(tc, 0, eff_spelllevel(u, u, sp, 3, 1));
|
||||
CuAssertIntEquals(tc, 0, change_resource(u, get_resourcetype(R_SILVER), -1));
|
||||
CuAssertIntEquals(tc, 0, eff_spelllevel(u, sp, 2, 1));
|
||||
CuAssertIntEquals(tc, 0, eff_spelllevel(u, u, sp, 2, 1));
|
||||
test_teardown();
|
||||
}
|
||||
|
||||
|
|
653
src/spells.c
653
src/spells.c
File diff suppressed because it is too large
Load Diff
|
@ -38,7 +38,7 @@ int sp_flying_ship(castorder * co)
|
|||
ship *sh;
|
||||
unit *u;
|
||||
region *r;
|
||||
unit *mage;
|
||||
unit *caster;
|
||||
int cast_level;
|
||||
double power;
|
||||
spellparameter *pa;
|
||||
|
@ -47,7 +47,7 @@ int sp_flying_ship(castorder * co)
|
|||
|
||||
assert(co);
|
||||
r = co_get_region(co);
|
||||
mage = co->magician.u;
|
||||
caster = co_get_caster(co);
|
||||
cast_level = co->level;
|
||||
power = co->force;
|
||||
pa = co->par;
|
||||
|
@ -57,22 +57,22 @@ int sp_flying_ship(castorder * co)
|
|||
return 0;
|
||||
sh = pa->param[0]->data.sh;
|
||||
if (sh->type->construction->maxsize > 50) {
|
||||
ADDMSG(&mage->faction->msgs, msg_feedback(mage, co->order,
|
||||
ADDMSG(&caster->faction->msgs, msg_feedback(caster, co->order,
|
||||
"error_flying_ship_too_big", "ship", sh));
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Duration = 1, nur diese Runde */
|
||||
|
||||
cno = levitate_ship(sh, mage, power, 1);
|
||||
cno = levitate_ship(sh, caster, power, 1);
|
||||
if (cno == 0) {
|
||||
if (is_cursed(sh->attribs, &ct_flyingship)) {
|
||||
/* Auf dem Schiff befindet liegt bereits so ein Zauber. */
|
||||
cmistake(mage, co->order, 211, MSG_MAGIC);
|
||||
cmistake(caster, co->order, 211, MSG_MAGIC);
|
||||
}
|
||||
else if (is_cursed(sh->attribs, &ct_shipspeedup)) {
|
||||
/* Es ist zu gefaehrlich, ein sturmgepeitschtes Schiff fliegen zu lassen. */
|
||||
cmistake(mage, co->order, 210, MSG_MAGIC);
|
||||
cmistake(caster, co->order, 210, MSG_MAGIC);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
@ -86,7 +86,7 @@ int sp_flying_ship(castorder * co)
|
|||
if (!(u->faction->flags & FFL_SELECT)) {
|
||||
u->faction->flags |= FFL_SELECT;
|
||||
if (!m) {
|
||||
m = msg_message("flying_ship_result", "mage ship", mage, sh);
|
||||
m = msg_message("flying_ship_result", "mage ship", caster, sh);
|
||||
}
|
||||
add_message(&u->faction->msgs, m);
|
||||
}
|
||||
|
|
|
@ -784,13 +784,7 @@ int study_cmd(unit * u, order * ord)
|
|||
show_potions(f, skill);
|
||||
}
|
||||
}
|
||||
else if (sk == SK_MAGIC) {
|
||||
sc_mage *mage = get_mage_depr(u);
|
||||
if (!mage) {
|
||||
mage = create_mage(u, u->faction->magiegebiet);
|
||||
}
|
||||
}
|
||||
init_order_depr(NULL);
|
||||
init_order(NULL, NULL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -51,6 +51,7 @@ void register_special_direction(struct locale *lang, const char *name)
|
|||
|
||||
if (lang == locales) {
|
||||
dir_lookup *dl = malloc(sizeof(dir_lookup));
|
||||
assert(dl);
|
||||
dl->name = str;
|
||||
dl->oldname = token;
|
||||
dl->next = dir_name_lookup;
|
||||
|
|
Loading…
Reference in New Issue