Account for meandering movement when predicting unit path in siege engine.

The movement is random, but there is an average slowdown coefficient.
develop
Alexander Gavrilov 2014-04-15 12:32:41 +04:00
parent 55cea36c76
commit fc9826389b
6 changed files with 69 additions and 0 deletions

@ -1326,6 +1326,10 @@ is <em>true</em>, subtracts the rust penalty.</p>
<li><p class="first"><tt class="docutils literal">dfhack.units.computeMovementSpeed(unit)</tt></p> <li><p class="first"><tt class="docutils literal">dfhack.units.computeMovementSpeed(unit)</tt></p>
<p>Computes number of frames * 100 it takes the unit to move in its current state of mind and body.</p> <p>Computes number of frames * 100 it takes the unit to move in its current state of mind and body.</p>
</li> </li>
<li><p class="first"><tt class="docutils literal">dfhack.units.computeSlowdownFactor(unit)</tt></p>
<p>Meandering and floundering in liquid introduces additional slowdown. It is
random, but the function computes and returns the expected mean factor as a float.</p>
</li>
<li><p class="first"><tt class="docutils literal">dfhack.units.getNoblePositions(unit)</tt></p> <li><p class="first"><tt class="docutils literal">dfhack.units.getNoblePositions(unit)</tt></p>
<p>Returns a list of tables describing noble position assignments, or <em>nil</em>. <p>Returns a list of tables describing noble position assignments, or <em>nil</em>.
Every table has fields <tt class="docutils literal">entity</tt>, <tt class="docutils literal">assignment</tt> and <tt class="docutils literal">position</tt>.</p> Every table has fields <tt class="docutils literal">entity</tt>, <tt class="docutils literal">assignment</tt> and <tt class="docutils literal">position</tt>.</p>

@ -1067,6 +1067,11 @@ Units module
Computes number of frames * 100 it takes the unit to move in its current state of mind and body. Computes number of frames * 100 it takes the unit to move in its current state of mind and body.
* ``dfhack.units.computeSlowdownFactor(unit)``
Meandering and floundering in liquid introduces additional slowdown. It is
random, but the function computes and returns the expected mean factor as a float.
* ``dfhack.units.getNoblePositions(unit)`` * ``dfhack.units.getNoblePositions(unit)``
Returns a list of tables describing noble position assignments, or *nil*. Returns a list of tables describing noble position assignments, or *nil*.

@ -1391,6 +1391,7 @@ static const LuaWrapper::FunctionReg dfhack_units_module[] = {
WRAPM(Units, getEffectiveSkill), WRAPM(Units, getEffectiveSkill),
WRAPM(Units, getExperience), WRAPM(Units, getExperience),
WRAPM(Units, computeMovementSpeed), WRAPM(Units, computeMovementSpeed),
WRAPM(Units, computeSlowdownFactor),
WRAPM(Units, getProfessionName), WRAPM(Units, getProfessionName),
WRAPM(Units, getCasteProfessionName), WRAPM(Units, getCasteProfessionName),
WRAPM(Units, getProfessionColor), WRAPM(Units, getProfessionColor),

@ -241,6 +241,7 @@ DFHACK_EXPORT int getEffectiveSkill(df::unit *unit, df::job_skill skill_id);
DFHACK_EXPORT int getExperience(df::unit *unit, df::job_skill skill_id, bool total = false); DFHACK_EXPORT int getExperience(df::unit *unit, df::job_skill skill_id, bool total = false);
DFHACK_EXPORT int computeMovementSpeed(df::unit *unit); DFHACK_EXPORT int computeMovementSpeed(df::unit *unit);
DFHACK_EXPORT float computeSlowdownFactor(df::unit *unit);
struct NoblePosition { struct NoblePosition {
df::historical_entity *entity; df::historical_entity *entity;

@ -54,6 +54,8 @@ using namespace std;
#include "df/unit_soul.h" #include "df/unit_soul.h"
#include "df/nemesis_record.h" #include "df/nemesis_record.h"
#include "df/historical_entity.h" #include "df/historical_entity.h"
#include "df/entity_raw.h"
#include "df/entity_raw_flags.h"
#include "df/historical_figure.h" #include "df/historical_figure.h"
#include "df/historical_figure_info.h" #include "df/historical_figure_info.h"
#include "df/entity_position.h" #include "df/entity_position.h"
@ -1060,6 +1062,8 @@ int Units::computeMovementSpeed(df::unit *unit)
{ {
using namespace df::enums::physical_attribute_type; using namespace df::enums::physical_attribute_type;
CHECK_NULL_POINTER(unit);
/* /*
* Pure reverse-engineered computation of unit _slowness_, * Pure reverse-engineered computation of unit _slowness_,
* i.e. number of ticks to move * 100. * i.e. number of ticks to move * 100.
@ -1264,6 +1268,54 @@ int Units::computeMovementSpeed(df::unit *unit)
return std::min(10000, std::max(0, speed)); return std::min(10000, std::max(0, speed));
} }
static bool entityRawFlagSet(int civ_id, df::entity_raw_flags flag)
{
auto entity = df::historical_entity::find(civ_id);
return entity && entity->entity_raw && entity->entity_raw->flags.is_set(flag);
}
float Units::computeSlowdownFactor(df::unit *unit)
{
CHECK_NULL_POINTER(unit);
/*
* These slowdowns are actually done by skipping a move if random(x) != 0, so
* it follows the geometric distribution. The mean expected slowdown is x.
*/
float coeff = 1.0f;
if (!unit->job.hunt_target && (!gamemode || *gamemode == game_mode::DWARF))
{
if (!unit->flags1.bits.marauder &&
casteFlagSet(unit->race, unit->caste, caste_raw_flags::MEANDERER) &&
!(unit->relations.following && isCitizen(unit)) &&
linear_index(unit->inventory, &df::unit_inventory_item::mode,
df::unit_inventory_item::Hauled) < 0)
{
coeff *= 4.0f;
}
if (unit->relations.group_leader_id < 0 &&
unit->flags1.bits.active_invader &&
!unit->job.current_job && !unit->flags3.bits.no_meandering &&
unit->profession != profession::THIEF && unit->profession != profession::MASTER_THIEF &&
!entityRawFlagSet(unit->civ_id, entity_raw_flags::ITEM_THIEF))
{
coeff *= 3.0f;
}
}
if (unit->flags3.bits.floundering)
{
coeff *= 3.0f;
}
return coeff;
}
static bool noble_pos_compare(const Units::NoblePosition &a, const Units::NoblePosition &b) static bool noble_pos_compare(const Units::NoblePosition &a, const Units::NoblePosition &b)
{ {
if (a.position->precedence < b.position->precedence) if (a.position->precedence < b.position->precedence)

@ -1206,6 +1206,7 @@ struct UnitPath {
{ {
float time = unit->counters.job_counter+0.5f; float time = unit->counters.job_counter+0.5f;
float speed = Units::computeMovementSpeed(unit)/100.0f; float speed = Units::computeMovementSpeed(unit)/100.0f;
float slowdown = Units::computeSlowdownFactor(unit);
if (unit->counters.unconscious > 0) if (unit->counters.unconscious > 0)
time += unit->counters.unconscious; time += unit->counters.unconscious;
@ -1217,9 +1218,14 @@ struct UnitPath {
continue; continue;
float delay = speed; float delay = speed;
// Diagonal movement
if (new_pos.x != pos.x && new_pos.y != pos.y) if (new_pos.x != pos.x && new_pos.y != pos.y)
delay *= 362.0/256.0; delay *= 362.0/256.0;
// Meandering slowdown
delay += (slowdown - 1) * speed;
path[time] = pos; path[time] = pos;
pos = new_pos; pos = new_pos;
time += delay + 1; time += delay + 1;