Cataclysm-DDA icon indicating copy to clipboard operation
Cataclysm-DDA copied to clipboard

Advanced AR Glasses constantly try to take photos

Open Acrepe opened this issue 2 years ago • 5 comments

Describe the bug

When used to play music, "pair of advanced AR glasses" will prompt the player to take a photo after every action taken even after the music has stopped playing, including after the glasses have had their battery removed or been thrown away. Breaking the glasses prevents further prompts.

Steps to reproduce

  1. Spawn a pair of advanced AR glasses with an appropriate battery
  2. Spawn an SD card, download music from the card to the glasses
  3. Play music
  4. Be endlessly prompted to take a photo after each action or movement
  5. Remove the battery of the glasses, throw them away, and continue to be prompted
  6. Break the glasses to finally escape their curse

Expected behavior

For advanced AR glasses to not force the player to take endless photos in response to playing music.

Screenshots

No response

Versions and configuration

  • OS: Windows
    • OS Version: 10.0.19043.1826 (21H1)
  • Game Version: 32ee0b1 [64-bit]
  • Graphics Version: Tiles
  • Game Language: System language []
  • Mods loaded: [ Dark Days Ahead [dda], Disable NPC Needs [no_npc_food], No Fungal Growth [no_fungal_growth], Bionic Professions [package_bionic_professions] ]

Additional context

No response

Acrepe avatar Jul 27 '22 21:07 Acrepe

Can confirm that this has also happened to me.

  • OS: Windows
    • OS Version: 10.0.19044.1826 (21H2)
  • Game Version: 3a934ca [64-bit]
  • Graphics Version: Tiles
  • Game Language: System language []
  • Mods loaded: [ Dark Days Ahead [dda], Disable NPC Needs [no_npc_food], No Fungal Growth [no_fungal_growth], Bionic Professions [package_bionic_professions], Blaze Industries [blazeindustries], Bionic Slots [cbm_slots] ]

ChromePoptart avatar Jul 31 '22 17:07 ChromePoptart

I wanted to try looking into the code to see if I could find the root cause of this issue. I'm hoping what I found might be able to help someone who knows more about how items are handled to fix this issue.

Both "ar_glasses_advanced" and "eink_tablet_pc" have "EINKTABLETPC" as one of their "use_action" entries. The "iuse::einktabletpc" function handles the e-ink tablet PC functionalities, including playing music (assuming songs have been downloaded to the item from SD cards). I'm assuming that the reason the e-ink tablet PC doesn't have a similar behavior when playing music is that it doesn't also have the "CAMERA" "use_action", whereas the advanced AR glasses does.

Well, smartphones ("smart_phone"), like the advanced AR glasses, also have both "EINKTABLETPC" and "CAMERA" "use_action" entries.

  • Smartphones also have the "MP3" "use_action", so they can play music like an MP3 player does -- no problems with this mode of operation. When music is start this way, the item transforms into "smart_phone_music".
  • When songs are downloaded onto the smartphone, music can also be played via the "Use SD-Card apps" submenu. When music is started this way, the item transforms into "smart_phone_flashlight", and there is subsequently no constant-asking-to-take-pictures behavior.

I think the important difference here is that the smartphone transforms when either of the music-playing options is selected, and that both the 'MP3-type' "smart_phone_music" and the 'tablet PC-type' "smart_phone_flashlight" are lacking the "CAMERA" "use_action". I didn't find in the code the exact mechanism for this, but it seems to me like, when an item is active, something causes all of the item's associated "iuse" functions to be called each turn.

I did verify that, when the advanced AR glasses are set to play music and then start showing the camera menu each turn, the advanced AR glasses are still playing music (i.e., morale is being affected). So, I'm assuming that whatever mechanism calls the "iuse" functions each turn for the active advanced AR glasses item is calling both "iuse::camera" and "iuse::einktabletpc". I also verified that opting to end music playback on active advanced AR glasses does stop music playing, but does not revert the item to being deactivated.

So, to summarize, it seems to me like the issues are:

  1. "ar_glasses_advanced" having both "CAMERA" and "EINKTABLETPC" "use_action" entries results in both "iuse::camera" and "iuse::einktabletpc" being called each turn
  2. "iuse::einktabletpc" works correctly for smartphones, and seems to do everything properly with advanced AR glasses EXCEPT deactivating the item when music is stopped. I'm not sure if this could be caused by either (a) "iuse::einktabletpc" NOT successfully deactivating the item (relevant code: else if( !it->is_transformable() ) { it->deactivate(); }), or (b) "iuse::einktabletpc" successfully deactivating the item but "iuse::camera" being called on the same turn re-activates it (although the code of "iuse::camera" doesn't seem to do any activation or deactivation itself)

And it seems like there are two options for fixing it all:

  1. Address whatever underlying item mechanism is causing both "iuse::camera" and "iuse::einktabletpc" to be called each turn so that, instead, only "iuse::einktabletpc" is called each turn. (I don't know how the "iuse" functions of active items are automatically called each turn, so I've no clue on how big of an issue fixing this would be.)
  2. Convert "ar_glasses_advanced" to be transformable, and add in a variant that's transformed to when music is playing and does NOT have the "CAMERA" "use_action". (Seems like a potentially easier fix, but I don't have a full grasp of how items transform and what goes into deciding the details of the new transformed variant.)

For reference, in \data\json\items\tool\tool_armor.json:

  {
    "id": "ar_glasses_advanced",
...
    "use_action": [ "CAMERA", "PORTABLE_GAME", "EINKTABLETPC", "ELECTRICSTORAGE", "EBOOKSAVE", "EBOOKREAD" ],
...
    "flags": [ "ZOOM", "WATCH", "ALARMCLOCK", "OUTER", "FRAGILE", "SUN_GLASSES", "THERMOMETER", "WATER_BREAK" ]
  },

In \data\json\items\tool\electronics.json:

  {
    "id": "smart_phone",
...
    "use_action": [
      "CAMERA",
      "MP3",
      "CALORIES_INTAKE_TRACKER",
      "PORTABLE_GAME",
      "EINKTABLETPC",
      "ELECTRICSTORAGE",
      "EBOOKSAVE",
      "EBOOKREAD",
      {
        "target": "smart_phone_flashlight",
        "msg": "You activate the flashlight app.",
        "menu_text": "Turn on flashlight",
        "active": true,
        "need_charges": 5,
        "need_charges_msg": "The smartphone's charge is too low.",
        "type": "transform"
      }
    ],
    "flags": [ "WATCH", "ALARMCLOCK", "USE_UPS", "NO_UNLOAD", "NO_RELOAD", "WATER_BREAK", "CALORIES_INTAKE" ],
...
  },
  {
    "id": "smartphone_music",
    "copy-from": "smart_phone",
...
    "revert_to": "smart_phone",
    "use_action": [ "MP3_ON", "PORTABLE_GAME", "EINKTABLETPC", "EBOOKSAVE", "EBOOKREAD" ],
    "flags": [ "WATCH", "TRADER_AVOID", "ALARMCLOCK", "USE_UPS", "NO_UNLOAD", "NO_RELOAD", "WATER_BREAK" ]
  },
  {
    "id": "smart_phone_flashlight",
    "copy-from": "smart_phone",
...
    "revert_to": "smart_phone",
    "use_action": [
      "PORTABLE_GAME",
      "EINKTABLETPC",
      "EBOOKSAVE",
      "EBOOKREAD",
      {
        "ammo_scale": 0,
        "target": "smart_phone",
        "msg": "You deactivate the flashlight app.",
        "menu_text": "Turn off flashlight",
        "type": "transform"
      }
    ],
    "flags": [ "WATCH", "LIGHT_20", "CHARGEDIM", "TRADER_AVOID", "ALARMCLOCK", "USE_UPS", "NO_UNLOAD", "NO_RELOAD", "WATER_BREAK" ]
  },

ChromePoptart avatar Aug 09 '22 16:08 ChromePoptart

When items are active, their use actions are invoked from item processing (to do things like drain charges). The bool parameter in a cata::optional<int> iuse::X( Character *, item *, bool, tripoint &) function is true if the use function is invoked from item processing. It seems like the solution to this is to return early from that use function if it is invoked from processing. https://github.com/CleverRaven/Cataclysm-DDA/blob/cb55b2ab7bb364b4f76055d3d488c64da5990890/src/iuse.cpp#L7301

anothersimulacrum avatar Aug 09 '22 16:08 anothersimulacrum

Thanks for the clarification, @anothersimulacrum -- I was wondering what that option bool meant, but didn't find it documented in iuse.cpp or elsewhere (although I admit I probably didn't look very hard). From what I can tell, your suggestion seems like it should work! Seems like iuse::einktabletpc already does this if music isn't playing:

cata::optional<int> iuse::einktabletpc( Character *p, item *it, bool t, const tripoint &pos )
{
    if( t ) {
        if( !it->get_var( "EIPC_MUSIC_ON" ).empty() &&
            it->ammo_sufficient( p ) ) {
            if( calendar::once_every( 5_minutes ) ) {
                it->ammo_consume( 1, p->pos(), p );
            }

            //the more varied music, the better max mood.
            const int songs = it->get_var( "EIPC_MUSIC", 0 );
            play_music( *p, pos, 8, std::min( 25, songs ) );
        }
        return cata::nullopt;
    }
...

So, does if( t ) { return cata::nullopt; } just need to be added as the first line of iuse::camera?

A follow-on question, though: do iuse::X functions automatically inherit some mechanism to activate the item when the function is called and the item isn't active? I'm just wondering why, in my testing, using iuse::einktabletpc to turn off music via 'Use SD-Card apps' results in music stopping (meaning iuse::einktabletpc seems to successfully execute), but the item remains active and the every-turn camera menu continues to show up. It seems like something either prevents iuse::einktabletpc from deactivating the item or reactivates the item on the same turn iuse::einktabletpc deactivates it.

Also, I don't have the infrastructure set up to build updated source code and run the modified game, so is there any way to request that someone else do that to try out the fix?

ChromePoptart avatar Aug 09 '22 16:08 ChromePoptart

So, does if( t ) { return cata::nullopt; } just need to be added as the first line of iuse::camera?

Yes.

A follow-on question, though: do iuse::X functions automatically inherit some mechanism to activate the item when the function is called and the item isn't active? I'm just wondering why, in my testing, using iuse::einktabletpc to turn off music via 'Use SD-Card apps' results in music stopping (meaning iuse::einktabletpc seems to successfully execute), but the item remains active and the every-turn camera menu continues to show up. It seems like something either prevents iuse::einktabletpc from deactivating the item or reactivates the item on the same turn iuse::einktabletpc deactivates it.

I'm not sure, sorry.

Also, I don't have the infrastructure set up to build updated source code and run the modified game, so is there any way to request that someone else do that to try out the fix?

By outlining the fix here and where to apply it, that's essentially already been done.

anothersimulacrum avatar Aug 10 '22 16:08 anothersimulacrum

By outlining the fix here and where to apply it, that's essentially already been done.

Got it -- thanks, @anothersimulacrum!

ChromePoptart avatar Aug 13 '22 14:08 ChromePoptart

Just had this issue in my playthrough of the latest experimental build. The issue is persisting. I'd like to add that even after removing the battery from the glasses, the issue persisted. At this point, there does not seem to be any fix and the game is unplayable in its current state. Is there any update or follow-up to this bug?

FellsHollow avatar Oct 16 '22 20:10 FellsHollow

I assumed that the bug hadn't been fixed because there hadn't been any further action on this thread/item.  I don't know if it's acceptable to bump issues, but I'm certainly hoping someone will come along and implement the fix.  Given the fix that anothersimulacrum helped me find, it seems like it should be a pretty open-and-shut, quick update to make and test, so, again, I'm hoping someone's interest is piqued enough to do the work. I suppose it potentially hasn't been worked on, even though a likely potential fix has been identified, is that it isn't a terribly impactful bug.  That said, I would really appreciate it if the bug were addressed!

ChromePoptart avatar Oct 16 '22 22:10 ChromePoptart

Thanks so much for taking care of this, @ehughsbaird!!!

ChromePoptart avatar Oct 17 '22 02:10 ChromePoptart

Happy to help! A little surprised nobody beat me to it.

ehughsbaird avatar Oct 17 '22 02:10 ehughsbaird

So, I went to the other thread by ehughsbaird to do what he said to do. I already had a pair of advanced AR glasses set to (active) but I spawned in a bunch of SD memory cards until I found one with music. I downloaded them using the steps laid out, it downloaded about 20 new songs, I went to Turn music on, but the issue of being prompted by a camera persisted.

EDIT: I spawned a new pair of glasses and went through the same steps and I am still being prompted about what I want to do with the camera. Even after I activated and deactivated the new pair, they are still showing as active (yellow) in my inventory.

FellsHollow avatar Oct 17 '22 15:10 FellsHollow

https://github.com/CleverRaven/Cataclysm-DDA/pull/61748 contains a fix for the issue, but it needs to be merged into the game for it to work. The steps I outline there are the steps to reproduce the bug, and once the bug is fixed (the linked PR is merged), the bug will no longer be able to be reproduced, and those steps will work without error. Right now we just have to wait for that PR to be merged. This issue will be closed when the bug is fixed/the PR is merged, then the next experimental build will have the fix.

ehughsbaird avatar Oct 17 '22 16:10 ehughsbaird

Thank you for your reply. I hope I helped in some way.

FellsHollow avatar Oct 17 '22 17:10 FellsHollow