void Team::markRadiusSeenToTeams(Stuff::Vector3D& location, float radius, bool shrinkForNight) { if(radius < 0.0) radius = fireVisualRange; if(shrinkForNight) radius -= (radius * 0.25f); bool didTeam[MAX_TEAMS] = {false, false, false, false, false, false, false, false}; for(size_t i = 0; i < ObjectManager->getNumMovers(); i++) { MoverPtr mover = ObjectManager->getMover(i); if(mover->getTeam() && !didTeam[mover->getTeamId()] && !isFriendly(mover->getTeam())) { Stuff::Vector3D result; result.x = location.x - mover->getPosition().x; result.y = location.y - mover->getPosition().y; result.z = 0.0; float dist = result.GetLength() * metersPerWorldUnit; if(dist < maxVisualRange) { markRadiusSeen(location, radius); didTeam[mover->getTeamId()] = true; } } } }
void MoverGroup::sortMovers( int32_t numMoversInGroup, MoverPtr* moverList, Stuff::Vector3D destination) { Mover::sortList->clear(); for (size_t i = 0; i < numMoversInGroup; i++) { int32_t index = -1; float dist = (float)3.48E+37; if (moverList[i]) { index = i; Stuff::Vector3D resultVector; resultVector.Subtract(moverList[i]->getPosition(), destination); dist = resultVector.GetLength(); } Mover::sortList->setId(i, index); Mover::sortList->setValue(i, dist); } Mover::sortList->sort(false); for (i = 0; i < numMoversInGroup; i++) { int32_t moverIndex = Mover::sortList->getId(i); if (moverIndex != -1) moverList[moverIndex]->selectionIndex = i; } }
//--------------------------------------------------------------------------- long SoundSystem::playDigitalSample (unsigned long sampleId, Stuff::Vector3D pos, bool allowDupes) { if (useSound && allowDupes || (!isPlayingSample(sampleId) && !allowDupes)) { if (sampleId >= numSoundBites) return(-1); long ourChannel = findOpenChannel(1,SUPPORT_CHANNEL); if (ourChannel != -1) { float distanceVolume = 1.0f; float panVolume = 0.0f; if (eye && (pos.z != -9999.0f)) { Stuff::Vector3D distance; distance.Subtract(eye->getPosition(),pos); float dist = distance.GetApproximateLength(); if (dist < FALLOFF_DISTANCE) distanceVolume = (FALLOFF_DISTANCE - dist) / FALLOFF_DISTANCE; else return -1; //Do not play sound. TOO far away!! //Figure out where in stereo field to play. OppRotate(distance,eye->getRotation().y); panVolume = distance.x / (FALLOFF_DISTANCE * 0.5f); if (panVolume > 1.0f) panVolume = 1.0f; else if (panVolume < -1.0f) panVolume = -1.0f; } float vol = sounds[sampleId].volume * distanceVolume; if (vol > 1.0f) vol = 1.0f; else if (vol <= 0.0f) //No VOlume. DON't PLAY! return -1; gosAudio_SetChannelSlider(ourChannel,gosAudio_Panning, panVolume); gosAudio_SetChannelSlider(ourChannel,gosAudio_Volume, (digitalMasterVolume * vol * SFXVolume)) ; channelSampleId[ourChannel] = sampleId; channelInUse[ourChannel] = TRUE; if (sounds[sampleId].biteData && sounds[sampleId].resourceHandle) { gosAudio_AssignResourceToChannel( ourChannel, sounds[sampleId].resourceHandle ); gosAudio_SetChannelPlayMode(ourChannel, gosAudio_PlayOnce); } return(ourChannel); } } return(-1); }
float distance_from (Stuff::Vector3D &v1, Stuff::Vector3D &v2) { Stuff::Vector3D result; result.x = v2.x - v1.x; result.y = v2.y - v1.y; result.z = v2.z - v1.z; float dist = result.GetLength(); return (dist); }
float angle_from (Stuff::Vector3D &v1, Stuff::Vector3D &v2) { float mag_product = v1.GetLength() * v2.GetLength(); if (mag_product == 0.0) return mag_product; // 0; else { float vecResult = v1 * v2; return (my_acos(vecResult / mag_product) * RADS_TO_DEGREES); } }
//--------------------------------------------------------------------------- float world_angle_between (Stuff::Vector3D &v1, Stuff::Vector3D &v2) { Stuff::Vector3D facingVec(0.0f,1.0f,0.0f); Stuff::Vector3D goalVec; goalVec.Subtract(v1, v2); float angle = angle_from(facingVec, goalVec); //-------------------------------- // Get sign of relative angle. float z = (facingVec.x * goalVec.y) - (facingVec.y * goalVec.x); if (z > 0.0f) angle = -angle; return(angle); }
Stuff::Vector3D Team::calcEscapeVector(MoverPtr mover, float threatRange) { static float distance[100]; static Stuff::Vector3D delta[100]; Stuff::Vector3D escapeVector; escapeVector.Zero(); //------------------------------ // Get the initial delta info... int32_t shortest = 0; int32_t longest = 0; for(size_t i = 0; i < rosterSize; i++) { GameObjectPtr obj = ObjectManager->getByWatchID(roster[i]); if(obj) { float distanceToObj = mover->distanceFrom(obj->getPosition()); if(distanceToObj <= threatRange) { delta[i].Subtract(mover->getPosition(), obj->getPosition()); distance[i] = distanceToObj; if(distance[i] > longest) longest = i; if(distance[i] < shortest) shortest = i; } else distance[i] = -999.0; } else distance[i] = -999.0; } //----------------------------------------------------------------- // Now, find the furthest enemy and scale the deltas accordingly... for(i = 0; i < rosterSize; i++) if(distance[i] >= 0.0) { float scale = distance[longest] / distance[i]; delta[i] *= scale; escapeVector += delta[i]; } //-------------------------------------------------------------------------------- // We don't care about the length, just the direction (we assume you want to go as // FAR as necessary)... escapeVector.Normalize(escapeVector); return(escapeVector); }
//--------------------------------------------------------------------------- void Terrain::geometry (void) { //--------------------------------------------------------------------- leastZ = 1.0f;leastW = 1.0f; mostZ = -1.0f; mostW = -1.0; leastWY = 0.0f; mostWY = 0.0f; //----------------------------------- // Transform entire list of vertices VertexPtr currentVertex = vertexList; Stuff::Vector3D cameraPos; cameraPos.x = -eye->getCameraOrigin().x; cameraPos.y = eye->getCameraOrigin().z; cameraPos.z = eye->getCameraOrigin().y; float vClipConstant = eye->verticalSphereClipConstant; float hClipConstant = eye->horizontalSphereClipConstant; long i=0; for (i=0;i<numberVertices;i++) { //---------------------------------------------------------------------------------------- // Figure out if we are in front of camera or not. Should be faster then actual project! // Should weed out VAST overwhelming majority of vertices! bool onScreen = false; //----------------------------------------------------------------- // Find angle between lookVector of Camera and vector from camPos // to Target. If angle is less then halfFOV, object is visible. if (eye->usePerspective) { //------------------------------------------------------------------- //NEW METHOD from the WAY BACK Days onScreen = true; Stuff::Vector3D vPosition; vPosition.x = currentVertex->vx; vPosition.y = currentVertex->vy; vPosition.z = currentVertex->pVertex->elevation; Stuff::Vector3D objectCenter; objectCenter.Subtract(vPosition,cameraPos); Camera::cameraFrame.trans_to_frame(objectCenter); float distanceToEye = objectCenter.GetApproximateLength(); Stuff::Vector3D clipVector = objectCenter; clipVector.z = 0.0f; float distanceToClip = clipVector.GetApproximateLength(); float clip_distance = fabs(1.0f / objectCenter.y); if (distanceToClip > CLIP_THRESHOLD_DISTANCE) { //Is vertex on Screen OR close enough to screen that its triangle MAY be visible? // WE have removed the atans here by simply taking the tan of the angle we want above. float object_angle = fabs(objectCenter.z) * clip_distance; float extent_angle = VERTEX_EXTENT_RADIUS / distanceToEye; if (object_angle > (vClipConstant + extent_angle)) { //In theory, we would return here. Object is NOT on screen. onScreen = false; } else { object_angle = fabs(objectCenter.x) * clip_distance; if (object_angle > (hClipConstant + extent_angle)) { //In theory, we would return here. Object is NOT on screen. onScreen = false; } } } if (onScreen) { if (distanceToEye > Camera::MaxClipDistance) { currentVertex->hazeFactor = 1.0f; } else if (distanceToEye > Camera::MinHazeDistance) { currentVertex->hazeFactor = (distanceToEye - Camera::MinHazeDistance) * Camera::DistanceFactor; } else { currentVertex->hazeFactor = 0.0f; } //--------------------------------------- // Vertex is at edge of world or beyond. Stuff::Vector3D vPos(currentVertex->vx,currentVertex->vy,currentVertex->pVertex->elevation); bool isVisible = Terrain::IsGameSelectTerrainPosition(vPos) || drawTerrainGrid; if (!isVisible) { currentVertex->hazeFactor = 1.0f; onScreen = true; } } else { currentVertex->hazeFactor = 1.0f; } } else { currentVertex->hazeFactor = 0.0f; onScreen = true; } bool inView = false; Stuff::Vector4D screenPos(-10000.0f,-10000.0f,-10000.0f,-10000.0f); if (onScreen) { Stuff::Vector3D vertex3D(currentVertex->vx,currentVertex->vy,currentVertex->pVertex->elevation); inView = eye->projectZ(vertex3D,screenPos); currentVertex->px = screenPos.x; currentVertex->py = screenPos.y; currentVertex->pz = screenPos.z; currentVertex->pw = screenPos.w; //---------------------------------------------------------------------------------- //We must transform these but should NOT draw any face where all three are fogged. // if (currentVertex->hazeFactor == 1.0f) // onScreen = false; } else { currentVertex->px = currentVertex->py = 10000.0f; currentVertex->pz = -0.5f; currentVertex->pw = 0.5f; currentVertex->hazeFactor = 0.0f; } //------------------------------------------------------------ // Fix clip. Vertices can all be off screen and triangle // still needs to be drawn! if (eye->usePerspective && Environment.Renderer != 3) { currentVertex->clipInfo = onScreen; } else currentVertex->clipInfo = inView; if (currentVertex->clipInfo) //ONLY set TRUE ones. Otherwise we just reset the FLAG each vertex! { setObjBlockActive(currentVertex->getBlockNumber(), true); setObjVertexActive(currentVertex->vertexNum,true); if (inView) { if (screenPos.z < leastZ) { leastZ = screenPos.z; } if (screenPos.z > mostZ) { mostZ = screenPos.z; } if (screenPos.w < leastW) { leastW = screenPos.w; leastWY = screenPos.y; } if (screenPos.w > mostW) { mostW = screenPos.w; mostWY = screenPos.y; } } } currentVertex++; } //----------------------------------- // setup terrain quad textures // Also sets up mine data. TerrainQuadPtr currentQuad = quadList; for (i=0;i<numberQuads;i++) { currentQuad->setupTextures(); currentQuad++; } float ywRange = 0.0f, yzRange = 0.0f; if (fabs(mostWY - leastWY) > Stuff::SMALL) { ywRange = (mostW - leastW) / (mostWY - leastWY); yzRange = (mostZ - leastZ) / (mostWY - leastWY); } eye->setInverseProject(mostZ,leastW,yzRange,ywRange); //----------------------------------- // update the cloud layer if (Terrain::cloudLayer) Terrain::cloudLayer->update(); }
//------------------------------------------------------------------------------ // bool gosFX::PointCloud::AnimateParticle( uint32_t index, const Stuff::LinearMatrix4D* world_to_new_local, Stuff::Time till ) { Check_Object(this); // //----------------------------------------------------------------------- // If this cloud is unparented, we need to transform the point from local // space into world space and set the internal position/velocity pointers // to these temporary values //----------------------------------------------------------------------- // Particle* particle = GetParticle(index); Check_Object(particle); float age = particle->m_age; if(age >= 1.0f) return false; Set_Statistic(Point_Count, Point_Count + 1); Stuff::Vector3D* velocity = &particle->m_localLinearVelocity; Stuff::Point3D* translation = &m_P_localTranslation[index]; int32_t sim_mode = GetSimulationMode(); if(sim_mode == DynamicWorldSpaceSimulationMode) { Check_Object(translation); Check_Object(velocity); particle->m_worldLinearVelocity.Multiply(*velocity, m_localToWorld); particle->m_worldTranslation.Multiply(*translation, m_localToWorld); translation = &particle->m_worldTranslation; velocity = &particle->m_worldLinearVelocity; } Check_Object(translation); Check_Object(velocity); // //------------------------------------------------------------------ // First, calculate the drag on the particle. Drag can never assist // velocity //------------------------------------------------------------------ // float seed = particle->m_seed; Specification* spec = GetSpecification(); Check_Object(spec); Stuff::Vector3D ether; ether.x = spec->m_pEtherVelocityX.ComputeValue(age, seed); ether.y = spec->m_pEtherVelocityY.ComputeValue(age, seed); ether.z = spec->m_pEtherVelocityZ.ComputeValue(age, seed); Stuff::Vector3D accel(Stuff::Vector3D::Identity); // //------------------------------------------------------------------- // Deal with pseudo-world simulation. In this mode, we interpret the // forces as if they are already in worldspace, and we transform them // back to local space //------------------------------------------------------------------- // float drag = -spec->m_pDrag.ComputeValue(age, seed); Max_Clamp(drag, 0.0f); if(sim_mode == StaticWorldSpaceSimulationMode) { Stuff::LinearMatrix4D world_to_effect; world_to_effect.Invert(m_localToWorld); Stuff::Vector3D local_ether; local_ether.MultiplyByInverse(ether, world_to_effect); Stuff::Vector3D rel_vel; rel_vel.Subtract(*velocity, local_ether); accel.Multiply(rel_vel, drag); // //----------------------------------------- // Now, add in acceleration of the particle //----------------------------------------- // Stuff::Vector3D world_accel; world_accel.x = spec->m_pAccelerationX.ComputeValue(age, seed); world_accel.y = spec->m_pAccelerationY.ComputeValue(age, seed); world_accel.z = spec->m_pAccelerationZ.ComputeValue(age, seed); Stuff::Vector3D local_accel; local_accel.Multiply(world_accel, world_to_effect); accel += local_accel; } // //---------------------------------------------------------------------- // Otherwise, just add the forces in the same space the particles are in //---------------------------------------------------------------------- // else { Stuff::Vector3D rel_vel; rel_vel.Subtract(*velocity, ether); accel.Multiply(rel_vel, drag); // //----------------------------------------- // Now, add in acceleration of the particle //----------------------------------------- // accel.x += spec->m_pAccelerationX.ComputeValue(age, seed); accel.y += spec->m_pAccelerationY.ComputeValue(age, seed); accel.z += spec->m_pAccelerationZ.ComputeValue(age, seed); } // //------------------------------------------------- // Compute the particle's new velocity and position //------------------------------------------------- // float time_slice = static_cast<float>(till - m_lastRan); velocity->AddScaled(*velocity, accel, time_slice); translation->AddScaled(*translation, *velocity, time_slice); // //--------------------------------------------------------------------- // If we are unparented, we need to transform the velocity and position // data back into the NEW local space //--------------------------------------------------------------------- // if(sim_mode == DynamicWorldSpaceSimulationMode) { Check_Object(world_to_new_local); particle->m_localLinearVelocity.Multiply( particle->m_worldLinearVelocity, *world_to_new_local ); m_P_localTranslation[index].Multiply( particle->m_worldTranslation, *world_to_new_local ); } // //------------------ // Animate the color //------------------ // Check_Pointer(m_P_color); m_P_color[index].red = spec->m_pRed.ComputeValue(age, seed); m_P_color[index].green = spec->m_pGreen.ComputeValue(age, seed); m_P_color[index].blue = spec->m_pBlue.ComputeValue(age, seed); m_P_color[index].alpha = spec->m_pAlpha.ComputeValue(age, seed); return true; }
//--------------------------------------------------------------------------- void Clouds::update (void) { renderClouds = false; scrollU += frameLength * SCROLL_U_FACTOR; scrollV += frameLength * SCROLL_V_FACTOR; if (scrollU > 1.0f) scrollU -= 1.0f; if (scrollV > 1.0f) scrollV -= 1.0f; if (scrollU < -1.0f) scrollU += 1.0f; if (scrollV < -1.0f) scrollV += 1.0f; //--------------------------------------------------------------------- // If projectionAngle is less then some magic number, draw the clouds. // Otherwise, do not do anything! if (eye->active && eye->usePerspective && (eye->getProjectionAngle() < MAX_CLOUDS_ANGLE)) { //renderClouds = true; //------------------------------------------------------- // Create the cloud grid based on camera CENTER position. Stuff::Vector3D centerPosition(eye->getPosition()); //------------------------------------------------------- // Create a topLeft vertex float tLeftX = centerPosition.x + MAX_CLOUDS_SIZE; float tLeftY = centerPosition.y + MAX_CLOUDS_SIZE; //------------------------------------------------------- // Create the grid. long cloudInc = float2long(MAX_CLOUDS_SIZE * 2.0f / gridSize); float uvInc = MAX_UV_REPEAT / float(gridSize); for (long y=0;y<gridSize;y++) { for (long x=0;x<gridSize;x++) { cloudVertices[x + (y*gridSize)].vx = tLeftX - (cloudInc * x); cloudVertices[x + (y*gridSize)].vy = tLeftY - (cloudInc * y); cloudVertices[x + (y*gridSize)].pu = CLOUD_START_U + (uvInc * x); cloudVertices[x + (y*gridSize)].pv = CLOUD_START_V + (uvInc * y); } } //------------------------------------------------------- // Transform Grid long gridTotal = gridSize * gridSize; for (long i=0;i<gridTotal;i++) { //---------------------------------------------------------------------------------------- // Figure out if we are in front of camera or not. Should be faster then actual project! // Should weed out VAST overwhelming majority of vertices! bool onScreen = true; //----------------------------------------------------------------- // Find angle between lookVector of Camera and vector from camPos // to Target. If angle is less then halfFOV, object is visible. //------------------------------------------------------------------- // Then figure out if FarClipped. Should weed out a boatload more! float hazeFactor = 0.0f; Stuff::Point3D Distance; Stuff::Point3D vPosition; Stuff::Point3D eyePosition(eye->getPosition()); vPosition.x = cloudVertices[i].vx;; vPosition.y = cloudVertices[i].vy; vPosition.z = centerPosition.z; Distance.Subtract(eyePosition,vPosition); float eyeDistance = Distance.GetApproximateLength(); if (eyeDistance > Camera::MaxClipDistance) { hazeFactor = 1.0f; //onScreen = false; } else if (eyeDistance > Camera::MinHazeDistance) { hazeFactor = (eyeDistance - Camera::MinHazeDistance) * Camera::DistanceFactor; } else { hazeFactor = 0.0f; } //------------------------------------------------------------ // Calculate the HazeDWORD here if (hazeFactor != 0.0f) { float fogFactor = 1.0 - hazeFactor; DWORD distFog = float2long(fogFactor * 255.0f); cloudVertices[i].fogRGB = (distFog<<24) + (0xffffff); } else { cloudVertices[i].fogRGB = 0xffffffff; } if (onScreen) { Stuff::Vector3D Distance; Stuff::Point3D objPosition; Stuff::Point3D eyePosition(eye->getCameraOrigin()); objPosition.x = -cloudVertices[i].vx; objPosition.y = CLOUD_ALTITUDE; objPosition.z = cloudVertices[i].vy; Distance.Subtract(objPosition,eyePosition); Distance.Normalize(Distance); float cosine = Distance * eye->getLookVector(); if (cosine > eye->cosHalfFOV) onScreen = true; else onScreen = false; } else { hazeFactor = 1.0f; } Stuff::Vector3D vertex3D(cloudVertices[i].vx,cloudVertices[i].vy,(CLOUD_ALTITUDE+eye->getCameraOrigin().y)); Stuff::Vector4D screenPos; bool inView = eye->projectZ(vertex3D,screenPos); cloudVertices[i].px = screenPos.x; cloudVertices[i].py = screenPos.y; cloudVertices[i].pz = screenPos.z; cloudVertices[i].pw = screenPos.w; //------------------------------------------------------------ // Fix clip. Vertices can all be off screen and triangle // still needs to be drawn! cloudVertices[i].clipInfo = onScreen && inView; //------------------------------------------------------------ // Still need to scrollUVs here! cloudVertices[i].pu += scrollU; cloudVertices[i].pv += scrollV; } for (y=0;y<(gridSize-1);y++) { for (long x=0;x<(gridSize-1);x++) { CloudVertexPtr cloudVertex0 = &(cloudVertices[x + (y *gridSize)]); CloudVertexPtr cloudVertex1 = &(cloudVertices[(x+1) + (y *gridSize)]); CloudVertexPtr cloudVertex2 = &(cloudVertices[(x+1) + ((y+1)*gridSize)]); CloudVertexPtr cloudVertex3 = &(cloudVertices[x + ((y+1)*gridSize)]); bool clipCheck = (cloudVertex0->clipInfo || cloudVertex1->clipInfo || cloudVertex2->clipInfo); if (clipCheck && ((cloudVertex0->pz < 1.0f) && (cloudVertex0->pz > 0.0f) && (cloudVertex1->pz < 1.0f) && (cloudVertex1->pz > 0.0f) && (cloudVertex2->pz < 1.0f) && (cloudVertex2->pz > 0.0f))) { mcTextureManager->addTriangle(mcTextureNodeIndex,MC2_DRAWALPHA); } clipCheck = (cloudVertex0->clipInfo || cloudVertex2->clipInfo || cloudVertex3->clipInfo); if (clipCheck && ((cloudVertex0->pz < 1.0f) && (cloudVertex0->pz > 0.0f) && (cloudVertex2->pz < 1.0f) && (cloudVertex2->pz > 0.0f) && (cloudVertex3->pz < 1.0f) && (cloudVertex3->pz > 0.0f))) { mcTextureManager->addTriangle(mcTextureNodeIndex,MC2_DRAWALPHA); } } } } }
//--------------------------------------------------------------------------- bool Team::lineOfSight(float startLocal, int32_t mCellRow, int32_t mCellCol, int32_t tCellRow, int32_t tCellCol, int32_t teamId, float extRad, bool checkVisibleBits) { #ifdef LAB_ONLY int64_t x = GetCycles(); #endif //----------------------------------------------------- // Once we allow teams to have alliances (for contacts, // etc.), simply set all nec. team bits in this mask... //TILE HACK... int32_t tileRow = tCellRow / 3; int32_t tileCol = tCellCol / 3; if((teamId < 0) || (teamId >= MAX_TEAMS)) //Not on any team. It can see everything! return true; if(checkVisibleBits) { uint8_t teamMask = 0x01 << teamId; uint8_t visbBits[4]; //---------------------------------------------------------------------------- // First check is simple. Is anyone within the magical line of sight radius? // If not, return false and move on. // If they are, you MUST check LOS between this object and the other one. bool losResult = false; visbBits[0] = Terrain::VisibleBits->getFlag(tileRow, tileCol); if(visbBits[0] & teamMask) losResult = true; if(!losResult) { visbBits[1] = Terrain::VisibleBits->getFlag(tileRow + 1, tileCol); if(visbBits[1] & teamMask) losResult = true; } if(!losResult) { visbBits[2] = Terrain::VisibleBits->getFlag(tileRow + 1, tileCol + 1); if(visbBits[2] & teamMask) losResult = true; } if(!losResult) { visbBits[3] = Terrain::VisibleBits->getFlag(tileRow, tileCol + 1); if(visbBits[3] & teamMask) losResult = true; } if(!losResult) { #ifdef LAB_ONLY x = GetCycles() - x; MCTimeLOSCalc += x; #endif return losResult; } } if(useRealLOS) { //------------------------------------------------------------------------------------------ // Within magic radius. Check REAL LOS now. // Check is really simple. // Find deltaCellRow and deltaCellCol and iterate over them from source to dest. // If the magic line ever goes BELOW the terrainElevation PLUS localElevation return false. Stuff::Vector3D startPos, endPos; startPos.Zero(); endPos.Zero(); land->getCellPos(tCellRow, tCellCol, endPos); land->getCellPos(mCellRow, mCellCol, startPos); startPos.z += startLocal; Stuff::Vector3D deltaCellVec; deltaCellVec.y = tCellRow - mCellRow; deltaCellVec.x = tCellCol - mCellCol; deltaCellVec.z = 0.0f; float startHeight = startPos.z; float length = deltaCellVec.GetApproximateLength(); if(length > Stuff::SMALL) { float colLength = deltaCellVec.x / length; float rowLength = deltaCellVec.y / length; float heightLen = (endPos.z - startPos.z) / length; float lastCol = fabs(colLength * 2.0); float lastRow = fabs(rowLength * 2.0); float startCellRow = mCellRow; float startCellCol = mCellCol; float endCellRow = tCellRow; float endCellCol = tCellCol; Stuff::Vector3D currentPos = startPos; Stuff::Vector3D dist; dist.Subtract(endPos, currentPos); float remainingDist = dist.GetApproximateLength(); bool colDone = false, rowDone = false; while(!colDone || !rowDone) { if(fabs(startCellRow - endCellRow) > lastRow) //DO NOT INCLUDE LAST CELL!!!!! { startCellRow += rowLength; } else { // startCellRow = (endCellRow - lastRow); rowDone = true; } if(fabs(startCellCol - endCellCol) > lastCol) //DO NOT INCLUDE LAST CELL!!!!! { startCellCol += colLength; } else { // startCellCol = (endCellCol - lastCol); colDone = true; } startHeight += heightLen; int32_t startCellC = startCellCol; int32_t startCellR = startCellRow; land->getCellPos(startCellR, startCellC, currentPos); float localElev = (worldUnitsPerMeter * 4.0f * (float)GameMap->getLocalHeight(startCellR, startCellC)); currentPos.z += localElev; if(startHeight + startLocal < currentPos.z) { #ifdef LAB_ONLY x = GetCycles() - x; MCTimeLOSCalc += x; #endif #ifdef LAB_ONLY if(drawTerrainGrid) { Stuff::Vector3D realStart = startPos; Stuff::Vector4D lineStart, lineEnd; eye->projectZ(realStart, lineStart); eye->projectZ(endPos, lineEnd); debugLines[currentLineElement++] = new LineElement(lineStart, lineEnd, SD_RED, nullptr, -1); } #endif return false; } if(extRad > Stuff::SMALL) { dist.Subtract(endPos, currentPos); remainingDist = dist.GetApproximateLength(); if(remainingDist < extRad) break; } } } #ifdef LAB_ONLY if(drawTerrainGrid) { Stuff::Vector3D realStart = startPos; Stuff::Vector4D lineStart, lineEnd; eye->projectZ(realStart, lineStart); eye->projectZ(endPos, lineEnd); debugLines[currentLineElement++] = new LineElement(lineStart, lineEnd, SD_GREEN, nullptr, -1); } #endif } #ifdef LAB_ONLY x = GetCycles() - x; MCTimeLOSCalc += x; #endif return true; }
//--------------------------------------------------------------------------- bool Team::teamLineOfSight(Stuff::Vector3D tPos, float extRad) { //----------------------------------------------------------- // For each member of the team, check LOS to point provided. for(size_t i = 0; i < rosterSize; i++) { MoverPtr obj = (MoverPtr)ObjectManager->getByWatchID(roster[i]); if(!obj->isDisabled() && !obj->isDestroyed() && (obj->getStatus() != OBJECT_STATUS_SHUTDOWN)) { Stuff::Vector3D distance; distance.Subtract(tPos, obj->getPosition()); float dist = distance.GetApproximateLength(); //Figure out altitude above minimum terrain altitude and look up in table. float baseElevation = MapData::waterDepth; if(MapData::waterDepth < Terrain::userMin) baseElevation = Terrain::userMin; float altitude = obj->getPosition().z - baseElevation; float altitudeIntegerRange = (Terrain::userMax - baseElevation) * 0.00390625f; int32_t altLevel = 0; if(altitudeIntegerRange > Stuff::SMALL) altLevel = altitude / altitudeIntegerRange; if(altLevel < 0) altLevel = 0; if(altLevel > 255) altLevel = 255; float radius = visualRangeTable[altLevel]; //Scouting specialty skill. if(obj->isMover()) { MoverPtr mover = (MoverPtr)obj; if(mover->pilot && mover->pilot->isScout()) radius += (radius * 0.2f); radius *= mover->getLOSFactor(); } if(dist <= (radius * 25.0f * worldUnitsPerMeter)) { if(lineOfSight(obj->getLOSPosition(), tPos, id, extRad, 0.0f, false)) return true; } } } //------------------------------------------------------------------------- // Check the lookout towers now. You can find them in special Buildings!! for(size_t spBuilding = 0; spBuilding < ObjectManager->numSpecialBuildings; spBuilding++) { if(ObjectManager->specialBuildings[spBuilding] && ObjectManager->specialBuildings[spBuilding]->getExists() && ObjectManager->specialBuildings[spBuilding]->isLookoutTower() && (ObjectManager->specialBuildings[spBuilding]->getTeamId() == id)) { GameObjectPtr obj = ObjectManager->specialBuildings[spBuilding]; if(!obj->isDisabled() && !obj->isDestroyed() && (obj->getStatus() != OBJECT_STATUS_SHUTDOWN)) { Stuff::Vector3D distance; distance.Subtract(tPos, obj->getPosition()); float dist = distance.GetApproximateLength(); //Figure out altitude above minimum terrain altitude and look up in table. float baseElevation = MapData::waterDepth; if(MapData::waterDepth < Terrain::userMin) baseElevation = Terrain::userMin; float altitude = obj->getPosition().z - baseElevation; float altitudeIntegerRange = (Terrain::userMax - baseElevation) * 0.00390625f; int32_t altLevel = 0; if(altitudeIntegerRange > Stuff::SMALL) altLevel = altitude / altitudeIntegerRange; if(altLevel < 0) altLevel = 0; if(altLevel > 255) altLevel = 255; float radius = visualRangeTable[altLevel]; //Scouting specialty skill. if(obj->isMover()) { MoverPtr mover = (MoverPtr)obj; if(mover->pilot && mover->pilot->isScout()) radius += (radius * 0.2f); radius *= mover->getLOSFactor(); } if(dist <= (radius * 25.0f * worldUnitsPerMeter)) { if(lineOfSight(obj->getLOSPosition(), tPos, id, 0.0f, obj->getAppearRadius(), false)) return true; } } } } return false; }
//--------------------------------------------------------------------------- bool Team::lineOfSight(float startLocal, int32_t mCellRow, int32_t mCellCol, float endLocal, int32_t tCellRow, int32_t tCellCol, int32_t teamId, float extRad, float startExtRad, bool checkVisibleBits) { #ifdef LAB_ONLY int64_t x = GetCycles(); #endif //----------------------------------------------------- // Once we allow teams to have alliances (for contacts, // etc.), simply set all nec. team bits in this mask... //TILE HACK... int32_t tileRow = tCellRow / 3; int32_t tileCol = tCellCol / 3; if((teamId < 0) || (teamId >= MAX_TEAMS)) //Not on any team. It can see everything! return true; #if 0 //Don't need to check this anymore. We do a distance check outside of this function. if(checkVisibleBits) { uint8_t teamMask = 0x01 << teamId; uint8_t visbBits[4]; //---------------------------------------------------------------------------- // First check is simple. Is anyone within the magical line of sight radius? // If not, return false and move on. // If they are, you MUST check LOS between this object and the other one. bool losResult = false; visbBits[0] = Terrain::VisibleBits->getFlag(tileRow, tileCol); if(visbBits[0] & teamMask) losResult = true; if(!losResult) { visbBits[1] = Terrain::VisibleBits->getFlag(tileRow + 1, tileCol); if(visbBits[1] & teamMask) losResult = true; } if(!losResult) { visbBits[2] = Terrain::VisibleBits->getFlag(tileRow + 1, tileCol + 1); if(visbBits[2] & teamMask) losResult = true; } if(!losResult) { visbBits[3] = Terrain::VisibleBits->getFlag(tileRow, tileCol + 1); if(visbBits[3] & teamMask) losResult = true; } if(!losResult) { #ifdef LAB_ONLY x = GetCycles() - x; MCTimeLOSCalc += x; #endif return losResult; } } #endif if(useRealLOS) { //------------------------------------------------------------------------------------------ // Within magic radius. Check REAL LOS now. // Check is really simple. // Find deltaCellRow and deltaCellCol and iterate over them from source to dest. // If the magic line ever goes BELOW the terrainElevation PLUS localElevation return false. Stuff::Vector3D startPos, endPos; startPos.Zero(); endPos.Zero(); land->getCellPos(tCellRow, tCellCol, endPos); land->getCellPos(mCellRow, mCellCol, startPos); startPos.z += startLocal; endPos.z += endLocal; Stuff::Vector3D deltaCellVec; deltaCellVec.y = tCellRow - mCellRow; deltaCellVec.x = tCellCol - mCellCol; deltaCellVec.z = 0.0f; float startHeight = startPos.z; float length = deltaCellVec.GetApproximateLength(); length *= ACCURACY_ADJUST; if(length > Stuff::SMALL) { float colLength = (endPos.x - startPos.x) / length; float rowLength = (endPos.y - startPos.y) / length; float heightLen = (endPos.z - startPos.z) / (length + ACCURACY_ADJUST); Stuff::Vector3D currentPos = startPos; currentPos.z = land->getTerrainElevation(currentPos); int32_t maxDistIter = (length - 0.5f); int32_t maxTrees = 0; Stuff::Vector3D dist; dist.Subtract(endPos, currentPos); float remainingDist = dist.GetApproximateLength(); bool checkExtent = (extRad > Stuff::SMALL); bool checkStart = (startExtRad > Stuff::SMALL); extRad += HALF_CELL_DIST; for(size_t distIter = 0; distIter < maxDistIter; distIter++) { bool outsideStartRadius = true; if(checkStart) { Stuff::Vector3D distance; distance.Subtract(currentPos, startPos); distance.z = 0.0f; float dist = distance.GetApproximateLength(); if(dist <= startExtRad) outsideStartRadius = false; } startHeight += heightLen; int32_t curCellRow, curCellCol; land->worldToCell(currentPos, curCellRow, curCellCol); float localElev = (worldUnitsPerMeter * 4.0f * (float)GameMap->getLocalHeight(curCellRow, curCellCol)); float thisHeight = currentPos.z + localElev; //First, check if we are now inside the extent radius of the thing we are calcing LOS to. // If we are and we haven't returned false since we're here, we can see it!!!! if(checkExtent) { dist.Subtract(endPos, currentPos); remainingDist = dist.GetApproximateLength(); if(remainingDist <= extRad) break; } if(outsideStartRadius && (startHeight < thisHeight)) { bool isTree = false; if(GameMap->getForest(curCellRow, curCellCol)) { maxTrees++; isTree = true; } if(!isTree || (maxTrees >= MaxTreeLOSCellBlock)) { #ifdef LAB_ONLY x = GetCycles() - x; MCTimeLOSCalc += x; #endif #ifdef LAB_ONLY if(drawTerrainGrid) { Stuff::Vector3D realStart = startPos; Stuff::Vector4D lineStart, lineEnd; eye->projectZ(realStart, lineStart); eye->projectZ(endPos, lineEnd); debugLines[currentLineElement++] = new LineElement(lineStart, lineEnd, SD_RED, nullptr, -1); } #endif return false; } } currentPos.x += colLength; currentPos.y += rowLength; currentPos.z = land->getTerrainElevation(currentPos); } } #ifdef LAB_ONLY if(drawTerrainGrid) { Stuff::Vector3D realStart = startPos; Stuff::Vector4D lineStart, lineEnd; eye->projectZ(realStart, lineStart); eye->projectZ(endPos, lineEnd); debugLines[currentLineElement++] = new LineElement(lineStart, lineEnd, SD_GREEN, nullptr, -1); } #endif } #ifdef LAB_ONLY x = GetCycles() - x; MCTimeLOSCalc += x; #endif return true; }
//--------------------------------------------------------------------------- int32_t Building::updateAnimations(void) { //--------------------------------------------- // Animate Sensor Towers first. /* if (sensorSystem != nullptr) { int32_t animState = appearance->getCurrentGestureId(); if (sensorSystem->numContacts) { switch (animState) { case -1: //NOT UPDATED YET. SWITCH TO ZERO if (!appearance->getInTransition()) { appearance->setGesture(0); } break; case 2: //Just Animating. Do NOTHING! break; case 0: //Not triggered yet. Switch to 1 appearance->setGesture(1); break; case 1: //triggered, when fully open switch to 2 if (!appearance->getInTransition()) { appearance->setGesture(2); } break; case 3: //Closing. Wait until closed and then switch to 1. if (!appearance->getInTransition()) { appearance->setGesture(1); } break; } } else //This will be handled by sensor system going disabled if building destroyed OR parent destroyed! { switch (animState) { case -1: //NOT UPDATED YET. SWITCH TO ZERO if (!appearance->getInTransition()) { appearance->setGesture(0); } break; case 2: //Just Animating. Wait until one loop done, then trigger closing if (!appearance->getInTransition()) { appearance->setGesture(3); } break; case 0: //Not triggered yet. DO NOTHING! break; case 1: //triggered, when fully open switch to 3 to close it. if (!appearance->getInTransition()) { appearance->setGesture(3); } break; case 3: //Closing to closed. When Closed, DO NOTHING break; } } } else*/ if(((BuildingTypePtr)getObjectType())->resourcePoints) { if(!MPlayer) { //We are a resource Points Building. //OPEN when we have been CAPTURED!! int32_t animState = appearance->getCurrentGestureId(); if(!teamId) //We've been Captured { switch(animState) { case -1: //NOT UPDATED YET. SWITCH TO ZERO if(!appearance->getInTransition()) { appearance->setGesture(0); } break; case 2: //Just Animating. Do NOTHING! break; case 0: //Not triggered yet. Switch to 1 appearance->setGesture(1); break; case 1: //triggered, when fully open switch to 2 if(!appearance->getInTransition()) { appearance->setGesture(2); } break; case 3: //Closing. Wait until closed and then switch to 1. if(!appearance->getInTransition()) { appearance->setGesture(1); } break; } } else { //Stay Closed switch(animState) { case -1: //NOT UPDATED YET. SWITCH TO ZERO if(!appearance->getInTransition()) { appearance->setGesture(0); } break; case 2: //Just Animating. Do NOTHING! break; case 0: //Do Nothing break; case 1: //triggered, when fully open switch to 3 if(!appearance->getInTransition()) { appearance->setGesture(3); } break; case 3: //Closing. Wait until closed and then switch to 1. if(!appearance->getInTransition()) { appearance->setGesture(0); } break; } } } } else if(((BuildingTypePtr)getObjectType())->mechBay) { if(!MPlayer) { //We are a Mech Repair Bay Building. // Open to the correct place based on our RepairBuddyWID int32_t animState = appearance->getCurrentGestureId(); if(!refitBuddyWID) //We're repairing no one. { switch(animState) { case -1: //NOT UPDATED YET. SWITCH TO ZERO if(!appearance->getInTransition()) { appearance->setGesture(0); } break; case 1: //We were repairing someone. Switch to doing nothing! if(!appearance->getInTransition()) { appearance->setGesture(5); } break; case 2: //We were repairing someone. Switch to doing nothing! if(!appearance->getInTransition()) { appearance->setGesture(6); } break; case 3: //We were repairing someone. Switch to doing nothing! if(!appearance->getInTransition()) { appearance->setGesture(7); } break; case 4: //We were repairing someone. Switch to doing nothing! if(!appearance->getInTransition()) { appearance->setGesture(8); } break; case 5: //We were repairing someone. Switch to doing nothing! case 6: //We were repairing someone. Switch to doing nothing! case 7: //We were repairing someone. Switch to doing nothing! case 8: //We were repairing someone. Switch to doing nothing! if(!appearance->getInTransition()) { appearance->setGesture(0); } break; case 0: //Do Nothing. We aren't repairing anyone break; } } else { //We are repairing someone. switch(animState) { case -1: //NOT UPDATED YET. SWITCH TO ZERO if(!appearance->getInTransition()) { appearance->setGesture(0); } break; case 1: case 2: case 3: case 4: //DO NOTHING!! We are in position. { GameObjectPtr refitMech = ObjectManager->getByWatchID(refitBuddyWID); if(refitMech && (refitMech->getStatus() == OBJECT_STATUS_SHUTDOWN)) { if(((BuildingTypePtr)getObjectType())->activityEffectId != 0xffffffff) appearance->startActivity(((BuildingTypePtr)getObjectType())->activityEffectId, true); } else { appearance->stopActivity(); } } break; case 0: if(!appearance->getInTransition()) { GameObjectPtr refitMech = ObjectManager->getByWatchID(refitBuddyWID); if(refitMech) { Stuff::Vector3D distance; distance.Subtract(refitMech->getPosition(), getPosition()); float dist = distance.GetApproximateLength(); if(dist <= 128.0f) { if(refitMech && (refitMech->getTonnage() <= 40.0f)) { appearance->setGesture(1); } else if(refitMech && (refitMech->getTonnage() <= 60.0f)) { appearance->setGesture(2); } else if(refitMech && (refitMech->getTonnage() <= 80.0f)) { appearance->setGesture(3); } else if(refitMech && (refitMech->getTonnage() <= 100.0f)) { appearance->setGesture(4); } } } } break; case 5: //We were repairing someone. Switch to doing nothing! case 6: //We were repairing someone. Switch to doing nothing! case 7: //We were repairing someone. Switch to doing nothing! case 8: //We were repairing someone. Switch to doing nothing! if(!appearance->getInTransition()) { appearance->setGesture(0); } break; } } } else //MechBays must ALWAYS be open in Mplayer or it will look dumb! { appearance->setGesture(4); } } else { //Just about everything else animates here. if(!isDisabled() && !isDestroyed()) { if(!appearance->getInTransition()) { appearance->setGesture(0); } } else //This will be handled by building destroyed OR parent destroyed! { } } return 0; }