//-----------------------------------------------------------------------------
// 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<strlen(%rawString);%i++)
{
// Grab the character at our current index location
%chrTemp = getSubStr(%rawString,%i,1);
// If the character is not valid for an HTTP URL... Encode it
if (strstr(%validChars,%chrTemp) == -1)
{
//Get the HEX value for the character
%chrTemp = dec2hex(chrValue(%chrTemp));
// Is it a space? Change it to a "+" symbol
if (%chrTemp $= "20")
{
%chrTemp = "+";
}
else
{
// It's not a space, prepend the HEX value with a %
%chrTemp = "%" @ %chrTemp;
}
}
// Build our encoded string
%encodeString = %encodeString @ %chrTemp;
}
}
// Return the encoded string value
return %encodeString;
}
//--------------------------------------------------------------------------------------------
// Zod: A default raycast function
function ShapeBase::doRaycast(%this, %range, %mask)
{
// get the eye vector and eye transform of the player
%eyeVec = %this.getEyeVector();
%eyeTrans = %this.getEyeTransform();
// extract the position of the player's camera from the eye transform (first 3 words)
%eyePos = posFromTransform(%eyeTrans);
// normalize the eye vector
%nEyeVec = VectorNormalize(%eyeVec);
// scale (lengthen) the normalized eye vector according to the search range
%scEyeVec = VectorScale(%nEyeVec, %range);
// add the scaled & normalized eye vector to the position of the camera
%eyeEnd = VectorAdd(%eyePos, %scEyeVec);
// see if anything gets hit
%searchResult = containerRayCast(%eyePos, %eyeEnd, %mask, %this);
return %searchResult;
}
Comments
0 B
|👍
/👎