Scripts

TR_m3-725_RotZ_Object_60

TR_Mainland.esm
Variables 17
Local Variables
tasks
OnPCDrop
ang_limit
rot_limit
dis_limit
timer_limit
theta
t1
timer
mx
my
mvx
mvy
ma
pvx
pvy
ca
Source
1begin TR_m3-725_RotZ_Object_60 2;Author: Seneca37 3;This script will rotate an object (usually a skull) about its Z axis, 4;+/- 60 degrees, based on the location of the player. 5;This gives the effect that the skull is watching/following the player. 6;This currently works with the following misc skull IDs 7;misc_skull00 8;misc_skull10 9;T_Com_SkullArgonian_01/02 10;T_Com_SkullKhajiit_01/02 11;T_Com_SkullOrc_01/02 12;T_Com_SkullVampire_01/02 13;NOTE: if the nice static human skulls (TR\f\TR_furn_skel_skull...) are ever 14;made into misc objects, this script would need to be modified to handle the 15;fact that when facing the player this skull pivots about its Y axis (not Z) 16 17;rot_limit, and timer_limit have been randomized to give each skull 18;its own unique motion 19 20float ang_limit 21float rot_limit 22float dis_limit 23float timer_limit 24float theta 25float t1 26float timer 27float mx 28float my 29float mvx 30float mvy 31float ma 32float pvx 33float pvy 34float ca 35short tasks 36short OnPCDrop 37 38if ( MenuMode ) 39 Return 40endif 41 42if ( OnPCDrop == 1 ) 43 set tasks to 0 ;reset position and angles 44 set OnPCDrop to 0 45endif 46 47if ( timer_limit == 0.0 ) 48 set timer_limit to 0.1 49endif 50set timer to ( timer + GetSecondsPassed ) 51if ( timer < timer_limit ) 52 Return 53endif 54 55 56if ( tasks == 0 ) 57 ;These calculations only need to be done once 58 set ang_limit to 60.0 ;allow skull to only rotate +/- 60 degrees from starting position 59; set rot_limit to 3.0 ;largest angular step 60;Letting each item/skull rotate a different amount 61;This value will be between 0.5 and 3.0 62 set rot_limit to random 30 63 set rot_limit to rot_limit / 10 64 if ( rot_limit < 0.5 ) 65 set rot_limit to 0.5 66 elseif ( rot_limit > 3.0 ) 67 set rot_limit to 3.0 68 endif 69;Letting each item/skull set own timer_limit value 70 set timer_limit to random 100 71 set timer_limit to timer_limit / 333.0 72 if ( timer_limit < 0.01 ) 73 set timer_limit to 0.01 74 elseif ( timer_limit > 0.3 ) 75 set timer_limit to 0.3 76 endif 77 set dis_limit to 400.0 ;distance from skull to start rotating 78 79 set mx to ( GetPos, X ) 80 set my to ( GetPos, Y ) 81 set ma to ( GetAngle, Z ) ;ma will be between 0 and 360 82 83 ;create unit vector facing forward of the skull 84 ;NOTE: the Maclaurin series expansion of the arc cosine and 85 ; arc sine functions is very very poor at angles < 37 deg 86 ; and > 143 degrees. So I use a unit vector pointing 87 ; 90 degrees away from a forward facing vector. This way 88 ; when the player is directly in front of the skull, the angle 89 ; between the vector from the skull to the player, and 90 ; this unit vector will be 90 degrees. 91 ; This additional 90 degrees is subtracted out later. 92 set mvx to 1.0 93 set mvy to 0.0 94 if ( ma == 360.0 ) ;occasionally I've seen this in the CS 95 set mvx to 1.0 ;have not noticed it reported in-game 96 set mvy to 0.0 ;better safe than sorry 97 elseif ( ma == 0.0 ) 98 set mvx to 1.0 99 set mvy to 0.0 100 elseif ( ma == 90.0 ) 101 set mvx to 0.0 102 set mvy to -1.0 103 elseif ( ma == 180.0 ) 104 set mvx to -1.0 105 set mvy to 0.0 106 elseif ( ma == 270.0 ) 107 set mvx to 0.0 108 set mvy to 1.0 109 else 110 ;Use Rotation Matrix on above unit vectors to properly align unit vector 111 ; R(theta) = [ cos -sin] 112 ; [ sin cos] 113 114 ;Series expansion of cos and sin 115 ;Angle x is in radians 116 ;sin(x) = x - x^3/6 + x^5/120 +O(x^7) 117 ;cos(x) = 1-x^2/2 + x^4/24 - x^6/720 + O(x^7) 118 ;these are best at angles -70 >= x <= 70 119 ; sin is easier to calculate 120 121 ;Also note that in-game axes are opposite the normal 122 ;convention, so the angles will be neg 123 124 ;To be sure that this is a unit vector 125 ;Only rotate 1 component then use the relationship 126 ;sin^2(theta) + cos^2(theta) = 1 to find other compenent 127 ;The above never returns a neg value, so the sign of the 2nd component 128 ;has to changed in the proper quadrants 129 if ( ma <= 45.0 ) ;Use 0 unit vector 130 ;set mvx to 1.0 131 ;set mvy to 0.0 132 ;convert ma to radians and change sign 133 set t1 to ( ma * -0.0174533 ) 134 set mvy to t1 - ( t1 * t1 * t1 / 6.0 ) 135 set mvy to mvy + ( t1 * t1 * t1 * t1 * t1 / 120.0 ) 136 ; the following should not happen - but better to be safe 137 if ( mvy > 1.0 ) 138 set mvy to 1.0 139 elseif ( mvy < -1.0 ) 140 set mvy to -1.0 141 endif 142 set mvx to ( 1.0 - mvy * mvy ) 143 set mvx to GetSquareRoot mvx 144 elseif ( ma <= 135.0 ) ;use 90 unit vector 145 ;set mvx to 0.0 146 ;set mvy to -1.0 147 set t1 to ( ( ma - 90.0 ) * -0.0174533 ) 148 set mvx to t1 - ( t1 * t1 * t1 / 6.0 ) 149 set mvx to mvx + ( t1 * t1 * t1 * t1 * t1 / 120.0 ) 150 ; the following should not happen - but better to be safe 151 if ( mvx > 1.0 ) 152 set mvx to 1.0 153 elseif ( mvx < -1.0 ) 154 set mvx to -1.0 155 endif 156 set mvy to ( 1.0 - mvx * mvx ) 157 set mvy to GetSquareRoot mvy 158 set mvy to ( -1.0 * mvy ) ;quadrant correction 159 elseif ( ma <= 225.0 ) ; use 180 unit vector 160 ;set mvx to -1.0 161 ;set mvy to 0.0 162 ;convert ma to radians and change sign 163 set t1 to ( ( ma - 180.0 ) * -0.0174533 ) 164 set mvy to t1 - ( t1 * t1 * t1 / 6.0 ) 165 set mvy to mvy + ( t1 * t1 * t1 * t1 * t1 / 120.0 ) 166 set mvy to ( mvy * -1.0 ) 167 ; the following should not happen - but better to be safe 168 if ( mvy > 1.0 ) 169 set mvy to 1.0 170 elseif ( mvy < -1.0 ) 171 set mvy to -1.0 172 endif 173 set mvx to ( 1.0 - mvy * mvy ) 174 set mvx to GetSquareRoot mvx 175 set mvx to ( -1.0 * mvx ) ;quadrant correction 176 elseif ( ma <= 315.0 ) ; use 270 unit vector 177 ;set mvx to 0.0 178 ;set mvy to 1.0 179 set t1 to ( ma - 270.0 ) * -0.0174533 180 set mvx to t1 - ( t1 * t1 * t1 / 6.0 ) 181 set mvx to mvx + ( t1 * t1 * t1 * t1 * t1 / 120.0 ) 182 set mvx to mvx * -1.0 183 ; the following should not happen - but better to be safe 184 if ( mvx > 1.0 ) 185 set mvx to 1.0 186 elseif ( mvx <-1.0 ) 187 set mvx to -1.0 188 endif 189 set mvy to ( 1 - mvx * mvx ) 190 set mvy to GetSquareRoot mvy 191 else ;Use 0 unit vector 192 ;set mvx to 1.0 193 ;set mvy to 0.0 194 ;convert ma to radians and change sign 195 set t1 to ( ma - 360 ) * -0.0174533 196 set mvy to t1 - ( t1 * t1 * t1 / 6.0 ) 197 set mvy to mvy + (t1 * t1 * t1 * t1 * t1 / 120.0 ) 198 ; the following should not happen - but better to be safe 199 if ( mvy > 1.0 ) 200 set mvy to 1.0 201 elseif ( mvy <-1.0 ) 202 set mvy to -1.0 203 endif 204 set mvx to ( 1 - mvy * mvy ) 205 set mvx to GetSquareRoot mvx 206 endif 207 endif 208 set tasks to 1 209 set timer to 0 210 Return 211elseif ( tasks == 1 ) 212 if ( GetDistance Player < dis_limit ) 213 ;2d vector from skull to player 214 set pvx to ( ( "Player"->getPos X ) - mx ) 215 set pvy to ( ( "Player"->getPos Y ) - my ) 216 ;normalize vector 217 set t1 to ( pvx * pvx + pvy * pvy ) 218 set t1 to GetSquareRoot t1 219 set pvx to pvx / t1 220 set pvy to pvy / t1 221 222 ;calc angle between 2 vectors (or lines) 223 ;arc_cos(a.b/|a|*|b|) 224 ;vectors a and b are unit vecors, only need to calculate the dot product 225 set t1 to ( mvx * pvx + mvy * pvy ) 226 ;the Maclaurin series of the arc cos function is 227 ;arc cos(x) = pi/2 -(x + x^3/6 + 3*x^5/40 +...) 228 set theta to 1.570796 - t1 - ( ( t1 * t1 * t1 ) / 6.0 ) 229 set theta to theta - ( 3 * ( t1 * t1 * t1 * t1 * t1 ) / 40.0 ) 230 set theta to theta * 57.296 ;convert to degrees 231 set theta to theta - 90.0 ;remove 90 degrees 232 233 ;get current angle of skull 234 set ca to GetAngle, Z 235 set ca to ca - ma ;how much has skull already rotated 236 set t1 to theta - ca ;how much skull needs to rotate 237 if ( t1 > 0.0 ) 238 if ( ca < ang_limit ) 239 if ( t1 > rot_limit ) 240 set ca to ca + rot_limit 241 else 242 set ca to ca + t1 243 endif 244 endif 245 set ca to ca + ma ;add back original angle 246 SetAngle Z ca 247 elseif ( t1 < 0.0 ) 248 if ( ca > ( -1.0 * ang_limit ) ) 249 if ( t1 < ( -1.0 * rot_limit ) ) 250 set ca to ca - rot_limit 251 else 252 set ca to ca + t1 253 endif 254 endif 255 set ca to ca + ma 256 SetAngle Z ca 257 endif 258 else 259 ;player is too far away - if skull is rotated - rotate it back to original position 260 ;get current angle of skull 261 set ca to GetAngle, Z 262 set t1 to ( ca - ma ) 263 if ( t1 > 0.0 ) 264 if ( t1 > rot_limit ) 265 set ca to ca - rot_limit 266 else 267 set ca to ca - t1 268 endif 269 SetAngle Z ca 270 elseif ( t1 < 0.0 ) 271 if ( t1 < ( -1.0 * rot_limit ) ) 272 set ca to ca + rot_limit 273 else 274 set ca to ca - t1 ;t1 is already negative 275 endif 276 SetAngle Z ca 277 endif 278 endif 279 set timer to 0 280endif 281 282end TR_m3-725_RotZ_Object_60