forked from github/server
Merge pull request #694 from ennorehling/feature/2326-undeadhero
BUG 2326: counting undead heroes in battle summary
This commit is contained in:
commit
383866c44b
28
src/battle.c
28
src/battle.c
|
@ -439,7 +439,7 @@ static int get_row(const side * s, int row, const side * vs)
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int get_unitrow(const fighter * af, const side * vs)
|
int get_unitrow(const fighter * af, const side * vs)
|
||||||
{
|
{
|
||||||
int row = statusrow(af->status);
|
int row = statusrow(af->status);
|
||||||
if (vs == NULL) {
|
if (vs == NULL) {
|
||||||
|
@ -1589,8 +1589,7 @@ static troop select_opponent(battle * b, troop at, int mindist, int maxdist)
|
||||||
return dt;
|
return dt;
|
||||||
}
|
}
|
||||||
|
|
||||||
selist *fighters(battle * b, const side * vs, int minrow, int maxrow,
|
selist *select_fighters(battle * b, const side * vs, int mask, select_fun cb, void *cbdata)
|
||||||
int mask)
|
|
||||||
{
|
{
|
||||||
side *s;
|
side *s;
|
||||||
selist *fightervp = 0;
|
selist *fightervp = 0;
|
||||||
|
@ -1613,8 +1612,7 @@ selist *fighters(battle * b, const side * vs, int minrow, int maxrow,
|
||||||
assert(mask == (FS_HELP | FS_ENEMY) || !"invalid alliance state");
|
assert(mask == (FS_HELP | FS_ENEMY) || !"invalid alliance state");
|
||||||
}
|
}
|
||||||
for (fig = s->fighters; fig; fig = fig->next) {
|
for (fig = s->fighters; fig; fig = fig->next) {
|
||||||
int row = get_unitrow(fig, vs);
|
if (cb(vs, fig, cbdata)) {
|
||||||
if (row >= minrow && row <= maxrow) {
|
|
||||||
selist_push(&fightervp, fig);
|
selist_push(&fightervp, fig);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1623,6 +1621,26 @@ selist *fighters(battle * b, const side * vs, int minrow, int maxrow,
|
||||||
return fightervp;
|
return fightervp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct selector {
|
||||||
|
int minrow;
|
||||||
|
int maxrow;
|
||||||
|
};
|
||||||
|
|
||||||
|
static bool select_row(const side *vs, const fighter *fig, void *cbdata)
|
||||||
|
{
|
||||||
|
struct selector *sel = (struct selector *)cbdata;
|
||||||
|
int row = get_unitrow(fig, vs);
|
||||||
|
return (row >= sel->minrow && row <= sel->maxrow);
|
||||||
|
}
|
||||||
|
|
||||||
|
selist *fighters(battle * b, const side * vs, int minrow, int maxrow, int mask)
|
||||||
|
{
|
||||||
|
struct selector sel;
|
||||||
|
sel.maxrow = maxrow;
|
||||||
|
sel.minrow = minrow;
|
||||||
|
return select_fighters(b, vs, mask, select_row, &sel);
|
||||||
|
}
|
||||||
|
|
||||||
static void report_failed_spell(struct battle * b, struct unit * mage, const struct spell *sp)
|
static void report_failed_spell(struct battle * b, struct unit * mage, const struct spell *sp)
|
||||||
{
|
{
|
||||||
message *m = msg_message("battle::spell_failed", "unit spell", mage, sp);
|
message *m = msg_message("battle::spell_failed", "unit spell", mage, sp);
|
||||||
|
|
32
src/battle.h
32
src/battle.h
|
@ -229,15 +229,17 @@ extern "C" {
|
||||||
fighter * get_fighter(battle * b, const struct unit * u);
|
fighter * get_fighter(battle * b, const struct unit * u);
|
||||||
/* END battle interface */
|
/* END battle interface */
|
||||||
|
|
||||||
extern void do_battles(void);
|
void do_battles(void);
|
||||||
|
|
||||||
/* for combat spells and special attacks */
|
/* for combat spells and special attacks */
|
||||||
enum { SELECT_ADVANCE = 0x1, SELECT_DISTANCE = 0x2, SELECT_FIND = 0x4 };
|
enum { SELECT_ADVANCE = 0x1, SELECT_DISTANCE = 0x2, SELECT_FIND = 0x4 };
|
||||||
enum { ALLY_SELF, ALLY_ANY };
|
enum { ALLY_SELF, ALLY_ANY };
|
||||||
|
|
||||||
extern troop select_enemy(struct fighter *af, int minrow, int maxrow,
|
int get_unitrow(const fighter * af, const side * vs);
|
||||||
|
|
||||||
|
troop select_enemy(struct fighter *af, int minrow, int maxrow,
|
||||||
int select);
|
int select);
|
||||||
extern troop select_ally(struct fighter *af, int minrow, int maxrow,
|
troop select_ally(struct fighter *af, int minrow, int maxrow,
|
||||||
int allytype);
|
int allytype);
|
||||||
|
|
||||||
int count_enemies(struct battle *b, const struct fighter *af,
|
int count_enemies(struct battle *b, const struct fighter *af,
|
||||||
|
@ -246,21 +248,25 @@ extern "C" {
|
||||||
int calculate_armor(troop dt, const struct weapon_type *dwtype, const struct weapon_type *awtype, union variant *magres);
|
int calculate_armor(troop dt, const struct weapon_type *dwtype, const struct weapon_type *awtype, union variant *magres);
|
||||||
bool terminate(troop dt, troop at, int type, const char *damage,
|
bool terminate(troop dt, troop at, int type, const char *damage,
|
||||||
bool missile);
|
bool missile);
|
||||||
extern void message_all(battle * b, struct message *m);
|
void message_all(battle * b, struct message *m);
|
||||||
extern int hits(troop at, troop dt, weapon * awp);
|
int hits(troop at, troop dt, weapon * awp);
|
||||||
extern void damage_building(struct battle *b, struct building *bldg,
|
void damage_building(struct battle *b, struct building *bldg,
|
||||||
int damage_abs);
|
int damage_abs);
|
||||||
|
|
||||||
|
typedef bool(*select_fun)(const struct side *vs, const struct fighter *fig, void *cbdata);
|
||||||
|
struct selist *select_fighters(struct battle *b, const struct side *vs, int mask, select_fun cb, void *cbdata);
|
||||||
struct selist *fighters(struct battle *b, const struct side *vs,
|
struct selist *fighters(struct battle *b, const struct side *vs,
|
||||||
int minrow, int maxrow, int mask);
|
int minrow, int maxrow, int mask);
|
||||||
|
|
||||||
int count_allies(const struct side *as, int minrow, int maxrow,
|
int count_allies(const struct side *as, int minrow, int maxrow,
|
||||||
int select, int allytype);
|
int select, int allytype);
|
||||||
extern bool helping(const struct side *as, const struct side *ds);
|
bool helping(const struct side *as, const struct side *ds);
|
||||||
extern void rmfighter(fighter * df, int i);
|
void rmfighter(fighter * df, int i);
|
||||||
extern struct fighter *select_corpse(struct battle *b, struct fighter *af);
|
struct fighter *select_corpse(struct battle *b, struct fighter *af);
|
||||||
extern int statusrow(int status);
|
int statusrow(int status);
|
||||||
extern void drain_exp(struct unit *u, int d);
|
void drain_exp(struct unit *u, int d);
|
||||||
extern void kill_troop(troop dt);
|
void kill_troop(troop dt);
|
||||||
extern void remove_troop(troop dt); /* not the same as the badly named rmtroop */
|
void remove_troop(troop dt); /* not the same as the badly named rmtroop */
|
||||||
|
|
||||||
bool is_attacker(const fighter * fig);
|
bool is_attacker(const fighter * fig);
|
||||||
struct battle *make_battle(struct region * r);
|
struct battle *make_battle(struct region * r);
|
||||||
|
|
|
@ -981,7 +981,7 @@ void move_unit(unit * u, region * r, unit ** ulist)
|
||||||
/* ist mist, aber wegen nicht skalierender attribute notwendig: */
|
/* ist mist, aber wegen nicht skalierender attribute notwendig: */
|
||||||
#include "alchemy.h"
|
#include "alchemy.h"
|
||||||
|
|
||||||
void transfermen(unit * u, unit * dst, int n)
|
void clone_men(unit * u, unit * dst, int n)
|
||||||
{
|
{
|
||||||
const attrib *a;
|
const attrib *a;
|
||||||
int hp = u->hp;
|
int hp = u->hp;
|
||||||
|
@ -1074,7 +1074,6 @@ void transfermen(unit * u, unit * dst, int n)
|
||||||
transfer_curse(u, dst, n);
|
transfer_curse(u, dst, n);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
scale_number(u, u->number - n);
|
|
||||||
if (dst) {
|
if (dst) {
|
||||||
set_number(dst, dst->number + n);
|
set_number(dst, dst->number + n);
|
||||||
hp -= u->hp;
|
hp -= u->hp;
|
||||||
|
@ -1100,6 +1099,12 @@ void transfermen(unit * u, unit * dst, int n)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void transfermen(unit * u, unit * dst, int n)
|
||||||
|
{
|
||||||
|
clone_men(u, dst, n);
|
||||||
|
scale_number(u, u->number - n);
|
||||||
|
}
|
||||||
|
|
||||||
struct building *inside_building(const struct unit *u)
|
struct building *inside_building(const struct unit *u)
|
||||||
{
|
{
|
||||||
if (!u->building) {
|
if (!u->building) {
|
||||||
|
|
|
@ -165,7 +165,8 @@ extern "C" {
|
||||||
|
|
||||||
void set_level(struct unit *u, skill_t id, int level);
|
void set_level(struct unit *u, skill_t id, int level);
|
||||||
int get_level(const struct unit *u, skill_t id);
|
int get_level(const struct unit *u, skill_t id);
|
||||||
extern void transfermen(struct unit *src, struct unit *dst, int n);
|
void transfermen(struct unit *src, struct unit *dst, int n);
|
||||||
|
void clone_men(struct unit *src, struct unit *dst, int n); /* like transfer, but do not subtract from src */
|
||||||
|
|
||||||
int eff_skill(const struct unit *u, const struct skill *sv, const struct region *r);
|
int eff_skill(const struct unit *u, const struct skill *sv, const struct region *r);
|
||||||
int effskill_study(const struct unit *u, skill_t sk, const struct region *r);
|
int effskill_study(const struct unit *u, skill_t sk, const struct region *r);
|
||||||
|
|
|
@ -256,6 +256,17 @@ static void scramble_fighters(selist * ql)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool select_armed(const side *vs, const fighter *fig, void *cbdata)
|
||||||
|
{
|
||||||
|
int row = get_unitrow(fig, vs);
|
||||||
|
|
||||||
|
UNUSED_ARG(cbdata);
|
||||||
|
if (row >= FIGHT_ROW && row < BEHIND_ROW) {
|
||||||
|
return fig->alive > 0 && fig->weapons;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/* Rosthauch */
|
/* Rosthauch */
|
||||||
int sp_combatrosthauch(struct castorder * co)
|
int sp_combatrosthauch(struct castorder * co)
|
||||||
{
|
{
|
||||||
|
@ -275,22 +286,13 @@ int sp_combatrosthauch(struct castorder * co)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
fgs = fighters(b, fi->side, FIGHT_ROW, BEHIND_ROW - 1, FS_ENEMY);
|
fgs = select_fighters(b, fi->side, FS_ENEMY, select_armed, NULL);
|
||||||
scramble_fighters(fgs);
|
scramble_fighters(fgs);
|
||||||
|
|
||||||
for (qi = 0, ql = fgs; ql; selist_advance(&ql, &qi, 1)) {
|
for (qi = 0, ql = fgs; force>0 && ql; selist_advance(&ql, &qi, 1)) {
|
||||||
fighter *df = (fighter *)selist_get(ql, qi);
|
fighter *df = (fighter *)selist_get(ql, qi);
|
||||||
|
|
||||||
if (df->alive == 0)
|
|
||||||
continue;
|
|
||||||
if (force <= 0)
|
|
||||||
break;
|
|
||||||
|
|
||||||
/* da n MIN(force, x), sollte force maximal auf 0 sinken */
|
|
||||||
assert(force >= 0);
|
|
||||||
|
|
||||||
if (df->weapons) {
|
|
||||||
int w;
|
int w;
|
||||||
|
|
||||||
for (w = 0; df->weapons[w].type != NULL; ++w) {
|
for (w = 0; df->weapons[w].type != NULL; ++w) {
|
||||||
weapon *wp = df->weapons;
|
weapon *wp = df->weapons;
|
||||||
int n = MIN(force, wp->used);
|
int n = MIN(force, wp->used);
|
||||||
|
@ -326,7 +328,6 @@ int sp_combatrosthauch(struct castorder * co)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
selist_free(fgs);
|
selist_free(fgs);
|
||||||
|
|
||||||
if (k == 0) {
|
if (k == 0) {
|
||||||
|
@ -889,6 +890,13 @@ int sp_strong_wall(struct castorder * co)
|
||||||
return level;
|
return level;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool select_alive(const side *vs, const fighter *fig, void *cbdata)
|
||||||
|
{
|
||||||
|
UNUSED_ARG(vs);
|
||||||
|
UNUSED_ARG(cbdata);
|
||||||
|
return fig->alive > 0;
|
||||||
|
}
|
||||||
|
|
||||||
/** Spells: chaosrow / song of confusion.
|
/** Spells: chaosrow / song of confusion.
|
||||||
* German Title: 'Gesang der Verwirrung'
|
* German Title: 'Gesang der Verwirrung'
|
||||||
*/
|
*/
|
||||||
|
@ -915,7 +923,7 @@ int sp_chaosrow(struct castorder * co)
|
||||||
|
|
||||||
power = chaosrow ? (power * 40) : get_force(power, 5);
|
power = chaosrow ? (power * 40) : get_force(power, 5);
|
||||||
|
|
||||||
fgs = fighters(b, fi->side, FIGHT_ROW, NUMROWS, FS_ENEMY);
|
fgs = select_fighters(b, fi->side, FS_ENEMY, select_alive, NULL);
|
||||||
scramble_fighters(fgs);
|
scramble_fighters(fgs);
|
||||||
|
|
||||||
for (qi = 0, ql = fgs; ql; selist_advance(&ql, &qi, 1)) {
|
for (qi = 0, ql = fgs; ql; selist_advance(&ql, &qi, 1)) {
|
||||||
|
@ -977,9 +985,18 @@ int sp_chaosrow(struct castorder * co)
|
||||||
return level;
|
return level;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool select_afraid(const side *vs, const fighter *fig, void *cbdata)
|
||||||
|
{
|
||||||
|
int row = get_unitrow(fig, vs);
|
||||||
|
UNUSED_ARG(cbdata);
|
||||||
|
if (row >= FIGHT_ROW && row <= AVOID_ROW) {
|
||||||
|
return fig->alive + fig->run.number < fig->unit->number;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/* Gesang der Furcht (Kampfzauber) */
|
/* Gesang der Furcht (Kampfzauber) */
|
||||||
/* Panik (Pr<50>kampfzauber) */
|
/* Panik (Pr<50>kampfzauber) */
|
||||||
|
|
||||||
int flee_spell(struct castorder * co, int strength)
|
int flee_spell(struct castorder * co, int strength)
|
||||||
{
|
{
|
||||||
fighter * fi = co->magician.fig;
|
fighter * fi = co->magician.fig;
|
||||||
|
@ -994,23 +1011,20 @@ int flee_spell(struct castorder * co, int strength)
|
||||||
int force;
|
int force;
|
||||||
|
|
||||||
force = (int)get_force(power, strength);
|
force = (int)get_force(power, strength);
|
||||||
if (!count_enemies(b, fi, FIGHT_ROW, AVOID_ROW, SELECT_ADVANCE | SELECT_FIND)) {
|
if (force<=0 || !count_enemies(b, fi, FIGHT_ROW, AVOID_ROW, SELECT_ADVANCE | SELECT_FIND)) {
|
||||||
msg = msg_message("sp_flee_effect_0", "mage spell", mage, sp);
|
msg = msg_message("sp_flee_effect_0", "mage spell", mage, sp);
|
||||||
message_all(b, msg);
|
message_all(b, msg);
|
||||||
msg_release(msg);
|
msg_release(msg);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
fgs = fighters(b, fi->side, FIGHT_ROW, AVOID_ROW, FS_ENEMY);
|
fgs = select_fighters(b, fi->side, FS_ENEMY, select_afraid, NULL);
|
||||||
scramble_fighters(fgs);
|
scramble_fighters(fgs);
|
||||||
|
|
||||||
for (qi = 0, ql = fgs; ql; selist_advance(&ql, &qi, 1)) {
|
for (qi = 0, ql = fgs; force > 0 && ql; selist_advance(&ql, &qi, 1)) {
|
||||||
fighter *df = (fighter *)selist_get(ql, qi);
|
fighter *df = (fighter *)selist_get(ql, qi);
|
||||||
|
|
||||||
for (n = 0; n != df->alive; ++n) {
|
for (n = 0; force > 0 && n != df->alive; ++n) {
|
||||||
if (force < 0)
|
|
||||||
break;
|
|
||||||
|
|
||||||
if (df->person[n].flags & FL_PANICED) { /* bei SPL_SONG_OF_FEAR m<>glich */
|
if (df->person[n].flags & FL_PANICED) { /* bei SPL_SONG_OF_FEAR m<>glich */
|
||||||
df->person[n].attack -= 1;
|
df->person[n].attack -= 1;
|
||||||
--force;
|
--force;
|
||||||
|
@ -1556,8 +1570,8 @@ int sp_healing(struct castorder * co)
|
||||||
message *msg;
|
message *msg;
|
||||||
bool use_item = has_ao_healing(mage);
|
bool use_item = has_ao_healing(mage);
|
||||||
|
|
||||||
/* bis zu 11 Personen pro Stufe (einen HP m<EFBFBD>ssen sie ja noch
|
/* bis zu 11 Personen pro Stufe (einen HP muessen sie ja noch
|
||||||
* haben, sonst w<EFBFBD>ren sie tot) k<EFBFBD>nnen geheilt werden */
|
* haben, sonst waeren sie tot) koennen geheilt werden */
|
||||||
|
|
||||||
if (use_item) {
|
if (use_item) {
|
||||||
healhp *= 2;
|
healhp *= 2;
|
||||||
|
@ -1589,6 +1603,19 @@ int sp_healing(struct castorder * co)
|
||||||
return level;
|
return level;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool select_hero(const side *vs, const fighter *fig, void *cbdata)
|
||||||
|
{
|
||||||
|
UNUSED_ARG(cbdata);
|
||||||
|
|
||||||
|
if (playerrace(u_race(fig->unit))) {
|
||||||
|
int row = get_unitrow(fig, vs);
|
||||||
|
if (row >= FIGHT_ROW && row <= AVOID_ROW) {
|
||||||
|
return fig->alive + fig->run.number < fig->unit->number;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
int sp_undeadhero(struct castorder * co)
|
int sp_undeadhero(struct castorder * co)
|
||||||
{
|
{
|
||||||
fighter * fi = co->magician.fig;
|
fighter * fi = co->magician.fig;
|
||||||
|
@ -1603,30 +1630,20 @@ int sp_undeadhero(struct castorder * co)
|
||||||
int force = (int)get_force(power, 0);
|
int force = (int)get_force(power, 0);
|
||||||
double c = 0.50 + 0.02 * power;
|
double c = 0.50 + 0.02 * power;
|
||||||
|
|
||||||
/* Liste aus allen K<EFBFBD>mpfern */
|
/* Liste aus allen Kaempfern */
|
||||||
fgs = fighters(b, fi->side, FIGHT_ROW, AVOID_ROW, FS_ENEMY | FS_HELP);
|
fgs = select_fighters(b, fi->side, FS_ENEMY | FS_HELP, select_hero, NULL);
|
||||||
scramble_fighters(fgs);
|
scramble_fighters(fgs);
|
||||||
|
|
||||||
for (qi = 0, ql = fgs; ql; selist_advance(&ql, &qi, 1)) {
|
for (qi = 0, ql = fgs; ql && force>0; selist_advance(&ql, &qi, 1)) {
|
||||||
fighter *df = (fighter *)selist_get(ql, qi);
|
fighter *df = (fighter *)selist_get(ql, qi);
|
||||||
unit *du = df->unit;
|
unit *du = df->unit;
|
||||||
|
|
||||||
if (force <= 0)
|
|
||||||
break;
|
|
||||||
|
|
||||||
/* keine Monster */
|
|
||||||
if (!playerrace(u_race(du)))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (df->alive + df->run.number < du->number) {
|
|
||||||
int j = 0;
|
int j = 0;
|
||||||
|
|
||||||
/* Wieviele Untote k<>nnen wir aus dieser Einheit wecken? */
|
/* Wieviele Untote koennen wir aus dieser Einheit wecken? */
|
||||||
for (n = df->alive + df->run.number; n != du->number; n++) {
|
for (n = df->alive + df->run.number; force>0 && n != du->number; n++) {
|
||||||
if (chance(c)) {
|
if (chance(c)) {
|
||||||
++j;
|
++j;
|
||||||
if (--force <= 0)
|
--force;
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1678,7 +1695,6 @@ int sp_undeadhero(struct castorder * co)
|
||||||
undead += j;
|
undead += j;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
selist_free(fgs);
|
selist_free(fgs);
|
||||||
|
|
||||||
level = MIN(level, undead);
|
level = MIN(level, undead);
|
||||||
|
|
|
@ -3,6 +3,7 @@ IF EXIST ..\build-vs10 SET BUILD=..\build-vs10\eressea\Debug
|
||||||
IF EXIST ..\build-vs11 SET BUILD=..\build-vs11\eressea\Debug
|
IF EXIST ..\build-vs11 SET BUILD=..\build-vs11\eressea\Debug
|
||||||
IF EXIST ..\build-vs12 SET BUILD=..\build-vs12\eressea\Debug
|
IF EXIST ..\build-vs12 SET BUILD=..\build-vs12\eressea\Debug
|
||||||
IF EXIST ..\build-vs14 SET BUILD=..\build-vs14\eressea\Debug
|
IF EXIST ..\build-vs14 SET BUILD=..\build-vs14\eressea\Debug
|
||||||
|
REM IF EXIST ..\build-vs15 SET BUILD=..\build-vs15\eressea\Debug
|
||||||
SET SERVER=%BUILD%\eressea.exe
|
SET SERVER=%BUILD%\eressea.exe
|
||||||
%BUILD%\test_eressea.exe
|
%BUILD%\test_eressea.exe
|
||||||
%SERVER% ..\scripts\run-tests.lua
|
%SERVER% ..\scripts\run-tests.lua
|
||||||
|
|
Loading…
Reference in New Issue