ReDragon2013 Posted January 15, 2017 Share Posted January 15, 2017 (edited) .. Edited March 6, 2017 by ReDragon2013 Link to comment Share on other sites More sharing options...
Masterofnet Posted January 15, 2017 Author Share Posted January 15, 2017 (edited) Let me explain this script a little better. Scriptname PlayerAliasScript extends ReferenceAlias Int Count Int NoPoison Potion Property ThePotion Auto ReferenceAlias Property PoisonedWeapon Auto Event OnItemRemoved(Form akBaseItem, int aiItemCount, ObjectReference akItemReference, ObjectReference akDestContainer) AddInventoryEventFilter(ThePotion) ; The exact poison you are using on the weapon. Count += 1 ;------------------------------------------------------------------------------------- ; The Wait must be used here because this is the only way we can determine if the Poison has been applied. The Event OnItemRemoved fires twice when you poison a weapon or take a potion. Utility.Wait(0.7) ;--------------------------------------------------------------------------------- If Count = 2 Weapon Poisoned = (PlayerRef.GetEquippedWeapon()) Int WeaponCount = PlayerRef.GetItemCount(Poisoned) ;---------------------------------------------------------------------------------------------- ; This must be done to clear any other weapons of the same type from the players inventory. The Drop function always drops the unequipped weapon first. If there are no extras it will go right to the next function. If they exist I drop, count, and disable them. While WeaponCount > 1 (PlayerRef.DropObject(Poisoned)).Disable() NoPoison += 1 EndWhile ;-------------------------------------------------------------------------------------------------- ; Now I have the exact weapon that has been poisoned. I drop it and force it to a ReferenceAlias that has a script on it to keep track of it. If it is equipped, Un-eqipped etc. PoisonedWeapon.ForceRefTo(PlayerRef.DropObject(Poisoned)) ObjectReference PWeaponRef = PoisonedWeapon.GetReference() PlayerRef.AddItem(PWeaponRef, 1, True) Utility.Wait(1) ;You must add Wait here or the weapon will not equip. PlayerRef.EquipItem(PWeaponRef.GetBaseObject(), False, True) ;------------------------------------------------------------------------------ After I equip the poisoned weapon the removed weapons are added back into the players inventory. PlayerRef.AddItem(Poisoned,NoPoison,True) EndIf endEvent I see in your script you get the Form of the equipped weapon. Do you think that will work on drop? Do you think it will be able to separate it from the other exact weapons? (If any are in inventory) I have never used that or had a need to. I have always separated items by getting an object reference. So this could be all I may need to do? Scriptname PlayerAliasScript extends ReferenceAlias Bool PropertiesGate Int PotionCount Potion Property ThePotion Auto ReferenceAlias Property PoisonedWeaponRef Auto Event OnItemRemoved(Form akBaseItem, int aiItemCount, ObjectReference akItemReference, ObjectReference akDestContainer) AddInventoryEventFilter(ThePotion) ; The exact poison you are using on the weapon. Actor PlayerRef = Game.GetPlayer() If AkBaseItem == ThePotion PotionCount += 1 EndIf ;------------------------------------------------------------------------------------- ; The Wait must be used here because this is the only way we can determine if the Utility.Wait(0.7) ;--------------------------------------------------------------------------------- If PotionCount == 2 If PropertiesGate == False Form Poisonedfm = PlayerRef.GetEquippedWeapon() as Form PropertiesGate = True EndIf PoisonedWeaponRef.ForceRefTo(PlayerRef.DropObject(Poisonedfm, 1)) PlayerRef.AddItem(PoisonedWeaponRef.GetReference(),1,True) Utility.Wait(1) PlayerRef.EquipItem(Poisonedfm,False,True) EndIf EndEvent Edited January 15, 2017 by Masterofnet Link to comment Share on other sites More sharing options...
Masterofnet Posted January 15, 2017 Author Share Posted January 15, 2017 (edited) Using form does not work. The game drops the unequipped weapons first.This script is removing all of the weapons of which there are 5 and adding 14 I can not figure out why. I have run some things down but they make no sense. The add items function is adding twice the amount of the INT even if I put in a # PlayerRef.AddItem(Poisoned,2,True) It will add 4 Why???? Scriptname PlayerAliasPotion extends ReferenceAlias Bool PropertiesGate Int PotionCount Potion Property ThePotion Auto Form Property PFM Auto KeyWord Property VendorItemPoison Auto Int NoPoison ReferenceAlias Property PoisonedWeaponRef Auto EVENT OnInit() self.AddInventoryEventFilter(ThePotion) ; The exact poison you are using on the weapon. Debug.Notification("Fired") ENDEVENT Event OnItemRemoved(Form akBaseItem, int aiItemCount, ObjectReference akItemReference, ObjectReference akDestContainer) Debug.Notification("Event Fired") Actor PlayerRef = Game.GetPlayer() If AkBaseItem == ThePotion PotionCount += 1 EndIf Utility.Wait(0.7) If PotionCount == 1 PotionCount =0 ElseIf PotionCount == 2 Weapon Poisoned = (PlayerRef.GetEquippedWeapon()) Int WeaponCount = PlayerRef.GetItemCount(Poisoned) If WeaponCount == 5 Debug.Notification("Got Five") EndIf While WeaponCount > 1 ;THIS IS NOT WORKING. IT IS NOT PRECISE ENOUGH TO COUNT THEM CORRECTLY EVEYTIME. (PlayerRef.DropObject(Poisoned)).Disable() WeaponCount -=1 NoPoison += 1 EndWhile PoisonedWeaponRef.ForceRefTo(PlayerRef.DropObject(Poisoned)) ObjectReference PWeaponRef = PoisonedWeaponRef.GetReference() PlayerRef.AddItem(PWeaponRef, 1, True) Utility.Wait(1) PlayerRef.EquipItem(PWeaponRef.GetBaseObject(), False, True) PlayerRef.AddItem(Poisoned,NoPoison,True) ; This is adding twice as many times as the Int States, PlayerRef.AddItem(Poisoned,2,True) It adds 4 Why???? EndIf endEvent Edited January 15, 2017 by Masterofnet Link to comment Share on other sites More sharing options...
cdcooley Posted January 15, 2017 Share Posted January 15, 2017 This section of the code is the reason for your extras. Because of the Wait both instances of the event will see a PotionCount of 2 and so all of that code runs twice (but not at exactly the same time leading to the strange numbers you're seeing.) If AkBaseItem == ThePotion PotionCount += 1 EndIf Utility.Wait(0.7) If PotionCount == 1 PotionCount =0 ElseIf PotionCount == 2 ;;;; do stuff EndIf Try this instead because only the first event should be waiting. The second event needs to happen during the wait. If AkBaseItem == ThePotion PotionCount += 1 If PotionCount == 1 Utility.Wait(0.7) PotionCount = 0 ElseIf PotionCount == 2 ;;;; do stuff EndIf EndIf Link to comment Share on other sites More sharing options...
cdcooley Posted January 15, 2017 Share Posted January 15, 2017 Thinking about this a little more, this should work: Event OnItemRemoved(Form akBaseItem, int aiItemCount, ObjectReference akItemReference, ObjectReference akDestContainer) Debug.Notification("Event Fired") Actor PlayerRef = Game.GetPlayer() If AkBaseItem == ThePotion PotionCount += 1 If PotionCount == 1 Utility.Wait(0.7) PotionCount =0 Else Weapon Poisoned = (PlayerRef.GetEquippedWeapon()) ObjectReference UnpoisonedStackRef ObjectReference PoisonedRef ; drop the stack of weapons that won't get poison Int UnpoisonedCount = PlayerRef.GetItemCount(Poisoned) - 1 if UnpoisonedCount > 0 UnpoisonedStackRef = PlayerRef.DropItem(Poisoned, UnpoisonedCount) endif ; now drop the equipped one so it can be poisoned PoisonedWeaponRef.ForceRefTo(PlayerRef.DropObject(Poisoned)) PoisonedRef = PoisonedWeaponRef.GetReference() ; give the poisoned item back and equip it PlayerRef.AddItem(PoisonedRef, 1, True) Utility.Wait(0.1) ; you shouldn't need to wait this long PlayerRef.EquipItem(PoisonedRef.GetBaseObject(), False, True) ; finally give back the stack of unpoisoned ones (if there are any) if UnpoisonedStackRef PlayerRef.AddItem(UnpoisonedStackRef, 1, true) endif EndIf EndIf endEvent Link to comment Share on other sites More sharing options...
Masterofnet Posted January 15, 2017 Author Share Posted January 15, 2017 (edited) Cooley you are a God Send. I just gated it and it works perfectly. I don't see how the functions can fire twice when the Count only reaches 2 in my testing once, but it is the problem. I am going to get some sleep and have a look when I wake up. Ya and thanks again. I can just not get out of my own way on this. For some reason I though you could not drop # of items. That is I why I have been counting them down. That is exactly what I would have done. Get the count -1 and drop them. I did read that they are dropped one at a time so you may not be able to get a stack of them. Also can you disable them?? With your script the player would see the weapons fall and lay on the ground. This script does work very well now. You can not see the dropped items at all and the weapon just looks like it was unequipped and then re- equipped. As far as the Wait(1) I have never had to use a wait at all between adding an item and equipping it. It may have something to do with the gating issue as well. Scriptname PlayerAliasPotion extends ReferenceAlias Bool PropertiesGate Int PotionCount Potion Property ThePotion Auto KeyWord Property VendorItemPoison Auto Int NoPoison ReferenceAlias Property PoisonedWeaponRef Auto EVENT OnInit() self.AddInventoryEventFilter(ThePotion) ; The exact poison you are using on the weapon. Debug.Notification("Fired") ENDEVENT Event OnItemRemoved(Form akBaseItem, int aiItemCount, ObjectReference akItemReference, ObjectReference akDestContainer) Debug.Notification("Event Fired") Actor PlayerRef = Self.GetReference() As Actor If AkBaseItem == ThePotion PotionCount += 1 EndIf Utility.Wait(0.7) If PotionCount == 1 PotionCount =0 ElseIf PotionCount == 2 If PropertiesGate == False PropertiesGate = True Weapon Poisoned = (PlayerRef.GetEquippedWeapon()) Int WeaponCount = PlayerRef.GetItemCount(Poisoned) While WeaponCount >1 (PlayerRef.DropObject(Poisoned)).Disable() WeaponCount -=1 NoPoison +=1 EndWhile PoisonedWeaponRef.ForceRefTo(PlayerRef.DropObject(Poisoned)) ObjectReference PWeaponRef = PoisonedWeaponRef.GetReference() PlayerRef.AddItem(PWeaponRef, 1, True) Utility.Wait(1) PlayerRef.EquipItem(PWeaponRef.GetBaseObject(), False, True) PlayerRef.AddItem(PWeaponRef.GetBaseObject(),NoPoison,True) EndIf EndIf endEvent Edited January 15, 2017 by Masterofnet Link to comment Share on other sites More sharing options...
Masterofnet Posted January 15, 2017 Author Share Posted January 15, 2017 (edited) One last thing about the Wait at the beginning. You must have it above the PotionCount == 1 because you need to use that to put the potion back in the players inventory if it is dropped. That is the only way to distinguish between it being dropped and being used. By the time the wait is done if the potion was used it will be at 2. If the potion is dropped the wait does not matter because it will always be one. You check the inventory and if it is not there you put it back. I was unable to add the stack back into the players inventory because it gave all of the weapons one objectreference. If the player were to drop them into the environment they would all disappear until only one was left. UPDATE: This was a really good attempt. However it does not function up to my standards. If you drop the potion enough times etc. it can sometimes fail. Thanks for the help. If anyone has any ideas on how this could be "fool prof" I am happy to hear them, but unfortunately I doubt it. Scriptname PlayerAliasPotion extends ReferenceAlias Int PotionCount Int UnpoisonedCount Potion Property ThePotion Auto ObjectReference UnpoisonedStackRef ObjectReference PWeaponRef ObjectReference PotionRef ReferenceAlias Property PotionAlias Auto ReferenceAlias Property PoisonedWeaponRef Auto Bool Gate EVENT OnInit() self.AddInventoryEventFilter(ThePotion) ; The exact poison you are using on the weapon. Debug.Notification("Fired") ENDEVENT Event OnItemRemoved(Form akBaseItem, int aiItemCount, ObjectReference akItemReference, ObjectReference akDestContainer) Actor PlayerRef = Self.GetReference() As Actor PotionRef = PotionAlias.GetReference() If AkBaseItem == ThePotion PotionCount += 1 EndIf Utility.Wait(0.1) If PotionCount == 2 If Gate == False Gate = True Weapon Poisoned = (PlayerRef.GetEquippedWeapon()) UnpoisonedCount = PlayerRef.GetItemCount(Poisoned) - 1 If UnpoisonedCount > 0 UnpoisonedStackRef = PlayerRef.DropObject(Poisoned, UnpoisonedCount).Disable() EndIf PoisonedWeaponRef.ForceRefTo(PlayerRef.DropObject(Poisoned)) PWeaponRef = PoisonedWeaponRef.GetReference() PlayerRef.AddItem(PWeaponRef, 1, True) PlayerRef.EquipItem(PWeaponRef.GetBaseObject(), False, True) PlayerRef.AddItem(Poisoned, UnpoisonedCount, True) EndIf ElseIf PotionCount == 1 If !PlayerRef.GetItemCount(PotionRef) If akDestContainer akDestContainer.RemoveItem(PotionRef, 1 , False, PlayerRef ) Else PlayerRef.AddItem(PotionRef, Absilent = 1) EndIf Debug.Notification("You can not drop this!") PotionCount = 0 EndIf EndIf EndEvent Edited January 15, 2017 by Masterofnet Link to comment Share on other sites More sharing options...
cdcooley Posted January 15, 2017 Share Posted January 15, 2017 You've added new features and that means you'll need a different structure. Timing issues are best handled with states. I spent many weeks exploring how the inventory functions interact for my Storage Helpers mod and states were the only way I was able to get things to work reliably. And in this case I think it makes the code easier to read. (I've also never needed a wait between the additem and equip but you're original code had one so I left it not knowing if you had a specific reason for using it.) Scriptname PlayerAliasPotion extends ReferenceAlias Int UnpoisonedCount Potion Property ThePotion Auto ObjectReference UnpoisonedStackRef ObjectReference PWeaponRef ObjectReference PotionRef ReferenceAlias Property PotionAlias Auto ReferenceAlias Property PoisonedWeaponRef Auto EVENT OnInit() self.AddInventoryEventFilter(ThePotion) ; The exact poison you are using on the weapon. Debug.Notification("Fired") ENDEVENT Event OnItemRemoved(Form akBaseItem, int aiItemCount, ObjectReference akItemReference, ObjectReference akDestContainer) GoToState("Watching") ; watch for the poison confirmation choice Utility.Wait(0.2) ; give plenty of time for the other event instance to be processed if GetState("Watching") ; return the poison potion if it wasn't used GoToState("") ; prepare for next time Actor PlayerRef = Self.GetReference() As Actor PotionRef = PotionAlias.GetReference() If !PlayerRef.GetItemCount(PotionRef) If akDestContainer akDestContainer.RemoveItem(PotionRef, 1 , False, PlayerRef ) Else PlayerRef.AddItem(PotionRef, Absilent = True) EndIf Debug.Notification("You can not drop this!") EndIf endif EndIf EndEvent State Watching ; for the poison confirmation Event OnItemRemoved(Form akBaseItem, int aiItemCount, ObjectReference akItemReference, ObjectReference akDestContainer) GoToState("") ; this lets the first event instance know that the poison is being applied Actor PlayerRef = Self.GetReference() As Actor PotionRef = PotionAlias.GetReference() Weapon Poisoned = (PlayerRef.GetEquippedWeapon()) UnpoisonedCount = PlayerRef.GetItemCount(Poisoned) - 1 If UnpoisonedCount > 0 UnpoisonedStackRef = PlayerRef.DropObject(Poisoned, UnpoisonedCount) UnpoisonedStackRef.Disable() EndIf PoisonedWeaponRef.ForceRefTo(PlayerRef.DropObject(Poisoned)) PWeaponRef = PoisonedWeaponRef.GetReference() PlayerRef.AddItem(PWeaponRef, 1, True) PlayerRef.EquipItem(PWeaponRef.GetBaseObject(), False, True) PlayerRef.AddItem(Poisoned, UnpoisonedCount, True) EndEvent EndState Link to comment Share on other sites More sharing options...
Masterofnet Posted January 15, 2017 Author Share Posted January 15, 2017 (edited) I got. I can use get distance to 100% tell if a potion has been placed on a weapon. I will update with the script when I get a chance. I did not think this was going to work. Thanks for your help CdCooley and everyone else. Please feel free to comment on the new script if you feel it can be improved. I can't believe it. This script is flawless. You know I keep my threads up to date so that may change but I beat the S*** out of this script and is just laughed at me. 100% perfect every time. Now I need to run down the couple of weapons that may have an issue with Drop. Scriptname PlayerAliasPotion extends ReferenceAlias Potion Property ThePotion Auto ObjectReference Property UnpoisonedStackRef Auto Hidden ObjectReference Property PWeaponRef Auto Hidden ObjectReference Property PotionRef Auto Hidden ReferenceAlias Property PotionAlias Auto ReferenceAlias Property PoisonedWeaponRef Auto Bool Gate Int Distance Weapon Poisoned Actor PlayerRef EVENT OnInit() self.AddInventoryEventFilter(ThePotion) ; The exact poison you are using on the weapon. Debug.Notification("Fired") ENDEVENT Event OnItemRemoved(Form akBaseItem, int aiItemCount, ObjectReference akItemReference, ObjectReference akDestContainer) PlayerRef = Self.GetReference() As Actor PotionRef = PotionAlias.GetReference() If PlayerRef.GetItemCount(ThePotion) Return Else Distance = PlayerRef.GetDistance(PotionRef) as Int If akDestContainer akDestContainer.RemoveItem(PotionRef, 1 , False, PlayerRef ) Debug.Notification("You can not drop this!") Else If Distance < 4000 PlayerRef.AddItem(PotionRef,1,True) Debug.Notification("You can not drop this!") Else WeaponPoisoned() EndIf EndIf EndIf EndEvent Function WeaponPoisoned() Poisoned = (PlayerRef.GetEquippedWeapon()) Int UnpoisonedCount = PlayerRef.GetItemCount(Poisoned) - 1 If UnpoisonedCount > 0 UnpoisonedStackRef = PlayerRef.DropObject(Poisoned, UnpoisonedCount).Disable() EndIf PoisonedWeaponRef.ForceRefTo(PlayerRef.DropObject(Poisoned)) PWeaponRef = PoisonedWeaponRef.GetReference() PlayerRef.AddItem(PWeaponRef, 1, True) PlayerRef.EquipItem(PWeaponRef.GetBaseObject(), False, True) PlayerRef.AddItem(Poisoned, UnpoisonedCount, True) EndFunction Edited January 15, 2017 by Masterofnet Link to comment Share on other sites More sharing options...
cdcooley Posted January 16, 2017 Share Posted January 16, 2017 There's a fairly simple way around the drop bug too but until you had everything else working I didn't want to mention it because it makes the script even messier. You need to use AddInventoryEventFilter on the weapon you're about to drop. You change to a new state watching for the weapon (as a separate but similar state to the one watching for the poison confirmation), then use the OnItemRemoved event in that state to get the reference. You'll only get a reference if the item was persistent and sometimes you'll get the exact same reference you're already getting from DropObject. With careful use of Wait and switching the state (and resetting the inventory event filter) you can get those pesky references for every item. Your code is also not putting back the actual items taken from the player for the unpoisoned ones. In 99.9% of the cases that's fine, but if you're going for absolute safety you need return the items that were dropped UnpoisonedStackRef instead of Poisoned as the first parameter. (And the Disable call has to be done on a separate line.) If the player has a collection of a particular weapon but some have player enchantments, improvements, or are somehow persistent the game may choose to only drop some of them despite the number you pass to DropObject. (The ordinary items get dropped as a group but customized ones may need to be dropped individually.) The fix for that is to make UnpoisonedStackRef an array and simply loop as long as the player has more than one left and store all of the resulting references into the array (including using the trick above to get the reference for any tricky persistent ones) then put back those references using additem on the reference id not the base formid. For this purpose you would certainly be safe just allocating it with 128 elements and keeping your own size variable to know how many you used. Generally it would be just 1 but it could be dozens, especially if the player had just gone on a crafting spree. The game doesn't always stack even ordinary weapons just after they've been crafted or improved. Link to comment Share on other sites More sharing options...
Recommended Posts