item glues to mouse pointer although dropped

General discussion regarding the OpenMW project.
For technical support, please use the Support subforum.
User avatar
asmo
Posts: 229
Joined: 18 Sep 2014, 21:20

item glues to mouse pointer although dropped

Post by asmo »

Hello,

I'm trying to drop an item via script, but it doesn't work.

Code: Select all

if ( player->GetEffect sEffectCharm == 0 ) ; gets true when the item is unequipped
    player->Drop foo 1
endif
What happens here is, that - although foo is dropped by the script - the items icon still sticks on the mouse pointer until you click somewhere.
I'd assume that Drop() means drop, right before the next frame. If an item is dropped only when the player does an action (like click on the ground) in order to make the item be dropped, Drop() is useless. I guess you mimic the odd behaviour of TES3 here, right?

thanks in advance
User avatar
Zini
Posts: 5538
Joined: 06 Aug 2011, 15:16

Re: item glues to mouse pointer although dropped

Post by Zini »

What you see is most likely a glitch. An item being dropped from a script while being dragged from the user is probably a corner case we overlooked. Nothing wrong with the drop instruction per se.
User avatar
asmo
Posts: 229
Joined: 18 Sep 2014, 21:20

Re: item glues to mouse pointer although dropped

Post by asmo »

Zini wrote:What you see is most likely a glitch. An item being dropped from a script while being dragged from the user is probably a corner case we overlooked. Nothing wrong with the drop instruction per se.
Sure, nothing wrong but in this case - new issue http://bugs.openmw.org/issues/3097
User avatar
asmo
Posts: 229
Joined: 18 Sep 2014, 21:20

Re: item glues to mouse pointer although dropped

Post by asmo »

BTW:
Is there a way to know if an item is actually held or just part of the (N)PCs inventory?

Something that would serve the same purpose like an OnPCHold, which would be
  • true after unequipping an item or taking one from a container or from the PCs inventory
  • not true when it was placed to a container/inventory or dropped/placed in the game world.
Right now I'm mainly interested in "is in the PCs inventory" (GetDistance == 0) and held or not held in the PCs hands. Can somebody help with a workaround please?
Chris
Posts: 1626
Joined: 04 Sep 2011, 08:33

Re: item glues to mouse pointer although dropped

Post by Chris »

asmo wrote:BTW:
Is there a way to know if an item is actually held or just part of the (N)PCs inventory?
If you mean when the player is dragging an item around with their mouse, then at that point it's considered unequipped and part of the PC's inventory. It's adding to their encumbrance and running scripts with the PC as its container like normal (or is it Oblivion that runs scripts on items in containers? never did much scripting with Morrowind). It only actually moves when it's dropped into the world or into another container window.

What do you need to know this information for? Perhaps there's another way to do what you're trying.
User avatar
asmo
Posts: 229
Joined: 18 Sep 2014, 21:20

Re: item glues to mouse pointer although dropped

Post by asmo »

Chris wrote:
asmo wrote:BTW:
Is there a way to know if an item is actually held or just part of the (N)PCs inventory?
If you mean when the player is dragging an item around with their mouse, then at that point it's considered unequipped and part of the PC's inventory.
When you unequip an item into your inventory there are two steps: a) take it from your neck into your hands and b) put it into your inventory. The weight doesn't change. And OnPCEquip is not reliable when you use it for stacked items.
What do you need to know this information for? Perhaps there's another way to do what you're trying.
What I try is to separate the stack from the "active" item. As mentioned OnPCEquip isn't reliable as well you can not make only the equipped item do something because scripts are executed for the whole stack. When you equip one item the whole stack is marked equipped.

Now, my idea was to simlpy care for separation myself. I have the stack (_inactive_ items) and one single equipped _active_ item. Works like: stacked and active items have a constant enchantment - e.g. Charm on self so:

inactive items script does the following (and more)

Code: Select all

IF ( GetEffect sEffectCharm == 1 )
    PC->RemoveItem inactive_item 1 ; remove equipped (RemoveItem seems to use the equipped item 1st, mayb Drop() is safer)
    PC->AddItem active_item 1
    PC->Equip active_item 1
ENDIF
The active item is now separated and can do what it should do. When an active item is unequipped it is converted back to inactive. This works pretty well.

Now, there is a problem when unequipping an active item. You can not determine if the PC did put it into it's inventory or is still holding it. When it is put to the world or a container GetDistance != 0. The script can not know what the player will do, drop, place somewhere, put it into a container or the PC inventory (container). So it needs to know when putting to inventory is actually done for converting it to an inactive item.
The last idea I had was - as soon as the item is unequipped - it is force Drop()-ed, then inactive added to inv and the dropped calls SetDelete on itself. Unfortunately there is a bug which makes an item not to be dropped when you hold it in your hand.
https://bugs.openmw.org/issues/3097

PS:
Forcing "unequip to inventory" (as just described) would help against another problem. You can not convert to inactive when you put the active into a container. There are ways to convert an active item taken from a container as soon as it was put into the PCs inventory. I haven't been so far to test what happens when an active item was put in a container and another item is equipped. There are two instances then, using GetDistance might help to make only the equipped work but the question is if it is executed by both or not. Then, what happens when active items are stacked in the container?
Chris
Posts: 1626
Joined: 04 Sep 2011, 08:33

Re: item glues to mouse pointer although dropped

Post by Chris »

asmo wrote:When you unequip an item into your inventory there are two steps: a) take it from your neck into your hands and b) put it into your inventory.
As far as the engine is concerned, the item never left your inventory. It's less "put it into your hands"+"put it in your inventory" and more like "unequip"+"cancel dragging". And as far as that goes, it's an implementation detail of the UI (personally I'd like to eventually see a UI mod that heavily reduces the amount of clicking and dragging, something more like Oblivion or SkyUI, so scripts couldn't rely on how exactly (un)equipping and transferring items works).
What I try is to separate the stack from the "active" item.
To accomplish what? Not being indignant, I'm just curious why you need the equipped item to be separate from the inactive ones, especially if it's just going to be re-stacked when unequipped and not store some kind of instance-specific state. If we're going to add stuff to the engine, it's better to get to the heart of the matter and work from there, rather than adding something in that's only needed because of other shortcomings you're trying to work around (i.e. do it properly from the start, instead of adding a hack for a hack that will be obsoleted eventually).
User avatar
asmo
Posts: 229
Joined: 18 Sep 2014, 21:20

Re: item glues to mouse pointer although dropped

Post by asmo »

Chris wrote:To accomplish what? Not being indignant, I'm just curious why you need the equipped item to be separate from the inactive ones, especially if it's just going to be re-stacked when unequipped and not store some kind of instance-specific state.
That's fine. :)
I'm making a mod. Part of it is that the PC can find special items. When the PC equips such an item a spell is added to it's list of known spells - when it's unequipped or served it's purpose (conjuring a creature and more) the spell is removed.

When you have more than two instances of that item stacked in the PCs inventory you can not achieve that anymore because you can not address the equipped item to remove the spell (and itself). Instead the script on the item seems to be executed twice per stack. IIRC Equipping sets "equipped" for the whole stack, not only the equipped item. OnPCEquip will return a wrong value in a circumstance that will occur often. When the spell is cast the active - and only the active item - shall do other things. This includes stack-distinct, own variable values. You can find an example where you can see from the MessageBox output that equipping an item causes the same message be shown twice.
like here: "Variables seem to have the same value at all instances?!" viewtopic.php?f=2&t=3140

What I tried was to workaround this stacking problem by making only one active (the equipped) item exist at a time and manage it's work by using GetEffect and other functions for managing conversion from/to an active item. So there is an item_inactive(-stack) and a unique item_active. That specific instance can be addressed now.

A fix would be to make all (stacked) instances execute the script separately, each having their own variables. The one that has OnPCEquip == true could be addressed by this or a selfmade ID and do the tasks the one (the active, equipped) instance shall do. Of course OnPCEquip should only be true for the single equipped instance then.
Otherwise this is not possible. Any instance is taken for executing the script. Even it you use OnPCEquip - out of 3 stacked items in the inventory - the script is only executed for some instance - lets say - number one and number two, but the equipped would be number 3… And even if it worked in one frame the engine may choose to use instance 1 for the next frame.

There is already a thread about this:
"scripting stacked items in container/inventory is a bad idea" viewtopic.php?f=2&t=3192
The essence is:
Zini wrote:It all comes down to being compatible with the original engine. At least to my knowledge we are replicating it correctly here. We can look at the situation again after 1.0 but for now it is what it is.
A workaround would be to make like 30 unique items (different IDs) - all looking the same, having the same name and script. When an instance is found a global script is used to determine, if there is already another instance existing - e.g. ring a3 is in the PCs inv and a3 is found in the just opened container. If the instance in the container is unique the item can be taken, otherwise … well, if I think about it, you can not temporarily exclude items from levelled lists, right?
Apart from that it's a dirty solution, what should be done when the PC collects 31 items? It's not dynamic and the items have to do vice-versa checks (~ 30^2 - 31) - or at least a global script would have to do it - for 30 item-IDs. And 30 items would be shown in the inventory.
Another idea would be to give the modder access to the equipped item by using my_item_equipped - so the engine would provide access to the item my_item that is equipped by extending its ID. But this would be a special case again.
Please, just let each instance (stacked or not) execute it's script. The modder has to make sure that this doesn't lead to a mess.

This touches this topic somewhat: viewtopic.php?f=2&t=3178

EDIT:
I can post the mod if you think it would help to see what I want to do, but it's only half done (e.g. conversation is done to 1%).
Chris
Posts: 1626
Joined: 04 Sep 2011, 08:33

Re: item glues to mouse pointer although dropped

Post by Chris »

asmo wrote:I'm making a mod. Part of it is that the PC can find special items. When the PC equips such an item a spell is added to it's list of known spells - when it's unequipped or served it's purpose (conjuring a creature and more) the spell is removed.
Hmm, I see. Would something like this be able to work? In a global script:

Code: Select all

if(player->HasItemEquipped, "MyUniqueItem" != 0)
    ;; Player has the item equipped, make sure they have its spell
    if(player->HasSpell, "MyUniqueSpell" == 0)
        player->AddSpell, "MyUniqueSpell"
    endif

    ;; Check if the player cast the spell, if so remove it and the item (can also add and
    ;; force-equip an alternate "drained" item variation, to ensure the player doesn't keep
    ;; a "charged" one equipped if they have more than one).
    if( ??? )
        player->RemoveSpell, "MyUniqueSpell"
        player->RemoveItem, "MyUniqueItem", 1
    endif
else
    ;; Player no longer has the item equipped, make sure they don't have the spell
    if(player->HasSpell, "MyUniqueSpell" != 0)
        player->RemoveSpell, "MyUniqueSpell"
    endif
endif
Checking for if the player cast a spell could be done by adding an on-self effect for the player that only lasts for one frame, something the player couldn't get otherwise (such as your 0-point Charm effect) and just check if the player has that spell effect. Just be careful with other mods that may try to do the same, as you could then erroneously detect it being cast (ideally we'd have scripted spell effects, where a custom script can be run for various stages of a spell effect, but this should work in the mean time).
User avatar
asmo
Posts: 229
Joined: 18 Sep 2014, 21:20

Re: item glues to mouse pointer although dropped

Post by asmo »

I'll check that ASAP.
Post Reply