Esempio n. 1
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)));
}
Esempio n. 2
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());
}
Esempio n. 3
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());
}
Esempio n. 4
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;
		}
	}
}
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
}
Esempio n. 6
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
}
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;
		}
	}
}