00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include <math.h>
00022
00023 #include "mech.h"
00024 #include "autopilot.h"
00025 #include "p.autopilot_command.h"
00026 #include "p.mech.utils.h"
00027 #include "p.map.obj.h"
00028 #include "spath.h"
00029 #include "p.mech.combat.h"
00030 #include "p.glue.hcode.h"
00031
00032 #define SCORE_MOD 100
00033 #define SAFE_SCORE SCORE_MOD * 1000
00034 #define MIN_SAFE 8
00035 #define NORM_SAFE 32
00036 #define MAX_SIM_PATHS 40
00037
00038 typedef struct {
00039 int e, t;
00040 float s, ds;
00041 float fx, fy;
00042 short x, y, lx, ly;
00043 int h;
00044 int dh;
00045 } LOC;
00046
00047 enum {
00048 SP_OPT_NORM, SP_OPT_FASTER, SP_OPT_SLOWER, SP_OPT_C
00049 };
00050 int sp_opt[SP_OPT_C] = { 0, 1, -1 };
00051
00052 #define MNORM_COUNT 37
00053
00054 int move_norm_opt[MNORM_COUNT][2] = {
00055 {0, SP_OPT_FASTER},
00056 {0, SP_OPT_NORM},
00057 {0, SP_OPT_SLOWER},
00058 {-1, SP_OPT_NORM},
00059 {1, SP_OPT_NORM},
00060 {-2, SP_OPT_NORM},
00061 {2, SP_OPT_NORM},
00062 {-3, SP_OPT_NORM},
00063 {3, SP_OPT_NORM},
00064 {-5, SP_OPT_NORM},
00065 {5, SP_OPT_NORM},
00066 {-10, SP_OPT_NORM},
00067 {10, SP_OPT_NORM},
00068 {-15, SP_OPT_NORM},
00069 {15, SP_OPT_NORM},
00070 {-20, SP_OPT_NORM},
00071 {20, SP_OPT_NORM},
00072 {-30, SP_OPT_NORM},
00073 {30, SP_OPT_NORM},
00074 {-40, SP_OPT_NORM},
00075 {40, SP_OPT_NORM},
00076 {-60, SP_OPT_NORM},
00077 {60, SP_OPT_NORM},
00078 {-60, SP_OPT_SLOWER},
00079 {60, SP_OPT_SLOWER},
00080 {-60, SP_OPT_FASTER},
00081 {60, SP_OPT_FASTER},
00082 {-80, SP_OPT_NORM},
00083 {80, SP_OPT_NORM},
00084 {-120, SP_OPT_NORM},
00085 {120, SP_OPT_NORM},
00086 {-160, SP_OPT_NORM},
00087 {160, SP_OPT_NORM},
00088 {-160, SP_OPT_SLOWER},
00089 {160, SP_OPT_SLOWER},
00090 {-160, SP_OPT_FASTER},
00091 {160, SP_OPT_FASTER}
00092 };
00093
00094 #define CFAST_COUNT 9
00095
00096
00097 int combat_fast_opt[CFAST_COUNT][2] = {
00098 {0, SP_OPT_FASTER},
00099 {0, SP_OPT_NORM},
00100 {0, SP_OPT_SLOWER},
00101 {-10, SP_OPT_NORM},
00102 {10, SP_OPT_NORM},
00103 {-30, SP_OPT_NORM},
00104 {30, SP_OPT_NORM},
00105 {-60, SP_OPT_NORM},
00106 {60, SP_OPT_NORM}
00107 };
00108
00109 void sendAIM(AUTO * a, MECH * m, char *msg)
00110 {
00111 auto_reply(m, msg);
00112 SendAI(msg);
00113 }
00114
00115 char *AI_Info(MECH * m, AUTO * a)
00116 {
00117 static char buf[MBUF_SIZE];
00118
00119 sprintf(buf, "Unit#%d on #%d [A#%d]:", m->mynum, m->mapindex, a->mynum);
00120 return buf;
00121 }
00122
00123 extern float terrain_speed(MECH * mech, float tempspeed, float maxspeed,
00124 int terrain, int elev);
00125
00126 static int ai_crash(MAP * map, MECH * m, LOC * l)
00127 {
00128 float newx = 0.0, newy = 0.0;
00129 float tempspeed, maxspeed, acc;
00130 int offset;
00131 int normangle;
00132 int mw_mod = 1;
00133 int ch = 0;
00134
00135 if(!map)
00136 return 0;
00137
00138 maxspeed = MMaxSpeed(m);
00139
00140
00141 if(l->h != l->dh && !(MechCritStatus(m) & GYRO_DESTROYED)) {
00142 ch = 1;
00143 if(is_aero(m))
00144 maxspeed = maxspeed * ACCEL_MOD;
00145 normangle = l->h - l->dh;
00146 if(MechType(m) == CLASS_MW || MechType(m) == CLASS_BSUIT)
00147 mw_mod = 60;
00148
00149 if(fabs(l->s) < 1.0)
00150 offset = 3 * maxspeed * MP_PER_KPH * mw_mod;
00151 else {
00152 offset = 2 * maxspeed * MP_PER_KPH * mw_mod;
00153 if((abs(normangle) > offset) && (l->s > (maxspeed * 2 / 3)))
00154 offset -= offset / 2 * (3.0 * l->s / maxspeed - 2.0);
00155 }
00156 offset = offset * MOVE_MOD;
00157 if(normangle < 0)
00158 normangle += 360;
00159 if(IsDS(m) && offset >= 10)
00160 offset = 10;
00161 if(normangle > 180) {
00162 l->h += offset;
00163 if(l->h >= 360)
00164 l->h -= 360;
00165 normangle += offset;
00166 if(normangle >= 360)
00167 l->h = l->dh;
00168 } else {
00169 l->h -= offset;
00170 if(l->h < 0)
00171 l->h += 360;
00172 normangle -= offset;
00173 if(normangle < 0)
00174 l->h = l->dh;
00175 }
00176
00177 }
00178
00179
00180
00181 tempspeed = l->ds;
00182 if(MechType(m) != CLASS_MW && MechMove(m) != MOVE_VTOL &&
00183 (MechMove(m) != MOVE_FLY || Landed(m)))
00184 tempspeed = terrain_speed(m, tempspeed, maxspeed, l->t, l->e);
00185 if(ch) {
00186 if(mudconf.btech_slowdown == 2) {
00187 int dif = MechFacing(m) - MechDesiredFacing(m);
00188
00189 if(dif < 0)
00190 dif = -dif;
00191 if(dif > 180)
00192 dif = 360 - dif;
00193 if(dif) {
00194 dif = (dif - 1) / 30 + 2;
00195 tempspeed = tempspeed * (10 - dif) / 10;
00196 }
00197 } else if(mudconf.btech_slowdown == 1) {
00198 if(l->h != l->dh)
00199 tempspeed = tempspeed * 2.0 / 3.0;
00200 else
00201 tempspeed = tempspeed * 3.0 / 4.0;
00202 }
00203 }
00204 if(MechIsQuad(m) && MechLateral(m))
00205 tempspeed -= MP1;
00206 if(tempspeed <= 0.0) {
00207 tempspeed = 0.0;
00208 }
00209 if(l->ds < 0.)
00210 tempspeed = -tempspeed;
00211 if(tempspeed != l->s) {
00212 if(MechIsQuad(m))
00213 acc = maxspeed / 10.;
00214 else
00215 acc = maxspeed / 20.;
00216 if(tempspeed < l->s) {
00217
00218 l->s -= acc;
00219 if(tempspeed > l->s)
00220 l->s = tempspeed;
00221 } else {
00222
00223 l->s += acc;
00224 if(tempspeed < l->s)
00225 l->s = tempspeed;
00226 }
00227 }
00228
00229
00230
00231
00232 FindComponents(l->s * MOVE_MOD, l->h, &newx, &newy);
00233 l->fx += newx;
00234 l->fy += newy;
00235 l->lx = l->x;
00236 l->ly = l->y;
00237 RealCoordToMapCoord(&l->x, &l->y, l->fx, l->fy);
00238
00239 if(BOUNDED(0, l->x, map->map_width - 1) != l->x)
00240 return 1;
00241 if(BOUNDED(0, l->y, map->map_height - 1) != l->y)
00242 return 1;
00243 if(l->lx != l->x || l->ly != l->y) {
00244 int oz = l->e;
00245
00246
00247
00248
00249 switch (GetRTerrain(map, l->x, l->y)) {
00250 case HEAVY_FOREST:
00251 if(MechType(m) != CLASS_MECH)
00252 return 1;
00253 break;
00254 case WATER:
00255 if(MechMove(m) == MOVE_TRACK || MechMove(m) == MOVE_WHEEL)
00256 return 1;
00257 else {
00258
00259 if(MechType(m) == CLASS_MECH) {
00260 int t = Elevation(map, l->x, l->y);
00261
00262 if(t < 0) {
00263 if(t == -1) {
00264
00265 #define Floodable(loc) (!GetSectArmor(m,loc) || (!GetSectRArmor(m,loc) && GetSectORArmor(m,loc)))
00266 #define FloodCheck(loc) if (GetSectInt(m,loc)) if (Floodable(loc)) return 1;
00267 FloodCheck(LLEG);
00268 FloodCheck(RLEG);
00269 if(MechIsQuad(m)) {
00270 FloodCheck(LARM);
00271 FloodCheck(RARM);
00272 }
00273 } else {
00274 int i;
00275
00276 for(i = 0; i < NUM_SECTIONS; i++)
00277 FloodCheck(i);
00278 }
00279 }
00280 }
00281 }
00282 break;
00283 case HIGHWATER:
00284 return 1;
00285 break;
00286 }
00287 l->e = Elevation(map, l->x, l->y);
00288 if(MechMove(m) == MOVE_HOVER)
00289 l->e = MAX(0, l->e);
00290 l->t = GetRTerrain(map, l->x, l->y);
00291 if(MechType(m) == CLASS_MECH)
00292 if((l->e - oz) > 2 || (oz - l->e) > 2)
00293 return 1;
00294
00295 if(MechType(m) == CLASS_VEH_GROUND)
00296 if((l->e - oz) > 1 || (oz - l->e) > 1)
00297 return 1;
00298
00299 }
00300 return 0;
00301 }
00302
00303 static void LOCInit(LOC * l, MECH * m)
00304 {
00305 l->fx = MechFX(m);
00306 l->fy = MechFY(m);
00307 l->e = MechElevation(m);
00308 l->h = MechFacing(m);
00309 l->dh = MechDesiredFacing(m);
00310 l->s = MechSpeed(m);
00311 l->t = MechRTerrain(m);
00312 l->ds = MechDesiredSpeed(m);
00313 l->x = MechX(m);
00314 l->y = MechY(m);
00315 l->lx = MechX(m);
00316 l->ly = MechY(m);
00317 }
00318
00319 static LOC enemy_l[MAX_MECHS_PER_MAP];
00320 static MECH *enemy_m[MAX_MECHS_PER_MAP];
00321 static int enemy_o[MAX_MECHS_PER_MAP];
00322 static int enemy_i[MAX_MECHS_PER_MAP];
00323 static int enemy_c = 0;
00324
00325 static LOC friend_l[MAX_MECHS_PER_MAP];
00326 static MECH *friend_m[MAX_MECHS_PER_MAP];
00327 static int friend_o[MAX_MECHS_PER_MAP];
00328 static int friend_i[MAX_MECHS_PER_MAP];
00329 static int friend_c = 0;
00330
00331 int getEnemies(MECH * mech, MAP * map, int reset)
00332 {
00333 MECH *tempMech;
00334 int i;
00335
00336 if(reset) {
00337 for(i = 0; i < enemy_c; i++) {
00338 LOCInit(&enemy_l[i], enemy_m[i]);
00339 enemy_o[i] = 0;
00340 }
00341 return 0;
00342 }
00343 enemy_c = 0;
00344 for(i = 0; i < map->first_free; i++) {
00345 tempMech = FindObjectsData(map->mechsOnMap[i]);
00346 if(!tempMech)
00347 continue;
00348 if(Destroyed(tempMech))
00349 continue;
00350 if(MechStatus(tempMech) & COMBAT_SAFE)
00351 continue;
00352 if(MechTeam(tempMech) == MechTeam(mech))
00353 continue;
00354 if(FlMechRange(map, mech, tempMech) > 50.0)
00355 continue;
00356
00357 LOCInit(&enemy_l[enemy_c], tempMech);
00358 enemy_m[enemy_c] = tempMech;
00359 enemy_i[enemy_c++] = i;
00360 }
00361 return enemy_c;
00362 }
00363
00364 int getFriends(MECH * mech, MAP * map, int reset)
00365 {
00366 MECH *tempMech;
00367 int i;
00368
00369 if(reset) {
00370 for(i = 0; i < friend_c; i++) {
00371 LOCInit(&friend_l[i], friend_m[i]);
00372 friend_o[i] = 0;
00373 }
00374 return 0;
00375 }
00376 friend_c = 0;
00377 for(i = 0; i < map->first_free; i++) {
00378 tempMech = FindObjectsData(map->mechsOnMap[i]);
00379 if(!tempMech)
00380 continue;
00381 if(Destroyed(tempMech))
00382 continue;
00383 if(MechTeam(tempMech) != MechTeam(mech))
00384 continue;
00385 if(MechType(tempMech) != CLASS_MECH)
00386 continue;
00387 if(FlMechRange(map, mech, tempMech) > 50.0)
00388 continue;
00389 LOCInit(&friend_l[friend_c], tempMech);
00390 friend_m[friend_c] = tempMech;
00391 friend_i[friend_c++] = i;
00392 }
00393 return friend_c;
00394 }
00395
00396
00397
00398
00399
00400
00401
00402 #define MAGIC_NUM -123456
00403
00404 #define U1(a,b) if (a < b || a == MAGIC_NUM) a = b
00405 #define U2(a,b) if (a > b || a == MAGIC_NUM) a = b
00406 #define FU(a,b,c,s) ((b) == (c) ? 0 : (s) * ((a) - (b)) / ((c) - (b)))
00407
00408 void ai_path_score(MECH * m, MAP * map, AUTO * a, int opts[][2], int num_o,
00409 int gotenemy, float dx, float dy, float delx, float dely,
00410 int *rl, int *bd, int *bscore)
00411 {
00412 int i, j, k, l, bearing;
00413 int sd, sc;
00414 LOC lo[MAX_SIM_PATHS];
00415 int dan[MAX_SIM_PATHS], tdan[MAX_SIM_PATHS], msc[MAX_SIM_PATHS],
00416 bsc[MAX_SIM_PATHS];
00417 int out[MAX_SIM_PATHS], stack[MAX_SIM_PATHS], br[MAX_SIM_PATHS];
00418
00419 for(i = 0; i < num_o; i++) {
00420 msc[i] = 0;
00421 bsc[i] = 0;
00422 dan[i] = 0;
00423 tdan[i] = 0;
00424 out[i] = 0;
00425 stack[i] = 0;
00426 br[i] = 9999;
00427 LOCInit(&lo[i], m);
00428 lo[i].dh = AcceptableDegree(lo[i].dh + opts[i][0]);
00429 sd = sp_opt[opts[i][1]];
00430 if(sd) {
00431 if(sd < 0) {
00432 lo[i].ds = lo[i].ds * 2.0 / 3.0;
00433 } else if(sd == 1) {
00434 float ms = MMaxSpeed(m);
00435
00436 lo[i].ds = (lo[i].ds < MP1 ? MP1 : lo[i].ds) * 4.0 / 3.0;
00437 if(lo[i].ds > ms)
00438 lo[i].ds = ms;
00439 } else {
00440 float ms = MMaxSpeed(m);
00441
00442 lo[i].ds = ms;
00443 }
00444 }
00445 }
00446 for(i = 0; i < NORM_SAFE; i++) {
00447 dx += delx;
00448 dy += dely;
00449 for(k = 0; k < num_o; k++) {
00450 if(out[k])
00451 continue;
00452 if(ai_crash(map, m, &lo[k])) {
00453 out[k] = i + 1;
00454 continue;
00455 }
00456
00457 if((l = FindXYRange(lo[k].fx, lo[k].fy, dx, dy)) < br[k])
00458 br[k] = l;
00459
00460
00461 msc[k] += 4 * (2 * (50 - br[k]) + (100 - l));
00462
00463
00464 if(lo[k].h != lo[k].dh)
00465 msc[k] -= 1;
00466
00467
00468 if(lo[k].x != lo[k].lx || lo[k].y != lo[k].ly) {
00469 if(lo[k].t == WATER)
00470 msc[k] -= 5;
00471 msc[k] += 10;
00472 }
00473
00474 if(opts[k][1] != SP_OPT_FASTER && MMaxSpeed(m) > 0.1) {
00475 sc = BOUNDED(0, 100 * lo[k].ds / MMaxSpeed(m), 100);
00476 msc[k] -= (100 - sc) / 30;
00477 }
00478 }
00479 if(MechType(m) == CLASS_MECH) {
00480
00481 for(j = 0; j < friend_c; j++) {
00482 if(friend_o[j])
00483 continue;
00484 if(ai_crash(map, friend_m[j], &friend_l[j]))
00485 friend_o[j] = 1;
00486 }
00487 for(k = 0; k < num_o; k++) {
00488 int sc = 0;
00489
00490 if(out[k] || stack[k])
00491 continue;
00492
00493 for(j = 0; j < friend_c; j++)
00494 if(!friend_o[j])
00495 if(lo[k].x == friend_l[j].x &&
00496 lo[k].y == friend_l[j].y)
00497 sc++;
00498 if(sc > 1) {
00499 int osc = sc;
00500
00501 for(j = 0; j < friend_c; j++)
00502 if(!friend_o[j])
00503 if(lo[k].x == friend_l[j].x &&
00504 lo[k].y == friend_l[j].y)
00505 if((lo[k].lx != lo[k].x ||
00506 lo[k].ly != lo[k].y) ||
00507 (friend_l[j].lx != friend_l[j].x ||
00508 friend_l[j].ly != friend_l[j].y))
00509 osc--;
00510 if(osc != sc)
00511 stack[k] = i + 1;
00512 }
00513 if(gotenemy)
00514 tdan[k] = 0;
00515 }
00516 }
00517 if(gotenemy) {
00518
00519 for(j = 0; j < enemy_c; j++) {
00520 if(enemy_o[j])
00521 continue;
00522 if(ai_crash(map, enemy_m[j], &enemy_l[j]))
00523 enemy_o[j] = 1;
00524 for(k = 0; k < num_o; k++) {
00525 if(out[k])
00526 continue;
00527 if((l = MyHexDist(lo[k].x, lo[k].y, enemy_l[j].x,
00528 enemy_l[j].y, 0)) >= 100)
00529 continue;
00530 switch (a->auto_cmode) {
00531 case 0:
00532 if(l > a->auto_cdist)
00533 bsc[k] += 5 * a->auto_cdist + l - a->auto_cdist;
00534 else
00535 bsc[k] += 5 * l;
00536 break;
00537 case 1:
00538 if(l < a->auto_cdist)
00539 bsc[k] -= 10 * (a->auto_cdist - l);
00540 else
00541 bsc[k] -= 2 * (l - a->auto_cdist);
00542 break;
00543 case 2:
00544 if(l < a->auto_cdist)
00545 bsc[k] -= 2 * (a->auto_cdist - l);
00546 else
00547 bsc[k] -= 10 * (l - a->auto_cdist);
00548 }
00549 if(l > 28)
00550 continue;
00551
00552 tdan[k] += (40 - MIN(40, l));
00553
00554 if(MechType(m) == CLASS_MECH) {
00555 bearing =
00556 FindBearing(lo[k].fx, lo[k].fy, enemy_l[j].fx,
00557 enemy_l[j].fy);
00558 bearing = lo[k].h - bearing;
00559 if(bearing < 0)
00560 bearing += 360;
00561 if(bearing >= 90 && bearing <= 270) {
00562
00563 tdan[k] += 5 * (29 - MIN(29, l));
00564 if(bearing >= 120 && bearing <= 240) {
00565
00566 tdan[k] += 20 * (29 - MIN(29, l));
00567 }
00568 }
00569 } else if(MechType(m) == CLASS_VEH_GROUND) {
00570 bearing =
00571 FindBearing(lo[k].fx, lo[k].fy, enemy_l[j].fx,
00572 enemy_l[j].fy);
00573 bearing = lo[k].h - bearing;
00574 if(bearing < 0)
00575 bearing += 360;
00576 if(bearing >= 45 && bearing <= 315) {
00577 if(bearing >= 135 && bearing <= 225) {
00578
00579 tdan[k] +=
00580 10 * (29 - MIN(29,
00581 l)) * (100 -
00582 100 *
00583 GetSectArmor(m,
00584 BSIDE)
00585 / MAX(1,
00586 GetSectOArmor
00587 (m,
00588 BSIDE))) /
00589 100;
00590 } else if(bearing < 135) {
00591
00592 tdan[k] +=
00593 7 * (29 - MIN(29,
00594 l)) * (100 -
00595 100 * GetSectArmor(m,
00596 RSIDE)
00597 / MAX(1,
00598 GetSectOArmor
00599 (m,
00600 RSIDE))) /
00601 100;
00602 } else {
00603 tdan[k] +=
00604 7 * (29 - MIN(29,
00605 l)) * (100 -
00606 100 * GetSectArmor(m,
00607 LSIDE)
00608 / MAX(1,
00609 GetSectOArmor
00610 (m,
00611 LSIDE))) /
00612 100;
00613 }
00614 } else
00615 tdan[k] +=
00616 5 * (29 - MIN(29,
00617 l)) * (100 -
00618 100 * GetSectArmor(m,
00619 FSIDE)
00620 / MAX(1,
00621 GetSectOArmor(m,
00622 FSIDE)))
00623 / 100;
00624 }
00625 }
00626 for(k = 0; k < num_o; k++) {
00627 if(out[k])
00628 continue;
00629
00630 l = FindXYRange(lo[k].fx, lo[k].fy, dx, dy);
00631 if(gotenemy && (delx != 0.0 || dely != 0.0))
00632 tdan[k] += MIN(100, l * l);
00633 if(enemy_c)
00634 tdan[k] = tdan[k] / enemy_c;
00635
00636 if(lo[k].s <= MP2)
00637 tdan[k] += 400;
00638 else if(lo[k].s <= MP4)
00639 tdan[k] += 300;
00640 else if(lo[k].s <= MP6)
00641 tdan[k] += 200;
00642 else if(lo[k].s <= MP9)
00643 tdan[k] += 100;
00644 dan[k] += tdan[k] * (NORM_SAFE - i) / (NORM_SAFE / 2);
00645 }
00646 }
00647 }
00648 }
00649 for(i = 0; i < num_o; i++) {
00650 U2(a->w_msc, msc[i]);
00651 U1(a->b_msc, msc[i]);
00652 if(gotenemy) {
00653 U2(a->w_bsc, bsc[i]);
00654 U1(a->b_bsc, bsc[i]);
00655 U2(a->w_dan, dan[i]);
00656 U1(a->b_dan, dan[i]);
00657 }
00658 }
00659
00660 *bscore = 0;
00661 *bd = -1;
00662
00663 for(i = 0; i < num_o; i++) {
00664 if(!out[i])
00665 out[i] = NORM_SAFE + 1;
00666 if(!stack[i])
00667 stack[i] = out[i];
00668 sc = (out[i] - (out[i] - stack[i]) / 2) * SAFE_SCORE + FU(msc[i],
00669 a->w_msc,
00670 a->b_msc,
00671 SCORE_MOD *
00672 a->
00673 auto_goweight);
00674 if(gotenemy)
00675 sc +=
00676 FU(bsc[i], a->w_bsc, a->b_bsc,
00677 SCORE_MOD * a->auto_fweight) - FU(dan[i], a->w_dan,
00678 a->b_dan,
00679 SCORE_MOD *
00680 (a->auto_fweight +
00681 a->auto_goweight));
00682 if(sc > *bscore
00683 || (*bd >= 0 && sc == *bscore
00684 && sp_opt[opts[i][1]] > sp_opt[opts[*bd][1]])) {
00685 *bscore = sc;
00686 *bd = i;
00687 *rl = out[i] - 1;
00688 }
00689 }
00690 }
00691
00692 int ai_max_speed(MECH * m, AUTO * a)
00693 {
00694 float ms;
00695
00696 if(MechDesiredSpeed(m) != (ms = MMaxSpeed(m)))
00697 return 0;
00698 return 1;
00699 }
00700
00701 int ai_opponents(AUTO * a, MECH * m)
00702 {
00703 if(a->auto_nervous) {
00704 a->auto_nervous--;
00705 return 1;
00706 }
00707 if(MechNumSeen(m))
00708 a->auto_nervous = 30;
00709 return MechNumSeen(m);
00710 }
00711
00712 void ai_run_speed(MECH * mech, AUTO * a)
00713 {
00714
00715 char buf[128];
00716
00717 if(!ai_max_speed(mech, a)) {
00718 strcpy(buf, "run");
00719 mech_speed(a->mynum, mech, buf);
00720 }
00721 }
00722
00723 void ai_stop(MECH * mech, AUTO * a)
00724 {
00725 char buf[128];
00726
00727 if(MechDesiredSpeed(mech) > 0.1) {
00728 strcpy(buf, "stop");
00729 mech_speed(a->mynum, mech, buf);
00730 }
00731 }
00732
00733 #if 0
00734 void ai_set_speed(MECH * mech, AUTO * a, int s)
00735 {
00736 float ms;
00737 char buf[SBUF_SIZE];
00738
00739 if(s >= 99) {
00740 ai_run_speed(mech, a);
00741 return;
00742 }
00743 if(!s) {
00744 ai_stop(mech, a);
00745 return;
00746 }
00747
00748 ms = MMaxSpeed(mech);
00749 ms = ms * s / 100.0;
00750 if(MechDesiredSpeed(mech) != ms) {
00751 sprintf(buf, "%f", ms);
00752 mech_speed(a->mynum, mech, buf);
00753 }
00754 }
00755 #endif
00756
00757 void ai_set_speed(MECH * mech, AUTO * a, float spd)
00758 {
00759 char buf[SBUF_SIZE];
00760 float newspeed;
00761
00762 if(!mech || !a)
00763 return;
00764
00765 newspeed = FBOUNDED(0, spd, ((MMaxSpeed(mech) * a->speed) / 100.0));
00766
00767 if(MechDesiredSpeed(mech) != newspeed) {
00768 sprintf(buf, "%f", newspeed);
00769 mech_speed(a->mynum, mech, buf);
00770 }
00771 }
00772
00773 void ai_set_heading(MECH * mech, AUTO * a, int dir)
00774 {
00775 char buf[128];
00776
00777 if(dir == MechDesiredFacing(mech))
00778 return;
00779 sprintf(buf, "%d", dir);
00780 mech_heading(a->mynum, mech, buf);
00781 }
00782
00783 #define UNREF(a,b,mod) if (a != MAGIC_NUM && b != MAGIC_NUM) { int c = a, d = b; a = (c * (mod - 1) + d) / mod; b = (c + d * (mod - 1)) / mod; }
00784
00785 void ai_adjust_move(AUTO * a, MECH * m, char *text, int hmod, int smod,
00786 int b_score)
00787 {
00788 float ms;
00789
00790 ai_set_heading(m, a, MechDesiredFacing(m) + hmod);
00791 switch (smod) {
00792 default:
00793 SendAI("%s state: %s (hmod:%d) sc:%d", AI_Info(m, a), text, hmod,
00794 b_score);
00795 break;
00796 case SP_OPT_FASTER:
00797 SendAI("%s state: %s+accelerating (hmod:%d) sc:%d", AI_Info(m, a),
00798 text, hmod, b_score);
00799 ms = MMaxSpeed(m);
00800 ai_set_speed(m, a,
00801 (float) ((MechDesiredSpeed(m) <
00802 MP1 ? MP1 : MechDesiredSpeed(m)) * 4.0 / 3.0));
00803 break;
00804 case SP_OPT_SLOWER:
00805 SendAI("%s state: %s+decelerating (hmod:%d) sc:%d", AI_Info(m, a),
00806 text, hmod, b_score);
00807 ms = MMaxSpeed(m);
00808 ai_set_speed(m, a, (int) (MechDesiredSpeed(m) * 2.0 / 3.0));
00809 break;
00810 }
00811 }
00812
00813 int ai_check_path(MECH * m, AUTO * a, float dx, float dy, float delx,
00814 float dely)
00815 {
00816 int o;
00817 int b_len, bl, b, b_score;
00818 MAP *map = getMap(m->mapindex);
00819
00820 o = ai_opponents(a, m);
00821 if(a->last_upd > mudstate.now || (mudstate.now - a->last_upd) > AUTO_GOET) {
00822 if((muxevent_tick - a->last_upd) > AUTO_GOTT) {
00823 a->b_msc = MAGIC_NUM;
00824 a->w_msc = MAGIC_NUM;
00825 a->b_bsc = MAGIC_NUM;
00826 a->w_bsc = MAGIC_NUM;
00827 a->b_dan = MAGIC_NUM;
00828 a->b_dan = (40 + 20 * 29 + 100) * 30;
00829 } else {
00830
00831 UNREF(a->w_msc, a->b_msc, 3);
00832 UNREF(a->w_bsc, a->b_bsc, 5);
00833 UNREF(a->w_dan, a->b_dan, 8);
00834 a->b_dan = MAX(a->b_dan, (40 + 20 * 29 + 100) * 30);
00835 }
00836 a->last_upd = mudstate.now;
00837 }
00838
00839 if(MechType(m) == CLASS_MECH)
00840 getFriends(m, map, 0);
00841 if(o) {
00842 getEnemies(m, map, 0);
00843 if(!((muxevent_tick / AUTOPILOT_GOTO_TICK) % 4)) {
00844
00845 ai_path_score(m, map, a, move_norm_opt, MNORM_COUNT, 1, dx, dy,
00846 delx, dely, &bl, &b, &b_score);
00847 b_len = b_score / SAFE_SCORE;
00848 if(b_len >= MIN_SAFE)
00849 ai_adjust_move(a, m, "combat(/twitchy)",
00850 move_norm_opt[b][0], move_norm_opt[b][1],
00851 b_score);
00852 } else {
00853 ai_path_score(m, map, a, combat_fast_opt, CFAST_COUNT, 1, dx,
00854 dy, delx, dely, &bl, &b, &b_score);
00855 b_len = b_score / SAFE_SCORE;
00856 if(b_len >= MIN_SAFE)
00857 ai_adjust_move(a, m, "[f]combat(/twitchy)",
00858 combat_fast_opt[b][0], combat_fast_opt[b][1],
00859 b_score);
00860 }
00861 return 1;
00862 }
00863 if(!((muxevent_tick / AUTOPILOT_GOTO_TICK) % 4)) {
00864
00865 ai_path_score(m, map, a, move_norm_opt, MNORM_COUNT, 0, dx, dy,
00866 delx, dely, &bl, &b, &b_score);
00867 b_len = b_score / SAFE_SCORE;
00868 if(b_len >= MIN_SAFE)
00869 ai_adjust_move(a, m, "moving", move_norm_opt[b][0],
00870 move_norm_opt[b][1], b_score);
00871 } else {
00872 ai_path_score(m, map, a, combat_fast_opt, CFAST_COUNT, 0, dx, dy,
00873 delx, dely, &bl, &b, &b_score);
00874 b_len = b_score / SAFE_SCORE;
00875 if(b_len >= MIN_SAFE)
00876 ai_adjust_move(a, m, "[f]moving", combat_fast_opt[b][0],
00877 combat_fast_opt[b][1], b_score);
00878 }
00879
00880 if(b_len >= MIN_SAFE)
00881 return 1;
00882
00883
00884 ai_stop(m, a);
00885 SendAI("%s state: panic", AI_Info(m, a));
00886 sendAIM(a, m, "PANIC! Unable to comply with order.");
00887 return 0;
00888 }
00889
00890 void ai_init(AUTO * a, MECH * m)
00891 {
00892
00893
00894 a->auto_cmode = 1;
00895 a->auto_cdist = 2;
00896 a->auto_nervous = 0;
00897 a->auto_goweight = 44;
00898 a->auto_fweight = 55;
00899 a->speed = 100;
00900 a->flags = 0;
00901 a->target = -1;
00902 }
00903
00904 static MECH *target_mech;
00905
00906 int artillery_round_flight_time(float fx, float fy, float tx, float ty);
00907
00908 static int mech_snipe_func(MECH * mech, dbref player, int index, int high)
00909 {
00910
00911 int now = 0, crashed = 0;
00912 int flt_time;
00913 LOC t;
00914 MAP *map = getMap(mech->mapindex);
00915
00916 LOCInit(&t, target_mech);
00917 while ((flt_time =
00918 artillery_round_flight_time(MechFX(mech), MechFY(mech), t.fx,
00919 t.fy)) > now) {
00920 if(!crashed)
00921 if(ai_crash(map, target_mech, &t))
00922 crashed = 1;
00923 now++;
00924 }
00925
00926 if(MechTargX(mech) != t.x || MechTargY(mech) != t.y)
00927 mech_settarget(player, mech, tprintf("%d %d", t.x, t.y));
00928 mech_fireweapon(player, mech, tprintf("%d", index));
00929 return 0;
00930 }
00931
00932 void mech_snipe(dbref player, MECH * mech, char *buffer)
00933 {
00934 char *args[3];
00935 dbref d;
00936
00937 DOCHECK(!WizRoy(player), "Permission denied.");
00938 DOCHECK(mech_parseattributes(buffer, args, 3) != 2,
00939 "Please supply target ID _and_ weapon(s) to use");
00940 DOCHECK((d =
00941 FindTargetDBREFFromMapNumber(mech, args[0])) <= 0,
00942 "Invalid target!");
00943 target_mech = getMech(d);
00944 multi_weap_sel(mech, player, args[1], 1, mech_snipe_func);
00945
00946 }
00947
00948
00949
00950
00951
00952
00953
00954
00955
00956 static astar_node *auto_create_astar_node(short x, short y,
00957 short x_parent, short y_parent,
00958 short g_score, short h_score)
00959 {
00960
00961 astar_node *temp;
00962 temp = malloc(sizeof(astar_node));
00963 if(temp == NULL)
00964 return NULL;
00965
00966 memset(temp, 0, sizeof(astar_node));
00967
00968 temp->x = x;
00969 temp->y = y;
00970 temp->x_parent = x_parent;
00971 temp->y_parent = y_parent;
00972 temp->g_score = g_score;
00973 temp->h_score = h_score;
00974 temp->f_score = g_score + h_score;
00975 temp->hexoffset = x * MAPY + y;
00976
00977 return temp;
00978
00979 }
00980
00981
00982
00983
00984
00985
00986 int astar_compare(int a, int b, void *arg)
00987 {
00988 return a - b;
00989 }
00990 void astar_release(void *key, void *data)
00991 {
00992 free(data);
00993 }
00994 int auto_astar_generate_path(AUTO * autopilot, MECH * mech, short end_x,
00995 short end_y)
00996 {
00997 MAP *map = getMap(autopilot->mapindex);
00998 int found_path = 0;
00999
01000
01001 unsigned char closed_list_bitfield[(MAPX * MAPY) / 8];
01002 unsigned char open_list_bitfield[(MAPX * MAPY) / 8];
01003
01004 float x1, y1, x2, y2;
01005 short map_x1, map_y1, map_x2, map_y2;
01006 int i;
01007 int child_g_score, child_h_score;
01008 int hexoffset;
01009
01010
01011
01012
01013 rbtree open_list_by_score;
01014 rbtree open_list_by_xy;
01015 rbtree closed_list;
01016
01017
01018 dllist_node *astar_path_node;
01019
01020
01021 astar_node *temp_astar_node;
01022 astar_node *parent_astar_node;
01023
01024 #ifdef DEBUG_ASTAR
01025
01026 FILE *logfile;
01027 char log_msg[MBUF_SIZE];
01028
01029
01030 logfile = fopen("astar.log", "a");
01031
01032
01033 snprintf(log_msg, MBUF_SIZE,
01034 "\nStarting ASTAR Path finding for AI #%d from "
01035 "%d, %d to %d, %d\n", autopilot->mynum, MechX(mech), MechY(mech),
01036 end_x, end_y);
01037 fprintf(logfile, "%s", log_msg);
01038 #endif
01039
01040
01041 memset(closed_list_bitfield, 0, sizeof(closed_list_bitfield));
01042 memset(open_list_bitfield, 0, sizeof(open_list_bitfield));
01043
01044
01045 open_list_by_score = rb_init((void *)astar_compare, NULL);
01046 open_list_by_xy = rb_init((void *)astar_compare, NULL);
01047 closed_list = rb_init((void *)astar_compare, NULL);
01048
01049
01050
01051 auto_destroy_astar_path(autopilot);
01052 autopilot->astar_path = dllist_create_list();
01053
01054
01055 temp_astar_node =
01056 auto_create_astar_node(MechX(mech), MechY(mech), -1, -1, 0, 0);
01057
01058 if(temp_astar_node == NULL) {
01061 #ifdef DEBUG_ASTAR
01062
01063 snprintf(log_msg, MBUF_SIZE,
01064 "AI ERROR - Unable to malloc astar node for " "hex %d, %d\n",
01065 MechX(mech), MechY(mech));
01066 fprintf(logfile, "%s", log_msg);
01067 #endif
01068
01069 }
01070
01071
01072 rb_insert(open_list_by_score, (void *) temp_astar_node->f_score,
01073 temp_astar_node);
01074 rb_insert(open_list_by_xy, (void *) temp_astar_node->hexoffset,
01075 temp_astar_node);
01076 SetHexBit(open_list_bitfield, temp_astar_node->hexoffset);
01077
01078 #ifdef DEBUG_ASTAR
01079
01080 snprintf(log_msg, MBUF_SIZE, "Added hex %d, %d (%d %d) to open list\n",
01081 temp_astar_node->x, temp_astar_node->y, temp_astar_node->g_score,
01082 temp_astar_node->h_score);
01083 fprintf(logfile, "%s", log_msg);
01084 #endif
01085
01086
01087 while (!found_path) {
01088
01089
01090
01091 if(rb_size(open_list_by_score) == 0) {
01092 break;
01093 }
01094
01095
01096 parent_astar_node = (astar_node *) rb_search(open_list_by_score,
01097 SEARCH_FIRST, NULL);
01098
01099 rb_delete(open_list_by_score, (void *) parent_astar_node->f_score);
01100 rb_delete(open_list_by_xy, (void *) parent_astar_node->hexoffset);
01101 ClearHexBit(open_list_bitfield, parent_astar_node->hexoffset);
01102
01103 #ifdef DEBUG_ASTAR
01104
01105 snprintf(log_msg, MBUF_SIZE, "Removed hex %d, %d (%d %d) from open "
01106 "list - lowest cost node\n",
01107 parent_astar_node->x, parent_astar_node->y,
01108 parent_astar_node->g_score, parent_astar_node->h_score);
01109 fprintf(logfile, "%s", log_msg);
01110 #endif
01111
01112
01113 rb_insert(closed_list, (void *) parent_astar_node->hexoffset,
01114 parent_astar_node);
01115 SetHexBit(closed_list_bitfield, parent_astar_node->hexoffset);
01116
01117 #ifdef DEBUG_ASTAR
01118
01119 snprintf(log_msg, MBUF_SIZE, "Added hex %d, %d (%d %d) to closed list"
01120 " - lowest cost node\n",
01121 parent_astar_node->x, parent_astar_node->y,
01122 parent_astar_node->g_score, parent_astar_node->h_score);
01123 fprintf(logfile, "%s", log_msg);
01124 #endif
01125
01126
01127
01128 if(CheckHexBit(closed_list_bitfield, HexOffSet(end_x, end_y))) {
01129 found_path = 1;
01130
01131 #ifdef DEBUG_ASTAR
01132 fprintf(logfile, "Found path for the AI\n");
01133 #endif
01134
01135 break;
01136 }
01137
01138
01139
01140
01141
01142
01143 map_x1 = parent_astar_node->x;
01144 map_y1 = parent_astar_node->y;
01145
01146
01147 for(i = 0; i < 360; i += 60) {
01148
01149
01150 MapCoordToRealCoord(map_x1, map_y1, &x1, &y1);
01151
01152
01153 FindXY(x1, y1, i, 1.0, &x2, &y2);
01154
01155
01156 RealCoordToMapCoord(&map_x2, &map_y2, x2, y2);
01157
01158
01159 if(map_x2 < 0 || map_y2 < 0 ||
01160 map_x2 >= map->map_width || map_y2 >= map->map_height)
01161 continue;
01162
01163
01164 hexoffset = HexOffSet(map_x2, map_y2);
01165
01166
01167
01168 if(CheckHexBit(closed_list_bitfield, hexoffset))
01169 continue;
01170
01171
01172 if((MechType(mech) == CLASS_MECH) &&
01173 (abs(Elevation(map, map_x1, map_y1)
01174 - Elevation(map, map_x2, map_y2)) > 2))
01175 continue;
01176
01177 if((MechType(mech) == CLASS_VEH_GROUND) &&
01178 (abs(Elevation(map, map_x1, map_y1)
01179 - Elevation(map, map_x2, map_y2)) > 1))
01180 continue;
01181
01182
01183
01184
01186 child_g_score = 100;
01187
01188
01189 child_g_score += parent_astar_node->g_score;
01190
01191
01192
01193
01194
01195
01196
01199
01200
01201 MapCoordToRealCoord(end_x, end_y, &x1, &y1);
01202
01203
01204
01205 child_h_score = 100 * FindHexRange(x2, y2, x1, y1);
01206
01207
01208 switch (GetTerrain(map, map_x2, map_y2)) {
01209 case LIGHT_FOREST:
01210
01211
01212
01213 if((MechType(mech) == CLASS_VEH_GROUND) &&
01214 (MechMove(mech) != MOVE_TRACK))
01215 continue;
01216
01217 child_g_score += 50;
01218 break;
01219 case ROUGH:
01220 child_g_score += 50;
01221 break;
01222 case HEAVY_FOREST:
01223
01224
01225
01226 if(MechType(mech) == CLASS_VEH_GROUND)
01227 continue;
01228
01229 child_g_score += 100;
01230 break;
01231 case MOUNTAINS:
01232 child_g_score += 100;
01233 break;
01234 case WATER:
01235
01236
01237
01238 if((MechType(mech) == CLASS_VEH_GROUND) &&
01239 (MechMove(mech) != MOVE_HOVER) && !(MechSpecials2(mech) & WATERPROOF_TECH))
01240 continue;
01241
01242
01243 child_g_score += 200;
01244 break;
01245 case HIGHWATER:
01246
01247
01248
01249 if((MechType(mech) == CLASS_VEH_GROUND) &&
01250 (MechMove(mech) != MOVE_HOVER) && !(MechSpecials2(mech) & WATERPROOF_TECH))
01251 continue;
01252
01253
01254 child_g_score += 200;
01255 break;
01256 default:
01257 break;
01258 }
01259
01260
01261 if(CheckHexBit(open_list_bitfield, hexoffset)) {
01262
01263
01264
01265
01266
01267 temp_astar_node = (astar_node *) rb_find(open_list_by_xy,
01268 (void *) hexoffset);
01269
01270
01271
01272
01273 if(child_g_score < temp_astar_node->g_score) {
01274
01275
01276 rb_delete(open_list_by_score,
01277 (void *) temp_astar_node->f_score);
01278 rb_delete(open_list_by_xy,
01279 (void *) temp_astar_node->hexoffset);
01280 ClearHexBit(open_list_bitfield,
01281 temp_astar_node->hexoffset);
01282
01283 #ifdef DEBUG_ASTAR
01284
01285 snprintf(log_msg, MBUF_SIZE,
01286 "Removed hex %d, %d (%d %d) from "
01287 "open list - score recal\n", temp_astar_node->x,
01288 temp_astar_node->y, temp_astar_node->g_score,
01289 temp_astar_node->h_score);
01290 fprintf(logfile, "%s", log_msg);
01291 #endif
01292
01293
01294
01295 temp_astar_node->g_score = child_g_score;
01296 temp_astar_node->f_score = temp_astar_node->g_score +
01297 temp_astar_node->h_score;
01298
01299
01300 temp_astar_node->x_parent = map_x1;
01301 temp_astar_node->y_parent = map_y1;
01302
01303
01304
01305 } else {
01306
01307
01308
01309 continue;
01310
01311 }
01312
01313 } else {
01314
01315
01316 temp_astar_node =
01317 auto_create_astar_node(map_x2, map_y2, map_x1, map_y1,
01318 child_g_score, child_h_score);
01319
01320 if(temp_astar_node == NULL) {
01323 #ifdef DEBUG_ASTAR
01324
01325 snprintf(log_msg, MBUF_SIZE,
01326 "AI ERROR - Unable to malloc astar"
01327 " node for hex %d, %d\n", map_x2, map_y2);
01328 fprintf(logfile, "%s", log_msg);
01329 #endif
01330
01331 }
01332
01333 }
01334
01335
01336
01337
01338
01339
01340 while (1) {
01341
01342 if(rb_exists
01343 (open_list_by_score, (void *) temp_astar_node->f_score)) {
01344 temp_astar_node->f_score++;
01345
01346 #ifdef DEBUG_ASTAR
01347 fprintf(logfile, "Adjusting score for hex %d, %d - same"
01348 " fscore already exists\n",
01349 temp_astar_node->x, temp_astar_node->y);
01350 #endif
01351
01352 } else {
01353 break;
01354 }
01355
01356 }
01357 rb_insert(open_list_by_score, (void *) temp_astar_node->f_score,
01358 temp_astar_node);
01359 rb_insert(open_list_by_xy, (void *) temp_astar_node->hexoffset,
01360 temp_astar_node);
01361 SetHexBit(open_list_bitfield, temp_astar_node->hexoffset);
01362
01363 #ifdef DEBUG_ASTAR
01364
01365 snprintf(log_msg, MBUF_SIZE,
01366 "Added hex %d, %d (%d %d) to open list\n",
01367 temp_astar_node->x, temp_astar_node->y,
01368 temp_astar_node->g_score, temp_astar_node->h_score);
01369 fprintf(logfile, "%s", log_msg);
01370 #endif
01371
01372 }
01373
01374 }
01375
01376
01377
01378
01379 if(found_path) {
01380
01381 #ifdef DEBUG_ASTAR
01382
01383 fprintf(logfile, "Building Path from closed list for AI\n");
01384 #endif
01385
01386
01387
01388
01389
01390
01391
01392
01393 hexoffset = HexOffSet(end_x, end_y);
01394 temp_astar_node = rb_find(closed_list, (void *) hexoffset);
01395
01396
01397 astar_path_node = dllist_create_node(temp_astar_node);
01398 dllist_insert_beginning(autopilot->astar_path, astar_path_node);
01399
01400 #ifdef DEBUG_ASTAR
01401
01402 fprintf(logfile, "Added hex %d, %d to path list\n",
01403 temp_astar_node->x, temp_astar_node->y);
01404 #endif
01405
01406
01407 rb_delete(closed_list, (void *) temp_astar_node->hexoffset);
01408
01409 #ifdef DEBUG_ASTAR
01410
01411 fprintf(logfile,
01412 "Removed hex %d, %d from closed list - path list work\n",
01413 temp_astar_node->x, temp_astar_node->y);
01414 #endif
01415
01416
01417 if(!(temp_astar_node->x == MechX(mech) &&
01418 temp_astar_node->y == MechY(mech))) {
01419
01420
01421
01422
01423
01424 while (1) {
01425
01426
01427 hexoffset = HexOffSet(temp_astar_node->x_parent,
01428 temp_astar_node->y_parent);
01429
01433
01434 parent_astar_node = rb_find(closed_list, (void *) hexoffset);
01435
01436
01437
01438 if(parent_astar_node->x == MechX(mech) &&
01439 parent_astar_node->y == MechY(mech)) {
01440 break;
01441 }
01442
01443
01444 astar_path_node = dllist_create_node(parent_astar_node);
01445 dllist_insert_beginning(autopilot->astar_path,
01446 astar_path_node);
01447
01448 #ifdef DEBUG_ASTAR
01449
01450 fprintf(logfile, "Added hex %d, %d to path list\n",
01451 parent_astar_node->x, parent_astar_node->y);
01452 #endif
01453
01454
01455 rb_delete(closed_list, (void *) parent_astar_node->hexoffset);
01456
01457 #ifdef DEBUG_ASTAR
01458
01459 fprintf(logfile,
01460 "Removed hex %d, %d from closed list - path list work\n",
01461 parent_astar_node->x, parent_astar_node->y);
01462 #endif
01463
01464
01465 temp_astar_node = parent_astar_node;
01466
01467 }
01468
01469 }
01470
01471
01472
01473 }
01474
01475
01476
01477 #ifdef DEBUG_ASTAR
01478
01479 fprintf(logfile, "Destorying the AI lists\n");
01480 #endif
01481
01482
01483 rb_release(open_list_by_score, (void *)astar_release, NULL);
01484 rb_destroy(open_list_by_xy);
01485
01486
01487 rb_release(closed_list, (void *)astar_release, NULL);
01488
01489 #ifdef DEBUG_ASTAR
01490
01491 fclose(logfile);
01492 #endif
01493
01494
01495 if(found_path) {
01496 return 1;
01497 } else {
01498 return 0;
01499 }
01500
01501 }
01502
01503
01504
01505
01506 void astar_smooth_path(AUTO * autopilot)
01507 {
01508
01509 dllist_node *current, *next, *prev;
01510
01511 float x1, y1, x2, y2;
01512 int degrees;
01513
01514
01515
01516
01517
01518
01519
01520
01521
01522
01523
01524
01525
01526
01527
01528
01529
01530
01531 return;
01532
01533 }
01534
01535 void auto_destroy_astar_path(AUTO * autopilot)
01536 {
01537
01538 astar_node *temp_astar_node;
01539
01540
01541 if(!(autopilot->astar_path))
01542 return;
01543
01544
01545 if(dllist_size(autopilot->astar_path) > 0) {
01546
01547 while (dllist_size(autopilot->astar_path)) {
01548 temp_astar_node =
01549 dllist_remove_node_at_pos(autopilot->astar_path, 1);
01550 free(temp_astar_node);
01551 }
01552
01553 }
01554
01555
01556 dllist_destroy_list(autopilot->astar_path);
01557 autopilot->astar_path = NULL;
01558
01559 }