mobilecai.cpp

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

CPP
1,090
字号
		case CMD_SET_WANTED_MAX_SPEED:	{ ExecuteSetWantedMaxSpeed(c); return; }
		case CMD_MOVE:      { ExecuteMove(c);	     return; }
		case CMD_PATROL:    { ExecutePatrol(c);		 return; }
		case CMD_FIGHT:     { ExecuteFight(c);		 return; }
		case CMD_GUARD:     { ExecuteGuard(c);		 return; }
		case CMD_LOAD_ONTO: { ExecuteLoadUnits(c); return; }
		default: {
		  CCommandAI::SlowUpdate();
		  return;
		}
	}
}

/**
* @brief executes the set wanted max speed command
*/
void CMobileCAI::ExecuteSetWantedMaxSpeed(Command &c)
{
	if (repeatOrders && (commandQue.size() >= 2) &&
			(commandQue.back().id != CMD_SET_WANTED_MAX_SPEED)) {
		commandQue.push_back(commandQue.front());
	}
	FinishCommand();
	SlowUpdate();
	return;
}

/**
* @brief executes the move command
*/
void CMobileCAI::ExecuteMove(Command &c)
{
	float3 pos = float3(c.params[0], c.params[1], c.params[2]);
	if(pos != goalPos){
		SetGoal(pos, owner->pos);
	}
	if((owner->pos - goalPos).SqLength2D() < cancelDistance ||
			owner->moveType->progressState == CMoveType::Failed){
		FinishCommand();
	}
	return;
}

void CMobileCAI::ExecuteLoadUnits(Command &c){
	CTransportUnit* tran = dynamic_cast<CTransportUnit*>(uh->units[(int)c.params[0]]);
	if(!tran){
		FinishCommand();
		return;
	}
	if(!inCommand){
		inCommand ^= true;
		Command newCommand;
		newCommand.id = CMD_LOAD_UNITS;
		newCommand.params.push_back(owner->id);
		newCommand.options = INTERNAL_ORDER | SHIFT_KEY;
		tran->commandAI->GiveCommandReal(newCommand);
	}
	if(owner->transporter) {
		FinishCommand();
		return;
	}
	CUnit *unit = uh->units[(int)c.params[0]];
	if (!unit) {
		return;
	}
	float3 pos = unit->pos;
	if((pos - goalPos).SqLength2D() > cancelDistance){
		SetGoal(pos, owner->pos);
	}
	if((owner->pos - goalPos).SqLength2D() < cancelDistance){
		StopMove();
	}
	if(owner->moveType->progressState == CMoveType::Failed){
	}
	return;
}

/**
* @brief Executes the Patrol command c
*/
void CMobileCAI::ExecutePatrol(Command &c)
{
	assert(owner->unitDef->canPatrol);
	assert(c.params.size() >= 3);
	Command temp;
	temp.id = CMD_FIGHT;
	temp.params.push_back(c.params[0]);
	temp.params.push_back(c.params[1]);
	temp.params.push_back(c.params[2]);
	temp.options = c.options | INTERNAL_ORDER;
	commandQue.push_back(c);
	commandQue.pop_front();
	commandQue.push_front(temp);
	if(owner->group){
		owner->group->CommandFinished(owner->id, CMD_PATROL);
	}
	ExecuteFight(temp);
	return;
}

/**
* @brief Executes the Fight command c
*/
void CMobileCAI::ExecuteFight(Command &c)
{
	assert((c.options & INTERNAL_ORDER) || owner->unitDef->canFight);
	if(c.params.size() == 1) {
		if(orderTarget && owner->weapons.size() > 0
				&& !owner->weapons.front()->AttackUnit(orderTarget, false)) {
			CUnit* newTarget = helper->GetClosestEnemyUnit(
				owner->pos, owner->maxRange, owner->allyteam);
			if(owner->weapons.front()->AttackUnit(newTarget, false)) {
				c.params[0] = newTarget->id;
				inCommand = false;
			} else {
				owner->weapons.front()->AttackUnit(orderTarget, false);
			}
		}
		ExecuteAttack(c);
		return;
	}
	if(tempOrder){
		inCommand = true;
		tempOrder = false;
	}
	if(c.params.size()<3){		//this shouldnt happen but anyway ...
		logOutput.Print("Error: got fight cmd with less than 3 params on %s in mobilecai",
			owner->unitDef->humanName.c_str());
		return;
	}
	if(c.params.size() >= 6){
		if(!inCommand){
			commandPos1 = float3(c.params[3],c.params[4],c.params[5]);
		}
	} else {
		// Some hackery to make sure the line (commandPos1,commandPos2) is NOT
		// rotated (only shortened) if we reach this because the previous return
		// fight command finished by the 'if((curPos-pos).SqLength2D()<(64*64)){'
		// condition, but is actually updated correctly if you click somewhere
		// outside the area close to the line (for a new command).
		commandPos1 = ClosestPointOnLine(commandPos1, commandPos2, owner->pos);
		if ((owner->pos - commandPos1).SqLength2D() > (96 * 96)) {
			commandPos1 = owner->pos;
		}
	}
	float3 pos(c.params[0],c.params[1],c.params[2]);
	if(!inCommand){
		inCommand = true;
		commandPos2 = pos;
		lastUserGoal = commandPos2;
	}
	if(c.params.size() >= 6){
		pos = ClosestPointOnLine(commandPos1, commandPos2, owner->pos);
	}
	if(pos!=goalPos){
		SetGoal(pos, owner->pos);
	}

	if(owner->unitDef->canAttack && owner->fireState>=2){
		float3 curPosOnLine = ClosestPointOnLine(commandPos1, commandPos2, owner->pos);
		CUnit* enemy=helper->GetClosestEnemyUnit(
			curPosOnLine, owner->maxRange + 100 * owner->moveState * owner->moveState,
			owner->allyteam);
		if(enemy && (owner->hasUWWeapons || !enemy->isUnderWater)
				&& !(owner->unitDef->noChaseCategory & enemy->category)
				&& !owner->weapons.empty()
				&& !enemy->neutral){
			Command c2;
			c2.id=CMD_FIGHT;
			c2.options=c.options|INTERNAL_ORDER;
			c2.params.push_back(enemy->id);
			PushOrUpdateReturnFight();
			commandQue.push_front(c2);
			inCommand=false;
			tempOrder=true;
			if(lastPC!=gs->frameNum){	//avoid infinite loops
				lastPC=gs->frameNum;
				SlowUpdate();
			}
			return;
		}
	}
	if((owner->pos - goalPos).SqLength2D() < (64 * 64)
			|| (owner->moveType->progressState == CMoveType::Failed)){
		FinishCommand();
	}
	return;
}

/**
* @brief Executes the guard command c
*/
void CMobileCAI::ExecuteGuard(Command &c)
{
	assert(owner->unitDef->canGuard);
	assert(!c.params.empty());
	if(int(c.params[0]) >= 0 && uh->units[int(c.params[0])] != NULL
			&& UpdateTargetLostTimer(int(c.params[0]))){
		CUnit* guarded = uh->units[int(c.params[0])];
		if(owner->unitDef->canAttack && guarded->lastAttacker
				&& guarded->lastAttack + 40 < gs->frameNum
				&& (owner->hasUWWeapons || !guarded->lastAttacker->isUnderWater)){
			StopSlowGuard();
			Command nc;
			nc.id=CMD_ATTACK;
			nc.params.push_back(guarded->lastAttacker->id);
			nc.options = c.options;
			commandQue.push_front(nc);
			SlowUpdate();
			return;
		} else {
			//float3 dif = guarded->speed * guarded->frontdir;
			float3 dif = guarded->pos - owner->pos;
			dif.Normalize();
			float3 goal = guarded->pos - dif * (guarded->radius + owner->radius + 64);
			if((goalPos - goal).SqLength2D() > 1600
					|| (goalPos - owner->pos).SqLength2D()
						< (owner->maxSpeed*30 + 1 + SQUARE_SIZE*2)
						 * (owner->maxSpeed*30 + 1 + SQUARE_SIZE*2)){
				SetGoal(goal, owner->pos);
			}
			if((goal - owner->pos).SqLength2D() < 6400) {
				StartSlowGuard(guarded->maxSpeed);
				if((goal-owner->pos).SqLength2D() < 1800){
					StopMove();
					NonMoving();
				}
			} else {
				StopSlowGuard();
			}
		}
	} else {
		FinishCommand();
	}
	return;
}

/**
* @brief Executes the stop command c
*/
void CMobileCAI::ExecuteStop(Command &c)
{
	StopMove();
	return CCommandAI::ExecuteStop(c);
}

/**
* @brief Executes the DGun command c
*/
void CMobileCAI::ExecuteDGun(Command &c)
{
	if(uh->limitDgun && owner->unitDef->isCommander
			&& owner->pos.distance(gs->Team(owner->team)->startPos)>uh->dgunRadius){
		StopMove();
		return FinishCommand();
	}
	ExecuteAttack(c);
}




/**
* @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) {
			int unitID = int(c.params[0]);

			// check if we have valid target parameter and that we aren't attacking ourselves
			if (uh->units[unitID] != 0 && uh->units[unitID] != owner) {
				float3 fix = uh->units[unitID]->pos + owner->posErrorVector * 128;
				float3 diff = float3(fix - owner->pos).Normalize();
				if(owner->moveState > 0 || !tempOrder) {
					SetGoal(fix - diff*uh->units[unitID]->radius, owner->pos);
				}
				// get ID of attack-order target unit
				orderTarget = uh->units[unitID];
				AddDeathDependence(orderTarget);
				inCommand = true;
			}
			else {
				// unit may not fire on itself, cancel order
				StopMove();
				FinishCommand();
				return;
			}
		}
		else {
			// 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->pos;

		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 = (w->range - (w->relWeaponPos).Length())
					> (orderTarget->pos.distance(owner->pos));
			b4 = w->TryTargetHeading(GetHeadingFromVector(-diff.x, -diff.z),
					orderTarget->pos, orderTarget != NULL);
			edgeFactor = fabs(w->targetBorder);
		}

		double 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

⌨️ 快捷键说明

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