airmovetype.cpp

来自「这是整套横扫千军3D版游戏的源码」· C++ 代码 · 共 1,197 行 · 第 1/3 页

CPP
1,197
字号
#include "StdAfx.h"
#include "AirMoveType.h"
#include "Game/GameHelper.h"
#include "Game/Player.h"
#include "LogOutput.h"
#include "Map/Ground.h"
#include "Mobility.h"
#include "myMath.h"
#include "Rendering/UnitModels/3DOParser.h"
#include "Sim/Misc/GeometricObjects.h"
#include "Sim/Misc/LosHandler.h"
#include "Sim/Misc/QuadField.h"
#include "Sim/Misc/RadarHandler.h"
#include "Sim/Projectiles/Unsynced/SmokeProjectile.h"
#include "Sim/Units/COB/CobFile.h"
#include "Sim/Units/COB/CobInstance.h"
#include "Sim/Units/UnitDef.h"
#include "Sim/Weapons/Weapon.h"
#include "Sound.h"
#include "mmgr.h"

CR_BIND_DERIVED(CAirMoveType, CMoveType, (NULL));
CR_BIND(CAirMoveType::DrawLine, );
CR_BIND(CAirMoveType::RudderInfo, );

CR_REG_METADATA(CAirMoveType, (
		CR_MEMBER(subState),

		CR_MEMBER(maneuver),
		CR_MEMBER(maneuverSubState),

		CR_MEMBER(loopbackAttack),
		CR_MEMBER(isFighter),
		CR_MEMBER(collide),

		CR_MEMBER(wingDrag),
		CR_MEMBER(wingAngle),
		CR_MEMBER(invDrag),
		CR_MEMBER(frontToSpeed),
		CR_MEMBER(speedToFront),
		CR_MEMBER(myGravity),

		CR_MEMBER(maxBank),
		CR_MEMBER(maxPitch),
		CR_MEMBER(maxSpeed),
		CR_MEMBER(turnRadius),
		CR_MEMBER(wantedHeight),

		CR_MEMBER(maxAcc),
		CR_MEMBER(maxAileron),
		CR_MEMBER(maxElevator),
		CR_MEMBER(maxRudder),

		CR_MEMBER(goalPos),

		CR_MEMBER(inSupply),

		CR_MEMBER(reservedLandingPos),

		CR_MEMBER(mySide),
		CR_MEMBER(crashAileron),
		CR_MEMBER(crashElevator),
		CR_MEMBER(crashRudder),

		CR_MEMBER(oldpos),
		CR_MEMBER(oldGoalPos),
		CR_MEMBER(oldSlowUpdatePos),

		CR_MEMBER(lines),

		CR_MEMBER(rudder),
		CR_MEMBER(elevator),
		CR_MEMBER(aileronRight),
		CR_MEMBER(aileronLeft),
		CR_MEMBER(rudders),

		CR_MEMBER(lastRudderUpdate),
		CR_MEMBER(lastRudderPos),
		CR_MEMBER(lastElevatorPos),
		CR_MEMBER(lastAileronPos),

		CR_MEMBER(inefficientAttackTime),
		CR_MEMBER(exitVector),

		CR_MEMBER(lastColWarning),
		CR_MEMBER(lastColWarningType),

		CR_MEMBER(repairBelowHealth),
		CR_MEMBER(reservedPad),
		CR_MEMBER(padStatus),
		CR_MEMBER(autoLand),
		CR_RESERVED(63)
		));

CR_REG_METADATA_SUB(CAirMoveType, DrawLine, (
		CR_MEMBER(pos1), CR_MEMBER(pos2),
		CR_MEMBER(color)));

CR_REG_METADATA_SUB(CAirMoveType, RudderInfo, (CR_MEMBER(rotation)));


CAirMoveType::CAirMoveType(CUnit* owner):
	CMoveType(owner),
	wingDrag(0.07f),
	wingAngle(0.1f),
	frontToSpeed(0.04f),
	speedToFront(0.01f),
	maxBank(0.55f),
	maxPitch(0.35f),
	maxAcc(0.006f),
	maxAileron(0.04f),
	maxElevator(0.02f),
	maxRudder(0.01f),
	goalPos(1000,0,1000),
	wantedHeight(80),
	invDrag(0.995f),
	aircraftState(AIRCRAFT_LANDED),
	inSupply(0),
	subState(0),
	myGravity(0.8f),
	mySide(1),
	isFighter(false),
	collide(true),
	oldpos(0,0,0),
	oldGoalPos(0,1,0),
	maneuver(0),
	maneuverSubState(0),
	inefficientAttackTime(0),
	reservedLandingPos(-1,-1,-1),
	oldSlowUpdatePos(-1,-1,-1),
	lastColWarning(0),
	lastColWarningType(0),
	repairBelowHealth(0.30f),
	padStatus(0),
	reservedPad(0),
	loopbackAttack(false),
	autoLand(true)
{
	turnRadius=150;
	if (owner)owner->mapSquare+=1;						//to force los recalculation

	//From Aircraft::Init
	maxRudder*=0.99f+gs->randFloat()*0.02f;
	maxElevator*=0.99f+gs->randFloat()*0.02f;
	maxAileron*=0.99f+gs->randFloat()*0.02f;
	maxAcc*=0.99f+gs->randFloat()*0.02f;

	crashAileron=1-gs->randFloat()*gs->randFloat();
	if(gs->randInt()&1)
		crashAileron=-crashAileron;
	crashElevator=gs->randFloat();
	crashRudder=gs->randFloat()-0.5f;

	lastRudderUpdate=gs->frameNum;
	lastElevatorPos=0;
	lastRudderPos=0;
	lastAileronPos=0;

	exitVector=gs->randVector();
	if(exitVector.y<0)
		exitVector.y=-exitVector.y;
	exitVector.y+=1;
}

CAirMoveType::~CAirMoveType(void)
{
	if(reservedPad){
		airBaseHandler->LeaveLandingPad(reservedPad);
		reservedPad=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->GetUnit();
		float3 relPos = unit->localmodel->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.distance2D(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(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);
			}
		}
	}


	switch (aircraftState) {
	case AIRCRAFT_FLYING:
#ifdef DEBUG_AIRCRAFT
	if (selectedUnits.selectedUnits.find(this) != selectedUnits.selectedUnits.end()) {
		logOutput.Print("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);
		SAFE_NEW CSmokeProjectile(owner->midPos,gs->randVector()*0.08f,100+gs->randFloat()*50,5,0.2f,owner,0.4f);
		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;
		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;
					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.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->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.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 CAirMoveType::SlowUpdate(void)
{
	if(aircraftState!=AIRCRAFT_LANDED && owner->unitDef->maxFuel>0)

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?