BUG 2478: Fleeing units cannot move.

This commit is contained in:
Enno Rehling 2018-09-23 20:01:12 +02:00
parent 0759482934
commit d70f05f8db
2 changed files with 87 additions and 31 deletions

View file

@ -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);
fig->run.hp += fig->person[dt.index].hp; if (fig->person[dt.index].flags & FL_PANICED) {
++fig->run.number; 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.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,13 +3919,7 @@ static void battle_flee(battle * b)
} }
continue; continue;
} }
flee(dt);
if (fig->person[dt.index].flags & FL_PANICED) {
ispaniced = EFFECT_PANIC_SPELL;
}
if (chance(fmin(fleechance(u) + ispaniced, 0.90))) {
flee(dt);
}
} }
} }
} }
@ -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;

View file

@ -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);