Metric VectorToPolarRadians (const CVector &vP, Metric *retrRadius) // VectorToPolarRadians // // Converts from a vector to polar coordinates (see PolarToVector) { Metric rAngle; Metric rRadius; Metric rSqrRadius = vP.Dot(vP); // If we are at the origin then the angle is undefined if (rSqrRadius == 0.0) { rAngle = 0.0; rRadius = 0.0; } else { rRadius = sqrt(rSqrRadius); if (vP.GetX() >= 0.0) rAngle = (vP.GetY() >= 0.0 ? asin(vP.GetY() / rRadius) : (2 * g_Pi) + asin(vP.GetY() / rRadius)); else rAngle = g_Pi - asin(vP.GetY() / rRadius); } // Done if (retrRadius) *retrRadius = rRadius; return rAngle; }
int VectorToPolar (const CVector &vP, Metric *retrRadius) // VectorToPolar // // Converts from a vector to polar coordinates (see PolarToVector) { int iAngle; Metric rRadius; Metric rSqrRadius = vP.Dot(vP); // If we are at the origin then the angle is undefined if (rSqrRadius == 0.0) { iAngle = 0; rRadius = 0.0; } else { rRadius = sqrt(rSqrRadius); if (vP.GetX() >= 0.0) iAngle = (((int)(180 * asin(vP.GetY() / rRadius) / g_Pi)) + 360) % 360; else iAngle = 180 - ((int)(180 * asin(vP.GetY() / rRadius) / g_Pi)); } // Done if (retrRadius) *retrRadius = rRadius; return iAngle; }
void CAutoDefenseClass::Update (CInstalledDevice *pDevice, CSpaceObject *pSource, int iTick, bool *retbSourceDestroyed, bool *retbConsumedItems) // Update // // Update device { if (pDevice->IsReady() && pDevice->IsEnabled()) { int i; // Look for a target CSpaceObject *pBestTarget = NULL; Metric rBestDist2 = MAX_INTERCEPT_DISTANCE * MAX_INTERCEPT_DISTANCE; for (i = 0; i < pSource->GetSystem()->GetObjectCount(); i++) { CSpaceObject *pObj = pSource->GetSystem()->GetObject(i); if (pObj && pObj->GetCategory() == CSpaceObject::catMissile && pObj->GetSource() != pSource && (pObj->GetSource() == NULL || pSource->IsEnemy(pObj->GetSource()))) { CVector vRange = pObj->GetPos() - pSource->GetPos(); Metric rDistance2 = vRange.Dot(vRange); if (rDistance2 < rBestDist2) { pBestTarget = pObj; rBestDist2 = rDistance2; } } } // If we found a target, try to shoot at it if (pBestTarget) { CDeviceClass *pWeapon = GetWeapon(); if (pWeapon) { int iFireAngle; if (pWeapon->IsWeaponAligned(pSource, pDevice, pBestTarget, &iFireAngle)) { pDevice->SetFireAngle(iFireAngle); pWeapon->Activate(pDevice, pSource, pBestTarget, iFireAngle, retbSourceDestroyed, retbConsumedItems); pDevice->SetActivationDelay(m_iRechargeTicks); } } } } }
void CZoanthropeAI::ImplementCombatManeuvers (CSpaceObject *pTarget) // ImplementCombatManeuvers // // Move and fire { CVector vTarget = pTarget->GetPos() - m_pShip->GetPos(); Metric rTargetDist2 = vTarget.Dot(vTarget); // Fire on the target as best we can (if iFireDir is not -1, then it // is the angle that we should turn towards to be able to fire). int iFireDir; m_AICtx.ImplementFireWeaponOnTarget(m_pShip, -1, -1, pTarget, vTarget, rTargetDist2, &iFireDir); // Compute our flocking position CVector vFlockPos; CVector vFlockVel; int iFlockFacing; if (rTargetDist2 > COMBAT_RANGE2 && m_AICtx.CalcFlockingFormation(m_pShip, NULL, MAX_FLOCK_DIST, SEPARATION_RANGE, &vFlockPos, &vFlockVel, &iFlockFacing)) { m_AICtx.ImplementFormationManeuver(m_pShip, vFlockPos, vFlockVel, m_pShip->AlignToRotationAngle(iFlockFacing)); } // Otherwise, if we are the leader, then fight else { // If we're not well in range of our primary weapon then // get closer to the target. (Or if we are not moving) if (rTargetDist2 > m_AICtx.GetPrimaryAimRange2()) { // Try to flank our target, if we are faster bool bFlank = (m_pShip->GetMaxSpeed() > pTarget->GetMaxSpeed()); m_AICtx.ImplementCloseOnTarget(m_pShip, pTarget, vTarget, rTargetDist2, bFlank); iFireDir = -1; } else if (pTarget->CanMove() && (m_pShip->GetVel().Length2() < (0.01 * 0.01 * LIGHT_SPEED * LIGHT_SPEED))) { m_AICtx.ImplementSpiralOut(m_pShip, vTarget); iFireDir = -1; } // If necessary, turn to aim our weapon based on the fire solution if (iFireDir != -1 && !m_AICtx.NoDogfights()) m_AICtx.ImplementManeuver(m_pShip, iFireDir, false); } }
CSpaceObject *CFerianShipAI::FindRandomAsteroid (void) // FindRandomAsteroid // // Returns a random asteroid within 60 light-seconds { int i; Metric rMaxDist2 = MAX_MINING_RANGE2; Metric rCloseDist2 = CLOSE_MINING_RANGE2; CSpaceObject *Table[MAX_RANDOM_COUNT]; int iCount = 0; for (i = 0; (i < m_pShip->GetSystem()->GetObjectCount() && iCount < MAX_RANDOM_COUNT); i++) { CSpaceObject *pObj = m_pShip->GetSystem()->GetObject(i); if (pObj && pObj->HasAttribute(ATTRIBUTE_ASTEROID)) { CVector vRange = pObj->GetPos() - m_pShip->GetPos(); Metric rDistance2 = vRange.Dot(vRange); // If we're within the max dist, add it to the list if (rDistance2 < rMaxDist2) Table[iCount++] = pObj; // If we're within 10 light-seconds, add it twice more (to increase // the probability) if (rDistance2 < rCloseDist2) { Table[iCount++] = pObj; Table[iCount++] = pObj; } } } // Pick a random entry from the list if (iCount == 0) return NULL; else return Table[mathRandom(0, iCount-1)]; }
BOOL CRVTrackerDrawPoly::OnStart() { // Make sure they're in the right edit mode for this.. if ((m_pView->GetEditMode() != BRUSH_EDITMODE) && (m_pView->GetEditMode() != GEOMETRY_EDITMODE)) return FALSE; //make sure that they weren't waiting for a polygon to finish, this fixes //a weird issue where a new tracker would get started after one just finished, //causing another brush drawing to begin right after the old one finished if(m_bFinishDrawingPoly) { return FALSE; } CEditVert vert; if( m_pView->GetVertexFromPoint(m_cCurPt, vert) ) { if( !m_pView->IsPerspectiveViewType( )) { CVector vOffset; vOffset = m_pView->EditGrid( ).Forward( ); vOffset = m_pView->EditGrid( ).Forward( ) * vOffset.Dot( m_pView->GetRegion( )->m_vMarker ); vert += vOffset; } m_pView->m_EditState = EDIT_DRAWINGPOLY; } else // Not sure how this would happen, but if we can't create the first vertex, cancel the tracker return FALSE; // Setup the new brush. m_pView->DrawingBrush().m_Points.Append( vert ); m_pView->DrawingBrush().m_Points.Append( vert ); // Update the view m_pView->GetDocument()->UpdateAllViews(m_pView); m_pView->DrawRect(); return TRUE; }
/* norm */ float Len2() { return fScalar*fScalar + cV.Dot( cV ); }
void CZoanthropeAI::Behavior (void) // Behavior { // Reset ResetBehavior(); // Behave according to our state switch (m_State) { case stateNone: BehaviorStart(); break; case stateAttackingOnPatrol: { ASSERT(m_pTarget); ImplementCombatManeuvers(m_pTarget); m_AICtx.ImplementFireOnTargetsOfOpportunity(m_pShip, m_pTarget); // See if we're out of our zone Metric rRange = LIGHT_SECOND * GetCurrentOrderData(); if (CheckOutOfZone(GetCurrentOrderTarget(), rRange - PATROL_SENSOR_RANGE, rRange + PATROL_SENSOR_RANGE, 30)) SetState(stateNone); break; } case stateAttackingThreat: { ASSERT(m_pTarget); ImplementCombatManeuvers(m_pTarget); m_AICtx.ImplementFireOnTargetsOfOpportunity(m_pShip, m_pTarget); // Every once in a while check to see if we've wandered too far from // our base. if (CheckOutOfRange(GetCurrentOrderTarget(), PATROL_SENSOR_RANGE, 20)) SetState(stateNone); break; } case stateOnCourseForStargate: { m_AICtx.ImplementGating(m_pShip, m_pBase); m_AICtx.ImplementAttackNearestTarget(m_pShip, ATTACK_RANGE, &m_pTarget); m_AICtx.ImplementFireOnTargetsOfOpportunity(m_pShip); break; } case stateOnEscortCourse: { ASSERT(m_pBase); CVector vFlockPos; CVector vFlockVel; int iFlockFacing; if (m_AICtx.CalcFlockingFormation(m_pShip, m_pBase, MAX_FLOCK_DIST, SEPARATION_RANGE, &vFlockPos, &vFlockVel, &iFlockFacing)) { m_AICtx.ImplementFormationManeuver(m_pShip, vFlockPos, vFlockVel, m_pShip->AlignToRotationAngle(iFlockFacing)); } else { CVector vTarget = m_pBase->GetPos() - m_pShip->GetPos(); Metric rTargetDist2 = vTarget.Dot(vTarget); m_AICtx.ImplementCloseOnTarget(m_pShip, m_pBase, vTarget, rTargetDist2); m_AICtx.ImplementAttackNearestTarget(m_pShip, m_AICtx.GetMaxWeaponRange(), &m_pTarget); m_AICtx.ImplementFireOnTargetsOfOpportunity(m_pShip); } // See if there is anything to attack CSpaceObject *pTarget; if (CheckForEnemiesInRange(m_pShip, PATROL_SENSOR_RANGE, 30, &pTarget)) SetState(stateAttackingThreat, m_pBase, pTarget); break; } case stateOnPatrolOrbit: { ASSERT(m_pBase); CVector vFlockPos; CVector vFlockVel; int iFlockFacing; if (m_AICtx.CalcFlockingFormation(m_pShip, NULL, MAX_FLOCK_DIST, SEPARATION_RANGE, &vFlockPos, &vFlockVel, &iFlockFacing)) { m_AICtx.ImplementFormationManeuver(m_pShip, vFlockPos, vFlockVel, m_pShip->AlignToRotationAngle(iFlockFacing)); } else { m_AICtx.ImplementOrbit(m_pShip, m_pBase, LIGHT_SECOND * GetCurrentOrderData()); m_AICtx.ImplementAttackNearestTarget(m_pShip, m_AICtx.GetMaxWeaponRange(), &m_pTarget); m_AICtx.ImplementFireOnTargetsOfOpportunity(m_pShip); } // See if there is anything to attack CSpaceObject *pTarget; if (CheckForEnemiesInRange(m_pShip, PATROL_SENSOR_RANGE, 30, &pTarget)) SetState(stateAttackingOnPatrol, m_pBase, pTarget); break; } case stateReturningFromThreat: { ASSERT(m_pBase); m_AICtx.ImplementDocking(m_pShip, m_pBase); m_AICtx.ImplementAttackNearestTarget(m_pShip, m_AICtx.GetMaxWeaponRange(), &m_pTarget); m_AICtx.ImplementFireOnTargetsOfOpportunity(m_pShip); // See if there is anything to attack CSpaceObject *pTarget; if (CheckForEnemiesInRange(m_pBase, PATROL_SENSOR_RANGE, 30, &pTarget)) SetState(stateAttackingThreat, m_pBase, pTarget); break; } case stateWaiting: m_AICtx.ImplementStop(m_pShip); if (m_pTarget) m_AICtx.ImplementAttackTarget(m_pShip, m_pTarget, true); m_AICtx.ImplementAttackNearestTarget(m_pShip, m_AICtx.GetMaxWeaponRange(), &m_pTarget); m_AICtx.ImplementFireOnTargetsOfOpportunity(m_pShip); break; case stateWaitingForThreat: { ASSERT(m_pBase); CSpaceObject *pTarget; if (CheckForEnemiesInRange(m_pBase, PATROL_SENSOR_RANGE, 30, &pTarget)) SetState(stateAttackingThreat, m_pBase, pTarget); break; } } }
BOOL CRVTrackerDrawPoly::OnRotate() { // Get the brush CEditBrush *pBrush = &m_pView->DrawingBrush(); // Make sure we've got at least three points specified if (pBrush->m_Points.GetSize() < 3) return FALSE; // The origin's point #1 CVector vOrigin = pBrush->m_Points[0]; // The original rotation direction's point #2 CVector vBase = pBrush->m_Points[1]; // The new rotation's point #3 CVector vNew = pBrush->m_Points[2]; // Get the base direction CVector vBaseDir = vBase - vOrigin; float fBaseMag = vBaseDir.Mag(); // Don't allow duplicate points if (fBaseMag < 0.01f) return TRUE; vBaseDir *= 1.0f / fBaseMag; // Get the rotation direction CVector vNewDir = vNew - vOrigin; float fNewMag = vNewDir.Mag(); // Don't allow duplicate points if (fNewMag < 0.01f) return TRUE; vNewDir *= 1.0f / fNewMag; // Get the rotation axis CVector vRotAxis = vNewDir.Cross(vBaseDir); // Get the sin of the angle from the cross product float fRotAngle = vRotAxis.Mag(); // Don't bother if the angle's 0... if (fRotAngle == 0.0f) return TRUE; // Normalize the axis vRotAxis *= 1.0f / fRotAngle; // Get the actual angle fRotAngle = (float)asin(fRotAngle); // Handle obtuse angles.. if (vBaseDir.Dot(vNewDir) < 0.0f) fRotAngle = MATH_PI - fRotAngle; LTMatrix mRotation; // Get the rotation matrix mRotation.SetupRot(vRotAxis, fRotAngle); // Set up an undo.. CEditRegion *pRegion = m_pView->GetRegion(); PreActionList actionList; for (uint32 nUndoLoop = 0; nUndoLoop < pRegion->m_Selections; ++nUndoLoop) actionList.AddTail(new CPreAction(ACTION_MODIFYNODE, pRegion->m_Selections[nUndoLoop])); m_pView->GetRegionDoc()->Modify(&actionList, TRUE); // If we're in geometry mode.. if (m_pView->GetEditMode() == GEOMETRY_EDITMODE) { // Get the selected vertices CVertRefArray vertList; m_pView->GetSelectedVerts(vertList); // Rotate 'em for (uint32 nVertLoop = 0; nVertLoop < vertList.GetSize(); ++nVertLoop) { CVertRef vert = vertList[nVertLoop]; if (!vert.IsValid()) continue; vert() -= vOrigin; mRotation.Apply(vert()); vert() += vOrigin; } } else { // Otherwise, rotate all the selected nodes for (uint32 nNodeLoop = 0; nNodeLoop < pRegion->m_Selections.GetSize( ); ++nNodeLoop) { pRegion->m_Selections[nNodeLoop]->Rotate(mRotation, vOrigin); } // Update the selection box since stuff rotated... m_pView->GetRegionDoc()->UpdateSelectionBox(); } return TRUE; }
void CAutonAI::Behavior (void) // Behavior // // Fly, fight, die { // Reset ResetBehavior(); // Behave according to our state switch (m_State) { case stateNone: BehaviorStart(); break; case stateAttackingTarget: ASSERT(m_pTarget); m_AICtx.ImplementAttackTarget(m_pShip, m_pTarget); m_AICtx.ImplementFireOnTargetsOfOpportunity(m_pShip, m_pTarget); break; case stateEscorting: m_AICtx.ImplementEscort(m_pShip, m_pDest, &m_pTarget); break; case stateFollowing: { ASSERT(m_pDest); CVector vTarget = m_pDest->GetPos() - m_pShip->GetPos(); Metric rTargetDist2 = vTarget.Dot(vTarget); Metric rMaxDist = (MAX_FOLLOW_DISTANCE) + (g_KlicksPerPixel * (m_pShip->GetDestiny() % 120)); if (rTargetDist2 > (rMaxDist * rMaxDist)) m_AICtx.ImplementCloseOnTarget(m_pShip, m_pDest, vTarget, rTargetDist2); else if (rTargetDist2 < (g_KlicksPerPixel * g_KlicksPerPixel * 1024.0)) m_AICtx.ImplementSpiralOut(m_pShip, vTarget); else m_AICtx.ImplementStop(m_pShip); if (m_pTarget) m_AICtx.ImplementAttackTarget(m_pShip, m_pTarget, true); m_AICtx.ImplementAttackNearestTarget(m_pShip, ATTACK_RANGE, &m_pTarget); m_AICtx.ImplementFireOnTargetsOfOpportunity(m_pShip); break; } case stateOnCourseForStargate: m_AICtx.ImplementGating(m_pShip, m_pDest); m_AICtx.ImplementAttackNearestTarget(m_pShip, ATTACK_RANGE, &m_pTarget); m_AICtx.ImplementFireOnTargetsOfOpportunity(m_pShip); break; case stateWaiting: m_AICtx.ImplementHold(m_pShip); if (m_pTarget) m_AICtx.ImplementAttackTarget(m_pShip, m_pTarget, true); m_AICtx.ImplementAttackNearestTarget(m_pShip, ATTACK_RANGE, &m_pTarget); m_AICtx.ImplementFireOnTargetsOfOpportunity(m_pShip); break; default: ASSERT(false); } }
// Wrap the textures, starting at a poly index void CRVTrackerTextureWrap::WrapTexture(CTWPolyInfo *pPoly, const CVector &vWrapDir, CTextExtents &cExtents) const { // Mark this poly as wrapped pPoly->m_bTouched = TRUE; CTexturedPlane& Texture = pPoly->m_pPoly->GetTexture(GetCurrTexture()); // Get the texture space LTVector vWrapO = Texture.GetO(); LTVector vWrapP = Texture.GetP(); LTVector vWrapQ = Texture.GetQ(); // Get the texture offset projections float fWrapOdotP = vWrapO.Dot(vWrapP); float fWrapOdotQ = vWrapO.Dot(vWrapQ); // Update the texturing extents for (uint32 nExtentLoop = 0; nExtentLoop < pPoly->m_aEdges.GetSize(); ++nExtentLoop) { LTVector vEdgePt = pPoly->m_aEdges[nExtentLoop]->m_aPt[0]; float fCurU = vWrapP.Dot(vEdgePt) - fWrapOdotP; float fCurV = vWrapQ.Dot(vEdgePt) - fWrapOdotQ; cExtents.m_fMinU = LTMIN(fCurU, cExtents.m_fMinU); cExtents.m_fMaxU = LTMAX(fCurU, cExtents.m_fMaxU); cExtents.m_fMinV = LTMIN(fCurV, cExtents.m_fMinV); cExtents.m_fMaxV = LTMAX(fCurV, cExtents.m_fMaxV); } CMoArray<uint32> aNeighbors; CMoArray<float> aDots; // Insert the neighbors into a list in dot-product order for (uint32 nNeighborLoop = 0; nNeighborLoop < pPoly->m_aNeighbors.GetSize(); ++nNeighborLoop) { CTWPolyInfo *pNeighbor = pPoly->m_aNeighbors[nNeighborLoop]; // Skip edges that don't have a neighbor if (!pNeighbor) continue; // Skip neighbors that are already wrapped if (pNeighbor->m_bTouched) continue; // Get our dot product float fCurDot = vWrapDir.Dot(pPoly->m_aEdges[nNeighborLoop]->m_Plane.m_Normal); if ((m_bRestrictWalkDir) && (fCurDot < 0.707f)) continue; // Mark this neighbor as touched (to avoid later polygons pushing it onto the stack) pNeighbor->m_bTouched = TRUE; // Insert it into the list for (uint32 nInsertLoop = 0; nInsertLoop < aNeighbors.GetSize(); ++nInsertLoop) { if (fCurDot > aDots[nInsertLoop]) break; } aDots.Insert(nInsertLoop, fCurDot); aNeighbors.Insert(nInsertLoop, nNeighborLoop); } // Recurse through its neighbors for (uint32 nWrapLoop = 0; nWrapLoop < aNeighbors.GetSize(); ++nWrapLoop) { CTWPolyInfo *pNeighbor = pPoly->m_aNeighbors[aNeighbors[nWrapLoop]]; CTWEdgeInfo *pEdge = pPoly->m_aEdges[aNeighbors[nWrapLoop]]; ////////////////////////////////////////////////////////////////////////////// // Wrap this neighbor // Create a matrix representing the basis of the polygon in relation to this edge LTMatrix mPolyBasis; mPolyBasis.SetTranslation(0.0f, 0.0f, 0.0f); mPolyBasis.SetBasisVectors(&pEdge->m_vDir, &pPoly->m_pPoly->m_Plane.m_Normal, &pEdge->m_Plane.m_Normal); // Create a new basis for the neighbor polygon LTMatrix mNeighborBasis; LTVector vNeighborForward; vNeighborForward = pNeighbor->m_pPoly->m_Plane.m_Normal.Cross(pEdge->m_vDir); // Just to be sure.. vNeighborForward.Norm(); mNeighborBasis.SetTranslation(0.0f, 0.0f, 0.0f); mNeighborBasis.SetBasisVectors(&pEdge->m_vDir, &pNeighbor->m_pPoly->m_Plane.m_Normal, &vNeighborForward); // Create a rotation matrix from here to there LTMatrix mRotation; mRotation = mNeighborBasis * ~mPolyBasis; // Rotate the various vectors LTVector vNewP; LTVector vNewQ; LTVector vNewDir; mRotation.Apply3x3(vWrapP, vNewP); mRotation.Apply3x3(vWrapQ, vNewQ); mRotation.Apply3x3(vWrapDir, vNewDir); // Rotate the texture basis if we're following a path if (m_nWrapStyle == k_WrapPath) { LTVector vNeighborEdgeDir; if (GetSimilarEdgeDir(pNeighbor, vNewDir, vNeighborEdgeDir, 0.707f)) { LTMatrix mRotatedNeighbor; LTVector vNeighborRight; vNeighborRight = vNeighborEdgeDir.Cross(pNeighbor->m_pPoly->m_Plane.m_Normal); vNeighborRight.Norm(); // Make sure we're pointing the right way... if (vNeighborRight.Dot(pEdge->m_vDir) < 0.0f) vNeighborRight = -vNeighborRight; mRotatedNeighbor.SetTranslation(0.0f, 0.0f, 0.0f); mRotatedNeighbor.SetBasisVectors(&vNeighborRight, &pNeighbor->m_pPoly->m_Plane.m_Normal, &vNeighborEdgeDir); // Build a basis based on an edge from the current polygon LTVector vBestPolyEdge; GetSimilarEdgeDir(pPoly, vWrapDir, vBestPolyEdge); LTVector vPolyRight = vBestPolyEdge.Cross(pNeighbor->m_pPoly->m_Plane.m_Normal); vPolyRight.Norm(); // Make sure we're pointing the right way... if (vPolyRight.Dot(pEdge->m_vDir) < 0.0f) vPolyRight = -vPolyRight; // Build the poly edge matrix LTMatrix mPolyEdgeBasis; mPolyEdgeBasis.SetTranslation(0.0f, 0.0f, 0.0f); mPolyEdgeBasis.SetBasisVectors(&vPolyRight, &pNeighbor->m_pPoly->m_Plane.m_Normal, &vBestPolyEdge); // Get a matrix from here to there LTMatrix mRotator; mRotator = mRotatedNeighbor * ~mPolyEdgeBasis; // Rotate the texture basis mRotator.Apply3x3(vNewP); mRotator.Apply3x3(vNewQ); // And use the new edge as the new direction vNewDir = vNeighborEdgeDir; } // Remove skew from vNewP/vNewQ if ((float)fabs(vNewP.Dot(vNewQ)) > 0.001f) { float fMagP = vNewP.Mag(); float fMagQ = vNewQ.Mag(); vNewQ *= 1.0f / fMagQ; vNewP -= vNewQ * vNewQ.Dot(vNewP); vNewP.Norm(fMagP); vNewQ *= fMagQ; } } // Get the first edge point.. CVector vEdgePt = pEdge->m_aPt[0]; // Calculate the texture coordinate at this point float fWrapU = vWrapP.Dot(vEdgePt) - fWrapOdotP; float fWrapV = vWrapQ.Dot(vEdgePt) - fWrapOdotQ; // Build the new offset float fNewOdotP = vNewP.Dot(vEdgePt) - fWrapU; float fNewOdotQ = vNewQ.Dot(vEdgePt) - fWrapV; LTVector vNewO; vNewO.Init(); float fNewPMag = vNewP.MagSqr(); if (fNewPMag > 0.0f) vNewO += vNewP * (fNewOdotP / fNewPMag); float fNewQMag = vNewQ.MagSqr(); if (fNewQMag > 0.0f) vNewO += vNewQ * (fNewOdotQ / fNewQMag); pNeighbor->m_pPoly->SetTextureSpace(GetCurrTexture(), vNewO, vNewP, vNewQ); // Recurse into this neighbor WrapTexture(pNeighbor, vNewDir, cExtents); } }
BOOL CRVTrackerTextureWrap::OnEnd() { // If we're getting OnEnd because the dialog got displayed, skip out if (m_bShowingDialog) return TRUE; // Show the options dialog m_bShowingDialog = TRUE; CAutoTextureOptionsDlg cDlg; // Load the options from the registry cDlg.LoadOptionsFromReg(); //if the skip tracker is active, just avoid the dialog int nModalResult; if(m_pSkipTracker && m_pSkipTracker->GetActive()) nModalResult = IDOK; else nModalResult = cDlg.DoModal(); m_bShowingDialog = FALSE; // Get the wrapping direction CVector vWrapDir = m_pView->DrawingBrush().m_Points[1] - m_pView->DrawingBrush().m_Points[0]; // Clear the drawing brush (so it doesn't hang around if they cancel) m_pView->DrawingBrush().Term(); // Jump out if they cancelled if (nModalResult != IDOK) return TRUE; // Get the style.. m_nWrapStyle = cDlg.m_nStyle; if (m_nWrapStyle >= k_WrapInvalid) return TRUE; // Save the options to the registry cDlg.SaveOptionsToReg(); // Get the options m_bScaleToFit = cDlg.m_bScale; m_bAdjustOffset = cDlg.m_bOffset; m_bRestrictWalkDir = cDlg.m_bRestrictDir; // This might take a while... m_pView->BeginWaitCursor(); // Select the brushes with selected faces in geometry mode so this can be undone if (m_pView->GetEditMode() == GEOMETRY_EDITMODE) { CPolyRefArray &rTaggedPolies = m_pView->TaggedPolies(); for (uint32 nFindBaseLoop = 0; nFindBaseLoop < rTaggedPolies.GetSize(); ++nFindBaseLoop) { if (!rTaggedPolies[nFindBaseLoop].IsValid()) continue; m_pView->GetRegion()->SelectNode(rTaggedPolies[nFindBaseLoop]()->m_pBrush->AsNode()); } m_pView->GetRegionDoc()->NotifySelectionChange(); } // They'll probably want to be able to undo this... m_pView->GetRegionDoc()->SetupUndoForSelections(); // If we didn't move, try and figure out a wrap direction if (vWrapDir.MagSqr() <= 0.01f) { // Try going to the right vWrapDir = m_pView->Nav().Right(); // Make sure we're actually still on the poly... CEditPlane *pPlane = &(m_rBasePoly()->m_Plane); vWrapDir -= pPlane->m_Normal * vWrapDir.Dot(pPlane->m_Normal); // If that doesn't work.. if (vWrapDir.MagSqr() <= 0.01f) { // Try going forward vWrapDir = m_pView->Nav().Forward(); vWrapDir -= pPlane->m_Normal * vWrapDir.Dot(pPlane->m_Normal); } } vWrapDir.Norm(); // Build the polygon set CTWPolyList aPolyList; BuildPolyList(aPolyList); // Find our base poly uint32 nBasePolyIndex = FindPolyIndex(aPolyList, m_rBasePoly()); // Wrap the textures, starting at the base poly index CTextExtents cExtents; WrapTexture(aPolyList[nBasePolyIndex], vWrapDir, cExtents); // Scale the textures to an even multiple if (m_bScaleToFit) ScaleToMultiple(aPolyList, cExtents); // Offset the textures to fit at the top/left if (m_bAdjustOffset) AlignToTopLeft(aPolyList, cExtents); // Clear the polygon set ClearPolyList(aPolyList); // Redraw the views POSITION pos = m_pView->GetDocument()->GetFirstViewPosition(); while (pos) { CView *pView = m_pView->GetDocument()->GetNextView(pos); pView->Invalidate(FALSE); } // This might take a while... m_pView->EndWaitCursor(); return TRUE; }
void CFleetShipAI::Behavior (void) // Behavior { // Reset ResetBehavior(); // Use basic items UseItemsBehavior(); // Behave according to our state switch (m_State) { case stateNone: BehaviorStart(); break; case stateAttackAtWill: { // If we don't have a target, find one if (m_pTarget == NULL && m_pShip->IsDestinyTime(13)) m_pTarget = m_pShip->GetNearestEnemy(ATTACK_AT_WILL_RANGE, true); // If we have a target, attack if (m_pTarget) { ImplementAttackTarget(m_pTarget); ImplementFireOnTargetsOfOpportunity(m_pTarget); } // Otherwise, stay in formation else { ImplementKeepFormation(); ImplementFireOnTargetsOfOpportunity(); ImplementFireOnNearestTarget(); } break; } case stateAttackInFormation: { bool bInFormation; ImplementKeepFormation(&bInFormation); // Fire the primary weapon (most of the time) if (bInFormation && mathRandom(1, 3) > 1) ImplementFireWeapon(); // Decrement counter if (m_iCounter > 0) { if (--m_iCounter == 0) { SetState(stateKeepFormation); m_iCounter = 0; } } break; } case stateAttackOnPatrol: ASSERT(m_pTarget); ImplementAttackTarget(m_pTarget); ImplementFireOnTargetsOfOpportunity(m_pTarget); // Check to see if we've wandered outside our patrol zone if (m_pShip->IsDestinyTime(20)) { CSpaceObject *pCenter = GetCurrentOrderTarget(); Metric rMaxRange2 = PATROL_ORBIT_DIST + PATROL_SENSOR_RANGE; rMaxRange2 = rMaxRange2 * rMaxRange2; Metric rMinRange2 = std::max(0.0, PATROL_ORBIT_DIST - PATROL_SENSOR_RANGE); rMinRange2 = rMinRange2 * rMinRange2; int iTick = m_pShip->GetSystem()->GetTick(); CVector vRange = pCenter->GetPos() - m_pShip->GetPos(); Metric rDistance2 = vRange.Dot(vRange); // If we're outside of our patrol range then stop the attack if (rDistance2 > rMaxRange2 || rDistance2 < rMinRange2) SetState(stateNone); } break; case stateAttackTarget: { ASSERT(m_pTarget); if (m_pTarget->CanMove()) ImplementAttackTarget(m_pTarget); else { // Attack the target as best we can CVector vTarget = m_pTarget->GetPos() - m_pShip->GetPos(); Metric rTargetDist2 = vTarget.Dot(vTarget); ImplementFireWeaponOnTarget(-1, -1, m_pTarget, vTarget, rTargetDist2); // Maneuver to a proper position near the target Metric rRange; int iCounterAdj; if (m_pAISettings->iCombatStyle == aicombatStandOff) { rRange = m_rBestWeaponRange / 2.0; iCounterAdj = 2; } else { rRange = m_rBestWeaponRange / 6.0; iCounterAdj = 1; } if (m_iCounter == 0) { m_vVector = ComputeAttackPos(m_pTarget, rRange, &m_iAngle); m_iCounter = mathRandom(130, 160) * iCounterAdj; } else m_iCounter--; ImplementFormationManeuver(m_vVector, NullVector, m_iAngle); } ImplementFireOnTargetsOfOpportunity(m_pTarget); break; } case stateKeepFormation: ImplementKeepFormation(); ImplementFireOnTargetsOfOpportunity(); ImplementFireOnNearestTarget(); break; case stateOnCourseForDocking: ASSERT(m_pDest); ImplementDocking(m_pDest); ImplementFireOnTargetsOfOpportunity(); ImplementFireOnNearestTarget(); break; case stateOnCourseForStargate: ASSERT(m_pDest); ImplementGating(m_pDest); ImplementFireOnTargetsOfOpportunity(); ImplementFireOnNearestTarget(); break; case stateOnPatrolOrbit: ASSERT(m_pDest); ImplementOrbit(m_pDest, PATROL_ORBIT_DIST); ImplementAttackNearestTarget(m_rMaxWeaponRange, &m_pTarget, m_pDest); ImplementFireOnTargetsOfOpportunity(NULL, m_pDest); // Check to see if any enemy ships appear if (m_pShip->IsDestinyTime(30)) { CSpaceObject *pPrincipal = GetCurrentOrderTarget(); CSpaceObject *pTarget = CalcEnemyShipInRange(pPrincipal, PATROL_SENSOR_RANGE, m_pDest); if (pTarget) { SetState(stateAttackOnPatrol); m_pTarget = pTarget; ASSERT(m_pTarget->DebugIsValid() && m_pTarget->NotifyOthersWhenDestroyed()); } } break; } }
Metric CalcDistanceToPath (const CVector &Pos, const CVector &Path1, const CVector &Path2, CVector *retvNearestPoint, CVector *retvAway) // CalcDistanceToPath // // Returns the distance from Pos to the path from Path1 to Path2. { // Create a unit vector from Path1 to Path2 CVector vPath; vPath = Path2 - Path1; vPath = vPath.Normal(); // Create a vector perpendicular to the path CVector vPerp = vPath.Perpendicular(); // Create a vector from the point to one of the endpoints CVector vPoint = Path1 - Pos; // Project this vector on to the perpendicular CVector vToLine = vPoint.Dot(vPerp) * vPerp; // Compute the point on the line that is nearest Pos CVector vIntersect = Pos + vToLine; // See if the point is between the two path endpoints bool bBetween = false; if (Path1.GetX() < Path2.GetX()) bBetween = vIntersect.GetX() > Path1.GetX() && vIntersect.GetX() < Path2.GetX(); else bBetween = vIntersect.GetX() > Path2.GetX() && vIntersect.GetX() < Path1.GetX(); if (bBetween) { if (Path1.GetY() < Path2.GetY()) bBetween = vIntersect.GetY() > Path1.GetY() && vIntersect.GetY() < Path2.GetY(); else bBetween = vIntersect.GetY() > Path2.GetY() && vIntersect.GetY() < Path1.GetY(); } // If we're between, then the nearest distance is the distance to the path if (bBetween) { if (retvNearestPoint) *retvNearestPoint = vIntersect; if (retvAway) *retvAway = vToLine.Normal(); return vToLine.Length(); } // Otherwise, the nearest distance is the nearest distance to the two endpoints else { CVector vDist1 = Path1 - Pos; CVector vDist2 = Path2 - Pos; Metric rLen1 = vDist1.Length(); Metric rLen2 = vDist2.Length(); if (rLen1 < rLen2) { if (retvNearestPoint) *retvNearestPoint = Path1; if (retvAway) *retvAway = vDist1.Normal(); return rLen1; } else { if (retvNearestPoint) *retvNearestPoint = Path2; if (retvAway) *retvAway = vDist2.Normal(); return rLen2; } } }