diff --git a/scripts/DXAI/helpers.cs b/scripts/DXAI/helpers.cs index 87221ed..98b4d1a 100644 --- a/scripts/DXAI/helpers.cs +++ b/scripts/DXAI/helpers.cs @@ -4,7 +4,7 @@ // https://github.com/Ragora/T2-DXAI.git // // Copyright (c) 2015 Robert MacGregor -// This software is licensed under the MIT license. +// This software is licensed under the MIT license. // Refer to LICENSE.txt for more information. //------------------------------------------------------------------------------------------ @@ -12,10 +12,10 @@ function sameSide(%p1, %p2, %a, %b) { %cp1 = vectorCross(vectorSub(%b, %a), vectorSub(%p1, %a)); %cp2 = vectorCross(vectorSub(%b, %a), vectorSub(%p2, %a)); - + if (vectorDot(%cp1, %cp2) >= 0) return true; - + return false; } @@ -26,17 +26,23 @@ function sameSide(%p1, %p2, %a, %b) // Param %a: One point of the triangle. // Param %b: One point of the triangle. // Param %c: One point of the triangle. -// Return: A boolean representing whether or not the given point resides inside of the +// Return: A boolean representing whether or not the given point resides inside of the // triangle. //------------------------------------------------------------------------------------------ function pointInTriangle(%point, %a, %b, %c) { if (sameSide(%point, %a, %b, %c) && sameSide(%point, %b, %a, %c) && sameSide(%point, %c, %a, %b)) return true; - + return false; } +function Player::getXFacing(%this) +{ + %forward = %this.getForwardVector(); + return mAtan(getWord(%forward, 1), getWord(%forward, 0)); +} + //------------------------------------------------------------------------------------------ // Description: Calculates all the points of the given client's view cone given a maximum // view distance and returns them in a long string. @@ -48,60 +54,30 @@ function pointInTriangle(%point, %a, %b, %c) // TODO: Return in a faster-to-read format: Could try as static GVar names // as the game's scripting environment for the gameplay is single threaded // and it probably does a hash to store the values. -// FIXME: Mathematical optimizations, right now it's a hack because of no -// reliable way of getting a player's X facing? Also, the horizontal view cones may -// be all that's necessary. A player height check could be used to help alleviate -// computational complexity. +// FIXME: The horizontal view cones may be all that's necessary. A player +// height check could be used to help alleviate computational complexity. //------------------------------------------------------------------------------------------ function GameConnection::calculateViewCone(%this, %distance) { if (!isObject(%this.player) || %this.player.getState() !$= "Move") return -1; - - //%xFacing = %this.player.getXFacing(); - %halfView = %this.fieldOfView / 2; + + %xFacing = %this.player.getXFacing(); %coneOrigin = %this.player.getMuzzlePoint($WeaponSlot); - - %forwardVector = %this.player.getForwardVector(); - %sideVector = vectorCross("0 0 1", %forwardVector); - - // Clockwise - //%viewConeClockwise = %xFacing - %halfView; - - // %viewConeClockwisePoint = mCos(%viewConeClockwise) SPC mSin(%viewConeClockwise) SPC "0"; - %viewConeClockwisePoint = mCos(-%halfView) SPC mSin(-%halfView) SPC "0"; - %viewConeClockwisePoint = vectorScale(%viewConeClockwisePoint, %this.viewDistance); - //%viewConeClockwisePoint = vectorAdd(%viewConeClockwisePoint, %coneOrigin); - - // Counter Clockwise - //%viewConeCounterClockwise = %xFacing + %halfView; - - //%viewConeCounterClockwisePoint = mCos(%viewConeCounterClockwise) SPC mSin(%viewConeCounterClockwise) SPC "0"; - %viewConeCounterClockwisePoint = mCos(%halfView) SPC mSin(%halfView) SPC "0"; - %viewConeCounterClockwisePoint = vectorScale(%viewConeCounterClockwisePoint, %this.viewDistance); - //%viewConeCounterClockwisePoint = vectorAdd(%viewConeCounterClockwisePoint, %coneOrigin); - - // Offsets - %halfDistance = vectorDist(%viewConeCounterClockwisePoint, %viewConeClockwisePoint) / 2; - - %viewConeCounterClockwisePoint = vectorScale(%sideVector, %halfDistance); - %viewConeCounterClockwisePoint = vectorAdd(%coneOrigin, %viewConeCounterClockwisePoint); - - %viewConeClockwisePoint = vectorScale(vectorScale(%sideVector, -1), %halfDistance); - %viewConeClockwisePoint = vectorAdd(%coneOrigin, %viewConeClockwisePoint); - + + %halfView = %this.fieldOfView / 2; + %cos = mCos(%halfView); + %sin = mSin(%halfView); + + // Translate the horizontal points + %viewConeClockwisePoint = vectorAdd(%coneOrigin, vectorScale(%cos SPC -%sin SPC "0", %this.viewDistance)); + %viewConeCounterClockwisePoint = vectorAdd(%coneOrigin, vectorScale(%cos SPC -%sin SPC "0", %this.viewDistance)); + // Translate the upper and lower points - %viewForwardPoint = vectorScale(%forwardVector, %this.viewDistance); - - %viewConeUpperPoint = vectorAdd(vectorScale("0 0 1", %halfDistance), %viewForwardPoint); - %viewConeUpperPoint = vectorAdd(%coneOrigin, %viewConeUpperPoint); - - %viewConeLowerPoint = vectorAdd(vectorScale("0 0 -1", %halfDistance), %viewForwardPoint); - %viewConeLowerPoint = vectorAdd(%coneOrigin, %viewConeLowerPoint); - - // Now cast them forward - %viewConeClockwisePoint = vectorAdd(%viewConeClockwisePoint, vectorScale(%this.player.getForwardVector(), %this.viewDistance)); - %viewConeCounterClockwisePoint = vectorAdd(%viewConeCounterClockwisePoint, vectorScale(%this.player.getForwardVector(), %this.viewDistance)); + %halfDistance = vectorDist(%viewConeCounterClockwisePoint, %viewConeClockwisePoint) / 2; + + %viewConeUpperPoint = vectorAdd(%coneOrigin, "0 0" SPC %halfDistance); + %viewConeLowerPoint = vectorAdd(%coneOrigin, "0 0" SPC -%halfDistance); return %coneOrigin SPC %viewConeClockwisePoint SPC %viewConeCounterClockwisePoint SPC %viewConeUpperPoint SPC %viewConeLowerPoint; } @@ -116,17 +92,17 @@ function SimSet::recurse(%this, %result) { if (!isObject(%result)) %result = new SimSet(); - + for (%iteration = 0; %iteration < %this.getCount(); %iteration++) { %current = %this.getObject(%iteration); - + if (%current.getClassName() $= "SimGroup" || %current.getClassName() $= "SimSet") %current.recurse(%result); else %result.add(%current); } - + return %result; } @@ -142,23 +118,23 @@ function GameConnection::getClosestInventory(%this) { if (!isObject(%this.player)) return -1; - + %group = nameToID("Team" @ %this.team); if (!isObject(%group)) return -1; - + %teamObjects = %group.recurse(); - + %closestInventory = -1; %closestInventoryDistance = 9999; for (%iteration = 0; %iteration < %teamObjects.getCount(); %iteration++) { %current = %teamObjects.getObject(%iteration); - + if (%current.getClassName() $= "StaticShape" && %current.getDatablock().getName() $= "StationInventory") { %inventoryDistance = vectorDist(%current.getPosition(), %this.player.getPosition()); - + if (%inventoryDistance < %closestInventoryDistance) { %closestInventoryDistance = %inventoryDistance; @@ -166,9 +142,9 @@ function GameConnection::getClosestInventory(%this) } } } - + %teamObjects.delete(); - + return %closestInventory; } @@ -190,27 +166,27 @@ function GameConnection::getObjectsInViewcone(%this, %typeMask, %distance, %perf %this.fieldOfView = $DXAPI::Bot::DefaultFieldOfView; error("DXAI: Bad field of view value! (" @ %this @ ".fieldOfView > 3.14 || " @ %this @ ".fieldOfView < 0)"); } - + if (%this.viewDistance <= 0) { %this.viewDistance = $DXAPI::Bot::DefaultViewDistance; error("DXAI: Bad view distance value! (" @ %this @ ".viewDistance <= 0)"); } - + if (%distance $= "") %distance = %this.viewDistance; - + %viewCone = %this.calculateViewCone(%distance); - + // Extract the results: See TODO above ::calculateViewCone implementation %coneOrigin = getWords(%viewCone, 0, 2); %viewConeClockwiseVector = getWords(%viewCone, 3, 5); %viewConeCounterClockwiseVector = getWords(%viewCone, 6, 8); %viewConeUpperVector = getWords(%viewCone, 9, 11); %viewConeLowerVector = getWords(%viewCone, 12, 14); - + %result = new SimSet(); - + // Doing a radius search should hopefully be faster than iterating over all objects in MissionCleanup. // Even if the game did that internally it's definitely faster than doing it in TS InitContainerRadiusSearch(%coneOrigin, %distance, %typeMask); @@ -227,9 +203,9 @@ function GameConnection::getObjectsInViewcone(%this, %typeMask, %distance, %perf else { %rayCast = containerRayCast(%coneOrigin, %currentObject.getWorldBoxCenter(), $TypeMasks::AllObjectType, %this.player); - + %hitObject = getWord(%raycast, 0); - + // Since the engine doesn't do raycasts against projectiles & items correctly, we just check if the bot // hit -nothing- when doing the raycast rather than checking for a hit against the object %workaroundTypes = $TypeMasks::ProjectileObjectType | $TypeMasks::ItemObjectType; @@ -238,14 +214,14 @@ function GameConnection::getObjectsInViewcone(%this, %typeMask, %distance, %perf } } } - + return %result; } //------------------------------------------------------------------------------------------ // Description: Gets a random position somewhere within %distance of the given position. // Param %position: The position to generate a new position around. -// Param %distance: The maximum distance the new position may be +// Param %distance: The maximum distance the new position may be // Param %raycast: A boolean representing whether or not a raycast should be made from // %position to the randomly chosen location to stop on objects that may be in the way. // This is useful for grabbing positions indoors. @@ -254,16 +230,16 @@ function getRandomPosition(%position, %distance, %raycast) { // First, we determine a random direction vector %direction = vectorNormalize(getRandom(0, 10000) SPC getRandom(0, 10000) SPC getRandom(0, 10000)); - + // Return the scaled result %result = vectorAdd(%position, vectorScale(%direction, getRandom(0, %distance))); - + if (!%raycast) return %result; - + %rayCast = containerRayCast(%position, %result, $TypeMasks::AllObjectType, 0); %result = getWords(%raycast, 1, 3); - + return %result; } @@ -273,7 +249,7 @@ function getRandomPosition(%position, %distance, %raycast) // getRandomPosition with the raycast setting if all that is necessary is generating a // position relative to the terrain object. // Param %position: The position to generate a new position around. -// Param %distance: The maximum distance the new position may be +// Param %distance: The maximum distance the new position may be //------------------------------------------------------------------------------------------ function getRandomPositionOnTerrain(%position, %distance) { @@ -289,8 +265,8 @@ function getRandomPositionOnTerrain(%position, %distance) //------------------------------------------------------------------------------------------ function vectorMult(%vec1, %vec2) { - return (getWord(%vec1, 0) * getWord(%vec2, 0)) SPC - (getWord(%vec1, 1) * getWord(%vec2, 1)) SPC + return (getWord(%vec1, 0) * getWord(%vec2, 0)) SPC + (getWord(%vec1, 1) * getWord(%vec2, 1)) SPC (getWord(%vec1, 2) * getWord(%vec2, 2)); }