Jump to content

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


adb3nj

Recommended Posts

The two-shot effect is massively overpowered, so I've been trying to mod it so it costs the player twice as much ammo. The Fallout 3 engine had a built-in way of doing this, but as far as I can tell, the only way of doing it in Fallout 4 is with a script.

 

Does anyone have any ideas for ways to do it elegantly and efficiently? Is there a way to script it so a weapon discharges two rounds simultaneously, or will it have to be a matter of removing the additional round from the player inventory?

Link to comment
Share on other sites

I don't see any way to do that, really. I mean scripting the ammo removal per shot, sure, but that's a bad solution really. You could reduce the ammo capacity in the gun by half but that's a bad solution too. Maybe, on equip you could silently halve the amount of ammo the player has altogether(saving the remainder) and then multiply the current ammo by two(and return the remainder) when unequipping? That technically would achieve the desired effect.

Link to comment
Share on other sites

Create a Quest >> add a new Quest Alias >> fill the Alias with the Player >> Save your plugin >> Open the Quest and the Alias >> attach this script to it >> fill the script property "MyAmmo".

Scriptname YOURSCRIPTNAME extends ReferenceAlias Auto

bool EventBlock			        ; if true, OnItemRemoved won't do anything
Ammo Property MyAmmo Auto Const	        ; Ammo of the weapon


Event OnAliasInit()
	AddInventoryEventFilter(MyAmmo)				        ; Event OnItemRemoved will be received only if akBaseItem (see event below) is MyAmmo
	RegisterForRemoteEvent(Game.GetPlayer(), "OnItemRemoved")	; listen to the event that's being received when MyAmmo gets removed from the Player's inventory (i.e., when shooting)
EndEvent

Event ObjectReference.OnItemRemoved(ObjectReference akSenderRef, Form akBaseItem, int aiItemCount, ObjectReference akItemReference, ObjectReference akDestContainer)
	If EventBlock == False				        ; see below
		Actor PlayerRef = Game.GetPlayer()		; ask the native Game script to get the Player reference and temporarly store it as an actor variable for speed (using "Game.GetPlayer()" all the time makes the process a tiny bit slower)
		If akSenderRef == PlayerRef			; sender object reference is the Player ==> this line is not necessary if there are no other OnItemRemoved registrations (the script can receive OnItemRemoved only if it's sent by the Player)
			If akBaseItem == MyAmmo		        ; this line isn't necessary either due to the inventory event filter
				EventBlock = True		                        ; to prevent the "infinite loop" of removing MyAmmo
				PlayerRef.RemoveItem(MyAmmo, 1, abSilent = True)	; remove 1 MyAmmo silently
				EventBlock = False
			EndIf
		EndIf
	EndIf
EndEvent

See the commented out lines ( the text after ';' ) for more info. The only limitation it is that it doesn't check if there's only one bullet left in the magazine.

Edited by LarannKiar
Link to comment
Share on other sites

Create a Quest >> add a new Quest Alias >> fill the Alias with the Player >> Save your plugin >> Open the Quest and the Alias >> attach this script to it >> fill the script property "MyAmmo".

Scriptname YOURSCRIPTNAME extends ReferenceAlias Auto

bool EventBlock			        ; if true, OnItemRemoved won't do anything
Ammo Property MyAmmo Auto Const	        ; Ammo of the weapon


Event OnAliasInit()
	AddInventoryEventFilter(MyAmmo)				        ; Event OnItemRemoved will be received only if akBaseItem (see event below) is MyAmmo
	RegisterForRemoteEvent(Game.GetPlayer(), "OnItemRemoved")	; listen to the event that's being received when MyAmmo gets removed from the Player's inventory (i.e., when shooting)
EndEvent

Event ObjectReference.OnItemRemoved(ObjectReference akSenderRef, Form akBaseItem, int aiItemCount, ObjectReference akItemReference, ObjectReference akDestContainer)
	If EventBlock == False				        ; see below
		Actor PlayerRef = Game.GetPlayer()		; ask the native Game script to get the Player reference and temporarly store it as an actor variable for speed (using "Game.GetPlayer()" all the time makes the process a tiny bit slower)
		If akSenderRef == PlayerRef			; sender object reference is the Player ==> this line is not necessary if there are no other OnItemRemoved registrations (the script can receive OnItemRemoved only if it's sent by the Player)
			If akBaseItem == MyAmmo		        ; this line isn't necessary either due to the inventory event filter
				EventBlock = True		                        ; to prevent the "infinite loop" of removing MyAmmo
				PlayerRef.RemoveItem(MyAmmo, 1, abSilent = True)	; remove 1 MyAmmo silently
				EventBlock = False
			EndIf
		EndIf
	EndIf
EndEvent
See the commented out lines ( the text after ';' ) for more info. The only limitation it is that it doesn't check if there's only one bullet left in the magazine.
Thanks! I'll give that a test later. Re the 'one bullet' problem: I figured I'd double the ammo capacity so it's always even, although I realised the game only doubles the base weapon capacity, i.e. it doesn't account for magazine mods, so I might have to find another solution for that :) Edited by adb3nj
Link to comment
Share on other sites

I don't see any way to do that, really. I mean scripting the ammo removal per shot, sure, but that's a bad solution really. You could reduce the ammo capacity in the gun by half but that's a bad solution too. Maybe, on equip you could silently halve the amount of ammo the player has altogether(saving the remainder) and then multiply the current ammo by two(and return the remainder) when unequipping? That technically would achieve the desired effect.

Yup, that could work! Or similarly, the mod could change the ammo type, but I'd then have to add different ammo types for every weapon in the game.
Link to comment
Share on other sites

Glad I could help :smile:

 

Anyway, now that I think about it, registering the script for the Player's WeaponFire animation event seems to be a better option.. less exlude conditions needed (as MyAmmo can get removed when selling it, dropping it, etc.).

Scriptname YOURSCRIPTNAME extends ReferenceAlias Const

Ammo Property AmmoToBeRemoved Auto Const
Weapon Property WeaponThatMustBeEquipped Auto Const


Event OnAliasInit()
	RegisterForAnimationEvent(Game.GetPlayer(),"WeaponFire")
EndEvent

Event OnAnimationEvent(ObjectReference akSource, string asEventName)
	Actor PlayerRef = Game.GetPlayer()
	If akSource == PlayerRef && asEventName == "WeaponFire"
		Weapon PlayerEquippedWeapon = PlayerRef.GetEquippedWeapon()
		If PlayerEquippedWeapon && PlayerEquippedWeapon == WeaponThatMustBeEquipped
			PlayerRef.RemoveItem(AmmoToBeRemoved, 1, abSilent = True)
		EndIf
	EndIf
EndEvent
Edited by LarannKiar
Link to comment
Share on other sites

 

Glad I could help :smile:

 

Anyway, now that I think about it, registering the script for the Player's WeaponFire animation event seems to be a better option.. less exlude conditions needed (as MyAmmo can get removed when selling it, dropping it, etc.).

Scriptname YOURSCRIPTNAME extends ReferenceAlias Const

Ammo Property AmmoToBeRemoved Auto Const
Weapon Property WeaponThatMustBeEquipped Auto Const


Event OnAliasInit()
	RegisterForAnimationEvent(Game.GetPlayer(),"WeaponFire")
EndEvent

Event OnAnimationEvent(ObjectReference akSource, string asEventName)
	Actor PlayerRef = Game.GetPlayer()
	If akSource == PlayerRef && asEventName == "WeaponFire"
		Weapon PlayerEquippedWeapon = PlayerRef.GetEquippedWeapon()
		If PlayerEquippedWeapon && PlayerEquippedWeapon == WeaponThatMustBeEquipped
			PlayerRef.RemoveItem(AmmoToBeRemoved, 1, abSilent = True)
		EndIf
	EndIf
EndEvent

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?

Link to comment
Share on other sites

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.

Link to comment
Share on other sites

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'm approaching it a different way and attaching the script to the object mod as an enchantment. So I think the script should literally just be:

Scriptname LegendaryTwoShotScript extends ActiveMagicEffect Const

Event OnEffectStart(Actor akTarget, Actor akCaster)

    akCaster.RemoveItem((akCaster.GetEquippedWeapon()).GetAmmo(), 1, abSilent = True)

EndEvent

Although it's not firing at the moment, so I've probably set it up wrong. With regard to automatic weapons, that's true, but there are automatic weapons with script-based effects in the vanilla game, e.g. the Kneecapper effect. It's part of the reason I was trying to avoid this approach though.

Link to comment
Share on other sites

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.

Link to comment
Share on other sites

  • Recently Browsing   0 members

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