예제 #1
0
bool CWeapon::TryTargetRotate(CUnit* unit, bool userTarget){
	float3 tempTargetPos(helper->GetUnitErrorPos(unit,owner->allyteam));
	tempTargetPos+=errorVector*(weaponDef->targetMoveError*30*unit->speed.Length()*(1.0f-owner->limExperience));
	float appHeight=ground->GetApproximateHeight(tempTargetPos.x,tempTargetPos.z)+2;
	if(tempTargetPos.y < appHeight){
		tempTargetPos.y=appHeight;
	}
	short weaponHeadding = GetHeadingFromVector(mainDir.x, mainDir.z);
	short enemyHeadding = GetHeadingFromVector(
		tempTargetPos.x - weaponPos.x, tempTargetPos.z - weaponPos.z);
	return TryTargetHeading(enemyHeadding - weaponHeadding, tempTargetPos,userTarget, unit);
}
예제 #2
0
void CFarTextureHandler::DrawFarTexture(const CSolidObject* obj, CVertexArray* va)
{
	const int farTextureNum = cache[obj->team][obj->model->id];

	// not found in the atlas
	if (farTextureNum <= 0)
		return;

	const float3 interPos = obj->drawPos + UpVector * obj->model->height * 0.5f;

	// indicates the orientation to draw
	static const int USHRT_MAX_ = (1 << 16);
	const int orient_step = USHRT_MAX_ / numOrientations;

	int orient = GetHeadingFromVector(-camera->forward.x, -camera->forward.z) - obj->heading;
		orient += USHRT_MAX_;          // make it positive only
		orient += (orient_step >> 1);  // we want that frontdir is from -orient_step/2 upto orient_step/2
		orient %= USHRT_MAX_;          // we have an angle so it's periodical
		orient /= orient_step;         // get the final direction index

	const float iconSizeX = float(this->iconSizeX) / texSizeX;
	const float iconSizeY = float(this->iconSizeY) / texSizeY;
	const float2 texcoords = GetTextureCoords(farTextureNum - 1, orient);

	const float3 curad = camera->up *    obj->model->radius;
	const float3 crrad = camera->right * obj->model->radius;

	va->AddVertexQT(interPos - curad + crrad, texcoords.x, texcoords.y );
	va->AddVertexQT(interPos + curad + crrad, texcoords.x, texcoords.y + iconSizeY);
	va->AddVertexQT(interPos + curad - crrad, texcoords.x + iconSizeX, texcoords.y + iconSizeY);
	va->AddVertexQT(interPos - curad - crrad, texcoords.x + iconSizeX, texcoords.y );
}
예제 #3
0
void HUDDrawer::DrawCameraDirectionArrow(const CUnit* unit)
{
	glDisable(GL_TEXTURE_2D);

	if (unit->moveType->useHeading) {
		glPushMatrix();
			glTranslatef(-0.8f, -0.4f, 0.0f);
			glScalef(0.33f, 0.33f * globalRendering->aspectRatio, 0.33f);

			glRotatef(
				GetHeadingFromVector(camera->forward.x, camera->forward.z) * 180.0f / 32768 + 180,
				0.0f, 0.0f, 1.0f
			);
			glScalef(0.4f, 0.4f, 0.3f);

			glColor4f(0.4f, 0.4f, 1.0f, 0.6f);
			glBegin(GL_TRIANGLE_FAN);
				glVertex2f(-0.2f, -0.3f);
				glVertex2f(-0.2f,  0.3f);
				glVertex2f( 0.0f,  0.5f);
				glVertex2f( 0.2f,  0.3f);
				glVertex2f( 0.2f, -0.3f);
				glVertex2f(-0.2f, -0.3f);
			glEnd();
		glPopMatrix();
	}
}
예제 #4
0
void CUnit::FinishedBuilding(void)
{
	beingBuilt = false;
	buildProgress = 1.0f;

	if (soloBuilder) {
		DeleteDeathDependence(soloBuilder);
		soloBuilder = NULL;
	}

	if (!(immobile && (mass == 100000))) {
		mass = unitDef->mass;		//set this now so that the unit is harder to move during build
	}

	ChangeLos(realLosRadius,realAirLosRadius);

	if (unitDef->startCloaked) {
		wantCloak = true;
		isCloaked = true;
	}

	if (unitDef->windGenerator>0) {
		if (wind.curStrength > unitDef->windGenerator) {
			cob->Call(COBFN_SetSpeed, (int)(unitDef->windGenerator * 3000.0f));
		} else {
			cob->Call(COBFN_SetSpeed, (int)(wind.curStrength       * 3000.0f));
		}
		cob->Call(COBFN_SetDirection, (int)GetHeadingFromVector(-wind.curDir.x, -wind.curDir.z));
	}

	if (unitDef->activateWhenBuilt) {
		Activate();
	}

	gs->Team(team)->metalStorage  += unitDef->metalStorage;
	gs->Team(team)->energyStorage += unitDef->energyStorage;

	//Sets the frontdir in sync with heading.
	frontdir = GetVectorFromHeading(heading) + float3(0,frontdir.y,0);

	if (unitDef->isAirBase) {
		airBaseHandler->RegisterAirBase(this);
	}

	luaCallIns.UnitFinished(this);
	globalAI->UnitFinished(this);

	if (unitDef->isFeature) {
		UnBlock();
		CFeature* f =
			featureHandler->CreateWreckage(pos, wreckName, heading, buildFacing,
			                               0, team, false, "");
		if (f) {
			f->blockHeightChanges = true;
		}
		KillUnit(false, true, 0);
	}
}
예제 #5
0
bool CWeapon::TryTargetRotate(float3 pos, bool userTarget) {
	if (!userTarget && weaponDef->noAutoTarget) {
		return false;
	}
	if (weaponDef->interceptor || !weaponDef->canAttackGround ||
	    (weaponDef->onlyTargetCategory != 0xffffffff)) {
		return false;
	}

	if (!weaponDef->waterweapon && pos.y < 1) {
		pos.y = 1;
	}

	short weaponHeading = GetHeadingFromVector(mainDir.x, mainDir.z);
	short enemyHeading = GetHeadingFromVector(
		pos.x - weaponPos.x, pos.z - weaponPos.z);

	return TryTargetHeading(enemyHeading - weaponHeading, pos, userTarget, 0);
}
예제 #6
0
void CUnit::PushWind(float x, float z, float strength)
{
    if(strength > unitDef->windGenerator)
    {
        cob->Call(COBFN_SetSpeed, (int)(unitDef->windGenerator*3000.0f));
    }
    else
    {
        cob->Call(COBFN_SetSpeed, (int)(strength*3000.0f));
    }

    cob->Call(COBFN_SetDirection, (int)GetHeadingFromVector(-x, -z));
}
예제 #7
0
파일: Feature.cpp 프로젝트: Arkazon/spring
void CFeature::ForcedSpin(const float3& newDir)
{
	float3 updir = UpVector;
	if (updir == newDir) {
		//FIXME perhaps save the old right,up,front directions, so we can
		// reconstruct the old upvector and generate a better assumption for updir
		updir -= GetVectorFromHeading(heading);
	}
	float3 rightdir = newDir.cross(updir).Normalize();
	updir = rightdir.cross(newDir);
	transMatrix = CMatrix44f(pos, -rightdir, updir, newDir);
	heading = GetHeadingFromVector(newDir.x, newDir.z);
}
예제 #8
0
void CAirMoveType::SetState(AAirMoveType::AircraftState state)
{
	// this state is only used by CTAAirMoveType
	assert(state != AIRCRAFT_HOVERING);

	if (aircraftState == AIRCRAFT_CRASHING || state == aircraftState)
		return;

	/*
	if (state == AIRCRAFT_LANDING)
		owner->cob->Call(COBFN_Deactivate);
	else if (state == aircraft_flying)
		// cob->Call(COBFN_Activate);
	*/

	if (state == AIRCRAFT_FLYING) {
		owner->Activate();
		owner->script->StartMoving();
	}

	if (state == AIRCRAFT_LANDED) {
		owner->heading = GetHeadingFromVector(owner->frontdir.x, owner->frontdir.z);
		owner->physicalState = CSolidObject::OnGround;
		owner->useAirLos = false;
	} else {
		owner->physicalState = CSolidObject::Flying;
		owner->useAirLos = true;
		if (state != AIRCRAFT_LANDING) {
			reservedLandingPos.x = -1;
			owner->UnBlock();
		}
	}

	if (aircraftState == AIRCRAFT_LANDED && reservedLandingPos.x > 0) {
		reservedLandingPos.x = -1;
	}
	subState = 0;

	// make sure we only go into takeoff if actually landed
	if (state != AIRCRAFT_TAKEOFF || aircraftState == AIRCRAFT_LANDED) {
		aircraftState = state;
	} else {
		aircraftState = AIRCRAFT_TAKEOFF;
	}
}
예제 #9
0
void CFeature::ForcedSpin(const float3& newDir)
{
/*
	heading = GetHeadingFromVector(newDir.x, newDir.z);
	CalculateTransform();
	if (def->drawType >= DRAWTYPE_TREE) {
		treeDrawer->DeleteTree(pos);
		treeDrawer->AddTree(def->drawType - 1, pos, 1.0f);
	}
*/

	float3 updir = UpVector;
	if (updir == newDir) {
		//FIXME perhaps save the old right,up,front directions, so we can
		// reconstruct the old upvector and generate a better assumption for updir
		updir -= GetVectorFromHeading(heading);
	}
	float3 rightdir = newDir.cross(updir).Normalize();
	updir = rightdir.cross(newDir);
	transMatrix = CMatrix44f(pos, -rightdir, updir, newDir);
	heading = GetHeadingFromVector(newDir.x, newDir.z);
}
예제 #10
0
void CAirMoveType::SetState(CAirMoveType::AircraftState state)
{
	if(aircraftState==AIRCRAFT_CRASHING || state==aircraftState)
		return;

/*	if (state == AIRCRAFT_LANDING)
		owner->animator->AnimAction(ANIMFN_Deactivate);
		else if (state == aircraft_flying)
		//animator->AnimAction(ANIMFN_Activate); */
	
	if (state == AIRCRAFT_FLYING) {
		owner->Activate();
		owner->animator->AnimAction(ANIMFN_StartMoving);
	}

	if(state==AIRCRAFT_LANDED){
		owner->heading=GetHeadingFromVector(owner->frontdir.x, owner->frontdir.z);
		owner->physicalState = CSolidObject::OnGround;
		owner->useAirLos=false;
	}else{
		owner->physicalState = CSolidObject::Flying;
		owner->useAirLos=true;
		if(state!=AIRCRAFT_LANDING){
			reservedLandingPos.x=-1;
			owner->UnBlock();
		}
	}

	if(aircraftState==AIRCRAFT_LANDED && reservedLandingPos.x>0){
		reservedLandingPos.x=-1;
	}
	subState=0;
	if(state!=AIRCRAFT_TAKEOFF || aircraftState==AIRCRAFT_LANDED)		//make sure we only go into takeoff if actually landed
		aircraftState=state;
	else
		aircraftState=AIRCRAFT_TAKEOFF;
}
예제 #11
0
파일: Factory.cpp 프로젝트: Finkky/spring
void CFactory::UpdateBuild(CUnit* buildee) {
	if (stunned)
		return;

	// factory not under construction and
	// nanolathing unit: continue building
	lastBuildUpdateFrame = gs->frameNum;

	// buildPiece is the rotating platform
	const int buildPiece = GetBuildPiece();
	const float3& buildPos = CalcBuildPos(buildPiece);
	const CMatrix44f& mat = script->GetPieceMatrix(buildPiece);
	const int h = GetHeadingFromVector(mat[2], mat[10]); //! x.z, z.z

	float3 buildeePos = buildPos;

	// rotate unit nanoframe with platform
	buildee->heading = (-h + GetHeadingFromFacing(buildFacing)) & (SPRING_CIRCLE_DIVS - 1);

	if (buildee->unitDef->floatOnWater && (buildeePos.y <= 0.0f))
		buildeePos.y = -buildee->unitDef->waterline;

	buildee->Move3D(buildeePos, false);
	buildee->UpdateDirVectors(false);
	buildee->UpdateMidAndAimPos();

	const CCommandQueue& queue = commandAI->commandQue;

	if (!queue.empty() && (queue.front().GetID() == CMD_WAIT)) {
		buildee->AddBuildPower(0, this);
	} else {
		if (buildee->AddBuildPower(buildSpeed, this)) {
			CreateNanoParticle();
		}
	}
}
예제 #12
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)));
}
예제 #13
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);
	}
}
예제 #14
0
void CTAAirMoveType::UpdateFlying()
{
	float3 &pos = owner->pos;
	float3 &speed = owner->speed;

	//Direction to where we would like to be
	float3 dir = goalPos - pos;
	bool arrived = false;
	owner->restTime=0;

	//are we there yet?
//	logOutput.Print("max drift %f %i %f %f",maxDrift,waitCounter,dir.Length2D(),fabs(ground->GetHeight(pos.x,pos.z)-pos.y+wantedHeight));
	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))){		//transport aircrafts need some time to detect that they can pickup
					if (dynamic_cast<CTransportUnit*>(owner)) {
						wantedSpeed=ZeroVector;
						if(waitCounter>60){
							wantedHeight=orgWantedHeight;
						}
					} else
						SetState(AIRCRAFT_HOVERING);
				} else {
					wantedHeight=orgWantedHeight;
					SetState(AIRCRAFT_LANDING);
				}
				//logOutput.Print("In position, landing");
				return;
			case FLY_CIRCLING:
				waitCounter++;
				if (waitCounter > 100) {
					//logOutput.Print("moving circlepos");
					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:{
				//logOutput.Print("wait is %d", waitCounter);
				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;
//				logOutput.Print("Changed circle pos");
				break;}
			case FLY_LANDING:{
/*				//First check if we can land around here somewhere
				if (!CanLandAt(pos)) {
					//Check the surrounding area for a suitable position
					float3 newPos;
					bool found = FindLandingSpot(pos, newPos);
					if (found) {
						SetState(AIRCRAFT_FLYING);		
						logOutput.Print("Found a landingspot when cruising around");
						goalPos = newPos;			
						return;
					}
				}
				else {
					SetState(AIRCRAFT_LANDING);
					return;
				}

				float3 relPos = pos - circlingPos;
				relPos.y = 0;
				CMatrix44f rot;
				rot.RotateY(2.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;}
		}
	}
	//no, so go there!
	
	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
	//if in attack mode dont slow down
	if (flyState!=FLY_ATTACKING && dist < breakDistance) {
		realMax = dist/(speed.Length2D()+0.01f) * decRate;
		//logOutput.Print("Break! %f %f %f", maxSpeed, dir.Length2D(), realMax);
	}

	wantedSpeed = dir.Normalize() * realMax;

	UpdateAirPhysics();


	//Point toward goal or forward
	if ((flyState == FLY_ATTACKING) || (flyState == FLY_CIRCLING)) {
		dir = circlingPos - pos;
	} else {
		dir = goalPos - pos;
	}
	if(dir.SqLength2D()>1)
		wantedHeading = GetHeadingFromVector(dir.x, dir.z);
}
예제 #15
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;
		}
	}
}
예제 #16
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());
}
예제 #17
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);
	}
}
예제 #18
0
void CFactory::Update()
{
	if(beingBuilt){
		CUnit::Update();
		return;
	}

	if(quedBuild && inBuildStance){
		float3 buildPos = CalcBuildPos();

		bool canBuild=true;
		std::vector<CUnit*> units=qf->GetUnitsExact(buildPos,16);
		for(std::vector<CUnit*>::iterator ui=units.begin();ui!=units.end();++ui){
			if((*ui)!=this)
				canBuild=false;
		}
		if(canBuild){
			quedBuild=false;
			CUnit* b=unitLoader.LoadUnit(nextBuild,buildPos+float3(0.01,0.01,0.01),team,true,buildFacing);
			AddDeathDependence(b);
			curBuild=b;

			animator->AnimAction("StartBuilding");

			if(unitDef->sounds.build.id)
				sound->PlaySound(unitDef->sounds.build.id, pos, unitDef->sounds.build.volume);
		} else {
			helper->BuggerOff(buildPos-float3(0.01,0,0.02),radius+8);
		}
	}

	if(curBuild && !beingBuilt){
		lastBuild=gs->frameNum;

		int buildPiece = GetBuildPiece();
		CMatrix44f mat=localmodel->GetPieceMatrix(buildPiece);
		int h=GetHeadingFromVector(mat[2],mat[10]);
		curBuild->heading=h;

		float3 buildPos = curBuild->pos = CalcBuildPos(buildPiece);
		if(curBuild->floatOnWater)
			curBuild->pos.y=ground->GetHeight(buildPos.x,buildPos.z)-curBuild->unitDef->waterline;
		curBuild->midPos=curBuild->pos+UpVector*curBuild->relMidPos.y;

		if(curBuild->AddBuildPower(buildSpeed,this)){
			std::vector<int> args;
			args.push_back(0);
			animator->AnimAction("QueryNanoPiece",args);

			if(unitDef->showNanoSpray){
				float3 relWeaponFirePos=localmodel->GetPiecePos(args[0]);
				float3 weaponPos=pos + frontdir*relWeaponFirePos.z + updir*relWeaponFirePos.y + rightdir*relWeaponFirePos.x;

				float3 dif=curBuild->midPos-weaponPos;
				float l=dif.Length();
				dif/=l;
				dif+=gs->randVector()*0.15f;
				float3 color= unitDef->nanoColor;
				if(gu->teamNanospray){
					unsigned char* tcol=gs->Team(team)->color;
					color = float3(tcol[0]*(1./255.),tcol[1]*(1./255.),tcol[2]*(1./255.));
				}
				new CGfxProjectile(weaponPos,dif,(int)l,color);
			}
		} else {
			if(!curBuild->beingBuilt){
				if(group)
					curBuild->SetGroup(group);
				Command c;
				c.id=CMD_MOVE_STATE;
				c.options=0;
				c.params.push_back(moveState);
				curBuild->commandAI->GiveCommand(c);
				c.params.clear();
				c.id=CMD_FIRE_STATE;
				c.params.push_back(fireState);
				curBuild->commandAI->GiveCommand(c);
				if(curBuild->commandAI->commandQue.empty() || (dynamic_cast<CMobileCAI*>(curBuild->commandAI) && ((CMobileCAI*)curBuild->commandAI)->unimportantMove)){
					if(((CFactoryCAI*)commandAI)->newUnitCommands.empty()){
						SendToEmptySpot(curBuild);
					} else {
						for(std::deque<Command>::iterator ci=((CFactoryCAI*)commandAI)->newUnitCommands.begin();ci!=((CFactoryCAI*)commandAI)->newUnitCommands.end();++ci)
							curBuild->commandAI->GiveCommand(*ci);
					}
				}
				StopBuild();
			}
		}
	}

	if(lastBuild+200 < gs->frameNum && !quedBuild && opening && uh->CanCloseYard(this)){
		readmap->CloseBlockingYard(this);
		opening=false;
		animator->AnimAction(ANIMFN_Deactivate);
	}
	CBuilding::Update();
}
예제 #19
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;
	}
}
예제 #20
0
void CWeapon::Update()
{
    if(hasCloseTarget) {
        std::vector<int> args;
        args.push_back(0);
        if(useWeaponPosForAim) {
            owner->cob->Call(COBFN_QueryPrimary+weaponNum,args);
        } else {
            owner->cob->Call(COBFN_AimFromPrimary+weaponNum,args);
        }
        relWeaponPos=owner->localmodel->GetPiecePos(args[0]);
    }

    if(targetType==Target_Unit) {
        if(lastErrorVectorUpdate<gs->frameNum-16) {
            float3 newErrorVector(gs->randVector());
            errorVectorAdd=(newErrorVector-errorVector)*(1.0f/16.0f);
            lastErrorVectorUpdate=gs->frameNum;
        }
        errorVector+=errorVectorAdd;
        if(weaponDef->selfExplode) {	//assumes that only flakker like units that need to hit aircrafts has this,change to a separate tag later
            targetPos=helper->GetUnitErrorPos(targetUnit,owner->allyteam)+targetUnit->speed*(0.5+predictSpeedMod*0.5)*predict;
        } else {
            targetPos=helper->GetUnitErrorPos(targetUnit,owner->allyteam)+targetUnit->speed*predictSpeedMod*predict;
        }
        targetPos+=errorVector*(weaponDef->targetMoveError*30*targetUnit->speed.Length()*(1.0-owner->limExperience));
        if(!weaponDef->waterweapon && targetPos.y<1)
            targetPos.y=1;
    }

    if(weaponDef->interceptor)
        CheckIntercept();
    if(targetType!=Target_None) {
        if(onlyForward) {
            float3 goaldir=targetPos-owner->pos;
            goaldir.Normalize();
            angleGood=owner->frontdir.dot(goaldir) > maxAngleDif;
        } else if(lastRequestedDir.dot(wantedDir)<maxAngleDif || lastRequest+15<gs->frameNum) {
            angleGood=false;
            lastRequestedDir=wantedDir;
            lastRequest=gs->frameNum;

            short int heading=GetHeadingFromVector(wantedDir.x,wantedDir.z);
            short int pitch=(short int) (asin(wantedDir.dot(owner->updir))*(32768/PI));
            std::vector<int> args;
            args.push_back(short(heading-owner->heading));
            args.push_back(pitch);
            owner->cob->Call(COBFN_AimPrimary+weaponNum,args,ScriptCallback,this,0);
        }
    }
    if(weaponDef->stockpile && numStockpileQued) {
        float p=1.0/reloadTime;
        if(gs->Team(owner->team)->metal>=metalFireCost*p && gs->Team(owner->team)->energy>=energyFireCost*p) {
            owner->UseEnergy(energyFireCost*p);
            owner->UseMetal(metalFireCost*p);
            buildPercent+=p;
        }
        if(buildPercent>=1) {
            buildPercent=0;
            numStockpileQued--;
            numStockpiled++;
            owner->commandAI->StockpileChanged(this);
        }
    }

    if(salvoLeft==0
#ifdef DIRECT_CONTROL_ALLOWED
            && (!owner->directControl || owner->directControl->mouse1 || owner->directControl->mouse2)
#endif
            && targetType!=Target_None
            && angleGood
            && subClassReady
            && reloadStatus<=gs->frameNum
            && (weaponDef->stockpile || (gs->Team(owner->team)->metal>=metalFireCost && gs->Team(owner->team)->energy>=energyFireCost))
            && (!weaponDef->stockpile || numStockpiled)
            && (weaponDef->waterweapon || weaponPos.y>0)
      ) {
        std::vector<int> args;
        args.push_back(0);
        owner->cob->Call(COBFN_QueryPrimary+weaponNum,args);
        relWeaponPos=owner->localmodel->GetPiecePos(args[0]);
        weaponPos=owner->pos+owner->frontdir*relWeaponPos.z+owner->updir*relWeaponPos.y+owner->rightdir*relWeaponPos.x;
        useWeaponPosForAim=reloadTime/16+8;

        if(TryTarget(targetPos,haveUserTarget,targetUnit)) {
            if(weaponDef->stockpile) {
                numStockpiled--;
                owner->commandAI->StockpileChanged(this);
            } else {
                owner->UseEnergy(energyFireCost);
                owner->UseMetal(metalFireCost);
            }
            if(weaponDef->stockpile)
                reloadStatus=gs->frameNum+60;
            else
                reloadStatus=gs->frameNum+(int)(reloadTime/owner->reloadSpeed);

            salvoLeft=salvoSize;
            nextSalvo=gs->frameNum;
            salvoError=gs->randVector()*(owner->isMoving?weaponDef->movingAccuracy:accuracy);
            if(targetType==Target_Pos || (targetType==Target_Unit && !(targetUnit->losStatus[owner->allyteam] & LOS_INLOS)))		//area firing stuff is to effective at radar firing...
                salvoError*=1.3;

            owner->lastMuzzleFlameSize=muzzleFlareSize;
            owner->lastMuzzleFlameDir=wantedDir;
            owner->cob->Call(COBFN_FirePrimary+weaponNum);
        }
    }

    if(salvoLeft && nextSalvo<=gs->frameNum) {
        salvoLeft--;
        nextSalvo=gs->frameNum+salvoDelay;
        owner->lastFireWeapon=gs->frameNum;

        std::vector<int> args;
        args.push_back(0);
        owner->cob->Call(/*COBFN_AimFromPrimary+weaponNum/*/COBFN_QueryPrimary+weaponNum/**/,args);
        relWeaponPos=owner->localmodel->GetPiecePos(args[0]);
        weaponPos=owner->pos+owner->frontdir*relWeaponPos.z+owner->updir*relWeaponPos.y+owner->rightdir*relWeaponPos.x;

//		info->AddLine("RelPosFire %f %f %f",relWeaponPos.x,relWeaponPos.y,relWeaponPos.z);

        owner->isCloaked=false;
        owner->curCloakTimeout=gs->frameNum+owner->cloakTimeout;

        Fire();

        //Rock the unit in the direction of the fireing
        float3 rockDir = wantedDir;
        rockDir.y = 0;
        rockDir = -rockDir.Normalize();
        std::vector<int> rockAngles;
        rockAngles.push_back((int)(500 * rockDir.z));
        rockAngles.push_back((int)(500 * rockDir.x));
        owner->cob->Call(COBFN_RockUnit,  rockAngles);

        owner->commandAI->WeaponFired(this);

        if(salvoLeft==0) {
            owner->cob->Call(COBFN_EndBurst+weaponNum);
        }
#ifdef TRACE_SYNC
        tracefile << "Weapon fire: ";
        tracefile << weaponPos.x << " " << weaponPos.y << " " << weaponPos.z << " " << targetPos.x << " " << targetPos.y << " " << targetPos.z << "\n";
#endif
    }
}
예제 #21
0
void CFactory::Update()
{
	if (beingBuilt) {
		// factory under construction
		CUnit::Update();
		return;
	}

	if (quedBuild && !opening && !stunned) {
		cob->Call(COBFN_Activate);
		groundBlockingObjectMap->OpenBlockingYard(this, yardMap);
		opening = true;
	}

	if (quedBuild && inBuildStance && !stunned) {
		// start building a unit
		float3 buildPos = CalcBuildPos();

		bool canBuild = true;
		std::vector<CUnit*> units = qf->GetUnitsExact(buildPos, 16);

		for (std::vector<CUnit*>::iterator ui = units.begin(); ui != units.end(); ++ui) {
			if ((*ui) != this)
				canBuild = false;
		}

		if (canBuild) {
			quedBuild = false;
			CUnit* b = unitLoader.LoadUnit(nextBuild, buildPos + float3(0.01f, 0.01f, 0.01f), team,
											true, buildFacing, this);
			b->lineage = this->lineage;

			if (!unitDef->canBeAssisted) {
				b->soloBuilder = this;
				b->AddDeathDependence(this);
			}

			AddDeathDependence(b);
			curBuild = b;

			cob->Call("StartBuilding");

			int soundIdx = unitDef->sounds.build.getRandomIdx();
			if (soundIdx >= 0) {
				sound->PlaySample(
					unitDef->sounds.build.getID(soundIdx), pos,
					unitDef->sounds.build.getVolume(0));
			}
		} else {
			helper->BuggerOff(buildPos - float3(0.01f, 0, 0.02f), radius + 8);
		}
	}


	if (curBuild && !beingBuilt) {
		if (!stunned) {
			// factory not under construction and
			// nanolathing unit: continue building
			lastBuild = gs->frameNum;
	
			// buildPiece is the rotating platform
			const int buildPiece = GetBuildPiece();
			CMatrix44f mat = localmodel->GetPieceMatrix(buildPiece);
			const int h = GetHeadingFromVector(mat[2], mat[10]);
	
			// rotate unit nanoframe with platform
			curBuild->heading = (h + GetHeadingFromFacing(buildFacing)) & 65535;
	
			const float3 buildPos = CalcBuildPos(buildPiece);
			curBuild->pos = buildPos;
	
			if (curBuild->floatOnWater) {
				curBuild->pos.y  = ground->GetHeight(buildPos.x, buildPos.z);
				curBuild->pos.y -= curBuild->unitDef->waterline;
			}
			curBuild->midPos = curBuild->pos + (UpVector * curBuild->relMidPos.y);
	
			const CCommandQueue& queue = commandAI->commandQue;
	
			if(!queue.empty() && (queue.front().id == CMD_WAIT)) {
				curBuild->AddBuildPower(0, this);
			} else {
				if (curBuild->AddBuildPower(buildSpeed, this)) {
					CreateNanoParticle();
				}
			}
		}

		if (!curBuild->beingBuilt &&
				(!unitDef->fullHealthFactory ||
						(curBuild->health >= curBuild->maxHealth)))
		{
			if (group && curBuild->group == 0) {
				curBuild->SetGroup(group);
			}

			bool userOrders = true;
			if (curBuild->commandAI->commandQue.empty() ||
					(dynamic_cast<CMobileCAI*>(curBuild->commandAI) &&
					 ((CMobileCAI*)curBuild->commandAI)->unimportantMove)) {
				userOrders = false;
				const CFactoryCAI* facAI = (CFactoryCAI*) commandAI;
				const CCommandQueue& newUnitCmds = facAI->newUnitCommands;

				if (newUnitCmds.empty()) {
					SendToEmptySpot(curBuild);
				} else {
					// XXX the pathfinder sometimes... makes mistakes, try to hack around it
					// XXX note this qualifies as HACK HACK HACK
					float3 testpos = curBuild->pos + frontdir * (this->radius - 1.0f);
					Command c;
					c.id = CMD_MOVE;
					c.params.push_back(testpos.x);
					c.params.push_back(testpos.y);
					c.params.push_back(testpos.z);
					curBuild->commandAI->GiveCommand(c);

					for (CCommandQueue::const_iterator ci = newUnitCmds.begin(); ci != newUnitCmds.end(); ++ci) {
						c = *ci;
						c.options |= SHIFT_KEY;
						curBuild->commandAI->GiveCommand(c);
					}
				}
				waitCommandsAI.AddLocalUnit(curBuild, this);
			}
			eventHandler.UnitFromFactory(curBuild, this, userOrders);

			StopBuild();
		}
	}

	if (((lastBuild + 200) < gs->frameNum) && !stunned &&
	    !quedBuild && opening && groundBlockingObjectMap->CanCloseYard(this)) {
		// close the factory after inactivity
		groundBlockingObjectMap->CloseBlockingYard(this, yardMap);
		opening = false;
		cob->Call(COBFN_Deactivate);
	}

	CBuilding::Update();
}
예제 #22
0
void CWeapon::Update()
{
	if(hasCloseTarget){
		std::vector<int> args;
		args.push_back(0);
		if(useWeaponPosForAim){
			owner->animator->AnimAction(ANIMFN_QueryPrimary+weaponNum,args);
		} else {
			owner->animator->AnimAction(ANIMFN_AimFromPrimary+weaponNum,args);
		}
		relWeaponPos=owner->localmodel->GetPiecePos(args[0]);
	}

	if(targetType==Target_Unit){
		if(lastErrorVectorUpdate<gs->frameNum-16){
			float3 newErrorVector(gs->randVector());
			errorVectorAdd=(newErrorVector-errorVector)*(1.0f/16.0f);
			lastErrorVectorUpdate=gs->frameNum;
		}
		errorVector+=errorVectorAdd;
		if (predict > 50000) {
			/* to prevent runaway prediction (happens sometimes when a missile is moving *away* from it's target), we may need to disable missiles in case they fly around too long */
			predict = 50000;
		}
		if(weaponDef->selfExplode){	//assumes that only flakker like units that need to hit aircrafts has this,change to a separate tag later
			targetPos=helper->GetUnitErrorPos(targetUnit,owner->allyteam)+targetUnit->speed*(0.5+predictSpeedMod*0.5)*predict;
		} else {
			targetPos=helper->GetUnitErrorPos(targetUnit,owner->allyteam)+targetUnit->speed*predictSpeedMod*predict;
		}
		targetPos+=errorVector*(weaponDef->targetMoveError*30*targetUnit->speed.Length()*(1.0-owner->limExperience));
		float appHeight=ground->GetApproximateHeight(targetPos.x,targetPos.z)+2;
		if(targetPos.y < appHeight)
			targetPos.y=appHeight;

		if(!weaponDef->waterweapon && targetPos.y<1)
			targetPos.y=1;
	}

	if(weaponDef->interceptor)
		CheckIntercept();
	if(targetType!=Target_None){
		if(onlyForward){
			float3 goaldir=targetPos-owner->pos;
			goaldir.Normalize();
			angleGood=owner->frontdir.dot(goaldir) > maxAngleDif;
		} else if(lastRequestedDir.dot(wantedDir)<maxAngleDif || lastRequest+15<gs->frameNum){
			angleGood=false;
			lastRequestedDir=wantedDir;
			lastRequest=gs->frameNum;

			short int heading=GetHeadingFromVector(wantedDir.x,wantedDir.z);
			short int pitch=(short int) (asin(wantedDir.dot(owner->updir))*(32768/PI));
			std::vector<int> args;
			args.push_back(short(heading-owner->heading));
			args.push_back(pitch);
			owner->animator->AnimAction(ANIMFN_AimPrimary+weaponNum,args,ScriptCallback,this,0);
		}
	}
	if(weaponDef->stockpile && numStockpileQued){
		float p=1.0/reloadTime;
		if(gs->Team(owner->team)->metal>=metalFireCost*p && gs->Team(owner->team)->energy>=energyFireCost*p){
			owner->UseEnergy(energyFireCost*p);
			owner->UseMetal(metalFireCost*p);
			buildPercent+=p;
		} else {
			// update the energy and metal required counts
			gs->Team(owner->team)->energyPullAmount += energyFireCost*p;
			gs->Team(owner->team)->metalPullAmount += metalFireCost*p;
		}
		if(buildPercent>=1){
			buildPercent=0;
			numStockpileQued--;
			numStockpiled++;
			owner->commandAI->StockpileChanged(this);
		}
	}

	if(salvoLeft==0 
#ifdef DIRECT_CONTROL_ALLOWED
	&& (!owner->directControl || owner->directControl->mouse1 || owner->directControl->mouse2)
#endif
	&& targetType!=Target_None
	&& angleGood 
	&& subClassReady 
	&& reloadStatus<=gs->frameNum
	&& (!weaponDef->stockpile || numStockpiled)
	&& (weaponDef->waterweapon || weaponPos.y>0)
	&& (owner->unitDef->maxFuel==0 || owner->currentFuel > 0)
	){
		if ((weaponDef->stockpile || (gs->Team(owner->team)->metal>=metalFireCost && gs->Team(owner->team)->energy>=energyFireCost))) {
			std::vector<int> args;
			args.push_back(0);
			owner->animator->AnimAction(ANIMFN_QueryPrimary+weaponNum,args);
			relWeaponPos=owner->localmodel->GetPiecePos(args[0]);
			weaponPos=owner->pos+owner->frontdir*relWeaponPos.z+owner->updir*relWeaponPos.y+owner->rightdir*relWeaponPos.x;
			useWeaponPosForAim=reloadTime/16+8;

			if(TryTarget(targetPos,haveUserTarget,targetUnit)){
				if(weaponDef->stockpile){
					numStockpiled--;
					owner->commandAI->StockpileChanged(this);
				} else {
					owner->UseEnergy(energyFireCost);
					owner->UseMetal(metalFireCost);
					owner->currentFuel = max(0.0f, owner->currentFuel - fuelUsage);
				}
				if(weaponDef->stockpile)
					reloadStatus=gs->frameNum+60;
				else
					reloadStatus=gs->frameNum+(int)(reloadTime/owner->reloadSpeed);

				salvoLeft=salvoSize;
				nextSalvo=gs->frameNum;
				salvoError=gs->randVector()*(owner->isMoving?weaponDef->movingAccuracy:accuracy);
				if(targetType==Target_Pos || (targetType==Target_Unit && !(targetUnit->losStatus[owner->allyteam] & LOS_INLOS)))		//area firing stuff is to effective at radar firing...
					salvoError*=1.3;

				owner->lastMuzzleFlameSize=muzzleFlareSize;
				owner->lastMuzzleFlameDir=wantedDir;
				owner->animator->AnimAction(ANIMFN_FirePrimary+weaponNum);
			} 
		} else {
			if (TryTarget(targetPos,haveUserTarget,targetUnit) && !weaponDef->stockpile) {
				// update the energy and metal required counts
				const int minPeriod = max(1, (int)(reloadTime / owner->reloadSpeed));
				const float averageFactor = 1.0f / (float)minPeriod;
				gs->Team(owner->team)->energyPullAmount += averageFactor * energyFireCost;
				gs->Team(owner->team)->metalPullAmount += averageFactor * metalFireCost;
			}
		}
	}

	if(salvoLeft && nextSalvo<=gs->frameNum){
		salvoLeft--;
		nextSalvo=gs->frameNum+salvoDelay;
		owner->lastFireWeapon=gs->frameNum;
		
		// add a shot count if it helps to end the current 'attack ground' command
		// (the 'salvoLeft' check is done because the positions may already have been adjusted)
		if ((salvoLeft == (salvoSize - 1)) &&
		    ((targetType == Target_Pos) && (targetPos == owner->userAttackPos)) ||
				((targetType == Target_Unit) && (targetUnit == owner->userTarget))) {
			owner->commandShotCount++;
		}
		
		std::vector<int> args;
		args.push_back(0);
		owner->animator->AnimAction(/*ANIMFN_AimFromPrimary+weaponNum/*/ANIMFN_QueryPrimary+weaponNum/**/,args);
		relWeaponPos=owner->localmodel->GetPiecePos(args[0]);
		weaponPos=owner->pos+owner->frontdir*relWeaponPos.z+owner->updir*relWeaponPos.y+owner->rightdir*relWeaponPos.x;

//		info->AddLine("RelPosFire %f %f %f",relWeaponPos.x,relWeaponPos.y,relWeaponPos.z);

		owner->isCloaked=false;
		owner->curCloakTimeout=gs->frameNum+owner->cloakTimeout;

		Fire();

		//Rock the unit in the direction of the fireing
		float3 rockDir = wantedDir;
		rockDir.y = 0;
		rockDir = -rockDir.Normalize();
		std::vector<int> rockAngles;
		rockAngles.push_back((int)(500 * rockDir.z));
		rockAngles.push_back((int)(500 * rockDir.x));
		owner->animator->AnimAction(ANIMFN_RockUnit,  rockAngles);		

		owner->commandAI->WeaponFired(this);

		if(salvoLeft==0){
			owner->animator->AnimAction(ANIMFN_EndBurst+weaponNum);		
		}
#ifdef TRACE_SYNC
	tracefile << "Weapon fire: ";
	tracefile << weaponPos.x << " " << weaponPos.y << " " << weaponPos.z << " " << targetPos.x << " " << targetPos.y << " " << targetPos.z << "\n";
#endif
	}
}
예제 #23
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());
}
예제 #24
0
void CWeapon::Update()
{
	if(hasCloseTarget){
		std::vector<int> args;
		args.push_back(0);
		if(useWeaponPosForAim){ //if we couldn't get a line of fire from the muzzle try if we can get it from the aim piece
			owner->cob->Call(COBFN_QueryPrimary+weaponNum,args);
		} else {
			owner->cob->Call(COBFN_AimFromPrimary+weaponNum,args);
		}
		relWeaponMuzzlePos=owner->localmodel->GetPiecePos(args[0]);

		owner->cob->Call(COBFN_AimFromPrimary+weaponNum,args);
		relWeaponPos=owner->localmodel->GetPiecePos(args[0]);
	}

	if(targetType==Target_Unit){
		if(lastErrorVectorUpdate<gs->frameNum-16){
			float3 newErrorVector(gs->randVector());
			errorVectorAdd=(newErrorVector-errorVector)*(1.0f/16.0f);
			lastErrorVectorUpdate=gs->frameNum;
		}
		errorVector+=errorVectorAdd;
		if (predict > 50000) {
			/* to prevent runaway prediction (happens sometimes when a missile is moving *away* from it's target), we may need to disable missiles in case they fly around too long */
			predict = 50000;
		}

		float3 lead = targetUnit->speed * (weaponDef->predictBoost+predictSpeedMod * (1.0f - weaponDef->predictBoost)) * predict;

		if (weaponDef->leadLimit >= 0.0f && lead.Length() > weaponDef->leadLimit + weaponDef->leadBonus * owner->experience) {
			lead *= (weaponDef->leadLimit + weaponDef->leadBonus*owner->experience) / (lead.Length() + 0.01f);
		}

		targetPos = helper->GetUnitErrorPos(targetUnit, owner->allyteam) + lead;
		targetPos += errorVector * (weaponDef->targetMoveError * 30 * targetUnit->speed.Length() * (1.0f - owner->limExperience));
		float appHeight = ground->GetApproximateHeight(targetPos.x, targetPos.z) + 2;

		if (targetPos.y < appHeight)
			targetPos.y = appHeight;

		if (!weaponDef->waterweapon && targetPos.y < 1.0f)
			targetPos.y = 1.0f;
	}

	if (weaponDef->interceptor) {
		CheckIntercept();
	}
	if (targetType != Target_None){
		if (onlyForward) {
			float3 goaldir = targetPos - owner->pos;
			goaldir.Normalize();
			angleGood = (owner->frontdir.dot(goaldir) > maxAngleDif);
		} else if (lastRequestedDir.dot(wantedDir) < maxAngleDif || lastRequest + 15 < gs->frameNum) {
			angleGood=false;
			lastRequestedDir=wantedDir;
			lastRequest=gs->frameNum;

			short int heading=GetHeadingFromVector(wantedDir.x,wantedDir.z);
			short int pitch=(short int) (asin(wantedDir.dot(owner->updir))*(32768/PI));
			std::vector<int> args;
			args.push_back(short(heading - owner->heading));
			args.push_back(pitch);
			owner->cob->Call(COBFN_AimPrimary+weaponNum,args,ScriptCallback,this,0);
		}
	}
	if(weaponDef->stockpile && numStockpileQued){
		float p=1.0f/stockpileTime;
		if(gs->Team(owner->team)->metal>=metalFireCost*p && gs->Team(owner->team)->energy>=energyFireCost*p){
			owner->UseEnergy(energyFireCost*p);
			owner->UseMetal(metalFireCost*p);
			buildPercent+=p;
		} else {
			// update the energy and metal required counts
			gs->Team(owner->team)->energyPull += energyFireCost*p;
			gs->Team(owner->team)->metalPull += metalFireCost*p;
		}
		if(buildPercent>=1){
			const int oldCount = numStockpiled;
			buildPercent=0;
			numStockpileQued--;
			numStockpiled++;
			owner->commandAI->StockpileChanged(this);
			eventHandler.StockpileChanged(owner, this, oldCount);
		}
	}

	if ((salvoLeft == 0)
#ifdef DIRECT_CONTROL_ALLOWED
	    && (!owner->directControl || owner->directControl->mouse1
	                              || owner->directControl->mouse2)
#endif
	    && (targetType != Target_None)
	    && angleGood
	    && subClassReady
	    && (reloadStatus <= gs->frameNum)
	    && (!weaponDef->stockpile || numStockpiled)
	    && (weaponDef->fireSubmersed || (weaponMuzzlePos.y > 0))
	    && ((owner->unitDef->maxFuel == 0) || (owner->currentFuel > 0))
	   )
	{
		if ((weaponDef->stockpile ||
		     (gs->Team(owner->team)->metal >= metalFireCost &&
		      gs->Team(owner->team)->energy >= energyFireCost)))
		{
			std::vector<int> args;
			args.push_back(0);
			owner->cob->Call(COBFN_QueryPrimary + weaponNum, args);
			owner->localmodel->GetEmitDirPos(args[0], relWeaponMuzzlePos, weaponDir);
			weaponMuzzlePos = owner->pos + owner->frontdir * relWeaponMuzzlePos.z +
			                               owner->updir    * relWeaponMuzzlePos.y +
			                               owner->rightdir * relWeaponMuzzlePos.x;
			useWeaponPosForAim = reloadTime / 16 + 8;
			weaponDir = owner->frontdir * weaponDir.z +
			            owner->updir    * weaponDir.y +
			            owner->rightdir * weaponDir.x;
			weaponDir.Normalize();

			if (TryTarget(targetPos,haveUserTarget,targetUnit) && !CobBlockShot(targetUnit)) {
				if(weaponDef->stockpile){
					const int oldCount = numStockpiled;
					numStockpiled--;
					owner->commandAI->StockpileChanged(this);
					eventHandler.StockpileChanged(owner, this, oldCount);
				} else {
					owner->UseEnergy(energyFireCost);
					owner->UseMetal(metalFireCost);
					owner->currentFuel = std::max(0.0f, owner->currentFuel - fuelUsage);
				}
				reloadStatus=gs->frameNum+(int)(reloadTime/owner->reloadSpeed);

				salvoLeft=salvoSize;
				nextSalvo=gs->frameNum;
				salvoError=gs->randVector()*(owner->isMoving?weaponDef->movingAccuracy:accuracy);
				if(targetType==Target_Pos || (targetType==Target_Unit && !(targetUnit->losStatus[owner->allyteam] & LOS_INLOS)))		//area firing stuff is to effective at radar firing...
					salvoError*=1.3f;

				owner->lastMuzzleFlameSize=muzzleFlareSize;
				owner->lastMuzzleFlameDir=wantedDir;
				owner->cob->Call(COBFN_FirePrimary+weaponNum);
			}
		} else {
			// FIXME  -- never reached?
			if (TryTarget(targetPos,haveUserTarget,targetUnit) && !weaponDef->stockpile) {
				// update the energy and metal required counts
				const int minPeriod = std::max(1, (int)(reloadTime / owner->reloadSpeed));
				const float averageFactor = 1.0f / (float)minPeriod;
				gs->Team(owner->team)->energyPull += averageFactor * energyFireCost;
				gs->Team(owner->team)->metalPull += averageFactor * metalFireCost;
			}
		}
	}
	if(salvoLeft && nextSalvo<=gs->frameNum ){
		salvoLeft--;
		nextSalvo=gs->frameNum+salvoDelay;
		owner->lastFireWeapon=gs->frameNum;

		int projectiles = projectilesPerShot;

		while(projectiles > 0) {
			--projectiles;

			// add to the commandShotCount if this is the last salvo,
			// and it is being directed towards the current target
			// (helps when deciding if a queued ground attack order has been completed)
			if ((salvoLeft == 0) && (owner->commandShotCount >= 0) &&
			    ((targetType == Target_Pos) && (targetPos == owner->userAttackPos)) ||
					((targetType == Target_Unit) && (targetUnit == owner->userTarget))) {
				owner->commandShotCount++;
			}

			std::vector<int> args;
			args.push_back(0);

			owner->cob->Call(COBFN_Shot+weaponNum,0);

			owner->cob->Call(COBFN_AimFromPrimary+weaponNum,args);
			relWeaponPos=owner->localmodel->GetPiecePos(args[0]);

			owner->cob->Call(/*COBFN_AimFromPrimary+weaponNum*/COBFN_QueryPrimary+weaponNum/**/,args);
			owner->localmodel->GetEmitDirPos(args[0], relWeaponMuzzlePos, weaponDir);

			weaponPos=owner->pos+owner->frontdir*relWeaponPos.z+owner->updir*relWeaponPos.y+owner->rightdir*relWeaponPos.x;

			weaponMuzzlePos=owner->pos+owner->frontdir*relWeaponMuzzlePos.z+owner->updir*relWeaponMuzzlePos.y+owner->rightdir*relWeaponMuzzlePos.x;
			weaponDir = owner->frontdir * weaponDir.z + owner->updir * weaponDir.y + owner->rightdir * weaponDir.x;
			weaponDir.Normalize();

	//		logOutput.Print("RelPosFire %f %f %f",relWeaponPos.x,relWeaponPos.y,relWeaponPos.z);

			if (owner->unitDef->decloakOnFire && (owner->scriptCloak <= 2)) {
				if (owner->isCloaked) {
					owner->isCloaked = false;
					eventHandler.UnitDecloaked(owner);
				}
				owner->curCloakTimeout = gs->frameNum + owner->cloakTimeout;
			}

			Fire();
		}

		//Rock the unit in the direction of the fireing
		float3 rockDir = wantedDir;
		rockDir.y = 0;
		rockDir = -rockDir.Normalize();
		std::vector<int> rockAngles;
		rockAngles.push_back((int)(500 * rockDir.z));
		rockAngles.push_back((int)(500 * rockDir.x));
		owner->cob->Call(COBFN_RockUnit,  rockAngles);

		owner->commandAI->WeaponFired(this);

		if(salvoLeft==0){
			owner->cob->Call(COBFN_EndBurst+weaponNum);
		}
#ifdef TRACE_SYNC
	tracefile << "Weapon fire: ";
	tracefile << weaponPos.x << " " << weaponPos.y << " " << weaponPos.z << " " << targetPos.x << " " << targetPos.y << " " << targetPos.z << "\n";
#endif
	}
}
예제 #25
0
void CMobileCAI::ExecuteAttack(Command &c)
{
	assert(owner->unitDef->canAttack);

	// limit how far away we fly based on our movestate
	if (tempOrder && orderTarget) {
		const float3& closestPos = ClosestPointOnLine(commandPos1, commandPos2, owner->pos);
		const float curTargetDist = LinePointDist(closestPos, commandPos2, orderTarget->pos);
		const float maxTargetDist = (500 * owner->moveState + owner->maxRange);

		if (owner->moveState < MOVESTATE_ROAM && curTargetDist > maxTargetDist) {
			StopMove();
			FinishCommand();
			return;
		}
	}

	// check if we are in direct command of attacker
	if (!inCommand) {
		if (c.params.size() == 1) {
			CUnit* targetUnit = unitHandler->GetUnit(c.params[0]);

			// check if we have valid target parameter and that we aren't attacking ourselves
			if (targetUnit == NULL) { StopMove(); FinishCommand(); return; }
			if (targetUnit == owner) { StopMove(); FinishCommand(); return; }
			if (targetUnit->GetTransporter() != NULL && !modInfo.targetableTransportedUnits) {
				StopMove(); FinishCommand(); return;
			}

			const float3 tgtErrPos = targetUnit->pos + owner->posErrorVector * 128;
			const float3 tgtPosDir = (tgtErrPos - owner->pos).Normalize();

			SetGoal(tgtErrPos - tgtPosDir * targetUnit->radius, owner->pos);
			SetOrderTarget(targetUnit);
			owner->AttackUnit(targetUnit, (c.options & INTERNAL_ORDER) == 0, c.GetID() == CMD_MANUALFIRE);

			inCommand = true;
		}
		else if (c.params.size() >= 3) {
			// user gave force-fire attack command
			SetGoal(c.GetPos(0), owner->pos);

			inCommand = true;
		}
	}

	// if our target is dead or we lost it then stop attacking
	// NOTE: unit should actually just continue to target area!
	if (targetDied || (c.params.size() == 1 && UpdateTargetLostTimer(int(c.params[0])) == 0)) {
		// cancel keeppointingto
		StopMove();
		FinishCommand();
		return;
	}


	// user clicked on enemy unit (note that we handle aircrafts slightly differently)
	if (orderTarget != NULL) {
		bool tryTargetRotate  = false;
		bool tryTargetHeading = false;

		float edgeFactor = 0.0f; // percent offset to target center
		const float3 targetMidPosVec = owner->midPos - orderTarget->midPos;

		const float targetGoalDist = (orderTarget->pos + owner->posErrorVector * 128.0f).SqDistance2D(goalPos);
		const float targetPosDist = Square(10.0f + orderTarget->pos.distance2D(owner->pos) * 0.2f);
		const float minPointingDist = std::min(1.0f * owner->losRadius * loshandler->losDiv, owner->maxRange * 0.9f);

		// FIXME? targetMidPosMaxDist is 3D, but compared with a 2D value
		const float targetMidPosDist2D = targetMidPosVec.Length2D();
		//const float targetMidPosMaxDist = owner->maxRange - (orderTarget->speed.SqLength() / owner->unitDef->maxAcc);

		if (!owner->weapons.empty()) {
			if (!(c.options & ALT_KEY) && SkipParalyzeTarget(orderTarget)) {
				StopMove();
				FinishCommand();
				return;
			}
		}

		for (unsigned int wNum = 0; wNum < owner->weapons.size(); wNum++) {
			CWeapon* w = owner->weapons[wNum];

			if (c.GetID() == CMD_MANUALFIRE) {
				assert(owner->unitDef->canManualFire);

				if (!w->weaponDef->manualfire) {
					continue;
				}
			}

			tryTargetRotate  = w->TryTargetRotate(orderTarget, (c.options & INTERNAL_ORDER) == 0);
			tryTargetHeading = w->TryTargetHeading(GetHeadingFromVector(-targetMidPosVec.x, -targetMidPosVec.z), orderTarget->pos, orderTarget != NULL, orderTarget);

			if (tryTargetRotate || tryTargetHeading)
				break;

			edgeFactor = math::fabs(w->targetBorder);
		}


		// if w->AttackUnit() returned true then we are already
		// in range with our biggest (?) weapon, so stop moving
		// also make sure that we're not locked in close-in/in-range state loop
		// due to rotates invoked by in-range or out-of-range states
		if (tryTargetRotate) {
			const bool canChaseTarget = (!tempOrder || owner->moveState != MOVESTATE_HOLDPOS);
			const bool targetBehind = (targetMidPosVec.dot(orderTarget->speed) < 0.0f);

			if (canChaseTarget && tryTargetHeading && targetBehind) {
				SetGoal(owner->pos + (orderTarget->speed * 80), owner->pos, SQUARE_SIZE, orderTarget->speed.Length() * 1.1f);
			} else {
				StopMove();

				if (gs->frameNum > lastCloseInTry + MAX_CLOSE_IN_RETRY_TICKS) {
					owner->moveType->KeepPointingTo(orderTarget->midPos, minPointingDist, true);
				}
			}

			owner->AttackUnit(orderTarget, (c.options & INTERNAL_ORDER) == 0, c.GetID() == CMD_MANUALFIRE);
		}

		// if we're on hold pos in a temporary order, then none of the close-in
		// code below should run, and the attack command is cancelled.
		else if (tempOrder && owner->moveState == MOVESTATE_HOLDPOS) {
			StopMove();
			FinishCommand();
			return;
		}

		// if ((our movetype has type HoverAirMoveType and length of 2D vector from us to target
		// less than 90% of our maximum range) OR squared length of 2D vector from us to target
		// less than 1024) then we are close enough
		else if (targetMidPosDist2D < (owner->maxRange * 0.9f)) {
			if (dynamic_cast<CHoverAirMoveType*>(owner->moveType) != NULL || (targetMidPosVec.SqLength2D() < 1024)) {
				StopMove();
				owner->moveType->KeepPointingTo(orderTarget->midPos, minPointingDist, true);
			}

			// if (((first weapon range minus first weapon length greater than distance to target)
			// and length of 2D vector from us to target less than 90% of our maximum range)
			// then we are close enough, but need to move sideways to get a shot.
			//assumption is flawed: The unit may be aiming or otherwise unable to shoot
			else if (owner->unitDef->strafeToAttack && targetMidPosDist2D < (owner->maxRange * 0.9f)) {
				moveDir ^= (owner->moveType->progressState == AMoveType::Failed);

				const float sin = moveDir ? 3.0/5 : -3.0/5;
				const float cos = 4.0 / 5;

				float3 goalDiff;
				goalDiff.x = targetMidPosVec.dot(float3(cos, 0, -sin));
				goalDiff.z = targetMidPosVec.dot(float3(sin, 0,  cos));
				goalDiff *= (targetMidPosDist2D < (owner->maxRange * 0.3f)) ? 1/cos : cos;
				goalDiff += orderTarget->pos;
				SetGoal(goalDiff, owner->pos);
			}
		}

		// if 2D distance of (target position plus attacker error vector times 128)
		// to goal position greater than
		// (10 plus 20% of 2D distance between attacker and target) then we need to close
		// in on target more
		else if (targetGoalDist > targetPosDist) {
			// if the target isn't in LOS, go to its approximate position
			// otherwise try to go precisely to the target
			// this should fix issues with low range weapons (mainly melee)
			const float3 errPos = ((orderTarget->losStatus[owner->allyteam] & LOS_INLOS)? ZeroVector: owner->posErrorVector * 128.0f);
			const float3 tgtPos = orderTarget->pos + errPos;

			const float3 norm = (tgtPos - owner->pos).Normalize();
			const float3 goal = tgtPos - norm * (orderTarget->radius * edgeFactor * 0.8f);

			SetGoal(goal, owner->pos);

			if (lastCloseInTry < gs->frameNum + MAX_CLOSE_IN_RETRY_TICKS)
				lastCloseInTry = gs->frameNum;
		}
	}

	// user wants to attack the ground; cycle through our
	// weapons until we find one that can accomodate him
	else if (c.params.size() >= 3) {
		const float3 attackPos = c.GetPos(0);
		const float3 attackVec = attackPos - owner->pos;

		bool foundWeapon = false;

		for (unsigned int wNum = 0; wNum < owner->weapons.size(); wNum++) {
			CWeapon* w = owner->weapons[wNum];

			if (foundWeapon)
				break;

			// XXX HACK - special weapon overrides any checks
			if (c.GetID() == CMD_MANUALFIRE) {
				assert(owner->unitDef->canManualFire);

				if (!w->weaponDef->manualfire)
					continue;
				if (attackVec.SqLength() >= (w->range * w->range))
					continue;

				StopMove();
				owner->AttackGround(attackPos, (c.options & INTERNAL_ORDER) == 0, c.GetID() == CMD_MANUALFIRE);
				owner->moveType->KeepPointingTo(attackPos, owner->maxRange * 0.9f, true);

				foundWeapon = true;
			} else {
				// NOTE:
				//   we call TryTargetHeading which is less restrictive than TryTarget
				//   (eg. the former succeeds even if the unit has not already aligned
				//   itself with <attackVec>)
				if (w->TryTargetHeading(GetHeadingFromVector(attackVec.x, attackVec.z), attackPos, (c.options & INTERNAL_ORDER) == 0, NULL)) {
					if (w->TryTargetRotate(attackPos, (c.options & INTERNAL_ORDER) == 0)) {
						StopMove();
						owner->AttackGround(attackPos, (c.options & INTERNAL_ORDER) == 0, c.GetID() == CMD_MANUALFIRE);

						foundWeapon = true;
					}

					// for gunships, this pitches the nose down such that
					// TryTargetRotate (which also checks range for itself)
					// has a bigger chance of succeeding
					//
					// hence it must be called as soon as we get in range
					// and may not depend on what TryTargetRotate returns
					// (otherwise we might never get a firing solution)
					owner->moveType->KeepPointingTo(attackPos, owner->maxRange * 0.9f, true);
				}
			}
		}

		#if 0
		// no weapons --> no need to stop at an arbitrary distance?
		else if (diff.SqLength2D() < 1024) {
			StopMove();
			owner->moveType->KeepPointingTo(attackPos, owner->maxRange * 0.9f, true);
		}
		#endif

		// if we are unarmed and more than 10 elmos distant
		// from target position, then keeping moving closer
		if (owner->weapons.empty() && attackPos.SqDistance2D(goalPos) > 100) {
			SetGoal(attackPos, owner->pos);
		}
	}
예제 #26
0
void CFactory::Update()
{
	if(beingBuilt){
		CUnit::Update();
		return;
	}

	if(quedBuild && inBuildStance){
		std::vector<long> args;
		args.push_back(0);
		cob->Call("QueryBuildInfo",args);
		float3 relBuildPos=localmodel->GetPiecePos(args[0]);
		float3 buildPos=pos + frontdir*relBuildPos.z + updir*relBuildPos.y + rightdir*relBuildPos.x;

		bool canBuild=true;
		std::vector<CUnit*> units=qf->GetUnitsExact(buildPos,16);
		for(std::vector<CUnit*>::iterator ui=units.begin();ui!=units.end();++ui){
			if((*ui)!=this)
				canBuild=false;
		}
		if(canBuild){
			quedBuild=false;
			CUnit* b=unitLoader.LoadUnit(nextBuild,buildPos+float3(0.01,0.01,0.01),team,true);
			AddDeathDependence(b);
			curBuild=b;

			cob->Call("StartBuilding");

			if(unitDef->sounds.build.id)
				sound->PlaySound(unitDef->sounds.build.id, pos, unitDef->sounds.build.volume);
		} else {
			helper->BuggerOff(buildPos-float3(0.01,0,0.02),radius+8);
		}
	}

	if(curBuild && !beingBuilt){
		lastBuild=gs->frameNum;

		std::vector<long> args;
		args.push_back(0);
		cob->Call("QueryBuildInfo",args);
		CMatrix44f mat=localmodel->GetPieceMatrix(args[0]);
		int h=GetHeadingFromVector(mat[2],mat[10]);
		curBuild->heading=h;
//		if(curBuild->unitDef->canfly){	//hack to get naval air plant to work correctly, how to do it correctly ?
			float3 relBuildPos=localmodel->GetPiecePos(args[0]);
			float3 buildPos=pos + frontdir*relBuildPos.z + updir*relBuildPos.y + rightdir*relBuildPos.x;
			curBuild->pos=buildPos;
			if(curBuild->floatOnWater)
				curBuild->pos.y=ground->GetHeight(buildPos.x,buildPos.z)-curBuild->unitDef->waterline;
			curBuild->midPos=curBuild->pos+UpVector*curBuild->relMidPos.y;
//		}
		if(curBuild->AddBuildPower(buildSpeed,this)){
			std::vector<long> args;
			args.push_back(0);
			cob->Call("QueryNanoPiece",args);
			float3 relWeaponFirePos=localmodel->GetPiecePos(args[0]);
			float3 weaponPos=pos + frontdir*relWeaponFirePos.z + updir*relWeaponFirePos.y + rightdir*relWeaponFirePos.x;

			float3 dif=curBuild->midPos-weaponPos;
			float l=dif.Length();
			dif/=l;
			dif+=gs->randVector()*0.15f;

			new CGfxProjectile(weaponPos,dif,l,float3(0.2f,0.7f,0.2f));
		} else {
			if(!curBuild->beingBuilt){
				if(group)
					curBuild->SetGroup(group);
				Command c;
				c.id=CMD_MOVE_STATE;
				c.options=0;
				c.params.push_back(moveState);
				curBuild->commandAI->GiveCommand(c);
				c.params.clear();
				c.id=CMD_FIRE_STATE;
				c.params.push_back(fireState);
				curBuild->commandAI->GiveCommand(c);
				if(curBuild->commandAI->commandQue.empty() || (dynamic_cast<CMobileCAI*>(curBuild->commandAI) && ((CMobileCAI*)curBuild->commandAI)->unimportantMove)){
					if(((CFactoryCAI*)commandAI)->newUnitCommands.empty()){
						SendToEmptySpot(curBuild);
					} else {
						for(std::deque<Command>::iterator ci=((CFactoryCAI*)commandAI)->newUnitCommands.begin();ci!=((CFactoryCAI*)commandAI)->newUnitCommands.end();++ci)
							curBuild->commandAI->GiveCommand(*ci);
					}
				}
				StopBuild();
			}
		}
	}

	if(lastBuild+200 < gs->frameNum && !quedBuild && opening && uh->CanCloseYard(this)){
		readmap->CloseBlockingYard(this);
		opening=false;
		cob->Call(COBFN_Deactivate);
	}
	CBuilding::Update();
}
예제 #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;
    }
}
예제 #28
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;
		}
	}
}
예제 #29
0
파일: Factory.cpp 프로젝트: eXLabT/spring
void CFactory::Update()
{
	if (beingBuilt) {
		// factory under construction
		CUnit::Update();
		return;
	}

	if (quedBuild && !opening && !stunned) {
		script->Activate();
		groundBlockingObjectMap->OpenBlockingYard(this, curYardMap);
		opening = true;
	}

	if (quedBuild && inBuildStance && !stunned) {
		// start building a unit
		const float3        buildPos = CalcBuildPos();
		const CSolidObject* solidObj = groundBlockingObjectMap->GroundBlocked(buildPos);

		if (solidObj == NULL || (dynamic_cast<const CUnit*>(solidObj) == this)) {
			quedBuild = false;
			CUnit* b = unitLoader.LoadUnit(nextBuild, buildPos + float3(0.01f, 0.01f, 0.01f), team,
											true, buildFacing, this);

			if (!unitDef->canBeAssisted) {
				b->soloBuilder = this;
				b->AddDeathDependence(this);
			}

			AddDeathDependence(b);
			curBuild = b;

			script->StartBuilding();

			int soundIdx = unitDef->sounds.build.getRandomIdx();
			if (soundIdx >= 0) {
				Channels::UnitReply.PlaySample(
					unitDef->sounds.build.getID(soundIdx), pos,
					unitDef->sounds.build.getVolume(0));
			}
		} else {
			helper->BuggerOff(buildPos - float3(0.01f, 0, 0.02f), radius + 8, true, true, NULL);
		}
	}


	if (curBuild && !beingBuilt) {
		if (!stunned) {
			// factory not under construction and
			// nanolathing unit: continue building
			lastBuild = gs->frameNum;

			// buildPiece is the rotating platform
			const int buildPiece = GetBuildPiece();
			const CMatrix44f& mat = script->GetPieceMatrix(buildPiece);
			const int h = GetHeadingFromVector(mat[2], mat[10]); //! x.z, z.z

			// rotate unit nanoframe with platform
			curBuild->heading = (h + GetHeadingFromFacing(buildFacing)) & 65535;

			const float3 buildPos = CalcBuildPos(buildPiece);
			curBuild->pos = buildPos;

			if (curBuild->floatOnWater) {
				float waterline = ground->GetHeight(buildPos.x, buildPos.z) - curBuild->unitDef->waterline;
				if (waterline > curBuild->pos.y)
					curBuild->pos.y = waterline;
			}
			curBuild->midPos = curBuild->pos + (UpVector * curBuild->relMidPos.y);

			const CCommandQueue& queue = commandAI->commandQue;

			if(!queue.empty() && (queue.front().id == CMD_WAIT)) {
				curBuild->AddBuildPower(0, this);
			} else {
				if (curBuild->AddBuildPower(buildSpeed, this)) {
					CreateNanoParticle();
				}
			}
		}

		if (!curBuild->beingBuilt &&
				(!unitDef->fullHealthFactory ||
						(curBuild->health >= curBuild->maxHealth)))
		{
			if (group && curBuild->group == 0) {
				curBuild->SetGroup(group);
			}

			bool userOrders = true;
			if (curBuild->commandAI->commandQue.empty() ||
					(dynamic_cast<CMobileCAI*>(curBuild->commandAI) &&
					 ((CMobileCAI*)curBuild->commandAI)->unimportantMove)) {
				userOrders = false;

				AssignBuildeeOrders(curBuild);
				waitCommandsAI.AddLocalUnit(curBuild, this);
			}
			eventHandler.UnitFromFactory(curBuild, this, userOrders);

			StopBuild();
		}
	}

	if (((lastBuild + 200) < gs->frameNum) && !stunned &&
	    !quedBuild && opening && groundBlockingObjectMap->CanCloseYard(this)) {
		// close the factory after inactivity
		groundBlockingObjectMap->CloseBlockingYard(this, curYardMap);
		opening = false;
		script->Deactivate();
	}

	CBuilding::Update();
}
예제 #30
0
/**
* @brief Causes this CMobileCAI to execute the attack order c
*/
void CMobileCAI::ExecuteAttack(Command &c)
{
	assert(owner->unitDef->canAttack);

	// limit how far away we fly
	if (tempOrder && (owner->moveState < 2) && orderTarget
			&& LinePointDist(ClosestPointOnLine(commandPos1, commandPos2, owner->pos),
					commandPos2, orderTarget->pos)
			> (500 * owner->moveState + owner->maxRange)) {
		StopMove();
		FinishCommand();
		return;
	}

	// check if we are in direct command of attacker
	if (!inCommand) {
		// don't start counting until the owner->AttackGround() order is given
		owner->commandShotCount = -1;

		if (c.params.size() == 1) {
			CUnit* targetUnit = uh->GetUnit(c.params[0]);

			// check if we have valid target parameter and that we aren't attacking ourselves
			if (targetUnit != NULL && targetUnit != owner) {
				float3 fix = targetUnit->pos + owner->posErrorVector * 128;
				float3 diff = float3(fix - owner->pos).Normalize();

				SetGoal(fix - diff * targetUnit->radius, owner->pos);

				orderTarget = targetUnit;
				AddDeathDependence(orderTarget);
				inCommand = true;
			} else {
				// unit may not fire on itself, cancel order
				StopMove();
				FinishCommand();
				return;
			}
		}
		else if (c.params.size() >= 3) {
			// user gave force-fire attack command
			float3 pos(c.params[0], c.params[1], c.params[2]);
			SetGoal(pos, owner->pos);
			inCommand = true;
		}
	}
	else if ((c.params.size() == 3) && (owner->commandShotCount > 0) && (commandQue.size() > 1)) {
		// the trailing CMD_SET_WANTED_MAX_SPEED in a command pair does not count
		if ((commandQue.size() > 2) || (commandQue.back().id != CMD_SET_WANTED_MAX_SPEED)) {
			StopMove();
			FinishCommand();
			return;
		}
	}

	// if our target is dead or we lost it then stop attacking
	// NOTE: unit should actually just continue to target area!
	if (targetDied || (c.params.size() == 1 && UpdateTargetLostTimer(int(c.params[0])) == 0)) {
		// cancel keeppointingto
		StopMove();
		FinishCommand();
		return;
	}


	// user clicked on enemy unit (note that we handle aircrafts slightly differently)
	if (orderTarget) {
		//bool b1 = owner->AttackUnit(orderTarget, c.id == CMD_DGUN);
		bool b2 = false;
		bool b3 = false;
		bool b4 = false;
		float edgeFactor = 0.f; // percent offset to target center
		float3 diff = owner->pos - orderTarget->midPos;

		if (owner->weapons.size() > 0) {
			if (!(c.options & ALT_KEY) && SkipParalyzeTarget(orderTarget)) {
				StopMove();
				FinishCommand();
				return;
			}
			CWeapon* w = owner->weapons.front();
			// if we have at least one weapon then check if we
			// can hit target with our first (meanest) one
			b2 = w->TryTargetRotate(orderTarget, c.id == CMD_DGUN);
			b3 = Square(w->range - (w->relWeaponPos).Length())
					> (orderTarget->pos.SqDistance(owner->pos));
			b4 = w->TryTargetHeading(GetHeadingFromVector(-diff.x, -diff.z),
					orderTarget->pos, orderTarget != NULL, orderTarget);
			edgeFactor = fabs(w->targetBorder);
		}

		float diffLength2d = diff.Length2D();

		// if w->AttackUnit() returned true then we are already
		// in range with our biggest weapon so stop moving
		// also make sure that we're not locked in close-in/in-range state loop
		// due to rotates invoked by in-range or out-of-range states
		if (b2) {
			if (!(tempOrder && owner->moveState == 0)
				&& (diffLength2d * 1.4f > owner->maxRange
					- orderTarget->speed.SqLength()
							/ owner->unitDef->maxAcc)
				&& b4 && diff.dot(orderTarget->speed) < 0)
			{
				SetGoal(owner->pos + (orderTarget->speed * 80), owner->pos,
						SQUARE_SIZE, orderTarget->speed.Length() * 1.1f);
			} else {
				StopMove();
				// FIXME kill magic frame number
				if (gs->frameNum > lastCloseInTry + MAX_CLOSE_IN_RETRY_TICKS) {
					owner->moveType->KeepPointingTo(orderTarget->midPos,
							std::min((float) owner->losRadius * loshandler->losDiv,
								owner->maxRange * 0.9f), true);
				}
			}
			owner->AttackUnit(orderTarget, c.id == CMD_DGUN);
		}

		// if we're on hold pos in a temporary order, then none of the close-in
		// code below should run, and the attack command is cancelled.
		else if (tempOrder && owner->moveState == 0) {
			StopMove();
			FinishCommand();
			return;
		}

		// if ((our movetype has type TAAirMoveType and length of 2D vector from us to target
		// less than 90% of our maximum range) OR squared length of 2D vector from us to target
		// less than 1024) then we are close enough
		else if(diffLength2d < (owner->maxRange * 0.9f)){
			if (dynamic_cast<CTAAirMoveType*>(owner->moveType)
					|| (diff.SqLength2D() < 1024))
			{
				StopMove();
				owner->moveType->KeepPointingTo(orderTarget->midPos,
						std::min((float) owner->losRadius * loshandler->losDiv,
							owner->maxRange * 0.9f), true);
			}

			// if (((first weapon range minus first weapon length greater than distance to target)
			// and length of 2D vector from us to target less than 90% of our maximum range)
			// then we are close enough, but need to move sideways to get a shot.
			//assumption is flawed: The unit may be aiming or otherwise unable to shoot
			else if (owner->unitDef->strafeToAttack && b3 && diffLength2d < (owner->maxRange * 0.9f))
			{
				moveDir ^= (owner->moveType->progressState == AMoveType::Failed);
				float sin = moveDir ? 3.0/5 : -3.0/5;
				float cos = 4.0/5;
				float3 goalDiff(0, 0, 0);
				goalDiff.x = diff.dot(float3(cos, 0, -sin));
				goalDiff.z = diff.dot(float3(sin, 0, cos));
				goalDiff *= (diffLength2d < (owner->maxRange * 0.3f)) ? 1/cos : cos;
				goalDiff += orderTarget->pos;
				SetGoal(goalDiff, owner->pos);
			}
		}

		// if 2D distance of (target position plus attacker error vector times 128)
		// to goal position greater than
		// (10 plus 20% of 2D distance between attacker and target) then we need to close
		// in on target more
		else if ((orderTarget->pos + owner->posErrorVector * 128).SqDistance2D(goalPos)
				> Square(10 + orderTarget->pos.distance2D(owner->pos) * 0.2f)) {
			// if the target isn't in LOS, go to its approximate position
			// otherwise try to go precisely to the target
			// this should fix issues with low range weapons (mainly melee)
			float3 fix = orderTarget->pos +
					(orderTarget->losStatus[owner->allyteam] & LOS_INLOS ?
						float3(0.f,0.f,0.f) :
						owner->posErrorVector * 128);
			float3 norm = float3(fix - owner->pos).Normalize();
			float3 goal = fix - norm*(orderTarget->radius*edgeFactor*0.8f);
			SetGoal(goal, owner->pos);
			if (lastCloseInTry < gs->frameNum + MAX_CLOSE_IN_RETRY_TICKS)
				lastCloseInTry = gs->frameNum;
		}
	}

	// user is attacking ground
	else if (c.params.size() >= 3) {
		const float3 pos(c.params[0], c.params[1], c.params[2]);
		const float3 diff = owner->pos - pos;

		if (owner->weapons.size() > 0) {
			// if we have at least one weapon then check if
			// we can hit position with our first (assumed
			// to be meanest) one
			CWeapon* w = owner->weapons.front();

			// XXX hack - dgun overrides any checks
			if (c.id == CMD_DGUN) {
				float rr = owner->maxRange * owner->maxRange;

				for (vector<CWeapon*>::iterator it = owner->weapons.begin();
						it != owner->weapons.end(); ++it) {

					if (dynamic_cast<CDGunWeapon*>(*it))
						rr = (*it)->range * (*it)->range;
				}

				if (diff.SqLength() < rr) {
					StopMove();
					owner->AttackGround(pos, c.id == CMD_DGUN);
					owner->moveType->KeepPointingTo(pos, owner->maxRange * 0.9f, true);
				}
			} else {
				const bool inAngle = w->TryTargetRotate(pos, c.id == CMD_DGUN);
				const bool inRange = diff.SqLength2D() < Square(w->range - (w->relWeaponPos).Length2D());

				if (inAngle || inRange) {
					StopMove();
					owner->AttackGround(pos, c.id == CMD_DGUN);
					owner->moveType->KeepPointingTo(pos, owner->maxRange * 0.9f, true);
				}
			}
		}

		else if (diff.SqLength2D() < 1024) {
			StopMove();
			owner->moveType->KeepPointingTo(pos, owner->maxRange * 0.9f, true);
		}

		// if we are more than 10 units distant from target position then keeping moving closer
		else if (pos.SqDistance2D(goalPos) > 100) {
			SetGoal(pos, owner->pos);
		}
	}
}