示例#1
0
文件: AirCAI.cpp 项目: 9heart/spring
bool CAirCAI::SelectNewAreaAttackTargetOrPos(const Command& ac) {
    assert(ac.GetID() == CMD_AREA_ATTACK || (ac.GetID() == CMD_ATTACK && ac.GetParamsCount() >= 3));

    if (ac.GetID() == CMD_ATTACK) {
        FinishCommand();
        return false;
    }

    const float3& pos = ac.GetPos(0);
    const float radius = ac.params[3];

    std::vector<int> enemyUnitIDs;
    CGameHelper::GetEnemyUnits(pos, radius, owner->allyteam, enemyUnitIDs);

    if (enemyUnitIDs.empty()) {
        float3 attackPos = pos + (gs->randVector() * radius);
        attackPos.y = CGround::GetHeightAboveWater(attackPos.x, attackPos.z);

        owner->AttackGround(attackPos, (ac.options & INTERNAL_ORDER) == 0, false);
        SetGoal(attackPos, owner->pos);
    } else {
        // note: the range of randFloat() is inclusive of 1.0f
        const unsigned int unitIdx = std::min<int>(gs->randFloat() * enemyUnitIDs.size(), enemyUnitIDs.size() - 1);
        const unsigned int unitID = enemyUnitIDs[unitIdx];

        CUnit* targetUnit = unitHandler->GetUnitUnsafe(unitID);

        SetOrderTarget(targetUnit);
        owner->AttackUnit(targetUnit, (ac.options & INTERNAL_ORDER) == 0, false);
        SetGoal(targetUnit->pos, owner->pos);
    }

    return true;
}
示例#2
0
void CCommandAI::ExecuteAttack(Command& c)
{
	assert(owner->unitDef->canAttack);

	if (inCommand) {
		if (targetDied || (c.params.size() == 1 && UpdateTargetLostTimer(int(c.params[0])) == 0)) {
			FinishCommand();
			return;
		}
		if (!(c.options & ALT_KEY) && SkipParalyzeTarget(orderTarget)) {
			FinishCommand();
			return;
		}
	} else {
		if (c.params.size() == 1) {
			CUnit* targetUnit = unitHandler->GetUnit(c.params[0]);

			if (targetUnit == NULL) { FinishCommand(); return; }
			if (targetUnit == owner) { FinishCommand(); return; }
			if (targetUnit->GetTransporter() != NULL && !modInfo.targetableTransportedUnits) {
				FinishCommand(); return;
			}

			SetOrderTarget(targetUnit);
			owner->AttackUnit(targetUnit, (c.options & INTERNAL_ORDER) == 0, c.GetID() == CMD_MANUALFIRE);
			inCommand = true;
		} else {
			owner->AttackGround(c.GetPos(0), (c.options & INTERNAL_ORDER) == 0, c.GetID() == CMD_MANUALFIRE);
			inCommand = true;
		}
	}
}
示例#3
0
void CFactoryCAI::DecreaseQueueCount(const Command& buildCommand, BuildOption& buildOption, bool)
{
	// copy in case we get pop'ed
	// NOTE: the queue should not be empty at this point!
	const Command frontCommand = commandQue.empty()? Command(CMD_STOP): commandQue.front();

	if (!repeatOrders || (buildCommand.options & INTERNAL_ORDER))
		buildOption.numQued--;

	UpdateIconName(buildCommand.GetID(), buildOption);

	// if true, factory was set to wait and its buildee
	// could only have been finished by assisting units
	// --> make sure not to cancel the wait-order
	if (frontCommand.GetID() == CMD_WAIT)
		commandQue.pop_front();

	// can only finish the real build-command command if
	// we still have it in our queue (FinishCommand also
	// asserts this)
	if (!commandQue.empty())
		FinishCommand();

	if (frontCommand.GetID() == CMD_WAIT)
		commandQue.push_front(frontCommand);
}
示例#4
0
bool CTransportCAI::AllowedCommand(const Command& c, bool fromSynced)
{
	if (!CMobileCAI::AllowedCommand(c, fromSynced)) {
		return false;
	}

	switch (c.GetID()) {
		case CMD_UNLOAD_UNIT:
		case CMD_UNLOAD_UNITS: {
			const CTransportUnit* transport = static_cast<CTransportUnit*>(owner);
			const std::list<CTransportUnit::TransportedUnit>& transportees = transport->GetTransportedUnits();

			// allow unloading empty transports for easier setup of transport bridges
			if (transportees.empty())
				return true;

			if (c.GetParamsCount() == 5) {
				if (fromSynced) {
					// point transported buildings (...) in their wanted direction after unloading
					for (auto it = transportees.begin(); it != transportees.end(); ++it) {
						CBuilding* building = dynamic_cast<CBuilding*>(it->unit);

						if (building == NULL)
							continue;

						building->buildFacing = std::abs(int(c.GetParam(4))) % NUM_FACINGS;
					}
				}
			}

			if (c.GetParamsCount() >= 4) {
				// find unload positions for transportees (WHY can this run in unsynced context?)
				for (auto it = transportees.begin(); it != transportees.end(); ++it) {
					CUnit* u = it->unit;

					const float radius = (c.GetID() == CMD_UNLOAD_UNITS)? c.GetParam(3): 0.0f;
					const float spread = u->radius * transport->unitDef->unloadSpread;

					float3 foundPos;

					if (FindEmptySpot(c.GetPos(0), radius, spread, foundPos, u, fromSynced)) {
						return true;
					}
					 // FIXME: support arbitrary unloading order for other unload types also
					if (unloadType != UNLOAD_LAND) {
						return false;
					}
				}

				// no empty spot found for any transported unit
				return false;
			}

			break;
		}
	}

	return true;
}
示例#5
0
std::vector<Command> CCommandAI::GetOverlapQueued(const Command& c, CCommandQueue& q)
{
	CCommandQueue::iterator ci = q.end();
	std::vector<Command> v;
	BuildInfo cbi(c);

	if (ci != q.begin()) {
		do {
			--ci; //iterate from the end and dont check the current order
			const Command& t = *ci;

			if (t.params.size() != c.params.size())
				continue;

			if (t.GetID() == c.GetID() || (c.GetID() < 0 && t.GetID() < 0)) {
				if (c.params.size() == 1) {
					// assume the param is a unit or feature id
					if (t.params[0] == c.params[0]) {
						v.push_back(t);
					}
				}
				else if (c.params.size() >= 3) {
					// assume c and t are positional commands
					// NOTE: uses a BuildInfo structure, but <t> can be ANY command
					BuildInfo tbi;
					if (tbi.Parse(t)) {
						const float dist2X = 2.0f * math::fabs(cbi.pos.x - tbi.pos.x);
						const float dist2Z = 2.0f * math::fabs(cbi.pos.z - tbi.pos.z);
						const float addSizeX = SQUARE_SIZE * (cbi.GetXSize() + tbi.GetXSize());
						const float addSizeZ = SQUARE_SIZE * (cbi.GetZSize() + tbi.GetZSize());
						const float maxSizeX = SQUARE_SIZE * std::max(cbi.GetXSize(), tbi.GetXSize());
						const float maxSizeZ = SQUARE_SIZE * std::max(cbi.GetZSize(), tbi.GetZSize());

						if (cbi.def == NULL) continue;
						if (tbi.def == NULL) continue;

						if (((dist2X > maxSizeX) || (dist2Z > maxSizeZ)) &&
						    ((dist2X < addSizeX) && (dist2Z < addSizeZ))) {
							v.push_back(t);
						}
					} else {
						if ((cbi.pos - tbi.pos).SqLength2D() >= (COMMAND_CANCEL_DIST * COMMAND_CANCEL_DIST))
							continue;
						if ((c.options & SHIFT_KEY) != 0 && (c.options & INTERNAL_ORDER) != 0)
							continue;

						v.push_back(t);
					}
				}
			}
		} while (ci != q.begin());
	}
	return v;
}
示例#6
0
void CBuilderCAI::GiveCommandReal(const Command& c, bool fromSynced)
{
	if (!AllowedCommand(c, fromSynced))
		return;

	// don't guard yourself
	if ((c.GetID() == CMD_GUARD) &&
	    (c.params.size() == 1) && ((int)c.params[0] == owner->id)) {
		return;
	}

	// stop building/reclaiming/... if the new command is not queued, i.e. replaces our current activity
	// FIXME should happen just before CMobileCAI::GiveCommandReal? (the new cmd can still be skipped!)
	if ((c.GetID() != CMD_WAIT && c.GetID() != CMD_SET_WANTED_MAX_SPEED) && !(c.options & SHIFT_KEY)) {
		if (nonQueingCommands.find(c.GetID()) == nonQueingCommands.end()) {
			building = false;
			static_cast<CBuilder*>(owner)->StopBuild();
		}
	}

	if (buildOptions.find(c.GetID()) != buildOptions.end()) {
		if (c.params.size() < 3)
			return;

		BuildInfo bi;
		bi.pos = c.GetPos(0);

		if (c.params.size() == 4)
			bi.buildFacing = abs((int)c.params[3]) % NUM_FACINGS;

		bi.def = unitDefHandler->GetUnitDefByID(-c.GetID());
		bi.pos = CGameHelper::Pos2BuildPos(bi, true);

		// We are a static building, check if the buildcmd is in range
		if (!owner->unitDef->canmove) {
			if (!IsInBuildRange(bi.pos, GetBuildOptionRadius(bi.def, c.GetID()))) {
				return;
			}
		}

		const CUnit* nanoFrame = NULL;

		// check if the buildpos is blocked
		if (IsBuildPosBlocked(bi, &nanoFrame))
			return;

		// if it is a nanoframe help to finish it
		if (nanoFrame != NULL) {
			Command c2(CMD_REPAIR, c.options | INTERNAL_ORDER, nanoFrame->id);
			CMobileCAI::GiveCommandReal(c2, fromSynced);
			CMobileCAI::GiveCommandReal(c, fromSynced);
			return;
		}
	} else {
		if (c.GetID() < 0)
			return;
	}

	CMobileCAI::GiveCommandReal(c, fromSynced);
}
示例#7
0
void CFactoryCAI::InsertBuildCommand(CCommandQueue::iterator& it,
                                     const Command& newCmd)
{
	map<int, BuildOption>::iterator boi = buildOptions.find(newCmd.GetID());
	if (boi != buildOptions.end()) {
		boi->second.numQued++;
		UpdateIconName(newCmd.GetID(), boi->second);
	}
	if (!commandQue.empty() && (it == commandQue.begin())) {
		// ExecuteStop(), without the pop_front()
		CFactory* fac = static_cast<CFactory*>(owner);
		fac->StopBuild();
	}
	commandQue.insert(it, newCmd);
}
示例#8
0
/// pushes 7 items on the stack
static void PushUnitAndCommand(lua_State* L, const CUnit* unit, const Command& cmd)
{
	// push the unit info
	lua_pushnumber(L, unit->id);
	lua_pushnumber(L, unit->unitDef->id);
	lua_pushnumber(L, unit->team);

	// push the command id
	lua_pushnumber(L, cmd.GetID());

	// push the params list
	lua_newtable(L);
	for (int p = 0; p < (int)cmd.params.size(); p++) {
		lua_pushnumber(L, p + 1);
		lua_pushnumber(L, cmd.params[p]);
		lua_rawset(L, -3);
	}

	// push the options table
	lua_newtable(L);
	HSTR_PUSH_NUMBER(L, "coded", cmd.options);
	HSTR_PUSH_BOOL(L, "alt",   !!(cmd.options & ALT_KEY));
	HSTR_PUSH_BOOL(L, "ctrl",  !!(cmd.options & CONTROL_KEY));
	HSTR_PUSH_BOOL(L, "shift", !!(cmd.options & SHIFT_KEY));
	HSTR_PUSH_BOOL(L, "right", !!(cmd.options & RIGHT_MOUSE_KEY));
	HSTR_PUSH_BOOL(L, "meta",  !!(cmd.options & META_KEY));

	// push the command tag
	lua_pushnumber(L, cmd.tag);
}
示例#9
0
inline bool CBuilderCAI::OutOfImmobileRange(const Command& cmd) const
{
	if (owner->unitDef->canmove) {
		return false; // builder can move
	}
	if (((cmd.options & INTERNAL_ORDER) == 0) || (cmd.params.size() != 1)) {
		return false; // not an internal object targetted command
	}

	const int objID = cmd.params[0];
	const CWorldObject* obj = uh->GetUnit(objID);

	if (obj == NULL) {
		// features don't move, but maybe the unit was transported?
		obj = featureHandler->GetFeature(objID - uh->MaxUnits());

		if (obj == NULL) {
			return false;
		}
	}

	switch (cmd.GetID()) {
		case CMD_REPAIR:
		case CMD_RECLAIM:
		case CMD_RESURRECT:
		case CMD_CAPTURE: {
			if (!IsInBuildRange(obj)) {
				return true;
			}
			break;
		}
	}
	return false;
}
示例#10
0
void CSelectedUnits::SendCommand(const Command& c)
{
	if (selectionChanged) {
		// send new selection
		SendSelection();
	}
	net->Send(CBaseNetProtocol::Get().SendCommand(gu->myPlayerNum, c.GetID(), c.options, c.params));
}
示例#11
0
std::vector<Command> CCommandAI::GetOverlapQueued(const Command& c, CCommandQueue& q)
{
	CCommandQueue::iterator ci = q.end();
	std::vector<Command> v;
	BuildInfo cbi(c);

	if (ci != q.begin()){
		do {
			--ci; //iterate from the end and dont check the current order
			const Command& t = *ci;

			if (((t.GetID() == c.GetID()) || ((c.GetID() < 0) && (t.GetID() < 0))) &&
			    (t.params.size() == c.params.size())){
				if (c.params.size()==1) {
					// assume the param is a unit or feature id
					if (t.params[0] == c.params[0]) {
						v.push_back(t);
					}
				}
				else if (c.params.size() >= 3) {
					// assume this means that the first 3 makes a position
					BuildInfo tbi;
					if (tbi.Parse(t)) {
						const float dist2X = 2.0f * fabs(cbi.pos.x - tbi.pos.x);
						const float dist2Z = 2.0f * fabs(cbi.pos.z - tbi.pos.z);
						const float addSizeX = SQUARE_SIZE * (cbi.GetXSize() + tbi.GetXSize());
						const float addSizeZ = SQUARE_SIZE * (cbi.GetZSize() + tbi.GetZSize());
						const float maxSizeX = SQUARE_SIZE * std::max(cbi.GetXSize(), tbi.GetXSize());
						const float maxSizeZ = SQUARE_SIZE * std::max(cbi.GetZSize(), tbi.GetZSize());
						if (cbi.def && tbi.def &&
						    ((dist2X > maxSizeX) || (dist2Z > maxSizeZ)) &&
						    ((dist2X < addSizeX) && (dist2Z < addSizeZ))) {
							v.push_back(t);
						}
					} else {
						if ((cbi.pos - tbi.pos).SqLength2D() < (17.0f * 17.0f)) {
							v.push_back(t);
						}
					}
				}
			}
		} while (ci != q.begin());
	}
	return v;
}
示例#12
0
inline void CCommandAI::SetCommandDescParam0(const Command& c)
{
	for (unsigned int n = 0; n < possibleCommands.size(); n++) {
		if (possibleCommands[n].id != c.GetID())
			continue;

		possibleCommands[n].params[0] = IntToString(int(c.params[0]), "%d");
		break;
	}
}
示例#13
0
/**
 * Update the network tables associated with the Scheduler object on the
 * SmartDashboard.
 */
void Scheduler::UpdateTable() {
  CommandSet::iterator commandIter;
  if (m_table != nullptr) {
    // Get the list of possible commands to cancel
    auto new_toCancel = m_table->GetValue("Cancel");
    if (new_toCancel)
      toCancel = new_toCancel->GetDoubleArray();
    else
      toCancel.resize(0);
    //		m_table->RetrieveValue("Ids", *ids);

    // cancel commands that have had the cancel buttons pressed
    // on the SmartDashboad
    if (!toCancel.empty()) {
      for (commandIter = m_commands.begin(); commandIter != m_commands.end();
           ++commandIter) {
        for (unsigned i = 0; i < toCancel.size(); i++) {
          Command* c = *commandIter;
          if (c->GetID() == toCancel[i]) {
            c->Cancel();
          }
        }
      }
      toCancel.resize(0);
      m_table->PutValue("Cancel", nt::Value::MakeDoubleArray(toCancel));
    }

    // Set the running commands
    if (m_runningCommandsChanged) {
      commands.resize(0);
      ids.resize(0);
      for (commandIter = m_commands.begin(); commandIter != m_commands.end();
           ++commandIter) {
        Command* c = *commandIter;
        commands.push_back(c->GetName());
        ids.push_back(c->GetID());
      }
      m_table->PutValue("Names", nt::Value::MakeStringArray(commands));
      m_table->PutValue("Ids", nt::Value::MakeDoubleArray(ids));
    }
  }
}
示例#14
0
inline void CCommandAI::SetCommandDescParam0(const Command& c)
{
	vector<CommandDescription>::iterator cdi;
	for (cdi = possibleCommands.begin(); cdi != possibleCommands.end(); ++cdi) {
		if (cdi->id == c.GetID()) {
			char t[10];
			SNPRINTF(t, 10, "%d", (int)c.params[0]);
			cdi->params[0] = t;
			return;
		}
	}
}
示例#15
0
void CCommandAI::ExecuteAttack(Command& c)
{
	assert(owner->unitDef->canAttack);

	if (inCommand) {
		if (targetDied || (c.params.size() == 1 && UpdateTargetLostTimer(int(c.params[0])) == 0)) {
			FinishCommand();
			return;
		}
		if ((c.params.size() == 3) && (owner->commandShotCount > 0) && (commandQue.size() > 1)) {
			FinishCommand();
			return;
		}
		if (!(c.options & ALT_KEY) && SkipParalyzeTarget(orderTarget)) {
			FinishCommand();
			return;
		}
	}
	else {
		owner->commandShotCount = -1;

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

			if (targetUnit != NULL && targetUnit != owner) {
				owner->AttackUnit(targetUnit, c.GetID() == CMD_MANUALFIRE);

				SetOrderTarget(targetUnit);
				inCommand = true;
			} else {
				FinishCommand();
				return;
			}
		} else {
			float3 pos(c.params[0], c.params[1], c.params[2]);
			owner->AttackGround(pos, c.GetID() == CMD_MANUALFIRE);
			inCommand = true;
		}
	}
}
示例#16
0
CCommandQueue::iterator CCommandAI::GetCancelQueued(const Command& c, CCommandQueue& q)
{
	CCommandQueue::iterator ci = q.end();

	while (ci != q.begin()) {
		--ci; //iterate from the end and dont check the current order
		const Command& c2 = *ci;
		const int cmdID = c.GetID();
		const int cmd2ID = c2.GetID();

		const bool attackAndFight = (cmdID == CMD_ATTACK && cmd2ID == CMD_FIGHT && c2.params.size() == 1);

		if (c2.params.size() != c.params.size())
			continue;

		if ((cmdID == cmd2ID) || (cmdID < 0 && cmd2ID < 0) || attackAndFight) {
			if (c.params.size() == 1) {
				// assume the param is a unit-ID or feature-ID
				if ((c2.params[0] == c.params[0]) &&
				    (cmd2ID != CMD_SET_WANTED_MAX_SPEED)) {
					return ci;
				}
			}
			else if (c.params.size() >= 3) {
				if (cmdID < 0) {
					BuildInfo bc1(c);
					BuildInfo bc2(c2);

					if (bc1.def == NULL) continue;
					if (bc2.def == NULL) continue;

					if (math::fabs(bc1.pos.x - bc2.pos.x) * 2 <= std::max(bc1.GetXSize(), bc2.GetXSize()) * SQUARE_SIZE &&
					    math::fabs(bc1.pos.z - bc2.pos.z) * 2 <= std::max(bc1.GetZSize(), bc2.GetZSize()) * SQUARE_SIZE) {
						return ci;
					}
				} else {
					// assume c and c2 are positional commands
					const float3& c1p = c.GetPos(0);
					const float3& c2p = c2.GetPos(0);

					if ((c1p - c2p).SqLength2D() >= (COMMAND_CANCEL_DIST * COMMAND_CANCEL_DIST))
						continue;
					if ((c.options & SHIFT_KEY) != 0 && (c.options & INTERNAL_ORDER) != 0)
						continue;

					return ci;
				}
			}
		}
	}
	return q.end();
}
示例#17
0
void CCommandAI::FinishCommand()
{
	assert(!commandQue.empty());

	const Command cmd = commandQue.front(); //cppcheck false positive, copy is needed here
	const bool dontRepeat = (cmd.options & INTERNAL_ORDER);

	if (repeatOrders
	    && !dontRepeat
	    && (cmd.GetID() != CMD_STOP)
	    && (cmd.GetID() != CMD_PATROL)
	    && (cmd.GetID() != CMD_SET_WANTED_MAX_SPEED)){
		commandQue.push_back(cmd);
	}

	commandQue.pop_front();
	inCommand = false;
	targetDied = false;
	unimportantMove = false;
	SetOrderTarget(NULL);
	eoh->CommandFinished(*owner, cmd);
	eventHandler.UnitCmdDone(owner, cmd);
	ClearTargetLock(cmd);

	if (commandQue.empty()) {
		if (!owner->group) {
			eoh->UnitIdle(*owner);
		}
		eventHandler.UnitIdle(owner);
	}

	// avoid infinite loops
	if (lastFinishCommand != gs->frameNum) {
		lastFinishCommand = gs->frameNum;
		if (!owner->IsStunned()) {
			SlowUpdate();
		}
	}
}
示例#18
0
static inline bool MayRequireSetMaxSpeedCommand(const Command &c)
{
	switch (c.GetID()) {
		// this is not a complete list
		case CMD_STOP:
		case CMD_WAIT:
		case CMD_SELFD:
		case CMD_FIRE_STATE:
		case CMD_MOVE_STATE:
		case CMD_ONOFF:
		case CMD_REPEAT: {
			return false;
		}
	}
	return true;
}
示例#19
0
static inline bool IsCommandInMap(const Command& c)
{
	// TODO:
	//   extend the check to commands for which
	//   position is not stored in params[0..2]
	if (c.params.size() < 3) {
		return true;
	}
	if ((c.GetPos(0)).IsInBounds()) {
		return true;
	}
	const float3 pos = c.GetPos(0);
	LOG_L(L_DEBUG, "Dropped command %d: outside of map (x:%f y:%f z:%f)", c.GetID(), pos.x, pos.y, pos.z);

	return false;

}
示例#20
0
void CWaitCommandsAI::AcknowledgeCommand(const Command& cmd)
{
	if ((cmd.GetID() != CMD_WAIT) || (cmd.params.size() != 2)) {
		return;
	}
	const KeyType key = Wait::GetKeyFromFloat(cmd.params[1]);
	WaitMap::iterator it = unackedMap.find(key);
	if (it != unackedMap.end()) {
		Wait* wait = it->second;
		if (wait->GetCode() != cmd.params[0]) {
			return; // code mismatch
		}
		// move into the acknowledged pool
		unackedMap.erase(key);
		waitMap[key] = wait;
	}
}
void CSelectedUnitsHandler::SendCommand(const Command& c)
{
	if (selectionChanged) {
		// send new selection

		// first, convert CUnit* to unit IDs.
		std::vector<short> selectedUnitIDs(selectedUnits.size());
		std::vector<short>::iterator i = selectedUnitIDs.begin();
		CUnitSet::const_iterator ui = selectedUnits.begin();
		for(; ui != selectedUnits.end(); ++i, ++ui) {
			*i = (*ui)->id;
		}
		clientNet->Send(CBaseNetProtocol::Get().SendSelect(gu->myPlayerNum, selectedUnitIDs));
		selectionChanged = false;
	}

	clientNet->Send(CBaseNetProtocol::Get().SendCommand(gu->myPlayerNum, c.GetID(), c.options, c.params));
}
示例#22
0
/// pushes 7 items on the stack
static void PushUnitAndCommand(lua_State* L, const CUnit* unit, const Command& cmd)
{
	// push the unit info
	lua_pushnumber(L, unit->id);
	lua_pushnumber(L, unit->unitDef->id);
	lua_pushnumber(L, unit->team);

	// push the command id
	lua_pushnumber(L, cmd.GetID());

	// push the params list
	LuaUtils::PushCommandParamsTable(L, cmd, false);
	// push the options table
	LuaUtils::PushCommandOptionsTable(L, cmd, false);

	// push the command tag
	lua_pushnumber(L, cmd.tag);
}
示例#23
0
CCommandQueue::iterator CCommandAI::GetCancelQueued(const Command& c, CCommandQueue& q)
{
	CCommandQueue::iterator ci = q.end();

	while (ci != q.begin()) {
		--ci; //iterate from the end and dont check the current order
		const Command& c2 = *ci;
		const int& cmd_id = c.GetID();
		const int& cmd2_id = c2.GetID();

		if (((cmd_id == cmd2_id) || ((cmd_id < 0) && (cmd2_id < 0))
				|| (cmd2_id == CMD_FIGHT && cmd_id == CMD_ATTACK && c2.params.size() == 1))
				&& (c2.params.size() == c.params.size())) {
			if (c.params.size() == 1) {
				// assume the param is a unit-ID or feature-ID
				if ((c2.params[0] == c.params[0]) &&
				    (cmd2_id != CMD_SET_WANTED_MAX_SPEED)) {
					return ci;
				}
			}
			else if (c.params.size() >= 3) {
				if (cmd_id < 0) {
					BuildInfo bc(c);
					BuildInfo bc2(c2);
					if (bc.def && bc2.def
					    && fabs(bc.pos.x - bc2.pos.x) * 2 <= std::max(bc.GetXSize(), bc2.GetXSize()) * SQUARE_SIZE
					    && fabs(bc.pos.z - bc2.pos.z) * 2 <= std::max(bc.GetZSize(), bc2.GetZSize()) * SQUARE_SIZE) {
						return ci;
					}
				} else {
					// assume this means that the first 3 makes a position
					float3 cp(c.params[0], c.params[1], c.params[2]);
					float3 c2p(c2.params[0], c2.params[1], c2.params[2]);
					if ((cp - c2p).SqLength2D() < (17.0f * 17.0f)) {
						return ci;
					}
				}
			}
		}
	}
	return q.end();
}
示例#24
0
int CCommandAI::CancelCommands(const Command &c, CCommandQueue& q, bool& first)
{
	first = false;
	int cancelCount = 0;

	while (true) {
		CCommandQueue::iterator ci = GetCancelQueued(c, q);
		if (ci == q.end()) {
			return cancelCount;
		}
		first = first || (ci == q.begin());
		cancelCount++;

		CCommandQueue::iterator firstErase = ci;
		CCommandQueue::iterator lastErase = ci;

		++ci;
		if ((ci != q.end()) && (ci->GetID() == CMD_SET_WANTED_MAX_SPEED)) {
			lastErase = ci;
			cancelCount++;
			++ci;
		}

		if ((ci != q.end()) && (ci->GetID() == CMD_WAIT)) {
			waitCommandsAI.RemoveWaitCommand(owner, *ci);
			lastErase = ci;
			cancelCount++;
			++ci;
		}

		++lastErase; // STL: erase the range [first, last)
		q.erase(firstErase, lastErase);

		if (c.GetID() >= 0) {
			return cancelCount; // only delete one non-build order
		}
	}

	return cancelCount;
}
示例#25
0
void CCommandAI::FinishCommand()
{
	assert(!commandQue.empty());
	const Command cmd = commandQue.front();
	const int cmdID  = cmd.GetID();
	const int cmdTag = cmd.tag;
	const bool dontrepeat = (cmd.options & DONT_REPEAT) ||
	                        (cmd.options & INTERNAL_ORDER);
	if (repeatOrders
	    && !dontrepeat
	    && (cmdID != CMD_STOP)
	    && (cmdID != CMD_PATROL)
	    && (cmdID != CMD_SET_WANTED_MAX_SPEED)){
		commandQue.push_back(commandQue.front());
	}

	commandQue.pop_front();
	inCommand = false;
	targetDied = false;
	unimportantMove = false;
	SetOrderTarget(NULL);
	eoh->CommandFinished(*owner, cmd);
	eventHandler.UnitCmdDone(owner, cmdID, cmdTag);

	if (commandQue.empty()) {
		if (!owner->group) {
			eoh->UnitIdle(*owner);
		}
		eventHandler.UnitIdle(owner);
	}

	if (lastFinishCommand != gs->frameNum) {	//avoid infinite loops
		lastFinishCommand = gs->frameNum;
		if (!owner->stunned) {
			SlowUpdate();
		}
	}
}
示例#26
0
void CommandDrawer::DrawDefaultCommand(const Command& c, const CUnit* owner) const
{
	// TODO add Lua callin perhaps, for more elaborate needs?
	const CCommandColors::DrawData* dd = cmdColors.GetCustomCmdData(c.GetID());
	if (dd == NULL) {
		return;
	}
	const int paramsCount = c.params.size();

	if (paramsCount == 1) {
		const CUnit* unit = uh->GetUnit(c.params[0]);

		if ((unit != NULL) && IsUnitTrackable(unit, owner)) {
			const float3& endPos = helper->GetUnitErrorPos(unit, owner->allyteam);
			lineDrawer.DrawLineAndIcon(dd->cmdIconID, endPos, dd->color);
		}

		return;
	}

	if (paramsCount < 3) {
		return;
	}

	const float3 endPos(c.params[0], c.params[1] + 3.0f, c.params[2]);

	if (!dd->showArea || (paramsCount < 4)) {
		lineDrawer.DrawLineAndIcon(dd->cmdIconID, endPos, dd->color);
	}
	else {
		const float radius = c.params[3];
		lineDrawer.DrawLineAndIcon(dd->cmdIconID, endPos, dd->color);
		lineDrawer.Break(endPos, dd->color);
		glSurfaceCircle(endPos, radius, 20);
		lineDrawer.RestartWithColor(dd->color);
	}
}
示例#27
0
void CBuilderCAI::ExecuteBuildCmd(Command& c)
{
	CBuilder* builder = (CBuilder*) owner;

	map<int, string>::iterator boi = buildOptions.find(c.GetID());
	if (boi == buildOptions.end())
		return;

	if (!inCommand) {
		BuildInfo bi;
		bi.pos.x = floor(c.params[0] / SQUARE_SIZE + 0.5f) * SQUARE_SIZE;
		bi.pos.z = floor(c.params[2] / SQUARE_SIZE + 0.5f) * SQUARE_SIZE;
		bi.pos.y = c.params[1];

		if (c.params.size() == 4)
			bi.buildFacing = abs((int)c.params[3]) % NUM_FACINGS;

		bi.def = unitDefHandler->GetUnitDefByName(boi->second);

		CFeature* f = NULL;
		uh->TestUnitBuildSquare(bi, f, owner->allyteam, true);

		if (f != NULL) {
			if (!bi.def->isFeature || bi.def->wreckName != f->def->name) {
				ReclaimFeature(f);
			} else {
				FinishCommand();
			}
		} else {
			inCommand = true;
			build.Parse(c);
			ExecuteBuildCmd(c);
		}
		return;
	}

	assert(build.def);
	const float radius = GetBuildOptionRadius(build.def, c.GetID());
	if (building) {
		MoveInBuildRange(build.pos, radius);

		if (!builder->curBuild && !builder->terraforming) {
			building = false;
			StopMove(); // cancel the effect of KeepPointingTo
			FinishCommand();
		}
		// This can only be true if two builders started building
		// the restricted unit in the same simulation frame
		else if (uh->unitsByDefs[owner->team][build.def->id].size() > build.def->maxThisUnit) {
			// unit restricted
			building = false;
			builder->StopBuild();
			CancelRestrictedUnit(boi->second);
		}
	} else {
		if (uh->unitsByDefs[owner->team][build.def->id].size() >= build.def->maxThisUnit) {
			// unit restricted, don't bother moving all the way
			// to the construction site first before telling us
			// (since greyed-out icons can still be clicked etc,
			// would be better to prevent that but doesn't cover
			// case where limit reached while builder en-route)
			CancelRestrictedUnit(boi->second);
			StopMove();
			return;
		}

		build.pos = helper->Pos2BuildPos(build, true);

		// we are on the way to the buildpos, meanwhile it can happen
		// that another builder already finished our buildcmd or blocked
		// the buildpos with another building (skip our buildcmd then)
		const bool checkBuildPos = (gs->frameNum % (5 * UNIT_SLOWUPDATE_RATE)) < UNIT_SLOWUPDATE_RATE; //FIXME add a per-unit solution to better balance the load?
		CFeature* feature = NULL;
		if (checkBuildPos && !uh->TestUnitBuildSquare(build, feature, owner->allyteam, true)) {
			if (!feature) {
				const int yardxpos = int(build.pos.x + 4) / SQUARE_SIZE;
				const int yardypos = int(build.pos.z + 4) / SQUARE_SIZE;
				const CSolidObject* s = groundBlockingObjectMap->GroundBlocked(yardxpos, yardypos);
				const CUnit* u = dynamic_cast<const CUnit*>(s);
				if (u != NULL) {
					const bool canAssist =
						   u->beingBuilt
						&& owner->unitDef->canAssist
						&& (!u->soloBuilder || (u->soloBuilder == owner));

					if ((u->unitDef != build.def) || !canAssist) {
						StopMove();
						FinishCommand();
						return;
					}
				}
			}
		}

		if (MoveInBuildRange(build.pos, radius, true)) {
			if (luaRules && !luaRules->AllowUnitCreation(build.def, owner, &build)) {
				StopMove(); // cancel KeepPointingTo
				FinishCommand();
			}
			else if (!teamHandler->Team(owner->team)->AtUnitLimit()) {
				// unit-limit not yet reached
				CFeature* f = NULL;

				bool waitstance = false;
				if (builder->StartBuild(build, f, waitstance) || (++buildRetries > 30)) {
					building = true;
				}
				else if (f != NULL && (!build.def->isFeature || build.def->wreckName != f->def->name)) {
					inCommand = false;
					ReclaimFeature(f);
				}
				else if (!waitstance) {
					const float fpSqRadius = (build.def->xsize * build.def->xsize + build.def->zsize * build.def->zsize);
					const float fpRadius = (math::sqrt(fpSqRadius) * 0.5f) * SQUARE_SIZE;

					// tell everything within the radius of the soon-to-be buildee
					// to get out of the way; using the model radius is not correct
					// because this can be shorter than half the footprint diagonal
					helper->BuggerOff(build.pos, std::max(radius, fpRadius), false, true, owner->team, NULL);
					NonMoving();
				}
			}
		} else {
			if (owner->moveType->progressState == AMoveType::Failed) {
				if (++buildRetries > 5) {
					StopMove();
					FinishCommand();
				}
			}
		}
	}
}
示例#28
0
void CCommandAI::GiveAllowedCommand(const Command& c, bool fromSynced)
{
	if (ExecuteStateCommand(c)) {
		return;
	}

	switch (c.GetID()) {
		case CMD_SELFD: {
			if (owner->unitDef->canSelfD) {
				if (!(c.options & SHIFT_KEY) || commandQue.empty()) {
					if (owner->selfDCountdown != 0) {
						owner->selfDCountdown = 0;
					} else {
						owner->selfDCountdown = owner->unitDef->selfDCountdown*2+1;
					}
				}
				else if (commandQue.back().GetID() == CMD_SELFD) {
					commandQue.pop_back();
				} else {
					commandQue.push_back(c);
				}
			}
			return;
		}
		case CMD_SET_WANTED_MAX_SPEED: {
			if (CanSetMaxSpeed() &&
			    (commandQue.empty() ||
			     (commandQue.back().GetID() != CMD_SET_WANTED_MAX_SPEED))) {
				// bail early, do not check for overlaps or queue cancelling
				commandQue.push_back(c);
				if (commandQue.size()==1 && !owner->beingBuilt) {
					SlowUpdate();
				}
			}
			return;
		}
		case CMD_WAIT: {
			GiveWaitCommand(c);
			return;
		}
		case CMD_INSERT: {
			ExecuteInsert(c, fromSynced);
			return;
		}
		case CMD_REMOVE: {
			ExecuteRemove(c);
			return;
		}
	}

	// flush the queue for immediate commands
	if (!(c.options & SHIFT_KEY)) {
		if (!commandQue.empty()) {
			const int& cmd_id = commandQue.front().GetID();
			if ((cmd_id == CMD_MANUALFIRE) ||
			    (cmd_id == CMD_ATTACK)     ||
			    (cmd_id == CMD_AREA_ATTACK)) {
				owner->AttackUnit(0,true);
			}
			waitCommandsAI.ClearUnitQueue(owner, commandQue);
			ClearCommandDependencies();
			commandQue.clear();
		}
		inCommand=false;
		SetOrderTarget(NULL);
	}

	AddCommandDependency(c);

	if (c.GetID() == CMD_PATROL) {
		CCommandQueue::iterator ci = commandQue.begin();
		for (; ci != commandQue.end() && ci->GetID() != CMD_PATROL; ++ci) {
			// just increment
		}
		if (ci == commandQue.end()) {
			if (commandQue.empty()) {
				Command c2(CMD_PATROL, c.options);
				c2.params.push_back(owner->pos.x);
				c2.params.push_back(owner->pos.y);
				c2.params.push_back(owner->pos.z);
				commandQue.push_back(c2);
			}
			else {
				do {
					--ci;
					if (ci->params.size() >= 3) {
						Command c2(CMD_PATROL, c.options);
						c2.params = ci->params;
						commandQue.push_back(c2);
						break;
					} else if (ci == commandQue.begin()) {
						Command c2(CMD_PATROL, c.options);
						c2.params.push_back(owner->pos.x);
						c2.params.push_back(owner->pos.y);
						c2.params.push_back(owner->pos.z);
						commandQue.push_back(c2);
						break;
					}
				}
				while (ci != commandQue.begin());
			}
		}
	}

	// cancel duplicated commands
	bool first;
	if (CancelCommands(c, commandQue, first) > 0) {
		if (first) {
			Command stopCommand(CMD_STOP);
			commandQue.push_front(stopCommand);
			SlowUpdate();
		}
		return;
	}

	// do not allow overlapping commands
	if (!GetOverlapQueued(c).empty()) {
		return;
	}

	if (c.GetID() == CMD_ATTACK) {
		// avoid weaponless units moving to 0 distance when given attack order
		if (owner->weapons.empty() && (owner->unitDef->canKamikaze == false)) {
			Command c2(CMD_STOP);
			commandQue.push_back(c2);
			return;
		}
	}

	commandQue.push_back(c);

	if (commandQue.size() == 1 && !owner->beingBuilt && !owner->stunned) {
		SlowUpdate();
	}
}
示例#29
0
bool CCommandAI::ExecuteStateCommand(const Command& c)
{
	switch (c.GetID()) {
		case CMD_FIRE_STATE: {
			owner->fireState = (int)c.params[0];
			SetCommandDescParam0(c);
			selectedUnits.PossibleCommandChange(owner);
			return true;
		}
		case CMD_MOVE_STATE: {
			owner->moveState = (int)c.params[0];
			SetCommandDescParam0(c);
			selectedUnits.PossibleCommandChange(owner);
			return true;
		}
		case CMD_REPEAT: {
			if (c.params[0] == 1) {
				repeatOrders = true;
			} else if(c.params[0] == 0) {
				repeatOrders = false;
			} else {
				// cause some code parts need it to be either 0 or 1,
				// we can not accept any other values as valid
				return false;
			}
			SetCommandDescParam0(c);
			selectedUnits.PossibleCommandChange(owner);
			return true;
		}
		case CMD_TRAJECTORY: {
			owner->useHighTrajectory = !!c.params[0];
			SetCommandDescParam0(c);
			selectedUnits.PossibleCommandChange(owner);
			return true;
		}
		case CMD_ONOFF: {
			if (c.params[0] == 1) {
				owner->Activate();
			} else if (c.params[0] == 0) {
				owner->Deactivate();
			} else {
				// cause some code parts need it to be either 0 or 1,
				// we can not accept any other values as valid
				return false;
			}
			SetCommandDescParam0(c);
			selectedUnits.PossibleCommandChange(owner);
			return true;
		}
		case CMD_CLOAK: {
			if (c.params[0] == 1) {
				owner->wantCloak = true;
			} else if(c.params[0] == 0) {
				owner->wantCloak = false;
				owner->curCloakTimeout = gs->frameNum + owner->cloakTimeout;
			} else {
				// cause some code parts need it to be either 0 or 1,
				// we can not accept any other values as valid
				return false;
			}
			SetCommandDescParam0(c);
			selectedUnits.PossibleCommandChange(owner);
			return true;
		}
		case CMD_STOCKPILE: {
			int change = 1;
			if (c.options & RIGHT_MOUSE_KEY) { change *= -1; }
			if (c.options & SHIFT_KEY)       { change *=  5; }
			if (c.options & CONTROL_KEY)     { change *= 20; }
			stockpileWeapon->numStockpileQued += change;
			if (stockpileWeapon->numStockpileQued < 0) {
				stockpileWeapon->numStockpileQued = 0;
			}
			UpdateStockpileIcon();
			return true;
		}
	}
	return false;
}
示例#30
0
bool CCommandAI::AllowedCommand(const Command& c, bool fromSynced)
{
	// TODO check if the command is in the map first, for more commands
	switch (c.GetID()) {
		case CMD_MOVE:
		case CMD_ATTACK:
		case CMD_AREA_ATTACK:
		case CMD_RECLAIM:
		case CMD_REPAIR:
		case CMD_RESURRECT:
		case CMD_PATROL:
		case CMD_RESTORE:
		case CMD_FIGHT:
		case CMD_MANUALFIRE:
		case CMD_UNLOAD_UNIT:
		case CMD_UNLOAD_UNITS: {
			if (!IsCommandInMap(c)) { return false; }
		} break;

		default: {
			// build commands
			if (c.GetID() < 0 && !IsCommandInMap(c)) { return false; }
		} break;
	}


	const UnitDef* ud = owner->unitDef;
	// AI's may do as they like
	const CSkirmishAIHandler::ids_t& saids = skirmishAIHandler.GetSkirmishAIsInTeam(owner->team);
	const bool aiOrder = (!saids.empty());
	const int& cmd_id = c.GetID();
	
	switch (cmd_id) {
		case CMD_MANUALFIRE:
			if (!ud->canManualFire)
				return false;

		case CMD_ATTACK: {
			if (!IsAttackCapable())
				return false;

			if (c.params.size() == 1) {
				const CUnit* attackee = GetCommandUnit(c, 0);

				if (attackee && !attackee->pos.IsInBounds()) {
					return false;
				}
			} else {
				if (c.params.size() == 3) {
					const float3 cPos(c.params[0], c.params[1], c.params[2]);

					// check if attack ground is really attack ground
					if (!aiOrder && !fromSynced &&
						fabs(cPos.y - ground->GetHeightReal(cPos.x, cPos.z)) > SQUARE_SIZE) {
						return false;
					}
				}
			}
			break;
		}

		case CMD_MOVE:      if (!ud->canmove)       return false; break;
		case CMD_FIGHT:     if (!ud->canFight)      return false; break;
		case CMD_GUARD: {
			const CUnit* guardee = GetCommandUnit(c, 0);

			if (!ud->canGuard) { return false; }
			if (owner && !owner->pos.IsInBounds()) { return false; }
			if (guardee && !guardee->pos.IsInBounds()) { return false; }
		} break;

		case CMD_PATROL: {
			if (!ud->canPatrol) { return false; }
		} break;

		case CMD_CAPTURE: {
			const CUnit* capturee = GetCommandUnit(c, 0);

			if (!ud->canCapture) { return false; }
			if (capturee && !capturee->pos.IsInBounds()) { return false; }
		} break;

		case CMD_RECLAIM: {
			const CUnit* reclaimeeUnit = GetCommandUnit(c, 0);
			const CFeature* reclaimeeFeature = NULL;

			if (c.IsAreaCommand()) { return true; }
			if (!ud->canReclaim) { return false; }
			if (reclaimeeUnit && !reclaimeeUnit->unitDef->reclaimable) { return false; }
			if (reclaimeeUnit && !reclaimeeUnit->AllowedReclaim(owner)) { return false; }
			if (reclaimeeUnit && !reclaimeeUnit->pos.IsInBounds()) { return false; }

			if (reclaimeeUnit == NULL && !c.params.empty()) {
				const unsigned int reclaimeeFeatureID(c.params[0]);

				if (reclaimeeFeatureID >= uh->MaxUnits()) {
					reclaimeeFeature = featureHandler->GetFeature(reclaimeeFeatureID - uh->MaxUnits());

					if (reclaimeeFeature && !reclaimeeFeature->def->reclaimable) {
						return false;
					}
				}
			}
		} break;

		case CMD_RESTORE: {
			if (!ud->canRestore || mapDamage->disabled) {
				return false;
			}
		} break;

		case CMD_RESURRECT: {
			if (!ud->canResurrect) { return false; }
		} break;

		case CMD_REPAIR: {
			const CUnit* repairee = GetCommandUnit(c, 0);

			if (!ud->canRepair && !ud->canAssist) { return false; }
			if (repairee && !repairee->pos.IsInBounds()) { return false; }
			if (repairee && ((repairee->beingBuilt && !ud->canAssist) || (!repairee->beingBuilt && !ud->canRepair))) { return false; }
		} break;
	}


	if (cmd_id == CMD_FIRE_STATE
			&& (c.params.empty() || !CanChangeFireState()))
	{
		return false;
	}
	if (cmd_id == CMD_MOVE_STATE
			&& (c.params.empty() || (!ud->canmove && !ud->builder)))
	{
		return false;
	}
	if (cmd_id == CMD_REPEAT && (c.params.empty() || !ud->canRepeat || ((int)c.params[0] % 2) != (int)c.params[0]/* only 0 or 1 allowed */))
	{
		return false;
	}
	if (cmd_id == CMD_TRAJECTORY
			&& (c.params.empty() || ud->highTrajectoryType < 2))
	{
		return false;
	}
	if (cmd_id == CMD_ONOFF
			&& (c.params.empty() || !ud->onoffable || owner->beingBuilt || ((int)c.params[0] % 2) != (int)c.params[0]/* only 0 or 1 allowed */))
	{
		return false;
	}
	if (cmd_id == CMD_CLOAK && (c.params.empty() || !ud->canCloak || ((int)c.params[0] % 2) != (int)c.params[0]/* only 0 or 1 allowed */))
	{
		return false;
	}
	if (cmd_id == CMD_STOCKPILE && !stockpileWeapon)
	{
		return false;
	}
	return true;
}