Jump to content

Looking for ideas on how to mod the two-shot effect so it uses double ammo


adb3nj

Recommended Posts

 

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

 

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 by LarannKiar
Link to comment
Share on other sites

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

endEvent

Thanks 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 by adb3nj
Link to comment
Share on other sites

 

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

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
endEvent

The 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

 

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

 

 

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)
endEvent

You'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
endEvent

The 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

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

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

  • 4 months later...

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

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...