Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor aiming UI and its target selection / aim preservation #39785

Merged
merged 48 commits into from
May 3, 2020
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
48 commits
Select commit Hold shift + click to select a range
dd72c80
Use separate functions for modes & derive relevant info from arguments
olanti-p Apr 17, 2020
d8bfb43
Pass arguments as class members
olanti-p Apr 17, 2020
949a0f5
Remove duplicate code for window creation, input context setup, setti…
olanti-p Apr 17, 2020
6a0b030
Deduplicate checks fired when npc/monster has been selected as target
olanti-p Apr 17, 2020
3529ad7
Consolidate movement of aim point and center of view
olanti-p Apr 18, 2020
7965e6d
Cache critter under cursor; deduplicate 'set_as_target';
olanti-p Apr 18, 2020
5764f04
Deduplicate and refine 'confirm_non_enemy_target'
olanti-p Apr 18, 2020
e5e1475
Deduplicate and refine target cycling
olanti-p Apr 18, 2020
74cbe45
Extract some variables used by FIRE and SPELL modes
olanti-p Apr 18, 2020
64e9345
Refactor how penalty from moving aim point applies to current aim
olanti-p Apr 18, 2020
b677379
Deduplicate event loop
olanti-p Apr 19, 2020
1625c61
Deduplicate terrain drawing; fix cursor-related visual bug.
olanti-p Apr 19, 2020
fc74251
Refactor drawing of window base and list of controls
olanti-p Apr 19, 2020
304a542
Break up and reorganize rendering of panels inside aiming window
olanti-p Apr 19, 2020
6516d41
Re-implement reloading guns from aiming UI
olanti-p Apr 20, 2020
7a0d7fb
Handle empty gun modes and gun modes with different range
olanti-p Apr 20, 2020
b67a646
Some minor improvements & cleanup
olanti-p Apr 20, 2020
6a0e7b7
Refactored display of vehicle turrets in range;
olanti-p Apr 20, 2020
69c2ec9
Keep 'snap-to-target' state across turns
olanti-p Apr 20, 2020
e5dee87
Refactor target selection; save aim when killing target
olanti-p Apr 20, 2020
7bb5020
Remove old comments
olanti-p Apr 20, 2020
46f2157
Extract window creation and input context setup into function
olanti-p Apr 20, 2020
eca972b
Replace enum TARGET_MODE_* with enum class TargetMode
olanti-p Apr 20, 2020
f394840
Show info about creatures only if player can see them
olanti-p Apr 20, 2020
117918c
Merge branch 'master' into target_ui-as-class
olanti-p Apr 20, 2020
dc93ba3
Update list of targets when range changes
olanti-p Apr 21, 2020
82342c3
Prevent an exploit when firing from monster list
olanti-p Apr 21, 2020
5907ca0
Remove debug output
olanti-p Apr 21, 2020
ca0ea7c
Disable switching aim mode when you can't aim/shoot
olanti-p Apr 21, 2020
80097f3
For compact version, draw over bottom border
olanti-p Apr 21, 2020
a6d5eb2
Invalidate aim point when moving
olanti-p Apr 21, 2020
0a61cb2
Fix player's sprite disappearing when changing Z levels
olanti-p Apr 21, 2020
3e8d092
Appease clang-tidy
olanti-p Apr 21, 2020
b97c960
Merge branch 'master' into target_ui-as-class
olanti-p Apr 21, 2020
1bd24b0
Fix incorrect usage of ui_adaptor::disable_uis_below
olanti-p Apr 22, 2020
9acbb8b
Update src/ranged.cpp
olanti-p Apr 22, 2020
53a4cf4
When extremely short on space, collapse blank lines reserved for target.
olanti-p Apr 22, 2020
661a841
Merge commit 'd1c39eb0d81c202e7a7b69d57988d2c2d9242fa5' into target_u…
olanti-p Apr 30, 2020
1197d21
Migrate '[?] show help' from master
olanti-p Apr 30, 2020
584f058
Dynamically shrink list of controls
olanti-p May 1, 2020
7a6b3d7
Migrate the rest of the changes from master
olanti-p May 1, 2020
327846c
Merge branch 'master' into target_ui-as-class
olanti-p May 1, 2020
7ec443b
Some positioning-related fixes
olanti-p May 1, 2020
d452cac
Remove a duplicate check
olanti-p May 1, 2020
dc64250
Better comments
olanti-p May 1, 2020
5ec7c37
Don't re-confirm attack when aim-and-fire takes multiple turns
olanti-p May 1, 2020
a3073c6
Fix regression related to aim point not snapping to nearest target wh…
olanti-p May 1, 2020
42a145d
Appease clang-tidy
olanti-p May 1, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Some minor improvements & cleanup
  • Loading branch information
olanti-p committed Apr 20, 2020
commit b67a64692ce5f27dd90e7de323c999ad516370cf
2 changes: 1 addition & 1 deletion src/activity_handlers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4780,7 +4780,7 @@ void activity_handlers::spellcasting_finish( player_activity *act, player *p )
if( spell_being_cast.range() > 0 && !spell_being_cast.is_valid_target( target_none ) &&
!spell_being_cast.has_flag( RANDOM_TARGET ) ) {
do {
std::vector<tripoint> trajectory = target_handler::mode_spell( *p, &spell_being_cast, no_fail,
std::vector<tripoint> trajectory = target_handler::mode_spell( *p, spell_being_cast, no_fail,
no_mana );
if( !trajectory.empty() ) {
target = trajectory.back();
Expand Down
6 changes: 3 additions & 3 deletions src/avatar_action.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -901,7 +901,7 @@ void avatar_action::aim_do_turn( avatar &you, map &m )
g->temp_exit_fullscreen();
m.draw( g->w_terrain, you.pos() );
bool reload_requested;
target_handler::trajectory trajectory = target_handler::mode_fire( you, weapon, reload_requested );
target_handler::trajectory trajectory = target_handler::mode_fire( you, *weapon, reload_requested );

//may be changed in target_ui
gun = weapon->gun_current_mode();
Expand Down Expand Up @@ -983,7 +983,7 @@ void avatar_action::fire_turret_manual( avatar &you, map &m, turret_data &turret

g->temp_exit_fullscreen();
g->m.draw( g->w_terrain, you.pos() );
target_handler::trajectory trajectory = target_handler::mode_turret_manual( you, &turret );
target_handler::trajectory trajectory = target_handler::mode_turret_manual( you, turret );

if( !trajectory.empty() ) {
// Recenter our view
Expand Down Expand Up @@ -1177,7 +1177,7 @@ void avatar_action::plthrow( avatar &you, item_location loc,
g->temp_exit_fullscreen();
g->m.draw( g->w_terrain, you.pos() );

target_handler::trajectory trajectory = target_handler::mode_throw( you, &you.weapon,
target_handler::trajectory trajectory = target_handler::mode_throw( you, you.weapon,
blind_throw_from_pos.has_value() );

// If we previously shifted our position, put ourselves back now that we've picked our target.
Expand Down
2 changes: 1 addition & 1 deletion src/handle_action.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1289,7 +1289,7 @@ static void reach_attack( player &u )
g->temp_exit_fullscreen();
g->m.draw( g->w_terrain, u.pos() );

target_handler::trajectory traj = target_handler::mode_reach( u, &u.weapon );
target_handler::trajectory traj = target_handler::mode_reach( u, u.weapon );

if( !traj.empty() ) {
u.reach_attack( traj.back() );
Expand Down
137 changes: 64 additions & 73 deletions src/ranged.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,8 @@ enum target_mode : int {
class target_ui
{
public:
/* None of the public members (except ammo and range) should be modified during execution */

// Interface mode
target_mode mode = TARGET_MODE_FIRE;
// Weapon being fired/thrown
Expand Down Expand Up @@ -143,7 +145,9 @@ class target_ui
Timeout,
Reload
};

// Initialize UI and run the event loop.
// Uses public members to determine UI contents
// If exit_code != nullptr, exit code will be written into provided address
target_handler::trajectory run( player &pc, ExitCode *exit_code = nullptr );

Expand All @@ -158,8 +162,8 @@ class target_ui
// Ui status (affects which UI controls are temporarily disabled)
Status status;

// Current trajectory (TODO: better name)
std::vector<tripoint> ret;
// Current trajectory
std::vector<tripoint> traj;
// Aiming source (player's position)
tripoint src;
// Aiming destination (cursor position)
Expand All @@ -179,18 +183,12 @@ class target_ui

// Compact layout - slightly smaller then normal
bool compact;
// Tiny layout - smallest possible
// Tiny layout - uses whole sidebar
bool tiny;
// Window width
int height;
// Window height
int width;
// Window
catacurses::window w_target;
// Input context
input_context ctxt;
// Number of free instruction lines
int num_instruction_lines;

/* These members are relevant for TARGET_MODE_FIRE */
// Weapon sight dispersion
Expand All @@ -206,16 +204,9 @@ class target_ui
// relative to the current one.
double predicted_recoil;

/* These members are relevant for TARGET_MODE_SPELL */
// For AOE spells, list of tiles affected by the spell
// relevant for TARGET_MODE_SPELL
std::set<tripoint> spell_aoe;
// Spell casting effect
std::string spell_fx;

// Returns new cursor position or current cursor position
// based on user input
// TODO: betters docs/name?
tripoint get_desired_cursor_pos( const std::string &action );

// Handle input related to cursor movement.
// Returns 'true' if action was recognized and processed.
Expand Down Expand Up @@ -303,13 +294,13 @@ class target_ui
void on_target_accepted( player &pc, bool harmful );
};

target_handler::trajectory target_handler::mode_fire( player &pc, item *weapon,
target_handler::trajectory target_handler::mode_fire( player &pc, item &weapon,
bool &reload_requested )
{
target_ui ui = target_ui();
ui.mode = TARGET_MODE_FIRE;
ui.relevant = weapon;
gun_mode gun = weapon->gun_current_mode();
ui.relevant = &weapon;
gun_mode gun = weapon.gun_current_mode();
ui.range = gun.target->gun_range( &pc );
ui.ammo = gun->ammo_data();

Expand All @@ -319,49 +310,49 @@ target_handler::trajectory target_handler::mode_fire( player &pc, item *weapon,
return result;
}

target_handler::trajectory target_handler::mode_throw( player &pc, item *relevant,
target_handler::trajectory target_handler::mode_throw( player &pc, item &relevant,
bool blind_throwing )
{
target_ui ui = target_ui();
ui.mode = blind_throwing ? TARGET_MODE_THROW_BLIND : TARGET_MODE_THROW;
ui.relevant = relevant;
ui.range = pc.throw_range( *relevant );
ui.relevant = &relevant;
ui.range = pc.throw_range( relevant );

return ui.run( pc );
}

target_handler::trajectory target_handler::mode_reach( player &pc, item *weapon )
target_handler::trajectory target_handler::mode_reach( player &pc, item &weapon )
{
target_ui ui = target_ui();
ui.mode = TARGET_MODE_REACH;
ui.relevant = weapon;
ui.range = weapon->current_reach_range( pc );
ui.relevant = &weapon;
ui.range = weapon.current_reach_range( pc );

return ui.run( pc );
}

target_handler::trajectory target_handler::mode_turret_manual( player &pc, turret_data *turret )
target_handler::trajectory target_handler::mode_turret_manual( player &pc, turret_data &turret )
{
target_ui ui = target_ui();
ui.mode = TARGET_MODE_TURRET_MANUAL;
ui.turret = turret;
ui.relevant = &*turret->base();
ui.range = turret->range();
ui.ammo = turret->ammo_data();
ui.turret = &turret;
ui.relevant = &*turret.base();
ui.range = turret.range();
ui.ammo = turret.ammo_data();

return ui.run( pc );
}

target_handler::trajectory target_handler::mode_turrets( player &pc, vehicle *veh,
const std::vector<vehicle_part *> *turrets )
target_handler::trajectory target_handler::mode_turrets( player &pc, vehicle &veh,
const std::vector<vehicle_part *> &turrets )
{
// Find radius of a circle centered at u encompassing all points turrets can aim at
// FIXME: this calculation is fine for square distances, but results in an underestimation
// when used with real circles
int range_total = 0;
for( vehicle_part *t : *turrets ) {
int range = veh->turret_query( *t ).range();
tripoint pos = veh->global_part_pos3( *t );
for( vehicle_part *t : turrets ) {
int range = veh.turret_query( *t ).range();
tripoint pos = veh.global_part_pos3( *t );

int res = 0;
res = std::max( res, rl_dist( g->u.pos(), pos + point( range, 0 ) ) );
Expand All @@ -373,20 +364,20 @@ target_handler::trajectory target_handler::mode_turrets( player &pc, vehicle *ve

target_ui ui = target_ui();
ui.mode = TARGET_MODE_TURRET;
ui.veh = veh;
ui.vturrets = turrets;
ui.veh = &veh;
ui.vturrets = &turrets;
ui.range = range_total;

return ui.run( pc );
}

target_handler::trajectory target_handler::mode_spell( player &pc, spell *casting, bool no_fail,
target_handler::trajectory target_handler::mode_spell( player &pc, spell &casting, bool no_fail,
bool no_mana )
{
target_ui ui = target_ui();
ui.mode = TARGET_MODE_SPELL;
ui.casting = casting;
ui.range = casting->range();
ui.casting = &casting;
ui.range = casting.range();
ui.no_fail = no_fail;
ui.no_mana = no_mana;

Expand All @@ -396,7 +387,7 @@ target_handler::trajectory target_handler::mode_spell( player &pc, spell *castin
target_handler::trajectory target_handler::mode_spell( player &pc, spell_id sp, bool no_fail,
bool no_mana )
{
return mode_spell( pc, &g->u.magic.get_spell( sp ), no_fail, no_mana );
return mode_spell( pc, g->u.magic.get_spell( sp ), no_fail, no_mana );
}

bool targeting_data::is_valid() const
Expand Down Expand Up @@ -1870,12 +1861,9 @@ double player::gun_value( const item &weap, int ammo ) const

target_handler::trajectory target_ui::run( player &pc, ExitCode *exit_code )
{
if( mode == TARGET_MODE_SPELL ) {
if( !no_mana && !casting->can_cast( pc ) ) {
pc.add_msg_if_player( m_bad, _( "You don't have enough %s to cast this spell" ),
casting->energy_string() );
}
spell_fx = casting->effect();
if( mode == TARGET_MODE_SPELL && !no_mana && !casting->can_cast( pc ) ) {
pc.add_msg_if_player( m_bad, _( "You don't have enough %s to cast this spell" ),
casting->energy_string() );
}

// Load settings
Expand All @@ -1886,7 +1874,8 @@ target_handler::trajectory target_ui::run( player &pc, ExitCode *exit_code )
compact = TERMY < 41;
tiny = TERMY < 32;
int top = 0;
width = 55;
int width = 55;
int height;
if( tiny ) {
// If we're extremely short on space, use the whole sidebar.
height = TERMY;
Expand Down Expand Up @@ -1972,7 +1961,7 @@ target_handler::trajectory target_ui::run( player &pc, ExitCode *exit_code )
}

ExitCode loop_exit_code;
std::string timed_out_activity;
std::string timed_out_action;

bool skip_redraw = false;
const tripoint saved_view_offset = pc.view_offset;
Expand Down Expand Up @@ -2038,7 +2027,7 @@ target_handler::trajectory target_ui::run( player &pc, ExitCode *exit_code )
// Aiming can be stopped / aborted at any time.

if( !action_aim( pc ) ) {
timed_out_activity = "AIM";
timed_out_action = "AIM";
loop_exit_code = ExitCode::Timeout;
break;
}
Expand All @@ -2056,7 +2045,7 @@ target_handler::trajectory target_ui::run( player &pc, ExitCode *exit_code )
if( action_aim_and_shoot( pc, action ) ) {
loop_exit_code = ExitCode::Fire;
} else {
timed_out_activity = action;
timed_out_action = action;
loop_exit_code = ExitCode::Timeout;
}
break;
Expand All @@ -2067,7 +2056,7 @@ target_handler::trajectory target_ui::run( player &pc, ExitCode *exit_code )

switch( loop_exit_code ) {
case ExitCode::Abort: {
ret.clear();
traj.clear();
break;
}
case ExitCode::Fire: {
Expand All @@ -2079,22 +2068,22 @@ target_handler::trajectory target_ui::run( player &pc, ExitCode *exit_code )
// automatically re-enter the aiming UI on the next turn.
// pc.activity.str_values[0] remembers which action, AIM or *_SHOT,
// we didn't have the time to finish.
ret.clear();
traj.clear();
pc.assign_activity( ACT_AIM, 0, 0 );
pc.activity.str_values.push_back( timed_out_activity );
pc.activity.str_values.push_back( timed_out_action );
break;
}
case ExitCode::Reload: {
// Calling function will handle reloading for us
ret.clear();
traj.clear();
break;
}
}

if( exit_code ) {
*exit_code = loop_exit_code;
}
return ret;
return traj;
}

bool target_ui::handle_cursor_movement( player &pc, const std::string &action, bool &skip_redraw )
Expand Down Expand Up @@ -2198,10 +2187,10 @@ bool target_ui::set_cursor_pos( player &pc, const tripoint &new_pos )
} else if( new_pos == valid_pos ) {
// We can reuse new_traj
dst = valid_pos;
ret = new_traj;
traj = new_traj;
} else {
dst = valid_pos;
ret = g->m.find_clear_path( src, dst );
traj = g->m.find_clear_path( src, dst );
}

if( snap_to_target ) {
Expand Down Expand Up @@ -2233,21 +2222,20 @@ bool target_ui::set_cursor_pos( player &pc, const tripoint &new_pos )
dst_critter = nullptr;
}

// Update tiles affected by AOE spells
if( spell_fx == "target_attack" || spell_fx == "projectile_attack" ||
spell_fx == "ter_transform" ) {
spell_aoe = spell_effect::spell_effect_blast( *casting, src, dst, casting->aoe(), true );
} else if( spell_fx == "cone_attack" ) {
spell_aoe = spell_effect::spell_effect_cone( *casting, src, dst, casting->aoe(), true );
} else if( spell_fx == "line_attack" ) {
spell_aoe = spell_effect::spell_effect_line( *casting, src, dst, casting->aoe(), true );
} else {
spell_aoe.clear();
}

// Update predicted 'recoil'
// Update mode-specific stuff
if( mode == TARGET_MODE_FIRE ) {
recalc_aim_turning_penalty( pc );
} else if( mode == TARGET_MODE_SPELL ) {
const std::string fx = casting->effect();
if( fx == "target_attack" || fx == "projectile_attack" || fx == "ter_transform" ) {
spell_aoe = spell_effect::spell_effect_blast( *casting, src, dst, casting->aoe(), true );
} else if( fx == "cone_attack" ) {
spell_aoe = spell_effect::spell_effect_cone( *casting, src, dst, casting->aoe(), true );
} else if( fx == "line_attack" ) {
spell_aoe = spell_effect::spell_effect_line( *casting, src, dst, casting->aoe(), true );
} else {
spell_aoe.clear();
}
}

// Update UI controls & colors
Expand Down Expand Up @@ -2504,7 +2492,7 @@ void target_ui::draw_terrain( player &pc )
// Draw trajectory
if( dst != src ) {
// But only points on this Z-level
std::vector<tripoint> this_z = ret;
std::vector<tripoint> this_z = traj;
this_z.erase( std::remove_if( this_z.begin(), this_z.end(),
[&center]( const tripoint & p ) {
return p.z != center.z;
Expand Down Expand Up @@ -2540,6 +2528,8 @@ void target_ui::draw_terrain( player &pc )
void target_ui::draw_ui_window( player &pc )
{
// Clear target window and make it non-transparent.
int width = getmaxx( w_target );
int height = getmaxy( w_target );
for( int y = 0; y < height; y++ ) {
for( int x = 0; x < width; x++ ) {
mvwputch( w_target, point( x, y ), c_white, ' ' );
Expand Down Expand Up @@ -2627,6 +2617,7 @@ int target_ui::draw_controls_list()

nc_color move_color = ( status != Status::OutOfAmmo ? c_white : c_light_gray );
nc_color fire_color = ( status == Status::Good ? c_white : c_light_gray );
int height = getmaxy( w_target );

// Since this list is of variable length and positioned
// at the bottom, we draw everything in reverse order
Expand Down
Loading