Fix a case where target lock is annoying

This commit is contained in:
2025-05-02 13:57:14 -05:00
parent c3dcd55dc7
commit cf5ce53721
5 changed files with 33 additions and 7 deletions

View File

@@ -42,7 +42,7 @@
<led name='snail' relative='pos pos-in' anchor='slow' top='0' left='15'>Quite Slow</led>
</group>
<text name='targeting-head' size='large' relative='pos-in pos' anchor='spd-head' top='30' left='0' width='182' height='17'>Targeting mode:</text>
<led name='target-lock' relative='pos-in pos' rel-anchor='prev' top='4' left='15'>Shift screen to show enemies in range</led>
<led name='target-lock' relative='pos-in pos' rel-anchor='prev' top='4' left='15'>Shift screen to show more enemies in range</led>
<text name="keyshift-head" relative='neg pos' rel-anchor='prev' top='8' left='3'>Directional keys:</text>
<group name='keyshift-options'>
<led name='target-adjacent' relative='pos pos-in' anchor='keyshift-head' top='0' left='15'>Select adjacent tiles</led>

View File

@@ -105,7 +105,10 @@ std::map<std::string,std::vector<std::string>> feature_flags = {
// Legacy behavior of pacifist spellcasting (used by some replays)
// lets the player select combat spells and click 'Cast' which will fail.
{"pacifist-spellcast-check", {"V2"}},
{"target-lock", {"V1"}},
// Target lock
// V1: Shift screen to show the maximum number of enemies in range
// V2: Like V1, but don't shift if it hides any enemies that are already visible
{"target-lock", {"V1", "V2"}},
// New in-game save file picker
{"file-picker-dialog", {"V1"}},
{"scenario-meta-format", {"V2"}},

View File

@@ -1054,18 +1054,23 @@ void handle_target_mode(eGameMode target_mode, int range, eSpell spell) {
location loc = univ.current_pc().combat_pos;
std::vector<location> enemy_locs_in_range;
std::vector<location> enemy_locs_already_seen;
for(short i = 0; i < univ.town.monst.size(); i++){
auto& monst = univ.town.monst[i];
if(monst.is_alive() && party_can_see_monst(i)) {
eAttitude att = monst.attitude;
if((att == eAttitude::HOSTILE_A || att == eAttitude::HOSTILE_B)
&& dist(loc, monst.cur_loc) <= range){
// Target lock V2: Don't move the screen if it hides an enemy the player can already see
if(has_feature_flag("target-lock", "V2") && is_on_screen(monst.cur_loc))
enemy_locs_already_seen.push_back(monst.cur_loc);
enemy_locs_in_range.push_back(monst.cur_loc);
}
}
}
if(!enemy_locs_in_range.empty()){
std::vector<location> dest_candidates = points_containing_most(enemy_locs_in_range);
std::vector<location> dest_candidates = points_containing_most(enemy_locs_in_range, enemy_locs_already_seen);
center = closest_point(dest_candidates, loc);
draw_terrain();
}

View File

@@ -354,6 +354,18 @@ location between_anchor_points(location anchor1, location anchor2, int padding){
}
std::vector<location> points_containing_most(std::vector<location> points, int padding) {
return points_containing_most(points, {}, padding);
}
static int points_can_see(location checking_point, std::vector<location> points_of_interest, int padded_radius) {
int can_see = 0;
for(location p : points_of_interest){
if(is_on_screen(p, checking_point, padded_radius)) ++can_see;
}
return can_see;
}
std::vector<location> points_containing_most(std::vector<location> points, std::vector<location> required_points, int padding) {
// Find the bounding box of the given points:
int min_x = std::numeric_limits<int>::max();
int min_y = min_x;
@@ -379,10 +391,12 @@ std::vector<location> points_containing_most(std::vector<location> points, int p
location checking_point;
for(checking_point.x = min_x; checking_point.x <= max_x; ++checking_point.x){
for(checking_point.y = min_y; checking_point.y <= max_y; ++checking_point.y){
int can_see = 0;
for(location p : points){
if(is_on_screen(p, checking_point, padded_radius)) ++can_see;
}
// Eliminate points that don't see every required point:
int required_can_see = points_can_see(checking_point, required_points, padded_radius);
if(required_can_see < required_points.size()) continue;
// Count how many desired points can be seen:
int can_see = points_can_see(checking_point, points, padded_radius);
points_seen_from.push_back(std::make_pair(checking_point, can_see));
}
}

View File

@@ -195,6 +195,10 @@ location between_anchor_points(location anchor1, location anchor2, int padding=1
// with the given amount of padding
std::vector<location> points_containing_most(std::vector<location> points, int padding=1);
// Get all view center points which contain the greatest possible number of the given points
// with the given amount of padding, as long as they still contain all of the given required points
std::vector<location> points_containing_most(std::vector<location> points, std::vector<location> required_points, int padding=1);
// Find which of the given points is closest to the given anchor point.
int closest_point_idx(std::vector<location> points, location anchor);
location closest_point(std::vector<location> points, location anchor);