Converted Script to XML. (Last step is to validate XML in the code, true last step is to take diffs of the xml output)
Several debugging issues dealing with parameters and interrupts that need to be fixed, but I'm kind of impressed that this was doable in only 3 days. It aint perfect, but it is on the way there.
Code: Select all
aiscript order.move.recon{ // {name="order.move.recon", xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance", xsi:noNamespaceSchemaLocation="aiscripts.xsd"}
order("internal", "{1041, 292}", "Recon", "{1041, 291}"){ // {category, description, id, name}
param object targetspace("Space. Space to reconnoiter", "null", "true", "{1041, 10117}"){ // {comment, default, required, text}
input_param class = "[class.sector, class.gate, class.highwayentrygate]";
}
param length radius("true", "Radius. only used by blindtourist.", "null", "{1041, 10093}"); // {advanced, comment, default, text}
param time timeout("true", "Duration", "0s", "0s", "{1041, 10034}"){ // {advanced, comment, default, infinitevalue, text}
input_param min = "0s";
input_param max = "24h";
input_param step = "10min";
}
param object hq("true", "Headquarters. Station or ship this ship will report back to after doing reconnaissance. Only used by normal recon or police.", "null", "{1041, 10045}"){ // {advanced, comment, default, text}
input_param class = "[class.station, class.ship]";
input_param canbecommanderof = "this.ship";
}
param internal targetclasses("Target object classes", "[class.ship, class.station]"); // {comment, default}
param internal targetpurposes("Target object purposes", "[]"); // {comment, default}
param internal police("Police investigation. Look for disguised criminals or smuggled goods? Otherwise, default behavior is to identify potential threats to our faction in $targetspace.", "false", "{1041, 10084}"); // {comment, default, text}
param internal exploreupdate("Update known space. Refresh information on known stations in $targetspace.", "false", "{1041, 10137}"); // {comment, default, text}
param internal resourcescout("Scout for resources. Look for valuable asteroids, collectables, or lockboxes in $targetspace.", "false", "{1041, 10109}"); // {comment, default, text}
param internal blindtourist("Explore blind with no cheating", "false", "{1041, 10039}"); // {comment, default, text}
param internal cannotdock("Unable to dock. used for error handling in case of inability to dock", "false", "{1041, 10133}"); // {comment, default, text}
param bool debugchance("true", "Print debug output", "0", "{1041, 10086}"){ // {advanced, comment, default, text}
input_param truevalue = "100";
}
skill("40"); // {min}
}
#interrupt_handler_ref(SectorChangeHandler);
#interrupt_handler_ref(TargetInvalidHandler);
#interrupt_handler_ref(AttackHandler);
#interrupt_handler_ref(MissileLockHandler);
#interrupt_handler_ref(ScannedHandler);
#interrupt_handler_ref(InspectedHandler);
#interrupt_handler_ref(FoundAbandonedHandler);
#interrupt_handler_ref(ResupplyHandler);
#interrupt_handler_ref(JobRemoveRequestHandler);
#interrupt_handler_if(check_any(event_object_attacked(group="$localtargetgroup") && event_object_signalled(check="false", object="this.sector", param="'police'")) &&
set_value(exact="if (event.name == 'event_object_attacked') then event.param else event.param2", name="$attacker") &&
$police &&
this.sector.exists &&
$attacker.isoperational &&
$attacker.zone.policefaction &&
not this.hasrelation.enemy.{$attacker.zone.policefaction} &&
$attacker.owner != this.owner &&
$attacker.owner != event.param3.owner){
if(event.name == 'event_object_attacked'){
debug_text("$debugchance", "'%s %s attacking attacker %s %s of scanned ship in sector %s. interdicted ship cleared.'.[this.ship.knownname, this.ship, $attacker.knownname, $attacker, this.sector.knownname]"); // {chance, text}
}else{
debug_text("$debugchance", "'%s %s called to attack %s %s in sector %s. interdicted ship cleared.'.[this.ship.knownname, this.ship, $attacker.knownname, $attacker, this.sector.knownname]"); // {chance, text}
}
if(@$localtarget){
if($localtarget == player.occupiedship and $attacker != player.occupiedship){
debug_text("$debugchance", "'called to attack. interdicted player ship cleared.'"); // {chance, text}
// NB: has to stay a conversation. cannot call player.interaction from an interrupt, and this is fairly important.
start_conversation("this", "(ship scan result - nothing found).", "Speak_Scan", "11204", "80", "unqueued"); // {actor, comment, conversation, convparam, priority, type}
}
signal_objects("$localtarget", "'proceed'", "this.defensible"); // {object, param, param2}
// cleaned up in order.wait.signal by $localtarget's pilot
this.$police_cleared.{$localtarget} = player.age;
}
if($attacker.isplayerowned){
add_relation_boost("1", "5min", "this", "$attacker", "relationchangereason.illegalcargo", "-0.1"); // {decay, delay, object, otherobject, reason, value}
}else{
add_relation_boost("1", "5min", "$attacker", "this", "-0.1"); // {decay, delay, object, otherobject, value}
}
create_order("'Attack'", "true", "this.ship"){ // {id, immediate, object}
param primarytarget("$attacker"); // {value}
param allowothertargets("true"); // {value}
param debugchance("$debugchance"); // {value}
}
};
function init(){
if(not $targetspace){
if(this.sector){
$targetspace = this.sector;
}else{
// assumes that if this.sector is null, we are in a superhighway
if(this.zone.issuperhighway){
$targetspace = this.zone.destination.sector;
}else{
debug_text("error", "'%s %s %s is neither in a sector nor in a superhighway. zone: %s %s. aborting.'.[this.assignedcontrolled.idcode, this.assignedcontrolled.knownname, this.assignedcontrolled, this.zone.knownname, this.zone]"); // {filter, text}
return();
}
}
if($targetspace){
edit_order_param("will cause script to restart", "this.assignedcontrolled.order", "'targetspace'", "$targetspace"); // {comment, order, param, value}
}
}
if($targetspace.isclass.gate){
if(not $targetspace.isactive){
debug_text("'selected gate is inactive. no space to reconnoiter. aborting.'"); // {text}
return();
}else{
debug_text("$debugchance", "'switching targetspace from %s %s %s to %s %s %s.'.[$targetspace.class, $targetspace.knownname, $targetspace, $targetspace.destination.sector.class, $targetspace.destination.sector.knownname, $targetspace.destination.sector]"); // {chance, text}
$targetspace = $targetspace.destination.sector;
}
}else if($targetspace.isclass.highwayentrygate){
if($targetspace.highway.destination.sector){
debug_text("$debugchance", "'switching targetspace from %s %s %s to %s %s %s.'.[$targetspace.class, $targetspace.knownname, $targetspace, $targetspace.highway.destination.sector.class, $targetspace.highway.destination.sector.knownname, $targetspace.highway.destination.sector]"); // {chance, text}
$targetspace = $targetspace.highway.destination.sector;
}else{
debug_text("error", "'Highway entry gate: %s has no destination or destination is not in a sector. Destination: %s %s'.[$targetspace, @$targetspace.highway.destination.knownname, @$targetspace.highway.destination]"); // {filter, text}
return();
}
}
// also handles case where targetspace is null
else if(not @$targetspace.isclass.sector){
debug_text("$debugchance", "'Warning: targetspace %1 %2 (%3) is neither a sector, a gate, nor a highway entry gate. Attempting to recover.'.[@$targetspace.class, @$targetspace.knownname, $targetspace]"); // {chance, text}
if($police){
if(this.controlled.jobmainzone){
if(this.controlled.jobmainzone.policefaction == this.trueowner){
$targetspace = this.controlled.jobmainzone.sector;
}else{
debug_text("error", "'police ship %s %s has jobmainzone set to an area where they are not police. Check job definition: %s. Attempting to recover. jobmainzone: %s %s in sector %s %s with local police %s'.[this.controlled.knownname, this.controlled, this.controlled.job, this.controlled.jobmainzone.knownname, this.controlled.jobmainzone, this.controlled.jobmainzone.sector.knownname, this.controlled.jobmainzone.sector, this.controlled.jobmainzone.policefaction]"); // {filter, text}
}
}else if(@this.sector.policefaction == this.trueowner){
$targetspace = this.sector;
} else{
// in this case, do not set $targetspace here. will need to set it after the script starts where we could have blocking actions.
debug_text("$debugchance", "'police ship %s %s cannot set a target space at init. initializing after script starts'.[this.controlled.knownname, this.controlled]"); // {chance, text}
}
}else if(@$targetspace.sector){
$targetspace = $targetspace.sector;
} else if(this.sector){
$targetspace = this.sector;
} else if(this.zone.isclass.highway){
$targetspace = this.zone.destination.sector;
} else{
debug_text("error", "'targetspace %1 %2 (%3) is neither a sector nor in a sector. Attempt to recover failed. Stopping reconnaissance. (This can go very badly if this is my default order. Is it? %4)'.[@$targetspace.class, @$targetspace.knownname, $targetspace, this.ship.order == this.ship.defaultorder]"); // {filter, text}
return();
}
debug_text("$debugchance", "'Recovered. targetspace is now: %1 %2 (%3)'.[$targetspace.class, $targetspace.knownname, $targetspace]"); // {chance, text}
} create_group("$localtargetgroup"); // {groupname}
if($police and not this.$police_cleared?){
this.$police_cleared = table[];
}
if($blindtourist and not this.isplayerowned){
debug_text("$debugchance", "'blind tourist called on someone who does not belong to the player faction. this is not supported. reverting to normal recon.'"); // {chance, text}
$blindtourist = false;
edit_order_param("this.assignedcontrolled.order", "'blindtourist'", "false"); // {order, param, value}
}
if($blindtourist){
$anchorpos = position.[0, 0, 0];
if(this.hascontext.{$targetspace}){
$refpos = this.assignedcontrolled.position;
$refzone = this.zone;
}else if(this.zone.isclass.highway and (this.zone.destination.sector == $targetspace)){
$refpos = position.[0, 0, 0];
$refzone = this.zone.destination;
} if($refpos? and $refzone?){
create_position("$anchorpos", "$refzone", "$targetspace", "$refpos"); // {name, object, space, value}
}
delete $refzone;
delete $refpos;
}
}
function attention(unknown){
set_command_action("commandaction.calculating"); // {commandaction}
label("start"); // {name}
if($police){
if(not $targetspace){
find_cluster_in_range("$clusterstable", "22", "true", "this.controlled"); // {distances, maxdistance, multiple, object}
// sort them
$sortedclusters = $clusterstable.keys.sorted;
do_all("$i", "$sortedclusters.count"){ // {counter, exact}
find_sector("true", "$clustersectors", "$sortedclusters.{$i}"); // {multiple, name, space}
do_all("$j", "$clustersectors.count"){ // {counter, exact}
if($clustersectors.{$j}.policefaction == this.trueowner){
$targetspace = $clustersectors.{$j};
break();
}
}
if($targetspace){
debug_text("$debugchance", "'targetspace successfully set.'"); // {chance, text}
break();
}
}
delete $clustersectors;
delete $sortedclusters;
}
debug_text("$debugchance", "'starting in sector %s. local police: %s. our faction: %s. target space: %s %s'.[this.sector.knownname, @this.sector.policefaction, this.trueowner, @$targetspace.class, @$targetspace.knownname]"); // {chance, text}
}
// checks: will we need any special equipment? if we don't, should we go get it? could we just assume that we have it? if we have it now, will we always have it?
if(not $targetspace and this.ship.isjobship){
if(this.zone.isclass.highway){
debug_text("$debugchance", "'%1 %2 is in a highway. waiting to exit.'.[this.ship.idcode, this.ship.knownname]"); // {chance, text}
wait(){
}
}
$targetspace = this.sector;
}
set_order_syncpoint_reached("this.ship.order"); // {order}
label("prep"); // {name}
$num_timesreset = @$num_timesreset + 1;
/* <do_if value="$num_timesreset gt 1 and (player.age - $time_lastreset) lt 2s">
<debug_text text="'reset after %s seconds.\n in player sector? %s\n police? %s\n resourcescout? %s\n exploreupdate? %s\n blindtourist? %s'.[player.age - $time_lastreset, this.ship.attention ge attention.insector, $police, $resourcescout, $exploreupdate, $blindtourist]"/>
<do_if value="not $init_debugchance?">
<set_value name="$init_debugchance" exact="$debugchance"/>
</do_if>
<set_value name="$debugchance" exact="100"/>
</do_if>
*/
$time_lastreset = player.age;
// NB: this would be more efficient in init, but moved here in case we decide to change $targetspace dynamically via Faction Logic or by other means.
if($police){
set_command("command.investigate"); // {command}
$scanningrange = [this.ship.maxradarrange, (this.assignedcontrolled.size / 2.0 + 1km)].min;
}else if($resourcescout){
set_command("command.searchresources"); // {command}
$scanningrange = [this.ship.maxradarrange, (this.assignedcontrolled.size / 2.0 + 100m)].min;
} else{
if(this.ship.relationto.{$targetspace.owner} lt 0){
set_command("command.recon"); // {command}
}else{
set_command("command.explore"); // {command}
}
$scanningrange = this.ship.maxradarrange;
}
if(this.ship.jobexpired or ($timeout and $time_init? and (player.age ge $time_init + $timeout))){
resume("end"); // {label}
}else if($timeout and not $time_init?){
$time_init = player.age;
}
// reset all recon data. we should only be back here if we're starting fresh.
$list_objectsscanned = [];
$list_threats = [];
$list_nonthreats = [];
$table_factionthreatlevels = table[];
if($exploreupdate){
create_list("$list_zonestoinvestigate"); // {name}
find_station("true", "this.owner", "true", "$list_knownstations", "$targetspace"); // {checkoperational, knownto, multiple, name, space}
// <find_station name="$list_knownstations" space="$targetspace" checkoperational="true" canhaveofferlocation="true" knownto="this.owner" multiple="true"/>
do_all("$i", "$list_knownstations.count"){ // {counter, exact}
if(not $list_zonestoinvestigate.indexof.{$list_knownstations.{$i}.zone}){
append_to_list("$list_knownstations.{$i}.zone", "$list_zonestoinvestigate"); // {exact, name}
}
}
delete $list_knownstations;
}else if($resourcescout){
// resourcescout should be called from order.mining.routine after we are already in a resource-rich area, so we shouldn't wander off at this point.
create_list("$list_zonestoinvestigate"); // {name}
append_to_list("this.zone", "$list_zonestoinvestigate"); // {exact, name}
// $resourcezones populated only in high attention
find_zone("true", "$resourcezones", "this.sector"){ // {multiple, name, space}
match_content("class.asteroid"); // {class}
}
shuffle_list("$resourcezones"); // {list}
do_all("$i", "$resourcezones.count"){ // {counter, exact}
append_to_list("$resourcezones.{$i}", "$list_zonestoinvestigate"); // {exact, name}
}
debug_text("$debugchance", "'resourcescout: found %s zones with resources (only works in high attention). %s zones to explore.'.[$resourcezones.count, $list_zonestoinvestigate.count]"); // {chance, text}
}
// blind tourist explores each zone as they are found, so no list of zones to explore.
else if($blindtourist){
} else{
// make a sorted list of zones in targetspace.
find_zone("true", "$list_zonestoinvestigate", "true", "$targetspace"); // {multiple, name, normalzone, space}
}
if(@$list_zonestoinvestigate.count){
debug_text("$debugchance", "'found %1 zones in %2'.[$list_zonestoinvestigate.count, $targetspace.knownname]"); // {chance, text}
$table_zones = table[];
do_all("$i", "$list_zonestoinvestigate.count", "true"){ // {counter, exact, reverse}
$table_zones.{$list_zonestoinvestigate.{$i}} = this.ship.distanceto.{$list_zonestoinvestigate.{$i}};
if($list_zonestoinvestigate.{$i}.isclass.highway){
debug_text("error", "'recon ship has highway in list of zones to investigate.\npolice? %s\nresourcescout? %s\nexploreupdate? %s\nblindtourist? %s'.[$police, $resourcescout, $exploreupdate, $blindtourist]"); // {filter, text}
delete $list_zonestoinvestigate.{$i};
}
}
$list_zonestoinvestigate = $table_zones.keys.sorted;
delete $table_zones;
}
debug_text("$debugchance", "'%1 %2 starting reconnaissance mission:\n to %3 %4\n owned by %5.\n relation: %6\n police investigation? %7'.[this.ship.idcode, this.ship.knownname, $targetspace.class, $targetspace.knownname, $targetspace.owner, this.ship.relationto.{$targetspace.owner}, $police]"); // {chance, text}
label("gothere"); // {name}
// are we there yet? if not, go there. (note: what is "there"? targetspace? an interim zone?)
if(not this.hascontext.{$targetspace}){
debug_text("$debugchance", "'%1 %2 moving to %3 %4, %5.'.[this.ship.idcode, this.ship.knownname, $targetspace.class, $targetspace.knownname, $targetspace.cluster.knownname]"); // {chance, text}
run_script('move.generic'){
param destination("$targetspace"); // {value}
param endintargetzone("true"); // {value}
param debugchance("$debugchance"); // {value}
}
}
if(this.sector != $targetspace){
debug_text("error", "'%1 %2 did not arrive at targetspace.\n targetspace: %3, %4\n at: %5, %6'.[this.ship.idcode, this.ship.knownname, $targetspace.knownname, $targetspace.cluster.knownname, this.sector.knownname, this.cluster.knownname]"); // {filter, text}
resume("gothere"); // {label}
}
if($police and @this.zone.policefaction != this.trueowner){
debug_text("error", "'police ship %s %s at targetspace but we are not the police faction here. local police: %s, our faction: %s\nat: %s %s owned by %s'.[this.controlled.knownname, this.controlled, @this.zone.policefaction, this.trueowner, this.zone.knownname, this.zone, this.zone.trueowner]"); // {filter, text}
}
// determine the zone we want to go to,
label("proceedtonextzone"); // {name}
$destination = null;
// Idle for a while. Important to prevent infinite loops in cases where there is absolutely nothing to explore. Shouldn't happen in normal game setup except for resource scout in low attention.
run_script('move.idle'){
param Min("1min"); // {value}
param Max("5min"); // {value}
}
if($blindtourist){
// try to find an undiscovered spot that's fairly close to me and is toward the sector center.
find_closest_undiscovered_position("this.assignedcontrolled.combinedskill", "this.ship.maxradarrange * 2", "$pos_target", "$targetspace"){ // {chance, range, result, sector}
position("$targetspace"); // {object}
rangecenter("this.assignedcontrolled"); // {object}
}
if(not @$pos_target or $pos_target.distanceto.{$anchorpos} gt $radius){
debug_text("$debugchance", "'no close undiscovered areas found. widening search.'"); // {chance, text}
/* if there aren't any, find the closest undiscovered spot to me. cap at a sensible distance.
fallback pos changed back to unknown closest to me to mitigate multiple ships going to the same position.
*/
find_closest_undiscovered_position("$radius", "$pos_target", "$targetspace"){ // {range, result, sector}
position("this.assignedcontrolled"); // {object}
rangecenter("$anchorpos"); // {value}
}
}
if(@$pos_target){
$destination = $targetspace;
create_position("$debugchance", "$temp_sectorpos", "this.zone", "$targetspace", "this.position"); // {chance, name, object, space, value}
debug_text("$debugchance", "'blind tourist is going to %s in %s %s %s.\npresent position: %s\nmy distance to new pos: %s\nanchor distance to new pos: %s\nradius: %s\nsector center distance to new pos: %s'.[$pos_target, $destination.class, $destination.knownname, $destination, $temp_sectorpos, this.ship.distanceto.[$targetspace, $pos_target], $pos_target.distanceto.{$anchorpos}, $radius, $targetspace.distanceto.[$targetspace, $pos_target]]"); // {chance, text}
delete $temp_sectorpos;
}else{
debug_text("$debugchance", "'blind tourist has nothing left to explore. reverting to normal reconnaisance.'"); // {chance, text}
edit_order_param("this.assignedcontrolled.order", "'blindtourist'", "false"); // {order, param, value}
}
}else if(@$list_zonestoinvestigate.{1}){
if($list_zonestoinvestigate.{1}.exists){
$destination = $list_zonestoinvestigate.{1};
}else{
do_all("$i", "$list_zonestoinvestigate.count", "true"){ // {counter, exact, reverse}
if(not $list_zonestoinvestigate.{$i}.exists){
delete $list_zonestoinvestigate.{$i};
}
}
if(@$list_zonestoinvestigate.{1}){
$destination = $list_zonestoinvestigate.{1};
}
}
}
// if we're there, move around looking for trouble.
label("lookfortrouble"); // {name}
if(@$destination.exists){
// pos_target is only used by blindtourist at the moment.
if($pos_target?){
get_safe_pos("this.ship.size / 2", "$safepos", "$destination", "$destination", "$pos_target"); // {radius, result, sector, space, value}
if(true){
// below optimistically assumes that safepos is fairly close to pos_target, close enough that one of the two distances checked is the hypotenuse. if we are very very close to either the safepos or pos_target, or if safepos is way off, then the distance to safepos calculation will be inaccurate. only used for debug output for now.
if(this.ship.distanceto.[$destination, $safepos] gt this.ship.distanceto.[$destination, $pos_target]){
$dist_hyp = this.ship.distanceto.[$destination, $safepos];
$dist_nothyp = this.ship.distanceto.[$destination, $pos_target];
}else{
$dist_hyp = this.ship.distanceto.[$destination, $pos_target];
$dist_nothyp = this.ship.distanceto.[$destination, $safepos];
}
debug_text("'safepos is:\n%s meters away from pos_target\n%s meters away from us\nand %s meters away from sector center.'.[sqrt(($dist_hyp^2)-($dist_nothyp^2)), this.ship.distanceto.[$destination, $safepos], $destination.distanceto.[$destination, $safepos]]"); // {text}
delete $dist_nothyp;
delete $dist_hyp;
}
delete $pos_target;
}else{
get_safe_pos("$destination.size / 3", "this.ship.maxradarrange", "this.ship.size / 2", "$safepos", "$destination"); // {max, min, radius, result, zone}
debug_text("$debugchance", "'next safe pos is %s km from the center of %s %s.\nzone radius: %s km.\nradar range: %s km\npos: %s'.[$destination.distanceto.[$destination, $safepos] / 1000, $destination.class, $destination.knownname, $destination.size / 2 / 1000, this.ship.maxradarrange / 1000, $safepos]"); // {chance, text}
}
debug_text("$debugchance", "'going to investigate %1 %2 in %3'.[$destination.class, $destination.knownname, $targetspace.knownname]"); // {chance, text}
}else{
debug_text("$debugchance", "'went through all of the zones.'"); // {chance, text}
resume("report"); // {label}
}
// it's possible to wander to a different sector entirely while scanning a ship. in that case, go back to the targetspace.
if(not this.hascontext.{$targetspace}){
debug_text("$debugchance", "'%1 %2 wandered out of target space. Going back.\n am in: %3\n target space: %4'.[this.ship.idcode, this.ship.knownname, this.sector.knownname, $targetspace.knownname]"); // {chance, text}
resume("gothere"); // {label}
}
if($police and $destination.isclass.[class.sector, class.zone] and @$destination.policefaction != this.trueowner){
debug_text("error", "'police ship %s %s about to patrol area where they are not police. Check jobs setup or faction logic assignment, whichever applies.'.[this.controlled.knownname, this.controlled]"); // {filter, text}
assert("'police ship %s %s about to patrol area where they are not police. Check jobs setup (location) or faction logic assignment (targetspace), whichever applies.'.[this.controlled.knownname, this.controlled]", "@$destination.policefaction == this.trueowner"); // {text, value}
}
if($resourcescout){
// we skip move.seekenemies at this point since gravidar doesn't find asteroids anyway which are our primary items of interest.
find_object("[class.asteroid, class.lockbox, class.collectable]", "true", "$list_potentialtargets", "this.sector"){ // {class, multiple, name, space}
match_distance("this.assignedcontrolled.maxradarrange * 2", "this.assignedcontrolled"); // {max, object}
}
if(not $list_potentialtargets.count){
if(this.assignedcontrolled.attention ge attention.visible){
// if we don't find anything in high attention, there's nothing to do here. go elsewhere.
return();
}
/* in low attention, there's a big chance that nothing will be found since asteroids are culled.
with a shift to high attention, asteroids will exist and we want this ship to operate in the general vicinity.
resource scout only ever has one zone in its list so, if we want it to shift spaces at this point, resume to label "end" and have order.mining.routine give us a new space.
*/
debug_text("$debugchance", "'resource scout %s %s did not find anything. idling.'.[this.assignedcontrolled.knownname, this.assignedcontrolled]"); // {chance, text}
run_script('move.idle'){
/* <param name="Min" value="17min"/>
<param name="Max" value="43min"/>
*/
param untilattentionchangeto("attention.visible"); // {value}
param debugchance("$debugchance"); // {value}
}
wait("1s"); // {exact}
if($destination.exists){
resume("lookfortrouble"); // {label}
}else{
resume("proceedtonextzone"); // {label}
}
}
debug_text("$debugchance", "'resource scout %s %s found %s items of interest in sector %s.'.[this.assignedcontrolled.knownname, this.assignedcontrolled, $list_potentialtargets.count, this.sector.knownname]"); // {chance, text}
}else{
if(this.ship.distanceto.[$destination, $safepos] gt (this.ship.maxspeed * 60)){
debug_text("$debugchance", "'destination to next position very far away. moving quickly to a point close to it.\n max speed: %s m/s\n distance: %s m\n time to traverse: %s s'.[this.ship.maxspeed, this.ship.distanceto.[$destination, $safepos], this.ship.distanceto.[$destination, $safepos] / [this.ship.maxspeed, 1m].max]"); // {chance, text}
create $travel;
}
// and go there while scanning for trouble.
run_script('move.seekenemies'){
param destination("$destination"); // {value}
param pos("$safepos"); // {value}
// <param name="pursuedistance" value="$scanningrange"/>
param targetclasses("$targetclasses"); // {value}
param targetpurposes("$targetpurposes"); // {value}
param recon("true"); // {value}
param travel("$travel?"); // {value}
param list_objectstoignore("$list_objectsscanned"); // {value}
param debugchance("$debugchance"); // {value}
save_retval("target", "$localtarget"); // {name, variable}
save_retval("list_targets", "$list_potentialtargets"); // {name, variable}
}
delete $travel;
}
label("scan"); // {name}
.......
Code: Select all
<?xml version="1.0" encoding="utf-8"?>
<aiscript name="order.move.recon" xsi:noNamespaceSchemaLocation="aiscripts.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<order id="Recon" name="{1041,291}" description="{1041,292}" category="internal">
<params />
<params>
<param name="length" type="radius" default="null" advanced="true" comment="Radius. only used by blindtourist." text="{1041, 10093}" />
</params>
<params />
<params>
<param name="internal" type="targetclasses" default="[class.ship, class.station]" comment="Target object classes" />
<param name="internal" type="targetpurposes" default="[]" comment="Target object purposes" />
<param name="internal" type="police" default="false" comment="Police investigation. Look for disguised criminals or smuggled goods? Otherwise, default behavior is to identify potential threats to our faction in $targetspace." text="{1041, 10084}" />
<param name="internal" type="exploreupdate" default="false" comment="Update known space. Refresh information on known stations in $targetspace." text="{1041, 10137}" />
<param name="internal" type="resourcescout" default="false" comment="Scout for resources. Look for valuable asteroids, collectables, or lockboxes in $targetspace." text="{1041, 10109}" />
<param name="internal" type="blindtourist" default="false" comment="Explore blind with no cheating" text="{1041, 10039}" />
<param name="internal" type="cannotdock" default="false" comment="Unable to dock. used for error handling in case of inability to dock" text="{1041, 10133}" />
</params>
<skill min="40" />
</order>
<interrupts>
<handler ref="SectorChangeHandler" />
<handler ref="TargetInvalidHandler" />
<handler ref="AttackHandler" />
<handler ref="MissileLockHandler" />
<handler ref="ScannedHandler" />
<handler ref="InspectedHandler" />
<handler ref="FoundAbandonedHandler" />
<handler ref="ResupplyHandler" />
<handler ref="JobRemoveRequestHandler" />
</interrupts>
<init>
<do_if value="not $targetspace">
<do_if value="this.sector">
<set_value name="$targetspace" exact="this.sector" />
</do_if>
<do_else>
<!-- assumes that if this.sector is null, we are in a superhighway-->
<do_if value="this.zone.issuperhighway">
<set_value name="$targetspace" exact="this.zone.destination.sector" />
</do_if>
<do_else>
<debug_text filter="error" text="'%s %s %s is neither in a sector nor in a superhighway. zone: %s %s. aborting.'.[this.assignedcontrolled.idcode,this.assignedcontrolled.knownname,this.assignedcontrolled,this.zone.knownname,this.zone]" />
<return />
</do_else>
</do_else>
<do_if value="$targetspace">
<edit_order_param param="'targetspace'" comment="will cause script to restart" value="$targetspace" order="this.assignedcontrolled.order" />
</do_if>
</do_if>
<do_if value="$targetspace.isclass.gate">
<do_if value="not $targetspace.isactive">
<debug_text text="'selected gate is inactive. no space to reconnoiter. aborting.'" />
<return />
</do_if>
<do_else>
<debug_text chance="$debugchance" text="'switching targetspace from %s %s %s to %s %s %s.'.[$targetspace.class,$targetspace.knownname,$targetspace,$targetspace.destination.sector.class,$targetspace.destination.sector.knownname,$targetspace.destination.sector]" />
<set_value name="$targetspace" exact="$targetspace.destination.sector" />
</do_else>
</do_if>
<do_elseif value="$targetspace.isclass.highwayentrygate">
<do_if value="$targetspace.highway.destination.sector">
<debug_text chance="$debugchance" text="'switching targetspace from %s %s %s to %s %s %s.'.[$targetspace.class,$targetspace.knownname,$targetspace,$targetspace.highway.destination.sector.class,$targetspace.highway.destination.sector.knownname,$targetspace.highway.destination.sector]" />
<set_value name="$targetspace" exact="$targetspace.highway.destination.sector" />
</do_if>
<do_else>
<debug_text filter="error" text="'Highway entry gate: %s has no destination or destination is not in a sector. Destination: %s %s'.[$targetspace,@$targetspace.highway.destination.knownname,@$targetspace.highway.destination]" />
<return />
</do_else>
</do_elseif>
<!-- also handles case where targetspace is null-->
<do_elseif value="not @$targetspace.isclass.sector">
<debug_text chance="$debugchance" text="'Warning: targetspace %1 %2 (%3) is neither a sector,a gate,nor a highway entry gate. Attempting to recover.'.[@$targetspace.class,@$targetspace.knownname,$targetspace]" />
<do_if value="$police">
<do_if value="this.controlled.jobmainzone">
<do_if value="this.controlled.jobmainzone.policefaction == this.trueowner">
<set_value name="$targetspace" exact="this.controlled.jobmainzone.sector" />
</do_if>
<do_else>
<debug_text filter="error" text="'police ship %s %s has jobmainzone set to an area where they are not police. Check job definition: %s. Attempting to recover. jobmainzone: %s %s in sector %s %s with local police %s'.[this.controlled.knownname,this.controlled,this.controlled.job,this.controlled.jobmainzone.knownname,this.controlled.jobmainzone,this.controlled.jobmainzone.sector.knownname,this.controlled.jobmainzone.sector,this.controlled.jobmainzone.policefaction]" />
</do_else>
</do_if>
<do_elseif value="@this.sector.policefaction == this.trueowner">
<set_value name="$targetspace" exact="this.sector" />
</do_elseif>
<do_else>
<!-- in this case, do not set $targetspace here. will need to set it after the script starts where we could have blocking actions.-->
<debug_text chance="$debugchance" text="'police ship %s %s cannot set a target space at init. initializing after script starts'.[this.controlled.knownname,this.controlled]" />
</do_else>
</do_if>
<do_elseif value="@$targetspace.sector">
<set_value name="$targetspace" exact="$targetspace.sector" />
</do_elseif>
<do_elseif value="this.sector">
<set_value name="$targetspace" exact="this.sector" />
</do_elseif>
<do_elseif value="this.zone.isclass.highway">
<set_value name="$targetspace" exact="this.zone.destination.sector" />
</do_elseif>
<do_else>
<debug_text filter="error" text="'targetspace %1 %2 (%3) is neither a sector nor in a sector. Attempt to recover failed. Stopping reconnaissance. (This can go very badly if this is my default order. Is it? %4)'.[@$targetspace.class,@$targetspace.knownname,$targetspace,this.ship.order == this.ship.defaultorder]" />
<return />
</do_else>
<debug_text chance="$debugchance" text="'Recovered. targetspace is now: %1 %2 (%3)'.[$targetspace.class,$targetspace.knownname,$targetspace]" />
</do_elseif>
<do_if value="$police and not this.$police_cleared?">
<set_value name="this.$police_cleared" exact="table[]" />
</do_if>
<do_if value="$blindtourist and not this.isplayerowned">
<debug_text chance="$debugchance" text="'blind tourist called on someone who does not belong to the player faction. this is not supported. reverting to normal recon.'" />
<set_value name="$blindtourist" exact="false" />
<edit_order_param param="'blindtourist'" value="false" order="this.assignedcontrolled.order" />
</do_if>
<do_if value="$blindtourist">
<set_value name="$anchorpos" exact="position.[0, 0, 0]" />
<do_if value="this.hascontext.{$targetspace}">
<set_value name="$refpos" exact="this.assignedcontrolled.position" />
<set_value name="$refzone" exact="this.zone" />
</do_if>
<do_elseif value="this.zone.isclass.highway and (this.zone.destination.sector == $targetspace)">
<set_value name="$refpos" exact="position.[0, 0, 0]" />
<set_value name="$refzone" exact="this.zone.destination" />
</do_elseif>
<create_position name="$anchorpos" object="$refzone" value="$refpos" space="$targetspace" />
<remove_value name="refzone" />
<remove_value name="refpos" />
</do_if>
</init>
<attention min="unknown">
<actions>
<set_command_action commandaction="commandaction.calculating" />
<label name="start" />
<do_if value="$police">
<do_if value="not $targetspace">
<find_cluster_in_range object="this.controlled" maxdistance="22" distances="$clusterstable" multiple="true" />
<!-- sort them-->
<set_value name="$sortedclusters" exact="$clusterstable.keys.sorted" />
<do_all exact="$sortedclusters.count" counter="$i">
<find_sector name="$clustersectors" multiple="true" space="$sortedclusters.{$i}" />
<do_all exact="$clustersectors.count" counter="$j">
<do_if value="$clustersectors.{$j}.policefaction == this.trueowner">
<set_value name="$targetspace" exact="$clustersectors.{$j}" />
<break />
</do_if>
</do_all>
<do_if value="$targetspace">
<debug_text chance="$debugchance" text="'targetspace successfully set.'" />
<break />
</do_if>
</do_all>
<remove_value name="clustersectors" />
<remove_value name="sortedclusters" />
</do_if>
<debug_text chance="$debugchance" text="'starting in sector %s. local police: %s. our faction: %s. target space: %s %s'.[this.sector.knownname,@this.sector.policefaction,this.trueowner,@$targetspace.class,@$targetspace.knownname]" />
</do_if>
<!-- checks: will we need any special equipment? if we don't, should we go get it? could we just assume that we have it? if we have it now, will we always have it?-->
<do_if value="not $targetspace and this.ship.isjobship">
<do_if value="this.zone.isclass.highway">
<debug_text chance="$debugchance" text="'%1 %2 is in a highway. waiting to exit.'.[this.ship.idcode,this.ship.knownname]" />
<wait />
</do_if>
<set_value name="$targetspace" exact="this.sector" />
</do_if>
<set_order_syncpoint_reached order="this.ship.order" />
<label name="prep" />
<set_value name="$num_timesreset" exact="@$num_timesreset + 1" />
<!-- /* <do_if value=\"$num_timesreset gt 1 and (player.age - $time_lastreset) lt 2s\">
<debug_text text=\"'reset after %s seconds.\n in player sector? %s\n police? %s\n resourcescout? %s\n exploreupdate? %s\n blindtourist? %s'.[player.age - $time_lastreset, this.ship.attention ge attention.insector, $police, $resourcescout, $exploreupdate, $blindtourist]\"/>
<do_if value=\"not $init_debugchance?\">
<set_value name=\"$init_debugchance\" exact=\"$debugchance\"/>
</do_if><set_value name=\"$debugchance\" exact=\"100\"/>
</do_if>-->
<set_value name="$time_lastreset" exact="player.age" />
<!-- NB: this would be more efficient in init, but moved here in case we decide to change $targetspace dynamically via Faction Logic or by other means.-->
<do_if value="$police">
<set_command command="command.investigate" />
<set_value name="$scanningrange" exact="[this.ship.maxradarrange, (this.assignedcontrolled.size / 2.0 + 1km)].min" />
</do_if>
<do_elseif value="$resourcescout">
<set_command command="command.searchresources" />
<set_value name="$scanningrange" exact="[this.ship.maxradarrange, (this.assignedcontrolled.size / 2.0 + 100m)].min" />
</do_elseif>
<do_else>
<do_if value="this.ship.relationto.{$targetspace.owner} lt 0">
<set_command command="command.recon" />
</do_if>
<do_else>
<set_command command="command.explore" />
</do_else>
<set_value name="$scanningrange" exact="this.ship.maxradarrange" />
</do_else>
<do_if value="this.ship.jobexpired or ($timeout and $time_init? and (player.age ge $time_init + $timeout))">
<resume label="end" />
</do_if>
<do_elseif value="$timeout and not $time_init?">
<set_value name="$time_init" exact="player.age" />
</do_elseif>
<!-- reset all recon data. we should only be back here if we're starting fresh.-->
<set_value name="$list_objectsscanned" exact="[]" />
<set_value name="$list_threats" exact="[]" />
<set_value name="$list_nonthreats" exact="[]" />
<set_value name="$table_factionthreatlevels" exact="table[]" />
<do_if value="$exploreupdate">
<create_list name="$list_zonestoinvestigate" />
<find_station name="$list_knownstations" multiple="true" checkoperational="true" knownto="this.owner" space="$targetspace" />
<!-- <find_station name=\"$list_knownstations\" space=\"$targetspace\" checkoperational=\"true\" canhaveofferlocation=\"true\" knownto=\"this.owner\" multiple=\"true\"/>-->
<do_all exact="$list_knownstations.count" counter="$i">
<do_if value="not $list_zonestoinvestigate.indexof.{$list_knownstations.{$i}.zone}">
<append_to_list name="$list_zonestoinvestigate" exact="$list_knownstations.{$i}.zone" />
</do_if>
</do_all>
<remove_value name="list_knownstations" />
</do_if>
<do_elseif value="$resourcescout">
<!-- resourcescout should be called from order.mining.routine after we are already in a resource-rich area, so we shouldn't wander off at this point.-->
<create_list name="$list_zonestoinvestigate" />
<append_to_list name="$list_zonestoinvestigate" exact="this.zone" />
<!-- $resourcezones populated only in high attention-->
<find_zone name="$resourcezones" multiple="true" space="this.sector">
<match_content class="class.asteroid" />
</find_zone>
<shuffle_list list="$resourcezones" />
<do_all exact="$resourcezones.count" counter="$i">
<append_to_list name="$list_zonestoinvestigate" exact="$resourcezones.{$i}" />
</do_all>
<debug_text chance="$debugchance" text="'resourcescout: found %s zones with resources (only works in high attention). %s zones to explore.'.[$resourcezones.count,$list_zonestoinvestigate.count]" />
</do_elseif>
<!-- blind tourist explores each zone as they are found, so no list of zones to explore.-->
<do_elseif value="$blindtourist" />
<do_else>
<!-- make a sorted list of zones in targetspace.-->
<find_zone name="$list_zonestoinvestigate" multiple="true" normalzone="true" space="$targetspace" />
</do_else>
<do_if value="@$list_zonestoinvestigate.count">
<debug_text chance="$debugchance" text="'found %1 zones in %2'.[$list_zonestoinvestigate.count,$targetspace.knownname]" />
<set_value name="$table_zones" exact="table[]" />
<do_all exact="$list_zonestoinvestigate.count" counter="$i" reverse="true">
<set_value name="$table_zones.{$list_zonestoinvestigate.{$i}}" exact="this.ship.distanceto.{$list_zonestoinvestigate.{$i}}" />
<do_if value="$list_zonestoinvestigate.{$i}.isclass.highway">
<debug_text filter="error" text="'recon ship has highway in list of zones to investigate.\npolice? %s\nresourcescout? %s\nexploreupdate? %s\nblindtourist? %s'.[$police,$resourcescout,$exploreupdate,$blindtourist]" />
<remove_value name="list_zonestoinvestigate.{$i}" />
</do_if>
</do_all>
<set_value name="$list_zonestoinvestigate" exact="$table_zones.keys.sorted" />
<remove_value name="table_zones" />
</do_if>
<debug_text chance="$debugchance" text="'%1 %2 starting reconnaissance mission:\n to %3 %4\n owned by %5.\n relation: %6\n police investigation? %7'.[this.ship.idcode,this.ship.knownname,$targetspace.class,$targetspace.knownname,$targetspace.owner,this.ship.relationto.{$targetspace.owner},$police]" />
<label name="gothere" />
<!-- are we there yet? if not, go there. (note: what is \"there\"? targetspace? an interim zone?)-->
<do_if value="not this.hascontext.{$targetspace}">
<debug_text chance="$debugchance" text="'%1 %2 moving to %3 %4,%5.'.[this.ship.idcode,this.ship.knownname,$targetspace.class,$targetspace.knownname,$targetspace.cluster.knownname]" />
<run_script />
</do_if>
<params>
<param name="destination" value="$targetspace" />
<param name="endintargetzone" value="true" />
<param name="debugchance" value="$debugchance" />
</params>
<do_if value="this.sector != $targetspace">
<debug_text filter="error" text="'%1 %2 did not arrive at targetspace.\n targetspace: %3,%4\n at: %5,%6'.[this.ship.idcode,this.ship.knownname,$targetspace.knownname,$targetspace.cluster.knownname,this.sector.knownname,this.cluster.knownname]" />
<resume label="gothere" />
</do_if>
<do_if value="$police and @this.zone.policefaction != this.trueowner">
<debug_text filter="error" text="'police ship %s %s at targetspace but we are not the police faction here. local police: %s,our faction: %s\nat: %s %s owned by %s'.[this.controlled.knownname,this.controlled,@this.zone.policefaction,this.trueowner,this.zone.knownname,this.zone,this.zone.trueowner]" />
</do_if>
<!-- determine the zone we want to go to,-->
<label name="proceedtonextzone" />
<set_value name="$destination" exact="null" />
<!-- Idle for a while. Important to prevent infinite loops in cases where there is absolutely nothing to explore. Shouldn't happen in normal game setup except for resource scout in low attention.-->
<run_script />
<params>
<param name="Min" value="1min" />
<param name="Max" value="5min" />
</params>
<do_if value="$blindtourist">
<!-- try to find an undiscovered spot that's fairly close to me and is toward the sector center.-->
<find_closest_undiscovered_position result="$pos_target" chance="this.assignedcontrolled.combinedskill" range="this.ship.maxradarrange * 2" sector="$targetspace">
<position object="$targetspace" />
<rangecenter object="this.assignedcontrolled" />
</find_closest_undiscovered_position>
<do_if value="not @$pos_target or $pos_target.distanceto.{$anchorpos} gt $radius">
<debug_text chance="$debugchance" text="'no close undiscovered areas found. widening search.'" />
<!-- /* if there aren't any, find the closest undiscovered spot to me. cap at a sensible distance.
fallback pos changed back to unknown closest to me to mitigate multiple ships going to the same position.-->
<find_closest_undiscovered_position result="$pos_target" range="$radius" sector="$targetspace">
<position object="this.assignedcontrolled" />
<rangecenter value="$anchorpos" />
</find_closest_undiscovered_position>
</do_if>
<do_if value="@$pos_target">
<set_value name="$destination" exact="$targetspace" />
<create_position name="$temp_sectorpos" object="this.zone" chance="$debugchance" value="this.position" space="$targetspace" />
<debug_text chance="$debugchance" text="'blind tourist is going to %s in %s %s %s.\npresent position: %s\nmy distance to new pos: %s\nanchor distance to new pos: %s\nradius: %s\nsector center distance to new pos: %s'.[$pos_target,$destination.class,$destination.knownname,$destination,$temp_sectorpos,this.ship.distanceto.[$targetspace,$pos_target],$pos_target.distanceto.{$anchorpos},$radius,$targetspace.distanceto.[$targetspace,$pos_target]]" />
<remove_value name="temp_sectorpos" />
</do_if>
<do_else>
<debug_text chance="$debugchance" text="'blind tourist has nothing left to explore. reverting to normal reconnaisance.'" />
<edit_order_param param="'blindtourist'" value="false" order="this.assignedcontrolled.order" />
</do_else>
</do_if>
<do_elseif value="@$list_zonestoinvestigate.{1">
<do_if value="$list_zonestoinvestigate.{1}.exists">
<set_value name="$destination" exact="$list_zonestoinvestigate.{1}" />
</do_if>
<do_else>
<do_all exact="$list_zonestoinvestigate.count" counter="$i" reverse="true">
<do_if value="not $list_zonestoinvestigate.{$i}.exists">
<remove_value name="list_zonestoinvestigate.{$i}" />
</do_if>
</do_all>
<do_if value="@$list_zonestoinvestigate.{1}">
<set_value name="$destination" exact="$list_zonestoinvestigate.{1}" />
</do_if>
</do_else>
</do_elseif>
<!-- if we're there, move around looking for trouble.-->
<label name="lookfortrouble" />
<do_if value="@$destination.exists">
<!-- pos_target is only used by blindtourist at the moment.-->
<do_if value="$pos_target?">
<get_safe_pos result="$safepos" radius="this.ship.size / 2" sector="$destination" value="$pos_target" space="$destination" />
<do_if value="true">
<!-- below optimistically assumes that safepos is fairly close to pos_target, close enough that one of the two distances checked is the hypotenuse. if we are very very close to either the safepos or pos_target, or if safepos is way off, then the distance to safepos calculation will be inaccurate. only used for debug output for now.-->
<do_if value="this.ship.distanceto.[$destination, $safepos] gt this.ship.distanceto.[$destination, $pos_target]">
<set_value name="$dist_hyp" exact="this.ship.distanceto.[$destination, $safepos]" />
<set_value name="$dist_nothyp" exact="this.ship.distanceto.[$destination, $pos_target]" />
</do_if>
<do_else>
<set_value name="$dist_hyp" exact="this.ship.distanceto.[$destination, $pos_target]" />
<set_value name="$dist_nothyp" exact="this.ship.distanceto.[$destination, $safepos]" />
</do_else>
<debug_text text="'safepos is:\n%s meters away from pos_target\n%s meters away from us\nand %s meters away from sector center.'.[sqrt(($dist_hyp^2)-($dist_nothyp^2)), this.ship.distanceto.[$destination, $safepos], $destination.distanceto.[$destination, $safepos]]" />
<remove_value name="dist_nothyp" />
<remove_value name="dist_hyp" />
</do_if>
<remove_value name="pos_target" />
</do_if>
<do_else>
<get_safe_pos result="$safepos" min="this.ship.maxradarrange" max="$destination.size / 3" zone="$destination" radius="this.ship.size / 2" />
<debug_text chance="$debugchance" text="'next safe pos is %s km from the center of %s %s.\nzone radius: %s km.\nradar range: %s km\npos: %s'.[$destination.distanceto.[$destination,$safepos] / 1000,$destination.class,$destination.knownname,$destination.size / 2 / 1000,this.ship.maxradarrange / 1000,$safepos]" />
</do_else>
<debug_text chance="$debugchance" text="'going to investigate %1 %2 in %3'.[$destination.class,$destination.knownname,$targetspace.knownname]" />
</do_if>
<do_else>
<debug_text chance="$debugchance" text="'went through all of the zones.'" />
<resume label="report" />
</do_else>
<!-- it's possible to wander to a different sector entirely while scanning a ship. in that case, go back to the targetspace.-->
<do_if value="not this.hascontext.{$targetspace}">
<debug_text chance="$debugchance" text="'%1 %2 wandered out of target space. Going back.\n am in: %3\n target space: %4'.[this.ship.idcode,this.ship.knownname,this.sector.knownname,$targetspace.knownname]" />
<resume label="gothere" />
</do_if>
<do_if value="$police and $destination.isclass.[class.sector, class.zone] and @$destination.policefaction != this.trueowner">
<debug_text filter="error" text="'police ship %s %s about to patrol area where they are not police. Check jobs setup or faction logic assignment,whichever applies.'.[this.controlled.knownname,this.controlled]" />
<assert text="'police ship %s %s about to patrol area where they are not police. Check jobs setup (location) or faction logic assignment (targetspace),whichever applies.'.[this.controlled.knownname,this.controlled]" value="@$destination.policefaction == this.trueowner" />
</do_if>
.........