Magnusen2 Posted August 21, 2016 Share Posted August 21, 2016 (edited) SummonedFurnitureReference = akCaster.PlaceAtMe(unsummonFX) SummonedFurnitureReference.placeatme(SummonedFurniture) SummonedFurnitureReference.setAngle(0, 0, akCaster.getAngleZ()) I'm making some summon spells for my mod to summon furniture (beds/workbenches/etc). Problem is: The object summons right were the player is (below the player to be more specific). I would like to make them summon at the location of the crosshair, just like other summons spells. Any papyrus function that i can use in the script piece above to accomplish this? Using "Aimed" on the MGEF and then using "akTarget" instead of "akCaster" maybe? Edited August 21, 2016 by Magnusen2 Link to comment Share on other sites More sharing options...
cdcooley Posted August 22, 2016 Share Posted August 22, 2016 If you simply wanted to place the item directly in front of the player at a usable position here's a function that should do the job. Actor Property PlayerRef Auto Function PlaceInFrontOfPlayer(ObjectReference targetItem, float distanceOffset = 150.0, float heightOffset = 0.0, float angleOffset = 0.0) {Place targetItem directly in front of oriented towards the player. The offsetValues may need to be changed for different objects.} float playerAngleZ = PlayerRef.GetAngleZ() float angZ = playerAngleZ + angleOffset float posX = PlayerRef.GetPositionX() + distanceOffset * Math.Sin(playerAngleZ) float posY = PlayerRef.GetPositionY() + distanceOffset * Math.Cos(playerAngleZ) float posZ = PlayerRef.GetPositionZ() + heightOffset targetItem.TranslateTo(posX, posY, posZ, 0.0, 0.0, angZ, 99999) ; Alternately SetPosition and SetAngle could be used, but I prefer TranslateTo EndFunction If you really want it to work like summoned creatures by placing at the crosshair then I can tell you how SmartBlueCat set up Inigo's summon spell. The placement is actually handled by the spell effect itself not the script (except for a need to adjust the object's angle). The only thing set up that same way in the original game is the VoiceThrowVoiceEffect. You can either look at it or Inigo's summoning spell. You want a Fire and Forget, Target Location type spell. Then you need a unique magic effect with the Archtype that will spawn a scripted reference. And that effect will need a custom Explosion that places the actual scripted object. In Inigo's case it's a simple marker with a script that moves him to it then deletes itself. In your case it could be the actual furniture item. Unfortunately the item will be oriented based on the way the player was pointing so you'll want to have it self-correct the angles in its own script (Inigo doesn't have that problem because actors get reoriented automatically). Inigo's actual script isn't all that helpful here. You'll have to decide if you want to re-use generic furniture or use custom furniture. If you use generic furniture you'll need to create marker that can be spawned by the explosion which can then move or spawn a furniture item. If you use custom furniture items you can simply have the explosion spawn it directly and add a script to get it oriented reasonably and deal with anything else that's needed later (like removing itself after some period of time or when the player leaves the cell). The basic script for re-orienting the object would be simple (although you might need to add or subtract 180 or some other angle from the player's angle depending on the furniture object). ScriptName RepositionOnLoad extends ObjectReference Event OnLoad() SetAngle(0,0,Game.GetPlayer().GetAngleZ()) EndEvent Any extra visual effects can be handled by the actual magic effect or explosion. Link to comment Share on other sites More sharing options...
Magnusen2 Posted August 22, 2016 Author Share Posted August 22, 2016 (edited) If you simply wanted to place the item directly in front of the player at a usable position here's a function that should do the job. Actor Property PlayerRef Auto Function PlaceInFrontOfPlayer(ObjectReference targetItem, float distanceOffset = 150.0, float heightOffset = 0.0, float angleOffset = 0.0) {Place targetItem directly in front of oriented towards the player. The offsetValues may need to be changed for different objects.} float playerAngleZ = PlayerRef.GetAngleZ() float angZ = playerAngleZ + angleOffset float posX = PlayerRef.GetPositionX() + distanceOffset * Math.Sin(playerAngleZ) float posY = PlayerRef.GetPositionY() + distanceOffset * Math.Cos(playerAngleZ) float posZ = PlayerRef.GetPositionZ() + heightOffset targetItem.TranslateTo(posX, posY, posZ, 0.0, 0.0, angZ, 99999) ; Alternately SetPosition and SetAngle could be used, but I prefer TranslateTo EndFunction If you really want it to work like summoned creatures by placing at the crosshair then I can tell you how SmartBlueCat set up Inigo's summon spell. The placement is actually handled by the spell effect itself not the script (except for a need to adjust the object's angle). The only thing set up that same way in the original game is the VoiceThrowVoiceEffect. You can either look at it or Inigo's summoning spell. You want a Fire and Forget, Target Location type spell. Then you need a unique magic effect with the Archtype that will spawn a scripted reference. And that effect will need a custom Explosion that places the actual scripted object. In Inigo's case it's a simple marker with a script that moves him to it then deletes itself. In your case it could be the actual furniture item. Unfortunately the item will be oriented based on the way the player was pointing so you'll want to have it self-correct the angles in its own script (Inigo doesn't have that problem because actors get reoriented automatically). Inigo's actual script isn't all that helpful here. You'll have to decide if you want to re-use generic furniture or use custom furniture. If you use generic furniture you'll need to create marker that can be spawned by the explosion which can then move or spawn a furniture item. If you use custom furniture items you can simply have the explosion spawn it directly and add a script to get it oriented reasonably and deal with anything else that's needed later (like removing itself after some period of time or when the player leaves the cell). The basic script for re-orienting the object would be simple (although you might need to add or subtract 180 or some other angle from the player's angle depending on the furniture object). ScriptName RepositionOnLoad extends ObjectReference Event OnLoad() SetAngle(0,0,Game.GetPlayer().GetAngleZ()) EndEvent Any extra visual effects can be handled by the actual magic effect or explosion. Uh i got lost here. Since i'm using formlists to get the furniture references i guess the first method would be best (in this way i don't need to create new furniture and attach scripts to them). Then make the MGEF a self cast spell (sort of like grand healing but without the FX) and spawn the object a meter or two in front of the player. FormList property FurnitureList auto String property SummonedFurnitureMessage auto ObjectReference property SummonedFurnitureReference = None Auto GlobalVariable Property FurnitureLimit auto Activator property unsummonFX auto Event OnEffectStart(Actor akTarget, Actor akCaster) float randomWait = Utility.randomFloat(0, 0.25) Utility.wait(randomWait) if (FurnitureLimit.getValue() > 0) debug.notification(SummonedFurnitureMessage) self.dispel() return; endIf FurnitureLimit.setValue(1) Spell leftHandSpell = akCaster.getEquippedSpell(0) Spell rightHandSpell = akCaster.getEquippedSpell(1) float spellMagnitude = 0 int spellMagicEffectIndex = 0 while spellMagicEffectIndex < leftHandSpell.getNumEffects() MagicEffect effect = leftHandSpell.getNthEffectMagicEffect(spellMagicEffectIndex) if (effect == self.getBaseObject()) spellMagnitude = leftHandSpell.getNthEffectMagnitude(spellMagicEffectIndex) endIf spellMagicEffectIndex += 1 endWhile FormList FurnitureToSummon = FurnitureList int randomIndex = Utility.RandomInt(0, FurnitureToSummon.GetSize() - 1) Form SummonedFurniture = FurnitureToSummon.getAt(randomIndex) SummonedFurnitureReference = akTarget.PlaceAtMe(SummonedFurniture) SummonedFurnitureReference.placeatme(unsummonFX) SummonedFurnitureReference.setAngle(0, 0, akCaster.getAngleZ()) EndEvent Do i need to call the function that you provided in the magic effect above? (Sorry for being a Noob). Edited August 22, 2016 by Magnusen2 Link to comment Share on other sites More sharing options...
cdcooley Posted August 23, 2016 Share Posted August 23, 2016 Yes, just add my function to your script then replace that SetAngle function call at the end of your OnEffectStart event with: PlaceInFrontOfPlayer(SummonedFurnitureReference) And if that ends up putting it to close or two far away or facing the wrong direction you can adjust the position by adding the other parameters. PlaceInFrontOfPlayer(SummonedFurnitureReference, 200.0, 0.0, 180.0) It will actually look better if you replace those last few lines like this: Form SummonedFurniture = FurnitureToSummon.getAt(randomIndex) SummonedFurnitureReference = akTarget.PlaceAtMe(SummonedFurniture, 1, false, true) ; start it disabled PlaceInFrontOfPlayer(SummonedFurnitureReference) ; move it into position SummonedFurnitureReference.placeatme(unsummonFX) ; start playing the special effect at that spot SummonedFurnitureReference.Enable(true) ; now let it fade in (take off the true if you want it to pop in) Link to comment Share on other sites More sharing options...
Magnusen2 Posted August 23, 2016 Author Share Posted August 23, 2016 Yes, just add my function to your script then replace that SetAngle function call at the end of your OnEffectStart event with: PlaceInFrontOfPlayer(SummonedFurnitureReference) And if that ends up putting it to close or two far away or facing the wrong direction you can adjust the position by adding the other parameters. PlaceInFrontOfPlayer(SummonedFurnitureReference, 200.0, 0.0, 180.0) It will actually look better if you replace those last few lines like this: Form SummonedFurniture = FurnitureToSummon.getAt(randomIndex) SummonedFurnitureReference = akTarget.PlaceAtMe(SummonedFurniture, 1, false, true) ; start it disabled PlaceInFrontOfPlayer(SummonedFurnitureReference) ; move it into position SummonedFurnitureReference.placeatme(unsummonFX) ; start playing the special effect at that spot SummonedFurnitureReference.Enable(true) ; now let it fade in (take off the true if you want it to pop in) Added your function to the script and that piece of code to the end of the OnEffectStart. Tested and the furniture spawned right below the player as before. Then i messed up with the 3 parameters on the PlaceInFrontOfPlayer(SummonedFurnitureReference, 200.0, 0.0, 180.0) I set them to high amounts and the furniture still spawned below the player. Form SummonedFurniture = FurnitureToSummon.getAt(randomIndex) SummonedFurnitureReference = akTarget.PlaceAtMe(SummonedFurniture, 1, false, true) ; start it disabled PlaceInFrontOfPlayer(SummonedFurnitureReference, 200.0, 0.0, 180.0) ; move it into position SummonedFurnitureReference.setAngle(0, 0, akCaster.getAngleZ()) SummonedFurnitureReference.placeatme(unsummonFX) ; start playing the special effect at that spot SummonedFurnitureReference.Enable(true) ; now let it fade in (take off the true if you want it to pop in) I added the setAngle line because the furniture spawned with a incorrect angle, and the line fixed it. Link to comment Share on other sites More sharing options...
cdcooley Posted August 24, 2016 Share Posted August 24, 2016 OK, the problem is probably because I used the TranslateTo function instead of SetPosition and SetAngle. (And I do that because when I use that function I'm trying to move items dropped by the player and using SetPosition and SetAngle doesn't work for those but TranslateTo does.) You can try changing my line: targetItem.TranslateTo(posX, posY, posZ, 0.0, 0.0, angZ, 99999) to targetItem.SetPosition(posX, posY, posZ) targetItem.SetAngle(0.0, 0.0, angZ) and then you wouldn't need the extra setAngle you added. Link to comment Share on other sites More sharing options...
Magnusen2 Posted August 24, 2016 Author Share Posted August 24, 2016 (edited) OK, the problem is probably because I used the TranslateTo function instead of SetPosition and SetAngle. (And I do that because when I use that function I'm trying to move items dropped by the player and using SetPosition and SetAngle doesn't work for those but TranslateTo does.) You can try changing my line: targetItem.TranslateTo(posX, posY, posZ, 0.0, 0.0, angZ, 99999) to targetItem.SetPosition(posX, posY, posZ) targetItem.SetAngle(0.0, 0.0, angZ) and then you wouldn't need the extra setAngle you added. Now: SummonedFurnitureReference = akTarget.PlaceAtMe(SummonedFurniture, 1, false, true) ; start it disabled PlaceInFrontOfPlayer(SummonedFurnitureReference, 0.0, 0.0, 0.0) ; move it into position SummonedFurnitureReference.placeatme(unsummonFX) ; start playing the special effect at that spot SummonedFurnitureReference.Enable(true) ; now let it fade in (take off the true if you want it to pop in) Function PlaceInFrontOfPlayer(ObjectReference SummonedFurnitureReference, float distanceOffset = 0.0, float heightOffset = 0.0, float angleOffset = 0.0) ;{Place SummonedFurnitureReference directly in front of oriented towards the player. The offsetValues may need to be changed for different objects.} float playerAngleZ = PlayerRef.GetAngleZ() float angZ = playerAngleZ + angleOffset float posX = PlayerRef.GetPositionX() + distanceOffset * Math.Sin(playerAngleZ) float posY = PlayerRef.GetPositionY() + distanceOffset * Math.Cos(playerAngleZ) float posZ = PlayerRef.GetPositionZ() + heightOffset SummonedFurnitureReference.SetPosition(posX, posY, posZ) SummonedFurnitureReference.SetAngle(0.0, 0.0, angZ) EndFunction The furniture/fx spawned is nowhere to be found. I changed all the offsets to multiple values them used the TCL command to go to the sky and test if it spawned somewhere below the player, but that wasn't the case. And sorry again. Edited August 24, 2016 by Magnusen2 Link to comment Share on other sites More sharing options...
cdcooley Posted August 24, 2016 Share Posted August 24, 2016 Did you fill the PlayerRef property? If the property isn't filled right that could cause what you're seeing. And if so, the easiest way to check is to put a "PlayerRef = Game.GetPlayer()" line at the top of my function. Link to comment Share on other sites More sharing options...
Magnusen2 Posted August 27, 2016 Author Share Posted August 27, 2016 Did you fill the PlayerRef property? If the property isn't filled right that could cause what you're seeing. And if so, the easiest way to check is to put a "PlayerRef = Game.GetPlayer()" line at the top of my function.I forgot that the script in the MGEF was the old one which didn't had the player ref property. After adding it and tweaking the offset everything works as intended. Thanks again. Link to comment Share on other sites More sharing options...
Recommended Posts