Skip to content

Commit

Permalink
Account for meandering movement when predicting unit path in siege en…
Browse files Browse the repository at this point in the history
…gine.

The movement is random, but there is an average slowdown coefficient.
  • Loading branch information
angavrilov committed Apr 15, 2014
1 parent 55cea36 commit fc98263
Show file tree
Hide file tree
Showing 6 changed files with 69 additions and 0 deletions.
4 changes: 4 additions & 0 deletions Lua API.html
Original file line number Diff line number Diff line change
Expand Up @@ -1326,6 +1326,10 @@ <h3><a class="toc-backref" href="#id22">Units module</a></h3>
<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>
</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>
<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>
Expand Down
5 changes: 5 additions & 0 deletions Lua API.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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.

* ``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)``

Returns a list of tables describing noble position assignments, or *nil*.
Expand Down
1 change: 1 addition & 0 deletions library/LuaApi.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1391,6 +1391,7 @@ static const LuaWrapper::FunctionReg dfhack_units_module[] = {
WRAPM(Units, getEffectiveSkill),
WRAPM(Units, getExperience),
WRAPM(Units, computeMovementSpeed),
WRAPM(Units, computeSlowdownFactor),
WRAPM(Units, getProfessionName),
WRAPM(Units, getCasteProfessionName),
WRAPM(Units, getProfessionColor),
Expand Down
1 change: 1 addition & 0 deletions library/include/modules/Units.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 computeMovementSpeed(df::unit *unit);
DFHACK_EXPORT float computeSlowdownFactor(df::unit *unit);

struct NoblePosition {
df::historical_entity *entity;
Expand Down
52 changes: 52 additions & 0 deletions library/modules/Units.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,8 @@ using namespace std;
#include "df/unit_soul.h"
#include "df/nemesis_record.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_info.h"
#include "df/entity_position.h"
Expand Down Expand Up @@ -1060,6 +1062,8 @@ int Units::computeMovementSpeed(df::unit *unit)
{
using namespace df::enums::physical_attribute_type;

CHECK_NULL_POINTER(unit);

/*
* Pure reverse-engineered computation of unit _slowness_,
* i.e. number of ticks to move * 100.
Expand Down Expand Up @@ -1264,6 +1268,54 @@ int Units::computeMovementSpeed(df::unit *unit)
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)
{
if (a.position->precedence < b.position->precedence)
Expand Down
6 changes: 6 additions & 0 deletions plugins/siege-engine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1206,6 +1206,7 @@ struct UnitPath {
{
float time = unit->counters.job_counter+0.5f;
float speed = Units::computeMovementSpeed(unit)/100.0f;
float slowdown = Units::computeSlowdownFactor(unit);

if (unit->counters.unconscious > 0)
time += unit->counters.unconscious;
Expand All @@ -1217,9 +1218,14 @@ struct UnitPath {
continue;

float delay = speed;

// Diagonal movement
if (new_pos.x != pos.x && new_pos.y != pos.y)
delay *= 362.0/256.0;

// Meandering slowdown
delay += (slowdown - 1) * speed;

path[time] = pos;
pos = new_pos;
time += delay + 1;
Expand Down

0 comments on commit fc98263

Please sign in to comment.