forked from github/server
BUG 2478: Fleeing units cannot move.
This commit is contained in:
parent
0759482934
commit
d70f05f8db
2 changed files with 87 additions and 31 deletions
52
src/battle.c
52
src/battle.c
|
@ -101,7 +101,7 @@ typedef enum combatmagic {
|
||||||
#define MAXSPELLRANGE 7
|
#define MAXSPELLRANGE 7
|
||||||
|
|
||||||
#define ROW_FACTOR 3 /* factor for combat row advancement rule */
|
#define ROW_FACTOR 3 /* factor for combat row advancement rule */
|
||||||
#define EFFECT_PANIC_SPELL 0.25
|
#define EFFECT_PANIC_SPELL 25
|
||||||
#define TROLL_REGENERATION 0.10
|
#define TROLL_REGENERATION 0.10
|
||||||
|
|
||||||
/* Nach dem alten System: */
|
/* Nach dem alten System: */
|
||||||
|
@ -126,6 +126,9 @@ const troop no_troop = { 0, 0 };
|
||||||
static int max_turns;
|
static int max_turns;
|
||||||
static int rule_damage;
|
static int rule_damage;
|
||||||
static int rule_loot;
|
static int rule_loot;
|
||||||
|
static int flee_chance_max_percent;
|
||||||
|
static int flee_chance_base;
|
||||||
|
static int flee_chance_skill_bonus;
|
||||||
static int skill_formula;
|
static int skill_formula;
|
||||||
static int rule_cavalry_skill;
|
static int rule_cavalry_skill;
|
||||||
static int rule_population_damage;
|
static int rule_population_damage;
|
||||||
|
@ -144,6 +147,9 @@ static void init_rules(void)
|
||||||
{
|
{
|
||||||
it_mistletoe = it_find("mistletoe");
|
it_mistletoe = it_find("mistletoe");
|
||||||
|
|
||||||
|
flee_chance_skill_bonus = config_get_int("rules.combat.flee_chance_bonus", 5);
|
||||||
|
flee_chance_base = config_get_int("rules.combat.flee_chance_base", 20);
|
||||||
|
flee_chance_max_percent = config_get_int("rules.combat.flee_chance_limit", 90);
|
||||||
rule_nat_armor = config_get_int("rules.combat.nat_armor", 0);
|
rule_nat_armor = config_get_int("rules.combat.nat_armor", 0);
|
||||||
rule_tactics_formula = config_get_int("rules.tactics.formula", 0);
|
rule_tactics_formula = config_get_int("rules.tactics.formula", 0);
|
||||||
rule_goblin_bonus = config_get_int("rules.combat.goblinbonus", 10);
|
rule_goblin_bonus = config_get_int("rules.combat.goblinbonus", 10);
|
||||||
|
@ -2276,7 +2282,7 @@ static void add_tactics(tactics * ta, fighter * fig, int value)
|
||||||
ta->value = value;
|
ta->value = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
static double horse_fleeing_bonus(const unit * u)
|
static int horse_fleeing_bonus(const unit * u)
|
||||||
{
|
{
|
||||||
const item_type *it_horse, *it_elvenhorse, *it_charger;
|
const item_type *it_horse, *it_elvenhorse, *it_charger;
|
||||||
int n1 = 0, n2 = 0, n3 = 0;
|
int n1 = 0, n2 = 0, n3 = 0;
|
||||||
|
@ -2299,26 +2305,26 @@ static double horse_fleeing_bonus(const unit * u)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (skl >= 5 && n3 >= u->number)
|
if (skl >= 5 && n3 >= u->number)
|
||||||
return 0.30;
|
return 30;
|
||||||
if (skl >= 2 && n2 + n3 >= u->number)
|
if (skl >= 2 && n2 + n3 >= u->number)
|
||||||
return 0.20;
|
return 20;
|
||||||
if (n1 + n2 + n3 >= u->number)
|
if (n1 + n2 + n3 >= u->number)
|
||||||
return 0.10;
|
return 10;
|
||||||
return 0.0F;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
double fleechance(unit * u)
|
static int fleechance(unit * u)
|
||||||
{
|
{
|
||||||
double p = 0.20; /* Fluchtwahrscheinlichkeit in % */
|
int p = flee_chance_base; /* Fluchtwahrscheinlichkeit in % */
|
||||||
/* Einheit u versucht, dem Get<65>mmel zu entkommen */
|
/* Einheit u versucht, dem Get<65>mmel zu entkommen */
|
||||||
|
|
||||||
p += (effskill(u, SK_STEALTH, 0) * 0.05);
|
p += (effskill(u, SK_STEALTH, 0) * flee_chance_skill_bonus);
|
||||||
p += horse_fleeing_bonus(u);
|
p += horse_fleeing_bonus(u);
|
||||||
|
|
||||||
if (u_race(u) == get_race(RC_HALFLING)) {
|
if (u_race(u) == get_race(RC_HALFLING)) {
|
||||||
p += 0.20;
|
p += flee_chance_base;
|
||||||
if (p > 0.9) {
|
if (p > flee_chance_max_percent) {
|
||||||
p = 0.9;
|
p = flee_chance_max_percent;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return p;
|
return p;
|
||||||
|
@ -2617,7 +2623,7 @@ static void aftermath(battle * b)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
snumber += du->number;
|
snumber += du->number;
|
||||||
if (df->alive == 0) {
|
if (dead == df->unit->number) {
|
||||||
flags = UFL_DEAD;
|
flags = UFL_DEAD;
|
||||||
}
|
}
|
||||||
else if (relevant) {
|
else if (relevant) {
|
||||||
|
@ -3631,13 +3637,21 @@ static void flee(const troop dt)
|
||||||
{
|
{
|
||||||
fighter *fig = dt.fighter;
|
fighter *fig = dt.fighter;
|
||||||
unit *u = fig->unit;
|
unit *u = fig->unit;
|
||||||
|
int fchance = fleechance(u);
|
||||||
|
|
||||||
|
if (fig->person[dt.index].flags & FL_PANICED) {
|
||||||
|
fchance += EFFECT_PANIC_SPELL;
|
||||||
|
}
|
||||||
|
if (fchance > flee_chance_max_percent) {
|
||||||
|
fchance = flee_chance_max_percent;
|
||||||
|
}
|
||||||
|
if (rng_int() % 100 < fchance) {
|
||||||
fig->run.hp += fig->person[dt.index].hp;
|
fig->run.hp += fig->person[dt.index].hp;
|
||||||
++fig->run.number;
|
++fig->run.number;
|
||||||
|
|
||||||
setguard(u, false);
|
setguard(u, false);
|
||||||
|
|
||||||
kill_troop(dt);
|
kill_troop(dt);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool is_calmed(const unit *u, const faction *f) {
|
static bool is_calmed(const unit *u, const faction *f) {
|
||||||
|
@ -3881,7 +3895,6 @@ static void battle_flee(battle * b)
|
||||||
dt.fighter = fig;
|
dt.fighter = fig;
|
||||||
dt.index = fig->alive - fig->removed;
|
dt.index = fig->alive - fig->removed;
|
||||||
while (s->size[SUM_ROW] && dt.index != 0) {
|
while (s->size[SUM_ROW] && dt.index != 0) {
|
||||||
double ispaniced = 0.0;
|
|
||||||
--dt.index;
|
--dt.index;
|
||||||
assert(dt.index >= 0 && dt.index < fig->unit->number);
|
assert(dt.index >= 0 && dt.index < fig->unit->number);
|
||||||
assert(fig->person[dt.index].hp > 0);
|
assert(fig->person[dt.index].hp > 0);
|
||||||
|
@ -3906,17 +3919,11 @@ static void battle_flee(battle * b)
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fig->person[dt.index].flags & FL_PANICED) {
|
|
||||||
ispaniced = EFFECT_PANIC_SPELL;
|
|
||||||
}
|
|
||||||
if (chance(fmin(fleechance(u) + ispaniced, 0.90))) {
|
|
||||||
flee(dt);
|
flee(dt);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool is_enemy(battle *b, unit *u1, unit *u2) {
|
static bool is_enemy(battle *b, unit *u1, unit *u2) {
|
||||||
|
@ -3966,8 +3973,7 @@ void force_leave(region *r, battle *b) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void do_battle(region * r)
|
static void do_battle(region * r) {
|
||||||
{
|
|
||||||
battle *b = NULL;
|
battle *b = NULL;
|
||||||
bool fighting;
|
bool fighting;
|
||||||
ship *sh;
|
ship *sh;
|
||||||
|
|
|
@ -2,6 +2,8 @@
|
||||||
|
|
||||||
#include "battle.h"
|
#include "battle.h"
|
||||||
|
|
||||||
|
#include "guard.h"
|
||||||
|
#include "keyword.h"
|
||||||
#include "reports.h"
|
#include "reports.h"
|
||||||
#include "skill.h"
|
#include "skill.h"
|
||||||
|
|
||||||
|
@ -10,6 +12,7 @@
|
||||||
#include <kernel/faction.h>
|
#include <kernel/faction.h>
|
||||||
#include <kernel/curse.h>
|
#include <kernel/curse.h>
|
||||||
#include <kernel/item.h>
|
#include <kernel/item.h>
|
||||||
|
#include <kernel/order.h>
|
||||||
#include <kernel/race.h>
|
#include <kernel/race.h>
|
||||||
#include <kernel/region.h>
|
#include <kernel/region.h>
|
||||||
#include <kernel/ship.h>
|
#include <kernel/ship.h>
|
||||||
|
@ -17,6 +20,7 @@
|
||||||
|
|
||||||
#include <spells/buildingcurse.h>
|
#include <spells/buildingcurse.h>
|
||||||
|
|
||||||
|
#include <util/base36.h>
|
||||||
#include <util/functions.h>
|
#include <util/functions.h>
|
||||||
#include <util/language.h>
|
#include <util/language.h>
|
||||||
#include <util/message.h>
|
#include <util/message.h>
|
||||||
|
@ -31,6 +35,21 @@
|
||||||
|
|
||||||
#include "tests.h"
|
#include "tests.h"
|
||||||
|
|
||||||
|
static void setup_messages(void) {
|
||||||
|
mt_create_va(mt_new("start_battle", NULL), "factions:string", MT_NEW_END);
|
||||||
|
mt_create_va(mt_new("para_army_index", NULL), "index:int", "name:string", MT_NEW_END);
|
||||||
|
mt_create_va(mt_new("battle_msg", NULL), "string:string", MT_NEW_END);
|
||||||
|
mt_create_va(mt_new("battle_row", NULL), "row:int", MT_NEW_END);
|
||||||
|
mt_create_va(mt_new("para_lineup_battle", NULL), "turn:int", MT_NEW_END);
|
||||||
|
mt_create_va(mt_new("para_after_battle", NULL), MT_NEW_END);
|
||||||
|
mt_create_va(mt_new("army_report", NULL),
|
||||||
|
"index:int", "abbrev:string", "dead:int", "fled:int", "survived:int",
|
||||||
|
MT_NEW_END);
|
||||||
|
mt_create_va(mt_new("casualties", NULL),
|
||||||
|
"unit:unit", "runto:region", "run:int", "alive:int", "fallen:int",
|
||||||
|
MT_NEW_END);
|
||||||
|
}
|
||||||
|
|
||||||
static void test_make_fighter(CuTest * tc)
|
static void test_make_fighter(CuTest * tc)
|
||||||
{
|
{
|
||||||
unit *au;
|
unit *au;
|
||||||
|
@ -566,7 +585,7 @@ static void test_battle_report_one(CuTest *tc)
|
||||||
fighter *fig;
|
fighter *fig;
|
||||||
|
|
||||||
test_setup();
|
test_setup();
|
||||||
mt_create_va(mt_new("start_battle", NULL), "factions:string", MT_NEW_END);
|
setup_messages();
|
||||||
r = test_create_plain(0, 0);
|
r = test_create_plain(0, 0);
|
||||||
u1 = test_create_unit(test_create_faction(NULL), r);
|
u1 = test_create_unit(test_create_faction(NULL), r);
|
||||||
u2 = test_create_unit(test_create_faction(NULL), r);
|
u2 = test_create_unit(test_create_faction(NULL), r);
|
||||||
|
@ -597,7 +616,7 @@ static void test_battle_report_two(CuTest *tc)
|
||||||
test_setup();
|
test_setup();
|
||||||
lang = test_create_locale();
|
lang = test_create_locale();
|
||||||
locale_setstring(lang, "and", "and");
|
locale_setstring(lang, "and", "and");
|
||||||
mt_create_va(mt_new("start_battle", NULL), "factions:string", MT_NEW_END);
|
setup_messages();
|
||||||
r = test_create_plain(0, 0);
|
r = test_create_plain(0, 0);
|
||||||
u1 = test_create_unit(test_create_faction(NULL), r);
|
u1 = test_create_unit(test_create_faction(NULL), r);
|
||||||
u1->faction->locale = lang;
|
u1->faction->locale = lang;
|
||||||
|
@ -630,7 +649,7 @@ static void test_battle_report_three(CuTest *tc)
|
||||||
test_setup();
|
test_setup();
|
||||||
lang = test_create_locale();
|
lang = test_create_locale();
|
||||||
locale_setstring(lang, "and", "and");
|
locale_setstring(lang, "and", "and");
|
||||||
mt_create_va(mt_new("start_battle", NULL), "factions:string", MT_NEW_END);
|
setup_messages();
|
||||||
r = test_create_plain(0, 0);
|
r = test_create_plain(0, 0);
|
||||||
u1 = test_create_unit(test_create_faction(NULL), r);
|
u1 = test_create_unit(test_create_faction(NULL), r);
|
||||||
u1->faction->locale = lang;
|
u1->faction->locale = lang;
|
||||||
|
@ -783,12 +802,43 @@ static void test_tactics_chance(CuTest *tc) {
|
||||||
test_teardown();
|
test_teardown();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void test_battle_fleeing(CuTest *tc) {
|
||||||
|
region *r;
|
||||||
|
unit *u1, *u2;
|
||||||
|
test_setup();
|
||||||
|
setup_messages();
|
||||||
|
r = test_create_plain(0, 0);
|
||||||
|
u1 = test_create_unit(test_create_faction(NULL), r);
|
||||||
|
u2 = test_create_unit(test_create_faction(NULL), r);
|
||||||
|
u1->status = ST_FLEE;
|
||||||
|
u2->status = ST_AGGRO;
|
||||||
|
#if 0
|
||||||
|
setguard(u1, true);
|
||||||
|
CuAssertIntEquals(tc, UFL_GUARD, (u1->flags & UFL_GUARD));
|
||||||
|
CuAssertIntEquals(tc, RF_GUARDED, (r->flags & RF_GUARDED));
|
||||||
|
#endif
|
||||||
|
config_set_int("rules.combat.flee_chance_base", 100);
|
||||||
|
config_set_int("rules.combat.flee_chance_limit", 100);
|
||||||
|
unit_addorder(u2, create_order(K_ATTACK, u2->faction->locale, itoa36(u1->no)));
|
||||||
|
do_battles();
|
||||||
|
CuAssertIntEquals(tc, 1, u1->number);
|
||||||
|
CuAssertIntEquals(tc, 1, u2->number);
|
||||||
|
#if 0
|
||||||
|
CuAssertIntEquals(tc, 0, (u1->flags & UFL_GUARD));
|
||||||
|
CuAssertIntEquals(tc, 0, (r->flags & RF_GUARDED));
|
||||||
|
#endif
|
||||||
|
CuAssertIntEquals(tc, UFL_LONGACTION, (u1->flags & UFL_LONGACTION));
|
||||||
|
CuAssertIntEquals(tc, UFL_LONGACTION | UFL_NOTMOVING, (u2->flags & (UFL_LONGACTION | UFL_NOTMOVING)));
|
||||||
|
test_teardown();
|
||||||
|
}
|
||||||
|
|
||||||
CuSuite *get_battle_suite(void)
|
CuSuite *get_battle_suite(void)
|
||||||
{
|
{
|
||||||
CuSuite *suite = CuSuiteNew();
|
CuSuite *suite = CuSuiteNew();
|
||||||
SUITE_ADD_TEST(suite, test_make_fighter);
|
SUITE_ADD_TEST(suite, test_make_fighter);
|
||||||
SUITE_ADD_TEST(suite, test_select_weapon_restricted);
|
SUITE_ADD_TEST(suite, test_select_weapon_restricted);
|
||||||
SUITE_ADD_TEST(suite, test_select_armor);
|
SUITE_ADD_TEST(suite, test_select_armor);
|
||||||
|
SUITE_ADD_TEST(suite, test_battle_fleeing);
|
||||||
SUITE_ADD_TEST(suite, test_battle_skilldiff);
|
SUITE_ADD_TEST(suite, test_battle_skilldiff);
|
||||||
SUITE_ADD_TEST(suite, test_battle_skilldiff_building);
|
SUITE_ADD_TEST(suite, test_battle_skilldiff_building);
|
||||||
SUITE_ADD_TEST(suite, test_battle_report_one);
|
SUITE_ADD_TEST(suite, test_battle_report_one);
|
||||||
|
|
Loading…
Reference in a new issue