diff --git a/src/common/kernel/battle.c b/src/common/kernel/battle.c
index 4b84d60cc..1f1173203 100644
--- a/src/common/kernel/battle.c
+++ b/src/common/kernel/battle.c
@@ -946,8 +946,8 @@ remove_troop(troop dt)
/* ------------------------------------------------------------- */
#if SKILLPOINTS
-static void
-drain_exp(unit *u, int n)
+void
+drain_exp(const struct unit *u, int n)
{
skill_t sk = (skill_t)(rand() % MAXSKILLS);
skill_t ssk;
@@ -971,8 +971,8 @@ drain_exp(unit *u, int n)
/** reduces the target's exp by an equivalent of n points learning
* 30 points = 1 week
*/
-static void
-drain_exp(unit *u, int n)
+void
+drain_exp(const struct unit *u, int n)
{
skill_t sk = (skill_t)(rand() % MAXSKILLS);
skill_t ssk;
@@ -1334,6 +1334,13 @@ select_enemy(fighter * af, int minrow, int maxrow)
void ** si;
int enemies;
+ if(af->unit->race->flags & RCF_FLY) {
+ /* flying races ignore min- and maxrow and can attack anyone fighting
+ * them */
+ minrow = FIGHT_ROW;
+ maxrow = BEHIND_ROW;
+ }
+
enemies = count_enemies(af->side, FS_ENEMY, minrow, maxrow);
if (!enemies)
diff --git a/src/common/kernel/battle.h b/src/common/kernel/battle.h
index 9dcb9192f..ca1f03d4e 100644
--- a/src/common/kernel/battle.h
+++ b/src/common/kernel/battle.h
@@ -120,7 +120,6 @@ typedef struct weapon {
/*** fighter::flags ***/
#define FIG_ATTACKED 1
#define FIG_NOLOOT 2
-#define FIG_COMBATEXP 4
typedef unsigned char armor_t;
enum {
@@ -237,5 +236,6 @@ extern boolean enemy (const struct side * a, const struct side * b);
extern struct troop select_corpse(struct battle * b, struct fighter * af);
extern fighter * make_fighter(struct battle * b, struct unit * u, boolean attack);
void flee(const troop dt);
+void drain_exp(const struct unit *u, int d);
#endif
diff --git a/src/common/kernel/combatspells.c b/src/common/kernel/combatspells.c
index ef1c9ca74..a56859962 100644
--- a/src/common/kernel/combatspells.c
+++ b/src/common/kernel/combatspells.c
@@ -637,12 +637,116 @@ sp_dragonodem(fighter * fi, int level, int power, spell * sp)
scat(".");
battlerecord(b, buf);
return level;
+}
+int
+sp_drainodem(fighter * fi, int level, int power, spell * sp)
+{
+ battle *b = fi->side->battle;
+ troop dt;
+ troop at;
+ /* Immer aus der ersten Reihe nehmen */
+ int minrow = FIGHT_ROW;
+ int maxrow = BEHIND_ROW-1;
+ int force, enemies;
+ int drained = 0;
+ int killed = 0;
+ const char *damage;
+
+ sprintf(buf, "%s zaubert %s", unitname(fi->unit), sp->name);
+ /* 11-26 HP */
+ damage = spell_damage(4);
+ /* Jungdrache 3->54, Drache 6->216, Wyrm 12->864 Treffer */
+ force = lovar(get_force(level,6));
+
+ enemies = count_enemies(fi->side, FS_ENEMY, minrow,
+ maxrow);
+
+ if (!enemies) {
+ scat(", aber niemand war in Reichweite.");
+ battlerecord(b, buf);
+ return 0;
+ }
+ scat(":");
+ battlerecord(b, buf);
+
+ at.fighter = fi;
+ at.index = 0;
+
+ do {
+ dt = select_enemy(fi, minrow, maxrow);
+ assert(dt.fighter);
+ if (hits(at, dt, NULL)) {
+ drain_exp(dt.fighter->unit, 90);
+ drained++;
+ }
+ killed += terminate(dt, at, AT_COMBATSPELL, damage, false);
+ --force;
+ } while (force && drained < enemies);
+
+ sprintf(buf, "%d Person%s wurde ihre Lebenskraft entzogen",
+ drained, drained == 1 ? " wurde" : "en wurden");
+
+ scat(".");
+ battlerecord(b, buf);
+ return level;
}
/* ------------------------------------------------------------- */
/* PRECOMBAT */
+int
+sp_shadowcall(fighter * fi, int level, int power, spell * sp)
+{
+ battle *b = fi->side->battle;
+ region *r = b->region;
+ unit *mage = fi->unit;
+ attrib *a;
+ int force = get_force(power, 3)/2;
+ race *rc;
+ int num;
+ unit *u;
+
+ unused(sp);
+
+ switch(rand()%3) {
+ case 0:
+ rc = new_race[RC_SHADOWBAT];
+ num = 5000+dice_rand("3d5000");
+ break;
+ case 1:
+ rc = new_race[RC_NIGHTMARE];
+ num = 500+dice_rand("3d500");
+ break;
+ case 2:
+ rc = new_race[RC_VAMPUNICORN];
+ num = 500+dice_rand("3d500");
+ break;
+ }
+
+ u = createunit(r, mage->faction, force, rc);
+ u->status = ST_FIGHT;
+
+ set_string(&u->name, racename(mage->faction->locale, u, u->race));
+ set_level(u, SK_WEAPONLESS, power/2);
+ set_level(u, SK_AUSDAUER, power/2);
+ u->hp = u->number * unit_max_hp(u);
+
+ if (fval(mage, FL_PARTEITARNUNG))
+ fset(u, FL_PARTEITARNUNG);
+
+ a = a_new(&at_unitdissolve);
+ a->data.ca[0] = 0;
+ a->data.ca[1] = 100;
+ a_add(&u->attribs, a);
+
+ make_fighter(b, u, true);
+ sprintf(buf, "%s ruft %d %s zu Hilfe", unitname(mage), force,
+ racename(default_locale, u, u->race));
+ battlerecord(b, buf);
+ return level;
+}
+
int
sp_wolfhowl(fighter * fi, int level, int power, spell * sp)
{
@@ -656,7 +760,7 @@ sp_wolfhowl(fighter * fi, int level, int power, spell * sp)
u->status = ST_FIGHT;
- set_string(&u->name, force == 1 ? "Wolf" : "Wölfe");
+ set_string(&u->name, racename(mage->faction->locale, u, u->race));
set_level(u, SK_WEAPONLESS, power/3);
set_level(u, SK_AUSDAUER, power/3);
u->hp = u->number * unit_max_hp(u);
@@ -671,7 +775,7 @@ sp_wolfhowl(fighter * fi, int level, int power, spell * sp)
make_fighter(b, u, true);
sprintf(buf, "%s ruft %d %s zu Hilfe", unitname(mage), force,
- force == 1 ? "Wolf" : "Wölfe");
+ racename(default_locale, u, u->race));
battlerecord(b, buf);
return level;
}
@@ -841,6 +945,10 @@ sp_flee(fighter * fi, int level, int power, spell * sp)
sprintf(buf, "%s stimmt einen düsteren Gesang an", unitname(mage));
force = get_force(power,3);
break;
+ case SPL_AURA_OF_FEAR:
+ sprintf(buf, "%s ist von dunklen Schatten umgeben", unitname(mage));
+ force = get_force(power,5);
+ break;
default:
force = get_force(power,10);
}
diff --git a/src/common/kernel/eressea.h b/src/common/kernel/eressea.h
index 40bf0fe0d..7576b24b6 100644
--- a/src/common/kernel/eressea.h
+++ b/src/common/kernel/eressea.h
@@ -685,7 +685,11 @@ enum {
RC_GNOME, /* 60 */
RC_TEMPLATE, /* 61 */
RC_CLONE, /* 62 */
-
+
+ RC_SHADOWDRAGON,
+ RC_SHADOWBAT,
+ RC_NIGHTMARE,
+ RC_VAMPUNICORN,
MAXRACES,
NORACE = (race_t) - 1
diff --git a/src/common/kernel/magic.c b/src/common/kernel/magic.c
index 368e06a56..850bbf8e6 100644
--- a/src/common/kernel/magic.c
+++ b/src/common/kernel/magic.c
@@ -622,8 +622,9 @@ get_combatspelllevel(const unit *u, int nr)
{
sc_mage *m;
+ assert(nr < MAXCOMBATSPELLS);
m = get_mage(u);
- if (!m || !(nr < MAXCOMBATSPELLS)) {
+ if (!m) {
return -1;
}
@@ -638,12 +639,15 @@ get_combatspell(const unit *u, int nr)
{
sc_mage *m;
+ assert(nr < MAXCOMBATSPELLS);
m = get_mage(u);
- if (!m || !(nr < MAXCOMBATSPELLS)) {
- return (spell *)NULL;
+ if (m) {
+ return find_spellbyid(m->combatspell[nr]);
+ } else if(u->race->precombatspell != NO_SPELL) {
+ return find_spellbyid(u->race->precombatspell);
}
- return find_spellbyid(m->combatspell[nr]);
+ return NULL;
}
void
diff --git a/src/common/kernel/race.c b/src/common/kernel/race.c
index 1101239cc..ac3cd1117 100644
--- a/src/common/kernel/race.c
+++ b/src/common/kernel/race.c
@@ -72,6 +72,7 @@ rc_new(const char * zName)
rc->_name[2] = strdup(zBuffer);
sprintf(zBuffer, "%s_x", zName);
rc->_name[3] = strdup(zBuffer);
+ rc->precombatspell = NO_SPELL;
return rc;
}
@@ -169,7 +170,7 @@ static const char * oldracenames[MAXRACES] = {
"centaur",
"skeleton", "skeleton lord", "zombie", "juju-zombie", "ghoul", "ghast", "museumghost", "gnome",
"template",
- "clone"
+ "clone", "shadowdragon", "shadowbat", "nightmare", "vampunicorn"
};
/* magres, {3 namen},
@@ -659,6 +660,7 @@ tagbegin(struct xml_stack * stack)
if (xml_bvalue(tag, "resistbash")) rc->battle_flags |= BF_RES_BASH;
if (xml_bvalue(tag, "resistcut")) rc->battle_flags |= BF_RES_CUT;
if (xml_bvalue(tag, "resistpierce")) rc->battle_flags |= BF_RES_PIERCE;
+
state->race = rc;
} else if (strcmp(tag->name, "ai")==0) {
@@ -698,6 +700,9 @@ tagbegin(struct xml_stack * stack)
}
a->type = xml_ivalue(tag, "type");
a->flags = xml_ivalue(tag, "flags");
+ } else if (strcmp(tag->name, "precombatspell") == 0) {
+ race * rc = state->race;
+ rc->precombatspell = xml_ivalue(tag, "spell");
} else if (strcmp(tag->name, "function")==0) {
race * rc = state->race;
const char * name = xml_value(tag, "name");
diff --git a/src/common/kernel/race.h b/src/common/kernel/race.h
index c0ca1595d..ede219ba8 100644
--- a/src/common/kernel/race.h
+++ b/src/common/kernel/race.h
@@ -66,7 +66,8 @@ typedef struct race {
char df_default; /* Verteidigungsskill Unbewaffnet (default: -2)*/
char at_bonus; /* Verändert den Angriffsskill (default: 0)*/
char df_bonus; /* Verändert den Verteidigungskill (default: 0)*/
- struct att attack[6];
+ spellid_t precombatspell;
+ struct att attack[10];
char bonus[MAXSKILLS];
boolean __remove_me_nonplayer;
int flags;
diff --git a/src/common/kernel/reports.c b/src/common/kernel/reports.c
index 131199b15..6506fbbc1 100644
--- a/src/common/kernel/reports.c
+++ b/src/common/kernel/reports.c
@@ -636,13 +636,16 @@ spskill(const struct locale * lang, const struct unit * u, skill_t sk, int *dh,
sbuf += sprintf(sbuf, " [%d]", get_skill(u, sk) / u->number);
}
#else
- if(effsk > 0 && u->faction->options & Pow(O_SHOWSKCHANGE)) {
- attrib *a;
- for(a = a_find(u->attribs,&at_showskchange); a; a=a->nexttype) {
- if(a->data.sa[0] == sk) {
- sbuf += sprintf(sbuf, " (%s%hd)", (a->data.sa[1]>0)?"+":"", a->data.sa[1]);
- break;
- }
+ if(u->faction->options & Pow(O_SHOWSKCHANGE)) {
+ skill *skill = get_skill(u, sk);
+ int oldeff = skill->old + get_modifier(u, sk, skill->old, u->region);
+ int diff;
+
+ oldeff = max(0, oldeff);
+ diff = effsk - oldeff;
+
+ if(diff != 0) {
+ sbuf += sprintf(sbuf, " (%s%hd)", (diff>0)?"+":"", diff);
}
}
#endif
diff --git a/src/common/kernel/save.c b/src/common/kernel/save.c
index f92204f5a..f30451f90 100644
--- a/src/common/kernel/save.c
+++ b/src/common/kernel/save.c
@@ -1474,7 +1474,7 @@ readgame(boolean backup)
assert(weeks>0 && weeks<=lvl+1);
if (lvl) {
skill * sv = add_skill(u, sk);
- sv->level = (unsigned char)lvl;
+ sv->level = sv->old = (unsigned char)lvl;
sv->weeks = (unsigned char)weeks;
}
}
@@ -1484,7 +1484,7 @@ readgame(boolean backup)
int weeks = ri(F);
if (level) {
skill * sv = add_skill(u, sk);
- sv->level = (unsigned char)level;
+ sv->level = sv->old = (unsigned char)level;
sv->weeks = (unsigned char)weeks;
}
}
diff --git a/src/common/kernel/skill.h b/src/common/kernel/skill.h
index efad33b49..564005203 100644
--- a/src/common/kernel/skill.h
+++ b/src/common/kernel/skill.h
@@ -30,6 +30,7 @@ typedef struct skill {
unsigned char id;
unsigned char level;
unsigned char weeks;
+ unsigned char old;
#endif
} skill;
diff --git a/src/common/kernel/spell.c b/src/common/kernel/spell.c
index b745f2dca..197794a5f 100644
--- a/src/common/kernel/spell.c
+++ b/src/common/kernel/spell.c
@@ -10369,6 +10369,48 @@ spell spelldaten[] =
{0, 0, 0}},
(spell_f)sp_dragonodem, patzer
},
+
+ { SPL_DRAINODEM, "Schattenodem",
+ "Entzieht Talentstufen und macht Schaden wie Großer Odem",
+ NULL,
+ NULL,
+ M_GRAU, (COMBATSPELL), 5, 12,
+ {
+ {R_AURA, 4, SPC_FIX},
+ {0, 0, 0},
+ {0, 0, 0},
+ {0, 0, 0},
+ {0, 0, 0}},
+ (spell_f)sp_dragonodem, patzer
+ },
+
+ {SPL_AURA_OF_FEAR, "Gesang der Furcht",
+ "Panik",
+ NULL,
+ NULL,
+ M_GRAU, (COMBATSPELL), 5, 12,
+ {
+ {R_AURA, 1, SPC_LEVEL},
+ {0, 0, 0},
+ {0, 0, 0},
+ {0, 0, 0},
+ {0, 0, 0}},
+ (spell_f)sp_flee, patzer
+ },
+
+ {SPL_SHADOWCALL, "Schattenruf",
+ "Ruft Schattenwesen.",
+ NULL,
+ NULL,
+ M_GRAU, (PRECOMBATSPELL), 5, 12,
+ {
+ {R_AURA, 2, SPC_LEVEL},
+ {0, 0, 0},
+ {0, 0, 0},
+ {0, 0, 0},
+ {0, 0, 0}},
+ (spell_f)sp_shadowcall, patzer
+ },
/* SPL_NOSPELL MUSS der letzte Spruch der Liste sein*/
diff --git a/src/common/kernel/spell.h b/src/common/kernel/spell.h
index 43df0d86b..2c0dcd2a6 100644
--- a/src/common/kernel/spell.h
+++ b/src/common/kernel/spell.h
@@ -197,6 +197,9 @@ enum {
SPL_BLOODSACRIFICE,
SPL_MALLORN,
SPL_CLONECOPY,
+ SPL_DRAINODEM, /* 174? */
+ SPL_AURA_OF_FEAR, /* 175? */
+ SPL_SHADOWCALL, /* 176? */
MAXALLSPELLS,
NO_SPELL = (spellid_t) -1
};
@@ -238,6 +241,7 @@ extern int sp_reduceshield(struct fighter * fi, int level, int power, struct spe
extern int sp_armorshield(struct fighter * fi, int level, int power, struct spell * sp);
extern int sp_stun(struct fighter * fi, int level, int power, struct spell * sp);
extern int sp_undeadhero(struct fighter * fi, int level, int power, struct spell * sp);
+extern int sp_shadowcall(struct fighter * fi, int level, int power, struct spell * sp);
/* ------------------------------------------------------------- */
diff --git a/src/common/kernel/unit.c b/src/common/kernel/unit.c
index c447ec0ff..e6dbe8640 100644
--- a/src/common/kernel/unit.c
+++ b/src/common/kernel/unit.c
@@ -914,10 +914,6 @@ set_number(unit * u, int count)
#if !SKILLPOINTS
-attrib_type at_showskchange = {
- "showskchange", NULL, NULL, NULL, NULL, NULL, ATF_UNIQUE
-};
-
boolean
learn_skill(unit * u, skill_t sk, double chance)
{
@@ -969,22 +965,6 @@ learn_skill(unit * u, skill_t sk, double chance)
}
*/
-/*
- if(load == false) {
- for(a = a_find(u->attribs, &at_showskchange);a;a = a->nexttype) {
- if(a->data.sa[0] == id) {
- a->data.sa[1] = (short)(a->data.sa[1] + (level-oldlevel));
- break;
- }
- }
- if(a == NULL) {
- a = a_add(&u->attribs, a_new(&at_showskchange));
- a->data.sa[0] = id;
- a->data.sa[1] = (short)(level-oldlevel);
- }
- }
-*/
-
skill *
add_skill(unit * u, skill_t id)
{
diff --git a/src/res/de/strings.xml b/src/res/de/strings.xml
index 763fcab45..d93ec8baf 100644
--- a/src/res/de/strings.xml
+++ b/src/res/de/strings.xml
@@ -2909,6 +2909,74 @@
ent
+
+ Schattendrache
+ shadow dragon
+
+
+ Schattendrachen
+ shadow dragons
+
+
+ Schattendrachen
+ shadow dragons
+
+
+ Schattendrachen
+ shadow dragon
+
+
+
+ Todesflatter
+ darkbat
+
+
+ Todesflattern
+ darkbats
+
+
+ Todesflattern
+ darkbats
+
+
+ Todesflatter
+ darkbat
+
+
+
+ Alptraum
+ nightmare
+
+
+ Alpträume
+ nightmares
+
+
+ Alpträumen
+ nightmares
+
+
+ Alptraum
+ nightmare
+
+
+
+ Nachteinhorn
+ vampiric unicorn
+
+
+ Nachteinhörner
+ vampiric unicorns
+
+
+ Nachteinhörnern
+ vampiric unicorns
+
+
+ Nachteinhorn
+ vampiric unicorn
+
+
Wyrm
wyrm
diff --git a/src/res/races.xml b/src/res/races.xml
index 85f96c3ad..97fb3b5f3 100644
--- a/src/res/races.xml
+++ b/src/res/races.xml
@@ -1263,4 +1263,41 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+