adb3nj Posted January 23, 2023 Author Share Posted January 23, 2023 Whilst papyrus is not good for high performance real time solutions like auto weapon fire, its all we got (without DLL injection) so WeaponFire animation event is the least worst option. It *is* better than OnPlayerFireWeapon used in FollowersScript tho. Since mod_legendary_weapon_twoShot is simply adding +1 uNumProjectiles it is unlikely to trigger OnEffectStart except maybe once when the OMOD is applied to the weapon. Haha, yes, I've just discovered that! It fires when the weapon is equipped. I'll try OnAnimationEvent as per your and LarannKiar's suggestion. Link to comment Share on other sites More sharing options...
LarannKiar Posted January 23, 2023 Share Posted January 23, 2023 (edited) Thanks again! Is there a mistake at 'If PlayerEquippedWeapon' though? Is there supposed to be some condition other than PlayerEquippedWeapon && PlayerEquippedWeapon == WeaponThatMustBeEquipped? Or is that a check to see if the player has a weapon equipped at all? Larann, I see what you're going for, but the problem is that almost any random weapon in the game can get this effect, it's the vanilla Two-Shot Legendary weapon effect, you can't pre-define a specific weapon for it in properties. You could perhaps check for it in equipped keywords though.Also I'd keep in mind that if this effect ends up on an automatic rifle, that script will be firing(pun intended) a whole lot, like really often. I forgot about it yes.. :smile: With Keyword-check, it should be fine: If PlayerRef.WornHasKeyword(HasLegendary_Weapon_TwoShot) == 1 Don't forget to add this property to the script: Keyword Property HasLegendary_Weapon_TwoShot Auto Const Regarding the automatic guns, well.. it's as fast as it can be. I don't have any other ideas but indeed make sure not to add too many conditions in the animations event. Edited January 23, 2023 by LarannKiar Link to comment Share on other sites More sharing options...
adb3nj Posted January 23, 2023 Author Share Posted January 23, 2023 (edited) Added it as an enchantment set to act constantly, with the following script: Scriptname LegendaryTwoShotScript extends ActiveMagicEffect Const Actor Property PlayerRef Auto Const Event OnEffectStart(Actor akTarget, Actor akCaster) RegisterForAnimationEvent(PlayerRef,"WeaponFire") endEvent Event OnAnimationEvent(ObjectReference akSource, string asEventName) If akSource == PlayerRef && asEventName == "WeaponFire" Weapon MyWeapon = PlayerRef.GetEquippedWeapon() Ammo MyAmmo = MyWeapon.GetAmmo() PlayerRef.RemoveItem(MyAmmo, 1, abSilent = true) EndIf endEventThanks everyone for your help! The slightly unsatisfying thing is, it removes unloaded ammo rather than ammo in the magazine, but I'm not sure changing the amount of ammo in the magazine is possible with a script? I can't find anything on the wiki or in the base script sources. Edited January 24, 2023 by adb3nj Link to comment Share on other sites More sharing options...
Fantafaust Posted January 24, 2023 Share Posted January 24, 2023 The slightly unsatisfying thing is, it removes unloaded ammo rather than ammo in the magazine, but I'm not sure changing the amount of ammo in the magazine is possible with a script? I can't find anything on the wiki or in the base script sources.That's why I was saying it was a bad solution. F4SE might have a way, but I have yet to find it. Scriptname LegendaryTwoShotScript extends ActiveMagicEffect Actor Property PlayerRef Auto Ammo Property MyAmmo Auto GlobalVariable Property TwoShotWeaponEquipped Auto Bool RemainderAmmo = False Import Math Event OnEffectStart(Actor akTarget, Actor akCaster) TwoShotWeaponEquipped.SetValue(1.0) Weapon MyWeapon = PlayerRef.GetEquippedWeapon();get the weapon with the effect MyAmmo = MyWeapon.GetAmmo();get the ammo to remove Int AmmoCount = PlayerRef.GetItemCount(MyAmmo)/2;get how much ammo player has, halved If AmmoCount-Floor(AmmoCount) > 0;check halved ammo against halved ammo rounded down RemainderAmmo = True;set bool if true, don't wanna lose any ammo EndIf PlayerRef.RemoveItem(MyAmmo, Ceiling(AmmoCount), True);remove halved ammo rounded up, includes having only one round ;you can't shoot the gun with "insufficient" ammo, and saves the remainder to be returned when unequipping endEvent Event OnEffectFinish(Actor akTarget, Actor akCaster) TwoShotWeaponEquipped.SetValue(0.0) Int AmmoCount = PlayerRef.GetItemCount(MyAmmo)*2;save time by just multiplying here If RemainderAmmo == True PlayerRef.AddItem(MyAmmo, AmmoCount+1, True);add back the remainder round with doubled current ammo Else PlayerRef.AddItem(MyAmmo, AmmoCount, True);only add doubled amount EndIf ;even if player had all ammo removed due to having one round before equipped, OR used all "two shot" ammo while equipped, player still gets one round back if remainder was true thus no ammo lost endEvent As discussed, this would simulate the gun only being able to fire two rounds at a time.EDIT: thinking about it, you might also want to throw a script on a Player RefAlias to halve the same ammo when being picked up while the weapon is equipped. That would prevent the player from dropping ammo, swapping to the weapon, then picking up the ammo and unequipping; multiplying their ammo to absurd levels. Also, multiply by two when dropping the ammo while equipped. That way it always stays the same. Link to comment Share on other sites More sharing options...
adb3nj Posted January 24, 2023 Author Share Posted January 24, 2023 Scriptname LegendaryTwoShotScript extends ActiveMagicEffect As discussed, this would simulate the gun only being able to fire two rounds at a time.EDIT: thinking about it, you might also want to throw a script on a Player RefAlias to halve the same ammo when being picked up while the weapon is equipped. That would prevent the player from dropping ammo, swapping to the weapon, then picking up the ammo and unequipping; multiplying their ammo to absurd levels. Also, multiply by two when dropping the ammo while equipped. That way it always stays the same. Thanks! Just FYi, there's a slight error in your code – on effect finish, there's no need to double the ammo amount before adding it back. Also I'm having problems with the adding/removing ammo scripts. This is what I have: Scriptname LegendaryTwoShotQuestScript extends ReferenceAlias Actor Property PlayerRef Auto Ammo Property MyAmmo Auto Event OnInit() debug.notification("Quest initialized") Weapon MyWeapon = PlayerRef.GetEquippedWeapon() MyAmmo = MyWeapon.GetAmmo() endEvent Event OnItemAdded(Form akBaseItem, int aiItemCount, ObjectReference akItemReference, ObjectReference akDestContainer) debug.notification("Item added") AddInventoryEventFilter(MyAmmo) If akBaseItem == MyAmmo ;not sure if I need this as well as the event filter debug.notification("Ammo added") Int AmmoToSubtract = aiItemCount/2 PlayerRef.RemoveItem(MyAmmo, AmmoToSubtract, true) ;will get to half bullets later EndIf endEvent Event OnItemRemoved(Form akBaseItem, int aiItemCount, ObjectReference akItemReference, ObjectReference akDestContainer) AddInventoryEventFilter(MyAmmo) If akBaseItem == MyAmmo akItemReference.AddItem(MyAmmo, aiItemCount, true) ;not entirely expecting this to work EndIf endEventThe quest is initializing (for some reason it's initializing on game start despite that being unflagged) but nothing is firing after OnItemAdded. Link to comment Share on other sites More sharing options...
Fantafaust Posted January 24, 2023 Share Posted January 24, 2023 Thanks! Just FYi, there's a slight error in your code – on effect finish, there's no need to double the ammo amount before adding it back. Also I'm having problems with the adding/removing ammo scripts. This is what I have:The quest is initializing (for some reason it's initializing on game start despite that being unflagged) but nothing is firing after OnItemAdded. Mathematically you do have to double it, because we're not restoring the amount that was removed, we're separating the 2 rounds sets from each other. If you had 400 rounds and we remove half to simulate double-shot ammo, you have 200 sets of shots. If you shoot those 50 times, you've spent 100 regular rounds. If we just restored the ammocount instead of doubling the current amount, you wouldn't be down 100 rounds, you'd only be down 50. 400/2=200, 200-50=150, 150+200=350 that would be standard usage of 1 round per shot. What we want is 400/2=200, 200-50=150, 150*2=300, two ammo per shot. The reason your RefAlias script isn't working is because you need to register for Inventory events in the OnInit(), because the OnItemAdded() isn't looked for without being registered for first, also you do want the quest to run on game start. Scriptname LegendaryTwoShotQuestScript extends ReferenceAlias Actor Property PlayerRef Auto GlobalVariable Property TwoShotWeaponEquipped Auto Import Math Event OnInit() debug.notification("Two Shot quest initialized") AddInventoryEventFilter(None);can't know what the ammo is yet since we need to be looking for these events all the time, with no filter it'll check all OnItemAdded() events endEvent Event OnItemAdded(Form akBaseItem, int aiItemCount, ObjectReference akItemReference, ObjectReference akSourceContainer) If TwoShotWeaponEquipped.GetValue() == 1.0;only modify ammo if the weapon is equipped Weapon MyWeapon = PlayerRef.GetEquippedWeapon();since we know the right kind of weapon is equipped, start checking ammo Ammo MyAmmo = MyWeapon.GetAmmo() debug.notification("Item added") If akBaseItem == MyAmmo && akSourceContainer != None;this is necessary like you thought, just needs a bit more to see if you picked it up off the ground debug.notification("two-shot ammo added") Int AmmoToSubtract = aiItemCount/2 If AmmoToSubtract-Floor(AmmoToSubtract) > 0;pretty easy to handle half rounds akSourceContainer.AddItem(MyAmmo, 1);we'll leave the lone round in the container Debug.Notification("With this weapon equipped, you can only acquire this ammo in sets of two.") EndIf PlayerRef.RemoveItem(MyAmmo, Ceiling(AmmoToSubtract), true) ElseIf akBaseItem == MyAmmo && akSourceContainer == None debug.notification("two-shot ammo found") Int AmmoToSubtract = aiItemCount/2 If AmmoToSubtract-Floor(AmmoToSubtract) > 0 PlayerRef.PlaceAtMe(MyAmmo, 1);we'll leave the lone round on the ground Debug.Notification("With this weapon equipped, you can only acquire this ammo in sets of two.") EndIf PlayerRef.RemoveItem(MyAmmo, Ceiling(AmmoToSubtract), true) EndIf EndIf endEvent Event OnItemRemoved(Form akBaseItem, int aiItemCount, ObjectReference akItemReference, ObjectReference akDestContainer) If TwoShotWeaponEquipped.GetValue() == 1.0 Weapon MyWeapon = PlayerRef.GetEquippedWeapon() Ammo MyAmmo = MyWeapon.GetAmmo() If akBaseItem == MyAmmo && akSourceContainer != None akDestContainer.AddItem(MyAmmo, aiItemCount, true);we'll add the ammo count to the container again thus doubling it ElseIf akBaseItem == MyAmmo && akSourceContainer == None PlayerRef.PlaceAtMe(MyAmmo, aiItemCount, true);we just have to drop the same amount you dropped EndIf EndIf endEvent Edited my first script to handle the globalvariable for this refalias script, you'll need to make the GlobalVariable yourself of course. Make sure to fill your properties :smile: Link to comment Share on other sites More sharing options...
adb3nj Posted January 24, 2023 Author Share Posted January 24, 2023 Thanks! Just FYi, there's a slight error in your code – on effect finish, there's no need to double the ammo amount before adding it back. Also I'm having problems with the adding/removing ammo scripts. This is what I have:The quest is initializing (for some reason it's initializing on game start despite that being unflagged) but nothing is firing after OnItemAdded. Mathematically you do have to double it, because we're not restoring the amount that was removed, we're separating the 2 rounds sets from each other. If you had 400 rounds and we remove half to simulate double-shot ammo, you have 200 sets of shots. If you shoot those 50 times, you've spent 100 regular rounds. If we just restored the ammocount instead of doubling the current amount, you wouldn't be down 100 rounds, you'd only be down 50. 400/2=200, 200-50=150, 150+200=350 that would be standard usage of 1 round per shot. What we want is 400/2=200, 200-50=150, 150*2=300, two ammo per shot. Right, but that isn't what your script does. Event OnEffectFinish(Actor akTarget, Actor akCaster) Int AmmoCount = PlayerRef.GetItemCount(MyAmmo)*2 PlayerRef.AddItem(MyAmmo, AmmoCount, True) endEventYou're getting the current (halved) ammo count, doubling it, and then adding it to itself – so in effect trebling it. PlayerRef.GetItemCount(MyAmmo) = 150; AmmoCount = 150*2 = 300; and then you add that 300 to the inventory, but there's already 150 in there, so you get 450. I've tested it and that's what it does. With regard to the second script, I didn't realise AddInventoryEventFilter registered the OnItem events, so I just needed to move that to the OnInit event. I was initiating the quest with the weapon enchantment, so it didn't need to run on game start, although I can just add it directly to the enchantment. My plan for half bullets was to keep them in a float, check the float value every time more bullets are added, and transfer them to the inventory whenever they reach a whole number. Until then, my script is: Scriptname LegendaryTwoShotScript extends ActiveMagicEffect Actor Property PlayerRef Auto Ammo Property MyAmmo Auto Bool RemainderAmmo = False Bool ItemAdded = False ;because OnItemRemoved is apparently triggered when an item is added Import Math Event OnEffectStart(Actor akTarget, Actor akCaster) Weapon MyWeapon = PlayerRef.GetEquippedWeapon() MyAmmo = MyWeapon.GetAmmo() ;get the ammo to remove Int AmmoCount = PlayerRef.GetItemCount(MyAmmo)/2 ;get how much ammo player has and half it If AmmoCount-Floor(AmmoCount) > 0 ;check halved ammo against halved ammo rounded down RemainderAmmo = True ;set bool if true, don't wanna lose any ammo EndIf PlayerRef.RemoveItem(MyAmmo, Ceiling(AmmoCount), True) ;remove halved ammo rounded up, includes having only one round AddInventoryEventFilter(MyAmmo) ;MyAmmo filter removes need for conditional later endEvent Event OnItemAdded(Form akBaseItem, int aiItemCount, ObjectReference akItemReference, ObjectReference akSourceContainer) ItemAdded = true Int AmmoToSubtract = aiItemCount/2 PlayerRef.RemoveItem(MyAmmo, AmmoToSubtract, true) Utility.Wait(0.5) ItemAdded = false endEvent Event OnItemRemoved(Form akBaseItem, int aiItemCount, ObjectReference akItemReference, ObjectReference akDestContainer) Utility.Wait(0.1) If ItemAdded == false ;make sure an item hasn't actually been added If akDestContainer != None akDestContainer.AddItem(MyAmmo, aiItemCount, true) ;add deposited amount of ammo to the container again Else PlayerRef.PlaceAtMe(MyAmmo, aiItemCount, true) ;place dropped amount of ammo at player again EndIf EndIf endEvent Event OnEffectFinish(Actor akTarget, Actor akCaster) Int AmmoCount = PlayerRef.GetItemCount(MyAmmo) If RemainderAmmo == True PlayerRef.AddItem(MyAmmo, AmmoCount+1, True) ;double ammo and add back remainder amount Else PlayerRef.AddItem(MyAmmo, AmmoCount, True) ;double ammo EndIf endEventThe problem I'm having now is picking up the relevant ammo triggers OnItemRemoved as well as OnItemAdded. I can't remember if I tested it while adding the script to a player alias. Adding the ItemAdded bool is my current workaround, but it's only any good if I'm not picking up multiple ammo boxes in quick succession. Link to comment Share on other sites More sharing options...
Fantafaust Posted January 24, 2023 Share Posted January 24, 2023 Oof, my bad lol, I missed that I didn't need to double it manually in the first script even though I realized it in the second script :facepalm: Hmm. The script is triggering both because the script is also removing ammo when you yourself pick up ammo. You could perhaps remove the Inventory event filter at the beginning of the OnItemAdded() block, then add it again at the end of the block? maybe: Event OnItemAdded(Form akBaseItem, int aiItemCount, ObjectReference akItemReference, ObjectReference akSourceContainer) RemoveInventoryEventFilter(MyAmmo) Int AmmoToSubtract = aiItemCount/2 PlayerRef.RemoveItem(MyAmmo, AmmoToSubtract, true) Utility.Wait(0.1) AddInventoryEventFilter(MyAmmo) endEvent Link to comment Share on other sites More sharing options...
adb3nj Posted January 25, 2023 Author Share Posted January 25, 2023 The script is triggering both because the script is also removing ammo when you yourself pick up ammo. Oh yeah, of course it is! I forgot that was how we were doing it. I'll have another look tomorrow - for now, I've moved back to the previous method of deducting one unit of ammo for every shot fired... Link to comment Share on other sites More sharing options...
Fantafaust Posted May 25, 2023 Share Posted May 25, 2023 I made a working version of my halving ammo concept, btw. It just needed a Wait to stop it from doubling ammo during the initial halve. I'm gonna upload it today, if it isn't sufficient for your purposes there is still the per shot method I suppose. Link to comment Share on other sites More sharing options...
Recommended Posts