void CAirCAI::ExecuteGuard(Command &c)
{
	assert(owner->unitDef->canGuard);
	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->lastAttack + 40 < gs->frameNum
				&& owner->maxRange > 0 && IsValidTarget(guarded->lastAttacker))
		{
			Command nc;
			nc.id = CMD_ATTACK;
			nc.params.push_back(guarded->lastAttacker->id);
			nc.options = c.options | INTERNAL_ORDER;
			commandQue.push_front(nc);
			SlowUpdate();
			return;
		} else {
			Command c2;
			c2.id = CMD_MOVE;
			c2.options = c.options | INTERNAL_ORDER;
			c2.params.push_back(guarded->pos.x);
			c2.params.push_back(guarded->pos.y);
			c2.params.push_back(guarded->pos.z);
			c2.timeOut = gs->frameNum + 60;
			commandQue.push_front(c2);
			return;
		}
	} else {
		FinishCommand();
	}
}
Beispiel #2
0
bool CAbilityState::CanUseAbility()
{
    if (m_PEntity->objtype == TYPE_MOB || m_PEntity->objtype == TYPE_PET)
        return true;
    if (m_PEntity->objtype == TYPE_PC)
    {
        auto PAbility = GetAbility();
        auto PChar = static_cast<CCharEntity*>(m_PEntity);
        if (PChar->PRecastContainer->HasRecast(RECAST_ABILITY, PAbility->getRecastId(), PAbility->getRecastTime()))
        {
            PChar->pushPacket(new CMessageBasicPacket(PChar, PChar, 0, 0, MSGBASIC_WAIT_LONGER));
            return false;
        }
        if (PChar->StatusEffectContainer->HasStatusEffect({EFFECT_AMNESIA, EFFECT_IMPAIRMENT}))
        {
            PChar->pushPacket(new CMessageBasicPacket(PChar, PChar, 0, 0, MSGBASIC_UNABLE_TO_USE_JA2));
            return false;
        }
        std::unique_ptr<CMessageBasicPacket> errMsg;
        auto PTarget = GetTarget();
        if (PChar->IsValidTarget(PTarget->targid, PAbility->getValidTarget(), errMsg))
        {
            if (PChar != PTarget && distance(PChar->loc.p, PTarget->loc.p) > PAbility->getRange())
            {
                PChar->pushPacket(new CMessageBasicPacket(PChar, PTarget, 0, 0, MSGBASIC_TOO_FAR_AWAY));
                return false;
            }
            if (!m_PEntity->PAI->TargetFind->canSee(&PTarget->loc.p))
            {
                m_errorMsg = std::make_unique<CMessageBasicPacket>(m_PEntity, PTarget, PAbility->getID(), 0, MSGBASIC_CANNOT_PERFORM_ACTION);
                return false;
            }
            if (PAbility->getID() >= ABILITY_HEALING_RUBY)
            {
                // Blood pact MP costs are stored under animation ID
                if (PChar->health.mp < PAbility->getAnimationID())
                {
                    PChar->pushPacket(new CMessageBasicPacket(PChar, PTarget, 0, 0, MSGBASIC_UNABLE_TO_USE_JA));
                    return false;
                }
            }
            CBaseEntity* PMsgTarget = PChar;
            int32 errNo = luautils::OnAbilityCheck(PChar, PTarget, PAbility, &PMsgTarget);
            if (errNo != 0)
            {
                PChar->pushPacket(new CMessageBasicPacket(PChar, PMsgTarget, PAbility->getID() + 16, PAbility->getID(), errNo));
                return false;
            }
            return true;
        }
        return false;
    }
    return true;
}
Beispiel #3
0
// The Node pointed to by node index is in range of it's target
// If it's still a valid target (no one chomped it this frame) 
// then join these two segments
HRESULT Chomp(short nodeIndex)
{
	short target = g_nodes[nodeIndex].attribs.targetID;
	
	if (IsValidTarget(target, nodeIndex))
	{
		g_nodes[nodeIndex].attribs.hasParent = true;
		g_nodes[target].attribs.hasChild = true;
		--g_numActiveNodes;
	}

	return S_OK;
}
Beispiel #4
0
void CAirCAI::ExecuteGuard(Command& c)
{
    assert(owner->unitDef->canGuard);

    const CUnit* guardee = unitHandler->GetUnit(c.params[0]);

    if (guardee == NULL) {
        FinishCommand();
        return;
    }
    if (UpdateTargetLostTimer(guardee->id) == 0) {
        FinishCommand();
        return;
    }
    if (guardee->outOfMapTime > (GAME_SPEED * 5)) {
        FinishCommand();
        return;
    }

    const bool pushAttackCommand =
        (owner->maxRange > 0.0f) &&
        owner->unitDef->canAttack &&
        ((guardee->lastAttackFrame + 40) < gs->frameNum) &&
        IsValidTarget(guardee->lastAttacker);

    if (pushAttackCommand) {
        Command nc(CMD_ATTACK, c.options | INTERNAL_ORDER, guardee->lastAttacker->id);
        commandQue.push_front(nc);
        SlowUpdate();
    } else {
        Command c2(CMD_MOVE, c.options | INTERNAL_ORDER);
        c2.timeOut = gs->frameNum + 60;

        if (guardee->pos.IsInBounds()) {
            c2.PushPos(guardee->pos);
        } else {
            float3 clampedGuardeePos = guardee->pos;

            clampedGuardeePos.ClampInBounds();

            c2.PushPos(clampedGuardeePos);
        }

        commandQue.push_front(c2);
    }
}
Beispiel #5
0
void CAirCAI::ExecuteGuard(Command& c)
{
	assert(owner->unitDef->canGuard);

	const CUnit* guardee = uh->GetUnit(c.params[0]);

	if (guardee == NULL) { FinishCommand(); return; }
	if (UpdateTargetLostTimer(guardee->id) == 0) { FinishCommand(); return; }
	if (guardee->outOfMapTime > (GAME_SPEED * 5)) { FinishCommand(); return; }

	const bool pushAttackCommand =
		owner->maxRange > 0.0f &&
		owner->unitDef->canAttack &&
		(guardee->lastAttack + 40 < gs->frameNum) &&
		IsValidTarget(guardee->lastAttacker);

	if (pushAttackCommand) {
		Command nc;
			nc.id = CMD_ATTACK;
			nc.params.push_back(guardee->lastAttacker->id);
			nc.options = c.options | INTERNAL_ORDER;
		commandQue.push_front(nc);
		SlowUpdate();
	} else {
		Command c2;
			c2.id = CMD_MOVE;
			c2.options = c.options | INTERNAL_ORDER;
			c2.timeOut = gs->frameNum + 60;

		if (guardee->pos.IsInBounds()) {
			c2.params.push_back(guardee->pos.x);
			c2.params.push_back(guardee->pos.y);
			c2.params.push_back(guardee->pos.z);
		} else {
			float3 clampedGuardeePos = guardee->pos;

			clampedGuardeePos.CheckInBounds();

			c2.params.push_back(clampedGuardeePos.x);
			c2.params.push_back(clampedGuardeePos.y);
			c2.params.push_back(clampedGuardeePos.z);
		}

		commandQue.push_front(c2);
	}
}
Beispiel #6
0
/**
* @brief Executes the guard command c
*/
void CMobileCAI::ExecuteGuard(Command &c)
{
	assert(owner->unitDef->canGuard);
	assert(!c.params.empty());

	CUnit* guarded = uh->GetUnit(c.params[0]);

	if (guarded != NULL && UpdateTargetLostTimer(guarded->id)) {
		if (owner->unitDef->canAttack && guarded->lastAttack + 40 < gs->frameNum
				&& IsValidTarget(guarded->lastAttacker))
		{
			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;
}
Beispiel #7
0
/**
* @brief Executes the guard command c
*/
void CMobileCAI::ExecuteGuard(Command &c)
{
	assert(owner->unitDef->canGuard);
	assert(!c.params.empty());

	const CUnit* guardee = unitHandler->GetUnit(c.params[0]);

	if (guardee == NULL) { FinishCommand(); return; }
	if (UpdateTargetLostTimer(guardee->id) == 0) { FinishCommand(); return; }
	if (guardee->outOfMapTime > (GAME_SPEED * 5)) { FinishCommand(); return; }

	const bool pushAttackCommand =
		owner->unitDef->canAttack &&
		(guardee->lastAttackFrame + 40 < gs->frameNum) &&
		IsValidTarget(guardee->lastAttacker);

	if (pushAttackCommand) {
		Command nc(CMD_ATTACK, c.options, guardee->lastAttacker->id);
		commandQue.push_front(nc);

		StopSlowGuard();
		SlowUpdate();
	} else {
		const float3 dif = (guardee->pos - owner->pos).SafeNormalize();
		const float3 goal = guardee->pos - dif * (guardee->radius + owner->radius + 64.0f);
		const bool resetGoal =
			((goalPos - goal).SqLength2D() > 1600.0f) ||
			(goalPos - owner->pos).SqLength2D() < Square(owner->moveType->GetMaxSpeed() * GAME_SPEED + 1 + SQUARE_SIZE * 2);

		if (resetGoal) {
			SetGoal(goal, owner->pos);
		}

		if ((goal - owner->pos).SqLength2D() < 6400.0f) {
			StartSlowGuard(guardee->moveType->GetMaxSpeed());

			if ((goal - owner->pos).SqLength2D() < 1800.0f) {
				StopMove();
				NonMoving();
			}
		} else {
			StopSlowGuard();
		}
	}
}
Beispiel #8
0
bool CAirCAI::AirAutoGenerateTarget(AAirMoveType* myPlane) {
    assert(commandQue.empty());
    assert(myPlane->owner == owner);

    const UnitDef* ownerDef = owner->unitDef;
    const bool autoLand = !ownerDef->DontLand() && myPlane->autoLand;
    const bool autoAttack = ((owner->fireState >= FIRESTATE_FIREATWILL) && (owner->moveState != MOVESTATE_HOLDPOS));

    if (myPlane->aircraftState == AAirMoveType::AIRCRAFT_FLYING && autoLand) {
        StopMove();
    }

    if (ownerDef->canAttack && autoAttack && owner->maxRange > 0) {
        if (ownerDef->IsFighterAirUnit()) {
            const float3 P = owner->pos + (owner->speed * 10.0);
            const float R = 1000.0f * owner->moveState;
            const CUnit* enemy = CGameHelper::GetClosestEnemyAircraft(NULL, P, R, owner->allyteam);

            if (IsValidTarget(enemy)) {
                Command nc(CMD_ATTACK, INTERNAL_ORDER, enemy->id);
                commandQue.push_front(nc);
                inCommand = false;
                return true;
            }
        } else {
            const float3 P = owner->pos + (owner->speed * 20.0f);
            const float R = 500.0f * owner->moveState;
            const CUnit* enemy = CGameHelper::GetClosestValidTarget(P, R, owner->allyteam, this);

            if (enemy != NULL) {
                Command nc(CMD_ATTACK, INTERNAL_ORDER, enemy->id);
                commandQue.push_front(nc);
                inCommand = false;
                return true;
            }
        }
    }

    return false;
}
Beispiel #9
0
bool CPlayerController::Engage(uint16 targid)
{
    //#TODO: pet engage/disengage
    std::unique_ptr<CMessageBasicPacket> errMsg;
    auto PChar = static_cast<CCharEntity*>(POwner);
    auto PTarget = PChar->IsValidTarget(targid, TARGET_ENEMY, errMsg);

    if (PTarget)
    {
        if (distance(PChar->loc.p, PTarget->loc.p) < 30)
        {
            if (m_LastAttackTime + std::chrono::milliseconds(PChar->GetWeaponDelay(false)) < server_clock::now())
            {
                if (CController::Engage(targid))
                {
                    PChar->PLatentEffectContainer->CheckLatentsWeaponDraw(true);
                    PChar->pushPacket(new CLockOnPacket(PChar, PTarget));
                    return true;
                }
            }
            else
            {
                errMsg = std::make_unique<CMessageBasicPacket>(PChar, PTarget, 0, 0, MSGBASIC_WAIT_LONGER);
            }
        }
        else
        {
            errMsg = std::make_unique<CMessageBasicPacket>(PChar, PTarget, 0, 0, MSGBASIC_TOO_FAR_AWAY);
        }
    }
    if (errMsg)
    {
        PChar->HandleErrorMessage(errMsg);
    }
    return false;
}
/**
* @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(IsValidTarget(newTarget) && !owner->weapons.empty()
					&& 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(IsValidTarget(enemy) && !owner->weapons.empty()) {
			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 == AMoveType::Failed)){
		FinishCommand();
	}
	return;
}
Beispiel #11
0
void CPlayerController::WeaponSkill(uint16 targid, uint16 wsid)
{
    auto PChar = static_cast<CCharEntity*>(POwner);
    if (PChar->PAI->CanChangeState())
    {
        //#TODO: put all this in weaponskill_state
        CWeaponSkill* PWeaponSkill = battleutils::GetWeaponSkill(wsid);

        if (PWeaponSkill && !charutils::hasWeaponSkill(PChar, PWeaponSkill->getID()))
        {
            PChar->pushPacket(new CMessageBasicPacket(PChar, PChar, 0, 0, MSGBASIC_CANNOT_USE_WS));
            return;
        }
        if (PChar->StatusEffectContainer->HasStatusEffect(EFFECT_AMNESIA))
        {
            PChar->pushPacket(new CMessageBasicPacket(PChar, PChar, 0, 0, MSGBASIC_CANNOT_USE_ANY_WS));
            return;
        }
        if (PChar->health.tp < 1000)
        {
            PChar->pushPacket(new CMessageBasicPacket(PChar, PChar, 0, 0, MSGBASIC_NOT_ENOUGH_TP));
            return;
        }
        if (PWeaponSkill->getType() == SKILL_ARC || PWeaponSkill->getType() == SKILL_MRK)
        {
            CItemWeapon* PItem = (CItemWeapon*)PChar->getEquip(SLOT_AMMO);

            // before allowing ranged weapon skill...
            if (PItem == nullptr ||
                !(PItem->isType(ITEM_WEAPON)) ||
                !PChar->m_Weapons[SLOT_AMMO]->isRanged() ||
                !PChar->m_Weapons[SLOT_RANGED]->isRanged() ||
                PChar->equip[SLOT_AMMO] == 0)
            {
                PChar->pushPacket(new CMessageBasicPacket(PChar, PChar, 0, 0, MSGBASIC_NO_RANGED_WEAPON));
                return;
            }
        }

        std::unique_ptr<CMessageBasicPacket> errMsg;
        auto PTarget = PChar->IsValidTarget(targid, battleutils::isValidSelfTargetWeaponskill(wsid) ? TARGET_SELF : TARGET_ENEMY, errMsg);

        if (PTarget)
        {
            if (!isFaceing(PChar->loc.p, PTarget->loc.p, 40))
            {
                PChar->pushPacket(new CMessageBasicPacket(PChar, PTarget, 0, 0, MSGBASIC_CANNOT_SEE));
                return;
            }

            CController::WeaponSkill(targid, wsid);
        }
        else if (errMsg)
        {
            PChar->pushPacket(std::move(errMsg));
        }
    }
    else
    {
        PChar->pushPacket(new CMessageBasicPacket(PChar, PChar, 0, 0, MSGBASIC_UNABLE_TO_USE_WS));
    }
}
Beispiel #12
0
void CAirCAI::ExecuteFight(Command &c)
{
	assert((c.options & INTERNAL_ORDER) || owner->unitDef->canFight);
	AAirMoveType* myPlane = (AAirMoveType*) owner->moveType;
	if(tempOrder){
		tempOrder=false;
		inCommand=true;
	}
	if(c.params.size()<3){		//this shouldnt happen but anyway ...
		logOutput.Print("Error: got fight cmd with less than 3 params on %s in AirCAI",
			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()<(127*127)){'
		// 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() > (150 * 150)) {
			commandPos1 = owner->pos;
		}
	}
	goalPos = float3(c.params[0], c.params[1], c.params[2]);
	if(!inCommand){
		inCommand = true;
		commandPos2=goalPos;
	}
	if(c.params.size() >= 6){
		goalPos = ClosestPointOnLine(commandPos1, commandPos2, owner->pos);
	}

	// CMD_FIGHT is pretty useless if !canAttack but we try to honour the modders wishes anyway...
	if (owner->unitDef->canAttack && owner->fireState >= 2
			&& owner->moveState != 0 && owner->maxRange > 0) {
		float3 curPosOnLine = ClosestPointOnLine(commandPos1, commandPos2,
				owner->pos + owner->speed*10);
		float testRad = 1000 * owner->moveState;
		CUnit* enemy = NULL;
		if(myPlane->IsFighter()) {
			enemy = helper->GetClosestEnemyAircraft(curPosOnLine,
					testRad, owner->allyteam);
		}
		if(IsValidTarget(enemy) && (owner->moveState!=1
				|| LinePointDist(commandPos1, commandPos2, enemy->pos) < 1000))
		{
			Command nc;
			nc.id=CMD_ATTACK;
			nc.params.push_back(enemy->id);
			nc.options=c.options|INTERNAL_ORDER;
			commandQue.push_front(nc);
			tempOrder=true;
			inCommand=false;
			if(lastPC1!=gs->frameNum){	//avoid infinite loops
				lastPC1=gs->frameNum;
				SlowUpdate();
			}
			return;
		} else {
			float3 curPosOnLine = ClosestPointOnLine(
				commandPos1, commandPos2, owner->pos + owner->speed * 20);
			float testRad = 500 * owner->moveState;
			enemy = helper->GetClosestEnemyUnit(curPosOnLine, testRad, owner->allyteam);
			if(IsValidTarget(enemy)) {
				Command nc;
				nc.id = CMD_ATTACK;
				nc.params.push_back(enemy->id);
				nc.options = c.options | INTERNAL_ORDER;
				PushOrUpdateReturnFight();
				commandQue.push_front(nc);
				tempOrder = true;
				inCommand = false;
				if(lastPC2 != gs->frameNum){	//avoid infinite loops
					lastPC2 = gs->frameNum;
					SlowUpdate();
				}
				return;
			}
		}
	}
	myPlane->goalPos = goalPos;

	if((owner->pos - goalPos).SqLength2D() < (127 * 127)
			|| (owner->pos + owner->speed*8 - goalPos).SqLength2D() < (127 * 127)) {
		FinishCommand();
	}
	return;
}
Beispiel #13
0
void CAirCAI::SlowUpdate()
{
	if (!commandQue.empty() && commandQue.front().timeOut < gs->frameNum) {
		FinishCommand();
		return;
	}

	if (owner->usingScriptMoveType) {
		return; // avoid the invalid (CAirMoveType*) cast
	}

	AAirMoveType* myPlane=(AAirMoveType*) owner->moveType;

	if(owner->unitDef->maxFuel > 0){
		RefuelIfNeeded();
	}

	if(commandQue.empty()){
		if(myPlane->aircraftState == AAirMoveType::AIRCRAFT_FLYING
			&& !owner->unitDef->DontLand() && myPlane->autoLand){
			StopMove();
//			myPlane->SetState(AAirMoveType::AIRCRAFT_LANDING);
		}

		if(owner->unitDef->canAttack && owner->fireState>=2
				&& owner->moveState != 0 && owner->maxRange > 0){
			if(myPlane->IsFighter()){
				float testRad=1000 * owner->moveState;
				CUnit* enemy=helper->GetClosestEnemyAircraft(
					owner->pos + (owner->speed * 10), testRad, owner->allyteam);
				if(IsValidTarget(enemy)) {
					Command nc;
					nc.id = CMD_ATTACK;
					nc.params.push_back(enemy->id);
					nc.options = 0;
					commandQue.push_front(nc);
					inCommand = false;
					return;
				}
			}
			float testRad = 500 * owner->moveState;
			CUnit* enemy = helper->GetClosestEnemyUnit(
				owner->pos + (owner->speed * 20), testRad, owner->allyteam);
			if(IsValidTarget(enemy)) {
				Command nc;
				nc.id = CMD_ATTACK;
				nc.params.push_back(enemy->id);
				nc.options = 0;
				commandQue.push_front(nc);
				inCommand = false;
				return;
			}
		}
		return;
	}

	Command& c = commandQue.front();

	if (c.id == CMD_WAIT) {
		if ((myPlane->aircraftState == AAirMoveType::AIRCRAFT_FLYING)
		    && !owner->unitDef->DontLand() && myPlane->autoLand) {
			StopMove(); 
//			myPlane->SetState(AAirMoveType::AIRCRAFT_LANDING);
		}
		return;
	}

	if (c.id != CMD_STOP) {
		myPlane->Takeoff();
	}

	float3 curPos=owner->pos;

	switch(c.id){
		case CMD_AREA_ATTACK:{
			ExecuteAreaAttack(c);
			return;
		}
		default:{
			CMobileCAI::Execute();
			return;
		}
	}
}
Beispiel #14
0
void CAirCAI::SlowUpdate()
{
	if(gs->paused) // Commands issued may invoke SlowUpdate when paused
		return;
	if (!commandQue.empty() && commandQue.front().timeOut < gs->frameNum) {
		FinishCommand();
		return;
	}

	if (owner->usingScriptMoveType) {
		return; // avoid the invalid (CAirMoveType*) cast
	}

	AAirMoveType* myPlane=(AAirMoveType*) owner->moveType;

	bool wantToRefuel = LandRepairIfNeeded();
	if(!wantToRefuel && owner->unitDef->maxFuel > 0){
		wantToRefuel = RefuelIfNeeded();
	}

	if(commandQue.empty()){
		if(myPlane->aircraftState == AAirMoveType::AIRCRAFT_FLYING
				&& !owner->unitDef->DontLand() && myPlane->autoLand) {
			StopMove();
//			myPlane->SetState(AAirMoveType::AIRCRAFT_LANDING);
		}

		if(owner->unitDef->canAttack && owner->fireState >= FIRESTATE_FIREATWILL
				&& owner->moveState != MOVESTATE_HOLDPOS && owner->maxRange > 0) {
			if (myPlane->IsFighter()) {
				float testRad=1000 * owner->moveState;
				CUnit* enemy=helper->GetClosestEnemyAircraft(
					owner->pos + (owner->speed * 10), testRad, owner->allyteam);
				if(IsValidTarget(enemy)) {
					Command nc;
					nc.id = CMD_ATTACK;
					nc.params.push_back(enemy->id);
					nc.options = 0;
					commandQue.push_front(nc);
					inCommand = false;
					return;
				}
			}
			const float searchRadius = 500 * owner->moveState;
			CUnit* enemy = helper->GetClosestValidTarget(
				owner->pos + (owner->speed * 20), searchRadius, owner->allyteam, this);
			if (enemy != NULL) {
				Command nc;
				nc.id = CMD_ATTACK;
				nc.params.push_back(enemy->id);
				nc.options = 0;
				commandQue.push_front(nc);
				inCommand = false;
				return;
			}
		}
		return;
	}

	Command& c = commandQue.front();

	if (c.id == CMD_WAIT) {
		if ((myPlane->aircraftState == AAirMoveType::AIRCRAFT_FLYING)
		    && !owner->unitDef->DontLand() && myPlane->autoLand) {
			StopMove();
//			myPlane->SetState(AAirMoveType::AIRCRAFT_LANDING);
		}
		return;
	}

	if (c.id != CMD_STOP && c.id != CMD_AUTOREPAIRLEVEL
			&& c.id != CMD_IDLEMODE && c.id != CMD_SET_WANTED_MAX_SPEED) {
		myPlane->Takeoff();
	}

	if (wantToRefuel) {
		switch (c.id) {
			case CMD_AREA_ATTACK:
			case CMD_ATTACK:
			case CMD_FIGHT:
				return;
		}
	}

	switch(c.id){
		case CMD_AREA_ATTACK:{
			ExecuteAreaAttack(c);
			return;
		}
		default:{
			CMobileCAI::Execute();
			return;
		}
	}
}
Beispiel #15
0
HRESULT FindNearestNeighbor(short index)
{
	HRESULT hr = S_OK;

	if (g_nodes[index].attribs.hasParent == true)
		return S_FALSE;

	float2 pos = {g_nodes[index].position.getX(), g_nodes[index].position.getY()};
	if (Bin(pos.x, pos.y, nullptr) != S_OK)
		return S_FALSE; // if we're not in a bin backed by memory, just keep our old neighbor

	int xrange[2] = {int(pos.x/g_binNWidth - 0.5f), int(pos.x/g_binNWidth + 0.5f)};
	int yrange[2] = {int(pos.y/g_binNHeight - 0.5f), int(pos.y/g_binNHeight + 0.5f)};

	uint minDist = -1;
	ushort nearest = -1;
	int bin;
	do {
		// Yes, we'll re-iterate over some bins, but the bin rows are stored linearly in memory
		// So the cache should make this pretty cheap (plus it's only one access since they'll probably be empty)
		for (int y = yrange[0]; y <= yrange[1]; y++)
		{
			for (int x = xrange[0]; x <= xrange[1]; x++)
			{
				hr = Bin(x, y, &bin);
				ASSERT(SUCCEEDED(hr)); // Bin fails if the bin isn't memory backed.

				for (uint slot = 0; slot < g_binStride; slot++)
				{
					// TODO: These large strides are going to kill the cache! 
					//		 We should probably switch to storing the node indexes linearly with the MSb denoting end of bucket
					//		 Then we'd have a separate table to index into this based on bucket
					// No, that won't work because inserts would be very difficult/expensive. The easiest way would be a linked
					//	   list, but that would obviously be super slow. I think I the first try was actually the best ;D
					ushort target = g_slots[bin*g_binStride + slot];
					if (target == EMPTY_SLOT)
						break;
					else if (IsValidTarget(target, index))
					{
						uint dist = Distance(g_nodes[index].position, g_nodes[target].position);
						if (dist < minDist)
						{
							minDist = dist;
							nearest = target;
						}
					}
				}
			}
		}
		if (xrange[0] > g_binRangeX[0]) xrange[0]--;
		if (xrange[1] < g_binRangeX[1]) xrange[1]++;
		if (yrange[0] > g_binRangeY[0]) yrange[0]--;
		if (yrange[1] < g_binRangeY[1]) yrange[1]++;

		// Do we need this? Could happen if a vert is in a quadrant of it's own
		if (xrange[1] - xrange[0] == g_binRangeX[1] - g_binRangeX[0] && 
			yrange[1] - yrange[0] == g_binRangeY[1] - g_binRangeY[0])
			break;

	} while (nearest == ushort(-1));

	if (nearest != ushort(-1)) g_nodes[index].attribs.targetID = nearest;
	else if (IsValidTarget(g_nodes[index].attribs.targetID, index) == false)
	{
		// If our current target is invalid, and we weren't able to find a new one, we'll have to revert to N^2
		for (uint i = 0; i < g_numNodes; i++)
		{
			if (IsValidTarget(i, index))
			{
				uint dist = Distance(g_nodes[index].position, g_nodes[i].position);
				if (dist < minDist)
				{
					minDist = dist;
					nearest = i;
				}
			}
		}
		ASSERT(nearest != -1);
		g_nodes[index].attribs.targetID = nearest; 
	}
	
	return S_OK;
}
void CMobileCAI::IdleCheck(void)
{
	if(owner->unitDef->canAttack && owner->moveState && owner->fireState
			&& !owner->weapons.empty() && owner->haveTarget) {
		if(!owner->userTarget) {
			owner->haveTarget = false;
		} else if(owner->pos.SqDistance2D(owner->userTarget->pos) <
				Square(owner->maxRange + 200*owner->moveState*owner->moveState)) {
			Command c;
			c.id = CMD_ATTACK;
			c.options=INTERNAL_ORDER;
			c.params.push_back(owner->userTarget->id);
			c.timeOut = gs->frameNum + 140;
			commandQue.push_front(c);
			return;
		}
	}
	if(owner->unitDef->canAttack && owner->moveState && owner->fireState
				&& !owner->weapons.empty() && !owner->haveTarget) {
		if(owner->lastAttacker && owner->lastAttack + 200 > gs->frameNum
				&& !(owner->unitDef->noChaseCategory & owner->lastAttacker->category)){
			float3 apos=owner->lastAttacker->pos;
			float dist=apos.SqDistance2D(owner->pos);
			if(dist<Square(owner->maxRange+200*owner->moveState*owner->moveState)){
				Command c;
				c.id=CMD_ATTACK;
				c.options=INTERNAL_ORDER;
				c.params.push_back(owner->lastAttacker->id);
				c.timeOut=gs->frameNum+140;
				commandQue.push_front(c);
				return;
			}
		}
	}
	if (owner->unitDef->canAttack && (gs->frameNum >= lastIdleCheck+10)
			&& owner->moveState && owner->fireState>=2 &&
			!owner->weapons.empty() && !owner->haveTarget)
	{
		CUnit* u = helper->GetClosestEnemyUnit(owner->pos,
				owner->maxRange + 150 * owner->moveState * owner->moveState, owner->allyteam);
		if(IsValidTarget(u)) {
			Command c;
			c.id=CMD_ATTACK;
			c.options=INTERNAL_ORDER;
			c.params.push_back(u->id);
			c.timeOut=gs->frameNum+140;
			commandQue.push_front(c);
			return;
		}
	}
	if (owner->usingScriptMoveType) {
		return;
	}
	lastIdleCheck = gs->frameNum;
	if (((owner->pos - lastUserGoal).SqLength2D() > 10000.0f) &&
	    !owner->haveTarget && !dynamic_cast<CTAAirMoveType*>(owner->moveType)) {
		//note that this is not internal order so that we dont keep generating
		//new orders if we cant get to that pos
		Command c;
		c.id=CMD_MOVE;
		c.options=0;
		c.params.push_back(lastUserGoal.x);
		c.params.push_back(lastUserGoal.y);
		c.params.push_back(lastUserGoal.z);
		commandQue.push_front(c);
		unimportantMove=true;
	} else {
		NonMoving();
	}
}
Beispiel #17
0
void CAirCAI::ExecuteFight(Command& c)
{
    assert((c.options & INTERNAL_ORDER) || owner->unitDef->canFight);

    // FIXME: check owner->UsingScriptMoveType() and skip rest if true?
    AAirMoveType* myPlane = GetStrafeAirMoveType(owner);

    assert(owner == myPlane->owner);

    if (tempOrder) {
        tempOrder = false;
        inCommand = true;
    }

    if (c.params.size() < 3) {
        LOG_L(L_ERROR, "[ACAI::%s][f=%d][id=%d] CMD_FIGHT #params < 3", __FUNCTION__, gs->frameNum, owner->id);
        return;
    }

    if (c.params.size() >= 6) {
        if (!inCommand) {
            commandPos1 = c.GetPos(3);
        }
    } else {
        // HACK 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()<(127*127)){'
        // 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() > (150 * 150)) {
            commandPos1 = owner->pos;
        }
    }

    goalPos = c.GetPos(0);

    if (!inCommand) {
        inCommand = true;
        commandPos2 = goalPos;
    }
    if (c.params.size() >= 6) {
        goalPos = ClosestPointOnLine(commandPos1, commandPos2, owner->pos);
    }

    // CMD_FIGHT is pretty useless if !canAttack, but we try to honour the modders wishes anyway...
    if (owner->unitDef->canAttack && (owner->fireState >= FIRESTATE_FIREATWILL)
            && (owner->moveState != MOVESTATE_HOLDPOS) && (owner->maxRange > 0))
    {
        CUnit* enemy = NULL;

        if (owner->unitDef->IsFighterAirUnit()) {
            const float3 P = ClosestPointOnLine(commandPos1, commandPos2, owner->pos + owner->speed*10);
            const float R = 1000.0f * owner->moveState;

            enemy = CGameHelper::GetClosestEnemyAircraft(NULL, P, R, owner->allyteam);
        }
        if (IsValidTarget(enemy) && (owner->moveState != MOVESTATE_MANEUVER
                                     || LinePointDist(commandPos1, commandPos2, enemy->pos) < 1000))
        {
            // make the attack-command inherit <c>'s options
            // (if <c> is internal, then so are the attacks)
            //
            // this is needed because CWeapon code will not
            // fire on "internal" targets if the weapon has
            // noAutoTarget set (although the <enemy> CUnit*
            // is technically not a user-target, we treat it
            // as such) even when explicitly told to fight
            Command nc(CMD_ATTACK, c.options, enemy->id);
            commandQue.push_front(nc);

            tempOrder = true;
            inCommand = false;

            if (lastPC1 != gs->frameNum) { // avoid infinite loops
                lastPC1 = gs->frameNum;
                SlowUpdate();
            }
            return;
        } else {
            const float3 P = ClosestPointOnLine(commandPos1, commandPos2, owner->pos + owner->speed * 20);
            const float R = 500.0f * owner->moveState;

            enemy = CGameHelper::GetClosestValidTarget(P, R, owner->allyteam, this);

            if (enemy != NULL) {
                PushOrUpdateReturnFight();

                // make the attack-command inherit <c>'s options
                Command nc(CMD_ATTACK, c.options, enemy->id);
                commandQue.push_front(nc);

                tempOrder = true;
                inCommand = false;

                // avoid infinite loops (?)
                if (lastPC2 != gs->frameNum) {
                    lastPC2 = gs->frameNum;
                    SlowUpdate();
                }
                return;
            }
        }
    }

    myPlane->goalPos = goalPos;

    const CStrafeAirMoveType* airMT = (!owner->UsingScriptMoveType())? static_cast<const CStrafeAirMoveType*>(myPlane): NULL;
    const float radius = (airMT != NULL)? std::max(airMT->turnRadius + 2*SQUARE_SIZE, 128.f) : 127.f;

    // we're either circling or will get to the target in 8 frames
    if ((owner->pos - goalPos).SqLength2D() < (radius * radius)
            || (owner->pos + owner->speed*8 - goalPos).SqLength2D() < 127*127)
    {
        FinishCommand();
    }
}