src/hcode/btech/autopilot_autogun.c File Reference

#include "mech.h"
#include "mech.events.h"
#include "autopilot.h"
#include "failures.h"
#include "mech.sensor.h"
#include "p.autogun.h"
#include "p.bsuit.h"
#include "p.glue.h"
#include "p.mech.sensor.h"
#include "p.mech.utils.h"
#include "p.mech.physical.h"
#include "p.mech.combat.h"
#include "p.mech.advanced.h"
#include "p.mech.bth.h"

Include dependency graph for autopilot_autogun.c:

Go to the source code of this file.

Functions

int SearchLightInRange (MECH *mech, MAP *map)
int PrefVisSens (MECH *mech, MAP *map, int slite, MECH *target)
void auto_sensor_event (AUTO *autopilot)
weapon_nodeauto_create_weapon_node (short weapon_number, short weapon_db_number, short section, short critical)
void auto_destroy_weapon_node (weapon_node *victim)
target_nodeauto_create_target_node (int target_score, dbref target_dbref)
void auto_destroy_target_node (target_node *victim)
void auto_destroy_weaplist (AUTO *autopilot)
static int auto_targets_callback (void *key, void *data, int depth, void *arg)
static int auto_generic_compare (void *a, void *b, void *token)
int auto_calc_weapon_score (int weapon_db_number, int range)
void auto_update_profile_event (AUTO *autopilot)
int auto_calc_target_score (AUTO *autopilot, MECH *mech, MECH *target, MAP *map)
void auto_gun_event (AUTO *autopilot)


Function Documentation

int auto_calc_target_score ( AUTO autopilot,
MECH mech,
MECH target,
MAP map 
)

Definition at line 744 of file autopilot_autogun.c.

References AUTO_GUN_MAX_RANGE, COMBAT_SAFE, Destroyed, FindHexRange(), GetSectArmor, GetSectInt, GetSectOArmor, GetSectOInt, GetSectORArmor, GetSectRArmor, MechBV, MechFX, MechFY, MECHLOSFLAG_SEEN, MechSpeed, MechStatus, MechTeam, MechToMech_LOSFlag, Started, and Uncon.

Referenced by auto_gun_event().

00746 {
00747 
00748         int target_score;
00749         float range;
00750         float target_speed;
00751         int target_bv;
00752 
00753         int total_armor_current;
00754         int total_armor_original;
00755         int total_internal_current;
00756         int total_internal_original;
00757 
00758         int section;
00759 
00760         float damage_score;
00761         float bv_score;
00762         float speed_score;
00763         float range_score;
00764         float status_score;
00765 
00766         /* Default Values */
00767         target_score = 0;
00768 
00769         total_armor_current = 0;
00770         total_armor_original = 0;
00771         total_internal_current = 0;
00772         total_internal_original = 0;
00773 
00774         damage_score = 0.0;
00775         bv_score = 0.0;
00776         speed_score = 0.0;
00777         range_score = 0.0;
00778         status_score = 0.0;
00779 
00780         /* Here is the meat of the function, basicly I gave each
00781          * part a maximum score, then fit a linear plot from the
00782          * max to a min value and score.  Then I just summed
00783          * all the pieces together, very linear but should
00784          * give us a good starting point */
00785 
00786         /* Is the target dead? */
00787         if(Destroyed(target))
00788                 return target_score;
00789 
00790         /* If target is combat safe don't even try to shoot it */
00791         if(MechStatus(target) & COMBAT_SAFE)
00792                 return target_score;
00793 
00794         /* Compare Teams - for now we won't try to shoot a guy on our team */
00795         if(MechTeam(target) == MechTeam(mech))
00796                 return target_score;
00797 
00798         /* Are we in los of the target - not sure really what to do about this
00799          * one, since we want the AI to be smart and all, for now, lets have
00800          * it be all seeing */
00801 
00802         /* Range to target */
00803         range = FindHexRange(MechFX(mech), MechFY(mech), MechFX(target),
00804                                                  MechFY(target));
00805 
00806         /* Our we outside the range of the AI's System */
00807         if((range >= (float) AUTO_GUN_MAX_RANGE)) {
00808                 return target_score;
00809         }
00810 
00811         /* Range score calc */
00812         /* Min range is 0, max range is 30, so score goes from 300 to 0 */
00813         range_score = -10.0 * range + 300.0;
00814 
00815         /* Get the Speed of the target */
00816         target_speed = MechSpeed(target);
00817 
00818         /* Speed score calc */
00819         /* Min speed is 0, max is 150 (can go higher tho), and score goes from
00820          * 300 to 0 (can go negative if the target is faster then 150) */
00822         speed_score = -2.0 * target_speed + 300.0;
00823 
00824         /* Get the BV of the target */
00825         target_bv = MechBV(target);
00826 
00827         /* BV score calc */
00828         /* Min bv is 0, max is around 2000 (can go higher), and score goes from
00829          * 0 to 100 (can go higher but we don't care much about bv) */
00830         bv_score = 0.05 * ((float) target_bv);
00831 
00832         /* Get the damage of the target by cycling through all the sections
00833          * and adding up the current and original values */
00834         for(section = 0; section < NUM_SECTIONS; section++) {
00835 
00836                 /* Total the current armor and original armor */
00837                 total_armor_current += GetSectArmor(target, section) +
00838                         GetSectRArmor(target, section);
00839                 total_armor_original += GetSectOArmor(target, section) +
00840                         GetSectORArmor(target, section);
00841 
00842                 /* Total the current internal and original internal */
00843                 total_internal_current += GetSectInt(target, section);
00844                 total_internal_original += GetSectOInt(target, section);
00845 
00846         }
00847 
00848         /* Ok like above, we set a min and max, for armor was 100% to 0%
00849          * and scored from 0 to 300.  For internal was 100% to 0% and
00850          * scored from 0 to 200. But we have to take care not to divide
00851          * by zero. */
00852 
00853         /* Check the totals before we divide so no Divide by zeros */
00854         if(total_internal_original == 0 && total_armor_original == 0) {
00855 
00856                 /* Both values are zero, not going to try and shoot it */
00857                 return target_score;
00858 
00859         } else if(total_internal_original == 0) {
00860 
00861                 /* Just use armor part of the calc */
00862                 damage_score = -3.0 * ((float) total_armor_current /
00863                                                            (float) total_armor_original) + 300.0;
00864 
00865         } else if(total_armor_original == 0) {
00866 
00867                 /* Just use internal part of the calc */
00868                 damage_score = -2.0 * ((float) total_internal_current /
00869                                                            (float) total_internal_original) + 200.0;
00870 
00871         } else {
00872 
00873                 /* Use the whole thing */
00874                 damage_score = -3.0 * ((float) total_armor_current /
00875                                                            (float) total_armor_original) + 300.0
00876                         - 2.0 * ((float) total_internal_current /
00877                                          (float) total_internal_original) + 200.0;
00878 
00879         }
00880 
00881         /* Get the 'state' ie: shutdown, prone whatever */
00882         if(!Started(target))
00883                 status_score += 100.0;
00884 
00885         if(Uncon(target))
00886                 status_score += 100.0;
00887 
00888         if(MechToMech_LOSFlag(map, mech, target) & MECHLOSFLAG_SEEN)
00889                 status_score += 500.0;
00890 
00891         /* Add the individual scores and return the value */
00892         target_score = (int) floor(range_score + speed_score + bv_score +
00893                                                            damage_score + status_score);
00894 
00895         return target_score;
00896 
00897 }

int auto_calc_weapon_score ( int  weapon_db_number,
int  range 
)

Definition at line 442 of file autopilot_autogun.c.

References weapon_struct::damage, weapon_struct::heat, IsMissile, missile_hit_table_struct::key, MechWeapons, and MissileHitTable.

00443 {
00444 
00445         int weapon_score;
00446         int range_score;
00447         int damage_score;
00448         int heat_score;
00449         int minrange_score;
00450 
00451         int weapon_damage;
00452         int weapon_heat;
00453 
00454         int i;
00455 
00456         /* Simple Calc */
00457 
00458         /* For the modifiers I assumed best was approx 550
00459          *
00460          * So for SR, chance of hitting is roughly 92% which is 506 rounded to 500 
00461          * For MR, its 72%, so 390 and LR its 41% its 225 */
00462 
00463         /* Assume default values */
00464         weapon_score = 0;
00465         weapon_damage = 0;
00466         range_score = 500;                      /* Since by default we assume its SR */
00467         damage_score = 0;
00468         heat_score = 0;
00469         minrange_score = 0;
00470 
00471         /* Don't bother trying to set a value if its outside its range */
00472         if(range >= MechWeapons[weapon_db_number].longrange) {
00473                 return weapon_score;
00474         }
00475 
00476         /* Are we at LR ? */
00477         if(range >= MechWeapons[weapon_db_number].medrange) {
00478                 range_score = 215;
00479         }
00480 
00481         /* Are we at MR ? */
00482         if(range >= MechWeapons[weapon_db_number].shortrange &&
00483            range < MechWeapons[weapon_db_number].medrange) {
00484                 range_score = 390;
00485         }
00486 
00487         /* Check min range */
00488         /* Use a polynomial equation here because at 2 under min its equiv to MR, at
00489          * 4 under its equiv to LR, so we want it to balance out the range score */
00490         /* score = -12.5(min - range)^2 - 25 * (min - range) */
00491         if(range < MechWeapons[weapon_db_number].min) {
00492                 minrange_score =
00493                         -12.5 * (float) ((MechWeapons[weapon_db_number].min - range) *
00494                                                          (MechWeapons[weapon_db_number].min - range)) -
00495                         25.0 * (float) (MechWeapons[weapon_db_number].min - range);
00496         }
00497 
00498         /* Get the damage for the weapon */
00499         if(IsMissile(weapon_db_number)) {
00500 
00501                 /* Its a missile weapon so lookup in the Missile table get the max
00502                  * number of missiles it can hit with, and multiply by the damage
00503                  * per missile */
00504                 /* To make it more fair going to use the avg # of missile hits
00505                  * which is when they would roll a 7, which becomes slot #
00506                  * 5 */
00507                 for(i = 0; MissileHitTable[i].key != -1; i++) {
00508                         if(MissileHitTable[i].key == weapon_db_number) {
00509                                 weapon_damage = MissileHitTable[i].num_missiles[5] *
00510                                         MechWeapons[weapon_db_number].damage;
00511                                 break;
00512                         }
00513                 }
00514 
00515         } else {
00516                 weapon_damage = MechWeapons[weapon_db_number].damage;
00517         }
00518 
00519         /* Get the damage score */
00520         /* Straight linear plot */
00521         damage_score = 50 * weapon_damage;
00522 
00523         /* Get the heat */
00524         weapon_heat = MechWeapons[weapon_db_number].heat;
00525 
00526         /* Get the heat score */
00527         /* Straight inverse linear plot - more heat bad... */
00528         heat_score = -25 * weapon_heat + 250;
00529 
00530         /* Final calc */
00531         weapon_score = range_score + damage_score + heat_score + minrange_score;
00532 
00533         return weapon_score;
00534 
00535 }

target_node* auto_create_target_node ( int  target_score,
dbref  target_dbref 
)

Definition at line 349 of file autopilot_autogun.c.

References target_node_t::target_dbref, and target_node_t::target_score.

Referenced by auto_gun_event().

00350 {
00351 
00352         target_node *temp;
00353 
00354         temp = malloc(sizeof(target_node));
00355 
00356         if(temp == NULL) {
00357                 return NULL;
00358         }
00359 
00360         memset(temp, 0, sizeof(target_node));
00361 
00362         temp->target_score = target_score;
00363         temp->target_dbref = target_dbref;
00364 
00365         return temp;
00366 
00367 }

weapon_node* auto_create_weapon_node ( short  weapon_number,
short  weapon_db_number,
short  section,
short  critical 
)

Definition at line 312 of file autopilot_autogun.c.

References weapon_node_t::critical, weapon_node_t::section, weapon_node_t::weapon_db_number, and weapon_node_t::weapon_number.

00315 {
00316 
00317         weapon_node *temp;
00318 
00319         temp = malloc(sizeof(weapon_node));
00320 
00321         if(temp == NULL) {
00322                 return NULL;
00323         }
00324 
00325         memset(temp, 0, sizeof(weapon_node));
00326 
00327         temp->weapon_number = weapon_number;
00328         temp->weapon_db_number = weapon_db_number;
00329         temp->section = section;
00330         temp->critical = critical;
00331 
00332         return temp;
00333 
00334 }

void auto_destroy_target_node ( target_node victim  ) 

Definition at line 372 of file autopilot_autogun.c.

Referenced by auto_targets_callback().

00373 {
00374 
00375         free(victim);
00376         return;
00377 
00378 }

void auto_destroy_weaplist ( AUTO autopilot  ) 

Definition at line 383 of file autopilot_autogun.c.

References auto_destroy_weapon_node(), dllist_destroy_list(), dllist_remove_node_at_pos(), dllist_size(), and AUTO::weaplist.

Referenced by auto_newautopilot(), and newfreemech().

00384 {
00385 
00386         weapon_node *temp_weapon_node;
00387 
00388         /* Check to make sure there is a weapon list */
00389         if(!(autopilot->weaplist))
00390                 return;
00391 
00392         /* There is a weapon list - lets kill it */
00393         if(dllist_size(autopilot->weaplist) > 0) {
00394 
00395                 while (dllist_size(autopilot->weaplist)) {
00396                         temp_weapon_node =
00397                                 (weapon_node *) dllist_remove_node_at_pos(autopilot->weaplist,
00398                                                                                                                   1);
00399                         auto_destroy_weapon_node(temp_weapon_node);
00400                 }
00401 
00402         }
00403 
00404         /* Finally destroying the list */
00405         dllist_destroy_list(autopilot->weaplist);
00406         autopilot->weaplist = NULL;
00407 
00408 }

void auto_destroy_weapon_node ( weapon_node victim  ) 

Definition at line 339 of file autopilot_autogun.c.

Referenced by auto_destroy_weaplist().

00340 {
00341 
00342         free(victim);
00343         return;
00344 }

static int auto_generic_compare ( void *  a,
void *  b,
void *  token 
) [static]

Definition at line 428 of file autopilot_autogun.c.

Referenced by auto_gun_event().

00429 {
00430 
00431         int *one, *two;
00432 
00433         one = (int *) a;
00434         two = (int *) b;
00435 
00436         return (*one - *two);
00437 }

void auto_gun_event ( AUTO autopilot  ) 

Definition at line 905 of file autopilot_autogun.c.

References AssignedTarget, auto_calc_target_score(), auto_create_target_node(), auto_generic_compare(), AUTO_GUN_MAX_RANGE, AUTO_GUN_UPDATE_TICK, auto_targets_callback(), Destroyed, DoStopGun, FindHexRange(), getMap(), getMech(), IsAuto(), IsMech, LBUF_SIZE, MECH::mapindex, MECH::mapnumber, MechFX, MechFY, AUTO::mymech, AUTO::mynum, MECH::mynum, OODing, print_autogun_log, rb_destroy(), rb_exists(), rb_init(), rb_insert(), rb_search(), rb_size(), rb_walk(), SEARCH_LAST, Started, AUTO::target, AUTO::target_score, AUTO::target_threshold, AUTO::target_update_tick, UnassignTarget, WALK_INORDER, AUTO::weaplist, x, y, and Zombify.

Referenced by auto_heartbeat().

00906 {
00907         MECH *mech = (MECH *) autopilot->mymech;        /* Its Mech */
00908         MAP *map;                                       /* The current Map */
00909         MECH *target;                           /* Our current target */
00910         MECH *physical_target;          /* Our physical target */
00911         rbtree targets;                     /* all the targets we're looking at */
00912         target_node *temp_target_node;  /* temp target node struct */
00913         weapon_node *temp_weapon_node;  /* temp weapon node struct */
00914 
00915         char buffer[LBUF_SIZE];         /* General use buffer */
00916 
00917         int target_score;                       /* variable to store temp score */
00918         int threshold_score;            /* The score to beat to switch targets */
00919 
00920         /* Stuff for Physical attacks */
00921         int elevation_diff;                     /* Whats the elevation difference between
00922                                                                    the target and the mech */
00923         int what_arc;                           /* What arc is the target in */
00924         int new_arc;                            /* What arc now that we've twisted
00925                                                                    our torso */
00926         int relative_bearing;           /* Int to figure out which part of
00927                                                                    the rear arc hes in */
00928         int is_section_destroyed[4];    /* Array of the different possible
00929                                                                            sections that could be destroyed */
00930         int section_hasbusyweap[4];     /* Array to show if a section has a
00931                                                                    cycling weapon in it */
00932         int rleg_bth, lleg_bth;         /* To help us decide which leg to kick
00933                                                                    with */
00934         int is_rarm_ready, is_larm_ready;       /* To help us decide which arms to
00935                                                                                    punch with */
00936 
00937         /* Stuff for Weapon Attacks */
00938         int accumulate_heat;            /* How much heat we're building up */
00939         int i, j;
00940 
00941         float range;                            /* General variable for range */
00942         float maxspeed;                         /* So we know how fast our guy is going */
00943 
00944         /* For use with chase targ */
00945         short x, y;
00946         float fx, fy;
00947         char do_chasetarget;            /* Flag should we do chasetarget
00948                                                                    based on certain conditions */
00949 
00950         /* Basic checks */
00951         if(!mech || !autopilot)
00952                 return;
00953 
00954         if(!IsMech(mech->mynum) || !IsAuto(autopilot->mynum))
00955                 return;
00956 
00957         /* Ok our mech is dead we're done */
00958         if(Destroyed(mech)) {
00959                 DoStopGun(autopilot);
00960                 return;
00961         }
00962 
00964         if(!Started(mech)) {
00965                 Zombify(autopilot);
00966                 return;
00967         }
00968 
00969         /* Not on map - so lets calm down */
00970         if(!(map = getMap(mech->mapindex))) {
00971                 Zombify(autopilot);
00972                 return;
00973         }
00974 
00975         /* Log it */
00976         print_autogun_log(autopilot, "Autogun Event Started");
00977 
00978         /* check for a gun profile. */
00979     if(autopilot->weaplist == NULL) {
00980                 print_autogun_log(autopilot, "Autogun Event Finished");
00981                 return;
00982         }
00983 
00984         /* OODing so don't shoot any guns */
00985         if(OODing(mech)) {
00986                 /* Log It */
00987                 print_autogun_log(autopilot, "Autogun Event Finished");
00988                 return;
00989         }
00990 
00991         /* First check to make sure we have a valid current target */
00992         if(autopilot->target > -1) {
00993 
00994                 if(!(target = getMech(autopilot->target))) {
00995 
00996                         /* ok its not a valid target reset */
00997                         autopilot->target = -1;
00998                         autopilot->target_score = 0;
00999 
01000                 } else if(Destroyed(target) || (target->mapindex != mech->mapindex)) {
01001 
01002                         /* Target is either dead or not on the map anymore */
01003                         autopilot->target = -1;
01004                         autopilot->target_score = 0;
01005 
01006                 } else {
01007 
01008                         /* Will keep on an assigned target even if its to far
01009                          * away */
01010 
01011                         /* Get range from mech to current target */
01012                         range = FindHexRange(MechFX(mech), MechFY(mech),
01013                                                                  MechFX(target), MechFY(target));
01014 
01015                         if((range >= (float) AUTO_GUN_MAX_RANGE) &&
01016                            !AssignedTarget(autopilot)) {
01017 
01018                                 /* Target is to far away */
01019                                 autopilot->target = -1;
01020                                 autopilot->target_score = 0;
01021 
01022                         }
01023 
01024                 }
01025 
01026         }
01027 
01028         /* Were we given a target and its no longer there? */
01029         if(AssignedTarget(autopilot) && autopilot->target == -1) {
01030 
01031                 /* Ok we had an assigned target but its gone now */
01032                 UnassignTarget(autopilot);
01033 
01035         }
01036 
01037         /* Do we need to look for a new target */
01038         if(autopilot->target == -1 ||
01039            (autopilot->target_update_tick >= AUTO_GUN_UPDATE_TICK &&
01040                 !AssignedTarget(autopilot))) {
01041 
01042                 /* Ok looking for a new target */
01043 
01044                 /* Log It */
01045                 print_autogun_log(autopilot, "Autogun - Looking for new target");
01046 
01047                 /* Reset the update ticker */
01048                 autopilot->target_update_tick = 0;
01049 
01050                 /* Setup the rbtree */
01051                 targets = rb_init(&auto_generic_compare, NULL);
01052 
01053                 /* Cycle through possible targets and pick something to shoot */
01054                 for(i = 0; i < map->first_free; i++) {
01055 
01056                         /* Make sure its on the right map */
01057                         if(i != mech->mapnumber && (j = map->mechsOnMap[i]) > 0) {
01058 
01059                                 /* Is it a valid unit ? */
01060                                 if(!(target = getMech(j)))
01061                                         continue;
01062 
01063                                 /* Score the target */
01064                                 target_score =
01065                                         auto_calc_target_score(autopilot, mech, target, map);
01066 
01067                                 /* Log It */
01068                                 print_autogun_log(autopilot,
01069                                                                   "Autogun - Possible target #%d with score %d",
01070                                                                   target->mynum, target_score);
01071 
01072                                 /* If target has a score add it to rbtree */
01073                                 if(target_score > 0) {
01074 
01075                                         /* Create target node and fill with proper values */
01076                                         temp_target_node = auto_create_target_node(target_score,
01077                                                                                                                            target->mynum);
01078 
01081                                         /* Add it to list but first make sure it doesn't overlap
01082                                          * with a current score */
01083                                         while (1) {
01084 
01085                                                 if(rb_exists
01086                                                    (targets, &temp_target_node->target_score)) {
01087                                                         temp_target_node->target_score++;
01088                                                 } else {
01089                                                         break;
01090                                                 }
01091 
01092                                         }
01093 
01094                                         /* Add it */
01095                                         rb_insert(targets, &temp_target_node->target_score,
01096                                                           temp_target_node);
01097 
01098                                 }
01099 
01100                                 /* Check to see if its our current target */
01101                                 if(autopilot->target == target->mynum) {
01102 
01103                                         /* Save the new score */
01104                                         autopilot->target_score = target_score;
01105 
01106                                 }
01107 
01108                         }
01109 
01110                 }                                               /* End of for loop */
01111 
01112                 /* Check to see if we couldn't find ANY targets within range,
01113                  * if not, cycle autogun and set the update tick to 20, so we
01114                  * check again in 10 seconds */
01115                 if(!(rb_size(targets) > 0)) {
01116 
01117                         /* Have the AI look for a new target 10 seconds from now */
01120                         autopilot->target = -1;
01121                         autopilot->target_score = 0;
01122                         autopilot->target_update_tick = 0;
01123 
01124                         /* Don't need the target list any more so lets destroy it */
01125                         rb_walk(targets, WALK_INORDER, &auto_targets_callback, NULL);
01126                         rb_destroy(targets);
01127 
01128             /* Log It */
01129                         print_autogun_log(autopilot, "Autogun in idle mode");
01130                         print_autogun_log(autopilot, "Autogun Event Finished");
01131                         return;
01132                 }
01133 
01134                 /* Now if we have a current target, compare it to best target from
01135                  * the new list.  If better then threshold, lock new target, else
01136                  * stay on target */
01137 
01138                 /* Best target */
01139                 temp_target_node =
01140                         (target_node *) rb_search(targets, SEARCH_LAST, NULL);
01141 
01142                 /* Log It */
01143                 print_autogun_log(autopilot,
01144                                                   "Autogun - Best target #%d with score %d",
01145                                                   temp_target_node->target_dbref,
01146                                                   temp_target_node->target_score);
01147                 print_autogun_log(autopilot,
01148                                                   "Autogun - Current target #%d with score %d",
01149                                                   autopilot->target, autopilot->target_score);
01150 
01151                 if(autopilot->target > -1 && autopilot->target_score > 0) {
01152 
01153                         /* Check to see if its our current target */
01154                         if(autopilot->target != temp_target_node->target_dbref) {
01155 
01156                                 /* Calc the threshold score to beat */
01157                                 threshold_score =
01158                                         ((100.0 +
01159                                           (float) autopilot->target_threshold) / 100.0) *
01160                                         autopilot->target_score;
01161 
01162                                 if(temp_target_node->target_score > threshold_score) {
01163 
01164                                         /* Change targets */
01165                                         autopilot->target = temp_target_node->target_dbref;
01166                                         autopilot->target_score = temp_target_node->target_score;
01167 
01168                                         print_autogun_log(autopilot, "Switching Target to #%d",
01169                                                                           autopilot->target);
01170 
01171                                 }
01172 
01173                                 /* Else: Don't switch targets */
01174 
01175                         }
01176 
01177                         /* Else: Don't need to swtich targets */
01178 
01179                 } else {
01180 
01181                         /* Don't have a good current target so lock this one */
01182                         autopilot->target = temp_target_node->target_dbref;
01183                         autopilot->target_score = temp_target_node->target_score;
01184 
01185                 }                                               /* End of choosing new target */
01186 
01187                 /* Don't need the target list any more so lets destroy it */
01188                 rb_walk(targets, WALK_INORDER, &auto_targets_callback, NULL);
01189                 rb_destroy(targets);
01190 
01191         } else {
01192 
01193                 /* Ok didn't need to look for a new target so update the ticker */
01194                 autopilot->target_update_tick++;
01195 
01196         }
01197 
01198         /* End of picking a new target */
01199 
01200         /* Log It */
01201         print_autogun_log(autopilot, "Autogun - Current target #%d with score %d",
01202                                           autopilot->target, autopilot->target_score);
01203 
01204         /* Setup the current target */
01205         if(!(target = getMech(autopilot->target))) {
01206 
01207                 /* There were no valid targets so
01208                  * rerun autogun */
01209 
01210                 /* Reset the AI */
01211                 autopilot->target = -1;
01212                 autopilot->target_score = 0;
01213 
01214         /* Log It */
01215                 print_autogun_log(autopilot, "Autogun - No valid current targets");
01216                 print_autogun_log(autopilot, "Autogun Event Finished");
01217                 return;
01218 
01219         }
01220 
01221         /* Check to see if we need to (re)lock our target */
01222         if(MechTarget(mech) != autopilot->target) {
01223 
01224                 /* Lock Him */
01225                 snprintf(buffer, LBUF_SIZE, "%c%c", MechID(target)[0],
01226                                  MechID(target)[1]);
01227                 mech_settarget(autopilot->mynum, mech, buffer);
01228 
01229                 /* Log It */
01230                 print_autogun_log(autopilot, "Autogun - Locking target #%d",
01231                                                   autopilot->target);
01232 
01233         }
01234 
01235         /* Update autosensor */
01236 
01237         /* Now lets get physical */
01238 
01239         /* Log It */
01240         print_autogun_log(autopilot, "Autogun - Start Physical Attack Stage");
01241 
01242         /* Get range from mech to current target */
01243         range =
01244                 FindHexRange(MechFX(mech), MechFY(mech), MechFX(target),
01245                                          MechFY(target));
01246 
01247         /* First check our range to our target, if within range attack it, else
01248          * check to see if its outside our range threshold and if so pick a target
01249          * close and attack that */
01250 
01252         if(range < 1.0) {
01253 
01254                 /* We're beating on our main target */
01255                 physical_target = target;
01256 
01257         } else if(range > AUTO_GUN_PHYSICAL_RANGE_MIN) {
01258 
01259                 /* Try and find a target */
01260 
01261                 physical_target = NULL;
01262 
01263                 /* Cycle through possible targets and pick something to beat on */
01264                 for(i = 0; i < map->first_free; i++) {
01265 
01266                         /* Make sure its on the right map */
01267                         if(i != mech->mapnumber && (j = map->mechsOnMap[i]) > 0) {
01268 
01269                                 /* Is it a valid unit ? */
01270                                 if(!(target = getMech(j)))
01271                                         continue;
01272 
01273                                 if(Destroyed(target))
01274                                         continue;
01275 
01276                                 if(MechStatus(target) & COMBAT_SAFE)
01277                                         continue;
01278 
01279                                 if(MechTeam(target) == MechTeam(mech))
01280                                         continue;
01281 
01282                                 /* Check its range */
01283                                 range = FindHexRange(MechFX(mech), MechFY(mech),
01284                                                                          MechFX(target), MechFY(target));
01285 
01286                                 /* Just go for first one , can always add scoring later */
01287                                 if(range < 1.0) {
01288                                         physical_target = target;
01289                                         break;
01290                                 }
01291 
01292                         }
01293 
01294                 }
01295 
01296         } else {
01297 
01298                 /* Our target is close so dont try and physically attack anyone */
01299                 physical_target = NULL;
01300 
01301         }
01302 
01303         /* Now nail it with a physical attack but only if we see it */
01304         if(physical_target &&
01305            (MechToMech_LOSFlag(map, mech, physical_target) & MECHLOSFLAG_SEEN)) {
01306 
01307                 /* Log It */
01308                 print_autogun_log(autopilot,
01309                                                   "Autogun - Attempting physical attack against"
01310                                                   " target #%d", physical_target->mynum);
01311 
01312                 /* Calculate elevation difference */
01313                 elevation_diff = MechZ(mech) - MechZ(target);
01314 
01315                 /* Are we a biped Mech */
01316                 if((MechType(mech) == CLASS_MECH) && (MechMove(mech) == MOVE_BIPED)) {
01317 
01318                         /* Center the torso */
01319                         MechStatus(mech) &= ~(TORSO_RIGHT | TORSO_LEFT);
01320 
01321                         if(MechSpecials(mech) & FLIPABLE_ARMS) {
01322 
01323                                 /* Center the arms if need be */
01324                                 MechStatus(mech) &= ~(FLIPPED_ARMS);
01325                         }
01326 
01327                         /* Find direction of bad guy */
01328                         what_arc =
01329                                 InWeaponArc(mech, MechFX(physical_target),
01330                                                         MechFY(physical_target));
01331 
01332                         /* Rotate if we need to */
01333                         if(what_arc & LSIDEARC) {
01334 
01335                                 /* Rotate Left */
01336                                 MechStatus(mech) |= TORSO_LEFT;
01337 
01338                         } else if(what_arc & RSIDEARC) {
01339 
01340                                 /* Rotate Right */
01341                                 MechStatus(mech) |= TORSO_RIGHT;
01342 
01343                         } else if(what_arc & REARARC) {
01344 
01345                                 /* Find out if it would be better to
01346                                  * rotate left or right */
01347                                 relative_bearing =
01348                                         MechFacing(mech) - FindBearing(MechFX(mech), MechFY(mech),
01349                                                                                                    MechFX(physical_target),
01350                                                                                                    MechFY(physical_target));
01351 
01352                                 if(relative_bearing > 120 && relative_bearing < 180) {
01353 
01354                                         /* Rotate Right */
01355                                         MechStatus(mech) |= TORSO_RIGHT;
01356 
01357                                 } else if(relative_bearing > 180 && relative_bearing < 240) {
01358 
01359                                         /* Rotate Left */
01360                                         MechStatus(mech) |= TORSO_LEFT;
01361 
01362                                 }
01363 
01364                                 /* ELSE: Hes directly behind us so we can't do anything */
01365 
01366                         }
01367 
01368                         /* Calculate the new arc */
01369                         new_arc =
01370                                 InWeaponArc(mech, MechFX(physical_target),
01371                                                         MechFY(physical_target));
01372 
01373                         /* Check to see what sections are destroyed */
01374                         memset(is_section_destroyed, 0, sizeof(is_section_destroyed));
01375                         is_section_destroyed[0] = SectIsDestroyed(mech, RARM);
01376                         is_section_destroyed[1] = SectIsDestroyed(mech, LARM);
01377                         is_section_destroyed[2] = SectIsDestroyed(mech, RLEG);
01378                         is_section_destroyed[3] = SectIsDestroyed(mech, LLEG);
01379 
01380                         /* Check to see if the sections have a busy weapon */
01381                         memset(section_hasbusyweap, 0, sizeof(section_hasbusyweap));
01382                         section_hasbusyweap[0] = SectHasBusyWeap(mech, RARM);
01383                         section_hasbusyweap[1] = SectHasBusyWeap(mech, LARM);
01384                         section_hasbusyweap[2] = SectHasBusyWeap(mech, RLEG);
01385                         section_hasbusyweap[3] = SectHasBusyWeap(mech, LLEG);
01386 
01387                         /* Try weapon physical attacks */
01388 
01389                         /* Right Arm */
01390                         if(!is_section_destroyed[0] && !section_hasbusyweap[0] &&
01391                            !AnyLimbsRecycling(mech) && ((new_arc & FORWARDARC) ||
01392                                                                                         (new_arc & RSIDEARC)) &&
01393                            (elevation_diff == 0 || elevation_diff == -1)) {
01394 
01395                                 snprintf(buffer, LBUF_SIZE, "r %c%c",
01396                                                  MechID(target)[0], MechID(target)[1]);
01397 
01398                                 if(have_axe(mech, RARM))
01399                                         mech_axe(autopilot->mynum, mech, buffer);
01400                                 /* else if (have_mace(mech, RARM)) */
01402                                 else if(have_sword(mech, RARM))
01403                                         mech_sword(autopilot->mynum, mech, buffer);
01404 
01405                         }
01406 
01407                         /* Left Arm */
01408                         if(!is_section_destroyed[1] && !section_hasbusyweap[1] &&
01409                            !AnyLimbsRecycling(mech) && ((new_arc & FORWARDARC) ||
01410                                                                                         (new_arc & LSIDEARC)) &&
01411                            (elevation_diff == 0 || elevation_diff == -1)) {
01412 
01413                                 snprintf(buffer, LBUF_SIZE, "l %c%c",
01414                                                  MechID(target)[0], MechID(target)[1]);
01415 
01416                                 if(have_axe(mech, LARM))
01417                                         mech_axe(autopilot->mynum, mech, buffer);
01418                                 /* else if (have_mace(mech, RARM)) */
01420                                 else if(have_sword(mech, LARM))
01421                                         mech_sword(autopilot->mynum, mech, buffer);
01422 
01423                         }
01424 
01425                         /* Try and kick but only if we got two legs, one of them
01426                          * doesn't have a cycling weapon and the target is in the
01427                          * front arc */
01428                         if((!section_hasbusyweap[2] || !section_hasbusyweap[3]) &&
01429                            !is_section_destroyed[2] && !is_section_destroyed[3] &&
01430                            (what_arc & FORWARDARC) && !AnyLimbsRecycling(mech) &&
01431                            (elevation_diff == 0 || elevation_diff == 1)) {
01432 
01433                                 rleg_bth = 0;
01434                                 lleg_bth = 0;
01435 
01436                                 /* Check the RLEG for any crits or weaps cycling */
01437                                 if(!section_hasbusyweap[2]) {
01438                                         if(!OkayCritSectS(RLEG, 0, SHOULDER_OR_HIP))
01439                                                 rleg_bth += 3;
01440                                         if(!OkayCritSectS(RLEG, 1, UPPER_ACTUATOR))
01441                                                 rleg_bth++;
01442                                         if(!OkayCritSectS(RLEG, 2, LOWER_ACTUATOR))
01443                                                 rleg_bth++;
01444                                         if(!OkayCritSectS(RLEG, 3, HAND_OR_FOOT_ACTUATOR))
01445                                                 rleg_bth++;
01446                                 } else {
01447                                         rleg_bth = 99;
01448                                 }
01449 
01450                                 /* Check the LLEG for any crits or weaps cycling */
01451                                 if(!section_hasbusyweap[3]) {
01452                                         if(!OkayCritSectS(LLEG, 0, SHOULDER_OR_HIP))
01453                                                 lleg_bth += 3;
01454                                         if(!OkayCritSectS(LLEG, 1, UPPER_ACTUATOR))
01455                                                 lleg_bth++;
01456                                         if(!OkayCritSectS(LLEG, 2, LOWER_ACTUATOR))
01457                                                 lleg_bth++;
01458                                         if(!OkayCritSectS(LLEG, 3, HAND_OR_FOOT_ACTUATOR))
01459                                                 lleg_bth++;
01460                                 } else {
01461                                         rleg_bth = 99;
01462                                 }
01463 
01464                                 /* Now kick depending on which one would be better 
01465                                  * to kick with */
01466                                 if(rleg_bth <= lleg_bth) {
01467                                         snprintf(buffer, LBUF_SIZE, "r %c%c",
01468                                                          MechID(physical_target)[0],
01469                                                          MechID(physical_target)[1]);
01470                                 } else {
01471                                         snprintf(buffer, LBUF_SIZE, "l %c%c",
01472                                                          MechID(physical_target)[0],
01473                                                          MechID(physical_target)[1]);
01474                                 }
01475                                 mech_kick(autopilot->mynum, mech, buffer);
01476                         }
01477 
01478                         /* Finally try to punch */
01479                         if(((!is_section_destroyed[0] && !section_hasbusyweap[0]) ||
01480                                 (!is_section_destroyed[1] && !section_hasbusyweap[1]))
01481                            && !AnyLimbsRecycling(mech) &&
01482                            (elevation_diff == 0 || elevation_diff == -1)) {
01483 
01484                                 is_rarm_ready = 0;
01485                                 is_larm_ready = 0;
01486 
01487                                 if(!is_section_destroyed[0] &&
01488                                    !section_hasbusyweap[0] &&
01489                                    ((new_arc & FORWARDARC) || (new_arc & RSIDEARC))) {
01490 
01491                                         /* We can use the right arm */
01492                                         is_rarm_ready = 1;
01493                                 }
01494 
01495                                 if(!is_section_destroyed[1] &&
01496                                    !section_hasbusyweap[1] &&
01497                                    ((new_arc & FORWARDARC) || (new_arc & LSIDEARC))) {
01498 
01499                                         /* We can use the left arm */
01500                                         is_larm_ready = 1;
01501                                 }
01502 
01503                                 if(is_rarm_ready == 1 && is_larm_ready == 1) {
01504                                         snprintf(buffer, LBUF_SIZE, "b %c%c",
01505                                                          MechID(target)[0], MechID(target)[1]);
01506                                 } else if(is_rarm_ready == 1) {
01507                                         snprintf(buffer, LBUF_SIZE, "r %c%c",
01508                                                          MechID(target)[0], MechID(target)[1]);
01509                                 } else {
01510                                         snprintf(buffer, LBUF_SIZE, "l %c%c",
01511                                                          MechID(target)[0], MechID(target)[1]);
01512                                 }
01513 
01514                                 /* Now punch */
01515                                 mech_punch(autopilot->mynum, mech, buffer);
01516 
01517                         }
01518 
01519                 } else if((MechType(mech) == CLASS_MECH) &&
01520                                   (MechMove(mech) == MOVE_QUAD)) {
01521 
01522                         /* Quad Mech - Right now only supporting kicking front style for quad */
01523                         /* Remember, the RARM becomes the Front RLEG and the LARM becomes the
01524                          * Front LLEG */
01525 
01526                         /* Find direction of bad guy */
01527                         what_arc =
01528                                 InWeaponArc(mech, MechFX(physical_target),
01529                                                         MechFY(physical_target));
01530 
01531                         /* Check to see what sections are destroyed */
01532                         memset(is_section_destroyed, 0, sizeof(is_section_destroyed));
01533                         is_section_destroyed[0] = SectIsDestroyed(mech, RARM);
01534                         is_section_destroyed[1] = SectIsDestroyed(mech, LARM);
01535                         is_section_destroyed[2] = SectIsDestroyed(mech, RLEG);
01536                         is_section_destroyed[3] = SectIsDestroyed(mech, LLEG);
01537 
01538                         /* Check to see if the sections have a busy weapon */
01539                         memset(section_hasbusyweap, 0, sizeof(section_hasbusyweap));
01540                         section_hasbusyweap[0] = SectHasBusyWeap(mech, RARM);
01541                         section_hasbusyweap[1] = SectHasBusyWeap(mech, LARM);
01542                         //section_hasbusyweap[2] = SectHasBusyWeap(mech, RLEG);
01543                         //section_hasbusyweap[3] = SectHasBusyWeap(mech, LLEG);
01544 
01545                         /* Try and kick but only if we got two legs, one of them
01546                          * doesn't have a cycling weapon and the target is in the
01547                          * front arc */
01548                         if((!section_hasbusyweap[0] || !section_hasbusyweap[0]) &&
01549                            !is_section_destroyed[0] && !is_section_destroyed[1] &&
01550                            !is_section_destroyed[2] && !is_section_destroyed[3] &&
01551                            (what_arc & FORWARDARC) && !AnyLimbsRecycling(mech) &&
01552                            (elevation_diff == 0 || elevation_diff == 1)) {
01553 
01554                                 rleg_bth = 0;
01555                                 lleg_bth = 0;
01556 
01557                                 /* Check the Front Right Leg for any crits or weaps cycling */
01558                                 if(!section_hasbusyweap[0]) {
01559                                         if(!OkayCritSectS(RARM, 0, SHOULDER_OR_HIP))
01560                                                 rleg_bth += 3;
01561                                         if(!OkayCritSectS(RARM, 1, UPPER_ACTUATOR))
01562                                                 rleg_bth++;
01563                                         if(!OkayCritSectS(RARM, 2, LOWER_ACTUATOR))
01564                                                 rleg_bth++;
01565                                         if(!OkayCritSectS(RARM, 3, HAND_OR_FOOT_ACTUATOR))
01566                                                 rleg_bth++;
01567                                 } else {
01568                                         rleg_bth = 99;
01569                                 }
01570 
01571                                 /* Check the Front Left Leg for any crits or weaps cycling */
01572                                 if(!section_hasbusyweap[1]) {
01573                                         if(!OkayCritSectS(LARM, 0, SHOULDER_OR_HIP))
01574                                                 lleg_bth += 3;
01575                                         if(!OkayCritSectS(LARM, 1, UPPER_ACTUATOR))
01576                                                 lleg_bth++;
01577                                         if(!OkayCritSectS(LARM, 2, LOWER_ACTUATOR))
01578                                                 lleg_bth++;
01579                                         if(!OkayCritSectS(LARM, 3, HAND_OR_FOOT_ACTUATOR))
01580                                                 lleg_bth++;
01581                                 } else {
01582                                         rleg_bth = 99;
01583                                 }
01584 
01585                                 /* Now kick depending on which one would be better 
01586                                  * to kick with */
01587                                 if(rleg_bth <= lleg_bth) {
01588                                         snprintf(buffer, LBUF_SIZE, "r %c%c",
01589                                                          MechID(physical_target)[0],
01590                                                          MechID(physical_target)[1]);
01591                                 } else {
01592                                         snprintf(buffer, LBUF_SIZE, "l %c%c",
01593                                                          MechID(physical_target)[0],
01594                                                          MechID(physical_target)[1]);
01595                                 }
01596                                 mech_kick(autopilot->mynum, mech, buffer);
01597                         }
01598 
01599                 } else if(MechType(mech) == CLASS_BSUIT) {
01600 
01601                         /* Are we a BSuit */
01602 
01603                 } else {
01604 
01605                         /* Eventually add code here maybe for other physical attacks for
01606                          * tanks perhaps */
01607 
01608                 }
01609 
01610         }
01611 
01612         /* End of physical attack */
01613         /* Log It */
01614         print_autogun_log(autopilot, "Autogun - End Physical Attack Stage");
01615 
01616         /* Now we mow down our target */
01617 
01618         /* Get our current target */
01619         /* Check to make sure we didn't kill it with physical attack
01620          * or something */
01621         if(!(target = getMech(autopilot->target))) {
01622 
01623                 /* There were no valid targets so
01624                  * rerun autogun */
01625 
01626                 /* Reset the AI */
01627                 autopilot->target = -1;
01628                 autopilot->target_score = 0;
01629 
01630         /* Log It */
01631                 print_autogun_log(autopilot, "Autogun - No valid current target");
01632                 print_autogun_log(autopilot, "Autogun Event Finished");
01633                 return;
01634 
01635         } else if(Destroyed(target) || (target->mapindex != mech->mapindex)) {
01636 
01637                 /* Target is either dead or not on the map anymore */
01638                 autopilot->target = -1;
01639                 autopilot->target_score = 0;
01640 
01641         /* Log it */
01642                 print_autogun_log(autopilot, "Autogun - Target Gone");
01643                 print_autogun_log(autopilot, "Autogun Event Finished");
01644                 return;
01645         }
01646 
01647         /* Log It */
01648         print_autogun_log(autopilot, "Autogun - Starting Weapon Attack Phase");
01649 
01650         /* Get range from mech to current target */
01651         range = FindHexRange(MechFX(mech), MechFY(mech),
01652                                                  MechFX(target), MechFY(target));
01653 
01654         /* This probably unnecessary but since it doesn't
01655          * take much to calc range it should be ok for
01656          * testing for now */
01657         if((range >= (float) AUTO_GUN_MAX_RANGE) && !AssignedTarget(autopilot)) {
01658 
01659                 /* Target is to far - reset */
01660                 autopilot->target = -1;
01661                 autopilot->target_score = 0;
01662 
01663 
01664                 /* Log it */
01665                 print_autogun_log(autopilot, "Autogun - Target out of range");
01666                 print_autogun_log(autopilot, "Autogun Event Finished");
01667                 return;
01668         }
01669 
01670         /* Cycle through Guns while watching the heat */
01671         if((range < (float) AUTO_GUN_MAX_RANGE)
01672            && autopilot->profile[(int) range]) {
01673 
01674                 /* Ok we got weapons lets use them */
01675 
01676                 /* Reset heat counter to current heat */
01677                 accumulate_heat = MechWeapHeat(mech);
01678 
01679                 /* If the unit is moving need to account for the heat of that as well */
01680                 if((MechType(mech) == CLASS_MECH) && (fabs(MechSpeed(mech)) > 0.0)) {
01681 
01682                         maxspeed = MMaxSpeed(mech);
01683                         if(IsRunning(MechDesiredSpeed(mech), maxspeed))
01684                                 accumulate_heat += 2;
01685                         else
01686                                 accumulate_heat += 1;
01687                 }
01688 
01689                 /* Get first weapon */
01690                 temp_weapon_node =
01691                         (weapon_node *) rb_search(autopilot->profile[(int) range],
01692                                                                           SEARCH_LAST, NULL);
01693 
01694                 while (temp_weapon_node) {
01695 
01696                         /* Check to see if the weapon even works */
01697                         if(WeaponIsNonfunctional(mech, temp_weapon_node->section,
01698                                                                          temp_weapon_node->critical,
01699                                                                          GetWeaponCrits(mech,
01700                                                                                                         Weapon2I
01701                                                                                                         (temp_weapon_node->
01702                                                                                                          weapon_db_number))) >
01703                            0) {
01704 
01705                                 /* Weapon Doesn't work so go to next one */
01706                                 temp_weapon_node =
01707                                         (weapon_node *) rb_search(autopilot->profile[(int) range],
01708                                                                                           SEARCH_PREV,
01709                                                                                           &temp_weapon_node->
01710                                                                                           range_scores[(int) range]);
01711 
01712                                 continue;
01713                         }
01714 
01715                         /* Check to see if its cycling */
01716                         if(WpnIsRecycling
01717                            (mech, temp_weapon_node->section,
01718                                 temp_weapon_node->critical)) {
01719 
01720                                 /* Go to the next one */
01721                                 temp_weapon_node =
01722                                         (weapon_node *) rb_search(autopilot->profile[(int) range],
01723                                                                                           SEARCH_PREV,
01724                                                                                           &temp_weapon_node->
01725                                                                                           range_scores[(int) range]);
01726 
01727                                 continue;
01728                         }
01729 
01730                         if(IsAMS(temp_weapon_node->weapon_db_number)) {
01731 
01732                                 /* Ok its an AMS so go to next weapon */
01733                                 temp_weapon_node =
01734                                         (weapon_node *) rb_search(autopilot->profile[(int) range],
01735                                                                                           SEARCH_PREV,
01736                                                                                           &temp_weapon_node->
01737                                                                                           range_scores[(int) range]);
01738                                 continue;
01739                         }
01740 
01741                         /* Check heat levels, since the heat isn't updated untill we're done
01742                          * we have to manage the heat ourselves */
01744                         if((MechType(mech) == CLASS_MECH) && (((float) accumulate_heat +
01745                                                                                                    (float)
01746                                                                                                    MechWeapons
01747                                                                                                    [temp_weapon_node->
01748                                                                                                         weapon_db_number].heat -
01749                                                                                                    (float)
01750                                                                                                    MechMinusHeat(mech)) >
01751                                                                                                   AUTO_GUN_MAX_HEAT)) {
01752 
01753                                 /* Would make ourselves to hot to fire this gun */
01754                                 temp_weapon_node =
01755                                         (weapon_node *) rb_search(autopilot->profile[(int) range],
01756                                                                                           SEARCH_PREV,
01757                                                                                           &temp_weapon_node->
01758                                                                                           range_scores[(int) range]);
01759 
01760                                 continue;
01761                         }
01762 
01763                         /* Ok passed the checks now setup the arcs and see if we can fire it */
01764 
01765                         /* Ok the rest depends on what type of unit we driving */
01766                         if((MechType(mech) == CLASS_MECH) &&
01767                            (MechMove(mech) == MOVE_BIPED)) {
01768 
01769                                 /* Center ourself and get target arc */
01770                                 MechStatus(mech) &= ~(TORSO_RIGHT | TORSO_LEFT);
01771                                 if(MechSpecials(mech) & FLIPABLE_ARMS) {
01772 
01773                                         /* Center the arms if need be */
01774                                         MechStatus(mech) &= ~(FLIPPED_ARMS);
01775                                 }
01776 
01777                                 /* Get Target Arc */
01778                                 what_arc = InWeaponArc(mech, MechFX(target), MechFY(target));
01779 
01780                                 /* Now go through the various arcs and see if we
01781                                  * need to flip arm or rotorso or something */
01782                                 if(what_arc & REARARC) {
01783 
01784                                         if(temp_weapon_node->section == LARM ||
01785                                            temp_weapon_node->section == RARM) {
01786 
01787                                                 /* First see if we can flip arms */
01788                                                 if(MechSpecials(mech) & FLIPABLE_ARMS) {
01789 
01790                                                         /* Flip the arms */
01791                                                         MechStatus(mech) |= FLIPPED_ARMS;
01792 
01793                                                 } else {
01794 
01795                                                         /* Now see if we can rotatorso */
01796 
01797                                                         /* Find out if it would be better to
01798                                                          * rotate left or right */
01799                                                         relative_bearing = MechFacing(mech) -
01800                                                                 FindBearing(MechFX(mech), MechFY(mech),
01801                                                                                         MechFX(target), MechFY(target));
01802 
01803                                                         if(relative_bearing > 120
01804                                                            && relative_bearing < 180
01805                                                            && temp_weapon_node->section == RARM) {
01806 
01807                                                                 /* Rotate Right */
01808                                                                 MechStatus(mech) |= TORSO_RIGHT;
01809 
01810                                                         } else if(relative_bearing > 180
01811                                                                           && relative_bearing < 240
01812                                                                           && temp_weapon_node->section == LARM) {
01813 
01814                                                                 /* Rotate Left */
01815                                                                 MechStatus(mech) |= TORSO_LEFT;
01816 
01817                                                         } else {
01818 
01819                                                                 /* Can't do anything so go to next weapon */
01820                                                                 temp_weapon_node =
01821                                                                         (weapon_node *) rb_search(autopilot->
01822                                                                                                                           profile[(int)
01823                                                                                                                                           range],
01824                                                                                                                           SEARCH_PREV,
01825                                                                                                                           &temp_weapon_node->
01826                                                                                                                           range_scores[(int) range]);
01827 
01828                                                                 continue;
01829 
01830                                                         }
01831 
01832                                                 }
01833 
01834                                         } else
01835                                                 if(!
01836                                                    (GetPartFireMode
01837                                                         (mech, temp_weapon_node->section,
01838                                                          temp_weapon_node->critical) & REAR_MOUNT)) {
01839 
01840                                                 /* Weapon is forward torso or leg mounted weapon
01841                                                  * so no way to shoot with */
01842                                                 temp_weapon_node =
01843                                                         (weapon_node *) rb_search(autopilot->
01844                                                                                                           profile[(int) range],
01845                                                                                                           SEARCH_PREV,
01846                                                                                                           &temp_weapon_node->
01847                                                                                                           range_scores[(int)
01848                                                                                                                                    range]);
01849 
01850                                                 continue;
01851 
01852                                         }
01853 
01854                                         /* ELSE: Weapon is rear mounted so don't need to 
01855                                          * do anything */
01856 
01857                                 } else if(what_arc & LSIDEARC) {
01858 
01859                                         if(temp_weapon_node->section == RLEG ||
01860                                            temp_weapon_node->section == LLEG) {
01861 
01862                                                 /* No way can we hit him with leg mounted
01863                                                  * weapons so lets go to next one */
01864                                                 temp_weapon_node =
01865                                                         (weapon_node *) rb_search(autopilot->
01866                                                                                                           profile[(int) range],
01867                                                                                                           SEARCH_PREV,
01868                                                                                                           &temp_weapon_node->
01869                                                                                                           range_scores[(int)
01870                                                                                                                                    range]);
01871 
01872                                                 continue;
01873 
01874                                         }
01875 
01876                                         /* Rotate torso left */
01877                                         MechStatus(mech) |= TORSO_LEFT;
01878 
01879                                 } else if(what_arc & RSIDEARC) {
01880 
01881                                         if(temp_weapon_node->section == RLEG ||
01882                                            temp_weapon_node->section == LLEG) {
01883 
01884                                                 /* No way can we hit him with leg mounted
01885                                                  * weapons so lets go to next one */
01886                                                 temp_weapon_node =
01887                                                         (weapon_node *) rb_search(autopilot->
01888                                                                                                           profile[(int) range],
01889                                                                                                           SEARCH_PREV,
01890                                                                                                           &temp_weapon_node->
01891                                                                                                           range_scores[(int)
01892                                                                                                                                    range]);
01893 
01894                                                 continue;
01895 
01896                                         }
01897 
01898                                         /* Rotate torso right */
01899                                         MechStatus(mech) |= TORSO_RIGHT;
01900 
01901                                 } else {
01902 
01903                                         if(GetPartFireMode(mech, temp_weapon_node->section,
01904                                                                            temp_weapon_node->
01905                                                                            critical) & REAR_MOUNT) {
01906 
01907                                                 /* No way can we hit the guy with a rear
01908                                                  * gun so lets go to next one */
01909                                                 temp_weapon_node =
01910                                                         (weapon_node *) rb_search(autopilot->
01911                                                                                                           profile[(int) range],
01912                                                                                                           SEARCH_PREV,
01913                                                                                                           &temp_weapon_node->
01914                                                                                                           range_scores[(int)
01915                                                                                                                                    range]);
01916 
01917                                                 continue;
01918 
01919                                         }
01920 
01921                                 }
01922 
01923                         } else if((MechType(mech) == CLASS_MECH) &&
01924                                           (MechMove(mech) == MOVE_QUAD)) {
01925 
01926                                 /* Get Target Arc */
01927                                 what_arc = InWeaponArc(mech, MechFX(target), MechFY(target));
01928 
01929                                 if(what_arc & REARARC) {
01930 
01931                                         if(!(GetPartFireMode(mech, temp_weapon_node->section,
01932                                                                                  temp_weapon_node->
01933                                                                                  critical) & REAR_MOUNT)) {
01934 
01935                                                 /* Weapon is not rear mounted so skip it and
01936                                                  * go to the next weapon */
01937                                                 temp_weapon_node =
01938                                                         (weapon_node *) rb_search(autopilot->
01939                                                                                                           profile[(int) range],
01940                                                                                                           SEARCH_PREV,
01941                                                                                                           &temp_weapon_node->
01942                                                                                                           range_scores[(int)
01943                                                                                                                                    range]);
01944 
01945                                                 continue;
01946 
01947                                         }
01948 
01949                                 } else if(what_arc & FORWARDARC) {
01950 
01951                                         if(GetPartFireMode(mech, temp_weapon_node->section,
01952                                                                            temp_weapon_node->
01953                                                                            critical) & REAR_MOUNT) {
01954 
01955                                                 /* Weapon is rear mounted so skip it and
01956                                                  * go to the next weapon */
01957                                                 temp_weapon_node =
01958                                                         (weapon_node *) rb_search(autopilot->
01959                                                                                                           profile[(int) range],
01960                                                                                                           SEARCH_PREV,
01961                                                                                                           &temp_weapon_node->
01962                                                                                                           range_scores[(int)
01963                                                                                                                                    range]);
01964 
01965                                                 continue;
01966 
01967                                         }
01968 
01969                                 } else {
01970 
01971                                         /* The attacker is in a zone we can't possibly
01972                                          * shoot into, so just go to next weapon */
01973                                         temp_weapon_node =
01974                                                 (weapon_node *) rb_search(autopilot->
01975                                                                                                   profile[(int) range],
01976                                                                                                   SEARCH_PREV,
01977                                                                                                   &temp_weapon_node->
01978                                                                                                   range_scores[(int) range]);
01979 
01980                                         continue;
01981 
01982                                 }
01983 
01984                         } else if((MechType(mech) == CLASS_VEH_GROUND) ||
01985                                           (MechType(mech) == CLASS_VEH_NAVAL)) {
01986 
01987                                 /* Get Target Arc */
01988                                 what_arc = InWeaponArc(mech, MechFX(target), MechFY(target));
01989 
01990                                 /* Check if turret exists and weapon is there */
01991                                 if(GetSectInt(mech, TURRET)
01992                                    && temp_weapon_node->section == TURRET) {
01993 
01994                                         /* Rotate Turret and nail the guy */
01995                                         if(!(MechTankCritStatus(mech) & TURRET_JAMMED) &&
01996                                            !(MechTankCritStatus(mech) & TURRET_LOCKED) &&
01997                                            (AcceptableDegree
01998                                                 (MechTurretFacing(mech) + MechFacing(mech)) !=
01999                                                 FindBearing(MechFX(mech), MechFY(mech),
02000                                                                         MechFX(target), MechFY(target)))) {
02001 
02002                                                 snprintf(buffer, LBUF_SIZE, "%d",
02003                                                                  FindBearing(MechFX(mech), MechFY(mech),
02004                                                                                          MechFX(target), MechFY(target)));
02005                                                 mech_turret(autopilot->mynum, mech, buffer);
02006                                         }
02007 
02008                                 } else {
02009 
02010                                         /* Check if in arc of weapon */
02011                                         if(!IsInWeaponArc(mech, MechFX(target), MechFY(target),
02012                                                                           temp_weapon_node->section,
02013                                                                           temp_weapon_node->critical)) {
02014 
02015                                                 /* Not in the arc so lets go to the next weapon */
02016                                                 temp_weapon_node =
02017                                                         (weapon_node *) rb_search(autopilot->
02018                                                                                                           profile[(int) range],
02019                                                                                                           SEARCH_PREV,
02020                                                                                                           &temp_weapon_node->
02021                                                                                                           range_scores[(int)
02022                                                                                                                                    range]);
02023 
02024                                                 continue;
02025 
02026                                         }
02027 
02028                                 }
02029 
02030                         } else {
02031 
02032                                 /* We're either an aero, ds, bsuit, mechwarrior or vtol
02033                                  *
02034                                  * Still need to add code for them */
02035 
02036                         }
02037 
02038                         /* Done moving around, fire the weapon */
02039                         snprintf(buffer, LBUF_SIZE, "%d",
02040                                          temp_weapon_node->weapon_number);
02041                         mech_fireweapon(autopilot->mynum, mech, buffer);
02042 
02043                         /* Log It */
02044                         print_autogun_log(autopilot, "Autogun - Fired Weapon #%d "
02045                                                           "at target #%d",
02046                                                           temp_weapon_node->weapon_number,
02047                                                           autopilot->target);
02048 
02049                         /* Ok check to see if weapon was fired if so account for the
02050                          * heat */
02051                         if(WpnIsRecycling
02052                            (mech, temp_weapon_node->section,
02053                                 temp_weapon_node->critical)) {
02054                                 accumulate_heat +=
02055                                         MechWeapons[temp_weapon_node->weapon_db_number].heat;
02056                         }
02057 
02058                         /* Ok go to the next weapon */
02059                         temp_weapon_node =
02060                                 (weapon_node *) rb_search(autopilot->profile[(int) range],
02061                                                                                   SEARCH_PREV,
02062                                                                                   &temp_weapon_node->
02063                                                                                   range_scores[(int) range]);
02064 
02065                 }                                               /* End of cycling through weapons */
02066 
02067         }
02068 
02069         /* Log It */
02070         print_autogun_log(autopilot, "Autogun - End Weapon Attack Phase");
02071 
02072         /* Setup chasetarg 
02073          * 
02074          * Since chasetarget uses follow but we don't want follow getting
02075          * messed up if its following a normal target.  We define our own
02076          * follow (basicly its follow but with the command name chasetarget */
02077 
02078         /* Get the first command, if its chasetarget or there is no command
02079          * check to see if we need to update chasetarget, otherwise means
02080          * AI is doing something else important so don't try to chase
02081          * anything */
02082 
02083         if(ChasingTarget(autopilot)) {
02084 
02085                 /* Reset the flag */
02086                 do_chasetarget = 0;
02087 
02088                 /* Get the first command's enum and check it */
02089                 switch (auto_get_command_enum(autopilot, 1)) {
02090 
02091                 case GOAL_CHASETARGET:
02092 
02093                         /* Ok its our command so we can change it */
02094                         do_chasetarget = 1;
02095                         break;
02096 
02097                 case -1:
02098 
02099                         /* No current commands so we can do our chasetarget */
02100                         do_chasetarget = 1;
02101                         break;
02102 
02103                         /* ALl the other stuff we don't want to mess with */
02104                 default:
02105 
02106                         /* Reset the chase values */
02107                         autopilot->chase_target = -10;
02108                         autopilot->chasetarg_update_tick =
02109                                 AUTOPILOT_CHASETARG_UPDATE_TICK;
02110                         autopilot->follow_update_tick = AUTOPILOT_FOLLOW_UPDATE_TICK;
02111                         break;
02112 
02113                 }
02114 
02115                 /* Check the flag */
02116                 if(do_chasetarget) {
02117 
02118                         /* Ok lets chase the guy */
02119 
02120                         /* First see if we need to update */
02121                         if((autopilot->target != autopilot->chase_target) ||
02122                            (autopilot->chasetarg_update_tick >=
02123                                 AUTOPILOT_CHASETARG_UPDATE_TICK)) {
02124 
02125                                 /* Tell the AI to follow its target */
02126                                 /* Basicly remove all the commands, add in
02127                                  * autogun and follow and engage */
02128 
02129                                 /* Let the AI know we chasing this guy */
02130                                 autopilot->chase_target = autopilot->target;
02131 
02132                                 /* Reset the tickers */
02133                                 autopilot->chasetarg_update_tick = 0;
02134                                 autopilot->follow_update_tick = AUTOPILOT_FOLLOW_UPDATE_TICK;
02135 
02136                                 /* Reset the AI */
02137                                 auto_disengage(autopilot->mynum, autopilot, "");
02138                                 auto_delcommand(autopilot->mynum, autopilot, "-1");
02139 
02140                                 /* Add in autogun and follow and engage */
02141                                 if(AssignedTarget(autopilot) && autopilot->target != -1) {
02142                                         snprintf(buffer, LBUF_SIZE, "autogun target %d",
02143                                                          autopilot->target);
02144                                 } else {
02145                                         snprintf(buffer, LBUF_SIZE, "autogun on");
02146                                 }
02147 
02148                                 auto_addcommand(autopilot->mynum, autopilot, buffer);
02149                                 snprintf(buffer, LBUF_SIZE, "chasetarget %d",
02150                                                  autopilot->target);
02151                                 auto_addcommand(autopilot->mynum, autopilot, buffer);
02152                                 auto_engage(autopilot->mynum, autopilot, "");
02153 
02154                                 /* Log it */
02155                                 print_autogun_log(autopilot, "Autogun Event Finished");
02156 
02157                                 return;
02158 
02159                         } else {
02160 
02161                                 /* Update the ticker */
02162                                 autopilot->chasetarg_update_tick++;
02163 
02164                                 /* Check to see if we need to turn to face the guy by
02165                                  * generating our target hex and seeing if we are in that
02166                                  * hex then face the bad guy */
02167                                 if((target = getMech(autopilot->target)) &&
02168                                    (!Destroyed(target)
02169                                         && (target->mapindex == mech->mapindex))) {
02170 
02171                                         /* Generate the target hex */
02174                                         FindXY(MechFX(target), MechFY(target),
02175                                                    MechFacing(target) + autopilot->ofsx,
02176                                                    autopilot->ofsy, &fx, &fy);
02177 
02178                                         RealCoordToMapCoord(&x, &y, fx, fy);
02179 
02180                                         /* Make sure the hex is sane */
02181                                         if(x < 0 || y < 0 || x >= map->map_width
02182                                            || y >= map->map_height) {
02183 
02184                                                 /* Bad Target Hex */
02185 
02186                                                 /* Reset the hex to the Target's current hex */
02187                                                 x = MechX(target);
02188                                                 y = MechY(target);
02189 
02190                                         }
02191 
02192                                         /* Are we in the target hex and is the target not moving */
02193                                         if((MechX(mech) == x) && (MechY(mech) == y)
02194                                            && (MechSpeed(target) < 0.5)) {
02195 
02196                                                 /* Get his bearing and face him */
02197                                                 MapCoordToRealCoord(x, y, &fx, &fy);
02198 
02199                                                 /* If we're not facing him, turn towards him */
02200                                                 if(MechDesiredFacing(mech) !=
02201                                                    FindBearing(MechFX(mech), MechFY(mech), fx, fy)) {
02202 
02203                                                         snprintf(buffer, LBUF_SIZE, "%d",
02204                                                                          FindBearing(MechFX(mech), MechFY(mech),
02205                                                                                                  fx, fy));
02206                                                         mech_heading(autopilot->mynum, mech, buffer);
02207 
02208                                                 }
02209                                                 /* Turn towards him */
02210                                         }
02211                                         /* Is he moving and are we in target hex */
02212                                 }
02213                                 /* Do we need to turn towards him */
02214                         }                                       /* Do we need to update */
02215 
02216                 }
02217                 /* Do we run chasetarget */
02218         }
02219 
02220         /* Is chasetarget on */
02221         /* Make sure multiple instances of autogun aren't running */
02222 
02223         /* Log it */
02224         print_autogun_log(autopilot, "Autogun Event Finished");
02225 
02226         /* The End */
02227 }

void auto_sensor_event ( AUTO autopilot  ) 

Todo:
{Improve this so it knows more about the terrain}

Definition at line 152 of file autopilot_autogun.c.

References AUTOPILOT_LSENS, BEAGLE_DESTROYED, BEAGLE_PROBE_TECH, BLOODHOUND_DESTROYED, BLOODHOUND_PROBE_TECH, BOUNDED(), statedata::db_top, Destroyed, DoStopGun, dprintk, FaMechRange, AUTO::flags, FlyingT, getMap(), getMech(), HeatFactor(), IsAuto(), IsMech, Landed, MECH::mapindex, MAP::maplight, MAP::mapvis, MarkForLOSUpdate(), mech_notify(), MECHALL, MechCritStatus, MechSensor, MechSpecials, MechSpecials2, MechTarget, MechTons, mudstate, AUTO::mymech, AUTO::mymechnum, MECH::mynum, AUTO::mynum, PrefVisSens(), SearchLightInRange(), SENSOR_BAP, SENSOR_BHAP, SENSOR_EM, SENSOR_IR, SENSOR_RA, SENSOR_VIS, Started, and Zombify.

Referenced by auto_heartbeat().

00153 {
00154         MECH *target = NULL;
00155         MAP *map;
00156         char buf[16];
00157         int wanted_s[2];
00158         int rvis;
00159         int slite, prefvis;
00160         float trng;
00161         int set = 0;
00162 
00163         if((autopilot->mymechnum > mudstate.db_top) || (autopilot->mymechnum < 0 )) {
00164                 dprintk("mymechnum is bad!");
00165                 return;
00166         }
00167         if((autopilot->mynum > mudstate.db_top) || (autopilot->mynum < 0 )) {
00168                 dprintk("mynum is bad!");
00169                 return;
00170         }
00171                          
00172         
00173         MECH *mech = (MECH *) autopilot->mymech;
00174         
00175         /* Make sure its a MECH Xcode Object and the AI is
00176          * an AUTOPILOT Xcode Object */
00177         /* Basic checks */
00178         if(!mech) {
00179                 dprintk("mech is bad!");
00180                 return;
00181         }
00182         if(!autopilot) {
00183                 dprintk("ai is bad!");
00184                 return;
00185         }
00186                         
00187         if(!IsMech(mech->mynum) || !IsAuto(autopilot->mynum))
00188                 return;
00189 
00190         /* Mech is dead so stop trying to shoot things */
00191         if(Destroyed(mech)) {
00192                 DoStopGun(autopilot);
00193                 return;
00194         }
00195 
00196         /* Mech isn't started */
00197         if(!Started(mech)) {
00198                 Zombify(autopilot);
00199                 return;
00200         }
00201 
00202         /* The mech is using user defined sensors so don't try
00203          * and change them */
00204         if(autopilot->flags & AUTOPILOT_LSENS)
00205                 return;
00206 
00207         /* Get the map */
00208         if(!(map = getMap(mech->mapindex))) {
00209 
00210                 /* Bad Map */
00211                 Zombify(autopilot);
00212                 return;
00213         }
00214         
00215         /* Get the target if there is one */
00216         if(MechTarget(mech) > 0)
00217                 target = getMech(MechTarget(mech));
00218 
00219         /* Checks to see if there is slite, and what types of vis
00220          * and which visual sensor (V or L) to use */
00221         slite = (map->mapvis != 2 ? SearchLightInRange(mech, map) : 0);
00222         rvis = (map->maplight ? (map->mapvis) : (map->mapvis * (slite ? 1 : 3)));
00223         prefvis = PrefVisSens(mech, map, slite, target);
00224 
00225         /* Is there a target */
00226         if(target) {
00227 
00228                 /* Range to target */
00229                 trng = FaMechRange(mech, target);
00230 
00231                 /* Actually not gonna bother with this */
00232                 /* If the target is running hot and is close switch to IR */
00233                 if(!set && HeatFactor(target) > 35 && (int) trng < 15) {
00234                         //wanted_s[0] = SENSOR_IR;
00235                         //wanted_s[1] = ((MechTons(target) >= 60) ? SENSOR_EM : prefvis);
00236                         //set++;
00237                 }
00238 
00239                 /* If the target is BIG and close enough, use EM */
00240                 if(!set && MechTons(target) >= 60 && (int) trng <= 20) {
00241                         wanted_s[0] = SENSOR_EM;
00242                         wanted_s[1] = SENSOR_IR;
00243                         set++;
00244                 }
00245 
00246                 /* If the target is flying switch to Radar */
00247                 if(!set && !Landed(target) && FlyingT(target)) {
00248                         wanted_s[0] = SENSOR_RA;
00249                         wanted_s[1] = prefvis;
00250                         set++;
00251                 }
00252 
00253                 /* If the target is really close and the unit has BAP, use it */
00254                 if(!set && (int) trng <= 4 && MechSpecials(mech) & BEAGLE_PROBE_TECH
00255                    && !(MechCritStatus(mech) & BEAGLE_DESTROYED)) {
00256                         wanted_s[0] = SENSOR_BAP;
00257                         wanted_s[1] = SENSOR_BAP;
00258                         set++;
00259                 }
00260 
00261                 /* If the target is really close and the unit has Bloodhound, use it */
00262                 if(!set && (int) trng <= 8
00263                    && MechSpecials2(mech) & BLOODHOUND_PROBE_TECH
00264                    && !(MechCritStatus(mech) & BLOODHOUND_DESTROYED)) {
00265                         wanted_s[0] = SENSOR_BHAP;
00266                         wanted_s[1] = SENSOR_BHAP;
00267                         set++;
00268                 }
00269 
00270                 /* Didn't stop at any of the others so use selected visual sensors */
00271                 if(!set) {
00272                         wanted_s[0] = prefvis;
00273                         wanted_s[1] = (rvis <= 15 ? SENSOR_EM : prefvis);
00274                         set++;
00275                 }
00276 
00277         }
00278 
00279         /* Ok no target and no sensors set yet so lets go for defaults */
00280         if(!set) {
00281                 if(rvis <= 15) {
00282                         /* Vis is less then or equal to 15 so go to E I for longer range */
00283                         wanted_s[0] = SENSOR_EM;
00284                         wanted_s[1] = SENSOR_IR;
00285                 } else {
00286                         /* Ok lets go with default visual sensors */
00287                         wanted_s[0] = prefvis;
00288                         wanted_s[1] = prefvis;
00289                 }
00290         }
00291 
00292         /* Check to make sure valid sensors are selected and then set them */
00293         if(wanted_s[0] >= SENSOR_VIS && wanted_s[0] <= SENSOR_BHAP &&
00294            wanted_s[1] >= SENSOR_VIS && wanted_s[1] <= SENSOR_BHAP &&
00295            (MechSensor(mech)[0] != wanted_s[0]
00296                 || MechSensor(mech)[1] != wanted_s[1])) {
00297 
00298                 wanted_s[0] = BOUNDED(SENSOR_VIS, wanted_s[0], SENSOR_BHAP);
00299                 wanted_s[1] = BOUNDED(SENSOR_VIS, wanted_s[1], SENSOR_BHAP);
00300 
00301                 MechSensor(mech)[0] = wanted_s[0];
00302                 MechSensor(mech)[1] = wanted_s[1];
00303                 mech_notify(mech, MECHALL, "As your sensors change, your lock clears.");
00304                 MechTarget(mech) = -1;
00305                 MarkForLOSUpdate(mech);
00306         }
00307 }

static int auto_targets_callback ( void *  key,
void *  data,
int  depth,
void *  arg 
) [static]

Definition at line 413 of file autopilot_autogun.c.

References auto_destroy_target_node().

Referenced by auto_gun_event().

00414 {
00415 
00416         target_node *temp;
00417 
00418         temp = (target_node *) data;
00419         auto_destroy_target_node(temp);
00420 
00421         return 1;
00422 
00423 }

void auto_update_profile_event ( AUTO autopilot  ) 

Definition at line 542 of file autopilot_autogun.c.

References AUTO_PROFILE_MAX_SIZE, statedata::db_top, Destroyed, dprintk, IsAuto(), IsMech, MAX_WEAPS_SECTION, mudstate, AUTO::mymech, AUTO::mymechnum, AUTO::mynum, MECH::mynum, print_autogun_log, AUTO::profile, rb_destroy(), and StopGun.

Referenced by auto_heartbeat().

00542                                                 {
00543         MECH *mech = (MECH *) autopilot->mymech;
00544 
00545         weapon_node *temp_weapon_node;
00546         dllist_node *temp_dllist_node;
00547 
00548         int section;
00549         int weapon_count_section;
00550         unsigned char weaparray[MAX_WEAPS_SECTION];
00551         unsigned char weapdata[MAX_WEAPS_SECTION];
00552         int critical[MAX_WEAPS_SECTION];
00553 
00554         int range;
00555 
00556         int weapon_count;
00557         int weapon_number;
00558 
00559         /* Basic checks */
00560         /* some accounting checks. try to prevent some race stuff */
00561 
00562         if((autopilot->mymechnum > mudstate.db_top) || (autopilot->mymechnum < 1 )) {
00563                 /* most commonly, the mech is a bad memory space.
00564                  * lets not try to access it
00565                  */
00566                 dprintk("ap mymechnum is bad");
00567                 StopGun(autopilot);
00568                 return;
00569         }
00570 
00571         if(!mech) {
00572                 dprintk("mech is bad!");
00573                 return;
00574         }
00575         if(!autopilot) {
00576                 dprintk("ai is bad!");
00577                 return;
00578         }
00579         if(!IsMech(mech->mynum) || !IsAuto(autopilot->mynum))
00580                 return;
00581 
00582         /* Ok our mech is dead we're done */
00583         if(Destroyed(mech)) {
00584                 return;
00585         }
00586     
00587         /* Log Message */
00588         print_autogun_log(autopilot, "Profiling Unit #%d", mech->mynum);
00589 
00590         /* Destroy the arrays first, don't worry about the weap
00591          * structures because we can clear them with the ddlist
00592          * weaplist */
00593 
00594         /* Zero the array of rbtree stuff */
00595         for(range = 0; range < AUTO_PROFILE_MAX_SIZE; range++) {
00596 
00597                 if(autopilot->profile[range]) {
00598 
00599                         /* Destroy rbtree */
00600                         rb_destroy(autopilot->profile[range]);
00601                 }
00602                 autopilot->profile[range] = NULL;
00603         }
00604 
00605         /* Check to see if the weaplist exists */
00606         if(autopilot->weaplist != NULL) {
00607 
00608                 /* Destroy the list */
00609                 auto_destroy_weaplist(autopilot);
00610         }
00611 
00612         /* List doesn't exist so lets build it */
00613         autopilot->weaplist = dllist_create_list();
00614 
00615         /* Reset the AI's max range value for its mech */
00616         autopilot->mech_max_range = 0;
00617 
00618         /* Set our counter */
00619         weapon_count = -1;
00620 
00621         /* Now loop through the weapons building a list */
00622         for(section = 0; section < NUM_SECTIONS; section++) {
00623 
00624                 /* Find all the weapons for a given section */
00625                 weapon_count_section = FindWeapons(mech, section,
00626                                                                                    weaparray, weapdata, critical);
00627 
00628                 /* No weapons here */
00629                 if(weapon_count_section <= 0)
00630                         continue;
00631 
00632                 /* loop through the possible weapons */
00633                 for(weapon_number = 0; weapon_number < weapon_count_section;
00634                         weapon_number++) {
00635 
00636                         /* Count it even if its not a valid weapon like AMS */
00637                         /* This is so when we go to fire the weapon we know
00638                          * which one to send in the command */
00639                         weapon_count++;
00640 
00641                         if(IsAMS(weaparray[weapon_number]))
00642                                 continue;
00643 
00644                         /* Does it work? */
00645                         if(WeaponIsNonfunctional(mech, section, critical[weapon_number],
00646                                                                          GetWeaponCrits(mech,
00647                                                                                                         Weapon2I(weaparray
00648                                                                                                                          [weapon_number])))
00649                            > 0)
00650                                 continue;
00651 
00652                         /* Ok made it this far, lets add it to our list */
00653                         temp_weapon_node = auto_create_weapon_node(weapon_count,
00654                                                                                                            weaparray
00655                                                                                                            [weapon_number],
00656                                                                                                            section,
00657                                                                                                            critical
00658                                                                                                            [weapon_number]);
00659 
00660                         temp_dllist_node = dllist_create_node(temp_weapon_node);
00661                         dllist_insert_end(autopilot->weaplist, temp_dllist_node);
00662 
00663                         /* Check the max range */
00664                         if(autopilot->mech_max_range <
00665                            MechWeapons[weaparray[weapon_number]].longrange) {
00666                                 autopilot->mech_max_range =
00667                                         MechWeapons[weaparray[weapon_number]].longrange;
00668                         }
00669 
00670                 }
00671 
00672         }
00673 
00674         /* Now build the profile array, basicly loop through 
00675          * all the current avail weapons, get its max range,
00676          * then loop through ranges and for each range add it
00677          * to profile */
00678 
00679         /* Our counter */
00680         weapon_number = 1;
00681 
00682         while (weapon_number <= dllist_size(autopilot->weaplist)) {
00683 
00684                 /* Get the weapon */
00685                 temp_weapon_node =
00686                         (weapon_node *) dllist_get_node(autopilot->weaplist,
00687                                                                                         weapon_number);
00688 
00689                 for(range = 0; range <
00690                         MechWeapons[temp_weapon_node->weapon_db_number].longrange;
00691                         range++) {
00692 
00693                         /* Out side the the range of AI's profile system */
00694                         if(range >= AUTO_PROFILE_MAX_SIZE) {
00695                                 break;
00696                         }
00697 
00698                         /* Score the weapon */
00699                         temp_weapon_node->range_scores[range] =
00700                                 auto_calc_weapon_score(temp_weapon_node->weapon_db_number,
00701                                                                            range);
00702 
00703                         /* If rbtree for this range doesn't exist, create it */
00704                         if(autopilot->profile[range] == NULL) {
00705                                 autopilot->profile[range] =
00706                                         rb_init(&auto_generic_compare, NULL);
00707                         }
00708 
00709                         /* Check to see if the score exists in the tree
00710                          * if so alter it slightly so we don't have
00711                          * overlaping keys */
00712                         while (1) {
00713 
00714                                 if(rb_exists(autopilot->profile[range],
00715                                                          &temp_weapon_node->range_scores[range])) {
00716                                         temp_weapon_node->range_scores[range]++;
00717                                 } else {
00718                                         break;
00719                                 }
00720 
00721                         }
00722 
00723                         /* Add it to tree */
00724                         rb_insert(autopilot->profile[range],
00725                                           &temp_weapon_node->range_scores[range],
00726                                           temp_weapon_node);
00727 
00728                 }
00729 
00730                 /* Increment */
00731                 weapon_number++;
00732 
00733         }
00734 
00735         /* Log Message */
00736         print_autogun_log(autopilot, "Finished Profiling");
00737 
00738 }

int PrefVisSens ( MECH mech,
MAP map,
int  slite,
MECH target 
)

Definition at line 124 of file autopilot_autogun.c.

References MAP::maplight, MechCritStatus, MechStatus, SENSOR_LA, SENSOR_VIS, SLITE_LIT, and SLITE_ON.

Referenced by auto_sensor_event().

00125 {
00126 
00127         /* No map or mech so use default till we get put somewhere */
00128         if(!mech || !map)
00129                 return SENSOR_VIS;
00130 
00131         /* Ok the AI is lit or using slite so use V */
00132         if(MechStatus(mech) & SLITE_ON || MechCritStatus(mech) & SLITE_LIT)
00133                 return SENSOR_VIS;
00134 
00135         /* The target is lit so use V */
00136         if(target && MechCritStatus(target) & SLITE_LIT)
00137                 return SENSOR_VIS;
00138 
00139         /* Ok if its night/dawn/dusk and theres no slite use L */
00140         if(map->maplight <= 1 && slite != 3 && slite != 5)
00141                 return SENSOR_LA;
00142 
00143         /* Default sensor */
00144         return SENSOR_VIS;
00145 }

int SearchLightInRange ( MECH mech,
MAP map 
)

Todo:
{ Add more code to the sensor system so the AI can be more aware of its terrain }

Definition at line 54 of file autopilot_autogun.c.

References FaMechRange, FindObjectsData(), MAP::first_free, FORWARDARC, InWeaponArc(), LITE_RANGE, MechCritStatus, MechFX, MechFY, MECHLOSFLAG_BLOCK, MAP::mechsOnMap, MechSpecials, MechStatus, SLITE_DEST, SLITE_ON, and SLITE_TECH.

Referenced by auto_sensor_event().

00055 {
00056 
00057         MECH *target;
00058         int i;
00059 
00060         /* Make sure theres a valid mech or map */
00061         if(!mech || !map)
00062                 return 0;
00063 
00064         /* Loop through all the units on the map */
00065         for(i = 0; i < map->first_free; i++) {
00066 
00067                 /* No units on the map */
00068                 if(!(target = FindObjectsData(map->mechsOnMap[i])))
00069                         continue;
00070 
00071                 /* The unit doesn't have slite on */
00072                 if(!(MechSpecials(target) & SLITE_TECH)
00073                    || MechCritStatus(mech) & SLITE_DEST)
00074                         continue;
00075 
00076                 /* Is the mech close enough to be affected by the slite */
00077                 if(FaMechRange(target, mech) < LITE_RANGE) {
00078 
00079                         /* Returning true, but let's differentiate also between being in-arc. */
00080                         if((MechStatus(target) & SLITE_ON) &&
00081                            InWeaponArc(target, MechFX(mech), MechFY(mech)) & FORWARDARC) {
00082 
00083                                 /* Make sure its in los */
00084                                 if(!
00085                                    (map->
00086                                         LOSinfo[target->mapnumber][mech->
00087                                                                                            mapnumber] &
00088                                         MECHLOSFLAG_BLOCK))
00089 
00090                                         /* Slite on and, arced, and LoS to you */
00091                                         return 3;
00092                                 else
00093                                         /* Slite on, arced, but LoS blocked */
00094                                         return 4;
00095 
00096                         } else if(!MechStatus(target) & SLITE_ON &&
00097                                           InWeaponArc(target, MechFX(mech),
00098                                                                   MechFY(mech)) & FORWARDARC) {
00099 
00100                                 if(!
00101                                    (map->
00102                                         LOSinfo[target->mapnumber][mech->
00103                                                                                            mapnumber] &
00104                                         MECHLOSFLAG_BLOCK))
00105 
00106                                         /* Slite off, arced, and LoS to you */
00107                                         return 5;
00108 
00109                                 else
00110                                         /* Slite off, arced, and LoS blocked */
00111                                         return 6;
00112                         }
00113 
00114                         /* Slite is in range of you, but apparently not arced on you. 
00115                          * Return tells wether on or off */
00116                         return (MechStatus(target) & SLITE_ON ? 1 : 2);
00117                 }
00118 
00119         }
00120         return 0;
00121 }


Generated on Mon May 28 04:25:32 2007 for BattletechMUX by  doxygen 1.4.7