FakeFishGames / Barotrauma

A 2D online multiplayer game taking place in a submarine travelling through the icy depths of Jupiter's moon Europa.
http://www.barotraumagame.com/
1.74k stars 405 forks source link

Problems about <Use /> #13136

Closed NotAlwaysTrue closed 9 months ago

NotAlwaysTrue commented 10 months ago

Disclaimers

<ItemContainer capacity="1" maxstacksize="1" depth="0.5"> <Containable tags="smallitem,medical,chem,syringe"/> </ItemContainer> <StatusEffect tags="medical" type="OnUse" target="This" Condition="-100.0" disabledeltatime="true"> <Sound file="%ModDir%/audio/injector.ogg" range="500" /> </StatusEffect> <StatusEffect tags="medical" type="OnUse" target="Contained,UseTarget" Condition="-100.0" disabledeltatime="true"> <Use /> </StatusEffect>

A medical item coding like this, while using the item, the contained item didn't get <Use />. If I put a combat stim in it and use it in health interface, I won't get buff from combat stim as the same as using combat stim itself. Can anybody tell me what happened to <Use />tag or how to fix it?

NotAlwaysTrue commented 10 months ago

I think it is a problem of game mechanism. HMG mech is functioning like this:

User input ↓ HMG "use" hmgmagazine → hmgmagazine spawn hmground in its inventory → HMG shoot hmground. ↓ hmgmagazine condition -1

Only stat "OnUse" itself get passed to the item.It seems no offical explain on how <Use /> works and no offical example uses such format to "use" an item. Should I suppose that <Use /> didn't pass any data like "UseTarget" to the item contained and that is why causes these code to fail?

Regalis11 commented 10 months ago

Thank you for the report!

It's a little hard to see what's happening here from these partial XML snippets, but to me it looks like the issue here is that the second effect reduces the condition of the contained item by -100 and then tries to use it, which I would imagine doing nothing (it will break the item, after which it cannot be used).

It seems no offical explain on how works and no offical example uses such format to "use" an item.

All it does is "using" the target item (the meaning of "using" depends on what the target item is or what it does). There's nothing more to it, no other formatting you'd need or any parameters to configure.

NotAlwaysTrue commented 10 months ago

No. That's not the problem. I deleted "Condition="-100.0" and the item is still there, not used with no affliction given. (Sorry about that.I pasted outdated version of my code) I think the container was the "UseTarget" for the contained item instead of the user since it is the container actually "use" the item.

Would you like to check the sourcecode and tell who exactly is the "UseTarget" when a container "<Use />" contained item, the person who "use" the container or the container itself? And if it is the container, how can I pass the "UseTarget" of the container to the contained item?

Regalis11 commented 10 months ago

Ah, thanks for the clarification!

Would you like to check the sourcecode and tell who exactly is the "UseTarget" when a container "" contained item, the person who "use" the container or the container itself?

As explained in the modding documentation, "UseTarget" is generally the thing the item is being used on (e.g. the character you're using a drug on, the wall you're welding with a welding tool, etc). It is not the character who's using the item. It's impossible to tell from that incomplete XML snippet what the UseTarget is in this case, because we don't know what kind of an item or component that status effect is inside. I think we need a bit more context to figure out what the issue is here - where is this status effect defined? Could you post the XML of the entire item?

NotAlwaysTrue commented 10 months ago
<?xml version="1.0" encoding="utf-8"?>
<Items>
    <Item name="" identifier="basepen" category="Medical" maxstacksize="32" maxstacksizecharacterinventory="1" cargocontaineridentifier="mediccrate" Tags="smallitem,chem,medical" useinhealthinterface="true" description="" scale="0.15" RequireAimToUse="True" impactsoundtag="impact_soft">
      <Deconstruct time="5" />
      <InventoryIcon texture="%ModDir%/icon/basepen.png" sourcerect="0,0,160,160" origin="0.5,0.5" />
      <Sprite texture="%ModDir%/icon/basepen.png" sourcerect="0,0,160,160" depth="0.6" origin="0.5,0.5" />
      <Body width="45" height="45" density="11" />
      <MeleeWeapon canBeCombined="true" removeOnCombined="true" slots="Any,RightHand,LeftHand" aimpos="40,5" handle1="0,0" reload="1.0" msg="ItemMsgPickUpSelect">
        <ItemContainer capacity="1" maxstacksize="1" depth="0.5"><!--Working-->
            <Containable tags="smallitem,medical,chem,syringe"/><!--Working-->
        </ItemContainer><!--Working-->
        <StatusEffect tags="medical" type="OnUse" target="This" Condition="0.0" disabledeltatime="true"><!--0.0 here is a debug value-->
          <Sound file="%ModDir%/audio/injector.ogg" range="500" />
        </StatusEffect>
        <StatusEffect tags="medical" type="OnUse" target="Contained,UseTarget" ><!--Not working-->
          <Use /><!--Not working-->
        </StatusEffect><!--Not working-->
        <StatusEffect type="OnBroken" target="This">
          <Remove />
        </StatusEffect>
      </MeleeWeapon>
      <AiTarget sightrange="1000" static="true" />
    </Item>
</Items>

Well, this is some of the code I made for my mod(Code here only have the necessary part to function, experimental). Lines marked with<!--Not working--> is where I have problem with. In this case, I hope to use the item(as a container of meds) as a agent to use the meds contained(to bypass the skill system and it is an experiment on improving compatibility with other mods*).

*:For example, if this method is possible, if I want to make my mod work with other medical mods that override vanillan meds that my mod is supposed to have the same afflictation(eg.Neurotrauma, which overrides morphine and adrenaline), rework on the whole project is no longer needed since you can just simply spawn the meds that have the afflictation in the hidden container and <Use /> it.

I think it might not a bug now since I originally believe "UseTarget" is a global var in this case.

NotAlwaysTrue commented 10 months ago

By the way, is it possible to add if/else or something similar to check whether a specific mod is loaded or not and in a result to load specific xml file in filelist.xml? it is really annoing to upload many versions of my mod to fit different needs from compating different mods. I will have to check the file name(and the folder name) to make sure i didn't edit the wrong version.

I think there will be great change in the modding community if this is practically possible.

Regalis11 commented 10 months ago

I don't see anything obviously wrong in that XML, so I have a feeling the issue could be in the medical item itself. I gave this a test with the vanilla meds, and it seems those don't work because they set RequireAimToUse="true", which means they'd need to be aimed when this StatusEffect tries to use them.

By the way, is it possible to add if/else or something similar to check whether a specific mod is loaded or not and in a result to load specific xml file in filelist.xml?

To my knowledge, this is not possible at the moment. I'm curious why it's necessary though - to me it seems like it'd be equally annoying to make the functionality differ depending on the installed mods. Can you give an example of how the mod might need to fit the needs of another mod? I'm wondering if there'd be some easier way to do that or if there's something we could do to make it easier.

NotAlwaysTrue commented 10 months ago

I don't see anything obviously wrong in that XML, so I have a feeling the issue could be in the medical item itself. I gave this a test with the vanilla meds, and it seems those don't work because they set RequireAimToUse="true", which means they'd need to be aimed when this StatusEffect tries to use them.

No. That is not the problem.

<Items>
<!--Previous code-->
<!--TEST MED-->
    <Item name="testmed" identifier="testmed" aliases="Corrigodone" category="Medical" maxstacksize="32" maxstacksizecharacterinventory="8" cargocontaineridentifier="mediccrate" Tags="smallitem,chem,medical,syringe" description="" useinhealthinterface="true" scale="0.5" impactsoundtag="impact_metal_light">
      <InventoryIcon texture="Content/Items/InventoryIconAtlas.png" sourcerect="256,448,64,64" origin="0.5,0.5" />
      <Sprite texture="Medicines.png" sourcerect="0,0,37,69" depth="0.6" origin="0.5,0.5" />
      <Body width="35" height="65" density="10.2" waterdragcoefficient="1" />
      <MeleeWeapon canBeCombined="true" removeOnCombined="true" slots="Any,RightHand,LeftHand" aimpos="40,5" handle1="0,0" holdangle="220" reload="1.0" msg="ItemMsgPickUpSelect" HitOnlyCharacters="true">
        <RequiredSkill identifier="medical" level="40" />
        <StatusEffect type="OnUse" target="This" Condition="-100.0" setvalue="true"/>
        <StatusEffect tags="medical" type="OnUse" target="UseTarget">
          <Affliction identifier="bleeding" amount="100" />
        </StatusEffect>
        <StatusEffect type="OnBroken" target="This">
          <Remove />
        </StatusEffect>
      </MeleeWeapon>
    </Item>
</Items>

This item is designed to check whether RequireAimToUse="true" was the problem(the code was from vanilla Morphine and original affliction was replaced with more obvious one). The result turns out neither RequireAimToUse="false" or simply remove it works.

I suppose it is the problem with <Use /> and the meds contained was "told" to get used but was not "told" who is the meds uses on(the "UseTarget", every affliction was supposed to be imposed to a entity, right?). It seems the <Use /> needs some parameters to tell the contained item that is being used who is the target it is being used on

NotAlwaysTrue commented 10 months ago

To my knowledge, this is not possible at the moment. I'm curious why it's necessary though - to me it seems like it'd be equally annoying to make the functionality differ depending on the installed mods. Can you give an example of how the mod might need to fit the needs of another mod? I'm wondering if there'd be some easier way to do that or if there's something we could do to make it easier.

Here, for example, Neurotrauma(NT), which mod defined affliction whose identifier was fever, which has the same identifier with mine. My "fever" is just a useless code to tell the player your body temperature is high and means noting. In this case, usually when loading NT and my mod, we will have a error that tells the user there is a confliciton.

In order to make NT compatible with my mod, I will have to create a new folder and copy paste my code there, modify filelist.xml and other xml file, then publish everything to steamworkshop. For smaller mods, this is not a big problem. Everything changes when your files have thousands of lines of codes, really tough work need to be done. Meanwhile the user will have to goto steamworkshop, download it again, load it with NT to play.

In the new method, I will have publish the whole project once, and if I want to make my mod compatible with any other mods, I only need to check his xml file and decided what to do with my mods. After making sure everything is working, I will have only have my click on "update".All users will receive this update, and evenif anyone didn't have both mod, my mod will still function.

For third-party patch makers, this method can ensure their patch was running with the right mod, not any fork mods(whose code and function might be very different from the original one.). For filelist.xml that didn't includes if/else nodes, it will sitll function as usual.

This feature might not be necessary for all modders, but really does good for those big mods who have demands to allow their mods to work with other mods.

I know there will be much more important stuff to do. If you don't have enough time to add or delete something, just leave this "Low prior". Since this is not the topic of the issue, is it necessary to start a new discussion?

NotAlwaysTrue commented 10 months ago

uh...Is there anyone is still looking into this post? It had a week since last comment...

Regalis11 commented 9 months ago

Sorry for taking so long to get back to you, we had quite a lot of other things on our plate before the Christmas holidays and didn't have time to take another look at this issue.

I tested the medicine you provided, and found the issue: it happened because the effects are defined in a MeleeWeapon component, and only characters are able to Use melee weapons (i.e. the "basepen" item is not able to use it).

This could be worked around by defining the effects in a "plain" ItemComponent instead, for example like this:

  <Item name="testmed" identifier="testmed" aliases="Corrigodone" category="Medical" maxstacksize="32" maxstacksizecharacterinventory="8" cargocontaineridentifier="mediccrate" Tags="smallitem,chem,medical,syringe" description="" useinhealthinterface="true" scale="0.5" impactsoundtag="impact_metal_light">
    <InventoryIcon texture="Content/Items/InventoryIconAtlas.png" sourcerect="256,448,64,64" origin="0.5,0.5" />
    <Sprite texture="Medicines.png" sourcerect="0,0,37,69" depth="0.6" origin="0.5,0.5" />
    <Body width="35" height="65" density="10.2" waterdragcoefficient="1" />
    <MeleeWeapon canBeCombined="true" removeOnCombined="true" slots="Any,RightHand,LeftHand" aimpos="40,5" handle1="0,0" holdangle="220" reload="1.0" msg="ItemMsgPickUpSelect" HitOnlyCharacters="true">
      <RequiredSkill identifier="medical" level="40" />
      <StatusEffect type="OnUse" target="This" Condition="-100.0" setvalue="true"/>
      <StatusEffect tags="medical" type="OnUse" target="UseTarget">
        <Affliction identifier="bleeding" amount="100" />
      </StatusEffect>
      <StatusEffect type="OnBroken" target="This">
        <Remove />
      </StatusEffect>
    </MeleeWeapon>
    <ItemComponent characterusable="false">
      <StatusEffect type="OnUse" target="This" Condition="-100.0" setvalue="true"/>
      <StatusEffect tags="medical" type="OnUse" target="UseTarget">
        <Affliction identifier="bleeding" amount="100" />
      </StatusEffect>
      <StatusEffect type="OnBroken" target="This">
        <Remove />
      </StatusEffect>
    </ItemComponent>
  </Item>

You could also simplify this by using the "inheritstatuseffectsfrom" attribute, which allows you to only define the effects in one component:

  <Item name="testmed" identifier="testmed" aliases="Corrigodone" category="Medical" maxstacksize="32" maxstacksizecharacterinventory="8" cargocontaineridentifier="mediccrate" Tags="smallitem,chem,medical,syringe" description="" useinhealthinterface="true" scale="0.5" impactsoundtag="impact_metal_light">
    <InventoryIcon texture="Content/Items/InventoryIconAtlas.png" sourcerect="256,448,64,64" origin="0.5,0.5" />
    <Sprite texture="Medicines.png" sourcerect="0,0,37,69" depth="0.6" origin="0.5,0.5" />
    <Body width="35" height="65" density="10.2" waterdragcoefficient="1" />
    <MeleeWeapon canBeCombined="true" removeOnCombined="true" slots="Any,RightHand,LeftHand" aimpos="40,5" handle1="0,0" holdangle="220" reload="1.0" msg="ItemMsgPickUpSelect" HitOnlyCharacters="true">
      <RequiredSkill identifier="medical" level="40" />
      <StatusEffect type="OnUse" target="This" Condition="-100.0" setvalue="true"/>
      <StatusEffect tags="medical" type="OnUse" target="UseTarget">
        <Affliction identifier="bleeding" amount="100" />
      </StatusEffect>
      <StatusEffect type="OnBroken" target="This">
        <Remove />
      </StatusEffect>
    </MeleeWeapon>
    <ItemComponent characterusable="false" inheritstatuseffectsfrom="MeleeWeapon" />
  </Item>
Regalis11 commented 9 months ago

Since this is not the topic of the issue, is it necessary to start a new discussion?

You could start a new discussion if you'd like to, although I can't give any promises on when / if at all we could implement a feature like this. I'm probably not fully grasping the issue, but to me it seems like there might be easier ways to go about fixing that kind of conflicts between mods: you could for example just use a different identifier for the conflicting content. A common practice is to add some kind of a prefix to all the identifiers (e.g. "mymod_fever") to prevent conflicts.