Help with using update and performAttack in AI.

Discussion and information relevant to creating special missions, new ships, skins etc.

Moderators: winston, another_commander

Post Reply
User avatar
LittleBear
---- E L I T E ----
---- E L I T E ----
Posts: 2876
Joined: Tue Apr 04, 2006 7:02 pm
Location: On a survey mission for GalCop. Ship: Cobra Corvette: Hidden Dragon Rated: Deadly.

Help with using update and performAttack in AI.

Post by LittleBear »

Having got my bars and hunters to break off from friendly fire incidents, I've told the bars to use their turrets on any pirates / criminals / thargoids they detect as well as launching hunters. The problem I'm finding is that whilst in performAttack the bar does not execute any other Commands until the target is destroyed or lost. As the bar cannot move and its turrets only have a range of 5km a problem is that the bar may lock onto a target 6 km away and go to performAttack, but it cannot hit the target as its out of range. What I'm trying to do is use update, so the bar only spends 6.5 seconds in the attack phase without requesting a new target. This works fine if a target is in range. The bar fires a 1.5 second burst of turret fire, launches a hunter and then re-engages with its turrets.However, if a target is out of range it just points its turrets at the target, doesn't launch any ships (as no other commands in the state are read until the performAttack is completed) and the update which should take it out of performAttack is only read when the ship is destroyed. I've playtested by helping it out by blasting its out of range target and as soon as I kill it, the update is read. Tried using FRUSTRATED =, but this doesn't seem to be acted upon. I'd assumed it would get frustrated if it has a target that's too far away to hit, but it doesn't seem to. Here's the AI. Any idea's anyone? The Bar is always on Red Alert when entering the ATTACK1 state, so three decreeseAlterLevels take it out of attack. This works, but the update is not read until performAttack is complete, which it never is if the target is out of range of the bars turrets!

Code: Select all

"ATTACK" = {
 "ENTER" = ("commsMessage: Attack1", "launchShipWithRole: random_hits_patrol", "pauseAI: 1.0");
 UPDATE = ("setStateTo: ATTACK2");
 "EXIT" = ();  };

"ATTACK2" = {
 "ENTER" = ("commsMessage: attack2", "launchShipWithRole: random_hits_patrol", checkTargetLegalStatus, increaseAlertLevel, performAttack, "pauseAI: 0.5");
 "TARGET_CLEAN" = ("sendTargetCommsMessage: [random_hits_bar_sorry_for_friendly_fire]", setTargetToSystemStation, "setStateTo: SCAN_FOR_CRIMINAL_PLAYER");
 "ENEMY_ATTACK" = (setTargetToFoundTarget, "sendTargetCommsMessage: [spacebar-warning]", "markTargetForOffence: 51", increaseAlertLevel, performAttack);
 "INCOMING_MISSILE" = (fireECM, setTargetToFoundTarget, "sendTargetCommsMessage: [spacebar-warning]", "markTargetForOffence: 51", increaseAlertLevel);
 "LAWFULL_ATTACK" = (setTargetToFoundTarget, "safeScriptActionOnTarget: setAITo: randomhitsbreakoffAI.plist", setTargetToSystemStation, "setStateTo: SCAN_FOR_CRIMINAL_PLAYER");
 "NO_TARGET" = (setTargetToSystemStation, "setStateTo: SCAN_FOR_CRIMINAL_PLAYER");
 "RED_ALERT" = ("launchShipWithRole: random_hits_patrol");
 "CONDITION_GREEN" = (setTargetToSystemStation, "setStateTo: SCRAMBLE_PAUSE");
 "TARGET_DESTROYED" = (setTargetToSystemStation, "setStateTo: SCAN_FOR_CRIMINAL_PLAYER");
 "TARGET_LOST" = (setTargetToSystemStation, "setStateTo: SCAN_FOR_CRIMINAL_PLAYER");
 "FRUSTRATED" = ("commsMessage: frustrated in attack", setTargetToSystemStation, "setStateTo: SCRAMBLE_PAUSE");
 "UPDATE" = (decreaseAlertLevel);
 "EXIT" =();    };

"SCRAMBLE_PAUSE" = {
 "ENTER" = ("commsMessage: scramble pause", "launchShipWithRole: random_hits_patrol", "pauseAI: 5.0");
 "ENEMY_ATTACK" = (setTargetToFoundTarget, "sendTargetCommsMessage: [spacebar-warning]", "markTargetForOffence: 51", increaseAlertLevel, "setStateTo: ATTACK");
 "INCOMING_MISSILE" = (fireECM, setTargetToFoundTarget, "sendTargetCommsMessage: [spacebar-warning]", "markTargetForOffence: 51", increaseAlertLevel, "setStateTo: ATTACK");
 "UPDATE" = (setTargetToSystemStation, "setStateTo: SCAN_FOR_CRIMINAL_PLAYER");
 "EXIT" =();    };
[/code]
OXPS : The Assassins Guild, Asteroid Storm, The Bank of the Black Monks, Random Hits, The Galactic Almanac, Renegade Pirates can be downloaded from the Elite Wiki here.
User avatar
Eric Walch
Slightly Grand Rear Admiral
Slightly Grand Rear Admiral
Posts: 5536
Joined: Sat Jun 16, 2007 3:48 pm
Location: Netherlands

Post by Eric Walch »

I am not sure if I see the problem. But general I think a lot of people not quite understand what happens with any of the performXxxx commands. It is not a single action like most of the other commands but is sets the ship in a certain status. (This becomes more clear when looking at the target inspector that is available in the mac console or looking in the code itself.)

On every update the system looks in what status a ship is and than acts upon that status. The performAttack sets the ship in an attack status until it receives any of the other performXxxxx commands. When in performAttack status it tries to kill the current target. I see in your code that you at several places change the current target to something else. But without a performIdle (or any other performXxxx) it switches just the target to attack.

When a ship is hit, the system puts the attacker identity in the "found_target". You set several times the target to the main station. Probably to break of the attack. I think all your setTargetToSystemStation should be replaced by performIdle as that is what you want.

But to your problem. I think you should add the following line in the ATTACK2 state.

Code: Select all

 "LAUNCH_RH_PATROL" = ("launchShipWithRole: random_hits_patrol"); 
And than in the station JS script

Code: Select all

this.launchTime = clock.absoluteSeconds
this.patrolNumber = 20

this.launchPatrol = function()
{
   if(this.patrolNumber > 0 && clock.absoluteSeconds > this.launchTime + 15)
   {
      this.patrolNumber--
      this.launchTime = clock.absoluteSeconds
      this.ship.reactToMessage("LAUNCH_RH_PATROL")
   }
}

this.otherShipDocked = function(ship)
{
	if(ship.primaryRole == "random_hits_patrol") this.patrolNumber++
}
This is an whole other approach. First define a launch-time and a maximum number of patrol ships. Whenever you need to launch a patrol ship in your script you use a "sendScriptMessage: launchPatrol", e.g. in the enemy_attack line. The function itself makes sure it only does something when there are still ships available and the last command was not issued within 15 seconds.
Defining a maximum number of ships prevents that your bar launches an infinite number of ships. I already noticed that when you leave the bar (and the computer) for several hours and than come back there are a huge number of ships around and all hyperspaced in an adjacent system. When you than jump yourself, you suddenly see dozens of your patrols arriving in that system also.
This counting was never possible in the past, but it can with JS and we should do it. Currently I do something similar with buoyRepair to prevent overpopulating of the stations perimeter.
User avatar
LittleBear
---- E L I T E ----
---- E L I T E ----
Posts: 2876
Joined: Tue Apr 04, 2006 7:02 pm
Location: On a survey mission for GalCop. Ship: Cobra Corvette: Hidden Dragon Rated: Deadly.

Post by LittleBear »

Thanks Eric. Basically the problem I had was, as I was using the same attack state both in response to detecting a target to kill and in responding to an attack on the bar itself, the launch que would be filled with ships waiting to launch, but none was actually launched as the bar would be busy in performAttack, so it just waggels its turrets at attackers too far away to hit and didn't launch ships. When its attacker eventually comes in range its is blasted with the turrets and destroyed. Then a load of hunters steam out, after the attackers have been blasted, as the bar has added loads of them to the que whilst waving its turrets impertently at tragets too far away to hit!

Redone it now this way, which produces a rather nice effect! I'm using a general scanning state for targets, which the station enters on spawning and returns to every 35 seconds after a target is detected. If it spots a target it first launches a hunter and waits 15 seconds. If attacked it uses its turrets for 10 seconds. 15 seconds after the hunter was launches it then uses turrets against any thargoids / criminals it spots for a further 10 seconds. Then it looks for targets again. In game this produces a much nicer effect, as I only have one hunter adder to the launch que at a time, a hunter is launched every 35 seconds if targets are by the bar and in between launches the gunners fire two 10 second bursts of turret fire at attackers. I think the excessive launches of hunters should be fixed by this. "The guns; they've stopped." :)

Code: Select all


"SCAN_FOR_CRIMINAL_PLAYER" = {
 "ENTER" = ("commsMessage: scan criminal player", setTargetToSystemStation, performIdle, decreaseAlertLevel, "scanForNearestShipWithRole: player");
 "EXIT" = ();
 "NOTHING_FOUND" = (setTargetToSystemStation, performIdle, "setStateTo: LOOK_FOR_ALL_TARGETS");
 "TARGET_FOUND" = (setTargetToFoundTarget, "setStateTo: CHECK_PLAYER_RAP_SHEET");
 "UPDATE" = ("scanForNearestShipWithRole: player");  };

"CHECK_PLAYER_RAP_SHEET" = {
 ENTER = ("commsMessage: check player rap sheet", checkTargetLegalStatus);
 "TARGET_CLEAN" = (setTargetToSystemStation, performIdle, decreaseAlertLevel, "setStateTo: LOOK_FOR_ALL_TARGETS");
 "TARGET_MINOR_OFFENDER" = (setTargetToSystemStation, performIdle, "setStateTo: LOOK_FOR_ALL_TARGETS");
 "TARGET_OFFENDER" = ("sendTargetCommsMessage: [spacebar-warning]", increaseAlertLevel, "setStateTo: LAUNCH_HUNTERS");
 "TARGET_FUGITIVE" = ("sendTargetCommsMessage: [spacebar-warning]", increaseAlertLevel, "setStateTo: LAUNCH_HUNTERS");
 "NO_TARGET" = (setTargetToSystemStation, performIdle, decreaseAlertLevel, "setStateTo: LOOK_FOR_ALL_TARGETS");
 "TARGET_LOST" = (setTargetToSystemStation, performIdle, decreaseAlertLevel, "setStateTo: LOOK_FOR_ALL_TARGETS");
 "TARGET_DESTROYED" = (setTargetToSystemStation, performIdle, decreaseAlertLevel, "setStateTo: LOOK_FOR_ALL_TARGETS");
 UPDATE = (checkTargetLegalStatus);
 EXIT = ();      };


"LOOK_FOR_ALL_TARGETS" = {
ENTER = ("commsMessage: look for all targets", "scanForNearestShipWithAnyRole: pirate hardpirate random_hits_big_boss random_hits_big_boss_guard thargoid terroriser thargoid-thargorn thargoid-escort thargoid-mothership", scanForOffenders, scanForThargoid);
"ENEMY_ATTACK" = (setTargetToFoundTarget, "sendTargetCommsMessage: [spacebar-warning]", "markTargetForOffence: 51", increaseAlertLevel, "setStateTo: TURRETT_ATTACK");
"INCOMING_MISSILE" = (fireECM, setTargetToFoundTarget, "sendTargetCommsMessage: [spacebar-warning]", "markTargetForOffence: 51", increaseAlertLevel, "setStateTo: TURRETT_ATTACK");
"NOTHING_FOUND" = (setTargetToSystemStation, performIdle, "setStateTo: LOOK_FOR_ALL_THARGOIDS");
"TARGET_FOUND" = (setTargetToFoundTarget, "setStateTo: LAUNCH_HUNTERS");
"OFFENCE_COMMITTED" = (setTargetToFoundTarget, "markTargetForOffence: 15", increaseAlertLevel, "sendTargetCommsMessage: [spacebar-warning]", "setStateTo: LAUNCH_HUNTERS");
"ACCEPT_DISTRESS_CALL" = (setTargetToFoundTarget, increaseAlertLevel, "setStateTo: LAUNCH_HUNTERS");
UPDATE = ("scanForNearestShipWithAnyRole: pirate hardpirate random_hits_big_boss random_hits_big_boss_guard thargoid terroriser thargoid-thargorn thargoid-escort thargoid-mothership", scanForOffenders, scanForThargoid);
EXIT = ();	};

"TURRETT_ATTACK" = {
 "ENTER" = ("commsMessage: Returning fire against an attacker - no launches", performAttack, "pauseAI: 10.0");
 "TARGET_CLEAN" = ("sendTargetCommsMessage: [random_hits_bar_sorry_for_friendly_fire]", setTargetToSystemStation, performIdle, "setStateTo: SCAN_FOR_CRIMINAL_PLAYER");
 "ENEMY_ATTACK" = (setTargetToFoundTarget, "sendTargetCommsMessage: [spacebar-warning]", "markTargetForOffence: 51", increaseAlertLevel, performIdle, performAttack);
 "INCOMING_MISSILE" = (fireECM, setTargetToFoundTarget, "sendTargetCommsMessage: [spacebar-warning]", "markTargetForOffence: 51", increaseAlertLevel, performIdle, performAttack);
 "LAWFULL_ATTACK" = (setTargetToFoundTarget, "safeScriptActionOnTarget: setAITo: randomhitsbreakoffAI.plist", setTargetToSystemStation, performIdle, "setStateTo: SCAN_FOR_CRIMINAL_PLAYER");
 "NO_TARGET" = (setTargetToSystemStation, performIdle, "setStateTo: SCAN_FOR_CRIMINAL_PLAYER");
 "CONDITION_GREEN" = (setTargetToSystemStation, performIdle, "setStateTo: SCAN_FOR_CRIMINAL_PLAYER");
 "TARGET_DESTROYED" = (setTargetToSystemStation, performIdle, "setStateTo: SCAN_FOR_CRIMINAL_PLAYER");
 "TARGET_LOST" = (setTargetToSystemStation, performIdle, "setStateTo: SCAN_FOR_CRIMINAL_PLAYER");
 "FRUSTRATED" = ("commsMessage: frustrated in attack", setTargetToSystemStation, performIdle, "setStateTo: LAUNCH_HUNTERS");
 UPDATE = ("commsMessage: Stopping turret attack", "setStateTo: LAUNCH_HUNTERS");
 "EXIT" = ();  };

"LAUNCH_HUNTERS" = {
 "ENTER" = ("commsMessage: Launch mode - no turrets unless attacked again", performIdle, "launchShipWithRole: random_hits_patrol", "pauseAI: 15.0");
 "TARGET_CLEAN" = ("sendTargetCommsMessage: [random_hits_bar_sorry_for_friendly_fire]", setTargetToSystemStation, performIdle, "setStateTo: SCAN_FOR_CRIMINAL_PLAYER");
 "ENEMY_ATTACK" = (setTargetToFoundTarget, "sendTargetCommsMessage: [spacebar-warning]", "markTargetForOffence: 51", increaseAlertLevel, performIdle, performAttack);
 "INCOMING_MISSILE" = (fireECM, setTargetToFoundTarget, "sendTargetCommsMessage: [spacebar-warning]", "markTargetForOffence: 51", increaseAlertLevel, performIdle, performAttack);
 "LAWFULL_ATTACK" = (setTargetToFoundTarget, "safeScriptActionOnTarget: setAITo: randomhitsbreakoffAI.plist", setTargetToSystemStation, performIdle, "setStateTo: SCAN_FOR_CRIMINAL_PLAYER");
 "NO_TARGET" = (setTargetToSystemStation, performIdle, "setStateTo: SCAN_FOR_CRIMINAL_PLAYER");
 "CONDITION_GREEN" = (setTargetToSystemStation, performIdle, "setStateTo: SCAN_FOR_CRIMINAL_PLAYER");
 "TARGET_DESTROYED" = (setTargetToSystemStation, performIdle, "setStateTo: SCAN_FOR_CRIMINAL_PLAYER");
 "TARGET_LOST" = (setTargetToSystemStation, performIdle, "setStateTo: SCAN_FOR_CRIMINAL_PLAYER");
 UPDATE = ("commsMessage: Stopping launches, looking for targets to shoot with turrets", "setStateTo: SHOOT_SELECTED_TARGET");
 "EXIT" = ();  };

"SHOOT_SELECTED_TARGET" = {
 "ENTER" = ("commsMessage: Trying to shoot Thargoid / Criminal with turrets - no launches", performAttack, "pauseAI: 10.0");
 "TARGET_CLEAN" = ("sendTargetCommsMessage: [random_hits_bar_sorry_for_friendly_fire]", setTargetToSystemStation, performIdle, "setStateTo: SCAN_FOR_CRIMINAL_PLAYER");
 "ENEMY_ATTACK" = (setTargetToFoundTarget, "sendTargetCommsMessage: [spacebar-warning]", "markTargetForOffence: 51", increaseAlertLevel, performIdle, performAttack);
 "INCOMING_MISSILE" = (fireECM, setTargetToFoundTarget, "sendTargetCommsMessage: [spacebar-warning]", "markTargetForOffence: 51", increaseAlertLevel, performIdle, performAttack);
 "LAWFULL_ATTACK" = (setTargetToFoundTarget, "safeScriptActionOnTarget: setAITo: randomhitsbreakoffAI.plist", setTargetToSystemStation, performIdle, "setStateTo: SCAN_FOR_CRIMINAL_PLAYER");
 "NO_TARGET" = (setTargetToSystemStation, performIdle, "setStateTo: SCAN_FOR_CRIMINAL_PLAYER");
 "CONDITION_GREEN" = (setTargetToSystemStation, performIdle, "setStateTo: SCAN_FOR_CRIMINAL_PLAYER");
 "TARGET_DESTROYED" = (setTargetToSystemStation, performIdle, "setStateTo: SCAN_FOR_CRIMINAL_PLAYER");
 "TARGET_LOST" = (setTargetToSystemStation, performIdle, "setStateTo: SCAN_FOR_CRIMINAL_PLAYER");
 "FRUSTRATED" = ("commsMessage: frustrated in attack", setTargetToSystemStation, performIdle, "setStateTo: LAUNCH_HUNTERS");
 UPDATE = ("commsMessage: Stopping turret attack. Shutting down Launches and turrets and looking for targets.", "setStateTo: SCAN_FOR_CRIMINAL_PLAYER");
 "EXIT" = ();  };

OXPS : The Assassins Guild, Asteroid Storm, The Bank of the Black Monks, Random Hits, The Galactic Almanac, Renegade Pirates can be downloaded from the Elite Wiki here.
Post Reply