

#process "destroy"
class auto_att_main;
class auto_att_fwd;
class auto_move;
class auto_retro;

core_pent_B, 4096, 
  {object_repair, 0},
  {object_downlink, 22, 
    {component_bowl, // component 1
      {object_uplink, 0},
      {object_interface, 0},
      {object_interface_depth, 0},
      {object_burst_l:auto_att_main, -297},
      {object_pulse:auto_att_fwd, -2048},
    }
  },
  {object_downlink, -22, 
    {component_bowl, // component 2
      {object_uplink, 0},
      {object_interface_depth, 0},
      {object_interface, 0},
      {object_pulse:auto_att_fwd, 2048},
      {object_burst_l:auto_att_main, 297},
    }
  },
  {object_downlink, 594, 
    {component_bowl, // component 3
      {object_move:auto_move, -1795},
      {object_uplink, 0},
      {object_move:auto_move, -470},
      {object_move:auto_move:auto_retro, -607},
      {object_move:auto_move, 1504},
    }
  },
  {object_downlink, -594, 
    {component_bowl, // component 4
      {object_move:auto_move, 1761},
      {object_move:auto_move, 382},
      {object_uplink, -703},
      {object_move:auto_move, -1564},
      {object_move:auto_move:auto_retro, 602},
    }
  },
#code




// Process AI modes (these reflect the capabilities of the process)
enum
{
  MODE_IDLE, // process isn't doing anything ongoing
  MODE_MOVE, // process is moving to target_x, target_y
  MODE_MOVE_ATTACK, // process is moving, but will attack anything it finds along the way
  MODE_ATTACK, // process is attacking a target it was commanded to attack
  MODE_ATTACK_FOUND, // process is attacking a target it found itself
  MODE_GUARD, // process is circling a friendly process
  MODES
};

// Commands that the user may give the process
// (these are fixed and should not be changed, although not all processes accept all commands)
enum
{
  COM_NONE, // no command
  COM_LOCATION, // user has right-clicked somewhere on the display or map
  COM_TARGET, // user has right-clicked on an enemy process
  COM_FRIEND, // user has right-clicked on a friendly process
  COM_DATA_WELL, // user has right-clicked on a data well
  COM_NUMBER // user has pressed a number key
};

// Targetting information
// Targetting memory allows processes to track targets (enemy or friend)
// The following enums are used as indices in the process' targetting memory
enum
{
  TARGET_PARENT, // a newly built process starts with its builder in address 0
  TARGET_MAIN, // main target
  TARGET_FRONT, // target of directional forward attack
  TARGET_GUARD, // target of guard command
};

int front_attack_primary; // is set to 1 if forward directional attack objects are attacking
 // the primary target (e.g. target selected by command). Set to 0 if the objects are available for autonomous fire.

// Variable declaration and initialisation
//  (note that declaration and initialisation cannot be combined)
//  (also, variables retain their values between execution cycles)
int core_x, core_y; // location of core
core_x = get_core_x(); // location is updated each cycle
core_y = get_core_y();
int angle; // direction process is pointing
 // angles are in integer degrees from 0 to 8192, with 0 being right,
 // 2048 down, 4096 left and 6144 (or -2048) up.
angle = get_core_angle(); // angle is updated each cycle

int mode; // what is the process doing? (should be one of the MODE enums)
int saved_mode; // save the process' mode while it's attacking something it found

int move_x, move_y; // destination
int target_x, target_y; // location of target (to attack, follow etc)

int scan_result; // used to hold the results of a scan of nearby processes
int initialised; // set to 1 after initialisation code below run the first time

if (!initialised)
{
   // initialisation code goes here (not all autocoded processes have initialisation code)
  initialised = 1;
  attack_mode(4); // attack objects (if present) will fire only when there is enough power
  // move the process forward a bit to stop it obstructing the next process to be built
  mode = MODE_MOVE;
  move_x = core_x + cos(angle, 300);
  move_y = core_y + sin(angle, 300);
}

int verbose; // if 1, process will print various things to the console

if (check_selected_single()) // returns 1 if the user has selected this process (and no other processes)
{
  if (!verbose) printf("\nProcess selected.");
  verbose = 1;
  set_debug_mode(1); // 1 means errors for this process will be printed to the console. Resets to 0 each cycle
}
  else
    verbose = 0;


// Accept commands from user
if (check_new_command() == 1) // returns 1 if a command has been given
{
  switch(get_command_type()) // get_command_type() returns the type of command given
  {
    case COM_LOCATION:
    case COM_DATA_WELL: // this process can't harvest, so treat data well commands as location commands
      move_x = get_command_x(); // get_command_x() and ...y() return the target location of the command
      move_y = get_command_y();
      if (get_command_ctrl() == 0) // returns 1 if control was pressed when the command was given
      {
        mode = MODE_MOVE;
        if (verbose) printf("\nMoving.");
      }
        else
        {
          mode = MODE_MOVE_ATTACK; // will attack anything found along the way
          if (verbose) printf("\nAttack-moving.");
        }
      break;
    
    case COM_TARGET:
      get_command_target(TARGET_MAIN); // writes the target of the command to address TARGET_MAIN in targetting memory
       // (targetting memory stores the target and allows the process to examine it if it's in scanning range
       //  of any friendly process)
      mode = MODE_ATTACK;
      if (verbose) printf("\nAttacking.");
      break;
    
    case COM_FRIEND:
      get_command_target(TARGET_GUARD); // writes the target of the command to address TARGET_GUARD in targetting memory
       // (targetting memory stores the target and allows the process to examine it if it's in scanning range)
      mode = MODE_GUARD;
      if (verbose) printf("\nGuarding.");
      break;
    
    default:
      if (verbose) printf("\nUnrecognised command.");
      break;
  
  } // end of command type switch
} // end of new command code


front_attack_primary = 0; // this will be set to 1 if process is attacking its main target


// What the process does next depends on its current mode
switch(mode)
{
  
  case MODE_IDLE:
    auto_move.set_power(0); // turn off all objects in the move class
    // now check for nearby hostile processes
    scan_result = scan_for_threat(0, 0, TARGET_MAIN); // scan_for_threat finds the hostile process nearest to the scan centre,
     // and saves it in the process' targetting memory.
     // (parameters are: (x offset of scan centre from core, y offset, targetting memory address))
    if (scan_result != 0)
    {
      mode = MODE_ATTACK_FOUND; // later code means that process will attack target in targetting memory 0
      saved_mode = MODE_IDLE; // when leaving MODE_ATTACK_FOUND, will return to this mode
      if (verbose) printf("\nTarget found; attacking.");
    }
    break;
  
  case MODE_MOVE_ATTACK:
  // check for nearby hostile processes
    scan_result = scan_for_threat(0, 0, TARGET_MAIN); // scan_for_threat finds the hostile process nearest to the scan centre,
     // and saves it in the process' targetting memory.
     // (parameters are: (x offset of scan centre from core, y offset, targetting memory address))
    if (scan_result != 0)
    {
      mode = MODE_ATTACK_FOUND; // later code means that process will attack target in targetting memory 0
      saved_mode = MODE_MOVE_ATTACK; // when leaving MODE_ATTACK_FOUND, will return to this mode
      if (verbose) printf("\nTarget found - attacking.");
      break;
    }
  // fall through to MODE_MOVE case...
  
  case MODE_MOVE:
  // stop moving when within 255 pixels of target (can change to higher or lower values if needed)
    if (distance_from_xy_less(move_x, move_y, 255))
    {
      clear_command(); // cancels the current command. If there's a queue of commands (e.g. shift-move waypoints)
       //  this moves the queue forward so that check_new_command() will return 1 next cycle.
      mode = MODE_IDLE;
      if (verbose) printf("\nReached destination.");
    }
      else
        auto_move.move_to(move_x, move_y); // calls move_to for all objects in the move class
    break;
  
  case MODE_ATTACK_FOUND:
  // Attack target as long as it's visible.
  // If target lost or destroyed, go back to previous action.
    target_x = process[TARGET_MAIN].get_core_x(); // calls get_core_x() on the process in targetting memory address TARGET_MAIN
    if (target_x == 0) // get_core_x() returns zero if the target is not visible or does not exist
    {
      mode = saved_mode;
      if (verbose) printf("\nTarget not detected.");
      break;
    }
    target_y = process[TARGET_MAIN].get_core_y();
    // Now see whether the commanded target is in scan range:
    if (!process[TARGET_MAIN].visible()) // returns zero if not target visible or doesn't exist
    {
      auto_move.move_to(target_x, target_y); // calls move_to for all objects in the move class
    }
      else
      {
        auto_move.approach_track(TARGET_MAIN,0,auto_att_main, 400);
         // approach_track() works out movement required to hit a target with a particular attacking object,
         //  but also tries to maintain a certain distance using retro (forward-facing) move objects.
         // It applies a simple target leading algorithm (which requires the attacking object to be identified)
         // Parameters are:
         //  - target's address in targetting memory
         //  - component of target process to attack (0 means the core)
         //  - class of attacking object (the first object in the class will be used)
         //  - stand-off distance (in pixels)
        if (process[TARGET_MAIN].distance_less(1000))
          auto_att_main.fire(0); // tries to fire all objects in the auto_att_main class. 0 is firing delay (in ticks)
         // (attack class is for fixed attack objects that point more or less forwards)
        if (process[TARGET_MAIN].distance_less(1000))
        {
          auto_att_fwd.fire_at(TARGET_MAIN,0); // Calls fire_at() on all objects in the forward directional attack class.
           // TARGET_MAIN indicates that the target is in targetting memory address TARGET_MAIN.
           // the second 0 is the target component (0 means the core is being targetted).
           // fire_at() rotates directional attack objects towards the target (with basic leading) and fires.
          front_attack_primary = 1; // this means the forward directional attack class will not try to find its own target.
        }
      }
    break;
  
  case MODE_ATTACK:
  // Attack target identified by user command
    target_x = get_command_x(); // get_command_x() returns the target location of the current command.
    target_y = get_command_y();
    if (target_x == 0) // get_command_x() returns 0 if target no longer visible
    {
      clear_command(); // clears the current command. If another command is queued,
       // it will register as a new command and can be retrieved next cycle.
      mode = MODE_IDLE;
      if (verbose) printf("\nTarget not detected.");
      break;
    }
    // Now see whether the commanded target is in scan range:
    if (!process[TARGET_MAIN].visible()) // returns zero if not target visible or doesn't exist
    {
      auto_move.move_to(target_x, target_y); // calls move_to for all objects in the move class
    }
      else
      {
        auto_move.approach_track(TARGET_MAIN,0,auto_att_main, 400);
         // approach_track() works out movement required to hit a target with a particular attacking object,
         //  but also tries to maintain a certain distance using retro (forward-facing) move objects.
         // It applies a simple target leading algorithm (which requires the attacking object to be identified)
         // Parameters are:
         //  - target's address in targetting memory
         //  - component of target process to attack (0 means the core)
         //  - class of attacking object (the first object in the class will be used)
         //  - stand-off distance (in pixels)
        if (process[TARGET_MAIN].distance_less(1000))
          auto_att_main.fire(0); // tries to fire all objects in the auto_att_main class. 0 is firing delay (in ticks)
         // (attack class is for fixed attack objects that point more or less forwards)
        if (process[TARGET_MAIN].distance_less(1000))
        {
          auto_att_fwd.fire_at(TARGET_MAIN,0); // Calls fire_at() on all objects in the forward directional attack class.
           // TARGET_MAIN indicates that the target is in targetting memory address TARGET_MAIN.
           // the second 0 is the target component (0 means the core is being targetted).
           // fire_at() rotates directional attack objects towards the target (with basic leading) and fires.
          front_attack_primary = 1; // this means the forward directional attack class will not try to find its own target.
        }
      }
    break;
  
  case MODE_GUARD:
  // Move in circle around friendly target identified by user command
  //  and attack any enemies that come near
    if (process[TARGET_GUARD].visible()) // returns 1 if target visible. Always returns 1 for a friendly target, if it exists.
    {
      // check for nearby hostile processes
      scan_result = scan_for_threat(0, 0, TARGET_MAIN); // scan_for_threat finds the hostile process nearest to the scan centre,
       // and saves it in the process' targetting memory.
       // (parameters are: (x offset of scan centre from core, y offset, targetting memory address))
      if (scan_result != 0)
      {
        mode = MODE_ATTACK_FOUND; // later code means that process will attack target in targetting memory 0
        saved_mode = MODE_GUARD; // when leaving MODE_ATTACK_FOUND, will return to this mode
        if (verbose) printf("\nTarget found - attacking.");
        break;
      }
      int angle_to_guard_target;
      angle_to_guard_target = atan2(process[TARGET_GUARD].get_core_y() - core_y, process[TARGET_GUARD].get_core_x() - core_x);
      angle_to_guard_target += 1024; // this will lead the process in a circle around the target
      auto_move.move_to(process[TARGET_GUARD].get_core_x() - cos(angle_to_guard_target, 200),
                        process[TARGET_GUARD].get_core_y() - sin(angle_to_guard_target, 200));
      break;
    }
    // guard target must have been destroyed. Go back to idle mode and check for new commands.
    clear_command(); // cancels the current command. If there's a queue of commands (e.g. shift-move waypoints)
     //  this moves the queue forward so that check_new_command() will return 1 next cycle.
    mode = MODE_IDLE;
    if (verbose) printf("\nGuard target lost.");
    break;

} // end of mode switch

if (front_attack_primary == 0) // is 1 if the forward attack objects are attacking the main target
{
  auto_att_fwd.attack_scan(0, 400, TARGET_FRONT);
}

charge_interface_max(); // charges the process' interface. Since the interface is shared across all
 // components with interface objects, this call is not specific to any object or class.
 // charge_interface_max() charges the interface using as much power as possible
 // (the charge rate is determined by the maximum interface strength).

restore_self(); // tries to restore any destroyed components

repair_self(); // tries to repair any damaged components
