SHOW:
|
|
- or go back to the newest paste.
| 1 | //----------------------------------------------------------------------------- | |
| 2 | // Torque Game Engine | |
| 3 | // Copyright (C) GarageGames.com, Inc. | |
| 4 | //----------------------------------------------------------------------------- | |
| 5 | ||
| 6 | //---------------------------------------------------------------------------------------------------------------- | |
| 7 | // Library Functions v2.1 | |
| 8 | //---------------------------------------------------------------------------------------------------------------- | |
| 9 | // These are nifty lil functions that are usefull for other things then solely supporting the functions they | |
| 10 | // were written to help. | |
| 11 | ||
| 12 | //************************************************************************************* | |
| 13 | //torque engine tidbits | |
| 14 | // | |
| 15 | // The rotation value returned for the z axis of an object in torque, is specified by | |
| 16 | // the last 2 words.(it can be made a single value by: getWord(%rot, 2) * getWord(%rot, 3)) | |
| 17 | // This value will remain positive until the angle is larger than 4.18879 radians OR 240 | |
| 18 | // degrees, any angle larger than this will revert to a negative value. | |
| 19 | // GOing clockwise around the torque compass there are the following degree values... | |
| 20 | // | |
| 21 | // North - 0 deg, 0 Rad | |
| 22 | // East - 90 deg, 1.5707963 rad | |
| 23 | // South- 180 deg, 3.1415926 rad | |
| 24 | // 240 deg, 4.18879 rad (changeover point, 30 degrees past south) | |
| 25 | // West - 270 deg, -1.5707963 rad (the negative value for due east) | |
| 26 | // | |
| 27 | // pi = 3.1415926 (3.14159265358979323846) | |
| 28 | // 2pi = 6.2831853 (6.28318530717958647692) | |
| 29 | // | |
| 30 | // Table X degrees = X radians | |
| 31 | // 1d = 0.0174532 | |
| 32 | // 5d = 0.0872664 | |
| 33 | // 10d = 0.1745329 | |
| 34 | // 45d = 0.785398 | |
| 35 | // 60d = 1.0471974 | |
| 36 | // 90d = 1.5707963 | |
| 37 | //180d = 3.1415926 | |
| 38 | // | |
| 39 | // when getting a rotation via an objects ID.rotation, the final word of the rotation | |
| 40 | // is in degrees, NOT radians! | |
| 41 | // ID.rotation = x y z amount(in degrees) | |
| 42 | ||
| 43 | ||
| 44 | // getWorldBox returns box.min.x, box.min.y, box.min.z, box.max.x, box.max.y, box.max.z | |
| 45 | // which are two diagonaly opposiing corners of the box | |
| 46 | ||
| 47 | // Just thought someone might find this usefull :D -Founder | |
| 48 | //************************************************************************************* | |
| 49 | ||
| 50 | //------------------------------------------------------------------------------------- | |
| 51 | // Rotations, positions, vectors, and Matricies OH MY! | |
| 52 | //------------------------------------------------------------------------------------- | |
| 53 | //set some usefull globals | |
| 54 | $Pi = 3.14159; | |
| 55 | $TwoPi = 6.28319; | |
| 56 | ||
| 57 | $North = 0; | |
| 58 | $NE = 0.785398; //45 | |
| 59 | $East = 1.5708; //90 | |
| 60 | $SE = 2.35619; //135 | |
| 61 | $South = $Pi; //180 | |
| 62 | $SW = 3.92699; //225 | |
| 63 | $West = 4.71239; //270 | |
| 64 | $NW = 5.49779; //315 | |
| 65 | ||
| 66 | //----Vectors---- | |
| 67 | ||
| 68 | //this function serves a similar purpose to vectorScale, except instead of scaling it | |
| 69 | //makes the specified vector.length equal to the number provided | |
| 70 | function setVectorLength(%vec, %desiredLength) | |
| 71 | {
| |
| 72 | error("setVectorLength vec:" SPC %vec SPC "desiredLength" SPC %desiredLength);
| |
| 73 | //this only works if we start with a unit vector so we have the relative valuse for x y and z | |
| 74 | %vecNorm = vectorLen(%vec) > 1 ? vectorNormalize(%vec) : %vec; | |
| 75 | ||
| 76 | // x + y + z = the number to devide the length by in order to get the proper scale by which to | |
| 77 | //multiply the vector elements | |
| 78 | %nl = mAbs(getWord(%vecNorm, 0)) + mAbs(getWord(%vecNorm, 1)) + mAbs(getWord(%vecNorm, 2)); | |
| 79 | %scale = %desiredLength / %nl; | |
| 80 | //now vector scale it and send it back | |
| 81 | %newVec = vectorScale(%vecNorm, %scale); | |
| 82 | error("finalVec:" SPC %newVec);
| |
| 83 | return %newVec; | |
| 84 | } | |
| 85 | ||
| 86 | //----common transform utilities---- | |
| 87 | function posFromRaycast(%transform) | |
| 88 | {
| |
| 89 | // the 2nd, 3rd, and 4th words returned from a successful raycast call are the position of the point | |
| 90 | %position = getWord(%transform, 1) SPC getWord(%transform, 2) SPC getWord(%transform, 3); | |
| 91 | return %position; | |
| 92 | } | |
| 93 | ||
| 94 | function normalFromRaycast(%transform) | |
| 95 | {
| |
| 96 | // the 5th, 6th and 7th words returned from a successful raycast call are the normal of the surface | |
| 97 | %norm = getWord(%transform, 4) SPC getWord(%transform, 5) SPC getWord(%transform, 6); | |
| 98 | return %norm; | |
| 99 | } | |
| 100 | ||
| 101 | // these stay, since having to type %rot = %obj.rotFromTransform(%transform); after already having the transform is | |
| 102 | // just way too much. | |
| 103 | function posFromTransform(%transform) | |
| 104 | {
| |
| 105 | // the first three words of an object's transform are the object's position | |
| 106 | %position = getWord(%transform, 0) SPC getWord(%transform, 1) SPC getWord(%transform, 2); | |
| 107 | return %position; | |
| 108 | } | |
| 109 | ||
| 110 | function rotFromTransform(%transform) | |
| 111 | {
| |
| 112 | // the last four words of an object's transform are the object's rotation | |
| 113 | %rotation = getWord(%transform, 3) SPC getWord(%transform, 4) SPC getWord(%transform, 5) SPC getWord(%transform, 6); | |
| 114 | return %rotation; | |
| 115 | } | |
| 116 | ||
| 117 | //if we are going to make these inherited functions, might as welllet them get the transform as well | |
| 118 | function SceneObject::posFromTransform(%obj, %transform) | |
| 119 | {
| |
| 120 | if(%transform $= "") | |
| 121 | %transform = %obj.getTransForm(); | |
| 122 | // the first three words of an object's transform are the object's position | |
| 123 | %position = getWord(%transform, 0) SPC getWord(%transform, 1) SPC getWord(%transform, 2); | |
| 124 | return %position; | |
| 125 | } | |
| 126 | ||
| 127 | function SceneObject::rotFromTransform(%obj, %transform) | |
| 128 | {
| |
| 129 | if(%transform $= "") | |
| 130 | %transform = %obj.getTransForm(); | |
| 131 | // the last four words of an object's transform are the object's rotation | |
| 132 | %rotation = getWord(%transform, 3) SPC getWord(%transform, 4) SPC getWord(%transform, 5) SPC getWord(%transform, 6); | |
| 133 | return %rotation; | |
| 134 | } | |
| 135 | ||
| 136 | //this finds the terrain height for the position and sets it x meters above the terrain | |
| 137 | function bumpZ(%pos, %heightMod) | |
| 138 | {
| |
| 139 | %x = getword(%pos, 0); | |
| 140 | %y = getword(%pos, 1); | |
| 141 | %height = getTerrainHeight(%x SPC %y); | |
| 142 | ||
| 143 | return %x SPC %y SPC %height + %heightMod; | |
| 144 | } | |
| 145 | ||
| 146 | //this function merely zeroes the z of a pos, not used anymore | |
| 147 | function gimpPosition(%pos) | |
| 148 | {
| |
| 149 | return getword(%pos, 0) SPC getword(%pos, 1) SPC "0"; | |
| 150 | } | |
| 151 | ||
| 152 | function getAngleDifferance(%angleOne, %angleTwo) | |
| 153 | {
| |
| 154 | //we need the smallest angle from angle one to angle two | |
| 155 | ||
| 156 | //First ensure both angles are positive | |
| 157 | %angleOne = %angleOne < 0 ? $TwoPi + %angleOne : %angleOne; | |
| 158 | %angleTwo = %angleTwo < 0 ? $TwoPi + %angleTwo : %angleTwo; | |
| 159 | ||
| 160 | %diff = %angleTwo - %angleOne; | |
| 161 | ||
| 162 | %diff = %diff > $Pi ? $TwoPi - %diff : %diff; | |
| 163 | %diff = %diff < -$Pi ? -$TwoPi - %diff : %diff; | |
| 164 | ||
| 165 | return %diff; | |
| 166 | } | |
| 167 | ||
| 168 | //---Directional (compass) functions---- | |
| 169 | ||
| 170 | function getClosestCompassTick(%angle) | |
| 171 | {
| |
| 172 | %value = ""; | |
| 173 | ||
| 174 | %angle = %angle < 0 ? $TwoPi + %angle : %angle; | |
| 175 | ||
| 176 | if(%angle >= mDegToRad(337.5) || %angle < mDegToRad(22.5)) | |
| 177 | %value = "North" SPC $North; | |
| 178 | else if(%angle >= mDegToRad(22.5) && %angle < mDegToRad(67.5)) | |
| 179 | %value = "NorthEast" SPC $NE; | |
| 180 | else if(%angle >= mDegToRad(67.5) && %angle < mDegToRad(112.5)) | |
| 181 | %value = "East" SPC $East; | |
| 182 | else if(%angle >= mDegToRad(112.5) && %angle < mDegToRad(157.5)) | |
| 183 | %value = "SouthEast" SPC $SE; | |
| 184 | else if(%angle >= mDegToRad(157.5) && %angle < mDegToRad(202.5)) | |
| 185 | %value = "South" SPC $South; | |
| 186 | else if(%angle >= mDegToRad(202.5) && %angle < mDegToRad(247.5)) | |
| 187 | %value = "SouthWest" SPC $SW; | |
| 188 | else if(%angle >= mDegToRad(247.5) && %angle < mDegToRad(292.5)) | |
| 189 | %value = "West" SPC $West; | |
| 190 | else if(%angle >= mDegToRad(292.5) && %angle < mDegToRad(337.5)) | |
| 191 | %value = "NorthWest" SPC $NW; | |
| 192 | ||
| 193 | return %value; | |
| 194 | } | |
| 195 | ||
| 196 | function getClosestCardinal(%angle) | |
| 197 | {
| |
| 198 | %value = ""; | |
| 199 | ||
| 200 | %angle = %angle < 0 ? $TwoPi + %angle : %angle; | |
| 201 | %angle = %angle > $TwoPi ? %angle - $TwoPi : %angle; | |
| 202 | ||
| 203 | if(%angle >= mDegToRad(315) || %angle < mDegToRad(45)) | |
| 204 | %value = "North" SPC $North; | |
| 205 | else if(%angle >= mDegToRad(45) && %angle < mDegToRad(135)) | |
| 206 | %value = "East" SPC $East; | |
| 207 | else if(%angle >= mDegToRad(135) && %angle < mDegToRad(225)) | |
| 208 | %value = "South" SPC $South; | |
| 209 | else if(%angle >= mDegToRad(225) && %angle < mDegToRad(315)) | |
| 210 | %value = "West" SPC $West; | |
| 211 | ||
| 212 | ||
| 213 | //error("getClosestCardinal Value:" SPC %value);
| |
| 214 | return %value; | |
| 215 | } | |
| 216 | ||
| 217 | //----angles and rotations---- | |
| 218 | ||
| 219 | function invertDegAngle(%angle) | |
| 220 | {
| |
| 221 | if(%angle > 0) | |
| 222 | %angle = -(180 - %angle); | |
| 223 | else | |
| 224 | %angle = mAbs(%angle + 180); | |
| 225 | ||
| 226 | return %angle; | |
| 227 | } | |
| 228 | ||
| 229 | function invertAngle(%angle) | |
| 230 | {
| |
| 231 | //add pi, then cap | |
| 232 | %angle += $PI; | |
| 233 | %angle = %angle > $TwoPi ? %angle - $TwoPi : %angle; | |
| 234 | ||
| 235 | return %angle; | |
| 236 | } | |
| 237 | ||
| 238 | function getAnglefromRot(%rot) | |
| 239 | {
| |
| 240 | //return a positive z angle in radians | |
| 241 | %angle = getWord(%rot, 2) * getWord(%rot, 3); | |
| 242 | %angle = %angle < 0 ? $TwoPi + %angle : %angle; | |
| 243 | return %angle; | |
| 244 | } | |
| 245 | ||
| 246 | function getDegAnglefromRot(%rot) | |
| 247 | {
| |
| 248 | //return the rot's z angle in positive degrees | |
| 249 | %angleOne = mRadtoDeg(getWord(%rot, 2) * getWord(%rot, 3)); | |
| 250 | %angle = %angleOne < 0 ? 360 + %angleOne : %angleOne; | |
| 251 | return %angle; | |
| 252 | } | |
| 253 | ||
| 254 | function getZangle(%posOne, %posTwo) | |
| 255 | {
| |
| 256 | %vec = VectorSub(%posTwo, %posOne); | |
| 257 | //get the angle | |
| 258 | %rotAngleZ = mATan( firstWord(%vec), getWord(%vec, 1) ); | |
| 259 | //add pi to the angle | |
| 260 | //%rotAngleZ += $Pi; | |
| 261 | ||
| 262 | //make this rotation a proper torque game value, anything more than 240 degrees is negative | |
| 263 | //if(%rotAngleZ > 4.18879) | |
| 264 | //subtract 2pi from the value, then make sure its positive | |
| 265 | // %rotAngleZ = -(mAbs(%rotAngleZ - $TwoPi)); | |
| 266 | ||
| 267 | return %rotAngleZ; | |
| 268 | } | |
| 269 | ||
| 270 | function absRot(%rot) | |
| 271 | {
| |
| 272 | %rot = %rot < 0 ? %rot + $TwoPi : %rot; | |
| 273 | ||
| 274 | return %rot; | |
| 275 | } | |
| 276 | ||
| 277 | function adjustRot(%rot, %rotAdjust) | |
| 278 | {
| |
| 279 | %angle = getWord(%rot, 2) * getWord(%rot, 3); | |
| 280 | //%rotAdjust = ((%rotAdjust >= 4.18879) ? (($TwoPi - %rotAdjust) * -1) : %rotAdjust); | |
| 281 | ||
| 282 | %rotAdjust = %rotAdjust < 0 ? $TwoPi + %rotAdjust : %rotAdjust; | |
| 283 | ||
| 284 | //now add the angle adjustment to the refrence rot | |
| 285 | %adjust = %angle + %rotAdjust; | |
| 286 | //bring in back in line with the torque world | |
| 287 | %adjust = ((%adjust >= 4.18879) ? (%adjust - $TwoPi) : %adjust); | |
| 288 | //if it's negative we'll stuff it into the vector and leave the angle value unchanged | |
| 289 | %rotZ = ((%adjust >= 0) ? 1 : (-1)); | |
| 290 | %adjust = mAbs(%adjust); | |
| 291 | %rot = getWord(%rot, 0) SPC getWord(%rot, 1) SPC %rotZ SPC %adjust; | |
| 292 | return %rot; | |
| 293 | } | |
| 294 | ||
| 295 | // This lil function generates the rotation required for an object at PosOne to point at PosTwo (z rot only) | |
| 296 | function pointToXYPos(%posOne, %posTwo) | |
| 297 | {
| |
| 298 | %vec = VectorSub(%posOne, %posTwo); | |
| 299 | //get the angle | |
| 300 | %rotAngleZ = mATan( firstWord(%vec), getWord(%vec, 1) ); | |
| 301 | //add pi to the angle | |
| 302 | %rotAngleZ += $Pi; | |
| 303 | ||
| 304 | //make this rotation a proper torque game value, anything more than 240 degrees is negative | |
| 305 | if(%rotAngleZ > 4.18879) | |
| 306 | {
| |
| 307 | //the rotation scale is seldom negative, instead make the axis value negative | |
| 308 | %modifier = -1; | |
| 309 | //subtract 2pi from the value, then make sure its positive | |
| 310 | %rotAngleZ = mAbs(%rotAngleZ - $TwoPi); | |
| 311 | //sigh, if only this were all true | |
| 312 | } | |
| 313 | else | |
| 314 | %modifier = 1; | |
| 315 | ||
| 316 | //assemble the rotation and send it back | |
| 317 | return "0 0" SPC %modifier SPC %rotAngleZ; | |
| 318 | } | |
| 319 | ||
| 320 | // And this lil function generates the rotation required for an object at posOne to | |
| 321 | // point at PosTwo for X, Y And Z axis. | |
| 322 | function pointToPos(%posOne, %posTwo) | |
| 323 | {
| |
| 324 | //sub the two positions so we get a vector pointing from the origin in the direction we want our object to face | |
| 325 | %vec = VectorSub(%posTwo, %posOne); | |
| 326 | ||
| 327 | // pull the values out of the vector | |
| 328 | %x = firstWord(%vec); | |
| 329 | %y = getWord(%vec, 1); | |
| 330 | %z = getWord(%vec, 2); | |
| 331 | ||
| 332 | //this finds the distance from origin to our point | |
| 333 | %len = vectorLen(%vec); | |
| 334 | ||
| 335 | //---------X----------------- | |
| 336 | //given the rise and length of our vector this will give us the angle in radians | |
| 337 | %rotAngleX = mATan( %z, %len ); | |
| 338 | ||
| 339 | //---------Z----------------- | |
| 340 | //get the angle for the z axis | |
| 341 | %rotAngleZ = mATan( %x, %y ); | |
| 342 | ||
| 343 | //create 2 matrices, one for the z rotation, the other for the x rotation | |
| 344 | %matrix = MatrixCreateFromEuler("0 0" SPC %rotAngleZ * -1);
| |
| 345 | %matrix2 = MatrixCreateFromEuler(%rotAngleX SPC "0 0"); | |
| 346 | ||
| 347 | //now multiply them together so we end up with the rotation we want | |
| 348 | %finalMat = MatrixMultiply(%matrix, %matrix2); | |
| 349 | ||
| 350 | //we're done, send the proper numbers back | |
| 351 | return getWords(%finalMat, 3, 6); | |
| 352 | } | |
| 353 | ||
| 354 | function getXYAngle(%posOne, %posTwo) | |
| 355 | {
| |
| 356 | //sub the two positions so we get a vector pointing from the origin in the direction we want our object to face | |
| 357 | %vec = VectorSub(%posTwo, %posOne); | |
| 358 | ||
| 359 | // pull the values out of the vector | |
| 360 | %x = firstWord(%vec); | |
| 361 | %y = getWord(%vec, 1); | |
| 362 | %z = getWord(%vec, 2); | |
| 363 | ||
| 364 | //this finds the distance from origin to our point | |
| 365 | %len = vectorLen(%vec); | |
| 366 | ||
| 367 | //---------XY----------------- | |
| 368 | //given the rise and length of our vector this will give us the angle in radians | |
| 369 | %rotAngleXY = mATan( %z, %len ); | |
| 370 | //%rotAngleXY+=$Pi; | |
| 371 | return %rotAngleXY; | |
| 372 | } | |
| 373 | ||
| 374 | function getXYangleFromRot(%rot) | |
| 375 | {
| |
| 376 | %a = getWord(%rot, 3); | |
| 377 | ||
| 378 | %x = firstWord(%rot) * %a; | |
| 379 | %y = getWord(%rot, 1) * %a; | |
| 380 | %z = getWord(%rot, 2) * %a; | |
| 381 | ||
| 382 | ||
| 383 | %xy = mSqrt((%x * %x) + (%y * %y)); | |
| 384 | %rotAngleXY = mATan( %xy, mAbs(%z) ); | |
| 385 | return %rotAngleXY; | |
| 386 | } | |
| 387 | ||
| 388 | function getZrise(%rot, %posOne, %posTwo) | |
| 389 | {
| |
| 390 | %XYAngle = getXYangleFromRot(%rot); | |
| 391 | ||
| 392 | %vec = VectorSub(%posTwo, %posOne); | |
| 393 | ||
| 394 | //this finds the distance from origin to our point | |
| 395 | %len = vectorLen(%vec); | |
| 396 | ||
| 397 | //pythagorian theroem says right triangle sides: a squared + b squared = c squared | |
| 398 | //we need to find the rise amount based on the angle and length | |
| 399 | // c^2 - a^2 = b^2 | |
| 400 | //the height of the right triangle equals the tangent of the angle times the length of the base | |
| 401 | //%zmod = mTan(%XYAngle + $Pi) * (%len + $Pi); | |
| 402 | %zmod = mTan(%XYAngle) * (%len - $Pi); | |
| 403 | return %zmod; | |
| 404 | } | |
| 405 | ||
| 406 | //-------------------------------------------------------------------------------------------- | |
| 407 | // Spline functions | |
| 408 | //-------------------------------------------------------------------------------------------- | |
| 409 | ||
| 410 | // These functions draw a curve from the first point to the last point, going near any middle points at time t. | |
| 411 | // t represents the percentage of distance between the first and last point that you want the curve point for | |
| 412 | // They can be used to draw a 3-d spline when all three axis are run through the function. | |
| 413 | ||
| 414 | // %t = (position Of Desired Spline Point) / (distance Between First And Last Points) | |
| 415 | // %curvePoint1.x = get3PointCurveValue(%point1.x, %point2.x, %point3.x, %t) | |
| 416 | // %curvePoint1.y = get3PointCurveValue(%point1.y, %point2.y, %point3.y, %t) | |
| 417 | // %curvePoint1.z = get3PointCurveValue(%point1.z, %point2.z, %point3.z, %t) | |
| 418 | ||
| 419 | // this lil guy doesn't actually draw a curve, but rather a line, however it is very usefull for mixing | |
| 420 | // two values together based on a percentage of time or distance | |
| 421 | function get2PointLineValue(%point1, %point2, %t) | |
| 422 | {
| |
| 423 | %pd = ( %point1 * (1-%t)) + (%point2 * %t); | |
| 424 | return %pd; | |
| 425 | } | |
| 426 | ||
| 427 | function get3PointCurveValue(%point1, %point2, %point3, %t) | |
| 428 | {
| |
| 429 | %step1 = %point1 * ((1-%t) * (1-%t)); | |
| 430 | %step2 = %point2 * 2 * %t * (1 - %t); | |
| 431 | %step3 = %point3 * (%t * %t); | |
| 432 | %pd = %step1 + %step2 + %step3; | |
| 433 | return %pd; | |
| 434 | } | |
| 435 | ||
| 436 | function get4PointCurveValue(%point1, %point2, %point3, %point4, %t) | |
| 437 | {
| |
| 438 | %step1 = %point1 * ( (1 - %t)*(1 - %t)*(1 - %t) ); | |
| 439 | %step2 = %point2 * 3 * %t * ( (1 - %t)*(1 - %t) ); | |
| 440 | %step3 = %point3 * 3 * (%t * %t) * (1 - %t); | |
| 441 | %step4 = %point4 * (%t * %t * %t); | |
| 442 | %pd = %step1 + %step2 + %step3 + %step4; | |
| 443 | return %pd; | |
| 444 | } | |
| 445 | ||
| 446 | //--------------------------------------------------------------------------------------------------------------- | |
| 447 | // functions dealing with terrain | |
| 448 | //--------------------------------------------------------------------------------------------------------------- | |
| 449 | ||
| 450 | //this takes the provided position, and sets it to the position of the earest terrain vertex | |
| 451 | function findNearestTerrainPoint(%pos) | |
| 452 | {
| |
| 453 | %x = findGridPoint(firstWord(%pos)); | |
| 454 | %y = findGridPoint(getWord(%pos, 1)); | |
| 455 | %z = getWord(%pos, 2); | |
| 456 | ||
| 457 | return(%x SPC %y SPC %z); | |
| 458 | } | |
| 459 | ||
| 460 | function findGridPoint(%axis) | |
| 461 | {
| |
| 462 | if(%axis == 0) | |
| 463 | return 0; | |
| 464 | %axis = mFloor(%axis); | |
| 465 | %remainder = %axis % Terrain.squareSize; | |
| 466 | ||
| 467 | if(%remainder >= (Terrain.squareSize / 2)) | |
| 468 | {
| |
| 469 | while(%axis % Terrain.squareSize != 0) | |
| 470 | %axis++; | |
| 471 | } | |
| 472 | else | |
| 473 | {
| |
| 474 | while(%axis % Terrain.squareSize != 0) | |
| 475 | %axis--; | |
| 476 | } | |
| 477 | return %axis; | |
| 478 | } | |
| 479 | ||
| 480 | //Takes the pos provided, and sets the z value to the surface height | |
| 481 | function getTerrainSurfacePoint(%pos) | |
| 482 | {
| |
| 483 | %x = getword(%pos, 0); | |
| 484 | %y = getword(%pos, 1); | |
| 485 | %height = getTerrainHeight(%x SPC %y); | |
| 486 | return %x SPC %y SPC %height; | |
| 487 | } | |
| 488 | ||
| 489 | //in a box with the given max and min x and y extents, this will find the average height value | |
| 490 | function getAverageTerrainHeight(%minX, %maxX, %minY, %maxY, %squareSize) | |
| 491 | {
| |
| 492 | %total = 0; | |
| 493 | %count = 0; | |
| 494 | for(%x = %minX; %x <= %maxX; %x += %squareSize) | |
| 495 | {
| |
| 496 | //we are already looping through x, so loop through Y while we're at it | |
| 497 | for(%y = %minY; %y <= %maxY; %y += %squareSize) | |
| 498 | {
| |
| 499 | %total += getTerrainHeight(%x SPC %y); | |
| 500 | %count++; | |
| 501 | } | |
| 502 | } | |
| 503 | return %total / %count; | |
| 504 | } | |
| 505 | ||
| 506 | function getTerrainAngle(%point) | |
| 507 | {
| |
| 508 | %angleRad = mACos(vectorDot(%point, "0 0 1")); | |
| 509 | %angleDeg = mRadtoDeg(%angleRad); | |
| 510 | return %angleDeg; | |
| 511 | } | |
| 512 | ||
| 513 | function getTerrainLevel(%pos, %rad) | |
| 514 | {
| |
| 515 | while(%retries < 500) | |
| 516 | {
| |
| 517 | %x = getWord(%pos, 0) + mFloor(getRandom(%rad * 2) - %rad); | |
| 518 | %y = getWord(%pos, 1) + mFloor(getRandom(%rad * 2) - %rad); | |
| 519 | %z = getWord(%pos, 2) + mFloor(getRandom(%rad * 2) - %rad); | |
| 520 | ||
| 521 | %start = %x @ " " @ %y @ " 5000"; | |
| 522 | %end = %x @ " " @ %y @ " -1"; | |
| 523 | %ground = containerRayCast(%start, %end, $TypeMasks::TerrainObjectType, 0); | |
| 524 | %z = getWord(%ground, 3); | |
| 525 | ||
| 526 | %z += 3.5; | |
| 527 | %position = %x @ " " @ %y @ " " @ %z; | |
| 528 | ||
| 529 | %mask = ( $TypeMasks::ShapeBaseObjectType | $TypeMasks::MoveableObjectType | | |
| 530 | $TypeMasks::StaticShapeObjectType | $TypeMasks::WaterObjectType | | |
| 531 | $TypeMasks::InteriorObjectType ); | |
| 532 | ||
| 533 | InitContainerRadiusSearch( %position, 3.5, %mask ); | |
| 534 | if(containerSearchNext() == 0) | |
| 535 | {
| |
| 536 | //error ("Position Is Good");
| |
| 537 | return %position; | |
| 538 | } | |
| 539 | else | |
| 540 | %retries++; | |
| 541 | } | |
| 542 | return( %pos ); | |
| 543 | } | |
| 544 | ||
| 545 | //--------------------------------------------------------------------------------------------------------------- | |
| 546 | // Functions for moving objects | |
| 547 | //--------------------------------------------------------------------------------------------------------------- | |
| 548 | function SceneObject::setOnTerrain(%obj, %pos, %calcOnly) | |
| 549 | {
| |
| 550 | if(%pos $= "") | |
| 551 | %pos = %obj.position; | |
| 552 | %terHeight = getTerrainHeight(%pos); | |
| 553 | %offset = %obj.GetHeightOffset(); | |
| 554 | %newPos = firstWord(%pos) SPC getWord(%pos, 1) SPC %terHeight + %offset; | |
| 555 | if(%calcOnly) | |
| 556 | return %newPos; | |
| 557 | else | |
| 558 | %obj.setTransform(%newPos SPC %obj.rotFromTransform()); | |
| 559 | } | |
| 560 | ||
| 561 | function SceneObject::alignTransforms(%obj, %pos, %rot, %rotAdjust, %xAngle, %yRadius, %zMod, %invert, %calc) | |
| 562 | {
| |
| 563 | //rotation hack - these rots just aren't natural! | |
| 564 | if(%rot $= "0 0 1 0" || %rot $= "0 1 0 0" || %rot $= "1 0 0 0") | |
| 565 | %rot = "0.0001 0.00001 0.99 0.001"; | |
| 566 | ||
| 567 | //get the angle of the refrence object(rot) so we know what direction to go to find the new position | |
| 568 | %angle = getWord(%rot, 2) * getWord(%rot, 3); | |
| 569 | ||
| 570 | //this is the angle to find the position at, relative to the refrence point | |
| 571 | %xAngle = mDegToRad(%xAngle); | |
| 572 | //now adjust it to be compatible with the refrence rotation | |
| 573 | %xAngleMod = ((%angle < 0) ? (-1 * %xAngle) : %xAngle); | |
| 574 | ||
| 575 | //generate a vector to the adjusted position | |
| 576 | %matrix = VectorOrthoBasis(getXYangleFromRot(%rot) SPC getWords(%rot,1,2) SPC getWord(%rot, 3) + %xAngleMod); | |
| 577 | //%matrix = VectorOrthoBasis(getWords(%rot,0,2) SPC getWord(%rot, 3) + %xAngleMod); | |
| 578 | %yRot = getWords(%matrix, 3, 5); | |
| 579 | ||
| 580 | //now scale from our current position the yRadius amount to get our new position | |
| 581 | %zPos = vectorAdd(%pos, vectorScale(%yRot, %yRadius)); | |
| 582 | %bPos = firstWord(%zPos) SPC getWord(%zPos, 1) SPC (getWord(%zPos, 2) + %zMod); | |
| 583 | ||
| 584 | //right now our new position is on the horizontal plane of world space, if the refrence rot is tilted | |
| 585 | //we need to move the pos up or down to account for it. | |
| 586 | //do wee need to adjust the Z hieght position to account for objects rotated on an x or y axis? | |
| 587 | %XYAngle = getXYangleFromRot(%rot); | |
| 588 | //only add to the Z if the angle is more then 1 deg (Otherwise the rotation hack above will try to bump the target up) | |
| 589 | if(mAbs(%XYAngle) > 0.0174533) | |
| 590 | {
| |
| 591 | %zRise = getZrise(%rot, %bpos, %pos);// + $Pi; | |
| 592 | %bPos = getWords(%bPos, 0, 1) SPC getword(%bPos, 2) + %zRise; | |
| 593 | } | |
| 594 | ||
| 595 | //lets try using the trusty ole matrix to take care of any tilt | |
| 596 | //so first thing is to subtract the target position from the ref position. | |
| 597 | ||
| 598 | ||
| 599 | ||
| 600 | //it would probably more accurate to calculate this on the surface of a shpere instead of a circle then adjusting | |
| 601 | //the hieght, but since I don't know how to do that just now we'll go this route, which is plenty damned acurate | |
| 602 | ||
| 603 | //if the generated position needs to point in a certain direction relative to the refrence, then generate it's rot | |
| 604 | if(%rotAdjust !$= "" && %rotAdjust != 0) | |
| 605 | {
| |
| 606 | //convert the adjustment to radians, then make it a valid torque world angle | |
| 607 | %rotAdjust = mDegToRad(%rotAdjust); | |
| 608 | %rotAdjust = ((%rotAdjust >= 4.18879) ? (($TwoPi - %rotAdjust) * -1) : %rotAdjust); | |
| 609 | ||
| 610 | //now add the angle adjustment to the refrence rot | |
| 611 | %adjust = %angle + %rotAdjust; | |
| 612 | //bring in back in line with the torque world | |
| 613 | %adjust = ((%adjust >= 4.18879) ? (%adjust - $TwoPi) : %adjust); | |
| 614 | //if it's negative we'll stuff it into the vector and leave the angle value unchanged | |
| 615 | %rotZ = ((%adjust >= 0) ? 1 : (-1)); | |
| 616 | %adjust = mAbs(%adjust); | |
| 617 | %rot = getWord(%rot, 0) SPC getWord(%rot, 1) SPC %rotZ SPC %adjust; | |
| 618 | %angle = getWord(%rot, 2) * getWord(%rot, 3); | |
| 619 | } | |
| 620 | if(%invert) | |
| 621 | {
| |
| 622 | //this is for turning the generated position upside down, wonder if this and the above are broken | |
| 623 | //for tilted refrence rotations? | |
| 624 | %angleR = -1 * %angle; | |
| 625 | %Mrot = MatrixCreateFromEuler("0 3.14" SPC %angleR);
| |
| 626 | %rot = getWord(%Mrot, 3) SPC getWord(%Mrot, 4) SPC getWord(%Mrot, 5) SPC getWord(%Mrot, 6); | |
| 627 | } | |
| 628 | ||
| 629 | //we're done, get the hell outta here! | |
| 630 | %transForm = %bPos SPC %rot; | |
| 631 | if(%calc) | |
| 632 | return %transForm; | |
| 633 | else | |
| 634 | {
| |
| 635 | %obj.setTransform(%transForm); | |
| 636 | return; | |
| 637 | } | |
| 638 | } | |
| 639 | ||
| 640 | //-------------------------------------------------------------------------------------------- | |
| 641 | // | |
| 642 | // SceneObject::alignTransforms() -by Founder | |
| 643 | // | |
| 644 | //-------------------------------------------------------------------------------------------- | |
| 645 | // Here it is!! THE mother of all functions!! AMAZING!! | |
| 646 | // | |
| 647 | // usage: %objectID.alignTransforms(%pos, %rot, %rotAdjust, %xAngle, %yRadius, %zMod, %invert, %calc); | |
| 648 | // | |
| 649 | // %pos is the position of the object(or point) around which to move the (%objectID) | |
| 650 | // %rot is the final rotation you want %objectID to face | |
| 651 | // %rotAdjust is for making a rotational offset of %objectID relative to the provided %rot | |
| 652 | // valid values go from 0 to 360; going clockwise from north(0), east(90) | |
| 653 | // south(180), west(270) etc. 360 will work, but I don't know what kind of | |
| 654 | // dumbass would rotate an object by 360 degrees in the z. | |
| 655 | // %xAngle and %yRadius are vars for adjusting %objectID's position relative to %pos | |
| 656 | // %yRadius describes a circle of (%yRadius) in size, along which you wish %objectID to be | |
| 657 | // placed. %xAngle is the relative angle in degrees (0 - 360) from %pos. Where this | |
| 658 | // angle intersects the circle is the position the object will be placed. | |
| 659 | // | |
| 660 | // %zMod is how far up you want to move the object relative to %pos | |
| 661 | // %invert is weather or not you want to turn %objectID upside down. | |
| 662 | // true and 1 will invert it, 0, false, or giveing it no value will not. | |
| 663 | // %calc will have the function return the calculated transform instead of actually moving | |
| 664 | // the object. | |
| 665 | // if for any option you do not want to make an adjustment fill the spot with a 0(zero) | |
| 666 | // negative values will subtract from x y and z axis, but negative values are not valid for | |
| 667 | // the %rotAdjust value | |
| 668 | // examples: | |
| 669 | // %deplObj.alignTransforms(%pos, %rot, 270, 0, 0, 8, true); | |
| 670 | // %deplObj.alignTransforms(%dPos, %rot, 0, 0, 0.7, -0.05); | |
| 671 | // | |
| 672 | // | |
| 673 | // | |
| 674 | // -- | |
| 675 | // - X | |
| 676 | // - - | |
| 677 | // P | |
| 678 | // - - | |
| 679 | // - - | |
| 680 | // -- | |
| 681 | // | |
| 682 | // | |
| 683 | // In the diagram above, P equals the position of the player or the position generated by the | |
| 684 | // deploy code or the postion of the reference object. The circle made up of (-)'s represents | |
| 685 | // a %yRadius of 5 meters. Or if you prefer, a circle which represents the distance | |
| 686 | // away from P that you want this object to be. X represents the object for whom we are | |
| 687 | // generating the new position, and where we want it. X is at an approximately 45 degree angle | |
| 688 | // from P, which is the northEast tick on the Torque compass. In order to keep X's position relative | |
| 689 | // to P, no matter what direction P faces you would use the following line of code: | |
| 690 | // %ObjectID.alignTransforms(%pos(of P), %rot(of P), 0, 45, 5, 0); | |
| 691 | //-------------------------------------------------------------------------------------------- | |
| 692 | ||
| 693 | function SceneObject::alignGroupRot(%obj, %pos, %rot, %rotAdjust, %xAngle, %yRadius, %zMod, %invert, %calc) | |
| 694 | {
| |
| 695 | %vAngle = getWord(%rot, 3); | |
| 696 | %angle = getWord(%rot, 2) * getWord(%rot, 3); | |
| 697 | %xAngle = mDegToRad(%xAngle); | |
| 698 | %xAngleMod = ((%angle < 0) ? (-1 * %xAngle) : %xAngle); | |
| 699 | %vRot = getWords(%rot,0,2); | |
| 700 | %matrix = VectorOrthoBasis(%vRot SPC %vAngle + %xAngleMod); | |
| 701 | %yRot = getWords(%matrix, 3, 5); | |
| 702 | %zPos = vectorAdd(%pos, vectorScale(%yRot, %yRadius)); | |
| 703 | %bPos = firstWord(%zPos) SPC getWord(%zPos, 1) SPC (getWord(%zPos, 2) + %zMod); | |
| 704 | if(%rotAdjust !$= "" && %rotAdjust != 0) | |
| 705 | {
| |
| 706 | %deg = mRadtoDeg(%angle); | |
| 707 | %rotAdjust = ((%rotAdjust >= 240) ? ((360 - %rotAdjust) * -1) : %rotAdjust); | |
| 708 | %adjust = %deg + %rotAdjust; | |
| 709 | %adjust = ((%adjust >= 240) ? (%adjust - 360) : %adjust); | |
| 710 | %rotZ = ((%adjust >= 0) ? 1 : (-1)); | |
| 711 | %adjust = mAbs(%adjust); | |
| 712 | %finAngle = mDegToRad(%adjust); | |
| 713 | %rot = getWord(%rot, 0) SPC getWord(%rot, 1) SPC %rotZ SPC %finAngle; | |
| 714 | %angle = getWord(%rot, 2) * getWord(%rot, 3); | |
| 715 | } | |
| 716 | if(%invert) | |
| 717 | {
| |
| 718 | %angleR = -1 * %angle; | |
| 719 | %Mrot = MatrixCreateFromEuler("0 3.14" SPC %angleR);
| |
| 720 | %rot = getWord(%Mrot, 3) SPC getWord(%Mrot, 4) SPC getWord(%Mrot, 5) SPC getWord(%Mrot, 6); | |
| 721 | } | |
| 722 | %transForm = %bPos SPC %rot; | |
| 723 | if(%calc) | |
| 724 | return %transForm; | |
| 725 | else | |
| 726 | {
| |
| 727 | %obj.setTransform(%transForm); | |
| 728 | return; | |
| 729 | } | |
| 730 | } | |
| 731 | ||
| 732 | function SceneObject::StartMoveObject(%obj, %endpos, %time, %smoothness, %delay) | |
| 733 | {
| |
| 734 | if(isObject(%obj)) | |
| 735 | {
| |
| 736 | %startpos = %obj.getTransform(); | |
| 737 | %diff = VectorSub(%endpos, %startpos); | |
| 738 | %numsteps = (%time/1000) * %smoothness; | |
| 739 | %interval = 1000 / %smoothness; | |
| 740 | %stepvec = VectorScale(%diff, (1/%numsteps)); | |
| 741 | %numstepsleft = %numsteps; | |
| 742 | %currpos = %startpos; | |
| 743 | %obj.MoveObject(%startpos, %endpos, %numsteps, %numstepsleft, %stepvec, %currpos, %interval, %delay); | |
| 744 | } | |
| 745 | } | |
| 746 | ||
| 747 | function SceneObject::MoveObject(%obj, %startpos, %endpos, %numsteps, %numstepsleft, %stepvec, %currpos, %interval, %delay) | |
| 748 | {
| |
| 749 | %rot = rotFromTransform(%obj.getTransform()); | |
| 750 | %currpos = VectorAdd(%currpos, %stepvec); | |
| 751 | ||
| 752 | %obj.setTransForm(%currpos SPC %rot); | |
| 753 | %numstepsleft--; | |
| 754 | if(%numstepsleft < 1) | |
| 755 | return; | |
| 756 | else | |
| 757 | %obj.schedule(%interval, "MoveObject", %startpos, %endpos, %numsteps, %numstepsleft, %stepvec, %currpos, %interval, %delay); | |
| 758 | } | |
| 759 | ||
| 760 | function getObjectTypeMask(%obj) | |
| 761 | {
| |
| 762 | if(%obj.getType() & $TypeMasks::StaticObjectType) | |
| 763 | error("\c4Type is: $TypeMasks::StaticObjectType");
| |
| 764 | else if(%obj.getType() & $TypeMasks::EnvironmentObjectType) | |
| 765 | error("\c4Type is: $TypeMasks::EnvironmentObjectType");
| |
| 766 | else if(%obj.getType() & $TypeMasks::TerrainObjectType) | |
| 767 | error("\c4Type is: $TypeMasks::TerrainObjectType");
| |
| 768 | else if(%obj.getType() & $TypeMasks::InteriorObjectType) | |
| 769 | error("\c4Type is: $TypeMasks::InteriorObjectType");
| |
| 770 | else if(%obj.getType() & $TypeMasks::WaterObjectType) | |
| 771 | error("\c4Type is: $TypeMasks::WaterObjectType");
| |
| 772 | else if(%obj.getType() & $TypeMasks::TriggerObjectType) | |
| 773 | error("\c4Type is: $TypeMasks::TriggerObjectType");
| |
| 774 | else if(%obj.getType() & $TypeMasks::MarkerObjectType) | |
| 775 | error("\c4Type is: $TypeMasks::MarkerObjectType");
| |
| 776 | else if(%obj.getType() & $TypeMasks::GameBaseObjectType) | |
| 777 | error("\c4Type is: $TypeMasks::GameBaseObjectType");
| |
| 778 | else if(%obj.getType() & $TypeMasks::ShapeBaseObjectType) | |
| 779 | error("\c4Type is: $TypeMasks::ShapeBaseObjectType");
| |
| 780 | else if(%obj.getType() & $TypeMasks::CameraObjectType) | |
| 781 | error("\c4Type is: $TypeMasks::CameraObjectType");
| |
| 782 | else if(%obj.getType() & $TypeMasks::StaticShapeObjectType) | |
| 783 | error("\c4Type is: $TypeMasks::StaticShapeObjectType");
| |
| 784 | else if(%obj.getType() & $TypeMasks::PlayerObjectType) | |
| 785 | error("\c4Type is: $TypeMasks::PlayerObjectType");
| |
| 786 | else if(%obj.getType() & $TypeMasks::ItemObjectType) | |
| 787 | error("\c4Type is: $TypeMasks::ItemObjectType");
| |
| 788 | else if(%obj.getType() & $TypeMasks::VehicleObjectType) | |
| 789 | error("\c4Type is: $TypeMasks::VehicleObjectType");
| |
| 790 | else if(%obj.getType() & $TypeMasks::VehicleBlockerObjectType) | |
| 791 | error("\c4Type is: $TypeMasks::VehicleBlockerObjectType");
| |
| 792 | else if(%obj.getType() & $TypeMasks::ProjectileObjectType) | |
| 793 | error("\c4Type is: $TypeMasks::ProjectileObjectType");
| |
| 794 | else if(%obj.getType() & $TypeMasks::ExplosionObjectType) | |
| 795 | error("\c4Type is: $TypeMasks::ExplosionObjectType");
| |
| 796 | else if(%obj.getType() & $TypeMasks::CorpseObjectType) | |
| 797 | error("\c4Type is: $TypeMasks::CorpseObjectType");
| |
| 798 | else if(%obj.getType() & $TypeMasks::DebrisObjectType) | |
| 799 | error("\c4Type is: $TypeMasks::DebrisObjectType");
| |
| 800 | else if(%obj.getType() & $TypeMasks::PhysicalZoneObjectType) | |
| 801 | error("\c4Type is: $TypeMasks::PhysicalZoneObjectType");
| |
| 802 | else if(%obj.getType() & $TypeMasks::StaticTSObjectType) | |
| 803 | error("\c4Type is: $TypeMasks::StaticTSObjectType");
| |
| 804 | else if(%obj.getType() & $TypeMasks::StaticRenderedObjectType) | |
| 805 | error("\c4Type is: $TypeMasks::StaticRenderedObjectType");
| |
| 806 | else if(%obj.getType() & $TypeMasks::DamagableItemObjectType) | |
| 807 | error("\c4Type is: $TypeMasks::DamagableItemObjectType");
| |
| 808 | else | |
| 809 | error("\c4Object type is: UNKNOWN");
| |
| 810 | } | |
| 811 | ||
| 812 | // Founder: Apply kickbak to anything | |
| 813 | function SceneObject::applyKickback(%obj, %kick) | |
| 814 | {
| |
| 815 | %dir = %obj.getVectorFromTransform( %obj.getTransform(), "reverse" ); | |
| 816 | %force = vectorScale( %dir, %kick ); | |
| 817 | %obj.applyImpulse( %obj.posFromTransform(), %force ); | |
| 818 | } | |
| 819 | ||
| 820 | // ZOD: Modified version of above to allow different directions | |
| 821 | function SceneObject::applyKick(%obj, %amt, %velCap, %dir) | |
| 822 | {
| |
| 823 | %vec = %obj.getVectorFromTransform( %obj.getTransform(), %dir ); | |
| 824 | %data = %obj.getDataBlock(); | |
| 825 | %pos = %obj.posFromTransform(); | |
| 826 | %velocity = %obj.getVelocity(); | |
| 827 | %normal = VectorDot( %velocity, VectorNormalize( %velocity ) ); | |
| 828 | ||
| 829 | if( %velCap != 0 && %normal > %velCap) // Whatever cap we wish.. | |
| 830 | {
| |
| 831 | %kick = %amt / %Normal; // Reduce impulse. | |
| 832 | //retrun; // Or apply no impulse at all and exit out. | |
| 833 | } | |
| 834 | else | |
| 835 | %kick = %amt; | |
| 836 | ||
| 837 | %impulse = VectorScale( %vec, %data.mass * %kick ); | |
| 838 | %obj.applyImpulse(%pos, %impulse); | |
| 839 | } | |
| 840 | ||
| 841 | //-------------------------------------------------------------------------------------------- | |
| 842 | // Taken from Harold Paul /*Wedge*/ DElia's post in the GG mod forums | |
| 843 | // http://www.garagegames.com/mg/forums/result.thread.php?qt=50109 | |
| 844 | function SceneObject::getVectorFromTransform(%obj, %transform, %vector) | |
| 845 | {
| |
| 846 | %aa = getWords(%transform, 3, 6); | |
| 847 | %tmat = VectorOrthoBasis(%aa); | |
| 848 | ||
| 849 | %rv = getWords(%tMat, 0, 2); | |
| 850 | %fv = getWords(%tMat, 3, 5); | |
| 851 | %uv = getWords(%tMat, 6, 8); | |
| 852 | ||
| 853 | if(%vector $= "up") | |
| 854 | return %uv; | |
| 855 | ||
| 856 | if(%vector $= "down") | |
| 857 | return VectorScale(%uv, -1); | |
| 858 | ||
| 859 | if(%vector $= "left") | |
| 860 | return VectorScale(%rv, -1); | |
| 861 | ||
| 862 | if(%vector $= "right") | |
| 863 | return %rv; | |
| 864 | ||
| 865 | if(%vector $= "forward") | |
| 866 | return %fv; | |
| 867 | ||
| 868 | if(%vector $= "reverse") | |
| 869 | return VectorScale(%fv, -1); | |
| 870 | } | |
| 871 | ||
| 872 | //-------------------------------------------------------------------------------------------- | |
| 873 | ||
| 874 | function stripTaggedVar(%var) | |
| 875 | {
| |
| 876 | return stripChars( detag( getTaggedString( %var ) ), "\cp\co\c6\c7\c8\c9" ); | |
| 877 | } | |
| 878 | ||
| 879 | //------------------------------------------------------------------------------------ | |
| 880 | // Object Box functions | |
| 881 | //------------------------------------------------------------------------------------ | |
| 882 | //box = min.x min.y min.z max.x max.y max.z | |
| 883 | ||
| 884 | //parse out a particular element | |
| 885 | function getBoxMinX(%box){ return getWord(%box, 0); }
| |
| 886 | function getBoxMinY(%box){ return getWord(%box, 1); }
| |
| 887 | function getBoxMinZ(%box){ return getWord(%box, 2); }
| |
| 888 | function getBoxMaxX(%box){ return getWord(%box, 3); }
| |
| 889 | function getBoxMaxY(%box){ return getWord(%box, 4); }
| |
| 890 | function getBoxMaxZ(%box){ return getWord(%box, 5); }
| |
| 891 | ||
| 892 | function SceneObject::getWorldBoxMin(%obj) | |
| 893 | {
| |
| 894 | %box = %obj.getObjectBox(); | |
| 895 | %matrix = %obj.getTransForm(); | |
| 896 | return MatrixMulPoint(%matrix, getWords(%box, 0, 2)); | |
| 897 | } | |
| 898 | ||
| 899 | function SceneObject::getWorldBoxMax(%obj) | |
| 900 | {
| |
| 901 | %box = %obj.getObjectBox(); | |
| 902 | %matrix = %obj.getTransForm(); | |
| 903 | return MatrixMulPoint(%matrix, getWords(%box, 3, 5)); | |
| 904 | } | |
| 905 | ||
| 906 | function SceneObject::getWorldBoxMinX(%obj) { return getWord(%obj.getWorldBoxMin(), 0); }
| |
| 907 | function SceneObject::getWorldBoxMinY(%obj) { return getWord(%obj.getWorldBoxMin(), 1); }
| |
| 908 | function SceneObject::getWorldBoxMinZ(%obj) { return getWord(%obj.getWorldBoxMin(), 2); }
| |
| 909 | function SceneObject::getWorldBoxMaxX(%obj) { return getWord(%obj.getWorldBoxMax(), 0); }
| |
| 910 | function SceneObject::getWorldBoxMaxY(%obj) { return getWord(%obj.getWorldBoxMax(), 1); }
| |
| 911 | function SceneObject::getWorldBoxMaxZ(%obj) { return getWord(%obj.getWorldBoxMax(), 2); }
| |
| 912 | ||
| 913 | ||
| 914 | //return a box dimension | |
| 915 | function SceneObject::GetBoxWidth(%obj) | |
| 916 | {
| |
| 917 | %box = %obj.getObjectBox(); | |
| 918 | return mAbs(getBoxMaxX(%box)) + mAbs(getBoxMinX(%box)); | |
| 919 | } | |
| 920 | ||
| 921 | function SceneObject::GetBoxLength(%obj) | |
| 922 | {
| |
| 923 | %box = %obj.getObjectBox(); | |
| 924 | return mAbs(getBoxMaxY(%box)) + mAbs(getBoxMinY(%box)); | |
| 925 | } | |
| 926 | ||
| 927 | function SceneObject::GetBoxHeight(%obj) | |
| 928 | {
| |
| 929 | %box = %obj.getObjectBox(); | |
| 930 | return mAbs(getBoxMaxZ(%box)) + mAbs(getBoxMinZ(%box)); | |
| 931 | } | |
| 932 | ||
| 933 | function SceneObject::GetBoxCenter(%obj) | |
| 934 | {
| |
| 935 | //box center by default will be 0 0 0, so use a lil matrix math, get it's current world position | |
| 936 | %matrix = %obj.getTransForm(); | |
| 937 | %box = %obj.getObjectBox(); | |
| 938 | %newBox = MatrixMulPoint(%matrix, getWords(%box, 0, 2)); | |
| 939 | %newBox = %newBox SPC MatrixMulPoint(%matrix, getWords(%box, 3, 5)); | |
| 940 | %centerX = (getBoxMinX(%newBox) + getBoxMaxX(%newBox)) * 0.5; | |
| 941 | %centerY = (getBoxMinY(%newBox) + getBoxMaxY(%newBox)) * 0.5; | |
| 942 | %centerZ = (getBoxMinZ(%newBox) + getBoxMaxZ(%newBox)) * 0.5; | |
| 943 | return %centerX SPC %centerY SPC %centerZ; | |
| 944 | } | |
| 945 | ||
| 946 | function SceneObject::GetHeightOffset(%obj) | |
| 947 | {
| |
| 948 | return mAbs(getWord(%obj.position, 2) - %obj.getWorldBoxMinZ()); | |
| 949 | } | |
| 950 | ||
| 951 | //------------------------------------------------------------------------------------ | |
| 952 | // Other functionality | |
| 953 | //------------------------------------------------------------------------------------ | |
| 954 | ||
| 955 | ||
| 956 | function getValidSpawnSurface(%pos, %rad) | |
| 957 | {
| |
| 958 | while(%retries < 500) | |
| 959 | {
| |
| 960 | %x = getWord(%pos, 0) + mFloor(getRandom(%rad * 2) - %rad); | |
| 961 | %y = getWord(%pos, 1) + mFloor(getRandom(%rad * 2) - %rad); | |
| 962 | ||
| 963 | %start = %x SPC %y SPC VectorAdd(getWord(%pos, 2), 3.5); | |
| 964 | %end = %x SPC %y SPC "-1"; | |
| 965 | %surface = containerRayCast(%start, %end, $TypeMasks::TerrainObjectType | $TypeMasks::InteriorObjectType, 0); | |
| 966 | ||
| 967 | %z = getWord(%surface, 3); | |
| 968 | %position = %x SPC %y SPC %z; | |
| 969 | ||
| 970 | %mask = ( $TypeMasks::ShapeBaseObjectType | $TypeMasks::MoveableObjectType | | |
| 971 | $TypeMasks::StaticShapeObjectType | $TypeMasks::WaterObjectType ); | |
| 972 | ||
| 973 | InitContainerRadiusSearch( %position, 3.5, %mask ); | |
| 974 | if ( containerSearchNext() == 0 ) | |
| 975 | {
| |
| 976 | //error("Random Position Is Good");
| |
| 977 | return %position; | |
| 978 | } | |
| 979 | else | |
| 980 | %retries++; | |
| 981 | ||
| 982 | } | |
| 983 | //error("Random Position Is Bad");
| |
| 984 | return( %pos ); | |
| 985 | } | |
| 986 | ||
| 987 | ||
| 988 | //-------------------------------------------------------------------------------- | |
| 989 | //a lil function to mark a position with an object and a default object to use as marker | |
| 990 | ||
| 991 | datablock StaticShapeData(markerObject) | |
| 992 | {
| |
| 993 | category = "Misc"; | |
| 994 | shapeFile = "~/data/shapes/markers/octahedron.dts"; | |
| 995 | dynamicType = $TypeMasks::StaticShapeObjectType; | |
| 996 | }; | |
| 997 | ||
| 998 | function markPoint(%pos, %rot, %block, %type, %name) | |
| 999 | {
| |
| 1000 | if(%block $= "" && %type $= "") | |
| 1001 | {
| |
| 1002 | %type = StaticShape; | |
| 1003 | %block = markerObject; | |
| 1004 | } | |
| 1005 | ||
| 1006 | %obj = new (%type)(%name) {
| |
| 1007 | dataBlock = %block; | |
| 1008 | }; | |
| 1009 | MissionCleanup.add(%obj); | |
| 1010 | ||
| 1011 | %obj.setTransform(%pos SPC %rot); | |
| 1012 | } | |
| 1013 | ||
| 1014 | function markPointArray(%array) | |
| 1015 | {
| |
| 1016 | %count = %array.count(); | |
| 1017 | for(%i = 0; %i < %count; %i++) | |
| 1018 | {
| |
| 1019 | markPoint(%array.getValue(%i)); | |
| 1020 | } | |
| 1021 | } | |
| 1022 | //-------------------------------------------------------------------------------------------- | |
| 1023 | // String functions | |
| 1024 | //-------------------------------------------------------------------------------------------- | |
| 1025 | ||
| 1026 | // Returns true if a string passed to it consists of nothing but digits and/or decimals. | |
| 1027 | // Passes false for strings with more than one decimal, or with a + | |
| 1028 | // or - as anything but the first character (+ or - are only allowed as the first character in the string) | |
| 1029 | function isCleanNumber(%string) | |
| 1030 | {
| |
| 1031 | %dot = 0; | |
| 1032 | for(%i = 0; (%char = getSubStr(%string, %i, 1)) !$= ""; %i++) | |
| 1033 | {
| |
| 1034 | switch$(%char) | |
| 1035 | {
| |
| 1036 | case "0" or "1" or "2" or "3" or "4" or "5" or "6" or "7" or "8" or "9": | |
| 1037 | continue; | |
| 1038 | ||
| 1039 | case ".": | |
| 1040 | if(%dot > 1) | |
| 1041 | return false; | |
| 1042 | ||
| 1043 | %dot++; | |
| 1044 | continue; | |
| 1045 | ||
| 1046 | case "-": | |
| 1047 | if(%i) // only valid as first character | |
| 1048 | return false; | |
| 1049 | ||
| 1050 | continue; | |
| 1051 | ||
| 1052 | case "+": | |
| 1053 | if(%i) // only valid as first character | |
| 1054 | return false; | |
| 1055 | ||
| 1056 | continue; | |
| 1057 | ||
| 1058 | default: | |
| 1059 | return false; | |
| 1060 | } | |
| 1061 | } | |
| 1062 | // %text passed the test | |
| 1063 | return true; | |
| 1064 | } | |
| 1065 | ||
| 1066 | //this function takes a pathed filename (common/missions/blah.mis) and takes out everything excpet the name (blah) | |
| 1067 | function cropToName(%filePAth) | |
| 1068 | {
| |
| 1069 | %name = ""; | |
| 1070 | %length = strlen(%filePAth); | |
| 1071 | %dot = 0; | |
| 1072 | ||
| 1073 | for(%i = 0; %i < %length; %i++) | |
| 1074 | {
| |
| 1075 | if(getSubStr(%filePAth, %i, 1) $= "/") | |
| 1076 | %lastDir = %i; | |
| 1077 | if(getSubStr(%filePAth, %i, 1) $= ".") | |
| 1078 | %dot = %i; | |
| 1079 | } | |
| 1080 | ||
| 1081 | if(%dot > 0) | |
| 1082 | {
| |
| 1083 | if(%lastDir $= "") | |
| 1084 | %name = getSubStr(%filePAth, 0, %dot - 1); | |
| 1085 | else | |
| 1086 | %name = getSubStr(%filePAth, %lastDir + 1, %dot - 1); | |
| 1087 | } | |
| 1088 | ||
| 1089 | else | |
| 1090 | %name = getSubStr(%filePAth, %lastDir + 1, %length); | |
| 1091 | ||
| 1092 | return %name; | |
| 1093 | ||
| 1094 | } | |
| 1095 | ||
| 1096 | function cropDecimal(%num) | |
| 1097 | {
| |
| 1098 | %length = strlen(%num); | |
| 1099 | %dot = 0; | |
| 1100 | ||
| 1101 | for(%i = 0; %i < %length; %i++) | |
| 1102 | {
| |
| 1103 | if(getSubStr(%num, %i, 1) $= ".") | |
| 1104 | %dot = %i; | |
| 1105 | } | |
| 1106 | ||
| 1107 | if(%dot > 0) | |
| 1108 | %name = getSubStr(%num, 0, %dot); | |
| 1109 | else | |
| 1110 | %name = %num; | |
| 1111 | ||
| 1112 | return %name; | |
| 1113 | } | |
| 1114 | ||
| 1115 | function messageTest() | |
| 1116 | {
| |
| 1117 | messageAll('MsgTestColors', '\c0Color 0 \c1Color 1 \c2Color 2 \c3 Color 3 \c4 Color 4 \c5 Color 5 \c6 Color 6 \c7Color 7 \c8 Color 8 \c9 Color 9');
| |
| 1118 | echo("\c0test \c1test \c2test \c3test \c4test \c5test \c6test \c7test \c8test \c9test");
| |
| 1119 | } | |
| 1120 | ||
| 1121 | //-------------------------------------------------------------------------------------------- | |
| 1122 | // Taken from Harold "LabRat" Brown's .plan | |
| 1123 | // http://www.garagegames.com/index.php?sec=mg&mod=resource&page=view&qid=10202 | |
| 1124 | function dec2hex(%val) | |
| 1125 | {
| |
| 1126 | // Converts a decimal number into a 2 digit HEX number | |
| 1127 | %digits ="0123456789ABCDEF"; //HEX digit table | |
| 1128 | ||
| 1129 | // To get the first number we divide by 16 and then round down, using | |
| 1130 | // that number as a lookup into our HEX table. | |
| 1131 | %firstDigit = getSubStr(%digits,mFloor(%val/16),1); | |
| 1132 | ||
| 1133 | // To get the second number we do a MOD 16 and using that number as a | |
| 1134 | // lookup into our HEX table. | |
| 1135 | %secDigit = getSubStr(%digits,%val % 16,1); | |
| 1136 | ||
| 1137 | // return our two digit HEX number | |
| 1138 | return %firstDigit @ %secDigit; | |
| 1139 | } | |
| 1140 | ||
| 1141 | function chrValue(%chr) | |
| 1142 | {
| |
| 1143 | // So we don't have to do any C++ changes we approximate the function | |
| 1144 | // to return ASCII Values for a character. This ignores the first 31 | |
| 1145 | // characters and the last 128. | |
| 1146 | ||
| 1147 | // Setup our Character Table. Starting with ASCII character 32 (SPACE) | |
| 1148 | %charTable = " !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_'abcdefghijklmnopqrstuvwxyz{|}~\t\n\r";
| |
| 1149 | ||
| 1150 | //Find the position in the string for the Character we are looking for the value of | |
| 1151 | %value = strpos(%charTable,%chr); | |
| 1152 | ||
| 1153 | // Add 32 to the value to get the true ASCII value | |
| 1154 | %value = %value + 32; | |
| 1155 | ||
| 1156 | //HACK: Encode TAB, New Line and Carriage Return | |
| 1157 | if (%value >= 127) | |
| 1158 | {
| |
| 1159 | if(%value == 127) | |
| 1160 | %value = 9; | |
| 1161 | if(%value == 128) | |
| 1162 | %value = 10; | |
| 1163 | if(%value == 129) | |
| 1164 | %value = 13; | |
| 1165 | } | |
| 1166 | //return the value of the character | |
| 1167 | return %value; | |
| 1168 | } | |
| 1169 | ||
| 1170 | function URLEncode(%rawString) | |
| 1171 | {
| |
| 1172 | // Encode strings to be HTTP safe for URL use | |
| 1173 | ||
| 1174 | // Table of characters that are valid in an HTTP URL | |
| 1175 | %validChars = "1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz:/.?=_-$(){}~&";
| |
| 1176 | ||
| 1177 | // If the string we are encoding has text... start encoding | |
| 1178 | if (strlen(%rawString) > 0) | |
| 1179 | {
| |
| 1180 | // Loop through each character in the string | |
| 1181 | for(%i=0;%i<strlen(%rawString);%i++) | |
| 1182 | {
| |
| 1183 | // Grab the character at our current index location | |
| 1184 | %chrTemp = getSubStr(%rawString,%i,1); | |
| 1185 | ||
| 1186 | // If the character is not valid for an HTTP URL... Encode it | |
| 1187 | if (strstr(%validChars,%chrTemp) == -1) | |
| 1188 | {
| |
| 1189 | //Get the HEX value for the character | |
| 1190 | %chrTemp = dec2hex(chrValue(%chrTemp)); | |
| 1191 | ||
| 1192 | // Is it a space? Change it to a "+" symbol | |
| 1193 | if (%chrTemp $= "20") | |
| 1194 | {
| |
| 1195 | %chrTemp = "+"; | |
| 1196 | } | |
| 1197 | else | |
| 1198 | {
| |
| 1199 | // It's not a space, prepend the HEX value with a % | |
| 1200 | %chrTemp = "%" @ %chrTemp; | |
| 1201 | } | |
| 1202 | } | |
| 1203 | // Build our encoded string | |
| 1204 | %encodeString = %encodeString @ %chrTemp; | |
| 1205 | } | |
| 1206 | } | |
| 1207 | // Return the encoded string value | |
| 1208 | return %encodeString; | |
| 1209 | } | |
| 1210 | ||
| 1211 | //-------------------------------------------------------------------------------------------- | |
| 1212 | // Zod: A default raycast function | |
| 1213 | function ShapeBase::doRaycast(%this, %range, %mask) | |
| 1214 | {
| |
| 1215 | // get the eye vector and eye transform of the player | |
| 1216 | %eyeVec = %this.getEyeVector(); | |
| 1217 | %eyeTrans = %this.getEyeTransform(); | |
| 1218 | ||
| 1219 | // extract the position of the player's camera from the eye transform (first 3 words) | |
| 1220 | %eyePos = posFromTransform(%eyeTrans); | |
| 1221 | ||
| 1222 | // normalize the eye vector | |
| 1223 | %nEyeVec = VectorNormalize(%eyeVec); | |
| 1224 | ||
| 1225 | // scale (lengthen) the normalized eye vector according to the search range | |
| 1226 | %scEyeVec = VectorScale(%nEyeVec, %range); | |
| 1227 | ||
| 1228 | // add the scaled & normalized eye vector to the position of the camera | |
| 1229 | %eyeEnd = VectorAdd(%eyePos, %scEyeVec); | |
| 1230 | ||
| 1231 | // see if anything gets hit | |
| 1232 | %searchResult = containerRayCast(%eyePos, %eyeEnd, %mask, %this); | |
| 1233 | ||
| 1234 | return %searchResult; | |
| 1235 | } |