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))); }
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()); }
bool CHoverAirMoveType::Update() { float3& pos = owner->pos; float3& speed = owner->speed; AAirMoveType::Update(); if (owner->stunned || owner->beingBuilt) { wantedSpeed = ZeroVector; wantToStop = true; } // Allow us to stop if wanted if (wantToStop) { ExecuteStop(); } const float3 lastSpeed = speed; if (owner->fpsControlPlayer != NULL) { SetState(AIRCRAFT_FLYING); const FPSUnitController& con = owner->fpsControlPlayer->fpsController; const float3 forward = con.viewDir; const float3 right = forward.cross(UpVector); const float3 nextPos = pos + speed; float3 flatForward = forward; flatForward.y = 0.0f; flatForward.Normalize(); wantedSpeed = ZeroVector; if (con.forward) wantedSpeed += flatForward; if (con.back ) wantedSpeed -= flatForward; if (con.right ) wantedSpeed += right; if (con.left ) wantedSpeed -= right; wantedSpeed.Normalize(); wantedSpeed *= maxSpeed; if (!nextPos.IsInBounds()) { speed = ZeroVector; } UpdateAirPhysics(); wantedHeading = GetHeadingFromVector(flatForward.x, flatForward.z); } else { if (reservedPad != NULL) { MoveToRepairPad(); if (padStatus >= 1) { flyState = FLY_LANDING; } } // Main state handling switch (aircraftState) { case AIRCRAFT_LANDED: UpdateLanded(); break; case AIRCRAFT_TAKEOFF: UpdateTakeoff(); break; case AIRCRAFT_FLYING: UpdateFlying(); break; case AIRCRAFT_LANDING: UpdateLanding(); break; case AIRCRAFT_HOVERING: UpdateHovering(); break; case AIRCRAFT_CRASHING: break; } } // Banking requires deltaSpeed.y = 0 deltaSpeed = speed - lastSpeed; deltaSpeed.y = 0.0f; // Turn and bank and move; update dirs UpdateHeading(); UpdateBanking(aircraftState == AIRCRAFT_HOVERING); return (HandleCollisions()); }
void 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 }
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; } } }