//------------------------------ //AI Objective Q functions... $ObjectiveClientsSet = 0; function AIObjectiveFindClients(%objective) { //create and clear the set if (! $ObjectiveClientsSet) { $ObjectiveClientsSet = new SimSet(); MissionCleanup.add($ObjectiveClientSet); } $ObjectiveClientsSet.clear(); %clientCount = 0; %count = ClientGroup.getCount(); for(%i = 0; %i < %count; %i++) { %cl = ClientGroup.getObject(%i); if (%cl.objective == %objective) $ObjectiveClientsSet.add(%cl); } return $ObjectiveClientsSet.getCount(); } function AIObjectiveGetClosestClient(%location, %team) { if (%location $= "") return -1; if (%team $= "") %team = 0; %closestClient = -1; %closestDistance = 32767; %count = ClientGroup.getCount(); for(%i = 0; %i < %count; %i++) { %cl = ClientGroup.getObject(%i); if (%cl.isAIControlled() && (%cl.team == %team || %team == 0) && AIClientIsAlive(%cl)) { %testPos = %cl.player.getWorldBoxCenter(); %distance = VectorDist(%location, %testPos); if (%distance < %closestDistance) { %closestDistance = %distance; %closestClient = %cl; } } } return %closestClient; } function AICountObjectives(%team) { %objCount = 0; %count = $ObjectiveQ[%team].getCount(); for (%i = 0; %i < %count; %i++) { %grp = $ObjectiveQ[%team].getObject(%i); if (%grp.getClassName() !$= "AIObjective") %objCount += %grp.getCount(); else %objCount++; } error("DEBUG" SPC %team SPC "has" SPC %objCount SPC "objectives."); } function AIAddTableObjective(%objective, %weight, %level, %bump, %position) { $objTable[%position, objective] = %objective; $objTable[%position, weight] = %weight; $objTable[%position, level] = %level; $objTable[%position, bump] = %bump; $objTableCount = %position + 1; } function AIChooseObjective(%client, %useThisObjectiveQ) { //pick which objectiveQ to use, or use the default if (%useThisObjectiveQ <= 0 && %client.team < 0) return; if (%useThisObjectiveQ <= 0) %useThisObjectiveQ = $ObjectiveQ[%client.team]; if (!isObject(%useThisObjectiveQ) || %useThisObjectiveQ.getCount() <= 0) return; //since most objectives check for inventory, find the closest inventory stations first %inventoryStr = AIFindClosestInventories(%client); //find the most appropriate objective if (!%client.objective) { //note, the table is never empty, during the course of this function AIAddTableObjective(0, 0, 0, 0, 0); } else { //should re-evaluate the current objective weight - but never decrease the weight!!! %testWeight = %client.objective.weight(%client, %client.objectiveLevel, 0, %inventoryStr); if (%testWeight <= 0 || %testWeight > %client.objectiveWeight) %client.objectiveWeight = %testWeight; if (%client.objectiveWeight > 0) AIAddTableObjective(%client.objective, %client.objectiveWeight, %client.objectiveLevel, 0, 0); else AIAddTableObjective(0, 0, 0, 0, 0); } %objCount = %useThisObjectiveQ.getCount(); for (%i = 0; %i < %objCount; %i++) { %objective = %useThisObjectiveQ.getObject(%i); //don't re-evaluate the client's own if (%objective == %client.objective) continue; //try this objective at each of the 4 weight levels to see if it is weighted higher for (%level = 1; %level <= 4; %level++) { %minWeight = 0; %bumpWeight = 0; %bumpClient = ""; //we can bump clients off the objective for the first three levels if (%level <= 3) { //if the objective is part of a group, check the whole group if (%objective.group > 0) { %bumpClient = %objective.group.clientLevel[%level]; %bumpWeight = %bumpClient.objectiveWeight; } else { %bumpClient = %objective.clientLevel[%level]; %bumpWeight = %bumpClient.objectiveWeight; } } //find the minimum weight the objective must have to be considered %minWeight = (%bumpWeight > $objTable[0, weight] ? %bumpWeight : $objTable[0, weight]); //evaluate the weight %weight = %objective.weight(%client, %level, %minWeight, %inventoryStr); //make sure we got a valid weight if (%weight <= 0) break; //if it's the highest so far, it now replaces anything else in the table if (%weight > $objTable[0, weight]) { //never bump someone unless you out- weight them if (%weight > %bumpWeight) { AIAddTableObjective(%objective, %weight, %level, %bumpClient, 0); //no need to keep checking the other levels break; } } //else if it's equal to the highest objective we've seen so far, and higher from our current objective else if (%weight == $objTable[0, weight] && %weight > %client.objectiveWeight) { //never bump someone unless you outweigh them if (%weight > %bumpWeight) { //if this wouldn't require us to bump someone, or the table is empty if (%bumpWeight <= 0 || $objTable[0, weight] <= 0) { //if the table currently contains objectives which would require bumping someone, clear it if ($objTable[0, bump] > 0) %position = 0; else %position = $objTableCount; //add it to the table AIAddTableObjective(%objective, %weight, %level, %bumpClient, %position); //no need to keep checking the other levels break; } //otherwise, the table is not empty, and this would require us to bump someone //only add it if everything else in the table would also require us to bump someone else if ($objTable[0, bump] > 0) { AIAddTableObjective(%objective, %weight, %level, %bumpClient, $objTableCount); //no need to keep checking the other levels break; } } } //else it must have been less than our highest objective so far- again, no need to keep checking other levels... else break; } } //if we have a table of possible objectives which are higher than our current- choose one at random if ($objTableCount > 0 && $objTable[0, objective] != %client.objective) { //choose the new one %index = mFloor(getRandom() * ($objTableCount - 0.01)); //clear the old objective if (%client.objective) { if (%client.objectiveLevel <= 3) { if (%client.objective.group > 0) { if (%client.objective.group.clientLevel[%client.objectiveLevel] == %client) %client.objective.group.clientLevel[%client.objectiveLevel] = ""; } else { if (%client.objective.clientLevel[%client.objectiveLevel] == %client) %client.objective.clientLevel[%client.objectiveLevel] = ""; } } %client.objective.unassignClient(%client); } //assign the new %chooseObjective = $objTable[%index, objective]; %client.objective = %chooseObjective; %client.objectiveWeight = $objTable[%index, weight]; %client.objectiveLevel = $objTable[%index, level]; if (%client.objectiveLevel <= 3) { if (%chooseObjective.group > 0) %chooseObjective.group.clientLevel[%client.objectiveLevel] = %client; else %chooseObjective.clientLevel[%client.objectiveLevel] = %client; } %chooseObjective.assignClient(%client); //see if this objective needs to be acknowledged if (%chooseObjective.shouldAcknowledge && %chooseObjective.issuedByHuman && isObject(%chooseObjective.issuedByClientId)) { //cancel any pending acknowledgements - a bot probably just got bumped off this objective cancel(%chooseObjective.ackSchedule); %chooseObjective.ackSchedule = schedule(5500, %chooseObjective, "AIAcknowledgeObjective", %client, %chooseObjective); } //if we had to bump someone off this objective, %bumpClient = $objTable[%index, bump]; if (%bumpClient > 0) { //unassign the bumped client and choose a new objective AIUnassignClient(%bumpClient); Game.AIChooseGameObjective(%bumpClient); } } //debuging - refresh aidebugq() if required //if ($AIDebugTeam >= 0) // aiDebugQ($AIDebugTeam); } function AIAcknowledgeObjective(%client, %objective) { %objective.shouldAcknowledge = false; //make sure the client is still assigned to this objective if (%client.objective == %objective) serverCmdAcceptTask(%client, %objective.issuedByClientId, -1, %objective.ackDescription); } function AIForceObjective(%client, %newObjective, %useWeight) { //if we found a new objective, release the old, and assign the new if (%newObjective && %newObjective != %client.objective) { //see if someone was already assigned to this objective if (%newObjective.group > 0) %prevClient = newObjective.group.clientLevel[1]; else %prevClient = newObjective.clientLevel[1]; if (%prevClient > 0) AIUnassignClient(%prevClient); //see if we should override the weight if (%useWeight < %newObjective.weightLevel1) %useWeight = %newObjective.weightLevel1; //release the client, and force the assignment AIUnassignClient(%client); %client.objective = %newObjective; %client.objectiveWeight = %useWeight; %client.objectiveLevel = 1; if (%newObjective.group > 0) %newObjective.group.clientLevel[1] = %client; else %newObjective.clientLevel[1] = %client; %newObjective.forceClientId = %client; %newObjective.assignClient(%client); //don't acknowledge anything that's been forced... %newObjective.shouldAcknowledge = false; //now reassign the prev client if (%prevClient) Game.AIChooseGameObjective(%prevClient); } //debuging - refresh aidebugq() if required //if ($AIDebugTeam >= 0) // aiDebugQ($AIDebugTeam); } function AIUnassignClient(%client) { //first, dissolve any link with a human aiReleaseHumanControl(%client.controlByHuman, %client); if (%client.objective) { if (%client.objectiveLevel <= 3) { if (%client.objective.group > 0) { //make sure the clientLevel was actually this client if (%client.objective.group.clientLevel[%client.objectiveLevel] == %client) %client.objective.group.clientLevel[%client.objectiveLevel] = ""; } else { if (%client.objective.clientLevel[%client.objectiveLevel] == %client) %client.objective.clientLevel[%client.objectiveLevel] = ""; } } %client.objective.unassignClient(%client); %client.objective = ""; %client.objectiveWeight = 0; } //debuging - refresh aidebugq() if required //if ($AIDebugTeam >= 0) // aiDebugQ($AIDebugTeam); } function AIClearObjective(%objective) { %count = ClientGroup.getCount(); for(%i = 0; %i < %count; %i++) { %cl = ClientGroup.getObject(%i); if (%cl.objective == %objective) AIUnassignClient(%cl); } //debuging - refresh aidebugq() if required //if ($AIDebugTeam >= 0) // aiDebugQ($AIDebugTeam); } //------------------------------ //TASKS AND OBJECTIVES function AIDefendLocation::initFromObjective(%task, %objective, %client) { //initialize the task vars from the objective %task.baseWeight = %client.objectiveWeight; %task.targetObject = %objective.targetObjectId; if (%objective.Location !$= "") %task.location = %objective.location; else %task.location = %objective.targetObjectId.getWorldBoxCenter(); %task.equipment = %objective.equipment; %task.buyEquipmentSet = %objective.buyEquipmentSet; %task.desiredEquipment = %objective.desiredEquipment; %task.issuedByClient = %objective.issuedByClientId; %task.chat = %objective.chat; //initialize other task vars %task.sendMsg = true; %task.sendMsgTime = 0; %task.engageTarget = -1; } function AIDefendLocation::assume(%task, %client) { %task.setWeightFreq(15); %task.setMonitorFreq(15); %client.inPerimeter = false; %client.needEquipment = AINeedEquipment(%task.equipment, %client); //even if we don't *need* equipemnt, see if we should buy some... if (! %client.needEquipment && %task.buyEquipmentSet !$= "") { //see if we could benefit from inventory %needArmor = AIMustUseRegularInvStation(%task.desiredEquipment, %client); %result = AIFindClosestInventory(%client, %needArmor); %closestInv = getWord(%result, 0); %closestDist = getWord(%result, 1); if (AINeedEquipment(%task.desiredEquipment, %client) && %closestInv > 0) { %result = AIFindClosestEnemy(%client, 200, $AIClientLOSTimeout); %closestEnemy = getWord(%result, 0); %closestEnemydist = getWord(%result, 1); if (%closestEnemy <= 0 || (%closestEnemyDist > %closestDist * 1.5)) %client.needEquipment = true; } } //mark the current time for the buy inventory state machine %task.buyInvTime = getSimTime(); //set a flag to determine if the objective should be re-aquired when the object is destroyed %task.reassignOnDestroyed = false; } function AIDefendLocation::retire(%task, %client) { %task.engageVehicle = -1; %client.setTargetObject(-1); } function AIDefendLocation::weight(%task, %client) { //update the task weight if (%task == %client.objectiveTask) %task.baseWeight = %client.objectiveWeight; %player = %client.player; if (!isObject(%player)) return; %hasMissile = (%player.getInventory("MissileLauncher") > 0) && (%player.getInventory("MissileLauncherAmmo") > 0); //if we're defending with a missile launcher, our first priority is to take out vehicles... //see if we're already attacking a vehicle... if (%task.engageVehicle > 0 && isObject(%task.engageVehicle) && %hasMissile) { //set the weight %task.setWeight(%task.baseWeight); return; } //search for a new vehicle to attack %task.engageVehicle = -1; %losTimeout = $AIClientMinLOSTime + ($AIClientLOSTimeout * %client.getSkillLevel()); %result = AIFindClosestEnemyPilot(%client, 300, %losTimeout); %pilot = getWord(%result, 0); %pilotDist = getWord(%result, 1); //if we've got missiles, and a vehicle to attack... if (%hasMissile && AIClientIsAlive(%pilot)) { %task.engageVehicle = %pilot.vehicleMounted; %client.needEquipment = false; } //otherwise look for a regular enemy to fight... else { %result = AIFindClosestEnemyToLoc(%client, %task.location, 100, %losTimeout); %closestEnemy = getWord(%result, 0); %closestdist = getWord(%result, 1); //see if we found someone if (%closestEnemy > 0) %task.engageTarget = %closestEnemy; else { %task.engageTarget = -1; //see if someone is near me... %result = AIFindClosestEnemy(%client, 100, %losTimeout); %closestEnemy = getWord(%result, 0); %closestdist = getWord(%result, 1); if (%closestEnemy <= 0 || %closestDist > 70) %client.setEngageTarget(-1); } } //set the weight %task.setWeight(%task.baseWeight); } function AIDefendLocation::monitor(%task, %client) { //first, buy the equipment if (%client.needEquipment) { %task.setMonitorFreq(5); if (%task.equipment !$= "") %equipmentList = %task.equipment; else %equipmentList = %task.desiredEquipment; %result = AIBuyInventory(%client, %equipmentList, %task.buyEquipmentSet, %task.buyInvTime); if (%result $= "InProgress") return; else if (%result $= "Finished") { %task.setMonitorFreq(15); %client.needEquipment = false; } else if (%result $= "Failed") { //if this task is the objective task, choose a new objective if (%task == %client.objectiveTask) { AIUnassignClient(%client); Game.AIChooseGameObjective(%client); } return; } } //if we made it past the inventory buying, reset the inv time %task.buyInvTime = getSimTime(); //chat if (%task.sendMsg) { if (%task.sendMsgTime == 0) %task.sendMsgTime = getSimTime(); else if (getSimTime() - %task.sendMsgTime > 7000) { %task.sendMsg = false; if (%client.isAIControlled()) { if (%task.chat !$= "") { %chatMsg = getWord(%task.chat, 0); %chatTemplate = getWord(%task.chat, 1); if (%chatTemplate !$= "") AIMessageThreadTemplate(%chatTemplate, %chatMsg, %client, -1); else AIMessageThread(%task.chat, %client, -1); } else if (%task.targetObject > 0) { %type = %task.targetObject.getDataBlock().getName(); if (%type $= "Flag") AIMessageThreadTemplate("DefendBase", "ChatSelfDefendFlag", %client, -1); else if (%type $= "GeneratorLarge") AIMessageThreadTemplate("DefendBase", "ChatSelfDefendGenerator", %client, -1); else if (%type $= "StationVehicle") AIMessageThreadTemplate("DefendBase", "ChatSelfDefendVehicle", %client, -1); else if (%type $= "SensorLargePulse") AIMessageThreadTemplate("DefendBase", "ChatSelfDefendSensors", %client, -1); else if (%type $= "SensorMediumPulse") AIMessageThreadTemplate("DefendBase", "ChatSelfDefendSensors", %client, -1); else if (%type $= "TurretBaseLarge") AIMessageThreadTemplate("DefendBase", "ChatSelfDefendTurrets", %client, -1); } } } } //if the defend location task has an object, set the "reset" flag if (%task == %client.objectiveTask && isObject(%task.targetObject)) { if (%task.targetObject.getDamageState() !$= "Destroyed") %task.reassignOnDestroyed = true; else { if (%task.reassignOnDestroyed) { AIUnassignClient(%client); Game.AIChooseGameObjective(%client); return; } } } //first, check for a vehicle to engage if (%task.engageVehicle > 0 && isObject(%task.engageVehicle)) { %client.stop(); %client.clearStep(); %client.setEngageTarget(-1); %client.setTargetObject(%task.engageVehicle, 300, "Missile"); } else { //clear the target vehicle... %client.setTargetObject(-1); //see if we're engaging a player if (%client.getEngageTarget() > 0) { //too far, or killed the enemy - return home if (%client.getStepStatus() !$= "InProgress" || %distance > 75) { %client.setEngageTarget(-1); %client.stepMove(%task.location, 8.0); } } //else see if we have a target to begin attacking else if (%task.engageTarget > 0) %client.stepEngage(%task.engageTarget); //else move to a random location around where we are defending else if (%client.getStepName() !$= "AIStepIdlePatrol") { %dist = VectorDist(%client.player.getWorldBoxCenter(), %task.location); if (%dist < 10) { //dissolve the human control link and re-evaluate the weight if (%task == %client.objectiveTask) { if (aiHumanHasControl(%task.issuedByClient, %client)) { aiReleaseHumanControl(%client.controlByHuman, %client); //should re-evaluate the current objective weight %inventoryStr = AIFindClosestInventories(%client); %client.objectiveWeight = %client.objective.weight(%client, %client.objectiveLevel, 0, %inventoryStr); } } %client.stepIdle(%task.location); } else %client.stepMove(%task.location, 8.0); } } //see if we're supposed to be engaging anyone... if (!AIClientIsAlive(%client.getEngageTarget()) && AIClientIsAlive(%client.shouldEngage)) %client.setEngageTarget(%client.shouldEngage); } //------------------------------ function AIAttackLocation::initFromObjective(%task, %objective, %client) { //initialize the task vars from the objective %task.baseWeight = %client.objectiveWeight; %task.location = %objective.location; %task.equipment = %objective.equipment; %task.buyEquipmentSet = %objective.buyEquipmentSet; %task.desiredEquipment = %objective.desiredEquipment; %task.issuedByClient = %objective.issuedByClientId; %task.chat = %objective.chat; //initialize other task vars %task.sendMsg = true; %task.sendMsgTime = 0; %task.engageTarget = -1; } function AIAttackLocation::assume(%task, %client) { %task.setWeightFreq(30); %task.setMonitorFreq(30); %client.needEquipment = AINeedEquipment(%task.equipment, %client); //even if we don't *need* equipemnt, see if we should buy some... if (! %client.needEquipment && %task.buyEquipmentSet !$= "") { //see if we could benefit from inventory %needArmor = AIMustUseRegularInvStation(%task.desiredEquipment, %client); %result = AIFindClosestInventory(%client, %needArmor); %closestInv = getWord(%result, 0); %closestDist = getWord(%result, 1); if (AINeedEquipment(%task.desiredEquipment, %client) && %closestInv > 0) { %result = AIFindClosestEnemyToLoc(%client, %task.location, 50, $AIClientLOSTimeout); %closestEnemy = getWord(%result, 0); if (%closestEnemy <= 0) %client.needEquipment = true; } } //mark the current time for the buy inventory state machine %task.buyInvTime = getSimTime(); %task.snipeLocation = ""; %task.hideLocation = ""; %task.moveToPosition = true; %task.moveToSnipe = false; %task.nextSnipeTime = 0; } function AIAttackLocation::retire(%task, %client) { } function AIAttackLocation::weight(%task, %client) { //update the task weight if (%task == %client.objectiveTask) %task.baseWeight = %client.objectiveWeight; //if we're a sniper, we're going to cheat, and see if there are clients near the attack location %losTimeout = $AIClientMinLOSTime + ($AIClientLOSTimeout * %client.getSkillLevel()); %distToLoc = VectorDist(%client.player.getWorldBoxCenter(), %task.location); if (%client.player.getInventory(SniperRifle) > 0 && %client.player.getInventory(EnergyPack) > 0 && %distToLoc > 60) %result = AIFindClosestEnemyToLoc(%client, %task.location, 50, $AIClientLOSTimeout, true); //otherwise, do the search normally. (cheat ignores LOS)... else %result = AIFindClosestEnemyToLoc(%client, %task.location, 50, %losTimeout, false); %closestEnemy = getWord(%result, 0); %closestdist = getWord(%result, 1); %task.setWeight(%task.baseWeight); //see if we found someone if (%closestEnemy > 0) %task.engageTarget = %closestEnemy; else %task.engageTarget = -1; } function AIAttackLocation::monitor(%task, %client) { //first, buy the equipment if (%client.needEquipment) { %task.setMonitorFreq(5); if (%task.equipment !$= "") %equipmentList = %task.equipment; else %equipmentList = %task.desiredEquipment; %result = AIBuyInventory(%client, %equipmentList, %task.buyEquipmentSet, %task.buyInvTime); if (%result $= "InProgress") return; else if (%result $= "Finished") { %task.setMonitorFreq(30); %client.needEquipment = false; } else if (%result $= "Failed") { //if this task is the objective task, choose a new objective if (%task == %client.objectiveTask) { AIUnassignClient(%client); Game.AIChooseGameObjective(%client); } return; } } //if we made it past the inventory buying, reset the inv time %task.buyInvTime = getSimTime(); //chat if (%task.sendMsg) { if (%task.sendMsgTime == 0) %task.sendMsgTime = getSimTime(); else if (getSimTime() - %task.sendMsgTime > 7000) { %task.sendMsg = false; if (%client.isAIControlled()) { if (%task.chat !$= "") { %chatMsg = getWord(%task.chat, 0); %chatTemplate = getWord(%task.chat, 1); if (%chatTemplate !$= "") AIMessageThreadTemplate(%chatTemplate, %chatMsg, %client, -1); else AIMessageThread(%task.chat, %client, -1); } else AIMessageThreadTemplate("AttackBase", "ChatSelfAttack", %client, -1); } } } //how far are we from the location we're defending %myPos = %client.player.getWorldBoxCenter(); %distance = %client.getPathDistance(%task.location); if (%distance < 0) %distance = 32767; if (%client.player.getInventory(SniperRifle) > 0 && %client.player.getInventory(EnergyPack) > 0) { //first, find an LOS location if (%task.snipeLocation $= "") { %task.snipeLocation = %client.getLOSLocation(%task.location, 150, 250); %task.hideLocation = %client.getHideLocation(%task.location, VectorDist(%task.location, %task.snipeLocation), %task.snipeLocation, 1); %client.stepMove(%task.hideLocation, 4.0); %task.moveToPosition = true; } else { //see if we can acquire a target %energy = %client.player.getEnergyPercent(); %distToSnipe = VectorDist(%task.snipelocation, %client.player.getWorldBoxCenter()); %distToHide = VectorDist(%task.hidelocation, %client.player.getWorldBoxCenter()); //until we're in position, we can move using the AIModeExpress, after that, we only want to walk... if (%task.moveToPosition) { if (%distToHide < 4.0) { //dissolve the human control link if (%task == %client.objectiveTask) { if (aiHumanHasControl(%task.issuedByClient, %client)) { aiReleaseHumanControl(%client.controlByHuman, %client); //should re-evaluate the current objective weight %inventoryStr = AIFindClosestInventories(%client); %client.objectiveWeight = %client.objective.weight(%client, %client.objectiveLevel, 0, %inventoryStr); } } %task.moveToPosition = false; } } else if (%task.moveToSnipe) { if (%energy > 0.75 && %client.getStepStatus() $= "Finished") { %client.stepMove(%task.snipeLocation, 4.0, $AIModeWalk); %client.setEngageTarget(%task.engageTarget); } else if (%energy < 0.4) { %client.setEngageTarget(-1); %client.stepMove(%task.hideLocation, 4.0); %task.nextSnipeTime = getSimTime() + 4000 + (getRandom() * 4000); %task.moveToSnipe = false; } } else if (%energy > 0.5 && %task.engageTarget > 0 && getSimTime() > %task.nextSnipeTime) { %client.stepRangeObject(%task.engageTarget.player.getWorldBoxCenter(), "BasicSniperShot", 150, 250, %task.snipelocation); %client.aimAt(%task.engageTarget.player.getWorldBoxCenter(), 8000); %task.moveToSnipe = true; } } } else { //else see if we have a target to begin attacking if (%client.getEngageTarget() <= 0 && %task.engageTarget > 0) %client.stepEngage(%task.engageTarget); //else move to the location we're defending else if (%client.getEngageTarget() <= 0) { %client.stepMove(%task.location, 8.0); if (VectorDist(%client.player.position, %task.location) < 10) { //dissolve the human control link if (%task == %client.objectiveTask) { if (aiHumanHasControl(%task.issuedByClient, %client)) { aiReleaseHumanControl(%client.controlByHuman, %client); //should re-evaluate the current objective weight %inventoryStr = AIFindClosestInventories(%client); %client.objectiveWeight = %client.objective.weight(%client, %client.objectiveLevel, 0, %inventoryStr); } } } } } //see if we're supposed to be engaging anyone... if (!AIClientIsAlive(%client.getEngageTarget()) && AIClientIsAlive(%client.shouldEngage)) %client.setEngageTarget(%client.shouldEngage); } //------------------------------ function AIAttackPlayer::initFromObjective(%task, %objective, %client) { %task.baseWeight = %client.objectiveWeight; %task.targetClient = %objective.targetClientId; %task.equipment = %objective.equipment; %task.buyEquipmentSet = %objective.buyEquipmentSet; %task.desiredEquipment = %objective.desiredEquipment; %task.issuedByClient = %objective.issuedByClientId; } function AIAttackPlayer::assume(%task, %client) { %task.setWeightFreq(15); %task.setMonitorFreq(15); %client.needEquipment = AINeedEquipment(%task.equipment, %client); if (! %client.needEquipment) %client.stepEngage(%task.targetClient); //even if we don't *need* equipemnt, see if we should buy some... if (! %client.needEquipment && %task.buyEquipmentSet !$= "") { //see if we could benefit from inventory %needArmor = AIMustUseRegularInvStation(%task.desiredEquipment, %client); %result = AIFindClosestInventory(%client, %needArmor); %closestInv = getWord(%result, 0); %closestDist = getWord(%result, 1); if (AINeedEquipment(%task.desiredEquipment, %client) && %closestInv > 0) { %distToTarg = %client.getPathDistance(%task.targetClient.player.getWorldBoxCenter()); if (%distToTarg < 0 || %distToTarg > 100) %client.needEquipment = true; } } //mark the current time for the buy inventory state machine %task.buyInvTime = getSimTime(); } function AIAttackPlayer::retire(%task, %client) { //dissolve the human control link if (%task == %client.objectiveTask) aiReleaseHumanControl(%client.controlByHuman, %client); } function AIAttackPlayer::weight(%task, %client) { //update the task weight if (%task == %client.objectiveTask) %task.baseWeight = %client.objectiveWeight; %task.setWeight(%task.baseWeight); } function AIAttackPlayer::monitor(%task, %client) { //first, buy the equipment if (%client.needEquipment) { %task.setMonitorFreq(5); if (%task.equipment !$= "") %equipmentList = %task.equipment; else %equipmentList = %task.desiredEquipment; %result = AIBuyInventory(%client, %equipmentList, %task.buyEquipmentSet, %task.buyInvTime); if (%result $= "InProgress") return; else if (%result $= "Finished") { %task.setMonitorFreq(15); %client.needEquipment = false; %client.stepEngage(%task.targetClient); } else if (%result $= "Failed") { //if this task is the objective task, choose a new objective if (%task == %client.objectiveTask) { AIUnassignClient(%client); Game.AIChooseGameObjective(%client); } return; } } //if we made it past the inventory buying, reset the inv time %task.buyInvTime = getSimTime(); //cheap hack for now... make the bot always know where you are... %client.clientDetected(%task.targetClient); //make sure we're still attacking... if (%client.getStepName() !$= "AIStepEngage") %client.stepEngage(%task.targetClient); //make sure we're still attacking the right target %client.setEngageTarget(%task.targetClient); if (%client.getStepStatus() !$= "InProgress" && %task == %client.objectiveTask) { AIUnassignClient(%client); Game.AIChooseGameObjective(%client); } } //------------------------------ function AITouchObject::initFromObjective(%task, %objective, %client) { %task.baseWeight = %client.objectiveWeight; %task.targetObject = %objective.targetObjectId; %task.mode = %objective.mode; if (%objective.mode $= "FlagCapture") %task.location = %objective.location; else if(%objective.mode $= "TouchFlipFlop") %task.location = %objective.location; else %task.location = ""; %task.equipment = %objective.equipment; %task.buyEquipmentSet = %objective.buyEquipmentSet; %task.desiredEquipment = %objective.desiredEquipment; %task.issuedByClient = %objective.issuedByClientId; %task.sendMsgTime = 0; if (%task.mode $= "FlagGrab") %task.sendMsg = true; else %task.sendMsg = false; } function AITouchObject::assume(%task, %client) { %task.setWeightFreq(15); %task.setMonitorFreq(15); %task.engageTarget = 0; %client.needEquipment = AINeedEquipment(%task.equipment, %client); //even if we don't *need* equipemnt, see if we should buy some... if (! %client.needEquipment && (%task.mode $= "FlagGrab" || %task.mode $= "TouchFlipFlop") && %task.buyEquipmentSet !$= "") { //see if we could benefit from inventory %needArmor = AIMustUseRegularInvStation(%task.desiredEquipment, %client); %result = AIFindClosestInventory(%client, %needArmor); %closestInv = getWord(%result, 0); %closestDist = getWord(%result, 1); if (AINeedEquipment(%task.desiredEquipment, %client) && %closestInv > 0) { //find where we are %clientPos = %client.player.getWorldBoxCenter(); %distToObject = %client.getPathDistance(%task.location); if (%distToObject < 0 || %closestDist < %distToObject) %client.needEquipment = true; } } //mark the current time for the buy inventory state machine %task.buyInvTime = getSimTime(); } function AITouchObject::retire(%task, %client) { } function AITouchObject::weight(%task, %client) { //update the task weight if (%task == %client.objectiveTask) %task.baseWeight = %client.objectiveWeight; //see if we can find someone to shoot at... if (%client.getEngageTarget() <= 0) { %losTimeout = $AIClientMinLOSTime + ($AIClientLOSTimeout * %client.getSkillLevel()); %myLocation = %client.player.getWorldBoxCenter(); %result = AIFindClosestEnemy(%client, 40, %losTimeout); %task.engageTarget = getWord(%result, 0); } %task.setWeight(%task.baseWeight); } function AITouchObject::monitor(%task, %client) { //first, buy the equipment if (%client.needEquipment) { %task.setMonitorFreq(5); if (%task.equipment !$= "") %equipmentList = %task.equipment; else %equipmentList = %task.desiredEquipment; %result = AIBuyInventory(%client, %equipmentList, %task.buyEquipmentSet, %task.buyInvTime); if (%result $= "InProgress") return; else if (%result $= "Finished") { %task.setMonitorFreq(15); %client.needEquipment = false; } else if (%result $= "Failed") { //if this task is the objective task, choose a new objective if (%task == %client.objectiveTask) { AIUnassignClient(%client); Game.AIChooseGameObjective(%client); } return; } } //if we made it past the inventory buying, reset the inv time %task.buyInvTime = getSimTime(); //chat if (%task.sendMsg) { if (%task.sendMsgTime == 0) %task.sendMsgTime = getSimTime(); else if (getSimTime() - %task.sendMsgTime > 7000) { %task.sendMsg = false; if (%client.isAIControlled()) { if (%task.mode $= "FlagGrab") AIMessageThreadTemplate("AttackBase", "ChatSelfAttackFlag", %client, -1); } } } //keep updating the position, in case the flag is flying through the air... if (%task.location !$= "") %touchPos = %task.location; else %touchPos = %task.targetObject.getWorldBoxCenter(); //see if we need to engage a new target %engageTarget = %client.getEngageTarget(); if (!AIClientIsAlive(%engageTarget) && %task.engageTarget > 0) %client.setEngageTarget(%task.engageTarget); //else see if we should abandon the engagement else if (AIClientIsAlive(%engageTarget)) { %myPos = %client.player.getWorldBoxCenter(); %testPos = %engageTarget.player.getWorldBoxCenter(); %distance = %client.getPathDistance(%testPos); if (%distance < 0 || %distance > 70) %client.setEngageTarget(-1); } //see if we have completed our objective if (%task == %client.objectiveTask) { %completed = false; switch$ (%task.mode) { case "TouchFlipFlop": if (%task.targetObject.team == %client.team) %completed = true; case "FlagGrab": if (!%task.targetObject.isHome) %completed = true; case "FlagDropped": if ((%task.targetObject.isHome) || (%task.targetObject.carrier !$= "")) %completed = true; case "FlagCapture": if (%task.targetObject.carrier != %client.player) %completed = true; } if (%completed) { AIUnassignClient(%client); Game.AIChooseGameObjective(%client); return; } } if (%task.mode $= "FlagCapture") { %homeFlag = $AITeamFlag[%client.team]; //if we're within range of the flag's home position, and the flag isn't home, start idling... if (VectorDist(%client.player.position, %touchPos) < 40 && !%homeFlag.isHome) { if (%client.getStepName() !$= "AIStepIdlePatrol") %client.stepIdle(%touchPos); } else %client.stepMove(%touchPos, 0.25); } else %client.stepMove(%touchPos, 0.25); if (VectorDist(%client.player.position, %touchPos) < 10) { //dissolve the human control link if (%task == %client.objectiveTask) { if (aiHumanHasControl(%task.issuedByClient, %client)) { aiReleaseHumanControl(%client.controlByHuman, %client); //should re-evaluate the current objective weight %inventoryStr = AIFindClosestInventories(%client); %client.objectiveWeight = %client.objective.weight(%client, %client.objectiveLevel, 0, %inventoryStr); } } } //see if we're supposed to be engaging anyone... if (!AIClientIsAlive(%client.getEngageTarget()) && AIClientIsAlive(%client.shouldEngage)) %client.setEngageTarget(%client.shouldEngage); } //------------------------------ function AIEscortPlayer::initFromObjective(%task, %objective, %client) { %task.baseWeight = %client.objectiveWeight; %task.targetClient = %objective.targetClientId; %task.equipment = %objective.equipment; %task.buyEquipmentSet = %objective.buyEquipmentSet; %task.desiredEquipment = %objective.desiredEquipment; %task.issuedByClient = %objective.issuedByClientId; %task.forceClient = %objective.forceClientId; } function AIEscortPlayer::assume(%task, %client) { %task.setWeightFreq(15); %task.setMonitorFreq(15); %task.rangedTarget = false; if (%task == %client.objectiveTask && %client == %task.forceClient && %task.issuedByClient == %task.targetClient) { %client.needEquipment = false; %client.mountVehicle = false; } else { %client.needEquipment = AINeedEquipment(%task.equipment, %client); if (! %client.needEquipment) %client.stepEscort(%task.targetClient); //even if we don't *need* equipemnt, see if we should buy some... if (! %client.needEquipment && %task.buyEquipmentSet !$= "") { //see if we could benefit from inventory %needArmor = AIMustUseRegularInvStation(%task.desiredEquipment, %client); %result = AIFindClosestInventory(%client, %needArmor); %closestInv = getWord(%result, 0); %closestDist = getWord(%result, 1); if (AINeedEquipment(%task.desiredEquipment, %client) && %closestInv > 0) { //find where we are %clientPos = %client.player.getWorldBoxCenter(); %targPos = %task.targetClient.player.getWorldBoxCenter(); %distToTarg = %client.getPathDistance(%targPos); if (%closestDist < 50 && (%distToTarg < 0 || %distToTarg > 100)) %client.needEquipment = true; } } } //mark the current time for the buy inventory state machine %task.buyInvTime = getSimTime(); } function AIEscortPlayer::retire(%task, %client) { %client.clearStep(); if(%client.player.isMounted()) AIDisembarkVehicle(%client); //clear the target object %client.setTargetObject(-1); } function AIEscortPlayer::weight(%task, %client) { //update the task weight if (%task == %client.objectiveTask) %task.baseWeight = %client.objectiveWeight; //make sure we still have someone to escort if (!AiClientIsAlive(%task.targetClient)) { %task.setWeight(0); return; } //always shoot at the closest person to the client being escorted %targetPos = %task.targetClient.player.getWorldBoxCenter(); %losTimeout = $AIClientMinLOSTime + ($AIClientLOSTimeout * %client.getSkillLevel()); %result = AIFindClosestEnemyToLoc(%client, %targetPos, 50, %losTimeout); %task.engageTarget = getWord(%result, 0); if (!AIClientIsAlive(%task.engageTarget)) { if (AIClientIsAlive(%task.targetClient.lastDamageClient, %losTimeout) && getSimTime() - %task.targetClient.lastDamageTime < %losTimeout) %task.engageTarget = %task.targetClient.lastDamageClient; } if (!AIClientIsAlive(%task.engageTarget)) { %myPos = %client.player.getWorldBoxCenter(); %result = AIFindClosestEnemy(%client, 50, %losTimeout); %task.engageTarget = getWord(%result, 0); } //if both us and the person we're escorting are in a vehicle, set the weight high! if (%task.targetClient.player.isMounted() && %client.player.isMounted()) { %vehicle = %client.vehicleMounted; if (%vehicle > 0 && isObject(%vehicle) && %vehicle.getDamagePercent() < 0.8) %task.setWeight($AIWeightVehicleMountedEscort); else %task.setWeight(%task.baseWeight); } else %task.setWeight(%task.baseWeight); //find out if our escortee is lazing a target... %task.missileTarget = -1; %targetCount = ServerTargetSet.getCount(); for (%i = 0; %i < %targetCount; %i++) { %targ = ServerTargetSet.getObject(%i); if (%targ.sourceObject == %task.targetClient.player) { //find out which item is being targetted... %targPoint = %targ.getTargetPoint(); InitContainerRadiusSearch(%targPoint, 10, $TypeMasks::TurretObjectType | $TypeMasks::StaticShapeObjectType); %task.missileTarget = containerSearchNext(); break; } } } function AIEscortPlayer::monitor(%task, %client) { //make sure we still have someone to escort if (!AiClientIsAlive(%task.targetClient)) { if (%task == %client.objectiveTask) { AIUnassignClient(%client); Game.AIChooseGameObjective(%client); } return; } //first, buy the equipment if (%client.needEquipment) { %task.setMonitorFreq(5); if (%task.equipment !$= "") %equipmentList = %task.equipment; else %equipmentList = %task.desiredEquipment; %result = AIBuyInventory(%client, %equipmentList, %task.buyEquipmentSet, %task.buyInvTime); if (%result $= "InProgress") return; else if (%result $= "Finished") { %task.setMonitorFreq(15); %client.needEquipment = false; %client.stepEscort(%task.targetClient); %task.buyInvTime = getSimTime(); } else if (%result $= "Failed") { //if this task is the objective task, choose a new objective if (%task == %client.objectiveTask) { AIUnassignClient(%client); Game.AIChooseGameObjective(%client); } return; } } //see if our target is mounted in a vehicle... if (%task.targetClient.player.isMounted()) { //find the passenger seat the bot will take %vehicle = %task.targetClient.vehicleMounted; %node = findAIEmptySeat(%vehicle, %client.player); //make sure there is an empty seat if (%node < 0 && %client.vehicleMounted != %task.targetClient.vehicleMounted) { if (%task == %client.objectiveTask) { AIUnassignClient(%client); Game.AIChooseGameObjective(%client); } return; } //find the passenger seat location... %slotPosition = %vehicle.getSlotTransform(%node); //make sure we're in the correct armor - assault tanks cannot have a heavy... if (%task.targetClient.vehicleMounted.getDataBlock().getName() $= "AssaultVehicle") { //if the bot is in a heavy, break off the escort... if (%client.player.getArmorSize() $= "Heavy") { if (%task == %client.objectiveTask) { AIUnassignClient(%client); Game.AIChooseGameObjective(%client); } return; } //throw away any packs that won't fit if (%client.player.getInventory(InventoryDeployable) > 0) %client.player.throwPack(); else if (%client.player.getInventory(TurretIndoorDeployable) > 0) %client.player.throwPack(); else if (%client.player.getInventory(TurretOutdoorDeployable) > 0) %client.player.throwPack(); } if (%client.player.isMounted()) { //make sure it's the same vehicle :) if (%client.vehicleMounted != %vehicle) AIDisembarkVehicle(%client); } else { //mount the vehicle %client.stepMove(%slotPosition, 0.25, $AIModeMountVehicle); } } else { //disembark if we're mounted, but our target isn't (anymore) if (%client.player.isMounted()) AIDisembarkVehicle(%client); } //see if we're supposed to be mortaring/missiling something... %hasMortar = (%client.player.getInventory("Mortar") > 0) && (%client.player.getInventory("MortarAmmo") > 0); %hasMissile = (%client.player.getInventory("MissileLauncher") > 0) && (%client.player.getInventory("MissileLauncherAmmo") > 0); if (!isObject(%task.engageTarget) && isobject(%task.missileTarget) && %task.missileTarget.getDamageState() !$= "Destroyed" && (%hasMortar || %hasMissile)) { if (%task.rangedTarget) { %client.stop(); %client.clearStep(); %client.setEngageTarget(-1); if (%hasMortar) %client.setTargetObject(%task.missileTarget, 250, "Mortar"); else %client.setTargetObject(%task.missileTarget, 500, "MissileNoLock"); } else if (%client.getStepName() !$= "AIStepRangeObject") { if (%hasMortar) %client.stepRangeObject(%task.missileTarget, "MortarShot", 100, 200); else %client.stepRangeObject(%task.missileTarget, "BasicTargeter", 50, 500); } else if (%client.getStepStatus() $= "Finished") %task.rangedTarget = true; } else { %task.rangedTarget = false; %client.setTargetObject(-1); if (%client.getStepName() !$= "AIStepEscort") %client.stepEscort(%task.targetClient); } //make sure we're still shooting... %client.setEngageTarget(%task.engageTarget); //see if we're supposed to be engaging anyone... if (!AIClientIsAlive(%client.getEngageTarget()) && AIClientIsAlive(%client.shouldEngage)) %client.setEngageTarget(%client.shouldEngage); } //------------------------------ function AIAttackObject::initFromObjective(%task, %objective, %client) { %task.baseWeight = %client.objectiveWeight; %task.targetObject = %objective.targetObjectId; %task.equipment = %objective.equipment; %task.buyEquipmentSet = %objective.buyEquipmentSet; %task.desiredEquipment = %objective.desiredEquipment; %task.issuedByClient = %objective.issuedByClientId; //initialize other task vars %task.sendMsg = true; %task.sendMsgTime = 0; } function AIAttackObject::assume(%task, %client) { %task.setWeightFreq(15); %task.setMonitorFreq(5); %client.needEquipment = AINeedEquipment(%task.equipment, %client); //even if we don't *need* equipemnt, see if we should buy some... if (! %client.needEquipment && %task.buyEquipmentSet !$= "") { //see if we could benefit from inventory %needArmor = AIMustUseRegularInvStation(%task.desiredEquipment, %client); %result = AIFindClosestInventory(%client, %needArmor); %closestInv = getWord(%result, 0); %closestDist = getWord(%result, 1); if (AINeedEquipment(%task.desiredEquipment, %client) && %closestInv > 0) { //find where we are %clientPos = %client.player.getWorldBoxCenter(); %objPos = %task.targetObject.getWorldBoxCenter(); %distToObject = %client.getPathDistance(%objPos); if (%distToObject < 0 || %closestDist < %distToObject) %client.needEquipment = true; } } //mark the current time for the buy inventory state machine %task.buyInvTime = getSimTime(); } function AIAttackObject::retire(%task, %client) { %client.setTargetObject(-1); } function AIAttackObject::weight(%task, %client) { //update the task weight if (%task == %client.objectiveTask) %task.baseWeight = %client.objectiveWeight; //let the monitor decide when to stop attacking %task.setWeight(%task.baseWeight); } function AIAttackObject::monitor(%task, %client) { //first, buy the equipment if (%client.needEquipment) { %task.setMonitorFreq(5); if (%task.equipment !$= "") %equipmentList = %task.equipment; else %equipmentList = %task.desiredEquipment; %result = AIBuyInventory(%client, %equipmentList, %task.buyEquipmentSet, %task.buyInvTime); if (%result $= "InProgress") return; else if (%result $= "Finished") { %task.setMonitorFreq(15); %client.needEquipment = false; } else if (%result $= "Failed") { //if this task is the objective task, choose a new objective if (%task == %client.objectiveTask) { AIUnassignClient(%client); Game.AIChooseGameObjective(%client); } return; } } //if we made it past the inventory buying, reset the inv time %task.buyInvTime = getSimTime(); //chat if (%task.sendMsg) { if (%task.sendMsgTime == 0) %task.sendMsgTime = getSimTime(); else if (getSimTime() - %task.sendMsgTime > 7000) { %task.sendMsg = false; if (%client.isAIControlled()) { if (%task.chat !$= "") { %chatMsg = getWord(%task.chat, 0); %chatTemplate = getWord(%task.chat, 1); if (%chatTemplate !$= "") AIMessageThreadTemplate(%chatTemplate, %chatMsg, %client, -1); else AIMessageThread(%task.chat, %client, -1); } else if (%task.targetObject > 0) { %type = %task.targetObject.getDataBlock().getName(); if (%type $= "GeneratorLarge") AIMessageThreadTemplate("AttackBase", "ChatSelfAttackGenerator", %client, -1); else if (%type $= "SensorLargePulse") AIMessageThreadTemplate("AttackBase", "ChatSelfAttackSensors", %client, -1); else if (%type $= "SensorMediumPulse") AIMessageThreadTemplate("AttackBase", "ChatSelfAttackSensors", %client, -1); else if (%type $= "TurretBaseLarge") AIMessageThreadTemplate("AttackBase", "ChatSelfAttackTurrets", %client, -1); else if (%type $= "StationVehicle") AIMessageThreadTemplate("AttackBase", "ChatSelfAttackVehicle", %client, -1); } } } } //set the target object if (isObject(%task.targetObject) && %task.targetObject.getDamageState() !$= "Destroyed") { %client.setTargetObject(%task.targetObject, 40, "Destroy"); //move towards the object until we're within range if (! %client.targetInRange()) %client.stepMove(%task.targetObject.getWorldBoxCenter(), 8.0); else { //dissolve the human control link if (%task == %client.objectiveTask) aiReleaseHumanControl(%client.controlByHuman, %client); %client.stop(); } } else { %client.setTargetObject(-1); %client.stop(); //if this task is the objective task, choose a new objective if (%task == %client.objectiveTask) { AIUnassignClient(%client); Game.AIChooseGameObjective(%client); } } } //------------------------------ function AIRepairObject::initFromObjective(%task, %objective, %client) { %task.baseWeight = %client.objectiveWeight; %task.targetObject = %objective.targetObjectId; //need to force this objective to only require a repair pack //%task.equipment = %objective.equipment; %task.equipment = "RepairPack"; %task.buyEquipmentSet = %objective.buyEquipmentSet; %task.desiredEquipment = %objective.desiredEquipment; %task.issuedByClient = %objective.issuedByClientId; %task.deployed = %objective.deployed; if (%task.deployed) { %task.location = %objective.position; %task.deployDirection = MatrixMulVector("0 0 0 " @ getWords(%objective.getTransform(), 3, 6), "0 1 0"); %task.deployDirection = VectorNormalize(%task.deployDirection); } } function AIRepairObject::assume(%task, %client) { %task.setWeightFreq(15); %task.setMonitorFreq(15); %client.needEquipment = AINeedEquipment(%task.equipment, %client); //clear the target object, and range it %client.setTargetObject(-1); if (! %client.needEquipment) { if (%task.deployed) { %task.repairLocation = VectorAdd(%task.location,VectorScale(%task.deployDirection, -4.0)); %client.stepMove(%task.repairLocation, 0.25); } else %client.stepRangeObject(%task.targetObject, "DefaultRepairBeam", 3, 8); } //mark the current time for the buy inventory state machine %task.buyInvTime = getSimTime(); %task.needToRangeTime = 0; %task.pickupRepairPack = -1; %task.usingInv = false; //set a tag to help the repairPack.cs script fudge acquiring a target %client.repairObject = %task.targetObject; } function AIRepairObject::retire(%task, %client) { %client.setTargetObject(-1); %client.repairObject = -1; } function AIRepairObject::weight(%task, %client) { //update the task weight if (%task == %client.objectiveTask) %task.baseWeight = %client.objectiveWeight; //let the monitor decide when to stop repairing %task.setWeight(%task.baseWeight); } function AIRepairObject::monitor(%task, %client) { //first, buy the equipment if (%client.needEquipment) { %task.setMonitorFreq(5); //first, see if we still need a repair pack if (%client.player.getInventory(RepairPack) > 0) { %client.needEquipment = false; %task.setMonitorFreq(15); //if this is to repair a deployed object, walk to the deploy point... if (%task.deployed) { %task.repairLocation = VectorAdd(%task.location,VectorScale(%task.deployDirection, -4.0)); %client.stepMove(%task.repairLocation, 0.25); } //otherwise, we'll need to range it... else %client.stepRangeObject(%task.targetObject, "DefaultRepairBeam", 3, 8); } else { // check to see if there's a repair pack nearby %closestRepairPack = -1; %closestRepairDist = 32767; //search the AIItemSet for a repair pack (someone might have dropped one...) %itemCount = $AIItemSet.getCount(); for (%i = 0; %i < %itemCount; %i++) { %item = $AIItemSet.getObject(%i); if (%item.getDataBlock().getName() $= "RepairPack" && !%item.isHidden()) { %dist = %client.getPathDistance(%item.getWorldBoxCenter()); if (%dist > 0 && %dist < %closestRepairDist) { %closestRepairPack = %item; %closestRepairDist = %dist; } } } //choose whether we're picking up the closest pack, or buying from an inv station... if ((isObject(%closestRepairPack) && %closestRepairPack != %task.pickupRepairPack) || (%task.buyInvTime != %client.buyInvTime)) { %task.pickupRepairPack = %closestRepairPack; //initialize the inv buying %task.buyInvTime = getSimTime(); AIBuyInventory(%client, "RepairPack", %task.buyEquipmentSet, %task.buyInvTime); //now decide which is closer if (isObject(%closestRepairPack)) { if (isObject(%client.invToUse)) { %dist = %client.getPathDistance(%item.position); if (%dist > %closestRepairDist) %task.usingInv = true; else %task.usingInv = false; } else %task.usingInv = false; } else %task.usingInv = true; } //now see if we found a closer repair pack if (!%task.usingInv) { %client.stepMove(%task.pickupRepairPack.position, 0.25); %distToPack = %client.getPathDistance(%task.pickupRepairPack.position); if (%distToPack < 10 && %client.player.getMountedImage($BackpackSlot) > 0) %client.player.throwPack(); //and we're finished until we actually have a repair pack... return; } else { %result = AIBuyInventory(%client, "RepairPack", %task.buyEquipmentSet, %task.buyInvTime); if (%result $= "InProgress") return; else if (%result $= "Finished") { %client.needEquipment = false; %task.setMonitorFreq(15); //if this is to repair a deployed object, walk to the deploy point... if (%task.deployed) { %task.repairLocation = VectorAdd(%task.location,VectorScale(%task.deployDirection, -4.0)); %client.stepMove(%task.repairLocation, 0.25); } //otherwise, we'll need to range it... else %client.stepRangeObject(%task.targetObject, "DefaultRepairBeam", 3, 8); } else if (%result $= "Failed") { //if this task is the objective task, choose a new objective if (%task == %client.objectiveTask) { AIUnassignClient(%client); Game.AIChooseGameObjective(%client); } return; } } } } //if we made it past the inventory buying, reset the inv time %task.buyInvTime = getSimTime(); //chat if (%task.sendMsg) { if (%task.sendMsgTime == 0) %task.sendMsgTime = getSimTime(); else if (getSimTime() - %task.sendMsgTime > 7000) { %task.sendMsg = false; if (%client.isAIControlled()) { if (%task.chat !$= "") { %chatMsg = getWord(%task.chat, 0); %chatTemplate = getWord(%task.chat, 1); if (%chatTemplate !$= "") AIMessageThreadTemplate(%chatTemplate, %chatMsg, %client, -1); else AIMessageThread(%task.chat, %client, -1); } else if (%task.targetObject > 0) { %type = %task.targetObject.getDataBlock().getName(); if (%type $= "GeneratorLarge") AIMessageThreadTemplate("RepairBase", "ChatSelfRepairGenerator", %client, -1); else if (%type $= "StationVehicle") AIMessageThreadTemplate("RepairBase", "ChatSelfRepairVehicle", %client, -1); else if (%type $= "SensorLargePulse") AIMessageThreadTemplate("RepairBase", "ChatSelfRepairSensors", %client, -1); else if (%type $= "SensorMediumPulse") AIMessageThreadTemplate("RepairBase", "ChatSelfRepairSensors", %client, -1); else if (%type $= "TurretBaseLarge") AIMessageThreadTemplate("RepairBase", "ChatSelfRepairTurrets", %client, -1); } } } } //set the target object if (%task.targetObject.getDamagePercent() > 0) { //make sure we still have equipment %client.needEquipment = AINeedEquipment(%task.equipment, %client); if (%client.needEquipment) { //if this task is the objective task, choose a new objective if (%task == %client.objectiveTask) { AIUnassignClient(%client); Game.AIChooseGameObjective(%client); return; } } if (%task.deployed) { //see if we're within range of the deploy location %clLoc = %client.player.position; %distance = VectorDist(%clLoc, %task.repairLocation); %dist2D = VectorDist(%client.player.position, getWords(%task.repairLocation, 0, 1) SPC getWord(%client.player.position, 2)); //set the aim when we get near the target... this will be overwritten when we're actually trying to deploy if (%distance < 10 && %dist2D < 10) %client.aimAt(%task.location, 1000); //see if we're at the deploy location if ((%client.pathDistRemaining(20) > %distance + 0.25) || %dist2D > 0.3) { %client.setTargetObject(-1); %client.stepMove(%task.repairLocation, 0.25); } else { %client.stop(); %client.setTargetObject(%task.targetObject, 8.0, "Repair"); } } else { %currentTime = getSimTime(); if (%currentTime > %task.needToRangeTime) { //force a rangeObject every 10 seconds... %task.needToRangeTime = %currentTime + 6000; %client.setTargetObject(-1); %client.stepRangeObject(%task.targetObject, "DefaultRepairBeam", 3, 8); } //if we've ranged the object, start repairing, else unset the object else if (%client.getStepStatus() $= "Finished") { //dissolve the human control link if (%task == %client.objectiveTask) aiReleaseHumanControl(%client.controlByHuman, %client); %client.setTargetObject(%task.targetObject, 8.0, "Repair"); } else %client.setTargetObject(-1); } } else { %client.setTargetObject(-1); //if this task is the objective task, choose a new objective if (%task == %client.objectiveTask) { AIUnassignClient(%client); Game.AIChooseGameObjective(%client); } } } //------------------------------ function AILazeObject::initFromObjective(%task, %objective, %client) { %task.baseWeight = %client.objectiveWeight; %task.targetObject = %objective.targetObjectId; %task.equipment = %objective.equipment; %task.buyEquipmentSet = %objective.buyEquipmentSet; %task.desiredEquipment = %objective.desiredEquipment; %task.issuedByClient = %objective.issuedByClientId; %task.msgAck = true; %task.msgFire = true; } function AILazeObject::assume(%task, %client) { %task.setWeightFreq(30); %task.setMonitorFreq(30); %client.needEquipment = AINeedEquipment(%task.equipment, %client); //clear the target object, and range it %client.setTargetObject(-1); if (! %client.needEquipment) %client.stepRangeObject(%task.targetObject, "BasicTargeter", 80, 300, %task.issuedByClient.player.getWorldBoxCenter()); //set up some task vars %task.celebrate = false; %task.waitTimerMS = 0; //mark the current time for the buy inventory state machine %task.buyInvTime = getSimTime(); } function AILazeObject::retire(%task, %client) { %client.setTargetObject(-1); } function AILazeObject::weight(%task, %client) { //update the task weight if (%task == %client.objectiveTask) %task.baseWeight = %client.objectiveWeight; //let the monitor decide when to stop lazing %task.setWeight(%task.baseWeight); } function AILazeObject::monitor(%task, %client) { //first, buy the equipment if (%client.needEquipment) { %task.setMonitorFreq(5); if (%task.equipment !$= "") %equipmentList = %task.equipment; else %equipmentList = %task.desiredEquipment; %result = AIBuyInventory(%client, %equipmentList, %task.buyEquipmentSet, %task.buyInvTime); if (%result $= "InProgress") return; else if (%result $= "Finished") { %task.setMonitorFreq(30); %client.needEquipment = false; %client.stepRangeObject(%task.targetObject, "BasicTargeter", 80, 300); } else if (%result $= "Failed") { //if this task is the objective task, choose a new objective if (%task == %client.objectiveTask) { AIUnassignClient(%client); Game.AIChooseGameObjective(%client); } return; } } //if we made it past the inventory buying, reset the inv time %task.buyInvTime = getSimTime(); //set the target object if (isObject(%task.targetObject) && %task.targetObject.getDamageState() !$= "Destroyed") { //make sure we still have equipment %client.needEquipment = AINeedEquipment(%task.equipment, %client); if (%client.needEquipment) { //if this task is the objective task, choose a new objective if (%task == %client.objectiveTask) { AIUnassignClient(%client); Game.AIChooseGameObjective(%client); return; } } //look to see if anyone else is also targetting... %foundTarget = false; %numTargets = ServerTargetSet.getCount(); for (%i = 0; %i < %numTargets; %i++) { %targ = ServerTargetSet.getObject(%i); if (%targ.sourceObject != %client.player) { %targDist = VectorDist(%targ.getTargetPoint(), %task.targetObject.getWorldBoxCenter()); if (%targDist < 10) { %foundTarget = true; break; } } } if (%foundTarget) { //if this task is the objective task, choose a new objective if (%task == %client.objectiveTask) AIUnassignClient(%client); } else if (%client.getStepStatus() $= "Finished") { //dissolve the human control link if (%task == %client.objectiveTask) aiReleaseHumanControl(%client.controlByHuman, %client); %client.setTargetObject(%task.targetObject, 300, "Laze"); %task.celebrate = true; %task.waitTimerMS = 0; //make sure we only say "fire..." once if (%task.msgFire) { AIMessageThread("FireOnTarget", %client, -1); %task.msgFire = false; } } else { %client.aimAt(%task.targetObject.getWorldBoxCenter(), 1000); %client.setTargetObject(-1); } } else { %client.setTargetObject(-1); if (%task.celebrate) { if (%task.waitTimerMS == 0) { //add in a "woohoo"! :) //choose the animation range %minCel = 3; %maxCel = 8; //pick a random sound if (getRandom() > 0.25) %sound = "gbl.awesome"; else if (getRandom() > 0.5) %sound = "gbl.thanks"; else if (getRandom() > 0.75) %sound = "gbl.nice"; else %sound = "gbl.rock"; %randTime = mFloor(getRandom() * 500) + 1; schedule(%randTime, %client, "AIPlayAnimSound", %client, %task.targetObject.getWorldBoxCenter(), %sound, %minCel, %maxCel, 0); //set the timer %task.waitTimerMS = getSimTime(); } //else see if the celebration period is over else if (getSimTime() - %task.waitTimerMS > 3000) %task.celebrate = false; } else { //if this task is the objective task, choose a new objective if (%task == %client.objectiveTask) { AIUnassignClient(%client); Game.AIChooseGameObjective(%client); } } } } //------------------------------ function AIMortarObject::initFromObjective(%task, %objective, %client) { %task.baseWeight = %client.objectiveWeight; %task.targetObject = %objective.targetObjectId; %task.equipment = %objective.equipment; %task.buyEquipmentSet = %objective.buyEquipmentSet; %task.desiredEquipment = %objective.desiredEquipment; %task.issuedByClient = %objective.issuedByClientId; %task.mode = %task.targetObject.getDataBlock().getName(); %task.sendMsgTime = 0; %task.sendMsg = true; } function AIMortarObject::assume(%task, %client) { %task.setWeightFreq(30); %task.setMonitorFreq(30); %task.state = moveToRange; %task.waitForTargetter = true; %task.celebrate = false; %task.waitTimerMS = 0; %task.targetAcquired = false; %task.sayAcquired = true; %client.needEquipment = AINeedEquipment(%task.equipment, %client); //even if we don't *need* equipemnt, see if we should buy some... if (! %client.needEquipment && %task.buyEquipmentSet !$= "") { //see if we could benefit from inventory %needArmor = AIMustUseRegularInvStation(%task.desiredEquipment, %client); %result = AIFindClosestInventory(%client, %needArmor); %closestInv = getWord(%result, 0); %closestDist = getWord(%result, 1); if (AINeedEquipment(%task.desiredEquipment, %client) && %closestInv > 0) { //find where we are %clientPos = %client.player.getWorldBoxCenter(); %objPos = %task.targetObject.getWorldBoxCenter(); %distToObject = %client.getPathDistance(%objPos); if (%distToObject < 0 || %closestDist < %distToObject) %client.needEquipment = true; } } //mark the current time for the buy inventory state machine %task.buyInvTime = getSimTime(); } function AIMortarObject::retire(%task, %client) { %client.setTargetObject(-1); //remove the associated lazeObjective if (%task.targetterObjective) { AIClearObjective(%task.targetterObjective); %task.targetterObjective.delete(); %task.targetterObjective = ""; } } function AIMortarObject::weight(%task, %client) { //update the task weight if (%task == %client.objectiveTask) %task.baseWeight = %client.objectiveWeight; //let the monitor decide when to stop mortaring %task.setWeight(%task.baseWeight); } function AIMortarObject::monitor(%task, %client) { //first, buy the equipment if (%client.needEquipment) { %task.setMonitorFreq(5); if (%task.equipment !$= "") %equipmentList = %task.equipment; else %equipmentList = %task.desiredEquipment; %result = AIBuyInventory(%client, %equipmentList, %task.buyEquipmentSet, %task.buyInvTime); if (%result $= "InProgress") return; else if (%result $= "Finished") { %task.setMonitorFreq(30); %client.needEquipment = false; } else if (%result $= "Failed") { //if this task is the objective task, choose a new objective if (%task == %client.objectiveTask) { AIUnassignClient(%client); Game.AIChooseGameObjective(%client); } return; } } //if we made it past the inventory buying, reset the inv time %task.buyInvTime = getSimTime(); //chat if (%task.sendMsg) { if (%task.sendMsgTime == 0) %task.sendMsgTime = getSimTime(); else if (getSimTime() - %task.sendMsgTime > 7000) { %task.sendMsg = false; if (%client.isAIControlled()) { if (%task.chat !$= "") { %chatMsg = getWord(%task.chat, 0); %chatTemplate = getWord(%task.chat, 1); if (%chatTemplate !$= "") AIMessageThreadTemplate(%chatTemplate, %chatMsg, %client, -1); else AIMessageThread(%task.chat, %client, -1); } else if (%task.targetObject > 0) { %type = %task.targetObject.getDataBlock().getName(); if (%type $= "GeneratorLarge") AIMessageThreadTemplate("AttackBase", "ChatSelfAttackGenerator", %client, -1); else if (%type $= "SensorLargePulse") AIMessageThreadTemplate("AttackBase", "ChatSelfAttackSensors", %client, -1); else if (%type $= "SensorMediumPulse") AIMessageThreadTemplate("AttackBase", "ChatSelfAttackSensors", %client, -1); else if (%type $= "TurretBaseLarge") AIMessageThreadTemplate("AttackBase", "ChatSelfAttackTurrets", %client, -1); else if (%type $= "StationVehicle") AIMessageThreadTemplate("AttackBase", "ChatSelfAttackVehicle", %client, -1); } } } } //make sure we still have something to destroy if (isObject(%task.targetObject) && %task.targetObject.getDamageState() !$= "Destroyed") { %clientPos = %client.player.getWorldBoxCenter(); %targetPos = %task.targetObject.getWorldBoxCenter(); %distance = %client.getPathDistance(%targetPos); if (%distance < 0) %distance = 32767; //make sure we still have equipment %client.needEquipment = AINeedEquipment(%task.equipment, %client); if (%client.needEquipment) { //if this task is the objective task, choose a new objective if (%task == %client.objectiveTask) { AIUnassignClient(%client); Game.AIChooseGameObjective(%client); return; } } //next move to within 220 else if (%distance > 220) { %client.setTargetObject(-1); %client.stepMove(%task.targetObject.getWorldBoxCenter(), 15); } //now start ask for someone to laze the target, and start a 20 sec timer else if (%task.waitForTargetter) { //see if we've started the timer if (%task.waitTimerMS == 0) { //range the object %client.stepRangeObject(%task.targetObject, "MortarShot", 100, 200); //now ask for a targeter... %targetType = %task.targetObject.getDataBlock().getName(); if (%targetType $= "TurretBaseLarge") AIMessageThread("ChatCmdTargetTurret", %client, -1); else if (%targetType $= "SensorLargePulse") AIMessageThread("ChatCmdTargetSensors", %client, -1); else if (%targetType $= "SensorMediumPulse") AIMessageThread("ChatCmdTargetSensors", %client, -1); else AIMessageThread("ChatNeedTarget", %client, -1); %task.waitTimerMS = getSimTime(); //create the objective if (! %task.targetterObjective) { %task.targetterObjective = new AIObjective(AIOLazeObject) { dataBlock = "AIObjectiveMarker"; weightLevel1 = $AIWeightLazeObject[1]; weightLevel2 = $AIWeightLazeObject[2]; description = "Laze the " @ %task.targetObject.getName(); targetObjectId = %task.targetObject; issuedByClientId = %client; offense = true; equipment = "TargetingLaser"; }; MissionCleanup.add(%task.targetterObjective); $ObjectiveQ[%client.team].add(%task.targetterObjective); } %task.targetterObjective.lastLazedTime = 0; //remove the escort (want a targetter instead) if (%client.escort) { AIClearObjective(%client.escort); %client.escort.delete(); %client.escort = ""; } } else { %elapsedTime = getSimTime() - %task.waitTimerMS; if (%task.targetterObjective.group > 0) %targetter = %task.targetterObjective.group.clientLevel[1]; else %targetter = %task.targetterObjective.clientLevel[1]; //see if we can find a target near our objective %task.targetAcquired = false; %numTargets = ServerTargetSet.getCount(); for (%i = 0; %i < %numTargets; %i++) { %targ = ServerTargetSet.getObject(%i); %targDist = VectorDist(%targ.getTargetPoint(), %task.targetObject.getWorldBoxCenter()); if (%targDist < 20) { %task.targetAcquired = true; break; } } if (%task.targetAcquired) { %task.waitForTargetter = false; %task.waitTimerMS = 0; %task.celebrate = true; %task.sayAcquired = false; AIMessageThread("ChatTargetAcquired", %client, -1); } //else see if we've run out of time else if ((! %targetter || ! %targetter.isAIControlled()) && %elapsedTime > 20000) { %task.waitForTargetter = false; %task.waitTimerMS = 0; %task.celebrate = true; } } } //now we should finally be attacking with or without a targetter //eventually, the target will be destroyed, or we'll run out of ammo... else { //dissolve the human control link if (%task == %client.objectiveTask) aiReleaseHumanControl(%client.controlByHuman, %client); //see if we didn't acquired a spotter along the way if (%task.targetterObjective.group > 0) %targetter = %task.targetterObjective.group.clientLevel[1]; else %targetter = %task.targetterObjective.clientLevel[1]; if (! %task.targetAcquired && AIClientIsAlive(%targetter) && %targetter.isAIControlled()) { %client.setTargetObject(-1); %task.waitForTargetter = true; } else { //see if we can find a target near our objective if (! %task.targetAcquired) { %numTargets = ServerTargetSet.getCount(); for (%i = 0; %i < %numTargets; %i++) { %targ = ServerTargetSet.getObject(%i); %targDist = VectorDist(%targ.getTargetPoint(), %task.targetObject.getWorldBoxCenter()); if (%targDist < 20) { %task.targetAcquired = true; break; } } //see if we found a target (must be by a human) if (%task.targetAcquired && %task.sayAcquired) { %task.sayAcquired = false; AIMessageThread("ChatTargetAcquired", %client, -1); } } //set the target object, and keep attacking it if (%client.getStepStatus() $= "Finished") %client.setTargetObject(%task.targetObject, 250, "Mortar"); else %client.setTargetObject(-1); } } } //the target must have been destroyed :) else { //dissolve the human control link if (%task == %client.objectiveTask) aiReleaseHumanControl(%client.controlByHuman, %client); %client.setTargetObject(-1); %client.clearStep(); %client.stop(); if (%task.celebrate) { if (%task.waitTimerMS == 0) { //client animation "woohoo"! :) //choose the animation range %minCel = 3; %maxCel = 8; //pick a random sound if (getRandom() > 0.25) %sound = "gbl.awesome"; else if (getRandom() > 0.5) %sound = "gbl.thanks"; else if (getRandom() > 0.75) %sound = "gbl.nice"; else %sound = "gbl.rock"; %randTime = mFloor(getRandom() * 500) + 1; schedule(%randTime, %client, "AIPlayAnimSound", %client, %task.targetObject.getWorldBoxCenter(), %sound, %minCel, %maxCel, 0); //team message AIMessageThread("ChatEnemyTurretsDestroyed", %client, -1); //set the timer %task.waitTimerMS = getSimTime(); } //else see if the celebration period is over else if (getSimTime() - %task.waitTimerMS > 3000) %task.celebrate = false; } else { //if this task is the objective task, choose a new objective if (%task == %client.objectiveTask) { AIUnassignClient(%client); Game.AIChooseGameObjective(%client); } } } } //------------------------------ function AIDeployEquipment::initFromObjective(%task, %objective, %client) { //initialize the task vars from the objective %task.baseWeight = %client.objectiveWeight; %task.location = %objective.location; %task.equipment = %objective.equipment; %task.buyEquipmentSet = %objective.buyEquipmentSet; %task.desiredEquipment = %objective.desiredEquipment; %task.issuedByClient = %objective.issuedByClientId; %task.chat = %objective.chat; //initialize other task vars %task.sendMsg = true; %task.sendMsgTime = 0; //use the Y-axis of the rotation as the desired direction of deployement, //and calculate a walk to point 3 m behind the deploy point. %task.deployDirection = MatrixMulVector("0 0 0 " @ getWords(%objective.getTransform(), 3, 6), "0 1 0"); %task.deployDirection = VectorNormalize(%task.deployDirection); } function AIDeployEquipment::assume(%task, %client) { %task.setWeightFreq(15); %task.setMonitorFreq(15); %client.needEquipment = AINeedEquipment(%task.equipment, %client); //mark the current time for the buy inventory state machine %task.buyInvTime = getSimTime(); %task.passes = 0; %task.deployAttempts = 0; %task.checkObstructed = false; %task.waitMove = 0; } function AIDeployEquipment::retire(%task, %client) { } function AIDeployEquipment::weight(%task, %client) { //update the task weight if (%task == %client.objectiveTask) %task.baseWeight = %client.objectiveWeight; %task.setWeight(%task.baseWeight); } function findTurretDeployPoint(%client, %location, %attempt) { %player = %client.player; if (!isObject(%player)) return "0 0 0"; %feetPos = posFromTransform(%player.getTransform()); %temp = VectorSub(%location, %feetPos); %temp2 = getWord(%temp, 0) @ " " @ getWord(%temp, 1) @ " 0"; %facingVector = VectorNormalize(%temp2); %aimPoint = VectorAdd(%feetPos, %facingVector); //assume that there will be 10 attempts %height = getWord(%location, 2) + 1.0 - (0.2 * %attempt); %aimAt = getWord(%aimPoint, 0) @ " " @ getWord(%aimPoint, 1) @ " " @ %height; return %aimAt; } function AIDeployEquipment::monitor(%task, %client) { //first, buy the equipment if (%client.needEquipment) { %task.setMonitorFreq(5); if (%task.equipment !$= "") %equipmentList = %task.equipment; else %equipmentList = %task.desiredEquipment; %result = AIBuyInventory(%client, %equipmentList, %task.buyEquipmentSet, %task.buyInvTime); if (%result $= "InProgress") return; else if (%result $= "Finished") { %task.setMonitorFreq(30); %client.needEquipment = false; //if we made it past the inventory buying, reset the inv time %task.buyInvTime = getSimTime(); } else if (%result $= "Failed") { //if this task is the objective task, choose a new objective if (%task == %client.objectiveTask) { AIUnassignClient(%client); Game.AIChooseGameObjective(%client); } return; } } //chat if (%task.sendMsg) { if (%task.sendMsgTime == 0) %task.sendMsgTime = getSimTime(); else if (getSimTime() - %task.sendMsgTime > 7000) { %task.sendMsg = false; if (%client.isAIControlled()) { if (%task.chat !$= "") { %chatMsg = getWord(%task.chat, 0); %chatTemplate = getWord(%task.chat, 1); if (%chatTemplate !$= "") AIMessageThreadTemplate(%chatTemplate, %chatMsg, %client, -1); else AIMessageThread(%task.chat, %client, -1); } } } } //see if we're supposed to be engaging anyone... if (AIClientIsAlive(%client.shouldEngage)) { %hasLOS = %client.hasLOSToClient(%client.shouldEngage); %losTime = %client.getClientLOSTime(%client.shouldEngage); if (%hasLOS || %losTime < 1000) %client.setEngageTarget(%client.shouldEngage); else %client.setEngageTarget(-1); } else %client.setEngageTarget(-1); //calculate the deployFromLocation %factor = -1 * (3 - (%task.passes * 0.5)); %task.deployFromLocation = VectorAdd(%task.location,VectorScale(%task.deployDirection, %factor)); //see if we're within range of the deploy location %clLoc = %client.player.position; %distance = VectorDist(%clLoc, %task.deployFromLocation); %dist2D = VectorDist(%client.player.position, getWords(%task.deployFromLocation, 0, 1) SPC getWord(%client.player.position, 2)); //set the aim when we get near the target... this will be overwritten when we're actually trying to deploy if (%distance < 10 && %dist2D < 10) %client.aimAt(%task.location, 1000); if ((%client.pathDistRemaining(20) > %distance + 0.25) || %dist2D > 0.5) { %task.deployAttempts = 0; %task.checkObstructed = false; %task.waitMove = 0; %client.stepMove(%task.deployFromLocation, 0.25); %task.setMonitorFreq(15); return; } if (%task.deployAttempts < 10 && %task.passes < 5 && !AIClientIsAlive(%client.getEngageTarget())) { //dissolve the human control link if (%task == %client.objectiveTask) aiReleaseHumanControl(%client.controlByHuman, %client); %task.setMonitorFreq(3); %client.stop(); if (%task.deployAttempts == 0) %deployPoint = %task.location; else %deployPoint = findTurretDeployPoint(%client, %task.location, %task.deployAttempts); if(%deployPoint !$= "") { // we have possible point %task.deployAttempts++; %client.aimAt(%deployPoint, 2000); //try to deploy the backpack %client.deployPack = true; %client.lastDeployedObject = -1; %client.player.use(Backpack); // check if pack deployed if (isObject(%client.lastDeployedObject)) { //see if there's a "repairObject" objective for the newly deployed thingy... if (%task == %client.objectiveTask) { %deployedObject = %client.lastDeployedObject; //search the current objective group and search for a "repair Object" task... %objective = %client.objective; //delete any previously associated "AIORepairObject" objective if (isObject(%objective.repairObjective)) { AIClearObjective(%objective.repairObjective); %objective.repairObjective.delete(); %objective.repairObjective = ""; } //add the repair objective %objective.repairObjective = new AIObjective(AIORepairObject) { dataBlock = "AIObjectiveMarker"; weightLevel1 = %objective.weightLevel1 - 60; weightLevel2 = 0; description = "Repair the " @ %deployedObject.getDataBlock().getName(); targetObjectId = %deployedObject; issuedByClientId = %client; offense = false; defense = true; equipment = "RepairPack"; }; %objective.repairObjective.deployed = true; %objective.repairObjective.setTransform(%objective.getTransform()); %objective.repairObjective.group = %objective.group; MissionCleanup.add(%objective.repairObjective); $ObjectiveQ[%client.team].add(%objective.repairObjective); //finally, unassign the client so he'll go do something else... AIUnassignClient(%client); Game.AIChooseGameObjective(%client); } //finished return; } } } else if (!%task.checkObstructed) { %task.checkObstructed = true; //see if anything is in our way InitContainerRadiusSearch(%task.location, 4, $TypeMasks::MoveableObjectType | $TypeMasks::VehicleObjectType | $TypeMasks::PlayerObjectType); %objSrch = containerSearchNext(); if (%objSrch == %client.player) %objSrch = containerSearchNext(); if (%objSrch) AIMessageThread("ChatMove", %client, -1); } else if (%task.waitMove < 5 && %task.passes < 5) { %task.waitMove++; //try another pass at deploying if (%task.waitMove == 5) { %task.waitMove = 0; %task.passes++; %task.deployAttempts = 0; //see if we're *right* underneath the deploy point %deployDist2D = VectorDist(getWords(%client.player.position, 0, 1) @ "0", getWords(%task.location, 0, 1) @ "0"); if (%deployDist2D < 0.25) { %client.pressjump(); %client.deployPack = true; %client.player.use(Backpack); // check if pack deployed if(%client.player.getMountedImage($BackpackSlot) == 0) { //don't add a "repairObject" objective for ceiling turrets if (%task == %client.objectiveTask) { AIUnassignClient(%client); Game.AIChooseGameObjective(%client); } } } } } else { //find a new assignment - and remove this one from the Queue if (%task == %client.objectiveTask) { error(%client SPC "from team" SPC %client.team SPC "is invalidating objective:" SPC %client.objective SPC "UNABLE TO DEPLOY EQUIPMENT"); %client.objective.isInvalid = true; AIUnassignClient(%client); Game.AIChooseGameObjective(%client); } } } //------------------------------ //AI Objective functions function ClientHasAffinity(%objective, %client) { if (%objective.offense && %client.offense) return true; else if (%objective.defense && !%client.offense) return true; else return false; } function ClientHasRequiredEquipment(%objective, %client) { return true; } function AIODefault::weight(%objective, %client, %level, %inventoryStr) { //make sure the player is still alive!!!!! if (! AIClientIsAlive(%client)) return 0; //set the base weight switch (%level) { case 1: %weight = %objective.weightLevel1; case 2: %weight = %objective.weightLevel2; case 3: %weight = %objective.weightLevel3; default: %weight = %objective.weightLevel4; } //check Affinity if (ClientHasAffinity(%objective, %client)) %weight += 40; //if the objective doesn't require any equipment, it automatically get's the +100... if (%objective.equipment $= "" && %objective.desiredEquipment $= "") %weight += 100; else { //check equipment requirement %needEquipment = AINeedEquipment(%objective.equipment, %client); //check Required equipment if (%objective.equipment !$= "" && !%needEquipment) %weight += 100; //figure out the percentage of desired equipment the bot has else if (%objective.desiredEquipment !$= "") { %count = getWordCount(%objective.desiredEquipment); %itemCount = 0; for (%i = 0; %i < %count; %i++) { %item = getWord(%objective.desiredEquipment, %i); if (!AINeedEquipment(%item, %client)) %itemCount++; } //add to the weight %weight += mFloor((%itemCount / %count) * 75); } } //find the distance to target if (%objective.targetClientId !$= "" || %objective.targetObjectId !$= "") { if (AIClientIsAlive(%objective.targetClientId)) { %targetPos = %objective.targetClientId.player.getWorldBoxCenter(); } else if (VectorDist(%objective.location, "0 0 0") > 1) %targetPos = %objective.location; else { if(%objective.targetObjectId > 0) %targetPos = %objective.targetObjectId.getWorldBoxCenter(); } } //make sure the destination is accessible %distance = %client.getPathDistance(%targetPos); if (%distance < 0) return 0; %closestInvIsRemote = (getWordCount(%inventoryStr) == 4); %closestInv = getWord(%inventoryStr, 0); %closestDist = getWord(%inventoryStr, 1); %closestRemoteInv = getWord(%inventoryStr, 2); %closestRemoteDist = getWord(%inventoryStr, 3); //if we need equipment, the distance is from the client, to an inv, then to the target if (%needEquipment) { //if we need a regular inventory station, and one doesn't exist, exit if (!isObject(%closestInv) && %needArmor) return 0; //find the closest inv based on whether we require armor (from a regular inv station) if (!%closestInvIsRemote) { %needArmor = false; %weightDist = %closestDist; %weightInv = %closestInv; } else { %needArmor = AIMustUseRegularInvStation(%objective.equipment, %client); if (%needArmor) { %weightDist = %closestDist; %weightInv = %closestInv; } else { %weightDist = %closestRemoteDist; %weightInv = %closestRemoteInv; } } //if we don't need armor, and there's no inventory station, see if the equipment we need //is something we can pick up off the ground (likely this would be a repair pack...) if (%weightDist >= 32767) { %itemType = getWord(%objective.equipment, 0); %found = false; %itemCount = $AIItemSet.getCount(); for (%i = 0; %i < %itemCount; %i++) { %item = $AIItemSet.getObject(%i); if (%item.getDataBlock().getName() $= %itemType && !%item.isHidden()) { %weightDist = %client.getPathDistance(%item.getWorldBoxCenter()); if (%weightDist > 0) { %weightInv = %item; //set the var so the distance function will work... %found = true; break; } } } if (! %found) return 0; } //now find the distance used for weighting the objective %tempDist = AIGetPathDistance(%targetPos, %weightInv.getWorldBoxCenter()); if (%tempDist < 0) %tempDist = 32767; %distance = %weightDist + %tempDist; } //see if we're within 200 m if (%distance < 200) %weight += 30; //see if we're within 90 m if (%distance < 90) %weight += 30; //see if we're within 45 m if (%distance < 45) %weight += 30; //see if we're within 20 m if (%distance < 20) %weight += 30; //final return, since we've made it through all the rest return %weight; } function AIODefault::QuickWeight(%objective, %client, %level, %minWeight) { //can't do a quick weight when re-evaluating a client's current objective if (%client.objective == %objective) return true; //do a quick check to disqualify this objective if it can't meet the minimum weight switch (%level) { case 1: %testWeight = %objective.weightLevel1; case 2: %testWeight = %objective.weightLevel2; case 3: %testWeight = %objective.weightLevel3; default: %testWeight = %objective.weightLevel4; } if (%testWeight + 260 < %minWeight) return false; else return true; } //------------------------------ function AIODefendLocation::weight(%this, %client, %level, %minWeight, %inventoryStr) { // if were playing CnH, check who owns this if (%this.targetObjectId > 0) { if (!isObject(%this.targetObjectId) || %this.targetObjectId.isHidden() || %this.targetObjectId.team != %client.team) return 0; } //make sure the player is still alive!!!!! if (! AIClientIsAlive(%client)) return 0; //do a quick check to disqualify this objective if it can't meet the minimum weight if (!AIODefault::QuickWeight(%this, %client, %level, %minWeight)) { if (%this.targetObjectId > 0 && %this.issuedByClientId == %client.controlByHuman) { if ($AIWeightHumanIssuedCommand < %minWeight) return 0; } else return 0; } %weight = AIODefault::weight(%this, %client, %level, %inventoryStr); //if the object has been destroyed, reduce the weight if (%this.targetObjectId > 0) { //see if we were forced on the objective if (%this.issuedByClientId == %client.controlByHuman && %weight < $AIWeightHumanIssuedCommand) %weight = $AIWeightHumanIssuedCommand; //else see if the object has been destroyed else if (!isObject(%this.targetObjectId) || %this.targetObjectId.getDamageState() $= "Destroyed") %weight -= 320; } return %weight; } function AIODefendLocation::assignClient(%this, %client) { %client.objectiveTask = %client.addTask(AIDefendLocation); %client.objectiveTask.initFromObjective(%this, %client); } function AIODefendLocation::unassignClient(%this, %client) { %client.removeTask(%client.objectiveTask); %client.objectiveTask = ""; } //------------------------------ function AIOAttackLocation::weight(%this, %client, %level, %minWeight, %inventoryStr) { //make sure the player is still alive!!!!! if (! AIClientIsAlive(%client)) return 0; //now, if this bot is linked to a human who has issued this command, up the weight if (%this.issuedByClientId == %client.controlByHuman) { //make sure we have the potential to reach the minWeight if (!AIODefault::QuickWeight(%this, %client, %level, %minWeight)) { if ($AIWeightHumanIssuedCommand < %minWeight) return 0; else %weight = $AIWeightHumanIssuedCommand; } else { // calculate the default... %weight = AIODefault::weight(%this, %client, %level, %inventoryStr); if (%weight < $AIWeightHumanIssuedCommand) %weight = $AIWeightHumanIssuedCommand; } } else { //make sure we have the potential to reach the minWeight if (!AIODefault::QuickWeight(%this, %client, %level, %minWeight)) return 0; // calculate the default... %weight = AIODefault::weight(%this, %client, %level, %inventoryStr); } return %weight; } function AIOAttackLocation::assignClient(%this, %client) { %client.objectiveTask = %client.addTask(AIAttackLocation); %client.objectiveTask.initFromObjective(%this, %client); } function AIOAttackLocation::unassignClient(%this, %client) { %client.removeTask(%client.objectiveTask); %client.objectiveTask = ""; } //------------------------------ function AIOTouchObject::weight(%this, %client, %level, %minWeight, %inventoryStr) { //make sure the player is still alive!!!!! if (! AIClientIsAlive(%client)) return 0; if (!AIODefault::QuickWeight(%this, %client, %level, %minWeight)) return 0; switch$ (%this.mode) { case "TouchFlipFlop": if(%this.targetObjectId.team == %client.team || %this.targetObjectId.isHidden()) return 0; else return AIODefault::weight(%this, %client, %level, %inventoryStr); case "FlagGrab": if (! %this.targetObjectId.isHome) return 0; else return AIODefault::weight(%this, %client, %level, %inventoryStr); case "FlagDropped": if ((%this.targetObjectId.isHome) || (%this.targetObjectId.carrier !$= "")) return 0; else return AIODefault::weight(%this, %client, %level, %inventoryStr); case "FlagCapture": if (%this.targetObjectId.carrier != %client.player) return 0; else { //find our home flag location %homeTeam = %client.team; %homeFlag = $AITeamFlag[%homeTeam]; %this.location = %homeFlag.originalPosition; return AIODefault::weight(%this, %client, %level, %inventoryStr); } } return 0; } function AIOTouchObject::assignClient(%this, %client) { %client.objectiveTask = %client.addTask(AITouchObject); %client.objectiveTask.initFromObjective(%this, %client); //create an AIOEscortPlayer objective to help out, if required if (%this.mode $= "FlagGrab") { %client.escort = new AIObjective(AIOEscortPlayer) { dataBlock = "AIObjectiveMarker"; weightLevel1 = $AIWeightEscortOffense[1]; weightLevel2 = $AIWeightEscortOffense[2]; description = "Escort " @ getTaggedString(%client.name); targetClientId = %client; offense = true; desiredEquipment = "EnergyPack"; buyEquipmentSet = "LightEnergyELF"; }; MissionCleanup.add(%client.escort); $ObjectiveQ[%client.team].add(%client.escort); } else if (%this.mode $= "FlagCapture") { %client.escort = new AIObjective(AIOEscortPlayer) { dataBlock = "AIObjectiveMarker"; weightLevel1 = $AIWeightEscortCapper[1]; weightLevel2 = $AIWeightEscortCapper[2]; description = "Escort " @ getTaggedString(%client.name); targetClientId = %client; offense = true; desiredEquipment = "EnergyPack"; buyEquipmentSet = "LightEnergyDefault"; }; MissionCleanup.add(%client.escort); $ObjectiveQ[%client.team].add(%client.escort); } } function AIOTouchObject::unassignClient(%this, %client) { //kill the escort objective if (%client.escort) { AIClearObjective(%client.escort); %client.escort.delete(); %client.escort = ""; } %client.removeTask(%client.objectiveTask); %client.objectiveTask = ""; } //------------------------------ function AIOAttackPlayer::weight(%this, %client, %level, %minWeight, %inventoryStr) { //make sure the player is still alive!!!!! if (! AIClientIsAlive(%client)) return 0; //if we're attacking the flag carrier, make sure a flag carrier exists if (%this.mode $= "FlagCarrier") { if (%this.targetObjectId.carrier $= "") return 0; else %this.targetClientId = %this.targetObjectId.carrier.client; } //now, if this bot is linked to a human who has issued this command, up the weight if (%this.issuedByClientId == %client.controlByHuman) { //make sure we have the potential to reach the minWeight if (!AIODefault::QuickWeight(%this, %client, %level, %minWeight)) { if ($AIWeightHumanIssuedCommand < %minWeight) return 0; else %weight = $AIWeightHumanIssuedCommand; } else { // calculate the default... %weight = AIODefault::weight(%this, %client, %level, %inventoryStr); if (%weight < $AIWeightHumanIssuedCommand) %weight = $AIWeightHumanIssuedCommand; } } else { //make sure we have the potential to reach the minWeight if (!AIODefault::QuickWeight(%this, %client, %level, %minWeight)) return 0; // calculate the default... %weight = AIODefault::weight(%this, %client, %level, %inventoryStr); } return %weight; } function AIOAttackPlayer::assignClient(%this, %client) { %client.objectiveTask = %client.addTask(AIAttackPlayer); %client.objectiveTask.initFromObjective(%this, %client); } function AIOAttackPlayer::unassignClient(%this, %client) { %client.removeTask(%client.objectiveTask); %client.objectiveTask = ""; } //------------------------------ function AIOEscortPlayer::weight(%this, %client, %level, %minWeight, %inventoryStr) { //make sure the player is still alive!!!!! if (! AIClientIsAlive(%client) || ! AIClientIsAlive(%this.targetClientId)) return 0; //can't escort yourself if (%client == %this.targetClientId) return 0; //make sure the class is appropriate if (%this.forceClientId <= 0 && %this.issuedByClientId != %client.controlByHuman) { %targArmor = %this.targetClientId.player.getArmorSize(); %myArmor = %client.player.getArmorSize(); if ((%targArmor $= "Light" && %myArmor !$= "Light") || %myArmor $= "Heavy") return 0; } //can't bump a forced client from level 1 if (%this.forceClientId > 0 && %this.forceClientId != %client && %level == 1) return 0; //if this bot is linked to a human who has issued this command, up the weight if (%this.issuedByClientId == %client.controlByHuman) { //make sure we have the potential to reach the minWeight if (!AIODefault::QuickWeight(%this, %client, %level, %minWeight)) { if ($AIWeightHumanIssuedEscort < %minWeight) return 0; else %weight = $AIWeightHumanIssuedEscort; } else { // calculate the default... %weight = AIODefault::weight(%this, %client, %level, %inventoryStr); if (%weight < $AIWeightHumanIssuedEscort) %weight = $AIWeightHumanIssuedEscort; } } else { //make sure we have the potential to reach the minWeight if (!AIODefault::QuickWeight(%this, %client, %level, %minWeight)) return 0; // calculate the default... %weight = AIODefault::weight(%this, %client, %level, %inventoryStr); } return %weight; } function AIOEscortPlayer::assignClient(%this, %client) { %client.objectiveTask = %client.addTask(AIEscortPlayer); %client.objectiveTask.initFromObjective(%this, %client); } function AIOEscortPlayer::unassignClient(%this, %client) { %client.removeTask(%client.objectiveTask); %client.objectiveTask = ""; } //------------------------------ function AIOAttackObject::weight(%this, %client, %level, %minWeight, %inventoryStr) { // if were playing CnH, check who owns this if (!isObject(%this.targetObjectId) || %this.targetObjectId.isHidden() || %this.targetObjectId.team == %client.team) return 0; //make sure the player is still alive!!!!! if (! AIClientIsAlive(%client)) return 0; //no need to attack if the object is already destroyed if (!isObject(%this.targetObjectId) || %this.targetObjectId.getDamageState() $= "Destroyed") return 0; else { //if this bot is linked to a human who has issued this command, up the weight if (%this.issuedByClientId == %client.controlByHuman) { //make sure we have the potential to reach the minWeight if (!AIODefault::QuickWeight(%this, %client, %level, %minWeight)) { if ($AIWeightHumanIssuedCommand < %minWeight) return 0; else %weight = $AIWeightHumanIssuedCommand; } else { // calculate the default... %weight = AIODefault::weight(%this, %client, %level, %inventoryStr); if (%weight < $AIWeightHumanIssuedCommand) %weight = $AIWeightHumanIssuedCommand; } } else { //make sure we have the potential to reach the minWeight if (!AIODefault::QuickWeight(%this, %client, %level, %minWeight)) return 0; // calculate the default... %weight = AIODefault::weight(%this, %client, %level, %inventoryStr); } return %weight; } } function AIOAttackObject::assignClient(%this, %client) { %client.objectiveTask = %client.addTask(AIAttackObject); %client.objectiveTask.initFromObjective(%this, %client); } function AIOAttackObject::unassignClient(%this, %client) { %client.removeTask(%client.objectiveTask); %client.objectiveTask = ""; } //------------------------------ function AIORepairObject::weight(%this, %client, %level, %minWeight, %inventoryStr) { // if were playing CnH, check who owns this if (!isObject(%this.targetObjectId) || %this.targetObjectId.isHidden() || %this.targetObjectId.team != %client.team) return 0; //make sure the player is still alive!!!!! if (! AIClientIsAlive(%client)) return 0; //no need to repair if the object isn't in need if (!isObject(%this.targetObjectId) || %this.targetObjectId.getDamagePercent() <= 0) return 0; else { //if this bot is linked to a human who has issued this command, up the weight if (%this.issuedByClientId == %client.controlByHuman) { //make sure we have the potential to reach the minWeight if (!AIODefault::QuickWeight(%this, %client, %level, %minWeight)) { if ($AIWeightHumanIssuedCommand < %minWeight) return 0; else %weight = $AIWeightHumanIssuedCommand; } else { // calculate the default... %weight = AIODefault::weight(%this, %client, %level, %inventoryStr); if (%weight < $AIWeightHumanIssuedCommand) %weight = $AIWeightHumanIssuedCommand; } } else { //make sure we have the potential to reach the minWeight if (!AIODefault::QuickWeight(%this, %client, %level, %minWeight)) return 0; // calculate the default... %weight = AIODefault::weight(%this, %client, %level, %inventoryStr); } return %weight; } } function AIORepairObject::assignClient(%this, %client) { %client.objectiveTask = %client.addTask(AIRepairObject); %client.objectiveTask.initFromObjective(%this, %client); } function AIORepairObject::unassignClient(%this, %client) { %client.removeTask(%client.objectiveTask); %client.objectiveTask = ""; } //------------------------------ function AIOLazeObject::weight(%this, %client, %level, %minWeight, %inventoryStr) { //make sure the player is still alive!!!!! if (! AIClientIsAlive(%client)) return 0; //see if it's already being lazed %numTargets = ServerTargetSet.getCount(); for (%i = 0; %i < %numTargets; %i++) { %targ = ServerTargetSet.getObject(%i); if (%targ.sourceObject != %client.player) { %targDist = VectorDist(%targ.getTargetPoint(), %this.targetObjectId.getWorldBoxCenter()); if (%targDist < 10) { %this.lastLazedTime = getSimTime(); %this.lastLazedClient = %targ.sourceObject.client; break; } } } //no need to laze if the object is already destroyed if (!isObject(%this.targetObjectId) || %this.targetObjectId.getDamageState() $= "Destroyed") return 0; else if (%this.targetObjectId.isHidden() || %this.targetObjectId.team != %client.team) return 0; else if (getSimTime() - %this.lastLazedTime <= 15000 && %this.lastLazedClient != %client) return 0; else { //set the base weight switch (%level) { case 1: %weight = %this.weightLevel1; case 2: %weight = %this.weightLevel2; case 3: %weight = %this.weightLevel3; default: %weight = %this.weightLevel4; } //check Affinity if (ClientHasAffinity(%this, %client)) %weight += 100; //for now, do not deviate from the current assignment to laze a target, if you don't //already have a targeting laser. %needEquipment = AINeedEquipment(%this.equipment, %client); if (!%needEquipment) %weight += 100; else if (!aiHumanHasControl(%client.controlByHuman, %client)) return 0; //see if this client is close to the issuing client if (%this.issuedByClientId > 0) { if (! AIClientIsAlive(%this.issuedByClientId)) return 0; %distance = %client.getPathDistance(%this.issuedByClientId.player.getWorldBoxCenter()); if (%distance < 0) %distance = 32767; //see if we're within 200 m if (%distance < 200) %weight += 30; //see if we're within 90 m if (%distance < 90) %weight += 30; //see if we're within 45 m if (%distance < 45) %weight += 30; } //now, if this bot is linked to a human who has issued this command, up the weight if (%this.issuedByClientId == %client.controlByHuman && %weight < $AIWeightHumanIssuedCommand) %weight = $AIWeightHumanIssuedCommand; return %weight; } } function AIOLazeObject::assignClient(%this, %client) { %client.objectiveTask = %client.addTask(AILazeObject); %client.objectiveTask.initFromObjective(%this, %client); } function AIOLazeObject::unassignClient(%this, %client) { %client.removeTask(%client.objectiveTask); %client.objectiveTask = ""; } //------------------------------ function AIOMortarObject::weight(%this, %client, %level, %minWeight, %inventoryStr) { // if were playing CnH, check who owns this if (!isObject(%this.targetObjectId) || %this.targetObjectId.isHidden() || %this.targetObjectId.team == %client.team) return 0; //make sure the player is still alive!!!!! if (! AIClientIsAlive(%client)) return 0; //no need to attack if the object is already destroyed if (%this.targetObjectId.getDamageState() $= "Destroyed") return 0; else { //if this bot is linked to a human who has issued this command, up the weight if (%this.issuedByClientId == %client.controlByHuman) { //make sure we have the potential to reach the minWeight if (!AIODefault::QuickWeight(%this, %client, %level, %minWeight)) { if ($AIWeightHumanIssuedCommand < %minWeight) return 0; else %weight = $AIWeightHumanIssuedCommand; } else { // calculate the default... %weight = AIODefault::weight(%this, %client, %level, %inventoryStr); if (%weight < $AIWeightHumanIssuedCommand) %weight = $AIWeightHumanIssuedCommand; } } else { //make sure we have the potential to reach the minWeight if (!AIODefault::QuickWeight(%this, %client, %level, %minWeight)) return 0; // calculate the default... %weight = AIODefault::weight(%this, %client, %level, %inventoryStr); } return %weight; } } function AIOMortarObject::assignClient(%this, %client) { %client.objectiveTask = %client.addTask(AIMortarObject); %client.objectiveTask.initFromObjective(%this, %client); //create the escort objective (require a targeting laser in this case...) %client.escort = new AIObjective(AIOEscortPlayer) { dataBlock = "AIObjectiveMarker"; weightLevel1 = $AIWeightEscortOffense[1]; weightLevel2 = $AIWeightEscortOffense[2]; description = "Escort " @ getTaggedString(%client.name); targetClientId = %client; offense = true; equipment = "TargetingLaser"; buyEquipmentSet = "LightEnergyDefault"; }; MissionCleanup.add(%client.escort); $ObjectiveQ[%client.team].add(%client.escort); } function AIOMortarObject::unassignClient(%this, %client) { //kill the escort objective if (%client.escort) { AIClearObjective(%client.escort); %client.escort.delete(); %client.escort = ""; } %client.removeTask(%client.objectiveTask); %client.objectiveTask = ""; } //------------------------------------------------------------------------ //If the function ShapeBaseImageData::testInvalidDeployConditions() changes at all, those changes need to be reflected here function AIODeployEquipment::weight(%this, %client, %level, %minWeight, %inventoryStr) { //make sure the player is still alive!!!!! if (! AIClientIsAlive(%client)) return 0; //make sure the deploy objective is valid if (%this.isInvalid) return 0; //first, make sure we haven't deployed too many... if (%this.equipment $= "TurretOutdoorDeployable" || %this.equipment $= "TurretIndoorDeployable") %maxAllowed = countTurretsAllowed(%this.equipment); else %maxAllowed = $TeamDeployableMax[%this.equipment]; if ($TeamDeployedCount[%client.team, %this.equipment] >= %maxAllowed) return 0; //now make sure there are no other items in the way... InitContainerRadiusSearch(%this.location, $MinDeployableDistance, $TypeMasks::VehicleObjectType | $TypeMasks::MoveableObjectType | $TypeMasks::StaticShapeObjectType | $TypeMasks::TSStaticShapeObjectType | $TypeMasks::ForceFieldObjectType | $TypeMasks::ItemObjectType | $TypeMasks::PlayerObjectType | $TypeMasks::TurretObjectType); %objSearch = containerSearchNext(); //make sure we're not invalidating the deploy location with the client's own player object if (%objSearch == %client.player) %objSearch = containerSearchNext(); //did we find an object which would block deploying the equipment? if (isObject(%objSearch)) return 0; //now run individual checks based on the equipment type... if (%this.equipment $= "TurretIndoorDeployable") { //check if there's another turret close to the deploy location InitContainerRadiusSearch(%this.location, $TurretIndoorSpaceRadius, $TypeMasks::StaticShapeObjectType); %found = containerSearchNext(); if (isObject(%found)) { %foundName = %found.getDataBlock().getName(); if ((%foundName $= TurretDeployedFloorIndoor) || (%foundName $= "TurretDeployedWallIndoor") || (%foundName $= "TurretDeployedCeilingIndoor") || (%foundName $= "TurretDeployedOutdoor")) return 0; } //now see if there are too many turrets in the area... %highestDensity = 0; InitContainerRadiusSearch(%this.location, $TurretIndoorSphereRadius, $TypeMasks::StaticShapeObjectType); %found = containerSearchNext(); while (isObject(%found)) { %foundName = %found.getDataBlock().getName(); if ((%foundName $= "TurretDeployedFloorIndoor") || (%foundName $= "TurretDeployedWallIndoor") || (%foundName $= "TurretDeployedCeilingIndoor") || (%foundName $= "TurretDeployedOutdoor")) { //found one %numTurretsNearby++; %nearbyDensity = testNearbyDensity(%found, $TurretIndoorSphereRadius); if (%nearbyDensity > %highestDensity) %highestDensity = %nearbyDensity; } %found = containerSearchNext(); } if (%numTurretsNearby > %highestDensity) %highestDensity = %numTurretsNearby; //now see if the area is already saturated if (%highestDensity > $TurretIndoorMaxPerSphere) return 0; } else if (%this.equipment $= "TurretOutdoorDeployable") { //check if there's another turret close to the deploy location InitContainerRadiusSearch(%this.location, $TurretOutdoorSpaceRadius, $TypeMasks::StaticShapeObjectType); %found = containerSearchNext(); if (isObject(%found)) { %foundName = %found.getDataBlock().getName(); if ((%foundName $= "TurretDeployedFloorIndoor") || (%foundName $= "TurretDeployedWallIndoor") || (%foundName $= "TurretDeployedCeilingIndoor") || (%foundName $= "TurretDeployedOutdoor")) return 0; } //now see if there are too many turrets in the area... %highestDensity = 0; InitContainerRadiusSearch(%this.location, $TurretOutdoorSphereRadius, $TypeMasks::StaticShapeObjectType); %found = containerSearchNext(); while (isObject(%found)) { %foundName = %found.getDataBlock().getName(); if ((%foundName $= "TurretDeployedFloorIndoor") || (%foundName $= "TurretDeployedWallIndoor") || (%foundName $= "TurretDeployedCeilingIndoor") || (%foundName $= "TurretDeployedOutdoor")) { //found one %numTurretsNearby++; %nearbyDensity = testNearbyDensity(%found, $TurretOutdoorSphereRadius); if (%nearbyDensity > %highestDensity) %highestDensity = %nearbyDensity; } %found = containerSearchNext(); } if (%numTurretsNearby > %highestDensity) %highestDensity = %numTurretsNearby; //now see if the area is already saturated if (%highestDensity > $TurretOutdoorMaxPerSphere) return 0; } //check equipment requirement %needEquipment = AINeedEquipment(%this.equipment, %client); //if don't need equipment, see if we've past the "point of no return", and should continue regardless if (! %needEquipment) { %needArmor = AIMustUseRegularInvStation(%this.equipment, %client); %result = AIFindClosestInventory(%client, %needArmor); %closestInv = getWord(%result, 0); %closestDist = getWord(%result, 1); //if we're too far from the inv to go back, or we're too close to the deploy location, force continue if (%closestDist > 50 && VectorDist(%client.player.getWorldBoxCenter(), %task.location) < 50) { %weight = AIODefault::weight(%this, %client, %level, %inventoryStr); if (%weight < $AIWeightContinueDeploying) %weight = $AIWeightContinueDeploying; return %weight; } } //if this bot is linked to a human who has issued this command, up the weight if (%this.issuedByClientId == %client.controlByHuman) { //make sure we have the potential to reach the minWeight if (!AIODefault::QuickWeight(%this, %client, %level, %minWeight)) { if ($AIWeightHumanIssuedCommand < %minWeight) return 0; else %weight = $AIWeightHumanIssuedCommand; } else { // calculate the default... %weight = AIODefault::weight(%this, %client, %level, %inventoryStr); if (%weight < $AIWeightHumanIssuedCommand) %weight = $AIWeightHumanIssuedCommand; } } else { //make sure we have the potential to reach the minWeight if (!AIODefault::QuickWeight(%this, %client, %level, %minWeight)) return 0; // calculate the default... %weight = AIODefault::weight(%this, %client, %level, %inventoryStr); } return %weight; } function AIODeployEquipment::assignClient(%this, %client) { %client.objectiveTask = %client.addTask(AIDeployEquipment); %task = %client.objectiveTask; %task.initFromObjective(%this, %client); } function AIODeployEquipment::unassignClient(%this, %client) { %client.removeTask(%client.objectiveTask); %client.objectiveTask = ""; } //------------------------------------------------------------------------