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);
	}
}
Exemplo n.º 3
0
// 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
}
Exemplo n.º 4
0
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;
	}
}
Exemplo n.º 5
0
// 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();
}
Exemplo n.º 6
0
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();
}
Exemplo n.º 9
0
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);
	}
}
Exemplo n.º 10
0
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);
    }
}
Exemplo n.º 11
0
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);
	}
}
Exemplo n.º 12
0
// 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();
}
Exemplo n.º 13
0
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
}
Exemplo n.º 14
0
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)));
}
Exemplo n.º 15
0
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);
	}
}
Exemplo n.º 16
0
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);
	}
}
Exemplo n.º 17
0
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;
		}
	}
}
Exemplo n.º 18
0
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
}
Exemplo n.º 19
0
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());
}
Exemplo n.º 20
0
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);
	}
}
Exemplo n.º 21
0
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;
	}
}
Exemplo n.º 22
0
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;
    }
}
Exemplo n.º 23
0
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);
}
Exemplo n.º 24
0
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);
}
Exemplo n.º 25
0
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);/**/
}
Exemplo n.º 26
0
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);
}
Exemplo n.º 27
0
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;
    }
}
Exemplo n.º 28
0
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;
	}
}
Exemplo n.º 29
0
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());
}
Exemplo n.º 30
0
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;
		}
	}
}