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 | } |