Tefnacht Posted July 3, 2010 Share Posted July 3, 2010 Hello. I have the following “problems” with a weapon script, maybe someone here knows a way around it. My character is a sneak, using primarily bows. After some time I got really tired of all the mini-stacks of two to five arrows of different flavor piling up in my inventory. Its a real hassle to switch back to the inventory every few odd shots to equip new arrows. I finally got so sick of it, that I decided to automate this somehow. I wrote a script attached to “my” bow, that would walk through my inventory, look for arrows, choose the “best” one (enchanted with highest damage if available or just highest damage) and equip them.I have it working pretty well, but it doesn't really satisfy me yet. My first problem: I did not find a CPU-friendly way to execute the script when the bow is fired. Currently I check the quiver slot each and every frame in a GameMode block while the bow is equipped. If the slot is empty, the script will search the best arrow and equip it. I did not notice any rendering slowdown but my computer is a power horse. There must be a better, less “expensive” way to do this? Something more elegant? My second problem: The script will only equip one single arrow (using EquipItemNS), not the whole stack. If I have 20 silver arrows, one will get equipped (and shown as equipped in the inventory screen), the remaining 19 get separated into a second stack. No big deal, really, but this means the ammunition counter in the GUI always shows 1.Of course, with the auto arrow equip, the ammo counter is now pretty useless anyway. But... I play mostly in third person. Since there is technically only one arrow equipped, the quiver on my characters back will disappear when the arrow is used. Of course the auto equip immediately kicks in and equips the next arrow, but for one render frame the quiver is gone. It “flickers” after every shot, if you will. This looks... a bit odd. Funny enough: The amount of arrows rendered in the quiver is always correct. If I have three silver arrows left, there will be three arrows visible in the quiver, although the ammo counter still reads 1. Odd, huh?Is there any way around this? Some trick to equip the whole stack of arrows? For reference, here are the scripts I wrote. OBSE 18 is required. This is the script attached to my bow:ScriptName LYDIABowScript ;******************************************************************************* ; LYDIABowScript (Object script) ;******************************************************************************* ; This script is attatched to the bow and will automagically equip the ; "best" arrow from the player inventory. Short worn ;set to 1 while the bow is equipped Ref arrowref ;reference to the currently equipped arrow Begin OnUnEquip Player Set worn To 0 ;the bow is no longer worn by the player If (arrowref) ;if the player has an arrow equipped Player.UnEquipItemNS arrowref ;unequip the arrow EndIf Set arrowref To 0 ;no arrow equipped anymore End Begin OnEquip Player Set worn To 1 ;the bow is now being worn by the player Set arrowref To Call LYDIAChooseArrow ;choose and equip best arrow from player inventory End Begin GameMode If (worn) ;if the player is wearing the bow If (Player.GetEquippedObject 17 == 0) ;if the player has no item in the quiver slot Set arrowref To Call LYDIAChooseArrow ;choose and equip best arrow from player inventory EndIf EndIf EndAnd this is the OBSE user function script called by the bow script:ScriptName LYDIAChooseArrow ;******************************************************************************* ; LYDIAChooseArrow (User function) ;******************************************************************************* ; This function will choose the best arrow from the player inventory, ; equip it and return a reference to the arrow, or 0 if no arrow was found. ; "Best arrow" means the arrow with the highest damage. If magical ; arrows are available, those will be chosen over mundane arrows, even ; if their damage is lower. Long i ;index counter variable Long j ;total number of inventory objects Long damage ;best found damage so far Ref arrowref ;reference to best arrow so far Ref itemref ;reference of inventory object currently being checked Short ismagic ;set to 1 if a magic arrow was found Long d ;variable with current arrows damage Begin Function {} Set i To 0 ;start with first inventory object Set j To Player.GetNumItems ;get total number of unique inventory objects Set damage To 0 ;best damage found so far is 0 Set arrowref To 0 ;no "best arrow" reference found so far Set ismagic To 0 ;no magical arrows found While (i < j) ;loop over all inventory objects Set itemref To Player.GetInventoryObject i ;get reference to the inventory object If (IsAmmo itemref) ;if this is an arrow Set d To GetAttackDamage itemref ;get that arrows damage If (GetEnchantment itemref) ;if the arrow has a enchantment If (ismagic == 0) ;if this is the first magical arrow we found Set damage To d ;it does best damage (override any mundane arrow) Set arrowref To itemref ;it is the best arrow Set ismagic To 1 ;now we found a magical arrow Else ;otherwise we already found a magical arrow If (d > damage) ;if it does better damage than our current "best" arrow Set damage To d ;it is the new best damage Set arrowref To itemref ;and the new best arrow EndIf EndIf Else ;otherwise the arrow is not enchanted If (d > damage) && (ismagic == 0) ;if it does better damage and we have not found a magical arrow Set damage To d ;this becomes best damage Set arrowref To itemref ;and the arrow is now "best" arrow EndIf EndIf EndIf Set i To i + 1 ;increment to next inventory object Loop If (arrowref) ;if we found a "best" arrow Player.EquipItemNS arrowref ;equip it EndIf SetFunctionValue arrowref ;return what we found EndAny help or comment would be appreciated. Thank you in advance. Link to comment Share on other sites More sharing options...
VesemirTheWitcher Posted July 5, 2010 Share Posted July 5, 2010 ^^ i've got the same darn question. "The script will only equip one single arrow not the whole stack." that's why i feel the urge to bump this up. heh heh "automagically"... by the way, i think if you told it to cycle through the inventory items one time when the bow is equipped and once more every time the equipped arrows have ran out, it would eat up a lot less CPU. but of course, you'll need to figure out the "equip only one arrow" problem, first. Link to comment Share on other sites More sharing options...
Tefnacht Posted July 5, 2010 Author Share Posted July 5, 2010 I think I found a solution for equipping all the arrows. I had to, or shelf the whole idea, because I noticed a serious issues with the two stacks of the same arrow type in the inventory. Imagine this scenario: One arrow got equipped by the script, 19 more are in the second, not equipped stack. I shoot the arrow, but it bounces off a wall. Another arrow gets equipped, 18 are now in the second stack. If I now pick up the arrow I fired first, it is added to the already equipped arrow, so now I have a stack of two arrows equipped and 18 in the second stack. If I shoot now... the equipped stack of two is correctly reduced to one, but the second stack of 18 goes poof and vanishes. After a short dungeon crawl I was wondering where all my hundred daedric arrows went... heh. The trick seems to be to remove all but one arrow of the stack from the player inventory, then equip that single arrow and then add back all the previously removed arrows. Since we're not really adding or removing items, just adding and subtracting from a stack, there seems to be no problem with doing this in a single frame. This is how I modified my LYDIAChooseArrow script. This stuff comes after the Loop:If (arrowref) ;if we found a "best" arrow Set i To Player.GetItemCount arrowref ;get amount of arrows in inventory If (i > 1) ;if there is more than one Set i To i - 1 ;calculate how many more than one Player.RemoveItemNS arrowref i ;and remove all but one Else ;otherwise there is just one Set i To 0 ;we did not have to remove any EndIf Player.EquipItemNS arrowref ;equip the one remaining arrow If (i) ;if we removed arrows Player.AddItemNS arrowref i ;add them back to the player EndIf EndIf SetFunctionValue arrowref ;return what we foundOf course, there is no free lunch. While the whole stack of arrows now gets equipped correctly (and the ammo counter works again) the amount of arrows rendered in the quiver is now wrong. There is always only one single arrow rendered in the quiver. Picking up another arrow corrects this though and it is really only a “cosmetic” problem. But it is still not a perfect solution. Link to comment Share on other sites More sharing options...
VileTouch Posted July 8, 2010 Share Posted July 8, 2010 i think you might want to look into Duke Patrick's Archery mod's scripts. there is an instance where the script auto equips a batch of arrows once they run out if you are close enough to the arrow case. that might be of some use. Link to comment Share on other sites More sharing options...
Tefnacht Posted July 9, 2010 Author Share Posted July 9, 2010 Thanks a lot for the tip, VileTouch. I'll go take a look at that mod right away. This is really driving me crazy (laughs) and not the good kind of crazy. Yesterday I found a “almost free lunch” solution after hours of trying, thinking and more trying. It seems to work well, the ammo counter is correct, there is just one stack, rendering of the quiver is right, but it requires dropping of one item into the gameworld every time the script has to equip more than one arrow... which, from my understanding, will lead to savegame bloating, very slow bloating, but bloating nonetheless. So... not quite a “free” lunch, but at least a cheap one. Here is my newest solution. Its not fully tested yet, but besides the bloating problem (which might not even exist, no idea, need more testing) it looks promising. This time, instead of removing the arrows and then adding them back, all but one arrow get dropped as a stack into the gameworld, then the one remaining arrow is equipped, and then the script scans through the cell the player is in until it finds the stack we dropped, and picks it up again. All in one frame, so the player will not notice any of the jazz that is going on behind his back. It looks great from third person view. Again, this comes after the Loop in the LYDIAChooseArrow script:If (arrowref) ;if we found a "best" arrow Set i To Player.GetItemCount arrowref ;get amount of arrows in the players inventory If (i > 1) ;if there is more than one Set i To i - 1 ;calculate how many more than one Player.Drop arrowref i ;drop all but one arrow as a stack into the gameworld Else ;otherwise we have only one arrow Set i To 0 ;and did not have to drop any EndIf Player.EquipItemNS arrowref ;equip the single arrow If (i) ;if we dropped arrows into the gameworld Set itemref To GetFirstRef 34 1 ;start scanning the current call for ammo (and 8 adjacent cells, in case we are standing on a cell border) While (itemref) ;as long as we find ammo references If (itemref.GetBaseObject == arrowref) && (itemref.GetRefCount == i) ;if the reference is a child of our arrow base and a stack of matching size itemref.Activate Player ;make the player pick up the stack Set itemref To 0 ;set itemref to 0 to leave the loop, we have found what we were looking for Else ;otherwise it is some other arrow Set itemref To GetNextRef ;scan for next ammo reference EndIf Loop EndIf EndIf SetFunctionValue arrowref ;return what we foundAll that just to equip some damned arrows (laughs). Hopefully Duke Patrick found a better solution... Link to comment Share on other sites More sharing options...
Tefnacht Posted July 15, 2010 Author Share Posted July 15, 2010 I was unable to find the mod made by Duke Patrik that VileTouch referred me to, so instead I just concentrated on testing my solution. I have now been using this script for a couple of days of intense marksmanship and it seems to work well. I couldn't find any problems with it. There is another “wrong amount of arrows rendered in the quiver”-glitch when the game was restarted and a savegame is loaded that was made with the arrows equipped, but that is a vanilla Oblivion problem (that I never noticed before). In this case the quiver always looks completely full, even if there should be just one arrow in it. But that is Oblivions fault, it happens without my script too. Also, the quiver rendering is not updated if you loot arrows of the type you have equipped from a actors inventory or a container. Again, this is a vanilla bug. Both are only visual and so rare, I decided not to try scripting a workaround. The bloating problem exists, however. But it is not “persistent” bloating, as far as I can tell. The savegame bloats the same way it does when a normal arrow is shot into the gameworld. After three ingame days, when a cell reset occurs, the garbage is cleared. So I think, my last solution, dropping all but one arrow into the gameworld, equipping the remaining arrow, then searching and picking up the dropped stack again is the best working way to do this. The bloating is negligible and not permanent. There are many vanilla Oblivion actions that cause much worse savegame bloat. This method should be save to use. With this conclusion, I consider my problem solved. Thanks again to those who posted comments. I do not claim credit for the method or the script itself, feel free to use it (or parts of it) if you need to equip arrows on the player within your own mods. Have fun. Link to comment Share on other sites More sharing options...
VileTouch Posted July 19, 2010 Share Posted July 19, 2010 you could have asked for the link... i thought i had put it here... well,sorry, my bad..this mod can be a little elusive so here's the official thread. the Actual file is in TesAlliance though, but you'll get everything you need there. Including the chance that Duke Patrick himself give you permission to use his scripts. http://forums.bethsoft.com/index.php?/topic/1093453-relz-duke-patricks-combat-archery-mod-thread-2/page__hl__duke%20patrick%20combat%20archery Link to comment Share on other sites More sharing options...
mitchalek Posted November 4, 2011 Share Posted November 4, 2011 (edited) I have a solution. Retrieve intentory reference of a stack and then call EquipMe on that reference. let invRefAmmo := *(player.GetInvRefsForItem Arrow3Silver) ; unbox array to get first reference of silver arrows invRefAmmo.EquipMe ; you get whole stack equipped and no message spam Edit: Forget it, seems only to work first time after stack of arrows has been added. Edited November 5, 2011 by mitchalek Link to comment Share on other sites More sharing options...
WarRatsG Posted November 4, 2011 Share Posted November 4, 2011 To cut down on the scripting and make sure it runs only when an arrow is fired, you could set an event handler. It would be quite simple I think... ; LYDIABowScript (Object script) ;******************************************************************************* ; This script is attatched to the bow and will automagically equip the ; "best" arrow from the player inventory. Short worn ;set to 1 while the bow is equipped Ref arrowref ;reference to the currently equipped arrow Begin OnUnEquip Player Set worn To 0 ;the bow is no longer worn by the player If (arrowref) ;if the player has an arrow equipped Player.UnEquipMe arrowref ;unequip the arrow [using UnEquipMe like mitchalek said] EndIf Set arrowref To 0 ;no arrow equipped anymore RemoveEventHandler ;To avoid problems when using other weapons End Begin OnEquip Player Set worn To 1 ;the bow is now being worn by the player Set arrowref To Call LYDIAChooseArrow ;choose and equip best arrow from player inventory SetEventHandler OnRelease LYDIAReleaseEventSCRIPT ref::Player ;The event "OnRelease" occurs whenever the actor finishes an attack End Now what used to be the GameMode block is now only executed after each shot. You will need a way of extracting the arrowref from the event handler, because they have no function values, but I think this should be enough to get you started. You seem like you know your way around a script editor. Hope this helped :) Link to comment Share on other sites More sharing options...
Recommended Posts