summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlexander Gavrilov2012-09-14 20:57:03 +0400
committerAlexander Gavrilov2012-09-14 20:57:03 +0400
commit000e3baf27e3d811e673bca08e4381c1f2c632b7 (patch)
tree7f053ee8da4cc97cdb8cdd3f7042996c42d5c4c9
parent811c096c0ecdcde1d0d19be8e4996996bde27995 (diff)
downloaddfhack-000e3baf27e3d811e673bca08e4381c1f2c632b7.tar.gz
dfhack-000e3baf27e3d811e673bca08e4381c1f2c632b7.tar.bz2
dfhack-000e3baf27e3d811e673bca08e4381c1f2c632b7.tar.xz
Implement skill-based miss probability in siege engine.
-rw-r--r--plugins/devel/siege-engine.cpp83
1 files changed, 72 insertions, 11 deletions
diff --git a/plugins/devel/siege-engine.cpp b/plugins/devel/siege-engine.cpp
index d1e34ced..b8a2f087 100644
--- a/plugins/devel/siege-engine.cpp
+++ b/plugins/devel/siege-engine.cpp
@@ -1286,6 +1286,12 @@ static int proposeUnitHits(lua_State *L)
* Projectile hook
*/
+static const int offsets[8][2] = {
+ { -1, -1 }, { 0, -1 }, { 1, -1 },
+ { -1, 0 }, { 1, 0 },
+ { -1, 1 }, { 0, 1 }, { 1, 1 }
+};
+
struct projectile_hook : df::proj_itemst {
typedef df::proj_itemst interpose_base;
@@ -1293,6 +1299,9 @@ struct projectile_hook : df::proj_itemst {
{
target_pos = path.target;
+ // Debug
+ Maps::getTileOccupancy(path.goal)->bits.arrow_color = COLOR_LIGHTMAGENTA;
+
PathMetrics raytrace(path);
// Materialize map blocks, or the projectile will crash into them
@@ -1320,7 +1329,53 @@ struct projectile_hook : df::proj_itemst {
fall_threshold = std::min(fall_threshold, engine->fire_range.second);
}
- void aimAtArea(EngineInfo *engine)
+ void aimAtPoint(EngineInfo *engine, int skill, const ProjectilePath &path)
+ {
+ df::coord fail_target = path.goal;
+
+ orient_engine(engine->bld, path.goal);
+
+ // Debug
+ Maps::getTileOccupancy(path.goal)->bits.arrow_color = COLOR_LIGHTRED;
+
+ // Dabbling always hit in 7x7 area
+ if (skill < skill_rating::Novice)
+ {
+ fail_target.x += random_int(7)-3;
+ fail_target.y += random_int(7)-3;
+ aimAtPoint(engine, ProjectilePath(path.origin, fail_target));
+ return;
+ }
+
+ // Exact hit chance
+ float hit_chance = 1.04f - powf(0.8f, skill);
+
+ if (float(rand())/RAND_MAX < hit_chance)
+ {
+ aimAtPoint(engine, path);
+ return;
+ }
+
+ // Otherwise perturb
+ if (skill <= skill_rating::Proficient)
+ {
+ // 5x5
+ fail_target.x += random_int(5)-2;
+ fail_target.y += random_int(5)-2;
+ }
+ else
+ {
+ // 3x3
+ int idx = random_int(8);
+ fail_target.x += offsets[idx][0];
+ fail_target.y += offsets[idx][1];
+ }
+
+ ProjectilePath fail(path.origin, fail_target, path.fudge_delta, path.fudge_factor);
+ aimAtPoint(engine, fail);
+ }
+
+ void aimAtArea(EngineInfo *engine, int skill)
{
df::coord target, last_passable;
df::coord tbase = engine->target.first;
@@ -1343,7 +1398,7 @@ struct projectile_hook : df::proj_itemst {
if (raytrace.hits() && engine->isInRange(raytrace.goal_step))
{
- aimAtPoint(engine, path);
+ aimAtPoint(engine, skill, path);
return;
}
}
@@ -1351,7 +1406,7 @@ struct projectile_hook : df::proj_itemst {
if (!last_passable.isValid())
last_passable = target;
- aimAtPoint(engine, ProjectilePath(engine->center, last_passable));
+ aimAtPoint(engine, skill, ProjectilePath(engine->center, last_passable));
}
static int safeAimProjectile(lua_State *L)
@@ -1373,9 +1428,9 @@ struct projectile_hook : df::proj_itemst {
lua_call(L, 5, 1);
if (lua_isnil(L, -1))
- proj->aimAtArea(engine);
+ proj->aimAtArea(engine, skill);
else
- proj->aimAtPoint(engine, decode_path(L, -1, engine->center));
+ proj->aimAtPoint(engine, skill, decode_path(L, -1, engine->center));
return 0;
}
@@ -1396,13 +1451,19 @@ struct projectile_hook : df::proj_itemst {
int skill = getOperatorSkill(engine->bld, true);
- lua_pushcfunction(L, safeAimProjectile);
- lua_pushlightuserdata(L, this);
- lua_pushlightuserdata(L, engine);
- lua_pushinteger(L, skill);
+ // Dabbling can't aim
+ if (skill < skill_rating::Novice)
+ aimAtArea(engine, skill);
+ else
+ {
+ lua_pushcfunction(L, safeAimProjectile);
+ lua_pushlightuserdata(L, this);
+ lua_pushlightuserdata(L, engine);
+ lua_pushinteger(L, skill);
- if (!Lua::Core::SafeCall(out, 3, 0))
- aimAtArea(engine);
+ if (!Lua::Core::SafeCall(out, 3, 0))
+ aimAtArea(engine, skill);
+ }
switch (item->getType())
{