Implement skill-based miss probability in siege engine.

develop
Alexander Gavrilov 2012-09-14 20:57:03 +04:00
parent 811c096c0e
commit 000e3baf27
1 changed files with 72 additions and 11 deletions

@ -1286,6 +1286,12 @@ static int proposeUnitHits(lua_State *L)
* Projectile hook * 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 { struct projectile_hook : df::proj_itemst {
typedef df::proj_itemst interpose_base; typedef df::proj_itemst interpose_base;
@ -1293,6 +1299,9 @@ struct projectile_hook : df::proj_itemst {
{ {
target_pos = path.target; target_pos = path.target;
// Debug
Maps::getTileOccupancy(path.goal)->bits.arrow_color = COLOR_LIGHTMAGENTA;
PathMetrics raytrace(path); PathMetrics raytrace(path);
// Materialize map blocks, or the projectile will crash into them // 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); 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 target, last_passable;
df::coord tbase = engine->target.first; df::coord tbase = engine->target.first;
@ -1343,7 +1398,7 @@ struct projectile_hook : df::proj_itemst {
if (raytrace.hits() && engine->isInRange(raytrace.goal_step)) if (raytrace.hits() && engine->isInRange(raytrace.goal_step))
{ {
aimAtPoint(engine, path); aimAtPoint(engine, skill, path);
return; return;
} }
} }
@ -1351,7 +1406,7 @@ struct projectile_hook : df::proj_itemst {
if (!last_passable.isValid()) if (!last_passable.isValid())
last_passable = target; last_passable = target;
aimAtPoint(engine, ProjectilePath(engine->center, last_passable)); aimAtPoint(engine, skill, ProjectilePath(engine->center, last_passable));
} }
static int safeAimProjectile(lua_State *L) static int safeAimProjectile(lua_State *L)
@ -1373,9 +1428,9 @@ struct projectile_hook : df::proj_itemst {
lua_call(L, 5, 1); lua_call(L, 5, 1);
if (lua_isnil(L, -1)) if (lua_isnil(L, -1))
proj->aimAtArea(engine); proj->aimAtArea(engine, skill);
else else
proj->aimAtPoint(engine, decode_path(L, -1, engine->center)); proj->aimAtPoint(engine, skill, decode_path(L, -1, engine->center));
return 0; return 0;
} }
@ -1396,13 +1451,19 @@ struct projectile_hook : df::proj_itemst {
int skill = getOperatorSkill(engine->bld, true); int skill = getOperatorSkill(engine->bld, true);
lua_pushcfunction(L, safeAimProjectile); // Dabbling can't aim
lua_pushlightuserdata(L, this); if (skill < skill_rating::Novice)
lua_pushlightuserdata(L, engine); aimAtArea(engine, skill);
lua_pushinteger(L, 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)) if (!Lua::Core::SafeCall(out, 3, 0))
aimAtArea(engine); aimAtArea(engine, skill);
}
switch (item->getType()) switch (item->getType())
{ {