//----------------------------------------------------------------------------- // Torque Game Engine // Copyright (C) GarageGames.com, Inc. //----------------------------------------------------------------------------- //---------------------------------------------------------------------------------------------------------------- // Library Functions v2.1 //---------------------------------------------------------------------------------------------------------------- // These are nifty lil functions that are usefull for other things then solely supporting the functions they // were written to help. //************************************************************************************* //torque engine tidbits // // The rotation value returned for the z axis of an object in torque, is specified by // the last 2 words.(it can be made a single value by: getWord(%rot, 2) * getWord(%rot, 3)) // This value will remain positive until the angle is larger than 4.18879 radians OR 240 // degrees, any angle larger than this will revert to a negative value. // GOing clockwise around the torque compass there are the following degree values... // // North - 0 deg, 0 Rad // East - 90 deg, 1.5707963 rad // South- 180 deg, 3.1415926 rad // 240 deg, 4.18879 rad (changeover point, 30 degrees past south) // West - 270 deg, -1.5707963 rad (the negative value for due east) // // pi = 3.1415926 (3.14159265358979323846) // 2pi = 6.2831853 (6.28318530717958647692) // // Table X degrees = X radians // 1d = 0.0174532 // 5d = 0.0872664 // 10d = 0.1745329 // 45d = 0.785398 // 60d = 1.0471974 // 90d = 1.5707963 //180d = 3.1415926 // // when getting a rotation via an objects ID.rotation, the final word of the rotation // is in degrees, NOT radians! // ID.rotation = x y z amount(in degrees) // getWorldBox returns box.min.x, box.min.y, box.min.z, box.max.x, box.max.y, box.max.z // which are two diagonaly opposiing corners of the box // Just thought someone might find this usefull :D -Founder //************************************************************************************* //------------------------------------------------------------------------------------- // Rotations, positions, vectors, and Matricies OH MY! //------------------------------------------------------------------------------------- //set some usefull globals $Pi = 3.14159; $TwoPi = 6.28319; $North = 0; $NE = 0.785398; //45 $East = 1.5708; //90 $SE = 2.35619; //135 $South = $Pi; //180 $SW = 3.92699; //225 $West = 4.71239; //270 $NW = 5.49779; //315 //----Vectors---- //this function serves a similar purpose to vectorScale, except instead of scaling it //makes the specified vector.length equal to the number provided function setVectorLength(%vec, %desiredLength) { error("setVectorLength vec:" SPC %vec SPC "desiredLength" SPC %desiredLength); //this only works if we start with a unit vector so we have the relative valuse for x y and z %vecNorm = vectorLen(%vec) > 1 ? vectorNormalize(%vec) : %vec; // x + y + z = the number to devide the length by in order to get the proper scale by which to //multiply the vector elements %nl = mAbs(getWord(%vecNorm, 0)) + mAbs(getWord(%vecNorm, 1)) + mAbs(getWord(%vecNorm, 2)); %scale = %desiredLength / %nl; //now vector scale it and send it back %newVec = vectorScale(%vecNorm, %scale); error("finalVec:" SPC %newVec); return %newVec; } //----common transform utilities---- function posFromRaycast(%transform) { // the 2nd, 3rd, and 4th words returned from a successful raycast call are the position of the point %position = getWord(%transform, 1) SPC getWord(%transform, 2) SPC getWord(%transform, 3); return %position; } function normalFromRaycast(%transform) { // the 5th, 6th and 7th words returned from a successful raycast call are the normal of the surface %norm = getWord(%transform, 4) SPC getWord(%transform, 5) SPC getWord(%transform, 6); return %norm; } // these stay, since having to type %rot = %obj.rotFromTransform(%transform); after already having the transform is // just way too much. function posFromTransform(%transform) { // the first three words of an object's transform are the object's position %position = getWord(%transform, 0) SPC getWord(%transform, 1) SPC getWord(%transform, 2); return %position; } function rotFromTransform(%transform) { // the last four words of an object's transform are the object's rotation %rotation = getWord(%transform, 3) SPC getWord(%transform, 4) SPC getWord(%transform, 5) SPC getWord(%transform, 6); return %rotation; } //if we are going to make these inherited functions, might as welllet them get the transform as well function SceneObject::posFromTransform(%obj, %transform) { if(%transform $= "") %transform = %obj.getTransForm(); // the first three words of an object's transform are the object's position %position = getWord(%transform, 0) SPC getWord(%transform, 1) SPC getWord(%transform, 2); return %position; } function SceneObject::rotFromTransform(%obj, %transform) { if(%transform $= "") %transform = %obj.getTransForm(); // the last four words of an object's transform are the object's rotation %rotation = getWord(%transform, 3) SPC getWord(%transform, 4) SPC getWord(%transform, 5) SPC getWord(%transform, 6); return %rotation; } //this finds the terrain height for the position and sets it x meters above the terrain function bumpZ(%pos, %heightMod) { %x = getword(%pos, 0); %y = getword(%pos, 1); %height = getTerrainHeight(%x SPC %y); return %x SPC %y SPC %height + %heightMod; } //this function merely zeroes the z of a pos, not used anymore function gimpPosition(%pos) { return getword(%pos, 0) SPC getword(%pos, 1) SPC "0"; } function getAngleDifferance(%angleOne, %angleTwo) { //we need the smallest angle from angle one to angle two //First ensure both angles are positive %angleOne = %angleOne < 0 ? $TwoPi + %angleOne : %angleOne; %angleTwo = %angleTwo < 0 ? $TwoPi + %angleTwo : %angleTwo; %diff = %angleTwo - %angleOne; %diff = %diff > $Pi ? $TwoPi - %diff : %diff; %diff = %diff < -$Pi ? -$TwoPi - %diff : %diff; return %diff; } //---Directional (compass) functions---- function getClosestCompassTick(%angle) { %value = ""; %angle = %angle < 0 ? $TwoPi + %angle : %angle; if(%angle >= mDegToRad(337.5) || %angle < mDegToRad(22.5)) %value = "North" SPC $North; else if(%angle >= mDegToRad(22.5) && %angle < mDegToRad(67.5)) %value = "NorthEast" SPC $NE; else if(%angle >= mDegToRad(67.5) && %angle < mDegToRad(112.5)) %value = "East" SPC $East; else if(%angle >= mDegToRad(112.5) && %angle < mDegToRad(157.5)) %value = "SouthEast" SPC $SE; else if(%angle >= mDegToRad(157.5) && %angle < mDegToRad(202.5)) %value = "South" SPC $South; else if(%angle >= mDegToRad(202.5) && %angle < mDegToRad(247.5)) %value = "SouthWest" SPC $SW; else if(%angle >= mDegToRad(247.5) && %angle < mDegToRad(292.5)) %value = "West" SPC $West; else if(%angle >= mDegToRad(292.5) && %angle < mDegToRad(337.5)) %value = "NorthWest" SPC $NW; return %value; } function getClosestCardinal(%angle) { %value = ""; %angle = %angle < 0 ? $TwoPi + %angle : %angle; %angle = %angle > $TwoPi ? %angle - $TwoPi : %angle; if(%angle >= mDegToRad(315) || %angle < mDegToRad(45)) %value = "North" SPC $North; else if(%angle >= mDegToRad(45) && %angle < mDegToRad(135)) %value = "East" SPC $East; else if(%angle >= mDegToRad(135) && %angle < mDegToRad(225)) %value = "South" SPC $South; else if(%angle >= mDegToRad(225) && %angle < mDegToRad(315)) %value = "West" SPC $West; //error("getClosestCardinal Value:" SPC %value); return %value; } //----angles and rotations---- function invertDegAngle(%angle) { if(%angle > 0) %angle = -(180 - %angle); else %angle = mAbs(%angle + 180); return %angle; } function invertAngle(%angle) { //add pi, then cap %angle += $PI; %angle = %angle > $TwoPi ? %angle - $TwoPi : %angle; return %angle; } function getAnglefromRot(%rot) { //return a positive z angle in radians %angle = getWord(%rot, 2) * getWord(%rot, 3); %angle = %angle < 0 ? $TwoPi + %angle : %angle; return %angle; } function getDegAnglefromRot(%rot) { //return the rot's z angle in positive degrees %angleOne = mRadtoDeg(getWord(%rot, 2) * getWord(%rot, 3)); %angle = %angleOne < 0 ? 360 + %angleOne : %angleOne; return %angle; } function getZangle(%posOne, %posTwo) { %vec = VectorSub(%posTwo, %posOne); //get the angle %rotAngleZ = mATan( firstWord(%vec), getWord(%vec, 1) ); //add pi to the angle //%rotAngleZ += $Pi; //make this rotation a proper torque game value, anything more than 240 degrees is negative //if(%rotAngleZ > 4.18879) //subtract 2pi from the value, then make sure its positive // %rotAngleZ = -(mAbs(%rotAngleZ - $TwoPi)); return %rotAngleZ; } function absRot(%rot) { %rot = %rot < 0 ? %rot + $TwoPi : %rot; return %rot; } function adjustRot(%rot, %rotAdjust) { %angle = getWord(%rot, 2) * getWord(%rot, 3); //%rotAdjust = ((%rotAdjust >= 4.18879) ? (($TwoPi - %rotAdjust) * -1) : %rotAdjust); %rotAdjust = %rotAdjust < 0 ? $TwoPi + %rotAdjust : %rotAdjust; //now add the angle adjustment to the refrence rot %adjust = %angle + %rotAdjust; //bring in back in line with the torque world %adjust = ((%adjust >= 4.18879) ? (%adjust - $TwoPi) : %adjust); //if it's negative we'll stuff it into the vector and leave the angle value unchanged %rotZ = ((%adjust >= 0) ? 1 : (-1)); %adjust = mAbs(%adjust); %rot = getWord(%rot, 0) SPC getWord(%rot, 1) SPC %rotZ SPC %adjust; return %rot; } // This lil function generates the rotation required for an object at PosOne to point at PosTwo (z rot only) function pointToXYPos(%posOne, %posTwo) { %vec = VectorSub(%posOne, %posTwo); //get the angle %rotAngleZ = mATan( firstWord(%vec), getWord(%vec, 1) ); //add pi to the angle %rotAngleZ += $Pi; //make this rotation a proper torque game value, anything more than 240 degrees is negative if(%rotAngleZ > 4.18879) { //the rotation scale is seldom negative, instead make the axis value negative %modifier = -1; //subtract 2pi from the value, then make sure its positive %rotAngleZ = mAbs(%rotAngleZ - $TwoPi); //sigh, if only this were all true } else %modifier = 1; //assemble the rotation and send it back return "0 0" SPC %modifier SPC %rotAngleZ; } // And this lil function generates the rotation required for an object at posOne to // point at PosTwo for X, Y And Z axis. function pointToPos(%posOne, %posTwo) { //sub the two positions so we get a vector pointing from the origin in the direction we want our object to face %vec = VectorSub(%posTwo, %posOne); // pull the values out of the vector %x = firstWord(%vec); %y = getWord(%vec, 1); %z = getWord(%vec, 2); //this finds the distance from origin to our point %len = vectorLen(%vec); //---------X----------------- //given the rise and length of our vector this will give us the angle in radians %rotAngleX = mATan( %z, %len ); //---------Z----------------- //get the angle for the z axis %rotAngleZ = mATan( %x, %y ); //create 2 matrices, one for the z rotation, the other for the x rotation %matrix = MatrixCreateFromEuler("0 0" SPC %rotAngleZ * -1); %matrix2 = MatrixCreateFromEuler(%rotAngleX SPC "0 0"); //now multiply them together so we end up with the rotation we want %finalMat = MatrixMultiply(%matrix, %matrix2); //we're done, send the proper numbers back return getWords(%finalMat, 3, 6); } function getXYAngle(%posOne, %posTwo) { //sub the two positions so we get a vector pointing from the origin in the direction we want our object to face %vec = VectorSub(%posTwo, %posOne); // pull the values out of the vector %x = firstWord(%vec); %y = getWord(%vec, 1); %z = getWord(%vec, 2); //this finds the distance from origin to our point %len = vectorLen(%vec); //---------XY----------------- //given the rise and length of our vector this will give us the angle in radians %rotAngleXY = mATan( %z, %len ); //%rotAngleXY+=$Pi; return %rotAngleXY; } function getXYangleFromRot(%rot) { %a = getWord(%rot, 3); %x = firstWord(%rot) * %a; %y = getWord(%rot, 1) * %a; %z = getWord(%rot, 2) * %a; %xy = mSqrt((%x * %x) + (%y * %y)); %rotAngleXY = mATan( %xy, mAbs(%z) ); return %rotAngleXY; } function getZrise(%rot, %posOne, %posTwo) { %XYAngle = getXYangleFromRot(%rot); %vec = VectorSub(%posTwo, %posOne); //this finds the distance from origin to our point %len = vectorLen(%vec); //pythagorian theroem says right triangle sides: a squared + b squared = c squared //we need to find the rise amount based on the angle and length // c^2 - a^2 = b^2 //the height of the right triangle equals the tangent of the angle times the length of the base //%zmod = mTan(%XYAngle + $Pi) * (%len + $Pi); %zmod = mTan(%XYAngle) * (%len - $Pi); return %zmod; } //-------------------------------------------------------------------------------------------- // Spline functions //-------------------------------------------------------------------------------------------- // These functions draw a curve from the first point to the last point, going near any middle points at time t. // t represents the percentage of distance between the first and last point that you want the curve point for // They can be used to draw a 3-d spline when all three axis are run through the function. // %t = (position Of Desired Spline Point) / (distance Between First And Last Points) // %curvePoint1.x = get3PointCurveValue(%point1.x, %point2.x, %point3.x, %t) // %curvePoint1.y = get3PointCurveValue(%point1.y, %point2.y, %point3.y, %t) // %curvePoint1.z = get3PointCurveValue(%point1.z, %point2.z, %point3.z, %t) // this lil guy doesn't actually draw a curve, but rather a line, however it is very usefull for mixing // two values together based on a percentage of time or distance function get2PointLineValue(%point1, %point2, %t) { %pd = ( %point1 * (1-%t)) + (%point2 * %t); return %pd; } function get3PointCurveValue(%point1, %point2, %point3, %t) { %step1 = %point1 * ((1-%t) * (1-%t)); %step2 = %point2 * 2 * %t * (1 - %t); %step3 = %point3 * (%t * %t); %pd = %step1 + %step2 + %step3; return %pd; } function get4PointCurveValue(%point1, %point2, %point3, %point4, %t) { %step1 = %point1 * ( (1 - %t)*(1 - %t)*(1 - %t) ); %step2 = %point2 * 3 * %t * ( (1 - %t)*(1 - %t) ); %step3 = %point3 * 3 * (%t * %t) * (1 - %t); %step4 = %point4 * (%t * %t * %t); %pd = %step1 + %step2 + %step3 + %step4; return %pd; } //--------------------------------------------------------------------------------------------------------------- // functions dealing with terrain //--------------------------------------------------------------------------------------------------------------- //this takes the provided position, and sets it to the position of the earest terrain vertex function findNearestTerrainPoint(%pos) { %x = findGridPoint(firstWord(%pos)); %y = findGridPoint(getWord(%pos, 1)); %z = getWord(%pos, 2); return(%x SPC %y SPC %z); } function findGridPoint(%axis) { if(%axis == 0) return 0; %axis = mFloor(%axis); %remainder = %axis % Terrain.squareSize; if(%remainder >= (Terrain.squareSize / 2)) { while(%axis % Terrain.squareSize != 0) %axis++; } else { while(%axis % Terrain.squareSize != 0) %axis--; } return %axis; } //Takes the pos provided, and sets the z value to the surface height function getTerrainSurfacePoint(%pos) { %x = getword(%pos, 0); %y = getword(%pos, 1); %height = getTerrainHeight(%x SPC %y); return %x SPC %y SPC %height; } //in a box with the given max and min x and y extents, this will find the average height value function getAverageTerrainHeight(%minX, %maxX, %minY, %maxY, %squareSize) { %total = 0; %count = 0; for(%x = %minX; %x <= %maxX; %x += %squareSize) { //we are already looping through x, so loop through Y while we're at it for(%y = %minY; %y <= %maxY; %y += %squareSize) { %total += getTerrainHeight(%x SPC %y); %count++; } } return %total / %count; } function getTerrainAngle(%point) { %angleRad = mACos(vectorDot(%point, "0 0 1")); %angleDeg = mRadtoDeg(%angleRad); return %angleDeg; } function getTerrainLevel(%pos, %rad) { while(%retries < 500) { %x = getWord(%pos, 0) + mFloor(getRandom(%rad * 2) - %rad); %y = getWord(%pos, 1) + mFloor(getRandom(%rad * 2) - %rad); %z = getWord(%pos, 2) + mFloor(getRandom(%rad * 2) - %rad); %start = %x @ " " @ %y @ " 5000"; %end = %x @ " " @ %y @ " -1"; %ground = containerRayCast(%start, %end, $TypeMasks::TerrainObjectType, 0); %z = getWord(%ground, 3); %z += 3.5; %position = %x @ " " @ %y @ " " @ %z; %mask = ( $TypeMasks::ShapeBaseObjectType | $TypeMasks::MoveableObjectType | $TypeMasks::StaticShapeObjectType | $TypeMasks::WaterObjectType | $TypeMasks::InteriorObjectType ); InitContainerRadiusSearch( %position, 3.5, %mask ); if(containerSearchNext() == 0) { //error ("Position Is Good"); return %position; } else %retries++; } return( %pos ); } //--------------------------------------------------------------------------------------------------------------- // Functions for moving objects //--------------------------------------------------------------------------------------------------------------- function SceneObject::setOnTerrain(%obj, %pos, %calcOnly) { if(%pos $= "") %pos = %obj.position; %terHeight = getTerrainHeight(%pos); %offset = %obj.GetHeightOffset(); %newPos = firstWord(%pos) SPC getWord(%pos, 1) SPC %terHeight + %offset; if(%calcOnly) return %newPos; else %obj.setTransform(%newPos SPC %obj.rotFromTransform()); } function SceneObject::alignTransforms(%obj, %pos, %rot, %rotAdjust, %xAngle, %yRadius, %zMod, %invert, %calc) { //rotation hack - these rots just aren't natural! if(%rot $= "0 0 1 0" || %rot $= "0 1 0 0" || %rot $= "1 0 0 0") %rot = "0.0001 0.00001 0.99 0.001"; //get the angle of the refrence object(rot) so we know what direction to go to find the new position %angle = getWord(%rot, 2) * getWord(%rot, 3); //this is the angle to find the position at, relative to the refrence point %xAngle = mDegToRad(%xAngle); //now adjust it to be compatible with the refrence rotation %xAngleMod = ((%angle < 0) ? (-1 * %xAngle) : %xAngle); //generate a vector to the adjusted position %matrix = VectorOrthoBasis(getXYangleFromRot(%rot) SPC getWords(%rot,1,2) SPC getWord(%rot, 3) + %xAngleMod); //%matrix = VectorOrthoBasis(getWords(%rot,0,2) SPC getWord(%rot, 3) + %xAngleMod); %yRot = getWords(%matrix, 3, 5); //now scale from our current position the yRadius amount to get our new position %zPos = vectorAdd(%pos, vectorScale(%yRot, %yRadius)); %bPos = firstWord(%zPos) SPC getWord(%zPos, 1) SPC (getWord(%zPos, 2) + %zMod); //right now our new position is on the horizontal plane of world space, if the refrence rot is tilted //we need to move the pos up or down to account for it. //do wee need to adjust the Z hieght position to account for objects rotated on an x or y axis? %XYAngle = getXYangleFromRot(%rot); //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) if(mAbs(%XYAngle) > 0.0174533) { %zRise = getZrise(%rot, %bpos, %pos);// + $Pi; %bPos = getWords(%bPos, 0, 1) SPC getword(%bPos, 2) + %zRise; } //lets try using the trusty ole matrix to take care of any tilt //so first thing is to subtract the target position from the ref position. //it would probably more accurate to calculate this on the surface of a shpere instead of a circle then adjusting //the hieght, but since I don't know how to do that just now we'll go this route, which is plenty damned acurate //if the generated position needs to point in a certain direction relative to the refrence, then generate it's rot if(%rotAdjust !$= "" && %rotAdjust != 0) { //convert the adjustment to radians, then make it a valid torque world angle %rotAdjust = mDegToRad(%rotAdjust); %rotAdjust = ((%rotAdjust >= 4.18879) ? (($TwoPi - %rotAdjust) * -1) : %rotAdjust); //now add the angle adjustment to the refrence rot %adjust = %angle + %rotAdjust; //bring in back in line with the torque world %adjust = ((%adjust >= 4.18879) ? (%adjust - $TwoPi) : %adjust); //if it's negative we'll stuff it into the vector and leave the angle value unchanged %rotZ = ((%adjust >= 0) ? 1 : (-1)); %adjust = mAbs(%adjust); %rot = getWord(%rot, 0) SPC getWord(%rot, 1) SPC %rotZ SPC %adjust; %angle = getWord(%rot, 2) * getWord(%rot, 3); } if(%invert) { //this is for turning the generated position upside down, wonder if this and the above are broken //for tilted refrence rotations? %angleR = -1 * %angle; %Mrot = MatrixCreateFromEuler("0 3.14" SPC %angleR); %rot = getWord(%Mrot, 3) SPC getWord(%Mrot, 4) SPC getWord(%Mrot, 5) SPC getWord(%Mrot, 6); } //we're done, get the hell outta here! %transForm = %bPos SPC %rot; if(%calc) return %transForm; else { %obj.setTransform(%transForm); return; } } //-------------------------------------------------------------------------------------------- // // SceneObject::alignTransforms() -by Founder // //-------------------------------------------------------------------------------------------- // Here it is!! THE mother of all functions!! AMAZING!! // // usage: %objectID.alignTransforms(%pos, %rot, %rotAdjust, %xAngle, %yRadius, %zMod, %invert, %calc); // // %pos is the position of the object(or point) around which to move the (%objectID) // %rot is the final rotation you want %objectID to face // %rotAdjust is for making a rotational offset of %objectID relative to the provided %rot // valid values go from 0 to 360; going clockwise from north(0), east(90) // south(180), west(270) etc. 360 will work, but I don't know what kind of // dumbass would rotate an object by 360 degrees in the z. // %xAngle and %yRadius are vars for adjusting %objectID's position relative to %pos // %yRadius describes a circle of (%yRadius) in size, along which you wish %objectID to be // placed. %xAngle is the relative angle in degrees (0 - 360) from %pos. Where this // angle intersects the circle is the position the object will be placed. // // %zMod is how far up you want to move the object relative to %pos // %invert is weather or not you want to turn %objectID upside down. // true and 1 will invert it, 0, false, or giveing it no value will not. // %calc will have the function return the calculated transform instead of actually moving // the object. // if for any option you do not want to make an adjustment fill the spot with a 0(zero) // negative values will subtract from x y and z axis, but negative values are not valid for // the %rotAdjust value // examples: // %deplObj.alignTransforms(%pos, %rot, 270, 0, 0, 8, true); // %deplObj.alignTransforms(%dPos, %rot, 0, 0, 0.7, -0.05); // // // // -- // - X // - - // P // - - // - - // -- // // // In the diagram above, P equals the position of the player or the position generated by the // deploy code or the postion of the reference object. The circle made up of (-)'s represents // a %yRadius of 5 meters. Or if you prefer, a circle which represents the distance // away from P that you want this object to be. X represents the object for whom we are // generating the new position, and where we want it. X is at an approximately 45 degree angle // from P, which is the northEast tick on the Torque compass. In order to keep X's position relative // to P, no matter what direction P faces you would use the following line of code: // %ObjectID.alignTransforms(%pos(of P), %rot(of P), 0, 45, 5, 0); //-------------------------------------------------------------------------------------------- function SceneObject::alignGroupRot(%obj, %pos, %rot, %rotAdjust, %xAngle, %yRadius, %zMod, %invert, %calc) { %vAngle = getWord(%rot, 3); %angle = getWord(%rot, 2) * getWord(%rot, 3); %xAngle = mDegToRad(%xAngle); %xAngleMod = ((%angle < 0) ? (-1 * %xAngle) : %xAngle); %vRot = getWords(%rot,0,2); %matrix = VectorOrthoBasis(%vRot SPC %vAngle + %xAngleMod); %yRot = getWords(%matrix, 3, 5); %zPos = vectorAdd(%pos, vectorScale(%yRot, %yRadius)); %bPos = firstWord(%zPos) SPC getWord(%zPos, 1) SPC (getWord(%zPos, 2) + %zMod); if(%rotAdjust !$= "" && %rotAdjust != 0) { %deg = mRadtoDeg(%angle); %rotAdjust = ((%rotAdjust >= 240) ? ((360 - %rotAdjust) * -1) : %rotAdjust); %adjust = %deg + %rotAdjust; %adjust = ((%adjust >= 240) ? (%adjust - 360) : %adjust); %rotZ = ((%adjust >= 0) ? 1 : (-1)); %adjust = mAbs(%adjust); %finAngle = mDegToRad(%adjust); %rot = getWord(%rot, 0) SPC getWord(%rot, 1) SPC %rotZ SPC %finAngle; %angle = getWord(%rot, 2) * getWord(%rot, 3); } if(%invert) { %angleR = -1 * %angle; %Mrot = MatrixCreateFromEuler("0 3.14" SPC %angleR); %rot = getWord(%Mrot, 3) SPC getWord(%Mrot, 4) SPC getWord(%Mrot, 5) SPC getWord(%Mrot, 6); } %transForm = %bPos SPC %rot; if(%calc) return %transForm; else { %obj.setTransform(%transForm); return; } } function SceneObject::StartMoveObject(%obj, %endpos, %time, %smoothness, %delay) { if(isObject(%obj)) { %startpos = %obj.getTransform(); %diff = VectorSub(%endpos, %startpos); %numsteps = (%time/1000) * %smoothness; %interval = 1000 / %smoothness; %stepvec = VectorScale(%diff, (1/%numsteps)); %numstepsleft = %numsteps; %currpos = %startpos; %obj.MoveObject(%startpos, %endpos, %numsteps, %numstepsleft, %stepvec, %currpos, %interval, %delay); } } function SceneObject::MoveObject(%obj, %startpos, %endpos, %numsteps, %numstepsleft, %stepvec, %currpos, %interval, %delay) { %rot = rotFromTransform(%obj.getTransform()); %currpos = VectorAdd(%currpos, %stepvec); %obj.setTransForm(%currpos SPC %rot); %numstepsleft--; if(%numstepsleft < 1) return; else %obj.schedule(%interval, "MoveObject", %startpos, %endpos, %numsteps, %numstepsleft, %stepvec, %currpos, %interval, %delay); } function getObjectTypeMask(%obj) { if(%obj.getType() & $TypeMasks::StaticObjectType) error("\c4Type is: $TypeMasks::StaticObjectType"); else if(%obj.getType() & $TypeMasks::EnvironmentObjectType) error("\c4Type is: $TypeMasks::EnvironmentObjectType"); else if(%obj.getType() & $TypeMasks::TerrainObjectType) error("\c4Type is: $TypeMasks::TerrainObjectType"); else if(%obj.getType() & $TypeMasks::InteriorObjectType) error("\c4Type is: $TypeMasks::InteriorObjectType"); else if(%obj.getType() & $TypeMasks::WaterObjectType) error("\c4Type is: $TypeMasks::WaterObjectType"); else if(%obj.getType() & $TypeMasks::TriggerObjectType) error("\c4Type is: $TypeMasks::TriggerObjectType"); else if(%obj.getType() & $TypeMasks::MarkerObjectType) error("\c4Type is: $TypeMasks::MarkerObjectType"); else if(%obj.getType() & $TypeMasks::GameBaseObjectType) error("\c4Type is: $TypeMasks::GameBaseObjectType"); else if(%obj.getType() & $TypeMasks::ShapeBaseObjectType) error("\c4Type is: $TypeMasks::ShapeBaseObjectType"); else if(%obj.getType() & $TypeMasks::CameraObjectType) error("\c4Type is: $TypeMasks::CameraObjectType"); else if(%obj.getType() & $TypeMasks::StaticShapeObjectType) error("\c4Type is: $TypeMasks::StaticShapeObjectType"); else if(%obj.getType() & $TypeMasks::PlayerObjectType) error("\c4Type is: $TypeMasks::PlayerObjectType"); else if(%obj.getType() & $TypeMasks::ItemObjectType) error("\c4Type is: $TypeMasks::ItemObjectType"); else if(%obj.getType() & $TypeMasks::VehicleObjectType) error("\c4Type is: $TypeMasks::VehicleObjectType"); else if(%obj.getType() & $TypeMasks::VehicleBlockerObjectType) error("\c4Type is: $TypeMasks::VehicleBlockerObjectType"); else if(%obj.getType() & $TypeMasks::ProjectileObjectType) error("\c4Type is: $TypeMasks::ProjectileObjectType"); else if(%obj.getType() & $TypeMasks::ExplosionObjectType) error("\c4Type is: $TypeMasks::ExplosionObjectType"); else if(%obj.getType() & $TypeMasks::CorpseObjectType) error("\c4Type is: $TypeMasks::CorpseObjectType"); else if(%obj.getType() & $TypeMasks::DebrisObjectType) error("\c4Type is: $TypeMasks::DebrisObjectType"); else if(%obj.getType() & $TypeMasks::PhysicalZoneObjectType) error("\c4Type is: $TypeMasks::PhysicalZoneObjectType"); else if(%obj.getType() & $TypeMasks::StaticTSObjectType) error("\c4Type is: $TypeMasks::StaticTSObjectType"); else if(%obj.getType() & $TypeMasks::StaticRenderedObjectType) error("\c4Type is: $TypeMasks::StaticRenderedObjectType"); else if(%obj.getType() & $TypeMasks::DamagableItemObjectType) error("\c4Type is: $TypeMasks::DamagableItemObjectType"); else error("\c4Object type is: UNKNOWN"); } // Founder: Apply kickbak to anything function SceneObject::applyKickback(%obj, %kick) { %dir = %obj.getVectorFromTransform( %obj.getTransform(), "reverse" ); %force = vectorScale( %dir, %kick ); %obj.applyImpulse( %obj.posFromTransform(), %force ); } // ZOD: Modified version of above to allow different directions function SceneObject::applyKick(%obj, %amt, %velCap, %dir) { %vec = %obj.getVectorFromTransform( %obj.getTransform(), %dir ); %data = %obj.getDataBlock(); %pos = %obj.posFromTransform(); %velocity = %obj.getVelocity(); %normal = VectorDot( %velocity, VectorNormalize( %velocity ) ); if( %velCap != 0 && %normal > %velCap) // Whatever cap we wish.. { %kick = %amt / %Normal; // Reduce impulse. //retrun; // Or apply no impulse at all and exit out. } else %kick = %amt; %impulse = VectorScale( %vec, %data.mass * %kick ); %obj.applyImpulse(%pos, %impulse); } //-------------------------------------------------------------------------------------------- // Taken from Harold Paul /*Wedge*/ DElia's post in the GG mod forums // http://www.garagegames.com/mg/forums/result.thread.php?qt=50109 function SceneObject::getVectorFromTransform(%obj, %transform, %vector) { %aa = getWords(%transform, 3, 6); %tmat = VectorOrthoBasis(%aa); %rv = getWords(%tMat, 0, 2); %fv = getWords(%tMat, 3, 5); %uv = getWords(%tMat, 6, 8); if(%vector $= "up") return %uv; if(%vector $= "down") return VectorScale(%uv, -1); if(%vector $= "left") return VectorScale(%rv, -1); if(%vector $= "right") return %rv; if(%vector $= "forward") return %fv; if(%vector $= "reverse") return VectorScale(%fv, -1); } //-------------------------------------------------------------------------------------------- function stripTaggedVar(%var) { return stripChars( detag( getTaggedString( %var ) ), "\cp\co\c6\c7\c8\c9" ); } //------------------------------------------------------------------------------------ // Object Box functions //------------------------------------------------------------------------------------ //box = min.x min.y min.z max.x max.y max.z //parse out a particular element function getBoxMinX(%box){ return getWord(%box, 0); } function getBoxMinY(%box){ return getWord(%box, 1); } function getBoxMinZ(%box){ return getWord(%box, 2); } function getBoxMaxX(%box){ return getWord(%box, 3); } function getBoxMaxY(%box){ return getWord(%box, 4); } function getBoxMaxZ(%box){ return getWord(%box, 5); } function SceneObject::getWorldBoxMin(%obj) { %box = %obj.getObjectBox(); %matrix = %obj.getTransForm(); return MatrixMulPoint(%matrix, getWords(%box, 0, 2)); } function SceneObject::getWorldBoxMax(%obj) { %box = %obj.getObjectBox(); %matrix = %obj.getTransForm(); return MatrixMulPoint(%matrix, getWords(%box, 3, 5)); } function SceneObject::getWorldBoxMinX(%obj) { return getWord(%obj.getWorldBoxMin(), 0); } function SceneObject::getWorldBoxMinY(%obj) { return getWord(%obj.getWorldBoxMin(), 1); } function SceneObject::getWorldBoxMinZ(%obj) { return getWord(%obj.getWorldBoxMin(), 2); } function SceneObject::getWorldBoxMaxX(%obj) { return getWord(%obj.getWorldBoxMax(), 0); } function SceneObject::getWorldBoxMaxY(%obj) { return getWord(%obj.getWorldBoxMax(), 1); } function SceneObject::getWorldBoxMaxZ(%obj) { return getWord(%obj.getWorldBoxMax(), 2); } //return a box dimension function SceneObject::GetBoxWidth(%obj) { %box = %obj.getObjectBox(); return mAbs(getBoxMaxX(%box)) + mAbs(getBoxMinX(%box)); } function SceneObject::GetBoxLength(%obj) { %box = %obj.getObjectBox(); return mAbs(getBoxMaxY(%box)) + mAbs(getBoxMinY(%box)); } function SceneObject::GetBoxHeight(%obj) { %box = %obj.getObjectBox(); return mAbs(getBoxMaxZ(%box)) + mAbs(getBoxMinZ(%box)); } function SceneObject::GetBoxCenter(%obj) { //box center by default will be 0 0 0, so use a lil matrix math, get it's current world position %matrix = %obj.getTransForm(); %box = %obj.getObjectBox(); %newBox = MatrixMulPoint(%matrix, getWords(%box, 0, 2)); %newBox = %newBox SPC MatrixMulPoint(%matrix, getWords(%box, 3, 5)); %centerX = (getBoxMinX(%newBox) + getBoxMaxX(%newBox)) * 0.5; %centerY = (getBoxMinY(%newBox) + getBoxMaxY(%newBox)) * 0.5; %centerZ = (getBoxMinZ(%newBox) + getBoxMaxZ(%newBox)) * 0.5; return %centerX SPC %centerY SPC %centerZ; } function SceneObject::GetHeightOffset(%obj) { return mAbs(getWord(%obj.position, 2) - %obj.getWorldBoxMinZ()); } //------------------------------------------------------------------------------------ // Other functionality //------------------------------------------------------------------------------------ function getValidSpawnSurface(%pos, %rad) { while(%retries < 500) { %x = getWord(%pos, 0) + mFloor(getRandom(%rad * 2) - %rad); %y = getWord(%pos, 1) + mFloor(getRandom(%rad * 2) - %rad); %start = %x SPC %y SPC VectorAdd(getWord(%pos, 2), 3.5); %end = %x SPC %y SPC "-1"; %surface = containerRayCast(%start, %end, $TypeMasks::TerrainObjectType | $TypeMasks::InteriorObjectType, 0); %z = getWord(%surface, 3); %position = %x SPC %y SPC %z; %mask = ( $TypeMasks::ShapeBaseObjectType | $TypeMasks::MoveableObjectType | $TypeMasks::StaticShapeObjectType | $TypeMasks::WaterObjectType ); InitContainerRadiusSearch( %position, 3.5, %mask ); if ( containerSearchNext() == 0 ) { //error("Random Position Is Good"); return %position; } else %retries++; } //error("Random Position Is Bad"); return( %pos ); } //-------------------------------------------------------------------------------- //a lil function to mark a position with an object and a default object to use as marker datablock StaticShapeData(markerObject) { category = "Misc"; shapeFile = "~/data/shapes/markers/octahedron.dts"; dynamicType = $TypeMasks::StaticShapeObjectType; }; function markPoint(%pos, %rot, %block, %type, %name) { if(%block $= "" && %type $= "") { %type = StaticShape; %block = markerObject; } %obj = new (%type)(%name) { dataBlock = %block; }; MissionCleanup.add(%obj); %obj.setTransform(%pos SPC %rot); } function markPointArray(%array) { %count = %array.count(); for(%i = 0; %i < %count; %i++) { markPoint(%array.getValue(%i)); } } //-------------------------------------------------------------------------------------------- // String functions //-------------------------------------------------------------------------------------------- // Returns true if a string passed to it consists of nothing but digits and/or decimals. // Passes false for strings with more than one decimal, or with a + // or - as anything but the first character (+ or - are only allowed as the first character in the string) function isCleanNumber(%string) { %dot = 0; for(%i = 0; (%char = getSubStr(%string, %i, 1)) !$= ""; %i++) { switch$(%char) { case "0" or "1" or "2" or "3" or "4" or "5" or "6" or "7" or "8" or "9": continue; case ".": if(%dot > 1) return false; %dot++; continue; case "-": if(%i) // only valid as first character return false; continue; case "+": if(%i) // only valid as first character return false; continue; default: return false; } } // %text passed the test return true; } //this function takes a pathed filename (common/missions/blah.mis) and takes out everything excpet the name (blah) function cropToName(%filePAth) { %name = ""; %length = strlen(%filePAth); %dot = 0; for(%i = 0; %i < %length; %i++) { if(getSubStr(%filePAth, %i, 1) $= "/") %lastDir = %i; if(getSubStr(%filePAth, %i, 1) $= ".") %dot = %i; } if(%dot > 0) { if(%lastDir $= "") %name = getSubStr(%filePAth, 0, %dot - 1); else %name = getSubStr(%filePAth, %lastDir + 1, %dot - 1); } else %name = getSubStr(%filePAth, %lastDir + 1, %length); return %name; } function cropDecimal(%num) { %length = strlen(%num); %dot = 0; for(%i = 0; %i < %length; %i++) { if(getSubStr(%num, %i, 1) $= ".") %dot = %i; } if(%dot > 0) %name = getSubStr(%num, 0, %dot); else %name = %num; return %name; } function messageTest() { 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'); echo("\c0test \c1test \c2test \c3test \c4test \c5test \c6test \c7test \c8test \c9test"); } //-------------------------------------------------------------------------------------------- // Taken from Harold "LabRat" Brown's .plan // http://www.garagegames.com/index.php?sec=mg&mod=resource&page=view&qid=10202 function dec2hex(%val) { // Converts a decimal number into a 2 digit HEX number %digits ="0123456789ABCDEF"; //HEX digit table // To get the first number we divide by 16 and then round down, using // that number as a lookup into our HEX table. %firstDigit = getSubStr(%digits,mFloor(%val/16),1); // To get the second number we do a MOD 16 and using that number as a // lookup into our HEX table. %secDigit = getSubStr(%digits,%val % 16,1); // return our two digit HEX number return %firstDigit @ %secDigit; } function chrValue(%chr) { // So we don't have to do any C++ changes we approximate the function // to return ASCII Values for a character. This ignores the first 31 // characters and the last 128. // Setup our Character Table. Starting with ASCII character 32 (SPACE) %charTable = " !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_'abcdefghijklmnopqrstuvwxyz{|}~\t\n\r"; //Find the position in the string for the Character we are looking for the value of %value = strpos(%charTable,%chr); // Add 32 to the value to get the true ASCII value %value = %value + 32; //HACK: Encode TAB, New Line and Carriage Return if (%value >= 127) { if(%value == 127) %value = 9; if(%value == 128) %value = 10; if(%value == 129) %value = 13; } //return the value of the character return %value; } function URLEncode(%rawString) { // Encode strings to be HTTP safe for URL use // Table of characters that are valid in an HTTP URL %validChars = "1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz:/.?=_-$(){}~&"; // If the string we are encoding has text... start encoding if (strlen(%rawString) > 0) { // Loop through each character in the string for(%i=0;%i