Summon Object
Jump to navigation
Jump to search
It's now known that the PlaceAtMe command is likely to cause bloating. Used a few times, no problem. Used a lot of times, problem. However, you can often avoid it by defining a permanent ref object and moving it to the player. But suppose that you don't want it right at the player's feet, but instead in front of them?
Here are some considerations:
- MoveTo does not allow relative positioning. You'll need to move to the player and then reposition relative to player.
- You'll need sine/cosine functions to get x,y offset relative to player heading, but oblivion doesn't have those functions. You can approximate them with polynomials. (The one used here comes from Handbook of Mathematical Functions.
- Moving a displayed object fails to update its collision data (notably required for getting activation cursors to work correctly). You can fix this by disabling the object and the re-enabling it.
- However, if you move, disable and then re-enable, the object will appear briefly at the player and then reappear at new position. Instead, you should disable, move and then re-enable. And there should be a time gap of a frame or two before enabling and disabling.
- The original ref has to be placed somewhere and set to persistent. If you want the original to be unfindable, a simple thing to do is place it in the Aleswell dummy cell.
So here's a chunk of code that does this for Wrye's Summon Bed mod. (Some irrelevant code trimmed for the purpose of clarity.)
; This is a bare bones version of my summon bed script effect. It moves ; a permanent ref bed to in front of the PC. scn wrSleepBedME float pos float ang ;(the measure of the angle, first deg, then radians) float ang2 ;(ang^2) Just for convenience. Could use ang*ang directly. float ang4 ;(ang^4) Just for convenience. Could use ang*ang*ang*ang directly. float sign ;sign correction float sin ;(sine of the angle) float cos ;(cosine of the angle) begin scriptEffectStart ;Because world activation and collision data don't update correctly, ;need to first disable and then reenabled. So here, item is disabled. ;Spell lasts one second, so re-enabling in next block happens with ;decent time gap. wrSleepBedRef.disable end begin scriptEffectFinish ; Now, want to summon bed and place it in front of player at 150 units. ; So, need to get player heading (north == 0, increasing clockwise, ; (east == 90), going up to 360.) Then use fourth/fifth order polynomial ; approximations for sin and cos. ;--sin, cos set sign to 1 set ang to player.getAngle z if ang > 270 set ang to ang - 360 elseif ang > 90 set ang to ang - 180 set sign to -1 endif set ang to 0.017453*ang set ang2 to ang * ang set ang4 to ang2 * ang2 set sin to sign*ang*(1 - 0.16605*ang2 + 0.00761*ang4) set cos to sign*(1 - 0.4967*ang2 + 0.03705*ang4) ;--Move it wrSleepBedRef.moveTo player set pos to player.getPos x + 150*sin wrSleepBedRef.setPos x pos set pos to player.getPos y + 150*cos wrSleepBedRef.setPos y pos set pos to player.getPos z + 55 ;--Tweak offset to put object on ground. wrSleepBedRef.setPos z pos ;--Set angle of bed relative to PC heading set ang to player.getAngle z + 90 wrSleepBedRef.setAngle x 0 wrSleepBedRef.setAngle y 0 wrSleepBedRef.setAngle z ang ;--Done wrSleepBedRef.enable end