Пример #1
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
}
Пример #2
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
}