void CHoverAirMoveType::UpdateLanding() { const float3& pos = owner->pos; const float3& speed = owner->speed; // We want to land, and therefore cancel our speed first wantedSpeed = ZeroVector; // Hang around for a while so queued commands have a chance to take effect if ((++waitCounter) < GAME_SPEED) { UpdateAirPhysics(); return; } if (reservedLandingPos.x < 0) { if (CanLandAt(pos)) { // found a landing spot reservedLandingPos = pos; goalPos = pos; owner->physicalState = CSolidObject::OnGround; owner->Block(); owner->physicalState = CSolidObject::Flying; owner->Deactivate(); owner->script->StopMoving(); } else { if (goalPos.SqDistance2D(pos) < 900) { goalPos = goalPos + gs->randVector() * 300; goalPos.ClampInBounds(); progressState = AMoveType::Failed; // exact landing pos failed, make sure finishcommand is called anyway } flyState = FLY_LANDING; UpdateFlying(); return; } } // We should wait until we actually have stopped smoothly if (speed.SqLength2D() > 1.0f) { UpdateFlying(); return; } // We have stopped, time to land // NOTE: wantedHeight is interpreted as RELATIVE altitude const float gh = ground->GetHeightAboveWater(pos.x, pos.z); const float gah = ground->GetHeightReal(pos.x, pos.z); float altitude = (wantedHeight = 0.0f); // can we submerge and are we still above water? if ((owner->unitDef->canSubmerge) && (gah < 0.0f)) { altitude = pos.y - gah; } else { altitude = pos.y - gh; } UpdateAirPhysics(); if (altitude <= 1.0f) { SetState(AIRCRAFT_LANDED); } }
void CTAAirMoveType::UpdateLanding() { float3 &pos = owner->pos; float3 &speed = owner->speed; //We want to land, and therefore cancel our speed first wantedSpeed = ZeroVector; waitCounter++; //Hang around for a while so queued commands have a chance to take effect if (waitCounter < 30) { //logOutput.Print("want to land, but.. %d", waitCounter); UpdateAirPhysics(); return; } if(reservedLandingPos.x<0){ // logOutput.Print("Searching for landing spot"); if(CanLandAt(pos)){ // logOutput.Print("Found landing spot"); reservedLandingPos=pos; goalPos=pos; owner->physicalState = CSolidObject::OnGround; owner->Block(); owner->physicalState = CSolidObject::Flying; owner->Deactivate(); owner->cob->Call(COBFN_StopMoving); } else { if(goalPos.distance2D(pos)<30){ goalPos=goalPos+gs->randVector()*300; goalPos.CheckInBounds(); } flyState = FLY_LANDING; UpdateFlying(); return; } } //We should wait until we actually have stopped smoothly if (speed.SqLength2D() > 1) { UpdateFlying(); return; } //We have stopped, time to land wantedHeight=-2; UpdateAirPhysics(); float h = pos.y - ground->GetHeight(pos.x, pos.z); if (h <= 0) { //logOutput.Print("Landed"); SetState(AIRCRAFT_LANDED); pos.y = ground->GetHeight(pos.x, pos.z); } }
// Move the unit around a bit.. void CHoverAirMoveType::UpdateHovering() { #if 0 #define NOZERO(x) std::max(x, 0.0001f) float3 deltaVec = goalPos - owner->pos; float3 deltaDir = float3(deltaVec.x, 0.0f, deltaVec.z); const float driftSpeed = math::fabs(owner->unitDef->dlHoverFactor); const float goalDistance = NOZERO(deltaDir.Length2D()); const float brakeDistance = 0.5f * owner->speed.SqLength2D() / decRate; // move towards goal position if it's not immediately // behind us when we have more waypoints to get to // *** this behavior interferes with the loading procedure of transports *** const bool b0 = (aircraftState != AIRCRAFT_LANDING && owner->commandAI->HasMoreMoveCommands()); const bool b1 = (goalDistance < brakeDistance && goalDistance > 1.0f); if (b0 && b1 && dynamic_cast<CTransportUnit*>(owner) == NULL) { deltaDir = owner->frontdir; } else { deltaDir *= smoothstep(0.0f, 20.0f, goalDistance) / goalDistance; deltaDir -= owner->speed; } if (deltaDir.SqLength2D() > (maxSpeed * maxSpeed)) { deltaDir *= (maxSpeed / NOZERO(math::sqrt(deltaDir.SqLength2D()))); } // random movement (a sort of fake wind effect) // random drift values are in range -0.5 ... 0.5 randomWind.x = randomWind.x * 0.9f + (gs->randFloat() - 0.5f) * 0.5f; randomWind.z = randomWind.z * 0.9f + (gs->randFloat() - 0.5f) * 0.5f; wantedSpeed = owner->speed + deltaDir; wantedSpeed += (randomWind * driftSpeed * 0.5f); UpdateAirPhysics(); #endif #if 1 randomWind.x = randomWind.x * 0.9f + (gs->randFloat() - 0.5f) * 0.5f; randomWind.z = randomWind.z * 0.9f + (gs->randFloat() - 0.5f) * 0.5f; // randomly drift (but not too far from goal-position) wantedSpeed = (randomWind * math::fabs(owner->unitDef->dlHoverFactor) * 0.5f); wantedSpeed += (smoothstep(0.0f, 20.0f * 20.0f, (goalPos - owner->pos)) * (goalPos - owner->pos)); UpdateAirPhysics(); #endif }
void CAirMoveType::UpdateManeuver(void) { #ifdef DEBUG_AIRCRAFT if(selectedUnits.selectedUnits.find(this)!=selectedUnits.selectedUnits.end()){ info->AddLine("UpdataMan %i %i",maneuver,maneuverSubState); } #endif float speedf=owner->speed.Length(); switch(maneuver){ case 1:{ int aileron=0,elevator=0; if(owner->updir.y>0){ if(owner->rightdir.y>maxAileron*speedf){ aileron=1; }else if(owner->rightdir.y<-maxAileron*speedf){ aileron=-1; } } if(fabs(owner->rightdir.y)<maxAileron*3*speedf || owner->updir.y<0) elevator=1; UpdateAirPhysics(0,aileron,elevator,1,owner->frontdir); if((owner->updir.y<0 && owner->frontdir.y<0) || speedf<0.8) maneuver=0; break;} case 2:{ int aileron=0,elevator=0; if(maneuverSubState==0){ if(owner->rightdir.y>=0){ aileron=-1; }else{ aileron=1; } } if(owner->frontdir.y<-0.7) maneuverSubState=1; if(maneuverSubState==1 || owner->updir.y<0) elevator=1; UpdateAirPhysics(0,aileron,elevator,1,owner->frontdir); if((owner->updir.y>0 && owner->frontdir.y>0 && maneuverSubState==1) || speedf<0.2) maneuver=0; break;} default: UpdateAirPhysics(0,0,0,1,owner->frontdir); maneuver=0; break; } }
// Move the unit around a bit.. void CTAAirMoveType::UpdateHovering() { #define NOZERO(x) std::max(x, 0.0001f) const float driftSpeed = fabs(owner->unitDef->dlHoverFactor); float3 deltaVec = goalPos - owner->pos; float3 deltaDir = float3(deltaVec.x, 0, deltaVec.z); float l = NOZERO(deltaDir.Length2D()); deltaDir *= smoothstep(0.0f, 20.0f, l) / l; // move towards goal position if it's not immediately // behind us when we have more waypoints to get to // *** this behavior interferes with the loading procedure of transports *** if (aircraftState != AIRCRAFT_LANDING && owner->commandAI->HasMoreMoveCommands() && (l < 120) && (deltaDir.SqDistance(deltaVec) > 1.0f) && dynamic_cast<CTransportUnit*>(owner) == NULL) { deltaDir = owner->frontdir; } deltaDir -= owner->speed; l = deltaDir.SqLength2D(); if (l > (maxSpeed * maxSpeed)) { deltaDir *= maxSpeed / NOZERO(sqrt(l)); } wantedSpeed = owner->speed + deltaDir; // random movement (a sort of fake wind effect) // random drift values are in range -0.5 ... 0.5 randomWind = float3(randomWind.x * 0.9f + (gs->randFloat() - 0.5f) * 0.5f, 0, randomWind.z * 0.9f + (gs->randFloat() - 0.5f) * 0.5f); wantedSpeed += randomWind * driftSpeed * 0.5f; UpdateAirPhysics(); }
void CHoverAirMoveType::UpdateLanding() { const float3& pos = owner->pos; if (!HaveLandingPos()) { if (CanLandAt(pos)) { // found a landing spot reservedLandingPos = pos; goalPos = pos; wantedHeight = 0; UpdateLandingHeight(); const float3 originalPos = pos; owner->Move(reservedLandingPos, false); owner->Block(); owner->Move(originalPos, false); owner->script->StopMoving(); } else { if (goalPos.SqDistance2D(pos) < (30.0f * 30.0f)) { // randomly pick another landing spot and try again goalPos += (gs->randVector() * 300.0f); goalPos.ClampInBounds(); // exact landing pos failed, make sure finishcommand is called anyway progressState = AMoveType::Failed; } flyState = FLY_LANDING; UpdateFlying(); return; } } flyState = FLY_LANDING; const float altitude = pos.y - reservedLandingPos.y; const float distSq2D = reservedLandingPos.SqDistance2D(pos); if (distSq2D > landRadiusSq) { const float tmpWantedHeight = wantedHeight; SetGoal(reservedLandingPos); wantedHeight = std::min((orgWantedHeight - wantedHeight) * distSq2D / altitude + wantedHeight, orgWantedHeight); UpdateFlying(); wantedHeight = tmpWantedHeight; return; } // We want to land, and therefore cancel our speed first wantedSpeed = ZeroVector; AAirMoveType::UpdateLanding(); UpdateAirPhysics(); }
void CTAAirMoveType::UpdateTakeoff() { float3 &pos = owner->pos; wantedSpeed=ZeroVector; wantedHeight=orgWantedHeight; UpdateAirPhysics(); float h = pos.y - ground->GetHeight(pos.x, pos.z); if (h > orgWantedHeight*0.8f) { //logOutput.Print("Houston, we have liftoff %f %f", h, wantedHeight); SetState(AIRCRAFT_FLYING); } }
// Move the unit around a bit.. and when it gets too far away from goal position it switches to normal flying instead void CTAAirMoveType::UpdateHovering() { float driftSpeed = owner->unitDef->dlHoverFactor; // move towards goal position float3 dir = goalPos - owner->pos; wantedSpeed += float3(dir.x, 0.0f, dir.z) * driftSpeed * 0.03f; // damping wantedSpeed *= 0.97f; // random movement (a sort of fake wind effect) wantedSpeed += float3(gs->randFloat()-.5f, 0.0f, gs->randFloat()-0.5f) * driftSpeed * 0.5f; UpdateAirPhysics(); }
void CHoverAirMoveType::UpdateTakeoff() { const float3& pos = owner->pos; wantedSpeed = ZeroVector; wantedHeight = orgWantedHeight; UpdateAirPhysics(); const float altitude = owner->unitDef->canSubmerge? (pos.y - CGround::GetHeightReal(pos.x, pos.z)): (pos.y - CGround::GetHeightAboveWater(pos.x, pos.z)); if (altitude > orgWantedHeight * 0.8f) { SetState(AIRCRAFT_FLYING); } }
void CTAAirMoveType::UpdateTakeoff() { float3 &pos = owner->pos; wantedSpeed = ZeroVector; wantedHeight = orgWantedHeight; UpdateAirPhysics(); float h = 0.0f; if (owner->unitDef->canSubmerge) { h = pos.y - ground->GetApproximateHeight(pos.x, pos.z); } else { h = pos.y - ground->GetHeightAboveWater(pos.x, pos.z); } if (h > orgWantedHeight * 0.8f) { SetState(AIRCRAFT_FLYING); } }
void CHoverAirMoveType::UpdateTakeoff() { float3& pos = owner->pos; wantedSpeed = ZeroVector; wantedHeight = orgWantedHeight; UpdateAirPhysics(); float altitude = 0.0f; if (owner->unitDef->canSubmerge) { altitude = pos.y - ground->GetHeightReal(pos.x, pos.z); } else { altitude = pos.y - ground->GetHeightAboveWater(pos.x, pos.z); } if (altitude > orgWantedHeight * 0.8f) { SetState(AIRCRAFT_FLYING); } }
// Move the unit around a bit.. and when it gets too far away from goal position // it switches to normal flying instead void CTAAirMoveType::UpdateHovering() { float driftSpeed = owner->unitDef->dlHoverFactor; float3 dir = goalPos - owner->pos; // move towards goal position if it's not immediately behind us when we have // more waypoints to get to if (aircraftState != AIRCRAFT_LANDING && (owner->commandAI->HasMoreMoveCommands() && dir.Length2D() < 120) && (goalPos - owner->pos).Normalize().distance(dir) > 1) { dir = owner->frontdir; } wantedSpeed += float3(dir.x, 0.0f, dir.z) * driftSpeed * 0.03f; // damping wantedSpeed *= 0.97f; // random movement (a sort of fake wind effect) wantedSpeed += float3(gs->randFloat() - 0.5f, 0.0f, gs->randFloat() - 0.5f) * driftSpeed * 0.5f; UpdateAirPhysics(); }
void CAirMoveType::Update(void) { float3 &pos=owner->pos; //This is only set to false after the plane has finished constructing if (useHeading){ useHeading = false; SetState(AIRCRAFT_TAKEOFF); } if(owner->stunned){ UpdateAirPhysics(0,lastAileronPos,lastElevatorPos,0,ZeroVector); goto EndNormalControl; } #ifdef DIRECT_CONTROL_ALLOWED if(owner->directControl && !(aircraftState==AIRCRAFT_CRASHING)){ SetState(AIRCRAFT_FLYING); DirectControlStruct* dc=owner->directControl; inefficientAttackTime=0; if(dc->forward || dc->back || dc->left || dc->right){ float aileron=0; float elevator=0; if(dc->forward) elevator-=1; if(dc->back) elevator+=1; if(dc->right) aileron+=1; if(dc->left) aileron-=1; UpdateAirPhysics(0,aileron,elevator,1,owner->frontdir); maneuver=0; goto EndNormalControl; //ok so goto is bad i know } } #endif if(reservedPad){ CUnit* unit=reservedPad->unit; float3 relPos=unit->localmodel->GetPiecePos(reservedPad->piece); float3 pos=unit->pos + unit->frontdir*relPos.z + unit->updir*relPos.y + unit->rightdir*relPos.x; if(padStatus==0){ if(aircraftState!=AIRCRAFT_FLYING && aircraftState!=AIRCRAFT_TAKEOFF) SetState(AIRCRAFT_FLYING); goalPos=pos; if(pos.distance(owner->pos)<400){ padStatus=1; } // geometricObjects->AddLine(owner->pos,pos,1,0,1); } else if(padStatus==1){ if(aircraftState!=AIRCRAFT_LANDING) SetState(AIRCRAFT_LANDING); goalPos=pos; reservedLandingPos=pos; if(owner->pos.distance(pos)<3 || aircraftState==AIRCRAFT_LANDED){ padStatus=2; } // geometricObjects->AddLine(owner->pos,pos,10,0,1); } else { if(aircraftState!=AIRCRAFT_LANDED) SetState(AIRCRAFT_LANDED); owner->pos=pos; owner->AddBuildPower(20,unit); if(owner->health>=owner->maxHealth-1){ airBaseHandler->LeaveLandingPad(reservedPad); reservedPad=0; padStatus=0; goalPos=oldGoalPos; SetState(AIRCRAFT_TAKEOFF); } } } switch(aircraftState){ case AIRCRAFT_FLYING: #ifdef DEBUG_AIRCRAFT if(selectedUnits.selectedUnits.find(this)!=selectedUnits.selectedUnits.end()){ info->AddLine("Flying %i %i %.1f %i",moveState,fireState,inefficientAttackTime,(int)isFighter); } #endif owner->restTime=0; if(owner->userTarget || owner->userAttackGround){ inefficientAttackTime=min(inefficientAttackTime,(float)gs->frameNum-owner->lastFireWeapon); if(owner->userTarget){ goalPos=owner->userTarget->pos; } else { goalPos=owner->userAttackPos; } if(maneuver){ UpdateManeuver(); inefficientAttackTime=0; } else if(isFighter && goalPos.distance(pos)<owner->maxRange*4){ inefficientAttackTime++; UpdateFighterAttack(); }else{ inefficientAttackTime=0; UpdateAttack(); } }else{ inefficientAttackTime=0; UpdateFlying(wantedHeight,1); } break; case AIRCRAFT_LANDED: inefficientAttackTime=0; UpdateLanded(); break; case AIRCRAFT_LANDING: inefficientAttackTime=0; UpdateLanding(); break; case AIRCRAFT_CRASHING: owner->crashing=true; UpdateAirPhysics(crashRudder,crashAileron,crashElevator,0,owner->frontdir); new CSmokeProjectile(owner->midPos,gs->randVector()*0.08,100+gs->randFloat()*50,5,0.2,owner,0.4); if(!(gs->frameNum&3) && max(0.f,ground->GetApproximateHeight(pos.x,pos.z))+5+owner->radius>pos.y) owner->KillUnit(true,false,0); break; case AIRCRAFT_TAKEOFF: UpdateTakeOff(wantedHeight); default: break; } EndNormalControl: if(pos!=oldpos){ oldpos=pos; if(aircraftState==AIRCRAFT_FLYING || aircraftState==AIRCRAFT_CRASHING){ vector<CUnit*> nearUnits=qf->GetUnitsExact(pos,owner->radius+6); vector<CUnit*>::iterator ui; for(ui=nearUnits.begin();ui!=nearUnits.end();++ui){ float sqDist=(pos-(*ui)->pos).SqLength(); float totRad=owner->radius+(*ui)->radius; if(sqDist<totRad*totRad && sqDist!=0){ float dist=sqrt(sqDist); float3 dif=pos-(*ui)->pos; dif/=dist; if((*ui)->immobile){ pos-=dif*(dist-totRad); owner->midPos=pos+owner->frontdir*owner->relMidPos.z + owner->updir*owner->relMidPos.y + owner->rightdir*owner->relMidPos.x; owner->speed*=0.99f; float damage=(((*ui)->speed-owner->speed)*0.1).SqLength(); owner->DoDamage(DamageArray()*damage,0,ZeroVector); (*ui)->DoDamage(DamageArray()*damage,0,ZeroVector); } else { float part=owner->mass/(owner->mass+(*ui)->mass); pos-=dif*(dist-totRad)*(1-part); owner->midPos=pos+owner->frontdir*owner->relMidPos.z + owner->updir*owner->relMidPos.y + owner->rightdir*owner->relMidPos.x; CUnit* u=(CUnit*)(*ui); u->pos+=dif*(dist-totRad)*(part); u->midPos=u->pos+u->frontdir*u->relMidPos.z + u->updir*u->relMidPos.y + u->rightdir*u->relMidPos.x; float damage=(((*ui)->speed-owner->speed)*0.1).SqLength(); owner->DoDamage(DamageArray()*damage,0,ZeroVector); (*ui)->DoDamage(DamageArray()*damage,0,ZeroVector); owner->speed*=0.99f; } } } } if(pos.x<0){ pos.x+=1.5; owner->midPos.x+=1.5; }else if(pos.x>float3::maxxpos){ pos.x-=1.5; owner->midPos.x-=1.5; } if(pos.z<0){ pos.z+=1.5; owner->midPos.z+=1.5; }else if(pos.z>float3::maxzpos){ pos.z-=1.5; owner->midPos.z-=1.5; } } #ifdef DEBUG_AIRCRAFT if(lastColWarningType==1){ int g=geometricObjects->AddLine(owner->pos,lastColWarning->pos,10,1,1); geometricObjects->SetColor(g,0.2,1,0.2,0.6); } else if(lastColWarningType==2){ int g=geometricObjects->AddLine(owner->pos,lastColWarning->pos,10,1,1); if(owner->frontdir.dot(lastColWarning->midPos+lastColWarning->speed*20 - owner->midPos - owner->speed*20)<0) geometricObjects->SetColor(g,1,0.2,0.2,0.6); else geometricObjects->SetColor(g,1,1,0.2,0.6); } #endif }
bool CHoverAirMoveType::Update() { const float3 lastPos = owner->pos; const float4 lastSpd = owner->speed; AAirMoveType::Update(); if ((owner->IsStunned() && !owner->IsCrashing()) || owner->beingBuilt) { wantedSpeed = ZeroVector; UpdateAirPhysics(); return (HandleCollisions(collide && !owner->beingBuilt && (padStatus == PAD_STATUS_FLYING) && (aircraftState != AIRCRAFT_TAKEOFF))); } // allow us to stop if wanted (changes aircraft state) if (wantToStop) ExecuteStop(); if (aircraftState != AIRCRAFT_CRASHING) { if (owner->UnderFirstPersonControl()) { SetState(AIRCRAFT_FLYING); const FPSUnitController& con = owner->fpsControlPlayer->fpsController; const float3 forward = con.viewDir; const float3 right = forward.cross(UpVector); const float3 nextPos = lastPos + owner->speed; float3 flatForward = forward; flatForward.Normalize2D(); wantedSpeed = ZeroVector; if (con.forward) wantedSpeed += flatForward; if (con.back ) wantedSpeed -= flatForward; if (con.right ) wantedSpeed += right; if (con.left ) wantedSpeed -= right; wantedSpeed.Normalize(); wantedSpeed *= maxSpeed; if (!nextPos.IsInBounds()) { owner->SetVelocityAndSpeed(ZeroVector); } UpdateAirPhysics(); wantedHeading = GetHeadingFromVector(flatForward.x, flatForward.z); } if (reservedPad != NULL) { MoveToRepairPad(); if (padStatus >= PAD_STATUS_LANDING) { flyState = FLY_LANDING; } } } switch (aircraftState) { case AIRCRAFT_LANDED: UpdateLanded(); break; case AIRCRAFT_TAKEOFF: UpdateTakeoff(); break; case AIRCRAFT_FLYING: UpdateFlying(); break; case AIRCRAFT_LANDING: UpdateLanding(); break; case AIRCRAFT_HOVERING: UpdateHovering(); break; case AIRCRAFT_CRASHING: { UpdateAirPhysics(); if ((CGround::GetHeightAboveWater(owner->pos.x, owner->pos.z) + 5.0f + owner->radius) > owner->pos.y) { owner->ClearPhysicalStateBit(CSolidObject::PSTATE_BIT_CRASHING); owner->KillUnit(NULL, true, false); } else { #define SPIN_DIR(o) ((o->id & 1) * 2 - 1) wantedHeading = GetHeadingFromVector(owner->rightdir.x * SPIN_DIR(owner), owner->rightdir.z * SPIN_DIR(owner)); wantedHeight = 0.0f; #undef SPIN_DIR } new CSmokeProjectile(owner, owner->midPos, gs->randVector() * 0.08f, 100 + gs->randFloat() * 50, 5, 0.2f, 0.4f); } break; } if (lastSpd == ZeroVector && owner->speed != ZeroVector) { owner->script->StartMoving(false); } if (lastSpd != ZeroVector && owner->speed == ZeroVector) { owner->script->StopMoving(); } // Banking requires deltaSpeed.y = 0 deltaSpeed = owner->speed - lastSpd; deltaSpeed.y = 0.0f; // Turn and bank and move; update dirs UpdateHeading(); UpdateBanking(aircraftState == AIRCRAFT_HOVERING); return (HandleCollisions(collide && !owner->beingBuilt && (padStatus == PAD_STATUS_FLYING) && (aircraftState != AIRCRAFT_TAKEOFF))); }
void CHoverAirMoveType::UpdateLanding() { const float3& pos = owner->pos; const float4& spd = owner->speed; // We want to land, and therefore cancel our speed first wantedSpeed = ZeroVector; // Hang around for a while so queued commands have a chance to take effect if ((++waitCounter) < GAME_SPEED) { UpdateAirPhysics(); return; } if (reservedLandingPos.x < 0.0f) { if (CanLandAt(pos)) { // found a landing spot reservedLandingPos = pos; goalPos = pos; owner->Block(); owner->Deactivate(); owner->script->StopMoving(); } else { if (goalPos.SqDistance2D(pos) < (30.0f * 30.0f)) { // randomly pick another landing spot and try again goalPos += (gs->randVector() * 300.0f); goalPos.ClampInBounds(); // exact landing pos failed, make sure finishcommand is called anyway progressState = AMoveType::Failed; } flyState = FLY_LANDING; UpdateFlying(); return; } } // We should wait until we actually have stopped smoothly if (spd.SqLength2D() > 1.0f) { UpdateFlying(); UpdateAirPhysics(); return; } // We have stopped, time to land // NOTE: wantedHeight is interpreted as RELATIVE altitude const float gh = CGround::GetHeightAboveWater(pos.x, pos.z); const float gah = CGround::GetHeightReal(pos.x, pos.z); float altitude = (wantedHeight = 0.0f); // can we submerge and are we still above water? if ((owner->unitDef->canSubmerge) && (gah < 0.0f)) { altitude = pos.y - gah; } else { altitude = pos.y - gh; } UpdateAirPhysics(); // collision detection does not let us get // closer to the ground than <radius> elmos // (wrt. midPos.y) if (altitude <= owner->radius) { SetState(AIRCRAFT_LANDED); } }
void CHoverAirMoveType::UpdateFlying() { const float3& pos = owner->pos; // const float4& spd = owner->speed; // Direction to where we would like to be float3 goalVec = goalPos - pos; owner->restTime = 0; // don't change direction for waypoints we just flew over and missed slightly if (flyState != FLY_LANDING && owner->commandAI->HasMoreMoveCommands()) { float3 goalDir = goalVec; if ((goalDir != ZeroVector) && (goalVec.dot(goalDir.UnsafeANormalize()) < 1.0f)) { goalVec = owner->frontdir; } } const float goalDistSq2D = goalVec.SqLength2D(); const float gHeight = UseSmoothMesh()? std::max(smoothGround->GetHeight(pos.x, pos.z), CGround::GetApproximateHeight(pos.x, pos.z)): CGround::GetHeightAboveWater(pos.x, pos.z); const bool closeToGoal = (flyState == FLY_ATTACKING)? (goalDistSq2D < ( 400.0f)): (goalDistSq2D < (maxDrift * maxDrift)) && (math::fabs(gHeight + wantedHeight - pos.y) < maxDrift); if (closeToGoal) { switch (flyState) { case FLY_CRUISING: { // NOTE: should CMD_LOAD_ONTO be here? const bool isTransporter = (dynamic_cast<CTransportUnit*>(owner) != NULL); const bool hasLoadCmds = isTransporter && !owner->commandAI->commandQue.empty() && (owner->commandAI->commandQue.front().GetID() == CMD_LOAD_ONTO || owner->commandAI->commandQue.front().GetID() == CMD_LOAD_UNITS); // [?] transport aircraft need some time to detect that they can pickup const bool canLoad = isTransporter && (++waitCounter < ((GAME_SPEED << 1) - 5)); const bool isBusy = IsUnitBusy(owner); if (!CanLand(isBusy) || (canLoad && hasLoadCmds)) { wantedSpeed = ZeroVector; if (isTransporter) { if (waitCounter > (GAME_SPEED << 1)) { wantedHeight = orgWantedHeight; } SetState(AIRCRAFT_HOVERING); return; } else { if (!isBusy) { wantToStop = true; // NOTE: // this is not useful, next frame UpdateFlying() // will change it to _LANDING because wantToStop // is now true SetState(AIRCRAFT_HOVERING); return; } } } else { wantedHeight = orgWantedHeight; SetState(AIRCRAFT_LANDING); return; } } break; case FLY_CIRCLING: { if ((++waitCounter) > ((GAME_SPEED * 3) + 10)) { if (airStrafe) { float3 relPos = pos - circlingPos; if (relPos.x < 0.0001f && relPos.x > -0.0001f) { relPos.x = 0.0001f; } static CMatrix44f rot(0.0f, fastmath::PI / 4.0f, 0.0f); // make sure the point is on the circle, go there in a straight line goalPos = circlingPos + (rot.Mul(relPos.Normalize2D()) * goalDistance); } waitCounter = 0; } } break; case FLY_ATTACKING: { if (airStrafe) { float3 relPos = pos - circlingPos; if (relPos.x < 0.0001f && relPos.x > -0.0001f) { relPos.x = 0.0001f; } CMatrix44f rot; if (gs->randFloat() > 0.5f) { rot.RotateY(0.6f + gs->randFloat() * 0.6f); } else { rot.RotateY(-(0.6f + gs->randFloat() * 0.6f)); } // Go there in a straight line goalPos = circlingPos + (rot.Mul(relPos.Normalize2D()) * goalDistance); } } break; case FLY_LANDING: { } break; } } // not "close" to goal yet, so keep going // use 2D math since goal is on the ground // but we are not goalVec.y = 0.0f; // if we are close to our goal, we should // adjust speed st. we never overshoot it // (by respecting current brake-distance) const float curSpeed = owner->speed.Length2D(); const float brakeDist = (0.5f * curSpeed * curSpeed) / decRate; const float goalDist = goalVec.Length() + 0.1f; const float goalSpeed = (maxSpeed ) * (goalDist > brakeDist) + (curSpeed - decRate) * (goalDist <= brakeDist); if (goalDist > goalSpeed) { // update our velocity and heading so long as goal is still // further away than the distance we can cover in one frame // we must use a variable-size "dead zone" to avoid freezing // in mid-air or oscillation behavior at very close distances // NOTE: // wantedSpeed is a vector, so even aircraft with turnRate=0 // are coincidentally able to reach any goal by side-strafing wantedHeading = GetHeadingFromVector(goalVec.x, goalVec.z); wantedSpeed = (goalVec / goalDist) * goalSpeed; } else { // switch to hovering (if !CanLand())) if (flyState != FLY_ATTACKING) { ExecuteStop(); } } // redundant, done in Update() // UpdateHeading(); UpdateAirPhysics(); // Point toward goal or forward - unless we just passed it to get to another goal if ((flyState == FLY_ATTACKING) || (flyState == FLY_CIRCLING)) { goalVec = circlingPos - pos; } else { const bool b0 = (flyState != FLY_LANDING && (owner->commandAI->HasMoreMoveCommands())); const bool b1 = (goalDist < brakeDist && goalDist > 1.0f); if (b0 && b1) { goalVec = owner->frontdir; } else { goalVec = goalPos - pos; } } if (goalVec.SqLength2D() > 1.0f) { // update heading again in case goalVec changed wantedHeading = GetHeadingFromVector(goalVec.x, goalVec.z); } }
void CTAAirMoveType::Update() { //Handy stuff. Wonder if there is a better way? float3 &pos=owner->pos; SyncedFloat3 &rightdir = owner->rightdir; SyncedFloat3 &frontdir = owner->frontdir; SyncedFloat3 &updir = owner->updir; float3 &speed = owner->speed; //This is only set to false after the plane has finished constructing if (useHeading){ useHeading = false; SetState(AIRCRAFT_TAKEOFF); } //Allow us to stop if wanted if (wantToStop) ExecuteStop(); float3 lastSpeed = speed; if(owner->stunned){ wantedSpeed=ZeroVector; UpdateAirPhysics(); } else { #ifdef DIRECT_CONTROL_ALLOWED if(owner->directControl){ DirectControlStruct* dc=owner->directControl; SetState(AIRCRAFT_FLYING); float3 forward=dc->viewDir; float3 flatForward=forward; flatForward.y=0; flatForward.Normalize(); float3 right=forward.cross(UpVector); wantedSpeed=ZeroVector; if(dc->forward) wantedSpeed+=flatForward; if(dc->back) wantedSpeed-=flatForward; if(dc->right) wantedSpeed+=right; if(dc->left) wantedSpeed-=right; wantedSpeed.Normalize(); wantedSpeed*=maxSpeed; UpdateAirPhysics(); wantedHeading=GetHeadingFromVector(flatForward.x,flatForward.z); } else #endif { if(reservedPad){ CUnit* unit=reservedPad->unit; float3 relPos=unit->localmodel->GetPiecePos(reservedPad->piece); float3 pos=unit->pos + unit->frontdir*relPos.z + unit->updir*relPos.y + unit->rightdir*relPos.x; if(padStatus==0){ if(aircraftState!=AIRCRAFT_FLYING && aircraftState!=AIRCRAFT_TAKEOFF) SetState(AIRCRAFT_FLYING); goalPos=pos; if(pos.distance(owner->pos)<400){ padStatus=1; } //geometricObjects->AddLine(owner->pos,pos,1,0,1); } else if(padStatus==1){ if(aircraftState!=AIRCRAFT_FLYING) SetState(AIRCRAFT_FLYING); flyState=FLY_LANDING; goalPos=pos; reservedLandingPos=pos; wantedHeight=pos.y-ground->GetHeight(pos.x,pos.z); if(owner->pos.distance(pos)<3 || aircraftState==AIRCRAFT_LANDED){ padStatus=2; } //geometricObjects->AddLine(owner->pos,pos,10,0,1); } else { if(aircraftState!=AIRCRAFT_LANDED) SetState(AIRCRAFT_LANDED); owner->pos=pos; owner->AddBuildPower(unit->unitDef->buildSpeed/30,unit); owner->currentFuel = min (owner->unitDef->maxFuel, owner->currentFuel + (owner->unitDef->maxFuel / (GAME_SPEED * owner->unitDef->refuelTime))); if(owner->health>=owner->maxHealth-1 && owner->currentFuel >= owner->unitDef->maxFuel){ airBaseHandler->LeaveLandingPad(reservedPad); reservedPad=0; padStatus=0; goalPos=oldGoalPos; SetState(AIRCRAFT_TAKEOFF); } } } //Main state handling switch (aircraftState) { case AIRCRAFT_LANDED: UpdateLanded(); break; case AIRCRAFT_TAKEOFF: UpdateTakeoff(); break; case AIRCRAFT_FLYING: UpdateFlying(); break; case AIRCRAFT_LANDING: UpdateLanding(); break; case AIRCRAFT_HOVERING: UpdateHovering(); break; } } } deltaSpeed = speed - lastSpeed; deltaSpeed.y = 0; //Banking requires this //Turn and bank and move UpdateHeading(); UpdateBanking(aircraftState == AIRCRAFT_HOVERING); //updates dirs owner->midPos=pos+frontdir*owner->relMidPos.z + updir*owner->relMidPos.y + rightdir*owner->relMidPos.x; //Push other units out of the way if(pos!=oldpos && aircraftState!=AIRCRAFT_TAKEOFF && padStatus==0){ oldpos=pos; if(!dontCheckCol){ vector<CUnit*> nearUnits=qf->GetUnitsExact(pos,owner->radius+6); vector<CUnit*>::iterator ui; for(ui=nearUnits.begin();ui!=nearUnits.end();++ui){ if((*ui)->transporter) continue; float sqDist=(pos-(*ui)->pos).SqLength(); float totRad=owner->radius+(*ui)->radius; if(sqDist<totRad*totRad && sqDist!=0){ float dist=sqrt(sqDist); float3 dif=pos-(*ui)->pos; dif/=dist; if((*ui)->mass>=100000 || (*ui)->immobile){ pos-=dif*(dist-totRad); owner->midPos=pos+owner->frontdir*owner->relMidPos.z + owner->updir*owner->relMidPos.y + owner->rightdir*owner->relMidPos.x; owner->speed*=0.99f; // float damage=((*ui)->speed-owner->speed).SqLength(); //dont think they should take damage when they dont try to avoid it // owner->DoDamage(DamageArray()*damage,0,ZeroVector); // (*ui)->DoDamage(DamageArray()*damage,0,ZeroVector); } else { float part=owner->mass/(owner->mass+(*ui)->mass); pos-=dif*(dist-totRad)*(1-part); owner->midPos=pos+owner->frontdir*owner->relMidPos.z + owner->updir*owner->relMidPos.y + owner->rightdir*owner->relMidPos.x; CUnit* u=(CUnit*)(*ui); u->pos+=dif*(dist-totRad)*(part); u->midPos=u->pos+u->frontdir*u->relMidPos.z + u->updir*u->relMidPos.y + u->rightdir*u->relMidPos.x; float colSpeed=-owner->speed.dot(dif)+u->speed.dot(dif); owner->speed+=dif*colSpeed*(1-part); u->speed-=dif*colSpeed*(part); // float damage=(((*ui)->speed-owner->speed)*0.1f).SqLength(); // owner->DoDamage(DamageArray()*damage,0,ZeroVector); // (*ui)->DoDamage(DamageArray()*damage,0,ZeroVector); // owner->speed*=0.99f; } } } } if(pos.x<0){ pos.x+=0.6f; owner->midPos.x+=0.6f; } else if(pos.x>float3::maxxpos){ pos.x-=0.6f; owner->midPos.x-=0.6f; } if(pos.z<0){ pos.z+=0.6f; owner->midPos.z+=0.6f; }else if(pos.z>float3::maxzpos){ pos.z-=0.6f; owner->midPos.z-=0.6f; } } }
void CAirMoveType::Update(void) { float3& pos = owner->pos; // note: this is only set to false after // the plane has finished constructing if (useHeading) { useHeading = false; SetState(AIRCRAFT_TAKEOFF); } if (owner->stunned) { UpdateAirPhysics(0, lastAileronPos, lastElevatorPos, 0, ZeroVector); goto EndNormalControl; } if (owner->directControl && !(aircraftState == AIRCRAFT_CRASHING)) { SetState(AIRCRAFT_FLYING); DirectControlStruct* dc = owner->directControl; inefficientAttackTime = 0; if (dc->forward || dc->back || dc->left || dc->right) { float aileron = 0; float elevator = 0; if (dc->forward) elevator -= 1; if (dc->back) elevator += 1; if (dc->right) aileron += 1; if (dc->left) aileron -= 1; UpdateAirPhysics(0, aileron, elevator, 1, owner->frontdir); maneuver = 0; goto EndNormalControl; // bad } } if (reservedPad) { CUnit* unit = reservedPad->GetUnit(); float3 relPos = unit->script->GetPiecePos(reservedPad->GetPiece()); float3 pos = unit->pos + (unit->frontdir * relPos.z) + (unit->updir * relPos.y) + (unit->rightdir * relPos.x); if (padStatus == 0) { if (aircraftState != AIRCRAFT_FLYING && aircraftState != AIRCRAFT_TAKEOFF) { SetState(AIRCRAFT_FLYING); } goalPos = pos; if (pos.SqDistance2D(owner->pos) < (400*400)) { padStatus = 1; } } else if (padStatus == 1) { if (aircraftState != AIRCRAFT_LANDING) { SetState(AIRCRAFT_LANDING); } goalPos = pos; reservedLandingPos = pos; if (owner->pos.SqDistance(pos) < 9 || aircraftState == AIRCRAFT_LANDED) { padStatus = 2; } } else { if (aircraftState != AIRCRAFT_LANDED) { SetState(AIRCRAFT_LANDED); } owner->pos = pos; owner->AddBuildPower(unit->unitDef->buildSpeed / GAME_SPEED, unit); owner->currentFuel = std::min(owner->unitDef->maxFuel, owner->currentFuel + (owner->unitDef->maxFuel / (GAME_SPEED * owner->unitDef->refuelTime))); if (owner->health >= owner->maxHealth - 1 && owner->currentFuel >= owner->unitDef->maxFuel) { // repaired and filled up, leave the pad airBaseHandler->LeaveLandingPad(reservedPad); reservedPad = 0; padStatus = 0; goalPos = oldGoalPos; SetState(AIRCRAFT_TAKEOFF); } } } else if ((owner->unitDef->maxFuel > 0.0f && owner->currentFuel <= 0.0f) && padStatus == 0 && maxWantedSpeed > 0.0f) { // keep us in the air to reach our landing goalPos // (which is hopefully in the vicinity of a pad) SetState(AIRCRAFT_FLYING); } switch (aircraftState) { case AIRCRAFT_FLYING: { #ifdef DEBUG_AIRCRAFT GML_RECMUTEX_LOCK(sel); // Update if (selectedUnits.selectedUnits.find(this) != selectedUnits.selectedUnits.end()) { logOutput.Print("Flying %i %i %.1f %i", moveState, fireState, inefficientAttackTime, (int) isFighter); } #endif owner->restTime = 0; // somewhat hackish, but planes that have attack orders // while no pad is available would otherwise continue // attacking even if out of fuel bool continueAttack = (!reservedPad && ((owner->currentFuel > 0.0f) || owner->unitDef->maxFuel <= 0.0f)); if (continueAttack && ((owner->userTarget && !owner->userTarget->isDead) || owner->userAttackGround)) { inefficientAttackTime = std::min(inefficientAttackTime, float(gs->frameNum) - owner->lastFireWeapon); if (owner->userTarget) { goalPos = owner->userTarget->pos; } else { goalPos = owner->userAttackPos; } if (maneuver) { UpdateManeuver(); inefficientAttackTime = 0; } else if (isFighter && goalPos.SqDistance(pos) < Square(owner->maxRange * 4)) { inefficientAttackTime++; UpdateFighterAttack(); } else { inefficientAttackTime = 0; UpdateAttack(); } } else { inefficientAttackTime = 0; UpdateFlying(wantedHeight, 1); } } break; case AIRCRAFT_LANDED: inefficientAttackTime = 0; UpdateLanded(); break; case AIRCRAFT_LANDING: inefficientAttackTime = 0; UpdateLanding(); break; case AIRCRAFT_CRASHING: owner->crashing = true; UpdateAirPhysics(crashRudder, crashAileron, crashElevator, 0, owner->frontdir); new CSmokeProjectile(owner->midPos, gs->randVector() * 0.08f, 100 + gs->randFloat() * 50, 5, 0.2f, owner, 0.4f); if (!(gs->frameNum & 3) && std::max(0.f, ground->GetApproximateHeight(pos.x, pos.z)) + 5 + owner->radius > pos.y) owner->KillUnit(true, false, 0); break; case AIRCRAFT_TAKEOFF: UpdateTakeOff(wantedHeight); break; default: break; } EndNormalControl: // handle collisions if (pos != oldpos) { oldpos = pos; bool hitBuilding = false; if (collide && (aircraftState == AIRCRAFT_FLYING || aircraftState == AIRCRAFT_CRASHING)) { vector<CUnit*> nearUnits = qf->GetUnitsExact(pos, owner->radius + 6); vector<CUnit*>::iterator ui; for (ui = nearUnits.begin(); ui != nearUnits.end(); ++ui) { float sqDist = (pos - (*ui)->pos).SqLength(); float totRad = owner->radius + (*ui)->radius; if (sqDist < totRad * totRad && sqDist != 0) { float dist = sqrt(sqDist); float3 dif = pos - (*ui)->pos; if (dist > 0.0f) { dif /= dist; } if ((*ui)->immobile) { pos -= dif * (dist - totRad); owner->UpdateMidPos(); owner->speed *= 0.99f; float damage = (((*ui)->speed - owner->speed) * 0.1f).SqLength(); owner->DoDamage(DamageArray() * damage, 0, ZeroVector); (*ui)->DoDamage(DamageArray() * damage, 0, ZeroVector); hitBuilding = true; } else { float part = owner->mass / (owner->mass + (*ui)->mass); pos -= dif * (dist - totRad) * (1 - part); owner->UpdateMidPos(); CUnit* u = (CUnit*)(*ui); u->pos += dif * (dist - totRad) * (part); u->UpdateMidPos(); float damage = (((*ui)->speed - owner->speed) * 0.1f).SqLength(); owner->DoDamage(DamageArray() * damage, 0, ZeroVector); (*ui)->DoDamage(DamageArray() * damage, 0, ZeroVector); owner->speed *= 0.99f; } } } if (hitBuilding && owner->crashing) { // if our collision sphere overlapped with that // of a building and we're crashing, die right // now rather than waiting until we're close // enough to the ground (which may never happen // if eg. we're going down over a crowded field // of windmills due to col-det) owner->KillUnit(true, false, 0); return; } } if (pos.x < 0) { pos.x += 1.5f; owner->midPos.x += 1.5f; } else if (pos.x > float3::maxxpos) { pos.x -= 1.5f; owner->midPos.x -= 1.5f; } if (pos.z < 0) { pos.z += 1.5f; owner->midPos.z += 1.5f; } else if (pos.z > float3::maxzpos) { pos.z -= 1.5f; owner->midPos.z -= 1.5f; } } #ifdef DEBUG_AIRCRAFT if (lastColWarningType == 1) { int g = geometricObjects->AddLine(owner->pos, lastColWarning->pos, 10, 1, 1); geometricObjects->SetColor(g, 0.2f, 1, 0.2f, 0.6f); } else if (lastColWarningType == 2) { int g = geometricObjects->AddLine(owner->pos, lastColWarning->pos, 10, 1, 1); if (owner->frontdir.dot(lastColWarning->midPos + lastColWarning->speed * 20 - owner->midPos - owner->speed * 20) < 0) geometricObjects->SetColor(g, 1, 0.2f, 0.2f, 0.6f); else geometricObjects->SetColor(g, 1, 1, 0.2f, 0.6f); } #endif }
bool CHoverAirMoveType::Update() { float3& pos = owner->pos; float3& speed = owner->speed; AAirMoveType::Update(); if (owner->stunned || owner->beingBuilt) { wantedSpeed = ZeroVector; wantToStop = true; } // Allow us to stop if wanted if (wantToStop) { ExecuteStop(); } const float3 lastSpeed = speed; if (owner->fpsControlPlayer != NULL) { SetState(AIRCRAFT_FLYING); const FPSUnitController& con = owner->fpsControlPlayer->fpsController; const float3 forward = con.viewDir; const float3 right = forward.cross(UpVector); const float3 nextPos = pos + speed; float3 flatForward = forward; flatForward.y = 0.0f; flatForward.Normalize(); wantedSpeed = ZeroVector; if (con.forward) wantedSpeed += flatForward; if (con.back ) wantedSpeed -= flatForward; if (con.right ) wantedSpeed += right; if (con.left ) wantedSpeed -= right; wantedSpeed.Normalize(); wantedSpeed *= maxSpeed; if (!nextPos.IsInBounds()) { speed = ZeroVector; } UpdateAirPhysics(); wantedHeading = GetHeadingFromVector(flatForward.x, flatForward.z); } else { if (reservedPad != NULL) { MoveToRepairPad(); if (padStatus >= 1) { flyState = FLY_LANDING; } } // Main state handling switch (aircraftState) { case AIRCRAFT_LANDED: UpdateLanded(); break; case AIRCRAFT_TAKEOFF: UpdateTakeoff(); break; case AIRCRAFT_FLYING: UpdateFlying(); break; case AIRCRAFT_LANDING: UpdateLanding(); break; case AIRCRAFT_HOVERING: UpdateHovering(); break; case AIRCRAFT_CRASHING: break; } } // Banking requires deltaSpeed.y = 0 deltaSpeed = speed - lastSpeed; deltaSpeed.y = 0.0f; // Turn and bank and move; update dirs UpdateHeading(); UpdateBanking(aircraftState == AIRCRAFT_HOVERING); return (HandleCollisions()); }
void CHoverAirMoveType::UpdateFlying() { const float3& pos = owner->pos; const float3& speed = owner->speed; // Direction to where we would like to be float3 goalVec = goalPos - pos; owner->restTime = 0; // don't change direction for waypoints we just flew over and missed slightly if (flyState != FLY_LANDING && owner->commandAI->HasMoreMoveCommands()) { float3 goalDir = goalVec; if ((goalDir != ZeroVector) && (goalDir.UnsafeANormalize()).SqDistance(goalVec) < 1.0f) { goalVec = owner->frontdir; } } const float goalDistSq2D = goalVec.SqLength2D(); const float gHeight = UseSmoothMesh()? std::max(smoothGround->GetHeight(pos.x, pos.z), ground->GetApproximateHeight(pos.x, pos.z)): ground->GetHeightAboveWater(pos.x, pos.z); const bool closeToGoal = (flyState == FLY_ATTACKING)? (goalDistSq2D < ( 400.0f)): (goalDistSq2D < (maxDrift * maxDrift)) && (math::fabs(gHeight - pos.y + wantedHeight) < maxDrift); if (closeToGoal) { switch (flyState) { case FLY_CRUISING: { const bool hasMoreMoveCmds = owner->commandAI->HasMoreMoveCommands(); const bool noland = dontLand || !autoLand || hasMoreMoveCmds; // NOTE: should CMD_LOAD_ONTO be here? const bool trans = (dynamic_cast<CTransportUnit*>(owner) != NULL); const bool hasLoadCmds = trans && !owner->commandAI->commandQue.empty() && (owner->commandAI->commandQue.front().GetID() == CMD_LOAD_ONTO || owner->commandAI->commandQue.front().GetID() == CMD_LOAD_UNITS); // [?] transport aircraft need some time to detect that they can pickup const bool canLoad = trans && (++waitCounter < ((GAME_SPEED << 1) - 5)); if (noland || (canLoad && hasLoadCmds)) { if (trans) { wantedSpeed = ZeroVector; SetState(AIRCRAFT_HOVERING); if (waitCounter > (GAME_SPEED << 1)) { wantedHeight = orgWantedHeight; } } else { wantedSpeed = ZeroVector; if (!hasMoreMoveCmds) { wantToStop = true; SetState(AIRCRAFT_HOVERING); } } } else { wantedHeight = orgWantedHeight; SetState(AIRCRAFT_LANDING); } return; } case FLY_CIRCLING: // break; if ((++waitCounter) > ((GAME_SPEED * 3) + 10)) { if (airStrafe) { float3 relPos = pos - circlingPos; if (relPos.x < 0.0001f && relPos.x > -0.0001f) { relPos.x = 0.0001f; } relPos.y = 0.0f; relPos.Normalize(); static CMatrix44f rot(0.0f,fastmath::PI/4.0f,0.0f); float3 newPos = rot.Mul(relPos); // Make sure the point is on the circle newPos = newPos * goalDistance; // Go there in a straight line goalPos = circlingPos + newPos; } waitCounter = 0; } break; case FLY_ATTACKING: { if (airStrafe) { float3 relPos = pos - circlingPos; if (relPos.x < 0.0001f && relPos.x > -0.0001f) { relPos.x = 0.0001f; } relPos.y = 0; relPos.Normalize(); CMatrix44f rot; if (gs->randFloat() > 0.5f) { rot.RotateY(0.6f + gs->randFloat() * 0.6f); } else { rot.RotateY(-(0.6f + gs->randFloat() * 0.6f)); } float3 newPos = rot.Mul(relPos); newPos = newPos * goalDistance; // Go there in a straight line goalPos = circlingPos + newPos; } break; } case FLY_LANDING: { break; } } } // not there yet, so keep going goalVec.y = 0.0f; // if we are close to our goal and not in attack mode, // we should go slow enough to be able to break in time const float goalDist = goalVec.Length() + 0.1f; const float approachSpeed = (flyState != FLY_ATTACKING && goalDist < brakeDistance)? (goalDist / (speed.Length2D() + 0.01f) * decRate): maxSpeed; wantedSpeed = (goalVec / goalDist) * approachSpeed; UpdateAirPhysics(); // Point toward goal or forward - unless we just passed it to get to another goal if ((flyState == FLY_ATTACKING) || (flyState == FLY_CIRCLING)) { goalVec = circlingPos - pos; } else { const bool b0 = (flyState != FLY_LANDING && (owner->commandAI->HasMoreMoveCommands())); const bool b1 = (goalDist < 120.0f) && ((goalVec.SafeNormalize()).SqDistance(goalVec) > 1.0f); if (b0 && b1) { goalVec = owner->frontdir; } else { goalVec = goalPos - pos; } } if (goalVec.SqLength2D() > 1.0f) { wantedHeading = GetHeadingFromVector(goalVec.x, goalVec.z); } }
void CAirMoveType::UpdateManeuver(void) { #ifdef DEBUG_AIRCRAFT GML_RECMUTEX_LOCK(sel); // UpdateManuever if (selectedUnits.selectedUnits.find(this) != selectedUnits.selectedUnits.end()) { logOutput.Print("UpdataMan %i %i", maneuver, maneuverSubState); } #endif float speedf = owner->speed.Length(); switch (maneuver) { case 1: { // Immelman int aileron = 0, elevator = 0; if (owner->updir.y > 0.0f) { if (owner->rightdir.y > maxAileron * speedf) { aileron = 1; } else if (owner->rightdir.y < -maxAileron * speedf) { aileron = -1; } } if (fabs(owner->rightdir.y) < maxAileron * 3.0f * speedf || owner->updir.y < 0.0f) elevator = 1; UpdateAirPhysics(0, aileron, elevator, 1, owner->frontdir); if ((owner->updir.y < 0.0f && owner->frontdir.y < 0.0f) || speedf < 0.8f) maneuver = 0; // some seem to report that the "unlimited altitude" thing is because of these maneuvers if (owner->pos.y - ground->GetApproximateHeight(owner->pos.x, owner->pos.z) > wantedHeight * 4.0f) maneuver = 0; break; } case 2: { // inverted Immelman int aileron = 0, elevator = 0; if (maneuverSubState == 0) { if (owner->rightdir.y >= 0.0f) { aileron = -1; } else { aileron = 1; } } if (owner->frontdir.y < -0.7f) maneuverSubState = 1; if (maneuverSubState == 1 || owner->updir.y < 0.0f) elevator = 1; UpdateAirPhysics(0, aileron, elevator, 1, owner->frontdir); if ((owner->updir.y > 0.0f && owner->frontdir.y > 0.0f && maneuverSubState == 1) || speedf < 0.2f) maneuver = 0; break; } default: UpdateAirPhysics(0, 0, 0, 1, owner->frontdir); maneuver = 0; break; } }
void CTAAirMoveType::UpdateLanding() { float3& pos = owner->pos; float3& speed = owner->speed; // We want to land, and therefore cancel our speed first wantedSpeed = ZeroVector; waitCounter++; // Hang around for a while so queued commands have a chance to take effect if (waitCounter < 30) { UpdateAirPhysics(); return; } if (reservedLandingPos.x < 0) { if (CanLandAt(pos)) { // found a landing spot reservedLandingPos = pos; goalPos = pos; owner->physicalState = CSolidObject::OnGround; owner->Block(); owner->physicalState = CSolidObject::Flying; owner->Deactivate(); owner->script->StopMoving(); } else { if (goalPos.SqDistance2D(pos) < 900) { goalPos = goalPos + gs->randVector() * 300; goalPos.CheckInBounds(); } flyState = FLY_LANDING; UpdateFlying(); return; } } // We should wait until we actually have stopped smoothly if (speed.SqLength2D() > 1.0f) { UpdateFlying(); return; } // We have stopped, time to land const float gah = ground->GetApproximateHeight(pos.x, pos.z); float h = 0.0f; // if aircraft submergible and above water we want height of ocean floor if ((owner->unitDef->canSubmerge) && (gah < 0.0f)) { h = pos.y - gah; wantedHeight = gah; } else { h = pos.y - ground->GetHeightAboveWater(pos.x, pos.z); wantedHeight = -2.0; } UpdateAirPhysics(); if (h <= 0) { SetState(AIRCRAFT_LANDED); pos.y = gah; } }
void CAirMoveType::UpdateFighterAttack(void) { float3 &pos = owner->pos; SyncedFloat3 &rightdir = owner->rightdir; SyncedFloat3 &frontdir = owner->frontdir; SyncedFloat3 &updir = owner->updir; float3 &speed = owner->speed; float speedf = owner->speed.Length(); if (speedf < 0.01f) { UpdateAirPhysics(0, 0, 0, 1, owner->frontdir); return; } if (!((gs->frameNum + owner->id) & 3)) CheckForCollision(); bool groundTarget = !owner->userTarget || !owner->userTarget->unitDef->canfly || owner->userTarget->unitDef->hoverAttack; bool airTarget = owner->userTarget && owner->userTarget->unitDef->canfly && !owner->userTarget->unitDef->hoverAttack; //only "real" aircrafts (non gunship) if (groundTarget) { if (frontdir.dot(goalPos - pos) < 0 && (pos - goalPos).SqLength() < turnRadius * turnRadius * (loopbackAttack ? 4 : 1)) { float3 dif = pos - goalPos; dif.y = 0; dif.Normalize(); goalPos = goalPos + dif * turnRadius * 4; } else if (loopbackAttack && !airTarget) { bool hasFired = false; if (!owner->weapons.empty() && owner->weapons[0]->reloadStatus > gs->frameNum && owner->weapons[0]->salvoLeft == 0) hasFired = true; if (frontdir.dot(goalPos - pos) < owner->maxRange * (hasFired ? 1.0f : 0.7f)) maneuver = 1; } else if (frontdir.dot(goalPos - pos) < owner->maxRange * 0.7f) { goalPos += exitVector * (owner->userTarget ? owner->userTarget->radius + owner->radius + 10 : owner->radius + 40); } } float3 tgp = goalPos + (goalPos - oldGoalPos) * 8; oldGoalPos = goalPos; goalPos = tgp; float goalLength = (goalPos - pos).Length(); float3 goalDir = (goalLength > 0.0f)? (goalPos - pos) / goalLength: ZeroVector; float aileron = 0; float rudder = 0; float elevator = 0; float engine = 0; float gHeight = ground->GetHeight(pos.x, pos.z); float goalDotRight = rightdir.dot(goalDir); float goalDotFront = goalDir.dot(frontdir) * 0.5f + 0.501f; if (goalDotFront != 0.0f) { goalDotRight /= goalDotFront; } if (goalDir.dot(frontdir) < -0.2f + inefficientAttackTime * 0.002f && frontdir.y > -0.2f && speedf > 2.0f && gs->randFloat() > 0.996f) maneuver = 1; if (goalDir.dot(frontdir) < -0.2f + inefficientAttackTime * 0.002f && fabs(frontdir.y) < 0.2f && gs->randFloat() > 0.996f && gHeight + 400 < pos.y) { maneuver = 2; maneuverSubState = 0; } // roll if (speedf > 0.45f && pos.y + owner->speed.y * 60 * fabs(frontdir.y) + std::min(0.0f, float(updir.y)) * 150 > gHeight + 60 + fabs(rightdir.y) * 150) { float goalBankDif = goalDotRight + rightdir.y * 0.2f; if (goalBankDif > maxAileron * speedf * 4.0f) { aileron = 1; } else if (goalBankDif < -maxAileron * speedf * 4.0f) { aileron = -1; } else { aileron = goalBankDif / (maxAileron * speedf * 4.0f); } } else { if (rightdir.y > 0.0f) { if (rightdir.y > maxAileron * speedf || frontdir.y < -0.7f) { aileron = 1; } else { if (speedf > 0.0f) { aileron = rightdir.y / (maxAileron * speedf); } } } else { if (rightdir.y < -maxAileron * speedf || frontdir.y < -0.7f) { aileron = -1; } else { if (speedf > 0.0f) { aileron = rightdir.y / (maxAileron * speedf); } } } } // yaw if (pos.y > gHeight + 30) { if (goalDotRight < -maxRudder * speedf) { rudder = -1; } else if (goalDotRight > maxRudder * speedf) { rudder = 1; } else { if (speedf > 0.0f) { rudder = goalDotRight / (maxRudder * speedf); } } } float upside = 1; if (updir.y < -0.3f) upside = -1; // pitch if (speedf < 1.5f) { if (frontdir.y < 0.0f) { elevator = upside; } else if (frontdir.y > 0.0f) { elevator = -upside; } } else { float gHeight2 = ground->GetHeight(pos.x + speed.x * 40, pos.z + speed.z * 40); float hdif = std::max(gHeight, gHeight2) + 60 - pos.y - frontdir.y * speedf * 20; float minPitch = 1.0f; // min(1.0f, hdif / (maxElevator * speedf * speedf * 20)); if (hdif < -(maxElevator * speedf * speedf * 20)) { minPitch = -1; } else if (hdif > (maxElevator * speedf * speedf * 20)) { minPitch = 1; } else { minPitch = hdif / (maxElevator * speedf * speedf * 20); } // } else { if (lastColWarning && lastColWarningType == 2 && frontdir.dot(lastColWarning->pos + lastColWarning->speed * 20 - pos-owner->speed * 20) < 0) { /* float pitchMod = (updir.y > 0.0f)? 1: -1; if (lastColWarning->pos.y > pos.y) elevator = -pitchMod; else elevator = pitchMod; */ elevator = (updir.dot(lastColWarning->midPos - owner->midPos) > 0.0f)? -1 : 1; } else { float hdif = goalDir.dot(updir); if (hdif < -maxElevator * speedf) { elevator = -1; } else if (hdif > maxElevator * speedf) { elevator = 1; } else { elevator = hdif / (maxElevator * speedf); } } if (elevator * upside < minPitch) elevator = minPitch * upside; } #ifdef DEBUG_AIRCRAFT GML_RECMUTEX_LOCK(sel); // UpdateFighterAttack if (selectedUnits.selectedUnits.find(this) != selectedUnits.selectedUnits.end()){ logOutput.Print("FAttack %.1f %.1f %.2f", pos.y - gHeight, goalLength, goalDir.dot(frontdir)); } #endif if (groundTarget) engine = 1; else engine = std::min(1.f, (float)(goalLength / owner->maxRange + 1 - goalDir.dot(frontdir) * 0.7f)); UpdateAirPhysics(rudder, aileron, elevator, engine, owner->frontdir); }
void CAirMoveType::UpdateFlying(float wantedHeight,float engine) { float3 &pos = owner->pos; float3 &rightdir = owner->rightdir; float3 &frontdir = owner->frontdir; float3 &updir = owner->updir; float3 &speed = owner->speed; float speedf=speed.Length(); float goalLength=(goalPos-pos).Length(); float3 goalDir=(goalPos-pos)/goalLength; goalDir.Normalize(); float aileron=0; float rudder=0; float elevator=0; float gHeight=ground->GetHeight(pos.x,pos.z); if(!((gs->frameNum+owner->id)&3)) CheckForCollision(); float otherThreat=0; float3 otherDir; if(lastColWarning){ float3 otherDif=lastColWarning->pos-pos; float otherLength=otherDif.Length(); otherDir=otherDif/otherLength; otherThreat=max(1200.f,goalLength)/otherLength*0.036; } float goalDot=rightdir.dot(goalDir); goalDot/=goalDir.dot(frontdir)*0.5+0.501; if(goalDir.dot(frontdir)<-0.1 && goalLength<turnRadius #ifdef DIRECT_CONTROL_ALLOWED && (!owner->directControl || owner->directControl->mouse2) #endif ) goalDot=-goalDot; if(lastColWarning){ goalDot-=otherDir.dot(rightdir)*otherThreat; } //roll if(speedf>1.5 && pos.y+speed.y*10>gHeight+wantedHeight*0.6){ float goalBankDif=goalDot+rightdir.y*0.5; if(goalBankDif>maxAileron*speedf*4 && rightdir.y>-maxBank){ aileron=1; } else if(goalBankDif<-maxAileron*speedf*4 && rightdir.y<maxBank){ aileron=-1; } else { if(fabs(rightdir.y)<maxBank) aileron=goalBankDif/(maxAileron*speedf*4); else { if(rightdir.y<0 && goalBankDif<0) aileron=-1; else if(rightdir.y>0 && goalBankDif>0) aileron=1; } } } else { if(rightdir.y>0.01){ aileron=1; } else if(rightdir.y<-0.01){ aileron=-1; } } //yaw if(pos.y>gHeight+15){ if(goalDot<-maxRudder*speedf*2){ rudder=-1;; } else if(goalDot>maxRudder*speedf*2){ rudder=1; } else { rudder=goalDot/(maxRudder*speedf*2); } } //pitch if(speedf>0.8){ if(lastColWarningType==2 && frontdir.dot(lastColWarning->midPos+lastColWarning->speed*20 - owner->midPos - owner->speed*20)<0){ /* float pitchMod=updir.y>0?1:-1; if(lastColWarning->pos.y>pos.y) elevator=-pitchMod; else elevator=pitchMod; /*/ elevator=updir.dot(lastColWarning->midPos-owner->midPos)>0?-1:1;/**/ } else { float gHeight2=ground->GetHeight(pos.x+speed.x*40,pos.z+speed.z*40); float hdif=max(gHeight,gHeight2)+wantedHeight-pos.y-frontdir.y*speedf*20; if(hdif<-(maxElevator*speedf*speedf*20) && frontdir.y>-maxPitch){ elevator=-1; } else if(hdif>(maxElevator*speedf*speedf*20) && frontdir.y<maxPitch){ elevator=1; } else { if(fabs(frontdir.y)<maxPitch) elevator=hdif/(maxElevator*speedf*speedf*20); } } } else { if(frontdir.y<-0.1){ elevator=1; } else if(frontdir.y>0.15){ elevator=-1; } } UpdateAirPhysics(rudder,aileron,elevator,engine,owner->frontdir); }
void CAirMoveType::UpdateFighterAttack(void) { float3 &pos = owner->pos; float3 &rightdir = owner->rightdir; float3 &frontdir = owner->frontdir; float3 &updir = owner->updir; float3 &speed = owner->speed; float speedf=owner->speed.Length(); if(speedf<0.01){ UpdateAirPhysics(0,0,0,1,owner->frontdir); return; } if(!((gs->frameNum+owner->id)&3)) CheckForCollision(); bool groundTarget=!owner->userTarget || !owner->userTarget->unitDef->canfly; if(groundTarget){ if(frontdir.dot(goalPos-pos)<0 && (pos-goalPos).SqLength()<turnRadius*turnRadius){ float3 dif=pos-goalPos; dif.y=0; dif.Normalize(); goalPos=goalPos+dif*turnRadius*4; } else if(frontdir.dot(goalPos-pos)<owner->maxRange*0.7){ goalPos+=exitVector*(owner->userTarget?owner->userTarget->radius+owner->radius+10:owner->radius+40); } } float3 tgp=goalPos+(goalPos-oldGoalPos)*8; oldGoalPos=goalPos; goalPos=tgp; float goalLength=(goalPos-pos).Length(); float3 goalDir=(goalPos-pos)/goalLength; float aileron=0; float rudder=0; float elevator=0; float engine=0; float gHeight=ground->GetHeight(pos.x,pos.z); float goalDot=rightdir.dot(goalDir); goalDot/=goalDir.dot(frontdir)*0.5+0.501; if(goalDir.dot(frontdir)<-0.2+inefficientAttackTime*0.002 && frontdir.y>-0.2 && speedf>2.0 && gs->randFloat()>0.996) maneuver=1; if(goalDir.dot(frontdir)<-0.2+inefficientAttackTime*0.002 && fabs(frontdir.y)<0.2 && gs->randFloat()>0.996 && gHeight+400<pos.y){ maneuver=2; maneuverSubState=0; } //roll if(speedf>0.45 && pos.y+owner->speed.y*60*fabs(frontdir.y)+min(0.f,updir.y)*150>gHeight+60+fabs(rightdir.y)*150){ float goalBankDif=goalDot+rightdir.y*0.2; if(goalBankDif>maxAileron*speedf*4){ aileron=1; } else if(goalBankDif<-maxAileron*speedf*4){ aileron=-1; } else { aileron=goalBankDif/(maxAileron*speedf*4); } } else { if(rightdir.y>0){ if(rightdir.y>maxAileron*speedf || frontdir.y<-0.7) aileron=1; else aileron=rightdir.y/(maxAileron*speedf); } else { if(rightdir.y<-maxAileron*speedf || frontdir.y<-0.7) aileron=-1; else aileron=rightdir.y/(maxAileron*speedf); } } //yaw if(pos.y>gHeight+30){ if(goalDot<-maxRudder*speedf){ rudder=-1; } else if(goalDot>maxRudder*speedf){ rudder=1; } else { rudder=goalDot/(maxRudder*speedf); } } float upside=1; if(updir.y<-0.3) upside=-1; //pitch if(speedf<1.5){ if(frontdir.y<0.0){ elevator=upside; } else if(frontdir.y>0.0){ elevator=-upside; } } else { float gHeight2=ground->GetHeight(pos.x+speed.x*40,pos.z+speed.z*40); float hdif=max(gHeight,gHeight2)+60-pos.y-frontdir.y*speedf*20; float minPitch;//=min(1.0f,hdif/(maxElevator*speedf*speedf*20)); if(hdif<-(maxElevator*speedf*speedf*20)){ minPitch=-1; } else if(hdif>(maxElevator*speedf*speedf*20)){ minPitch=1; } else { minPitch=hdif/(maxElevator*speedf*speedf*20); } /* if(pos.y+min(0,owner->speed.y)*70*fabs(frontdir.y)+min(0,updir.y)*50<gHeight+50){ if(frontdir.y<0.5){ elevator=upside; } else if(frontdir.y>0.55){ elevator=-upside; }*/ // } else { if(lastColWarningType==2 && frontdir.dot(lastColWarning->pos+lastColWarning->speed*20-pos-owner->speed*20)<0){ /* float pitchMod=updir.y>0?1:-1; if(lastColWarning->pos.y>pos.y) elevator=-pitchMod; else elevator=pitchMod; /*/ elevator=updir.dot(lastColWarning->midPos-owner->midPos)>0?-1:1;/**/ } else { float hdif=goalDir.dot(updir); if(hdif<-maxElevator*speedf){ elevator=-1; } else if(hdif>maxElevator*speedf){ elevator=1; } else { elevator=hdif/(maxElevator*speedf); } } if(elevator*upside<minPitch) elevator=minPitch*upside; } #ifdef DEBUG_AIRCRAFT if(selectedUnits.selectedUnits.find(this)!=selectedUnits.selectedUnits.end()){ info->AddLine("FAttack %.1f %.1f %.2f",pos.y-gHeight,goalLength,goalDir.dot(frontdir)); } #endif if(groundTarget) engine=1; else engine=min(1.f,(float)(goalLength/owner->maxRange+1-goalDir.dot(frontdir)*0.7)); UpdateAirPhysics(rudder,aileron,elevator,engine,owner->frontdir); /* std::vector<CWeapon*>::iterator wi; for(wi=owner->weapons.begin();wi!=owner->weapons.end();++wi){ (*wi)->targetPos=goalPos; if(owner->userTarget){ (*wi)->AttackUnit(owner->userTarget,true); } }*/ /* DrawLine dl; dl.color=UpVector; dl.pos1=pos; dl.pos2=goalPos; lines.push_back(dl); dl.color=float3(1,0,0); dl.pos1=pos; dl.pos2=pos+frontdir*maxRange; lines.push_back(dl);/**/ }
void CAirMoveType::UpdateFlying(float wantedHeight, float engine) { float3& pos = owner->pos; SyncedFloat3& rightdir = owner->rightdir; SyncedFloat3& frontdir = owner->frontdir; SyncedFloat3& updir = owner->updir; float3& speed = owner->speed; float speedf = speed.Length(); float3 goalDir = (goalPos - pos); float goalLength = std::max(0.001f, goalDir.Length2D()); goalDir /= goalLength; float3 adjustedGoalDir = float3(goalPos.x, 0, goalPos.z) - float3(pos.x, 0, pos.z); adjustedGoalDir.SafeANormalize(); float aileron = 0.0f; float rudder = 0.0f; float elevator = 0.0f; // do not check if the plane can be submerged here, since it'll cause // ground collisions later on float gHeight = ground->GetHeight(pos.x, pos.z); if (!((gs->frameNum + owner->id) & 3)) CheckForCollision(); float otherThreat = 0.0f; float3 otherDir; if (lastColWarning) { float3 otherDif = lastColWarning->pos - pos; float otherLength = otherDif.Length(); otherDir = (otherLength > 0.0f)? (otherDif / otherLength): ZeroVector; otherThreat = (otherLength > 0.0f)? std::max(1200.0f, goalLength) / otherLength * 0.036f: 0.0f; } float goalDotRight = rightdir.dot(adjustedGoalDir); float goalDotFront = adjustedGoalDir.dot(frontdir) * 0.5f + 0.501f; if (goalDotFront > 0.01f) { goalDotRight /= goalDotFront; } if (adjustedGoalDir.dot(frontdir) < -0.1f && goalLength < turnRadius && (!owner->directControl || owner->directControl->mouse2)) goalDotRight = -goalDotRight; if (lastColWarning) { goalDotRight -= otherDir.dot(rightdir) * otherThreat; } // roll if (speedf > 1.5f && pos.y + speed.y * 10 > gHeight + wantedHeight * 0.6f) { float goalBankDif = goalDotRight + rightdir.y * 0.5f; if (goalBankDif > maxAileron*speedf * 4 && rightdir.y > -maxBank) { aileron = 1; } else if (goalBankDif < -maxAileron * speedf * 4 && rightdir.y < maxBank) { aileron = -1; } else { if (fabs(rightdir.y) < maxBank) { aileron = goalBankDif / (maxAileron * speedf * 4); } else { if (rightdir.y < 0.0f && goalBankDif < 0.0f) { aileron = -1; } else if (rightdir.y > 0.0f && goalBankDif > 0.0f) { aileron = 1; } } } } else { if (rightdir.y > 0.01f) { aileron = 1; } else if (rightdir.y < -0.01f) { aileron = -1; } } // yaw if (pos.y > gHeight + 15) { if (goalDotRight < -maxRudder * speedf * 2) { rudder = -1; } else if (goalDotRight > maxRudder * speedf * 2) { rudder = 1; } else { if (speedf > 0.0f && maxRudder > 0.0f) { rudder = goalDotRight / (maxRudder * speedf * 2); } else { rudder = 0; } } } // pitch if (speedf > 0.8f) { bool notColliding = true; if (lastColWarningType == 2) { const float3 dir = lastColWarning->midPos - owner->midPos; const float3 sdir = lastColWarning->speed - owner->speed; if (frontdir.dot(dir + sdir * 20) < 0) { elevator = updir.dot(dir) > 0 ? -1 : 1; notColliding = false; } } if (notColliding) { float gHeight2 = ground->GetHeight(pos.x + speed.x * 40, pos.z + speed.z * 40); float hdif = std::max(gHeight, gHeight2) + wantedHeight - pos.y - frontdir.y * speedf * 20; if (hdif < -(maxElevator * speedf * speedf * 20) && frontdir.y > -maxPitch) { elevator = -1; } else if (hdif > (maxElevator * speedf * speedf * 20) && frontdir.y < maxPitch) { elevator = 1; } else { if (fabs(frontdir.y) < maxPitch) elevator = hdif / (maxElevator * speedf * speedf * 20); } } } else { if (frontdir.y < -0.1f) { elevator = 1; } else if (frontdir.y > 0.15f) { elevator = -1; } } UpdateAirPhysics(rudder, aileron, elevator, engine, owner->frontdir); }
void CTAAirMoveType::UpdateFlying() { float3 &pos = owner->pos; float3 &speed = owner->speed; // Direction to where we would like to be float3 dir = goalPos - pos; owner->restTime = 0; // don't change direction for waypoints we just flew over and missed slightly if (flyState != FLY_LANDING && owner->commandAI->HasMoreMoveCommands() && dir != ZeroVector && dir.SqLength2D() < 10000.0f) { float3 ndir = dir; ndir = ndir.UnsafeANormalize(); if (ndir.SqDistance(dir) < 1.0f) { dir = owner->frontdir; } } const float gHeight = UseSmoothMesh()? std::max(smoothGround->GetHeight(pos.x, pos.z), ground->GetApproximateHeight(pos.x, pos.z)): ground->GetHeightAboveWater(pos.x, pos.z); // are we there yet? bool closeToGoal = (dir.SqLength2D() < maxDrift * maxDrift) && (fabs(gHeight - pos.y + wantedHeight) < maxDrift); if (flyState == FLY_ATTACKING) { closeToGoal = (dir.SqLength2D() < 400); } if (closeToGoal) { // pretty close switch (flyState) { case FLY_CRUISING: { bool trans = dynamic_cast<CTransportUnit*>(owner); bool noland = dontLand || !autoLand; // should CMD_LOAD_ONTO be here? bool hasLoadCmds = trans && !owner->commandAI->commandQue.empty() && (owner->commandAI->commandQue.front().id == CMD_LOAD_ONTO || owner->commandAI->commandQue.front().id == CMD_LOAD_UNITS); if (noland || (trans && ++waitCounter < 55 && hasLoadCmds)) { // transport aircraft need some time to detect that they can pickup if (trans) { wantedSpeed = ZeroVector; SetState(AIRCRAFT_HOVERING); if (waitCounter > 60) { wantedHeight = orgWantedHeight; } } else { wantedSpeed = ZeroVector; if (!owner->commandAI->HasMoreMoveCommands()) wantToStop = true; SetState(AIRCRAFT_HOVERING); } } else { wantedHeight = orgWantedHeight; SetState(AIRCRAFT_LANDING); } return; } case FLY_CIRCLING: // break; waitCounter++; if (waitCounter > 100) { if (owner->unitDef->airStrafe) { float3 relPos = pos - circlingPos; if (relPos.x < 0.0001f && relPos.x > -0.0001f) { relPos.x = 0.0001f; } relPos.y = 0.0f; relPos.Normalize(); static CMatrix44f rot(0.0f,fastmath::PI/4.0f,0.0f); float3 newPos = rot.Mul(relPos); // Make sure the point is on the circle newPos = newPos * goalDistance; // Go there in a straight line goalPos = circlingPos + newPos; } waitCounter = 0; } break; case FLY_ATTACKING: { if (owner->unitDef->airStrafe) { float3 relPos = pos - circlingPos; if (relPos.x < 0.0001f && relPos.x > -0.0001f) { relPos.x = 0.0001f; } relPos.y = 0; relPos.Normalize(); CMatrix44f rot; if (gs->randFloat() > 0.5f) { rot.RotateY(0.6f + gs->randFloat() * 0.6f); } else { rot.RotateY(-(0.6f + gs->randFloat() * 0.6f)); } float3 newPos = rot.Mul(relPos); newPos = newPos * goalDistance; // Go there in a straight line goalPos = circlingPos + newPos; } break; } case FLY_LANDING: { break; } } } // not there yet, so keep going dir.y = 0; float realMax = maxSpeed; float dist = dir.Length() + 0.1f; // If we are close to our goal, we should go slow enough to be able to break in time // new additional rule: if in attack mode or if we have more move orders then this is // an intermediate waypoint, don't slow down (FIXME) if (flyState != FLY_ATTACKING && dist < brakeDistance) { realMax = dist / (speed.Length2D() + 0.01f) * decRate; } wantedSpeed = (dir / dist) * realMax; UpdateAirPhysics(); // Point toward goal or forward - unless we just passed it to get to another goal if ((flyState == FLY_ATTACKING) || (flyState == FLY_CIRCLING)) { dir = circlingPos - pos; } else if (flyState != FLY_LANDING && (owner->commandAI->HasMoreMoveCommands() && dist < 120) && (goalPos - pos).Normalize().SqDistance(dir) > 1) { dir = owner->frontdir; } else { dir = goalPos - pos; } if (dir.SqLength2D() > 1) { const int h = GetHeadingFromVector(dir.x, dir.z); wantedHeading = (h == 0)? wantedHeading : h; } }
void CTAAirMoveType::UpdateFlying() { float3 &pos = owner->pos; float3 &speed = owner->speed; // Direction to where we would like to be float3 dir = goalPos - pos; owner->restTime = 0; // don't change direction for waypoints we just flew over and missed slightly if (flyState != FLY_LANDING && (owner->commandAI->HasMoreMoveCommands() && dir.Length2D() < 100) && (goalPos - pos).Normalize().distance(dir) < 1) { dir = owner->frontdir; } // are we there yet? bool closeToGoal = (dir.SqLength2D() < maxDrift * maxDrift) && (fabs(ground->GetHeight(pos.x, pos.z) - pos.y + wantedHeight) < maxDrift); if (flyState == FLY_ATTACKING) closeToGoal = (dir.SqLength2D() < 400); if (closeToGoal) { // pretty close switch (flyState) { case FLY_CRUISING: if (dontLand || (++waitCounter < 55 && dynamic_cast<CTransportUnit*>(owner)) || !autoLand) { // transport aircraft need some time to detect that they can pickup if (dynamic_cast<CTransportUnit*>(owner)) { wantedSpeed = ZeroVector; if (waitCounter > 60) { wantedHeight = orgWantedHeight; } } else { wantedSpeed = ZeroVector; if (!owner->commandAI->HasMoreMoveCommands()) wantToStop = true; SetState(AIRCRAFT_HOVERING); } } else { wantedHeight = orgWantedHeight; SetState(AIRCRAFT_LANDING); } return; case FLY_CIRCLING: // break; waitCounter++; if (waitCounter > 100) { if (owner->unitDef->airStrafe) { float3 relPos = pos - circlingPos; if (relPos.x < 0.0001f && relPos.x > -0.0001f) relPos.x = 0.0001f; relPos.y = 0; relPos.Normalize(); CMatrix44f rot; rot.RotateY(1.0f); float3 newPos = rot.Mul(relPos); // Make sure the point is on the circle newPos = newPos.Normalize() * goalDistance; //Go there in a straight line goalPos = circlingPos + newPos; } waitCounter = 0; } break; case FLY_ATTACKING:{ if (owner->unitDef->airStrafe) { float3 relPos = pos - circlingPos; if (relPos.x < 0.0001f && relPos.x > -0.0001f) relPos.x = 0.0001f; relPos.y = 0; relPos.Normalize(); CMatrix44f rot; if (gs->randFloat() > 0.5f) rot.RotateY(0.6f + gs->randFloat() * 0.6f); else rot.RotateY(-(0.6f + gs->randFloat() * 0.6f)); float3 newPos = rot.Mul(relPos); newPos = newPos.Normalize() * goalDistance; // Go there in a straight line goalPos = circlingPos + newPos; } break; } case FLY_LANDING:{ break; } } } // not there yet, so keep going dir.y = 0; float realMax = maxSpeed; float dist = dir.Length2D(); // If we are close to our goal, we should go slow enough to be able to break in time // new additional rule: if in attack mode or if we have more move orders then this is // an intermediate waypoint, don't slow down (FIXME) /// if (flyState != FLY_ATTACKING && dist < breakDistance && !owner->commandAI->HasMoreMoveCommands()) { if (flyState != FLY_ATTACKING && dist < breakDistance) { realMax = dist / (speed.Length2D() + 0.01f) * decRate; } wantedSpeed = dir.Normalize() * realMax; UpdateAirPhysics(); // Point toward goal or forward - unless we just passed it to get to another goal if ((flyState == FLY_ATTACKING) || (flyState == FLY_CIRCLING)) { dir = circlingPos - pos; } else if (flyState != FLY_LANDING && (owner->commandAI->HasMoreMoveCommands() && dist < 120) && (goalPos - pos).Normalize().distance(dir) > 1) { dir = owner->frontdir; } else { dir = goalPos - pos; } if (dir.SqLength2D() > 1) { int h = GetHeadingFromVector(dir.x, dir.z); wantedHeading = (h == 0)? wantedHeading: h; } }
bool CTAAirMoveType::Update() { float3& pos = owner->pos; float3& speed = owner->speed; // This is only set to false after the plane has finished constructing if (useHeading) { useHeading = false; SetState(AIRCRAFT_TAKEOFF); } if (owner->stunned || owner->beingBuilt) { wantedSpeed = ZeroVector; wantToStop = true; } // Allow us to stop if wanted if (wantToStop) { ExecuteStop(); } const float3 lastSpeed = speed; if (owner->fpsControlPlayer != NULL) { SetState(AIRCRAFT_FLYING); const FPSUnitController& con = owner->fpsControlPlayer->fpsController; const float3 forward = con.viewDir; const float3 right = forward.cross(UpVector); const float3 nextPos = pos + speed; float3 flatForward = forward; flatForward.y = 0.0f; flatForward.Normalize(); wantedSpeed = ZeroVector; if (con.forward) wantedSpeed += flatForward; if (con.back ) wantedSpeed -= flatForward; if (con.right ) wantedSpeed += right; if (con.left ) wantedSpeed -= right; wantedSpeed.Normalize(); wantedSpeed *= maxSpeed; if (!nextPos.IsInBounds()) { speed = ZeroVector; } UpdateAirPhysics(); wantedHeading = GetHeadingFromVector(flatForward.x, flatForward.z); } else { if (reservedPad) { CUnit* unit = reservedPad->GetUnit(); const float3 relPos = unit->script->GetPiecePos(reservedPad->GetPiece()); const float3 pos = unit->pos + unit->frontdir * relPos.z + unit->updir * relPos.y + unit->rightdir * relPos.x; if (padStatus == 0) { if (aircraftState != AIRCRAFT_FLYING && aircraftState != AIRCRAFT_TAKEOFF) SetState(AIRCRAFT_FLYING); goalPos = pos; if (pos.SqDistance2D(owner->pos) < 400*400) { padStatus = 1; } } else if (padStatus == 1) { if (aircraftState != AIRCRAFT_FLYING) { SetState(AIRCRAFT_FLYING); } flyState = FLY_LANDING; goalPos = pos; reservedLandingPos = pos; wantedHeight = pos.y - ground->GetHeightAboveWater(pos.x, pos.z); if (owner->pos.SqDistance(pos) < 9 || aircraftState == AIRCRAFT_LANDED) { padStatus = 2; } } else { if (aircraftState != AIRCRAFT_LANDED) SetState(AIRCRAFT_LANDED); owner->pos = pos; owner->AddBuildPower(unit->unitDef->buildSpeed / 30, unit); owner->currentFuel = std::min(owner->unitDef->maxFuel, owner->currentFuel + (owner->unitDef->maxFuel / (GAME_SPEED * owner->unitDef->refuelTime))); if (owner->health >= owner->maxHealth - 1 && owner->currentFuel >= owner->unitDef->maxFuel) { airBaseHandler->LeaveLandingPad(reservedPad); reservedPad = NULL; padStatus = 0; goalPos = oldGoalPos; SetState(AIRCRAFT_TAKEOFF); } } } // Main state handling switch (aircraftState) { case AIRCRAFT_LANDED: UpdateLanded(); break; case AIRCRAFT_TAKEOFF: UpdateTakeoff(); break; case AIRCRAFT_FLYING: UpdateFlying(); break; case AIRCRAFT_LANDING: UpdateLanding(); break; case AIRCRAFT_HOVERING: UpdateHovering(); break; case AIRCRAFT_CRASHING: break; } } // Banking requires deltaSpeed.y = 0 deltaSpeed = speed - lastSpeed; deltaSpeed.y = 0.0f; // Turn and bank and move; update dirs UpdateHeading(); UpdateBanking(aircraftState == AIRCRAFT_HOVERING); owner->UpdateMidPos(); return (HandleCollisions()); }
void CTAAirMoveType::Update() { float3& pos = owner->pos; float3& speed = owner->speed; // This is only set to false after the plane has finished constructing if (useHeading) { useHeading = false; SetState(AIRCRAFT_TAKEOFF); } // Allow us to stop if wanted if (wantToStop) ExecuteStop(); float3 lastSpeed = speed; if (owner->stunned) { wantedSpeed = ZeroVector; UpdateAirPhysics(); } else { if (owner->directControl) { DirectControlStruct* dc = owner->directControl; SetState(AIRCRAFT_FLYING); float3 forward = dc->viewDir; float3 flatForward = forward; flatForward.y = 0; flatForward.Normalize(); float3 right = forward.cross(UpVector); float3 nextPos = pos + speed; wantedSpeed = ZeroVector; if (dc->forward) wantedSpeed += flatForward; if (dc->back) wantedSpeed -= flatForward; if (dc->right) wantedSpeed += right; if (dc->left) wantedSpeed -= right; wantedSpeed.Normalize(); wantedSpeed *= maxSpeed; if (!nextPos.CheckInBounds()) { speed = ZeroVector; } UpdateAirPhysics(); wantedHeading = GetHeadingFromVector(flatForward.x, flatForward.z); } else { if (reservedPad) { CUnit* unit = reservedPad->GetUnit(); float3 relPos = unit->script->GetPiecePos(reservedPad->GetPiece()); float3 pos = unit->pos + unit->frontdir * relPos.z + unit->updir * relPos.y + unit->rightdir * relPos.x; if (padStatus == 0) { if (aircraftState != AIRCRAFT_FLYING && aircraftState != AIRCRAFT_TAKEOFF) SetState(AIRCRAFT_FLYING); goalPos = pos; if (pos.SqDistance2D(owner->pos) < 400*400) { padStatus = 1; } } else if (padStatus == 1) { if (aircraftState != AIRCRAFT_FLYING) SetState(AIRCRAFT_FLYING); flyState = FLY_LANDING; goalPos = pos; reservedLandingPos = pos; wantedHeight = pos.y - ground->GetHeight(pos.x, pos.z); if (owner->pos.SqDistance(pos) < 9 || aircraftState == AIRCRAFT_LANDED) { padStatus = 2; } } else { if (aircraftState != AIRCRAFT_LANDED) SetState(AIRCRAFT_LANDED); owner->pos = pos; owner->AddBuildPower(unit->unitDef->buildSpeed / 30, unit); owner->currentFuel = std::min(owner->unitDef->maxFuel, owner->currentFuel + (owner->unitDef->maxFuel / (GAME_SPEED * owner->unitDef->refuelTime))); if (owner->health >= owner->maxHealth - 1 && owner->currentFuel >= owner->unitDef->maxFuel) { airBaseHandler->LeaveLandingPad(reservedPad); reservedPad = 0; padStatus = 0; goalPos = oldGoalPos; SetState(AIRCRAFT_TAKEOFF); } } } // Main state handling switch (aircraftState) { case AIRCRAFT_LANDED: UpdateLanded(); break; case AIRCRAFT_TAKEOFF: UpdateTakeoff(); break; case AIRCRAFT_FLYING: UpdateFlying(); break; case AIRCRAFT_LANDING: UpdateLanding(); break; case AIRCRAFT_HOVERING: UpdateHovering(); break; case AIRCRAFT_CRASHING: break; } } } // Banking requires deltaSpeed.y = 0 deltaSpeed = speed - lastSpeed; deltaSpeed.y = 0; // Turn and bank and move UpdateHeading(); UpdateBanking(aircraftState == AIRCRAFT_HOVERING); // updates dirs owner->UpdateMidPos(); // Push other units out of the way if (pos != oldpos && aircraftState != AIRCRAFT_TAKEOFF && padStatus == 0) { oldpos = pos; if (!dontCheckCol && collide) { vector<CUnit*> nearUnits = qf->GetUnitsExact(pos, owner->radius + 6); vector<CUnit*>::iterator ui; for (ui = nearUnits.begin(); ui != nearUnits.end(); ++ui) { if ((*ui)->transporter) continue; float sqDist = (pos-(*ui)->pos).SqLength(); float totRad = owner->radius + (*ui)->radius; if (sqDist < totRad * totRad && sqDist != 0) { float dist = sqrt(sqDist); float3 dif = pos - (*ui)->pos; if (dist > 0.0f) { dif /= dist; } if ((*ui)->mass >= 100000 || (*ui)->immobile) { pos -= dif * (dist - totRad); owner->UpdateMidPos(); owner->speed *= 0.99f; } else { float part = owner->mass / (owner->mass + (*ui)->mass); pos -= dif * (dist - totRad) * (1 - part); owner->UpdateMidPos(); CUnit* u = (CUnit*) (*ui); u->pos += dif * (dist - totRad) * (part); u->UpdateMidPos(); float colSpeed = -owner->speed.dot(dif) + u->speed.dot(dif); owner->speed += dif * colSpeed * (1 - part); u->speed -= dif * colSpeed * (part); } } } } if (pos.x < 0) { pos.x += 0.6f; owner->midPos.x += 0.6f; } else if (pos.x > float3::maxxpos) { pos.x -= 0.6f; owner->midPos.x -= 0.6f; } if (pos.z < 0) { pos.z += 0.6f; owner->midPos.z += 0.6f; } else if (pos.z > float3::maxzpos) { pos.z -= 0.6f; owner->midPos.z -= 0.6f; } } }