-
Notifications
You must be signed in to change notification settings - Fork 4.2k
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
Conversation
…ngs loading, trajectory buffer and cursor position initialization
change player's last target only when necessary
In non-spell version of target_ui, cursor was drawn using a custom implementation of draw_cursor. On CURSES it looked great, yes, but didn't work at all for TILES build.
This should fix parts of the UI jumping up and down when moving aim point or overwriting aim bars (when aiming using wielded guns) for 'compact' layout
It had to wait until event loop has been refactored
made 'fire' not work if there are no turrets in range
Fixes bug when view snaps back to the player if they have temporarily toggled snap-to-target on, moved aim point away, started aiming and ran out of moves
pc.recoil is tied to pc.last_target, so repeatedly firing from monster list by setting pc.last_target will bypass the penalty for swinging the gun around, allowing 180 no-scope
Resolves the problem of text overlapping on small sizes and shouldn't confuse new players since '[?] show help' is always there now
That should be it. I've used the merge as an opportunity to polish out a few parts - namely, the list of controls (see updated |
Is it intentional that if you kill a target, the next time you press |
…en entering the UI
It was more of a side-effect of the aim point preservation. I was conflicted should I do something about it (due to how it changes from the old behavior) or leave it as is (due to how it simulates player's aim point). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks! For future reference I'd appreciate it if you could keep PRs under 1000 lines or so, stuff this big is hard to review (though breaking up the commits like this helps a lot).
Yeah, sorry about that. I just couldn't leave it halfway... Thank you for your time! |
|
||
const auto lt_ptr = pc.last_target.lock(); | ||
if( npc *const guy = dynamic_cast<npc *>( lt_ptr.get() ) ) { | ||
if( casting.damage() > 0 ) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This condition being removed means that NPCs can be made angry when hit by healing spells.
// TODO: get rid of this. Or combine it with effect_hit_by_player | ||
guy->hit_by_player = true; // used for morale penalty | ||
case ExitCode::Fire: { | ||
on_target_accepted( pc, true ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This true should be some other condition to prevent that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, this true was supposed to be that removed condition :/
Summary
SUMMARY: Infrastructure "Refactored aiming UI and its target selection"
Purpose of change
target_handler::target_ui
is a very old and very complex function. It accepts 8 arguments, some of them can benullptr
, some of them it can deduce, and some of them it doesn't really need.This single function handles 5 cases of target selection:
ACT_AIM
activity)And allows to do many interesting things:
It also draws/prints:
All of that the function handles as a 588-line monolith of interconnected C++. It also handles window creation and input context, operates on
ACT_AIM
, modifies player state variables in many places (and sometimes doesn't restore them back), uses 3 closures and contains some complex aim thresholds I don't really understand.It also has a little sister called
target_ui(...); // magic mod
(350 LoC) which is basically a copy-pasted version, but for aiming spells. It contains some custom drawing code, but is missing some patches people applied to the normal version (notably the window expanding to the whole sidebar, changing map zoom and edge-scrolling).Furthermore,
target_ui()
has a number of visual/usability/inconsistency bugs:Describe the solution
Considering the huge number of arguments and long-living variables, I've decided it would be best to make this function into a class. This would make it easy to split the code into small segments without passing around long lists of arguments.
To avoid potential misuse, header bloat and boilerplate, I've put class declaration into
ranged.cpp
- this way, the class can only be used from the outside world by includingranged.h
and calling one of the 6 providedmode_xxx
functions. Each function takes bare minimum arguments necessary for the given mode, derives what it needs and assembles an instance of the class.The class itself has a single public method
run()
. It handles setup, event loop, and exit. The code inside the event loop has been untangled with the focus on modifyingplayer &pc
and member variables only when necessary (e.g. aim point validation, check for which turrets are in range, trajectory calculation - all of these now happen when aim point moves, not on every input). The drawing code has been separated into small self-contained methods - "panels" - with each panel guaranteed to occupy a constant number of lines. I've had to increase window height by 1 to help with text overlapping, though.I tried, as much as I could, to minimize visual changes and completely avoid big scary aim threshold calculations. But I had to refactor target selection (since it was there since before you could aim at empty tiles), and that produced some noticeable changes:
The new "change state only on user input" system allowed to implement some checks in a centralized manner:
And these checks made it possible to cleanly implement (or refactor) dynamic activation/deactivation of UI controls (see screenshots).
Separating window creation / input context / drawing, I believe, should help migrate it to
ui_adaptor
(no idea how it's done, didn't even try).Describe alternatives you've considered
Gaze upon
ranged.cpp
and despair.Declaring the class in
ranged.h
, but decided against it due to drawbacks mentioned earlier.Making 6 child classes (1 for each mode), but I don't like inheritance, and many modes differ only slightly. That would cause either a billion little methods or a bunch of copy-pasted & customized big ones.
Testing
I've tested each commit separately, and (with a few fixed cases), none of them seemed to break what they had changed.
The final result has been tested a bit using both TILES and CURSES, with "force redraw" and "3D FoV" turned on and off for all 6 modes. Things seem to be working, and none of the listed bugs have been observed.
The overlapping is somewhat better, with a bit bigger window and different drawing order, but still happens in some cases.Edit: The overlapping should be completely gone now. If there is not enough space to print all controls, the code now discards some entries based on how (imo) useless they are. There is a (somewhat) new "[?] show all controls" reminder at the bottom border as well, that should help new players or those who don't bother remembering shortcuts.
Also, I'm not familiar with printing / string formatting functions. It works for English, and looks correct.
Upd: The new algorithm for target selection might cause some weird behavior due to
player::last_target
andplayer::last_target_pos
not differentiating between UI modes.Additional context
What a wall of text. It needs a wall of pictures!
UI elements not jumping with/without target selected (normal layout)
UI elements not jumping with compact layout
List of controls gets shorter when extremely short on space
UI elements not jumping with narrow layout from #37715
Trying to use an empty gunmod
Switching from a long-ranged gunmod to a short-range firing mode
No turrets in range, can't fire