From d70f05f8dbe35877b2550d9d2c27e0c85653e158 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sun, 23 Sep 2018 20:01:12 +0200 Subject: [PATCH] BUG 2478: Fleeing units cannot move. --- src/battle.c | 62 ++++++++++++++++++++++++++--------------------- src/battle.test.c | 56 +++++++++++++++++++++++++++++++++++++++--- 2 files changed, 87 insertions(+), 31 deletions(-) diff --git a/src/battle.c b/src/battle.c index 8e8c3610b..bf9df9b2b 100644 --- a/src/battle.c +++ b/src/battle.c @@ -101,7 +101,7 @@ typedef enum combatmagic { #define MAXSPELLRANGE 7 #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 /* Nach dem alten System: */ @@ -126,6 +126,9 @@ const troop no_troop = { 0, 0 }; static int max_turns; static int rule_damage; 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 rule_cavalry_skill; static int rule_population_damage; @@ -144,6 +147,9 @@ static void init_rules(void) { 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_tactics_formula = config_get_int("rules.tactics.formula", 0); 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; } -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; 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) - return 0.30; + return 30; if (skl >= 2 && n2 + n3 >= u->number) - return 0.20; + return 20; if (n1 + n2 + n3 >= u->number) - return 0.10; - return 0.0F; + return 10; + 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�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); if (u_race(u) == get_race(RC_HALFLING)) { - p += 0.20; - if (p > 0.9) { - p = 0.9; + p += flee_chance_base; + if (p > flee_chance_max_percent) { + p = flee_chance_max_percent; } } return p; @@ -2617,7 +2623,7 @@ static void aftermath(battle * b) } } snumber += du->number; - if (df->alive == 0) { + if (dead == df->unit->number) { flags = UFL_DEAD; } else if (relevant) { @@ -3631,13 +3637,21 @@ static void flee(const troop dt) { fighter *fig = dt.fighter; unit *u = fig->unit; + int fchance = fleechance(u); - fig->run.hp += fig->person[dt.index].hp; - ++fig->run.number; + 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.number; - setguard(u, false); - - kill_troop(dt); + setguard(u, false); + kill_troop(dt); + } } static bool is_calmed(const unit *u, const faction *f) { @@ -3881,7 +3895,6 @@ static void battle_flee(battle * b) dt.fighter = fig; dt.index = fig->alive - fig->removed; while (s->size[SUM_ROW] && dt.index != 0) { - double ispaniced = 0.0; --dt.index; assert(dt.index >= 0 && dt.index < fig->unit->number); assert(fig->person[dt.index].hp > 0); @@ -3906,13 +3919,7 @@ static void battle_flee(battle * b) } 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); } } } @@ -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; bool fighting; ship *sh; diff --git a/src/battle.test.c b/src/battle.test.c index 7c7012e77..8cfbb0d2a 100644 --- a/src/battle.test.c +++ b/src/battle.test.c @@ -2,6 +2,8 @@ #include "battle.h" +#include "guard.h" +#include "keyword.h" #include "reports.h" #include "skill.h" @@ -10,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -17,6 +20,7 @@ #include +#include #include #include #include @@ -31,6 +35,21 @@ #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) { unit *au; @@ -566,7 +585,7 @@ static void test_battle_report_one(CuTest *tc) fighter *fig; test_setup(); - mt_create_va(mt_new("start_battle", NULL), "factions:string", MT_NEW_END); + 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); @@ -597,7 +616,7 @@ static void test_battle_report_two(CuTest *tc) test_setup(); lang = test_create_locale(); 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); u1 = test_create_unit(test_create_faction(NULL), r); u1->faction->locale = lang; @@ -630,7 +649,7 @@ static void test_battle_report_three(CuTest *tc) test_setup(); lang = test_create_locale(); 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); u1 = test_create_unit(test_create_faction(NULL), r); u1->faction->locale = lang; @@ -783,12 +802,43 @@ static void test_tactics_chance(CuTest *tc) { 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 *suite = CuSuiteNew(); SUITE_ADD_TEST(suite, test_make_fighter); SUITE_ADD_TEST(suite, test_select_weapon_restricted); 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_building); SUITE_ADD_TEST(suite, test_battle_report_one);