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

Characters automatically reload gas masks when filters run low #66913

Closed
wants to merge 5 commits into from

Conversation

ehughsbaird
Copy link
Contributor

Summary

Features "Characters automatically reload gasmasks when they run low"

Purpose of change

I recently visited a collapsed tower, and as I fought my way through the dungeon, I faced a consistent issue: my gas mask would run out, and I would not notice, becoming poisoned.

This was, needless to say, quite annoying. So, let's have the character manage the changing of filters, instead of the player.

Describe the solution

The solution is simple. Add a function to Character that will will take an item and look at it's remaining ammo. If the item is low, but not quite out, the function will warn every 8 turns about the item being low. When the item runs out, it will scan the player inventory and reload with appropriate items.

Then, this function simply needs to be called wherever the item consumes charges, and the player will automatically handle reloading.

A variety of behavior tweaks are available, but by default (and always, as there is no way to change them), a popup shown when the last suitable item has been reloaded (next reload will fail) and when a reload is attempted but fails.

Describe alternatives you've considered

I couldn't figure out another way to solve this problem short of only adding more messages when the gas mask is running low. I think this is preferable.

Testing

Several tests have been added to ensure this behavior works for both players and npcs.
For manual testing, equip a gas mask, grab some cartridges, and expose yourself to a lot of gas. (Going underground makes the gas dissipate slower).
The screenshots below show what this will be like to the player with the current settings

Default Settings

Start:
screenshot of player inventory. The player has 2 gas mask cartridges each with 0, 1, and 100 charges. The player is wearing an active gas mask with 10 charges.
Reload 1:
Screenshot of player's log. The message "Your ++ half face gas mask (active) is running low" is printed several times, 8 seconds apart, and at the end of the log, there are the messages "You notice your ++ half face gas mask (active) is running low and reload it" and "You have 1 remaining reloads for the ++ half face gas mask (active)"
Screenshot of the player's inventory again. The player now has 3 gas mask cartridges with 1 charge, 2 with 0, and 1 with 100. Their gas mask is still active, and now has 100 charges.
Reload 2:
Screenshot of popup message to player. The message says "Checking your pockets, you see this will be the last reload for your ++ half face gas mask (active)"
Screenshot of player's log. As before, the message that their gas mask is running low is printed several times, following by a message indicating they reloaded their mask. However, the message about remaining reloads is not printed.
Screenshot of the player's inventory. The player has 4 gas mask cartridges with 1 charge, and 2 with 0. Their gas mask is still active and has 100 charges.
Gas mask runs out:
Screenshot of popup message to player. The message says "You don't have anything to reload your ++ half face gas mask (active) with!"
Screenshot of the player's inventory. The player has 4 gas mask cartridges with 1 charge, and 2 with 0. Their gas mask is still active, but only has 1 charge.
Screenshot of the player's log. There are several messages about their gas mask running low, and a final message that it needs new filters.

The following sections show the three different reload methods. All start with this inventory:
Screenshot of the player's inventory. The player has gas mask cartridges with 0, 1, 47, 64, and 88 charges, as well as two with 100 charges. They are wearing an active gas mask with 94 charges.

Least First reload

Screenshot of the player's inventory. The player has gas mask cartridges with 0, 64, and 88 charges, as well as two each with 1 charge and 100 charges. They are wearing an active gas mask with 47 charges. This shows the gas mask has been reloaded with the cartridge that had the least charges (and was not empty).
Screenshot of the player's inventory. The player has gas mask cartridges with 0 and 88 charges, as well as two with 100 charges, and three with 1 charge. They are wearing an active gas mask with 64 charges. This shows the gas mask has been reloaded with the cartridge that had the least charges (and was not empty).

Most First reload

Screenshot of the player's inventory. The player has gas mask cartridges with 0, 47, 64, 88, and 100 charges, as well as two with 1 charge. They are wearing an active gas mask with 100 charges. This shows the gas mask has been reloaded with the cartridge that had the most charges.
Screenshot of the player's inventory. The player has gas mask cartridges with 0, 47, 64, and 88 charges, as well as three with 1 charge. They are wearing an active gas mask with 100 charges. This shows the gas mask has been reloaded with the cartridge that had the most charges.
Screenshot of the player's inventory. The player has gas mask cartridges with 0, 47, and 64 charges, as well as four with 1 charge. They are wearing an active gas mask with 88 charges. This shows the gas mask has been reloaded with the cartridge that had the most charges.

Player choose reload

Screenshot of a menu asking the player what they want to reload their gas mask with. There are five options, four showing cartridges with 100, 88, 64, and 47 charges, and a fifth saying "Don't reload". This shows the cartridges that the player has, but has not duplicated the entry for the two cartridges with 100 charges.
Screenshot of a menu asking the player what they want to reload their gas mask with. There are five options, four showing cartridges with 100, 88, 64, and 47 charges, and a fifth saying "Don't reload". This shows the cartridges that the player has, having consumed one of the 100 charge cartridges.
Screenshot of a menu asking the player what they want to reload their gas mask with. There are four options, three showing cartridges with 88, 64, and 47 charges, and a fourth saying "Don't reload". This shows the cartridges that the player has, having consumed both the 100 charge cartridges.
Screenshot of a menu asking the player what they want to reload their gas mask with. There are three options, two showing cartridges with 88 and 64 charges, and a third saying "Don't reload". This shows the cartridges that the player has, having consumed both the 100 charge cartridges and the 47 charge cartridge.

Additional context

I'd obviously like to let the player choose between these three options, as well as expand this to more things, but I figured I should get this out there first.

@github-actions github-actions bot added <Enhancement / Feature> New features, or enhancements on existing Code: Tests Measurement, self-control, statistics, balancing. [C++] Changes (can be) made in C++. Previously named `Code` astyled astyled PR, label is assigned by github actions json-styled JSON lint passed, label assigned by github actions labels Jul 15, 2023
Copy link
Contributor

@Qrox Qrox left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like the idea of automating character actions but we should also make it as non-intrusive as possible, so here are some suggestions.

src/character_management.cpp Outdated Show resolved Hide resolved
src/character_management.cpp Outdated Show resolved Hide resolved
// No valid targets? Tell the player, and don't try to autoreload for a bit
if( mags.empty() ) {
if( !is_npc && info.warn_no_ammo ) {
popup( "You don't have anything to reload your %s with!", it_name );
Copy link
Contributor

@Qrox Qrox Jul 15, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be a message to be consistent with other warnings.

Also, it seems this message and the query below will repeat itself every minute after the player's only magazine is nearly depleted or they choose not to reload, which I think is not good user expereience. I suggest to only warn once when no magazine is found, and add an option to never ask again to RELOAD_CHOICE until the next auto-reload opportunity.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would rather this be a popup to ensure I know I need to get out before my gas mask goes, but I agree it's not the best experience.

add_msg_if_player( m_good, _( "You notice your %s is running low and reload it." ), it_name );

// TODO: NPCs complain about running out of reloads
if( mags.size() == 1 && info.warn_on_last && !is_npc ) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How does this handle reloading with non-magazine items (such as bullets) which may only be partially consumed?

@@ -4270,6 +4271,7 @@ std::optional<int> iuse::gasmask( Character *p, item *it, bool t, const tripoint
_( "<npcname> needs new gas mask filters!" )
, it->tname() );
}
p->try_autoreload( *it, char_autoreload::params() );
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it makes more sense to reload with the fullest magazine so it lasts longer.

Also, how does this solve the problem that the player may not want to reload at a specific moment? For example, if the item charge happens to run out when the player is facing a much more serious threat, automatically reloading may cause the player to become more seriously harmed.

How does this handle the case where the player wants to specifically use a magazine with low charges? Some items may accept different types of ammo so the player may want to specifically use one with some special property that is important to their task.

An option in the auto-features option group to override the default reload types would be nice too (although adding more options may not be desired due to the concern about option bloat)

}

// Try to reload and see how it goes
bool status = it.reload( *this, mags[picked], 1 );
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this reduce the move points of the reloader? Also, some reloading actions takes a long time to complete so it might make sense to make it an activity.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, and it can be a significant number of moves. This will take a fair bit of work to address (with the above concerns).

// The gas mask
static const itype_id itype_mask_gas( "mask_gas" );
// Flag identifying cartridges
static const flag_id json_flag_GASFILTER_MED( "GASFILTER_MED" );
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You may want to add test-specific items to avoid changes to the stats of in-game items causing test regressions.

continue;
}
// Only mags with sufficient ammo to avoid immediate reload, too!
if( loc->ammo_remaining() < 2 ) {
Copy link
Contributor

@Qrox Qrox Jul 15, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Might also make sense to auto-reload with the fullest magazine if the current magazine is depleted but all the remaining magazines have less than this many remaining charges.

@github-actions github-actions bot added the BasicBuildPassed This PR builds correctly, label assigned by github actions label Jul 15, 2023
@github-actions
Copy link
Contributor

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions. Please do not bump or comment on this issue unless you are actively working on it. Stale issues, and stale issues that are closed are still considered.

@github-actions github-actions bot added the stale Closed for lack of activity, but still valid. label Aug 14, 2023
@I-am-Erk
Copy link
Member

I'd really like to merge this, are you still around to check out qrox' suggestions @ehughsbaird ?

@github-actions github-actions bot removed the stale Closed for lack of activity, but still valid. label Aug 20, 2023
@ehughsbaird
Copy link
Contributor Author

Yes, but I would not expect significant movement very soon.

Allows storing a time value on an item without converting to turns and
then converting back.
I recently visited a collapsed tower, and as I fought my way through the
dungeon, I faced a consistent issue: my gas mask would run out, and I
would not notice, becoming poisoned.

This was, needless to say, quite annoying. So, let's have the character
manage the changing of filters, instead of the player.

The solution is simple. Add a function to Character that will will take
an item and look at it's remaining ammo. If the item is low, but not
quite out, the function will warn every 8 turns about the item being
low. When the item runs out, it will scan the player inventory and
reload with appropriate items.

Then, this function simply needs to be called wherever the item consumes
charges, and the player will automatically handle reloading.

A variety of behavior tweaks are available, but by default (and always,
as there is no way to change them), a popup shown when the last suitable
item has been reloaded (next reload will fail) and when a reload is
attempted but fails.

Several tests have been added to ensure this behavior works for both
players and npcs.
@ehughsbaird ehughsbaird marked this pull request as draft August 25, 2023 01:06
@github-actions github-actions bot removed the BasicBuildPassed This PR builds correctly, label assigned by github actions label Aug 25, 2023
@github-actions
Copy link
Contributor

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions. Please do not bump or comment on this issue unless you are actively working on it. Stale issues, and stale issues that are closed are still considered.

@github-actions github-actions bot added the stale Closed for lack of activity, but still valid. label Sep 24, 2023
@github-actions github-actions bot closed this Oct 24, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
astyled astyled PR, label is assigned by github actions [C++] Changes (can be) made in C++. Previously named `Code` Code: Tests Measurement, self-control, statistics, balancing. <Enhancement / Feature> New features, or enhancements on existing json-styled JSON lint passed, label assigned by github actions stale Closed for lack of activity, but still valid.
Projects
Status: Abandoned PRs with no one to pick them up
Development

Successfully merging this pull request may close these issues.

3 participants