src/hcode/btech/mech.utils.c

Go to the documentation of this file.
00001 /*
00002  * Author: Markus Stenberg <fingon@iki.fi>
00003  *
00004  *  Copyright (c) 1996 Markus Stenberg
00005  *  Copyright (c) 1998-2002 Thomas Wouters
00006  *  Copyright (c) 2000-2002 Cord Awtry
00007  *  Copyright (c) 1999-2005 Kevin Stevens
00008  *       All rights reserved
00009  */
00010 
00011 #include "config.h"
00012 
00013 #include <stdio.h>
00014 #include <stdlib.h>
00015 #include <math.h>
00016 #include <sys/file.h>
00017 
00018 #include "mech.h"
00019 #include "map.h"
00020 #include "mech.events.h"
00021 #include "p.mech.restrict.h"
00022 #include "p.mech.consistency.h"
00023 #include "p.mech.utils.h"
00024 #include "p.mech.startup.h"
00025 #include "p.ds.bay.h"
00026 #include "p.btechstats.h"
00027 #include "p.mechrep.h"
00028 #include "p.crit.h"
00029 #include "p.mech.combat.h"
00030 #include "p.mech.damage.h"
00031 #include "p.template.h"
00032 #include "p.bsuit.h"
00033 #include "p.mech.los.h"
00034 #include "p.aero.bomb.h"
00035 #include "autopilot.h"
00036 
00037 #ifdef BT_ADVANCED_ECON
00038 #include "p.mech.tech.do.h"
00039 #endif
00040 
00041 #ifdef BT_PART_WEIGHTS
00042 /* From template.c */
00043 extern int internalsweight[];
00044 extern int cargoweight[];
00045 #endif
00046 
00047 #ifdef BT_MOVEMENT_MODES
00048 #include "failures.h"
00049 #endif
00050 
00051 /* TODO: We can use M_PI if exists, otherwise define something reasonable.  */
00052 #define DEG2RAD(d) ((float)(d) * (3.14159265f / 180.f))
00053 #define RAD2DEG(d) ((float)(d) * (180.f / 3.14159265f))
00054 
00055 extern dbref pilot_override;
00056 
00057 char *mechtypenames[CLASS_LAST + 1] = {
00058         "mech", "tank", "VTOL", "vessel", "aerofighter", "DropShip"
00059 };
00060 
00061 const char *mechtypename(MECH * foo)
00062 {
00063         return mechtypenames[(int) MechType(foo)];
00064 }
00065 
00066 int MNumber(MECH * mech, int low, int high)
00067 {
00068         if((muxevent_tick / RANDOM_TICK) != MechLastRndU(mech)) {
00069                 MechRnd(mech) = random();
00070                 MechLastRndU(mech) = muxevent_tick / RANDOM_TICK;
00071         }
00072         return (low + MechRnd(mech) % (high - low + 1));
00073 }
00074 
00075 char *MechIDS(MECH * mech, int islower)
00076 {
00077         static char buf[3];
00078 
00079         if(mech) {
00080                 buf[0] = MechID(mech)[0];
00081                 buf[1] = MechID(mech)[1];
00082         } else {
00083                 buf[0] = '*';
00084                 buf[1] = '*';
00085         }
00086         buf[2] = 0;
00087 
00088         if(islower) {
00089                 buf[0] = tolower(buf[0]);
00090                 buf[1] = tolower(buf[1]);
00091         }
00092         return buf;
00093 }
00094 
00095 char *MyToUpper(char *string)
00096 {
00097         if(*string)
00098                 *string = toupper(*string);
00099         return string;
00100 }
00101 
00102 int CritsInLoc(MECH * mech, int index)
00103 {
00104         if(MechType(mech) == CLASS_MECH)
00105                 switch (index) {
00106                 case HEAD:
00107                 case RLEG:
00108                 case LLEG:
00109                         return 6;
00110                 case RARM:
00111                 case LARM:
00112                         if(MechIsQuad(mech))
00113                                 return 6;
00114         } else if(MechType(mech) == CLASS_MW)
00115                 return 2;
00116         return NUM_CRITICALS;
00117 }
00118 
00119 int SectHasBusyWeap(MECH * mech, int sect)
00120 {
00121         int i = 0, count, critical[MAX_WEAPS_SECTION];
00122         unsigned char weaptype[MAX_WEAPS_SECTION];
00123         unsigned char weapdata[MAX_WEAPS_SECTION];
00124 
00125         count = FindWeapons(mech, sect, weaptype, weapdata, critical);
00126         for(i = 0; i < count; i++)
00127                 if(WpnIsRecycling(mech, sect, critical[i]))
00128                         return 1;
00129         return 0;
00130 }
00131 
00132 MAP *ValidMap(dbref player, dbref map)
00133 {
00134         char *str;
00135         MAP *maps;
00136 
00137         DOCHECKN(!Good_obj(map), "Index out of range!");
00138         str = silly_atr_get(map, A_XTYPE);
00139         DOCHECKN(!str || !*str, "That is not a valid map! (no XTYPE!)");
00140         DOCHECKN(strcmp("MAP", str), "That is not a valid map!");
00141         DOCHECKN(!(maps = getMap(map)), "The map has not been allocated!!");
00142         return maps;
00143 }
00144 
00145 dbref FindMechOnMap(MAP * map, char *mechid)
00146 {
00147         int loop;
00148         MECH *tempMech;
00149 
00150         for(loop = 0; loop < map->first_free; loop++)
00151                 if(map->mechsOnMap[loop] != -1) {
00152                         tempMech = getMech(map->mechsOnMap[loop]);
00153                         if(tempMech && !strncasecmp(MechID(tempMech), mechid, 2))
00154                                 return tempMech->mynum;
00155                 }
00156         return -1;
00157 }
00158 
00159 dbref FindTargetDBREFFromMapNumber(MECH * mech, char *mapnum)
00160 {
00161         MAP *map;
00162 
00163         if(mech->mapindex == -1)
00164                 return -1;
00165         map = getMap(mech->mapindex);
00166         if(!map) {
00167                 SendError(tprintf("FTDBREFFMN:invalid map:Mech: %d  Index: %d",
00168                                                   mech->mynum, mech->mapindex));
00169                 mech->mapindex = -1;
00170                 return -1;
00171         }
00172         return FindMechOnMap(map, mapnum);
00173 }
00174 
00175 void FindComponents(float magnitude, int degrees, float *x, float *y)
00176 {
00177         *x = magnitude * fcos((float) (TWOPIOVER360 * (degrees + 90)));
00178         *y = magnitude * fsin((float) (TWOPIOVER360 * (degrees + 90)));
00179         *x = -(*x);                                     /* because 90 is to the right */
00180         *y = -(*y);                                     /* because y increases downwards */
00181 }
00182 
00183 static int Leave_Hangar(MAP * map, MECH * mech)
00184 {
00185         MECH *car = NULL;
00186         int mapob;
00187         mapobj *mapo;
00188 
00189         /* For now, leaving leads to finding yourself on the new map
00190            at a predetermined position */
00191         mapob = mech->mapindex;
00192         if(MechCarrying(mech) > 0)
00193                 car = getMech(MechCarrying(mech));
00194         DOCHECKMA0(!map->cf, "The entrance is still filled with rubble!");
00195         MechLOSBroadcast(mech, "has left the hangar.");
00196         mech_Rsetmapindex(GOD, (void *) mech, tprintf("%d",
00197                                                                                                   (int) map->
00198                                                                                                   mapobj[TYPE_LEAVE]->obj));
00199         if(car)
00200                 mech_Rsetmapindex(GOD, (void *) car, tprintf("%d",
00201                                                                                                          (int) map->
00202                                                                                                          mapobj[TYPE_LEAVE]->
00203                                                                                                          obj));
00204         map = getMap(mech->mapindex);
00205         if(mech->mapindex == mapob) {
00206                 SendError(tprintf("#%d %s attempted to leave, but no target map?",
00207                                                   mech->mynum, GetMechID(mech)));
00208                 mech_notify(mech, MECHALL,
00209                                         "Exit of this map is.. fubared. Please contact a wizard");
00210                 return 0;
00211         }
00212         if(!(mapo = find_entrance_by_target(map, mapob))) {
00213                 SendError(tprintf
00214                                   ("#%d %s attempted to leave, but no target place was found? setting the mech at 0,0 at %d.",
00215                                    mech->mynum, GetMechID(mech), mech->mapindex));
00216                 mech_notify(mech, MECHALL,
00217                                         "Weird bug happened during leave. Please contact a wizard. ");
00218                 return 1;
00219         }
00220 
00221         StopBSuitSwarmers(FindObjectsData(mech->mapindex), mech, 1);
00222         mech_printf(mech, MECHALL, "You have left %s.", structure_name(mapo));
00223         mech_Rsetxy(GOD, (void *) mech, tprintf("%d %d", mapo->x, mapo->y));
00224         ContinueFlying(mech);
00225         if(car)
00226                 MirrorPosition(mech, car, 0);
00227         MechLOSBroadcast(mech, tprintf("has left %s at %d,%d.",
00228                                                                    structure_name(mapo), MechX(mech),
00229                                                                    MechY(mech)));
00230         loud_teleport(mech->mynum, mech->mapindex);
00231         if(car)
00232                 loud_teleport(car->mynum, mech->mapindex);
00233         if(In_Character(mech->mynum) && Location(MechPilot(mech)) != mech->mynum) {
00234                 mech_notify(mech, MECHALL,
00235                                         "%ch%cr%cf%ciINTRUDER ALERT! INTRUDER ALERT!%c");
00236                 mech_notify(mech, MECHALL,
00237                                         "%ch%cr%cfAutomatic self-destruct sequence initiated...%c");
00238                 mech_shutdown(GOD, (void *) mech, "");
00239         }
00240         auto_cal_mapindex(mech);
00241         if(MechSpeed(mech) > MMaxSpeed(mech))
00242                 MechSpeed(mech) = MMaxSpeed(mech);
00243         return 1;
00244 }
00245 
00246 void CheckEdgeOfMap(MECH * mech)
00247 {
00248         int pinned = 0;
00249         int linked;
00250         MAP *map;
00251 
00252         map = getMap(mech->mapindex);
00253 
00254         if(!map) {
00255                 mech_notify(mech, MECHPILOT,
00256                                         "You are on an invalid map! Map index reset!");
00257                 mech_shutdown(MechPilot(mech), (void *) mech, "");
00258                 SendError(tprintf("CheckEdgeofMap:invalid map:Mech: %d  Index: %d",
00259                                                   mech->mynum, mech->mapindex));
00260                 mech->mapindex = -1;
00261                 return;
00262         }
00263         linked = map_linked(mech->mapindex);
00264         /* Prevents you from going off the map */
00265         /* Eventually this could wrap and all that.. */
00266         if(MechX(mech) < 0) {
00267                 if(linked) {
00268                         MechX(mech) += map->map_width;
00269                         pinned = -1;
00270                 } else {
00271                         MechX(mech) = 0;
00272                         pinned = 4;
00273                 }
00274         } else if(MechX(mech) >= map->map_width) {
00275                 if(linked) {
00276                         MechX(mech) -= map->map_width;
00277                         pinned = -1;
00278                 } else {
00279                         MechX(mech) = map->map_width - 1;
00280                         pinned = 2;
00281                 }
00282         }
00283         if(MechY(mech) < 0) {
00284                 if(linked) {
00285                         pinned = -1;
00286                         MechY(mech) += map->map_height;
00287                 } else {
00288                         MechY(mech) = 0;
00289                         pinned = 1;
00290                 }
00291         } else if(MechY(mech) >= map->map_height) {
00292                 if(linked) {
00293                         pinned = -1;
00294                         MechY(mech) -= map->map_height;
00295                 } else {
00296                         MechY(mech) = map->map_height - 1;
00297                         pinned = 3;
00298                 }
00299         }
00300         if(pinned > 0) {
00301                 /* This is a DS bay. First, we need to check if the bay's doors are
00302                    blocked, one way or another.
00303                  */
00304                 if(map->onmap && IsMech(map->onmap)) {
00305                         if(Leave_DS(map, mech))
00306                                 return;
00307                 } else if(map->flags & MAPFLAG_MAPO && map->mapobj[TYPE_LEAVE])
00308                         if(Leave_Hangar(map, mech))
00309                                 return;
00310         }
00311         if(pinned) {
00312                 MapCoordToRealCoord(MechX(mech), MechY(mech), &MechFX(mech),
00313                                                         &MechFY(mech));
00314                 if(pinned > 0) {
00315                         mech_notify(mech, MECHALL, "You cannot move off this map!");
00316                         if(Jumping(mech) && !is_aero(mech))
00317                                 LandMech(mech);
00318                         MechCocoon(mech) = 0;
00319                         MechSpeed(mech) = 0.0;
00320                         MechDesiredSpeed(mech) = 0.0;
00321                         if(is_aero(mech)) {
00322                                 MechStartFX(mech) = 0.0;
00323                                 MechStartFY(mech) = 0.0;
00324                                 MechStartFZ(mech) = 0.0;
00325                                 if(!Landed(mech))
00326                                         MaybeMove(mech);
00327                         }
00328                 }
00329         }
00330 }
00331 int FindZBearing(float x0, float y0, float z0, float x1, float y1, float z1)
00332 {
00333         float adj, opp, deg;
00334 
00335         adj = FindXYRange(x0, y0, x1, y1);
00336         /*
00337          * XXX: Why can't opp be negative?  If z1 < z0, shouldn't Z-bearing
00338          * also be negative?  Also, why no range clamping on the value of deg?
00339          */
00340         opp = (float)(1./SCALEMAP) * fabsf(z1 - z0);
00341         /* TODO: Use atan2f(), if we've got it.  */
00342         deg = RAD2DEG(atan2(opp, adj));
00343         return ceilf(deg);
00344 }
00345 
00346 int FindBearing(float x0, float y0, float x1, float y1)
00347 {
00348         const float dx = x1 - x0;
00349         const float dy = y1 - y0;
00350 
00351         float rads;
00352         int degrees;
00353 
00354         /*
00355          * atan2() doesn't need this check because we never actually divide by
00356          * dx, but we handle it specially for consistency with existing code.
00357          */
00358         if (dx == 0.f) {
00359                 return (dy < 0.f) ? 0 : 180;
00360         }
00361 
00362         /* TODO: Use atan2f(), if we've got it.  */
00363         rads = (float)atan2(-dx, dy);
00364 
00365         /* Round off degrees.  */
00366         degrees = ((int)RAD2DEG(10.f * rads) + 5) / 10;
00367 
00368         return AcceptableDegree(degrees + 180);
00369 }
00370 
00371 int InWeaponArc(MECH * mech, float x, float y)
00372 {
00373         int relat;
00374         int bearingToTarget;
00375         int res = NOARC;
00376 
00377         bearingToTarget = FindBearing(MechFX(mech), MechFY(mech), x, y);
00378         relat = MechFacing(mech) - bearingToTarget;
00379         if(MechType(mech) == CLASS_MECH || MechType(mech) == CLASS_MW ||
00380            MechType(mech) == CLASS_BSUIT) {
00381                 if(MechStatus(mech) & TORSO_RIGHT)
00382                         relat += 59;
00383                 else if(MechStatus(mech) & TORSO_LEFT)
00384                         relat -= 59;
00385         }
00386         relat = AcceptableDegree(relat);
00387         if(relat >= 300 || relat <= 60)
00388                 res |= FORWARDARC;
00389         if(relat > 120 && relat < 240)
00390                 res |= REARARC;
00391         if(relat >= 240 && relat < 300)
00392                 res |= RSIDEARC;
00393         if(relat > 60 && relat <= 120)
00394                 res |= LSIDEARC;
00395 
00396         if(MechHasTurret(mech)) {
00397                 relat = AcceptableDegree((MechFacing(mech) + MechTurretFacing(mech))
00398                                                                  - bearingToTarget);
00399                 if(relat >= 330 || relat <= 30)
00400                         res |= TURRETARC;
00401         }
00402         if(res == NOARC)
00403                 SendError(tprintf("NoArc: #%d: BearingToTarget:%d Facing:%d",
00404                                                   mech->mynum, bearingToTarget, MechFacing(mech)));
00405         return res;
00406 }
00407 
00408 char *FindGunnerySkillName(MECH * mech, int weapindx)
00409 {
00410 #ifndef BT_EXILE_MW3STATS
00411         switch (MechType(mech)) {
00412         case CLASS_BSUIT:
00413                 return "Gunnery-BSuit";
00414         case CLASS_MECH:
00415                 return "Gunnery-Battlemech";
00416         case CLASS_VEH_GROUND:
00417         case CLASS_VEH_NAVAL:
00418                 return "Gunnery-Conventional";
00419         case CLASS_VTOL:
00420         case CLASS_AERO:
00421                 return "Gunnery-Aerospace";
00422         case CLASS_SPHEROID_DS:
00423         case CLASS_DS:
00424                 return "Gunnery-Spacecraft";
00425         case CLASS_MW:
00426                 if(weapindx >= 0) {
00427                         if(!strcmp(MechWeapons[weapindx].name, "PC.Sword"))
00428                                 return "Blade";
00429                         if(!strcmp(MechWeapons[weapindx].name, "PC.Vibroblade"))
00430                                 return "Blade";
00431                 }
00432                 return "Small_Arms";
00433         }
00434 #else
00435         if(weapindx < 0)
00436                 return NULL;
00437         if(MechType(mech) == CLASS_MW) {
00438                 if(weapindx >= 0) {
00439                         if(!strcmp(MechWeapons[weapindx].name, "PC.Blade"))
00440                                 return "Blade";
00441                         if(!strcmp(MechWeapons[weapindx].name, "PC.Vibroblade"))
00442                                 return "Blade";
00443                         if(!strcmp(MechWeapons[weapindx].name, "PC.Blazer"))
00444                                 return "Support_Weapons";
00445                         if(!strcmp(MechWeapons[weapindx].name, "PC.HeavyGyrojetGun"))
00446                                 return "Support_Weapons";
00447                         return "Small_Arms";
00448                 }
00449         } else if(IsArtillery(weapindx))
00450                 return "Gunnery-Artillery";
00451         else if(IsMissile(weapindx))
00452                 return "Gunnery-Missile";
00453         else if(IsBallistic(weapindx))
00454                 return "Gunnery-Ballistic";
00455         else if(IsEnergy(weapindx))
00456                 return "Gunnery-Laser";
00457         else if(IsFlamer(weapindx))
00458                 return "Gunnery-Flamer";
00459 #endif
00460         return NULL;
00461 }
00462 
00463 char *FindPilotingSkillName(MECH * mech)
00464 {
00465 #ifndef BT_EXILE_MW3STATS
00466         switch (MechType(mech)) {
00467         case CLASS_MW:
00468                 return "Running";
00469         case CLASS_BSUIT:
00470                 return "Piloting-BSuit";
00471         case CLASS_MECH:
00472                 return "Piloting-Battlemech";
00473         case CLASS_VEH_GROUND:
00474         case CLASS_VEH_NAVAL:
00475                 return "Drive";
00476         case CLASS_VTOL:
00477         case CLASS_AERO:
00478                 return "Piloting-Aerospace";
00479         case CLASS_SPHEROID_DS:
00480         case CLASS_DS:
00481                 return "Piloting-Spacecraft";
00482         }
00483 #else
00484         if(MechType(mech) == CLASS_MW && MechRTerrain(mech) == WATER)
00485                 return "Swimming";
00486         switch (MechType(mech)) {
00487         case CLASS_MW:
00488                 return "Running";
00489         case CLASS_BSUIT:
00490                 return "Piloting-Bsuit";
00491         case CLASS_VEH_NAVAL:
00492                 return "Piloting-Naval";
00493         case CLASS_DS:
00494         case CLASS_SPHEROID_DS:
00495                 return "Piloting-Spacecraft";
00496         case CLASS_VTOL:
00497         case CLASS_AERO:
00498                 return "Piloting-Aerospace";
00499         }
00500         switch (MechMove(mech)) {
00501         case MOVE_BIPED:
00502                 return "Piloting-Biped";
00503         case MOVE_QUAD:
00504                 return "Piloting-Quad";
00505         case MOVE_TRACK:
00506                 return "Piloting-Tracked";
00507         case MOVE_HOVER:
00508                 return "Piloting-Hover";
00509         case MOVE_WHEEL:
00510                 return "Piloting-Wheeled";
00511         }
00512 #endif
00513         return NULL;
00514 }
00515 
00516 #define MECHSKILL_PILOTING  0
00517 #define MECHSKILL_GUNNERY   1
00518 #define MECHSKILL_SPOTTING  2
00519 #define MECHSKILL_ARTILLERY 3
00520 #define NUM_MECHSKILLS      4
00521 
00522 // TODO: Replace this with a function.
00523 #define GENERIC_FIND_MECHSKILL(num,n) \
00524     if (Quiet(mech->mynum)) \
00525         { str = silly_atr_get(mech->mynum, A_MECHSKILLS); \
00526     if (*str) if (sscanf (str, "%d %d %d %d", &i[0], &i[1], &i[2], &i[3]) > num) \
00527         return i[num] - n; }
00528 
00529 int FindPilotPiloting(MECH * mech)
00530 {
00531         char *str;
00532         int i[NUM_MECHSKILLS];
00533 
00534         GENERIC_FIND_MECHSKILL(MECHSKILL_PILOTING, 0);
00535         if(RGotPilot(mech))
00536                 if((str = FindPilotingSkillName(mech)))
00537                         return char_getskilltarget(MechPilot(mech), str, 0);
00538         return DEFAULT_PILOTING;
00539 }
00540 
00541 int FindSPilotPiloting(MECH * mech)
00542 {
00543         return FindPilotPiloting(mech) + (MechMove(mech) == MOVE_QUAD ? -2 : 0);
00544 }
00545 
00546 int FindPilotSpotting(MECH * mech)
00547 {
00548         char *str;
00549         int i[NUM_MECHSKILLS];
00550 
00551         GENERIC_FIND_MECHSKILL(MECHSKILL_SPOTTING, 0);
00552         if(RGotPilot(mech))
00553                 return (char_getskilltarget(MechPilot(mech), "Gunnery-Spotting", 0));
00554         return DEFAULT_SPOTTING;
00555 }
00556 
00557 int FindPilotArtyGun(MECH * mech)
00558 {
00559         char *str;
00560         int i[NUM_MECHSKILLS];
00561 
00562         GENERIC_FIND_MECHSKILL(MECHSKILL_ARTILLERY, 0);
00563         if(RGotGPilot(mech))
00564                 return (char_getskilltarget(GunPilot(mech), "Gunnery-Artillery", 0));
00565         return DEFAULT_ARTILLERY;
00566 }
00567 
00568 int FindPilotGunnery(MECH * mech, int weapindx)
00569 {
00570         char *str;
00571         int i[NUM_MECHSKILLS];
00572 
00573         GENERIC_FIND_MECHSKILL(MECHSKILL_GUNNERY, 0);
00574         if(RGotGPilot(mech))
00575                 if((str = FindGunnerySkillName(mech, weapindx)))
00576                         return char_getskilltarget(GunPilot(mech), str, 0);
00577         return DEFAULT_GUNNERY;
00578 }
00579 
00580 char *FindTechSkillName(MECH * mech)
00581 {
00582         switch (MechType(mech)) {
00583         case CLASS_MECH:
00584         case CLASS_BSUIT:
00585                 return "Technician-Battlemech";
00586         case CLASS_VEH_GROUND:
00587         case CLASS_VEH_NAVAL:
00588                 return "Technician-Mechanic";
00589         case CLASS_AERO:
00590         case CLASS_VTOL:
00591         case CLASS_SPHEROID_DS:
00592         case CLASS_DS:
00593                 return "Technician-Aerospace";
00594 #if 0                                                   /* Used to be DS tech */
00595                 return (char_getskilltarget(player, "Technician-Spacecraft", 0));
00596 #endif
00597         }
00598         return NULL;
00599 }
00600 
00601 int FindTechSkill(dbref player, MECH * mech)
00602 {
00603         char *skname;
00604 
00605         if((skname = FindTechSkillName(mech)))
00606                 return (char_getskilltarget(player, skname, 0));
00607         return 18;
00608 }
00609 
00610 int MadePilotSkillRoll(MECH * mech, int mods)
00611 {
00612         return MadePilotSkillRoll_Advanced(mech, mods, 1);
00613 }
00614 
00615 int MechPilotSkillRoll_BTH(MECH * mech, int mods)
00616 {
00617         mods += FindSPilotPiloting(mech) + MechPilotSkillBase(mech);
00618         if(In_Character(mech->mynum) && Location(MechPilot(mech)) != mech->mynum)
00619                 mods += 5;
00620         return mods;
00621 }
00622 
00623 int MadePilotSkillRoll_NoXP(MECH * mech, int mods, int succeedWhenFallen)
00624 {
00625         int roll, roll_needed;
00626 
00627         if(Fallen(mech) && succeedWhenFallen)
00628                 return 1;
00629         if(Uncon(mech) || !Started(mech) || Blinded(mech))
00630                 return 0;
00631         roll = Roll();
00632         roll_needed = MechPilotSkillRoll_BTH(mech, mods);
00633 
00634         SendDebug(tprintf("Attempting to make pilot skill roll. "
00635                                           "SPilot: %d, mods: %d, MechPilot: %d, BTH: %d",
00636                                           FindSPilotPiloting(mech), mods,
00637                                           MechPilotSkillBase(mech), roll_needed));
00638 
00639         mech_notify(mech, MECHPILOT, "You make a piloting skill roll!");
00640         mech_printf(mech, MECHPILOT,
00641                                 "Modified Pilot Skill: BTH %d\tRoll: %d", roll_needed, roll);
00642         if(roll >= roll_needed) {
00643                 return 1;
00644         }
00645         return 0;
00646 }
00647 
00648 int MadePilotSkillRoll_Advanced(MECH * mech, int mods, int succeedWhenFallen)
00649 {
00650         int roll, roll_needed;
00651 
00652         if(Fallen(mech) && succeedWhenFallen)
00653                 return 1;
00654         if(Uncon(mech) || !Started(mech) || Blinded(mech))
00655                 return 0;
00656         roll = Roll();
00657         roll_needed = MechPilotSkillRoll_BTH(mech, mods);
00658 
00659         SendDebug(tprintf("Attempting to make pilot (noxp) skill roll. "
00660                                           "SPilot: %d, mods: %d, MechPilot: %d, BTH: %d",
00661                                           FindSPilotPiloting(mech), mods,
00662                                           MechPilotSkillBase(mech), roll_needed));
00663 
00664         mech_notify(mech, MECHPILOT, "You make a piloting skill roll!");
00665         mech_printf(mech, MECHPILOT,
00666                                 "Modified Pilot Skill: BTH %d\tRoll: %d", roll_needed, roll);
00667         if(roll >= roll_needed) {
00668                 if(roll_needed > 2)
00669                         AccumulatePilXP(MechPilot(mech), mech, BOUNDED(1,
00670                                                                                                                    roll_needed - 7,
00671                                                                                                                    MAX(2, 1 + mods)),
00672                                                         1);
00673                 return 1;
00674         }
00675         return 0;
00676 }
00677 
00678 void FindXY(float x0, float y0, int bearing, float range, float *x1, float *y1)
00679 {
00680         float xscale, correction;
00681 
00682         /* XXX: Something to do with ranges with actual number of hexes? */
00683         correction = (float) (bearing % 60) / 60.0;
00684         if(correction > 0.5)
00685                 correction = 1.0 - correction;
00686         correction = -correction * 2.0; /* 0 - 1 correction */
00687         xscale = (1.0 + XSCALE * correction) * SCALEMAP;
00688 
00689         /* TODO: Use sinf()/cosf(), if we've got them.  */
00690         *x1 = x0 + range * (float)sin(DEG2RAD(bearing)) * xscale;
00691         *y1 = y0 - range * (float)cos(DEG2RAD(bearing)) * SCALEMAP;
00692 }
00693 
00694 /* Computes hex range between Cartesian (x0, y0, z0) and (x1, y1, z1).  */
00695 float FindRange(float x0, float y0, float z0, float x1, float y1, float z1)
00696 {
00697         const float dx = x0 - x1;
00698         const float dy = y0 - y1;
00699         const float dz = z0 - z1;
00700 
00701         /* TODO: Use sqrtf(), if we've got it.  */
00702         return (float)(1./SCALEMAP) * (float)sqrt(dx * dx + dy * dy + dz * dz);
00703 }
00704 
00705 /* Computes hex range between Cartesian (x0, y0) and (x1, y1).  */
00706 float FindXYRange(float x0, float y0, float x1, float y1)
00707 {
00708         const float dx = x0 - x1;
00709         const float dy = y0 - y1;
00710 
00711         /* TODO: Use sqrtf(), if we've got it.  */
00712         return (float)(1./SCALEMAP) * (float)sqrt(dx * dx + dy * dy);
00713 }
00714 
00715 /* TODO: We could just make this a macro, right? Or substitute it away.  */
00716 float FindHexRange(float x0, float y0, float x1, float y1)
00717 {
00718         return FindXYRange(x0, y0, x1, y1);
00719 }
00720 
00721 /* CONVERSION ROUTINES courtesy Mike :) (Whoever that may be -focus) */
00722 
00723 /* Picture blatantly ripped from the MUSH code by Dizzledorf and co. If only
00724    I had found it _before_ reverse-engineering the code :)
00725      - Focus, July 2002.
00726  */
00727 
00728 /*
00729  * Convert floating-point cartesian coordinates into hex coordinates.
00730  *
00731  * To do this, split the hex map into a repeatable region, which itself has
00732  * 4 distinct regions, each part of a different hex. (See picture.) The hex
00733  * is normalized so that it is 1 unit high, and so is the repeatable region.
00734  * It works out that the repeatable region is exactly sqrt(3) wide, and can
00735  * be split up in six portions of each 1/6th sqrt(3), called 'alpha'. 
00736  * Section I is 2 alpha wide at the top and bottom, and 3 alpha in the
00737  * middle. Sections II and III are reversed, being 4 alpha at the top and
00738  * bottom of the region, and 2 alpha in the middle. Section IV is 1 alpha in
00739  * the middle and 0 at the top and bottom. The whole region encompasses
00740  * exactly two x-columns and one y-row. All calculations are now done in
00741  * 'real' scale, to avoid rounding errors (isn't floating point arithmatic
00742  * fun ?)
00743  *
00744  * Alpha also returns in the slope of the hexsides (2*alpha, flipped or rotated
00745  * as necessary).  ANGLE_ALPHA is alpha (unscaled) for use in angle
00746  * calculations.
00747  *
00748  *       ________________________
00749  *      |        \              /|
00750  *      |         \    III     / |
00751  *      |          \          /  |
00752  *      |           \________/ IV|
00753  *      |    I      /        \   |
00754  *      |          /   II     \  |
00755  *      |         /            \ |
00756  *      |________/______________\|
00757  *
00758  */
00759 
00760 /* Doubles for added accuracy; most calculations are doubles internally
00761    anyway, so we suffer little to no performance hit. */
00762 
00763 #define ROOT3 558.58638544096289        /* sqrt(3) * SCALEMAP */
00764 #define ALPHA 93.097730906827152        /* ROOT3 / 6 */
00765 #define ANGLE_ALPHA 0.28867513459481287 /* sqrt(3) / 6 */
00766 #define FULL_Y (1 * SCALEMAP)
00767 #define HALF_Y (0.5 * FULL_Y)
00768 
00769 void RealCoordToMapCoord(short *hex_x, short *hex_y, float cart_x,
00770                                                  float cart_y)
00771 {
00772         float x, y;
00773         int x_count, y_count;
00774 
00775         if(cart_x < ALPHA) {
00776                 /* Special case: we are in section IV of x-column 0 or off the map */
00777                 *hex_x = cart_x < 0 ? -1 : 0;
00778                 *hex_y = floor(cart_y / SCALEMAP);
00779                 return;
00780         }
00781 
00782         /* 'shift' the map to the left so the repeatable box starts at 0 */
00783         cart_x -= ALPHA;
00784 
00785         /* Figure out the x-coordinate of the 'repeatable box' we're in. */
00786         x_count = cart_x / ROOT3;
00787         /* And the offset inside the box, from the left edge. */
00788         x = cart_x - x_count * ROOT3;
00789 
00790         /* The repbox holds two x-columns, we want the real X coordinate. */
00791         x_count *= 2;
00792 
00793         /* Do the same for the y-coordinate; this is easy */
00794         y_count = floor(cart_y / FULL_Y);
00795         y = cart_y - y_count * FULL_Y;
00796 
00797         if(x < 2 * ALPHA) {
00798 
00799                 /* Clean in area I. Nothing to do */
00800 
00801         } else if(x >= 3 * ALPHA && x < 5 * ALPHA) {
00802                 /* Clean in either area II or III. Up x one, and y if in the lower
00803                    half of the box. */
00804                 x_count++;
00805                 if(y >= HALF_Y)
00806                         /* Area II */
00807                         y_count++;
00808 
00809         } else if(x >= 2 * ALPHA && x < 3 * ALPHA) {
00810                 /* Any of areas I, II and III. */
00811                 if(y >= HALF_Y) {
00812                         /* Area I or II */
00813                         if(2 * ANGLE_ALPHA * (FULL_Y - y) <= x - 2 * ALPHA) {
00814                                 /* Area II, up both */
00815                                 x_count++;
00816                                 y_count++;
00817                         }
00818                 } else {
00819                         /* Area I or III */
00820                         if(2 * ANGLE_ALPHA * y <= x - 2 * ALPHA)
00821                                 /* Area III, up only x */
00822                                 x_count++;
00823                 }
00824         } else if(y >= HALF_Y) {
00825                 /* Area II or IV. Up x at least one, maybe two, and y maybe one. */
00826                 x_count++;
00827                 if(2 * ANGLE_ALPHA * (y - HALF_Y) > (x - 5.0 * ALPHA))
00828                         /* Area II */
00829                         y_count++;
00830                 else
00831                         /* Area IV */
00832                         x_count++;
00833         } else {
00834                 /* Area III or IV, up x at least one, maybe two */
00835                 x_count++;
00836                 if(2 * ANGLE_ALPHA * y > ROOT3 - x)
00837                         /* Area IV */
00838                         x_count++;
00839         }
00840 
00841         *hex_x = x_count;
00842         *hex_y = y_count;
00843 }
00844 
00845 /*
00846  * Convert hex coordinates into centered floating-point cartesian coordinates.
00847  *
00848  * Properties of hex centers:
00849  * 1) Spaced 3 ALPHA apart horizontally, starting from 2 ALPHA.
00850  * 2) Spaced FULL_Y apart vertically.
00851  * 3a) Even column centers (counting from 0) are vertically offset HALF_Y.
00852  * 3b) Odd column centers (counting from 0) are not vertically offset.
00853  */
00854 void MapCoordToRealCoord(int hex_x, int hex_y, float *cart_x, float *cart_y)
00855 {
00856         /* TODO: Can use some integer math if we're careful about overflow.  */
00857         *cart_x = (2.f + 3.f * (float)hex_x) * ALPHA;
00858         *cart_y = ((hex_x & 0x1) ? 0 : HALF_Y) + ((float)hex_y * FULL_Y);
00859 }
00860 
00861 /*
00862    Sketch a 'mech on a Navigate map. Done here since it fiddles directly
00863    with cartesian coords.
00864 
00865    Navigate is 9 rows high, and a hex is exactly 1*SCALEMAP high, so each
00866    row is FULL_Y/9 cartesian y-coords high.
00867    
00868    Navigate is 21 hexes wide, at its widest point. This corresponds to the
00869    hex width, which is 4 * ALPHA, so each column is 4*ALPHA/21 cartesian
00870    x-coords wide.
00871 
00872    The actual navigate map starts two rows from the top and four columns
00873    from the left.
00874 
00875  */
00876 
00877 #define NAV_ROW_HEIGHT (FULL_Y / 9.0)
00878 #define NAV_COLUMN_WIDTH (4 * ALPHA / 21.0)
00879 #define NAV_Y_OFFSET 2
00880 #define NAV_X_OFFSET 4
00881 #define NAV_MAX_HEIGHT 2+9+2
00882 #define NAV_MAX_WIDTH 4+21+2
00883 
00884 void navigate_sketch_mechs(MECH * mech, MAP * map, int x, int y,
00885                                                    char buff[NAVIGATE_LINES][MBUF_SIZE])
00886 {
00887         float corner_fx, corner_fy, fx, fy;
00888         int i, row, column;
00889         MECH *other;
00890 
00891         MapCoordToRealCoord(x, y, &corner_fx, &corner_fy);
00892         corner_fx -= 2 * ALPHA;
00893         corner_fy -= HALF_Y;
00894 
00895         for(i = 0; i < map->first_free; i++) {
00896                 if(map->mechsOnMap[i] < 0)
00897                         continue;
00898                 if(!(other = FindObjectsData(map->mechsOnMap[i])))
00899                         continue;
00900                 if(other == mech)
00901                         continue;
00902                 if(MechX(other) != x || MechY(other) != y)
00903                         continue;
00904                 if(!InLineOfSight(mech, other, x, y, 0.5))
00905                         continue;
00906 
00907                 fx = MechFX(other) - corner_fx;
00908                 column = fx / NAV_COLUMN_WIDTH + NAV_X_OFFSET;
00909 
00910                 fy = MechFY(other) - corner_fy;
00911                 row = fy / NAV_ROW_HEIGHT + NAV_Y_OFFSET;
00912 
00913                 if(column < 0 || column > NAV_MAX_WIDTH ||
00914                    row < 0 || row > NAV_MAX_HEIGHT)
00915                         continue;
00916 
00917                 buff[row][column] = MechSeemsFriend(mech, other) ? 'x' : 'X';
00918         }
00919 
00920         /* Draw 'mech last so we always see it. */
00921 
00922         fx = MechFX(mech) - corner_fx;
00923         column = fx / NAV_COLUMN_WIDTH + NAV_X_OFFSET;
00924 
00925         fy = MechFY(mech) - corner_fy;
00926         row = fy / NAV_ROW_HEIGHT + NAV_Y_OFFSET;
00927 
00928         if(column < 0 || column > NAV_MAX_WIDTH ||
00929            row < 0 || row > NAV_MAX_HEIGHT)
00930                 return;
00931 
00932         buff[row][column] = '*';
00933 }
00934 
00935 int FindTargetXY(MECH * mech, float *x, float *y, float *z)
00936 {
00937         MECH *tempMech;
00938 
00939         if(MechTarget(mech) != -1) {
00940                 tempMech = getMech(MechTarget(mech));
00941                 if(tempMech) {
00942                         *x = MechFX(tempMech);
00943                         *y = MechFY(tempMech);
00944                         *z = MechFZ(tempMech);
00945                         return 1;
00946                 }
00947         } else if(MechTargX(mech) != -1 && MechTargY(mech) != -1) {
00948                 MapCoordToRealCoord(MechTargX(mech), MechTargY(mech), x, y);
00949                 *z = (float) ZSCALE *(MechTargZ(mech));
00950 
00951                 return 1;
00952         }
00953         return 0;
00954 }
00955 
00956 int global_silence = 0;
00957 
00958 #define UGLYTEST \
00959           if (num_crits) \
00960             { \
00961               if (num_crits != (i = GetWeaponCrits (mech, lastweap))) \
00962                 { \
00963                   if (whine && !global_silence) \
00964                     SendError (tprintf ("Error in the numcriticals for weapon on #%d! (Should be: %d, is: %d)", mech->mynum, i, num_crits)); \
00965                   return -1; \
00966                 } \
00967               num_crits = 0; \
00968             }
00969 
00970 /* ASSERTION: Weapons must be located next to each other in criticals */
00971 
00972 /* This is a hacked function. Sorry. */
00973 
00974 int FindWeapons_Advanced(MECH * mech, int index, unsigned char *weaparray,
00975                                                  unsigned char *weapdataarray, int *critical,
00976                                                  int whine)
00977 {
00978         int loop;
00979         int weapcount = 0;
00980         int temp, data, lastweap = -1;
00981         int num_crits = 0, i;
00982 
00983         for(loop = 0; loop < MAX_WEAPS_SECTION; loop++) {
00984                 temp = GetPartType(mech, index, loop);
00985                 data = GetPartData(mech, index, loop);
00986                 if(IsWeapon(temp)) {
00987                         temp = Weapon2I(temp);
00988                         if(weapcount == 0) {
00989                                 lastweap = temp;
00990                                 weapdataarray[weapcount] = data;
00991                                 weaparray[weapcount] = temp;
00992                                 critical[weapcount] = loop;
00993                                 weapcount++;
00994                                 num_crits = 1;
00995                                 continue;
00996                         }
00997                         if(!num_crits || temp != lastweap ||
00998                            (num_crits == GetWeaponCrits(mech, temp))) {
00999                                 UGLYTEST;
01000                                 weaparray[weapcount] = temp;
01001                                 weapdataarray[weapcount] = data;
01002                                 critical[weapcount] = loop;
01003                                 lastweap = temp;
01004                                 num_crits = 1;
01005                                 weapcount++;
01006                         } else
01007                                 num_crits++;
01008                 } else
01009                         UGLYTEST;
01010         }
01011         UGLYTEST;
01012         return (weapcount);
01013 }
01014 
01015 int FindAmmunition(MECH * mech, unsigned char *weaparray,
01016                                    unsigned short *ammoarray, unsigned short *ammomaxarray,
01017                                    unsigned int *modearray, int returnall)
01018 {
01019         int loop;
01020         int weapcount = 0;
01021         int temp, data, mode;
01022         int index, i, j, duplicate;
01023 
01024         for(index = 0; index < NUM_SECTIONS; index++)
01025                 for(loop = 0; loop < MAX_WEAPS_SECTION; loop++) {
01026                         temp = GetPartType(mech, index, loop);
01027                         if(IsAmmo(temp)) {
01028                                 data = GetPartData(mech, index, loop);
01029                                 mode = (GetPartAmmoMode(mech, index, loop) & AMMO_MODES);
01030                                 temp = Ammo2Weapon(temp);
01031                                 duplicate = 0;
01032 
01033                                 for(i = 0; i < weapcount; i++) {
01034                                         if(temp == weaparray[i] && mode == modearray[i]) {
01035                                                 if(!(PartIsNonfunctional(mech, index, loop)))
01036                                                         ammoarray[i] += data;
01037                                                 ammomaxarray[i] += FullAmmo(mech, index, loop);
01038                                                 duplicate = 1;
01039                                         }
01040                                 }
01041 
01042                                 if(!duplicate) {
01043                                         weaparray[weapcount] = temp;
01044 
01045                                         if(!(PartIsNonfunctional(mech, index, loop)))
01046                                                 ammoarray[weapcount] = data;
01047                                         else
01048                                                 ammoarray[weapcount] = 0;
01049 
01050                                         ammomaxarray[weapcount] = FullAmmo(mech, index, loop);
01051                                         modearray[weapcount] = mode;
01052 
01053                                         weapcount++;
01054                                 }
01055                         }
01056                 }
01057         /* Then, prune entries with 0 ammo left */
01058         if (!returnall) {
01059         for(i = 0; i < weapcount; i++)
01060                 if(!ammoarray[i]) {
01061                         for(j = i + 1; j < weapcount; j++) {
01062                                 weaparray[j - 1] = weaparray[j];
01063                                 ammoarray[j - 1] = ammoarray[j];
01064                                 ammomaxarray[j - 1] = ammomaxarray[j];
01065                                 modearray[j - 1] = modearray[j];
01066                         }
01067                         i--;
01068                         weapcount--;
01069                 } 
01070         }
01071         return (weapcount);
01072 }
01073 
01074 int FindLegHeatSinks(MECH * mech)
01075 {
01076         int loop;
01077         int heatsinks = 0;
01078 
01079         for(loop = 0; loop < NUM_CRITICALS; loop++) {
01080                 if(GetPartType(mech, LLEG, loop) == I2Special((HEAT_SINK)) &&
01081                    !PartIsNonfunctional(mech, LLEG, loop))
01082                         heatsinks++;
01083                 if(GetPartType(mech, RLEG, loop) == I2Special((HEAT_SINK)) &&
01084                    !PartIsNonfunctional(mech, RLEG, loop))
01085                         heatsinks++;
01086                 /*
01087                  * Added by Kipsta on 8/5/99
01088                  * Quads can get 'arm' HS in the water too
01089                  */
01090 
01091                 if(MechIsQuad(mech)) {
01092                         if(GetPartType(mech, LARM, loop) == I2Special((HEAT_SINK)) &&
01093                            !PartIsNonfunctional(mech, LARM, loop))
01094                                 heatsinks++;
01095                         if(GetPartType(mech, RARM, loop) == I2Special((HEAT_SINK)) &&
01096                            !PartIsNonfunctional(mech, RARM, loop))
01097                                 heatsinks++;
01098                 }
01099         }
01100         return (heatsinks);
01101 }
01102 
01103 /* Added for tic support. */
01104 
01105 /* returns the weapon index- -1 for not found, -2 for destroyed, -3, -4 */
01106 
01107 /* for reloading/recycling */
01108 int FindWeaponNumberOnMech_Advanced(MECH * mech, int number, int *section,
01109                                                                         int *crit, int sight)
01110 {
01111         int loop;
01112         unsigned char weaparray[MAX_WEAPS_SECTION];
01113         unsigned char weapdata[MAX_WEAPS_SECTION];
01114         int critical[MAX_WEAPS_SECTION];
01115         int running_sum = 0;
01116         int num_weaps;
01117         int index;
01118 
01119         for(loop = 0; loop < NUM_SECTIONS; loop++) {
01120                 num_weaps = FindWeapons(mech, loop, weaparray, weapdata, critical);
01121 
01122                 if(num_weaps <= 0)
01123                         continue;
01124 
01125                 if(number < running_sum + num_weaps) {
01126                         /* we found it... */
01127                         index = number - running_sum;
01128                         if(PartIsNonfunctional(mech, loop, critical[index])) {
01129                                 *section = loop;
01130                                 *crit = critical[index];
01131                                 return TIC_NUM_DESTROYED;
01132                         } else if(weapdata[index] > 0 && !sight) {
01133                                 *section = loop;
01134                                 *crit = critical[index];
01135                                 return (MechWeapons[weaparray[index]].type ==
01136                                                 TBEAM) ? TIC_NUM_RECYCLING : TIC_NUM_RELOADING;
01137                         } else {
01138 
01139                                 if(MechSections(mech)[loop].recycle &&
01140                                    (MechType(mech) == CLASS_MECH ||
01141                                         MechType(mech) == CLASS_VEH_GROUND ||
01142                                         MechType(mech) == CLASS_VTOL) && !sight) {
01143 
01144                                         *section = loop;
01145                                         *crit = critical[index];
01146                                         /* just did a physical attack */
01147                                         return TIC_NUM_PHYSICAL;
01148                                 }
01149 
01150                                 /* The recylce data for the weapon is clear- it is ready to fire! */
01151                                 *section = loop;
01152                                 *crit = critical[index];
01153                                 return weaparray[index];
01154                         }
01155                 } else
01156                         running_sum += num_weaps;
01157         }
01158         return -1;
01159 }
01160 
01161 int FindWeaponNumberOnMech(MECH * mech, int number, int *section, int *crit)
01162 {
01163         return FindWeaponNumberOnMech_Advanced(mech, number, section, crit, 0);
01164 }
01165 
01166 int FindWeaponFromIndex(MECH * mech, int weapindx, int *section, int *crit)
01167 {
01168         int loop;
01169         unsigned char weaparray[MAX_WEAPS_SECTION];
01170         unsigned char weapdata[MAX_WEAPS_SECTION];
01171         int critical[MAX_WEAPS_SECTION];
01172         int num_weaps;
01173         int index;
01174 
01175         for(loop = 0; loop < NUM_SECTIONS; loop++) {
01176                 num_weaps = FindWeapons(mech, loop, weaparray, weapdata, critical);
01177                 for(index = 0; index < num_weaps; index++)
01178                         if(weaparray[index] == weapindx) {
01179                                 *section = loop;
01180                                 *crit = critical[index];
01181                                 if(!PartIsNonfunctional(mech, loop, index) &&
01182                                    !WpnIsRecycling(mech, loop, index))
01183                                         return 1;
01184                                 /* Return if not Recycling/Destroyed */
01185                                 /* Otherwise keep looking */
01186                         }
01187         }
01188         return 0;
01189 }
01190 
01191 int FindWeaponIndex(MECH * mech, int number)
01192 {
01193         int loop;
01194         unsigned char weaparray[MAX_WEAPS_SECTION];
01195         unsigned char weapdata[MAX_WEAPS_SECTION];
01196         int critical[MAX_WEAPS_SECTION];
01197         int running_sum = 0;
01198         int num_weaps;
01199         int index;
01200 
01201         if(number < 0)
01202                 return -1;                              /* Anti-crash */
01203         for(loop = 0; loop < NUM_SECTIONS; loop++) {
01204                 num_weaps = FindWeapons(mech, loop, weaparray, weapdata, critical);
01205                 if(num_weaps <= 0)
01206                         continue;
01207                 if(number < running_sum + num_weaps) {
01208                         /* we found it... */
01209                         index = number - running_sum;
01210                         return weaparray[index];
01211                 }
01212                 running_sum += num_weaps;
01213         }
01214         return -1;
01215 }
01216 
01217 
01218 int FullAmmo(MECH * mech, int loc, int pos)
01219 {
01220         int baseammo;
01221 
01222         baseammo = MechWeapons[Ammo2I(GetPartType(mech,loc,pos))].ammoperton;
01223         if((GetPartAmmoMode(mech, loc, pos) & AC_AP_MODE) 
01224                         || (GetPartAmmoMode(mech, loc, pos) & AC_PRECISION_MODE)
01225                         || (GetPartFireMode(mech, loc, pos) & HALFTON_MODE)) {
01226                 return baseammo >> 1;
01227         }
01228         
01229         if((GetPartAmmoMode(mech, loc, pos) & AC_CASELESS_MODE)) {
01230                 return baseammo << 1;
01231         }
01232         
01233         return baseammo;
01234 }
01235 
01236 int findAmmoInSection(MECH * mech, int section, int type, int nogof, int gof)
01237 {
01238         int wIter;
01239 
01240         /* Can't use LBX ammo as normal, but can use Narc and Artemis as normal */
01241         for(wIter = 0; wIter < NUM_CRITICALS; wIter++) {
01242                 if(GetPartType(mech, section, wIter) == type &&
01243                    !PartIsNonfunctional(mech, section, wIter) && (!nogof ||
01244                                                                                                                   !(GetPartAmmoMode
01245                                                                                                                         (mech, section,
01246                                                                                                                          wIter) & nogof))
01247                    && (!gof || (GetPartAmmoMode(mech, section, wIter) & gof))) {
01248 
01249                         if(!PartIsNonfunctional(mech, section, wIter) &&
01250                            GetPartData(mech, section, wIter) > 0)
01251                                 return wIter;
01252                 }
01253         }
01254 
01255         return -1;
01256 }
01257 
01258 int FindAmmoForWeapon_sub(MECH * mech, int weapSection, int weapCritical,
01259                                                   int weapindx, int start, int *section,
01260                                                   int *critical, int nogof, int gof)
01261 {
01262         int loop;
01263         int foundSlot;
01264         int desired;
01265         int wCritType = 0;
01266         int wWeapSize = 0;
01267         int wFirstCrit = 0;
01268         int wDesiredLoc = -1;
01269 
01270         desired = I2Ammo(weapindx);
01271 
01272         /* The data on the desired location */
01273         if((weapSection > -1) && (weapCritical > -1)) {
01274                 wCritType = GetPartType(mech, weapSection, weapCritical);
01275                 wWeapSize = GetWeaponCrits(mech, Weapon2I(wCritType));
01276                 wFirstCrit =
01277                         FindFirstWeaponCrit(mech, weapSection, weapCritical, 0,
01278                                                                 wCritType, wWeapSize);
01279 
01280                 wDesiredLoc = GetPartDesiredAmmoLoc(mech, weapSection, wFirstCrit);
01281 
01282                 if(wDesiredLoc >= 0) {
01283                         foundSlot =
01284                                 findAmmoInSection(mech, wDesiredLoc, desired, nogof, gof);
01285 
01286                         if(foundSlot >= 0) {
01287                                 *section = wDesiredLoc;
01288                                 *critical = foundSlot;
01289 
01290                                 return 1;
01291                         }
01292                 }
01293         }
01294 
01295         /* Now lets search the current section */
01296         foundSlot = findAmmoInSection(mech, start, desired, nogof, gof);
01297 
01298         if(foundSlot >= 0) {
01299                 *section = start;
01300                 *critical = foundSlot;
01301 
01302                 return 1;
01303         }
01304 
01305         /* If all else fails, start hunting for ammo */
01306         for(loop = 0; loop < NUM_SECTIONS; loop++) {
01307                 if((loop == start) || (loop == wDesiredLoc))
01308                         continue;
01309 
01310                 foundSlot = findAmmoInSection(mech, loop, desired, nogof, gof);
01311 
01312                 if(foundSlot >= 0) {
01313                         *section = loop;
01314                         *critical = foundSlot;
01315 
01316                         return 1;
01317                 }
01318         }
01319 
01320         return 0;
01321 }
01322 
01323 int FindAmmoForWeapon(MECH * mech, int weapindx, int start, int *section,
01324                                           int *critical)
01325 {
01326         return FindAmmoForWeapon_sub(mech, -1, -1, weapindx, start, section,
01327                                                                  critical, AMMO_MODES, 0);
01328 }
01329 
01330 int CountAmmoForWeapon(MECH * mech, int weapindx)
01331 {
01332         int wSecIter;
01333         int wSlotIter;
01334         int wcAmmo = 0;
01335         int wAmmoIdx;
01336 
01337         wAmmoIdx = I2Ammo(weapindx);
01338 
01339         for(wSecIter = 0; wSecIter < NUM_SECTIONS; wSecIter++) {
01340                 for(wSlotIter = 0; wSlotIter < NUM_CRITICALS; wSlotIter++) {
01341                         if((GetPartType(mech, wSecIter, wSlotIter) == wAmmoIdx) &&
01342                            !PartIsNonfunctional(mech, wSecIter, wSlotIter) &&
01343                            (GetPartData(mech, wSecIter, wSlotIter) > 0))
01344                                 wcAmmo += GetPartData(mech, wSecIter, wSlotIter);
01345                 }
01346         }
01347 
01348         return wcAmmo;
01349 }
01350 
01351 int FindArtemisForWeapon(MECH * mech, int section, int critical)
01352 {
01353         int critloop;
01354         int desired;
01355 
01356         desired = I2Special(ARTEMIS_IV);
01357         for(critloop = 0; critloop < NUM_CRITICALS; critloop++)
01358                 if(GetPartType(mech, section, critloop) == desired &&
01359                    !PartIsNonfunctional(mech, section, critloop)) {
01360                         if(GetPartData(mech, section, critloop) == critical)
01361                                 return 1;
01362                 }
01363         return 0;
01364 }
01365 
01366 int FindDestructiveAmmo(MECH * mech, int *section, int *critical)
01367 {
01368         int loop;
01369         int critloop;
01370         int maxdamage = 0;
01371         int damage;
01372         int weapindx;
01373         int i;
01374         int type, data;
01375 
01376         for(loop = 0; loop < NUM_SECTIONS; loop++)
01377                 for(critloop = 0; critloop < NUM_CRITICALS; critloop++)
01378                         if(IsAmmo(GetPartType(mech, loop, critloop)) &&
01379                            !PartIsDestroyed(mech, loop, critloop)) {
01380                                 data = GetPartData(mech, loop, critloop);
01381                                 type = GetPartType(mech, loop, critloop);
01382                                 weapindx = Ammo2WeaponI(type);
01383                                 damage = data * MechWeapons[weapindx].damage;
01384                                 if(MechWeapons[weapindx].special & GAUSS)
01385                                         continue;
01386                                 if(IsMissile(weapindx) || IsArtillery(weapindx)) {
01387                                         for(i = 0; MissileHitTable[i].key != -1; i++)
01388                                                 if(MissileHitTable[i].key == weapindx)
01389                                                         damage *= MissileHitTable[i].num_missiles[10];
01390                                 }
01391                                 if(damage > maxdamage) {
01392                                         *section = loop;
01393                                         *critical = critloop;
01394                                         maxdamage = damage;
01395                                 }
01396                         }
01397         return (maxdamage);
01398 }
01399 
01400 int FindInfernoAmmo(MECH * mech, int *section, int *critical)
01401 {
01402         int loop;
01403         int critloop;
01404         int maxdamage = 0;
01405         int damage;
01406         int weapindx;
01407         int i;
01408         int type, data;
01409         int mode;
01410 
01411         for(loop = 0; loop < NUM_SECTIONS; loop++)
01412                 for(critloop = 0; critloop < NUM_CRITICALS; critloop++)
01413                         if(IsAmmo(GetPartType(mech, loop, critloop)) &&
01414                            !PartIsDestroyed(mech, loop, critloop)) {
01415                                 data = GetPartData(mech, loop, critloop);
01416                                 type = GetPartType(mech, loop, critloop);
01417                                 mode = GetPartAmmoMode(mech, loop, critloop);
01418                                 if(!(mode & INFERNO_MODE))
01419                                         continue;
01420                                 weapindx = Ammo2WeaponI(type);
01421                                 damage = data * MechWeapons[weapindx].damage;
01422                                 if(MechWeapons[weapindx].special & GAUSS)
01423                                         continue;
01424                                 if(IsMissile(weapindx) || IsArtillery(weapindx)) {
01425                                         for(i = 0; MissileHitTable[i].key != -1; i++)
01426                                                 if(MissileHitTable[i].key == weapindx)
01427                                                         damage *= MissileHitTable[i].num_missiles[10];
01428                                 }
01429                                 if(damage > maxdamage) {
01430                                         *section = loop;
01431                                         *critical = critloop;
01432                                         maxdamage = damage;
01433                                 }
01434                         }
01435         return (maxdamage);
01436 }
01437 
01438 int FindRoundsForWeapon(MECH * mech, int weapindx)
01439 {
01440         int loop;
01441         int critloop;
01442         int desired;
01443         int found = 0;
01444 
01445         desired = I2Ammo(weapindx);
01446         for(loop = 0; loop < NUM_SECTIONS; loop++)
01447                 for(critloop = 0; critloop < NUM_CRITICALS; critloop++)
01448                         if(GetPartType(mech, loop, critloop) == desired &&
01449                            !PartIsNonfunctional(mech, loop, critloop))
01450                                 found += GetPartData(mech, loop, critloop);
01451         return found;
01452 }
01453 
01454 char *quad_locs[NUM_SECTIONS + 1] = {
01455         "Front Left Leg",
01456         "Front Right Leg",
01457         "Left Torso",
01458         "Right Torso",
01459         "Center Torso",
01460         "Rear Left Leg",
01461         "Rear Right Leg",
01462         "Head",
01463         NULL
01464 };
01465 
01466 char *mech_locs[NUM_SECTIONS + 1] = {
01467         "Left Arm",
01468         "Right Arm",
01469         "Left Torso",
01470         "Right Torso",
01471         "Center Torso",
01472         "Left Leg",
01473         "Right Leg",
01474         "Head",
01475         NULL
01476 };
01477 
01478 char *bsuit_locs[NUM_BSUIT_MEMBERS + 1] = {
01479         "Suit 1",
01480         "Suit 2",
01481         "Suit 3",
01482         "Suit 4",
01483         "Suit 5",
01484         "Suit 6",
01485         "Suit 7",
01486         "Suit 8",
01487         NULL
01488 };
01489 
01490 char *veh_locs[NUM_VEH_SECTIONS + 1] = {
01491         "Left Side",
01492         "Right Side",
01493         "Front Side",
01494         "Aft Side",
01495         "Turret",
01496         "Rotor",
01497         NULL
01498 };
01499 
01500 char *aero_locs[NUM_AERO_SECTIONS + 1] = {
01501         "Nose",
01502         "Left Wing",
01503         "Right Wing",
01504         "Aft Side",
01505         NULL
01506 };
01507 
01508 char *ds_locs[NUM_DS_SECTIONS + 1] = {
01509         "Right Wing",
01510         "Left Wing",
01511         "Left Rear Wing",
01512         "Right Rear Wing",
01513         "Aft",
01514         "Nose",
01515         NULL
01516 };
01517 
01518 char *ds_spher_locs[NUM_DS_SECTIONS + 1] = {
01519         "Front Right Side",
01520         "Front Left Side",
01521         "Rear Left Side",
01522         "Rear Right Side",
01523         "Aft",
01524         "Nose",
01525         NULL
01526 };
01527 
01528 char **ProperSectionStringFromType(int type, int mtype)
01529 {
01530         switch (type) {
01531         case CLASS_BSUIT:
01532                 return bsuit_locs;
01533         case CLASS_MECH:
01534         case CLASS_MW:
01535                 if(mtype == MOVE_QUAD)
01536                         return quad_locs;
01537                 return mech_locs;
01538         case CLASS_VEH_GROUND:
01539         case CLASS_VEH_NAVAL:
01540         case CLASS_VTOL:
01541                 return veh_locs;
01542         case CLASS_AERO:
01543                 return aero_locs;
01544         case CLASS_SPHEROID_DS:
01545                 return ds_spher_locs;
01546         case CLASS_DS:
01547                 return ds_locs;
01548         }
01549         return NULL;
01550 }
01551 
01552 void ArmorStringFromIndex(int index, char *buffer, char type, char mtype)
01553 {
01554         char **locs = ProperSectionStringFromType(type, mtype);
01555         int high = 0;
01556 
01557         switch (type) {
01558         case CLASS_MECH:
01559         case CLASS_MW:
01560                 high = NUM_SECTIONS;
01561                 break;
01562         case CLASS_VEH_GROUND:
01563         case CLASS_VEH_NAVAL:
01564                 high = (NUM_VEH_SECTIONS - 1);
01565                 break;
01566         case CLASS_VTOL:
01567                 high = NUM_VEH_SECTIONS;
01568                 break;
01569         case CLASS_AERO:
01570                 high = NUM_AERO_SECTIONS;
01571                 break;
01572         case CLASS_SPHEROID_DS:
01573                 high = NUM_DS_SECTIONS;
01574         case CLASS_DS:
01575                 high = NUM_DS_SECTIONS;
01576                 break;
01577         case CLASS_BSUIT:
01578                 high = NUM_BSUIT_MEMBERS;
01579                 break;
01580         default:
01581                 strcpy(buffer, "Invalid!!");
01582                 return;
01583         }
01584         if(high > 0 && index < high && locs) {
01585                 strcpy(buffer, locs[index]);
01586                 return;
01587         }
01588         strcpy(buffer, "Invalid!!");
01589 }
01590 
01591 int IsInWeaponArc(MECH * mech, float x, float y, int section, int critical)
01592 {
01593         int weaponarc, isrear;
01594         int wantarc = NOARC;
01595 
01596         if(MechType(mech) == CLASS_MECH && (section == LLEG || section == RLEG
01597                                                                                 || (MechIsQuad(mech)
01598                                                                                         && (section == LARM
01599                                                                                                 || section == RARM)))) {
01600                 int ts = MechStatus(mech) & (TORSO_LEFT | TORSO_RIGHT);
01601                 MechStatus(mech) &= ~(ts);
01602                 weaponarc = InWeaponArc(mech, x, y);
01603                 MechStatus(mech) |= ts;
01604         } else
01605                 weaponarc = InWeaponArc(mech, x, y);
01606 
01607         switch (MechType(mech)) {
01608         case CLASS_MECH:
01609         case CLASS_BSUIT:
01610         case CLASS_MW:
01611                 if(GetPartFireMode(mech, section, critical) & REAR_MOUNT)
01612                         wantarc = REARARC;
01613                 else if(section == LARM && (MechStatus(mech) & FLIPPED_ARMS))
01614                         wantarc = REARARC | LSIDEARC;
01615                 else if(section == LARM)
01616                         wantarc = FORWARDARC | LSIDEARC;
01617                 else if(section == RARM && (MechStatus(mech) & FLIPPED_ARMS))
01618                         wantarc = REARARC | RSIDEARC;
01619                 else if(section == RARM)
01620                         wantarc = FORWARDARC | RSIDEARC;
01621                 else
01622                         wantarc = FORWARDARC;
01623                 break;
01624         case CLASS_VEH_GROUND:
01625         case CLASS_VEH_NAVAL:
01626         case CLASS_VTOL:
01627                 switch (section) {
01628                 case TURRET:
01629                         wantarc = TURRETARC;
01630                         break;
01631                 case FSIDE:
01632                         wantarc = FORWARDARC;
01633                         break;
01634                 case LSIDE:
01635                         wantarc = LSIDEARC;
01636                         break;
01637                 case RSIDE:
01638                         wantarc = RSIDEARC;
01639                         break;
01640                 case BSIDE:
01641                         wantarc = REARARC;
01642                         break;
01643                 }
01644                 break;
01645         case CLASS_DS:
01646                 switch (section) {
01647                 case DS_NOSE:
01648                         wantarc = FORWARDARC;
01649                         break;
01650                 case DS_LWING:
01651                 case DS_LRWING:
01652                         wantarc = LSIDEARC;
01653                         break;
01654                 case DS_RWING:
01655                 case DS_RRWING:
01656                         wantarc = RSIDEARC;
01657                         break;
01658                 case DS_AFT:
01659                         wantarc = REARARC;
01660                         break;
01661                 }
01662                 break;
01663         case CLASS_SPHEROID_DS:
01664                 switch (section) {
01665                 case DS_NOSE:
01666                         wantarc = FORWARDARC;
01667                         break;
01668                 case DS_LWING:
01669                         wantarc = FORWARDARC | LSIDEARC;
01670                         break;
01671                 case DS_LRWING:
01672                         wantarc = REARARC | LSIDEARC;
01673                         break;
01674                 case DS_RWING:
01675                         wantarc = FORWARDARC | RSIDEARC;
01676                         break;
01677                 case DS_RRWING:
01678                         wantarc = REARARC | RSIDEARC;
01679                         break;
01680                 case DS_AFT:
01681                         wantarc = REARARC;
01682                         break;
01683                 }
01684                 break;
01685 
01686         case CLASS_AERO:
01687                 isrear = (GetPartFireMode(mech, section, critical) & REAR_MOUNT);
01688                 switch (section) {
01689                 case AERO_NOSE:
01690                         wantarc = FORWARDARC | LSIDEARC | RSIDEARC;
01691                         break;
01692                 case AERO_LWING:
01693                         wantarc = LSIDEARC | (isrear ? REARARC : FORWARDARC);
01694                         break;
01695                 case AERO_RWING:
01696                         wantarc = RSIDEARC | (isrear ? REARARC : FORWARDARC);
01697                         break;
01698                 case AERO_AFT:
01699                         wantarc = REARARC;
01700                         break;
01701                 }
01702                 break;
01703         }
01704         return wantarc ? (wantarc & weaponarc) : 0;
01705 }
01706 
01707 int GetWeaponCrits(MECH * mech, int weapindx)
01708 {
01709         return (MechType(mech) ==
01710                         CLASS_MECH) ? (MechWeapons[weapindx].criticals) : 1;
01711 }
01712 
01713 int listmatch(char **foo, char *mat)
01714 {
01715         int i;
01716 
01717         for(i = 0; foo[i]; i++)
01718                 if(!strcasecmp(foo[i], mat))
01719                         return i;
01720         return -1;
01721 }
01722 
01723 /* Takes care of :
01724    JumpSpeed
01725    Numsinks
01726 
01727    TODO: More support(?)
01728  */
01729 
01730 void do_sub_magic(MECH * mech, int loud)
01731 {
01732         int jjs = 0;
01733         int hses = 0;
01734         int wanths, wanths_f;
01735         int shs_size = HS_Size(mech);
01736         int hs_eff = HS_Efficiency(mech);
01737         int i, j;
01738         int inthses = MechEngineSize(mech) / 25;
01739         int dest_hses = 0;
01740         int maxjjs = (int) ((float) MechMaxSpeed(mech) * MP_PER_KPH * 2 / 3);
01741 
01742         if(MechSpecials(mech) & ICE_TECH)
01743                 inthses = 0;
01744         for(i = 0; i < NUM_SECTIONS; i++)
01745                 for(j = 0; j < CritsInLoc(mech, i); j++)
01746                         switch (Special2I(GetPartType(mech, i, j))) {
01747                         case HEAT_SINK:
01748                                 hses++;
01749                                 if(PartIsNonfunctional(mech, i, j))
01750                                         dest_hses++;
01751                                 break;
01752                         case JUMP_JET:
01753                                 jjs++;
01754                                 break;
01755                         }
01756         hses +=
01757                 MIN(MechRealNumsinks(mech) * shs_size / hs_eff, inthses * shs_size);
01758         if(jjs > maxjjs) {
01759                 if(loud)
01760                         SendError(tprintf
01761                                           ("Error in #%d (%s): %d JJs, yet %d maximum available (due to walk MPs)?",
01762                                            mech->mynum, MechType_Ref(mech), jjs, maxjjs));
01763 
01764                 jjs = maxjjs;
01765         }
01766         MechJumpSpeed(mech) = MP1 * jjs;
01767         wanths_f = (hses / shs_size) * hs_eff;
01768         wanths = wanths_f - (dest_hses * hs_eff / shs_size);
01769         if(loud)
01770                 MechNumOsinks(mech) =
01771                         wanths - MIN(MechRealNumsinks(mech), inthses * hs_eff);
01772         if(wanths != MechRealNumsinks(mech) && loud) {
01773                 SendError(tprintf
01774                                   ("Error in #%d (%s): Set HS: %d. Existing HS: %d. Difference: %d. Please %s.",
01775                                    mech->mynum, MechType_Ref(mech), MechRealNumsinks(mech),
01776                                    wanths, MechRealNumsinks(mech) - wanths,
01777                                    wanths <
01778                                    MechRealNumsinks(mech) ? "add the extra HS critical(s)" :
01779                                    "fix the template"));
01780         } else
01781                 MechRealNumsinks(mech) = wanths;
01782         MechNumOsinks(mech) = wanths_f;
01783 }
01784 
01785 #define CV(fun) fun(mech) = fun(&opp)
01786 
01787 /* Values to take care of:
01788    - JumpSpeed
01789    - MaxSpeed
01790    - Numsinks
01791    - EngineHeat
01792    - PilotSkillBase
01793    - LRS/Tac/ScanRange
01794    - BTH
01795 
01796    Status:
01797    - Destroyed
01798 
01799    Critstatus:
01800    - kokonaan paitsi
01801 
01802    section(s) / basetohit
01803  */
01804 
01805 void do_magic(MECH * mech)
01806 {
01807         MECH opp;
01808         int i, j, t;
01809         int mask = 0;
01810         int tankCritMask = 0;
01811 
01812         if(MechType(mech) != CLASS_MECH)
01813                 tankCritMask =
01814                         (TURRET_LOCKED | TURRET_JAMMED | TAIL_ROTOR_DESTROYED |
01815                          CREW_STUNNED);
01816 
01817         /* stop the burning */
01818         StopBurning(mech);
01819         StopPerformingAction(mech);
01820 
01821         memcpy(&opp, mech, sizeof(MECH));
01822         mech_loadnew(GOD, &opp, MechType_Ref(mech));
01823         MechEngineSizeV(mech) = MechEngineSizeC(&opp);  /* From intact template */
01824         opp.mynum = -1;
01825         /* Ok.. It's at perfect condition. Start inflicting some serious crits.. */
01826         for(i = 0; i < NUM_SECTIONS; i++)
01827                 for(j = 0; j < CritsInLoc(mech, i); j++) {
01828                         SetPartType(&opp, i, j, GetPartType(mech, i, j));
01829                         SetPartBrand(&opp, i, j, GetPartBrand(mech, i, j));
01830                         SetPartData(&opp, i, j, 0);
01831                         SetPartFireMode(&opp, i, j, 0);
01832                         SetPartAmmoMode(&opp, i, j, 0);
01833                 }
01834         if(MechType(mech) == CLASS_MECH)
01835                 do_sub_magic(&opp, 0);
01836         MechNumOsinks(mech) = MechNumOsinks(&opp);
01837         for(i = 0; i < NUM_SECTIONS; i++) {
01838                 if(MechType(mech) == CLASS_MECH) {
01839                         for(j = 0; j < CritsInLoc(mech, i); j++) {
01840                                 if(PartIsDestroyed(mech, i, j)) {
01841                                         if(!PartIsDestroyed(&opp, i, j)) {
01842                                                 if(!IsAmmo((t = GetPartType(mech, i, j)))) {
01843                                                         if(!IsWeapon(t))
01844                                                                 HandleMechCrit(&opp, NULL, 0, i, j, t,
01845                                                                                            GetPartData(mech, i, j));
01846                                                 }
01847                                         }
01848                                 } else {
01849                                         t = GetPartType(mech, i, j);
01850                                         if(IsAMS(Weapon2I(t))) {
01851                                                 if(MechWeapons[Weapon2I(t)].special & CLAT)
01852                                                         MechSpecials(mech) |= CL_ANTI_MISSILE_TECH;
01853                                                 else
01854                                                         MechSpecials(mech) |= IS_ANTI_MISSILE_TECH;
01855                                         }
01856                                         GetPartFireMode(mech, i, j) &=
01857                                                 ~(OS_USED | ROCKET_FIRED | IS_JETTISONED_MODE);
01858                                 }
01859                         }
01860                 }
01861 
01862                 MechSections(mech)[i].config &= ~STABILIZERS_DESTROYED;
01863 
01864                 if(SectIsDestroyed(mech, i))
01865                         DestroySection(&opp, NULL, 0, i);
01866                 if(MechStall(mech) > 0)
01867                         UnSetSectBreached(mech, i);     /* Just in case ; this leads to 'unbreachable' legs once you've 'done your time' once */
01868         }
01869         CV(MechJumpSpeed);
01870         CV(MechMaxSpeed);
01871         CV(MechRealNumsinks);
01872         CV(MechEngineHeat);
01873         CV(MechPilotSkillBase);
01874         CV(MechLRSRange);
01875         CV(MechTacRange);
01876         CV(MechScanRange);
01877         CV(MechBTH);
01878         MechCritStatus(mech) &= mask;
01879         MechCritStatus(mech) |= MechCritStatus(&opp) & (~mask);
01880 
01881         MechTankCritStatus(mech) &= tankCritMask;
01882         MechTankCritStatus(mech) |= MechTankCritStatus(&opp) & (~tankCritMask);
01883 
01884         for(i = 0; i < NUM_SECTIONS; i++) {
01885                 MechSections(mech)[i].basetohit = MechSections(&opp)[i].basetohit;
01886                 MechSections(mech)[i].specials = MechSections(&opp)[i].specials;
01887                 MechSections(mech)[i].specials &=
01888                         ~(INARC_HOMING_ATTACHED | INARC_HAYWIRE_ATTACHED |
01889                           INARC_ECM_ATTACHED | INARC_NEMESIS_ATTACHED);
01890         }
01891 
01892         /* Case of undestroying */
01893         if(!Destroyed(&opp) && Destroyed(mech))
01894                 MechStatus(mech) &= ~DESTROYED;
01895         else if(Destroyed(&opp) && !Destroyed(mech))
01896                 MechStatus(mech) |= DESTROYED;
01897         if(!Destroyed(mech) && MechType(mech) != CLASS_MECH)
01898                 EvalBit(MechStatus(mech), FALLEN, Fallen(&opp));
01899         update_specials(mech);
01900 }
01901 
01902 void mech_RepairPart(MECH * mech, int loc, int pos)
01903 {
01904         int t = GetPartType(mech, loc, pos);
01905 
01906         UnDestroyPart(mech, loc, pos);
01907         if(IsWeapon(t) || IsAmmo(t)) {
01908                 SetPartData(mech, loc, pos, 0);
01909                 GetPartFireMode(mech, loc, pos) &=
01910                         ~(OS_USED | IS_JETTISONED_MODE | ROCKET_FIRED);
01911         } else if(IsSpecial(t)) {
01912                 switch (Special2I(t)) {
01913                 case TARGETING_COMPUTER:
01914                 case HEAT_SINK:
01915                 case LIFE_SUPPORT:
01916                 case COCKPIT:
01917                 case SENSORS:
01918                 case JUMP_JET:
01919                 case ENGINE:
01920                 case GYRO:
01921                 case SHOULDER_OR_HIP:
01922                 case LOWER_ACTUATOR:
01923                 case UPPER_ACTUATOR:
01924                 case HAND_OR_FOOT_ACTUATOR:
01925                 case C3_MASTER:
01926                 case C3_SLAVE:
01927                 case C3I:
01928                 case ECM:
01929                 case ANGELECM:
01930                 case NULL_SIGNATURE_SYSTEM:
01931                 case BEAGLE_PROBE:
01932                 case ARTEMIS_IV:
01933                 case TAG:
01934                 case BLOODHOUND_PROBE:
01935                         /* Magic stuff here :P */
01936                         if(MechType(mech) == CLASS_MECH)
01937                                 do_magic(mech);
01938                         break;
01939                 }
01940         }
01941 }
01942 
01943 int no_locations_destroyed(MECH * mech)
01944 {
01945         int i;
01946 
01947         for(i = 0; i < NUM_SECTIONS; i++)
01948                 if(GetSectOInt(mech, i) && SectIsDestroyed(mech, i))
01949                         return 0;
01950         return 1;
01951 }
01952 
01953 void mech_ReAttach(MECH * mech, int loc)
01954 {
01955         if(!SectIsDestroyed(mech, loc))
01956                 return;
01957         UnSetSectDestroyed(mech, loc);
01958         UnSetSectFlooded(mech, loc);
01959         SetSectInt(mech, loc, GetSectOInt(mech, loc));
01960         if(is_aero(mech))
01961                 SetSectInt(mech, loc, 1);
01962         if(MechType(mech) != CLASS_MECH) {
01963                 if(no_locations_destroyed(mech) && IsDS(mech))
01964                         MechStatus(mech) &= ~DESTROYED;
01965                 return;
01966         }
01967 }
01968 
01969 void mech_ReplaceSuit(MECH * mech, int loc)
01970 {
01971         if(!SectIsDestroyed(mech, loc))
01972                 return;
01973 
01974         UnSetSectDestroyed(mech, loc);
01975         SetSectInt(mech, loc, GetSectOInt(mech, loc));
01976 }
01977 
01978 /*
01979  * Added for new flood code by Kipsta
01980  * 8/4/99
01981  */
01982 
01983 void mech_ReSeal(MECH * mech, int loc)
01984 {
01985         int i;
01986 
01987         if(SectIsDestroyed(mech, loc))
01988                 return;
01989         if(!SectIsFlooded(mech, loc))
01990                 return;
01991 
01992         UnSetSectFlooded(mech, loc);
01993 
01994         for(i = 0; i < CritsInLoc(mech, loc); i++) {
01995                 if(PartIsDisabled(mech, loc, i)) {
01996                         if(!PartIsBroken(mech, loc, i) && !PartIsDamaged(mech, loc, i))
01997                                 mech_RepairPart(mech, loc, i);
01998                         else
01999                                 UnDisablePart(mech, loc, i);
02000                 }
02001         }
02002 }
02003 
02004 void mech_Detach(MECH * mech, int loc)
02005 {
02006         if(SectIsDestroyed(mech, loc))
02007                 return;
02008         DestroySection(mech, NULL, 0, loc);
02009 }
02010 
02011 /* Figures out how much ammo there is when we're 'fully loaded', and
02012    fills it */
02013 void mech_FillPartAmmo(MECH * mech, int loc, int pos)
02014 {
02015         int t, to;
02016 
02017         t = GetPartType(mech, loc, pos);
02018 
02019         if(!IsAmmo(t))
02020                 return;
02021         if(!(to = MechWeapons[Ammo2Weapon(t)].ammoperton))
02022                 return;
02023         SetPartData(mech, loc, pos, FullAmmo(mech, loc, pos));
02024 }
02025 
02026 int AcceptableDegree(int d)
02027 {
02028         /*
02029          * Silly billies, integer modulo (division) is still faster than loops.
02030          * And probably slightly faster than branches, too, but let's not worry
02031          * about that.
02032          */
02033         if (d < 0) {
02034                 return (d % 360) + 360;
02035         } else if (d >= 360) {
02036                 return (d % 360);
02037         } else {
02038                 return d;
02039         }
02040 }
02041 
02042 void MarkForLOSUpdate(MECH * mech)
02043 {
02044         MAP *mech_map;
02045 
02046         if(!(mech_map = getMap(mech->mapindex)))
02047                 return;
02048         mech_map->moves++;
02049         mech_map->mechflags[mech->mapnumber] = 1;
02050 }
02051 
02052 void multi_weap_sel(MECH * mech, dbref player, char *buffer, int bitbybit,
02053                                         int (*foo) (MECH *, dbref, int, int))
02054 {
02055         /* Insight: buffer contains stuff in form:
02056            <num>
02057            <num>-<num>
02058            <num>,..
02059            <num>-<num>,..
02060          */
02061         /* Ugly recursive piece of code :> */
02062         char *c;
02063         int i1, i2, i3;
02064         int section, critical;
02065 
02066         skipws(buffer);
02067         if((c = strstr(buffer, ","))) {
02068                 *c = 0;
02069                 c++;
02070         }
02071         if(sscanf(buffer, "%d-%d", &i1, &i2) == 2) {
02072                 DOCHECK(i1 < 0 ||
02073                                 i1 >= MAX_WEAPONS_PER_MECH,
02074                                 tprintf("Invalid first number in range (%d)", i1));
02075                 DOCHECK(i2 < 0 ||
02076                                 i2 >= MAX_WEAPONS_PER_MECH,
02077                                 tprintf("Invalid second number in range (%d)", i2));
02078                 if(i1 > i2) {
02079                         i3 = i1;
02080                         i1 = i2;
02081                         i2 = i3;
02082                 }
02083         } else {
02084                 DOCHECK(Readnum(i1, buffer), tprintf("Invalid value: %s", buffer));
02085                 DOCHECK(i1 < 0 ||
02086                                 i1 >= MAX_WEAPONS_PER_MECH,
02087                                 tprintf("Invalid weapon number: %d", i1));
02088                 i2 = i1;
02089         }
02090         if(bitbybit / 2) {
02091                 DOCHECK(i2 >= NUM_TICS, tprintf("There are only %d tics!", i2));
02092         } else {
02093                 DOCHECK(!(FindWeaponNumberOnMech(mech, i2, &section,
02094                                                                                  &critical) != -1),
02095                                 tprintf("Error: the mech doesn't HAVE %d weapons!", i2 + 1));
02096         }
02097         if(bitbybit % 2) {
02098                 for(i3 = i1; i3 <= i2; i3++)
02099                         if(foo(mech, player, i3, i3))
02100                                 return;
02101         } else if(foo(mech, player, i1, i2))
02102                 return;
02103         if(c)
02104                 multi_weap_sel(mech, player, c, bitbybit, foo);
02105 }
02106 
02107 int Roll()
02108 {
02109         int i = Number(1, 6) + Number(1, 6);
02110 
02111         rollstat.rolls[i - 2]++;
02112         rollstat.totrolls++;
02113         return i;
02114 }
02115 
02116 int MyHexDist(int x1, int y1, int x2, int y2, int tc)
02117 {
02118         int xd = abs(x2 - x1);
02119         int yd = abs(y2 - y1);
02120         int hm;
02121 
02122         /* _the_ base case */
02123         if(x1 == x2)
02124                 return yd;
02125         /*
02126            +
02127            +
02128            +
02129            +
02130          */
02131         if((hm = (xd / 2)) <= yd)
02132                 return (yd - hm) + tc + xd;
02133 
02134         /*
02135            +     +
02136            +   +
02137            + +
02138            +
02139          */
02140         if(!yd)
02141                 return (xd + tc);
02142         /*
02143            +
02144            +
02145            +   +
02146            + +
02147            +
02148          */
02149         /* For now, same as above */
02150         return (xd + tc);
02151 }
02152 
02153 int CountDestroyedLegs(MECH * objMech)
02154 {
02155         int wcDeadLegs = 0;
02156 
02157         if(MechType(objMech) != CLASS_MECH)
02158                 return 0;
02159 
02160         if(MechIsQuad(objMech)) {
02161                 if(IsLegDestroyed(objMech, LARM))
02162                         wcDeadLegs++;
02163 
02164                 if(IsLegDestroyed(objMech, RARM))
02165                         wcDeadLegs++;
02166         }
02167 
02168         if(IsLegDestroyed(objMech, LLEG))
02169                 wcDeadLegs++;
02170 
02171         if(IsLegDestroyed(objMech, RLEG))
02172                 wcDeadLegs++;
02173 
02174         return wcDeadLegs;
02175 }
02176 
02177 int IsLegDestroyed(MECH * objMech, int wLoc)
02178 {
02179         return (SectIsDestroyed(objMech, wLoc) || SectIsBreached(objMech, wLoc)
02180                         || SectIsFlooded(objMech, wLoc));
02181 }
02182 
02183 int IsMechLegLess(MECH * objMech)
02184 {
02185         int wcMaxLegs = 0;
02186 
02187         if(MechType(objMech) != CLASS_MECH)
02188                 return 0;
02189 
02190         if(MechIsQuad(objMech))
02191                 wcMaxLegs = 4;
02192         else
02193                 wcMaxLegs = 2;
02194 
02195         if(CountDestroyedLegs(objMech) >= wcMaxLegs)
02196                 return 1;
02197 
02198         return 0;
02199 }
02200 
02201 int FindFirstWeaponCrit(MECH * objMech, int wLoc, int wSlot,
02202                                                 int wStartSlot, int wCritType, int wMaxCrits)
02203 {
02204         int wCritsInLoc = 0;
02205         int wCritIter, wFirstCrit;
02206 
02207         /*
02208          * First let's count the number of crits in this loc, incase
02209          * we have two of the same weapon
02210          */
02211 
02212         wFirstCrit = -1;
02213 
02214         for(wCritIter = wStartSlot; wCritIter < NUM_CRITICALS; wCritIter++) {
02215                 if(GetPartType(objMech, wLoc, wCritIter) == wCritType) {
02216                         wCritsInLoc++;
02217 
02218                         if(wFirstCrit == -1)
02219                                 wFirstCrit = wCritIter;
02220                 }
02221         }
02222 
02223         if((wFirstCrit > -1) && (wSlot == -1))
02224                 return wFirstCrit;
02225 
02226         /*
02227          * Now, if there are more crits than our max crit, then we have
02228          * two of the same weapon in this location. We need to figure
02229          * out which weapon this crit actually belongs to.
02230          */
02231         if(wCritsInLoc > wMaxCrits) {
02232                 /*
02233                  * Well, we have thje first crit of the first instance, so
02234                  * let's see if our crit falls out of that range.. if so, then
02235                  * we need to figure out what range it actually falls into.
02236                  */
02237                 if((wFirstCrit + wMaxCrits) <= wSlot)
02238                         wFirstCrit =
02239                                 FindFirstWeaponCrit(objMech, wLoc, wSlot,
02240                                                                         (wFirstCrit + wMaxCrits), wCritType,
02241                                                                         wMaxCrits);
02242         }
02243 
02244         return wFirstCrit;
02245 }
02246 
02247 int checkAllSections(MECH * mech, int specialToFind)
02248 {
02249         int i;
02250 
02251         for(i = 0; i < NUM_SECTIONS; i++) {
02252                 if(checkSectionForSpecial(mech, specialToFind, i))
02253                         return 1;
02254         }
02255 
02256         return 0;
02257 }
02258 
02259 int checkSectionForSpecial(MECH * mech, int specialToFind, int wSec)
02260 {
02261         if(SectIsDestroyed(mech, wSec))
02262                 return 0;
02263 
02264         if(MechSections(mech)[wSec].specials & specialToFind)
02265                 return 1;
02266 
02267         return 0;
02268 }
02269 
02270 int getRemainingInternalPercent(MECH * mech)
02271 {
02272         int i;
02273         float wMax = 0;
02274         float wRemaining = 0;
02275 
02276         for(i = 0; i < NUM_SECTIONS; i++) {
02277                 wMax += GetSectOInt(mech, i);
02278 
02279                 wRemaining += GetSectInt(mech, i);
02280         }
02281 
02282         if(wMax == 0)
02283                 return 0;
02284 
02285         return ((wRemaining / wMax) * 100);
02286 }
02287 
02288 int getRemainingArmorPercent(MECH * mech)
02289 {
02290         int i;
02291         float wMax = 0;
02292         float wRemaining = 0;
02293 
02294         for(i = 0; i < NUM_SECTIONS; i++) {
02295                 wMax += GetSectOArmor(mech, i);
02296                 wMax += GetSectORArmor(mech, i);
02297 
02298                 wRemaining += GetSectArmor(mech, i);
02299                 wRemaining += GetSectRArmor(mech, i);
02300         }
02301 
02302         if(wMax == 0)
02303                 return 0;
02304 
02305         return ((wRemaining / wMax) * 100);
02306 }
02307 
02308 int FindObj(MECH * mech, int loc, int type)
02309 {
02310         int count = 0, i;
02311 
02312         for(i = 0; i < NUM_CRITICALS; i++)
02313                 if(GetPartType(mech, loc, i) == type)
02314                         if(!PartIsNonfunctional(mech, loc, i))
02315                                 count++;
02316         return count;
02317 }
02318 
02319 int FindObjWithDest(MECH * mech, int loc, int type)
02320 {
02321         int count = 0, i;
02322 
02323         for(i = 0; i < NUM_CRITICALS; i++)
02324                 if(GetPartType(mech, loc, i) == type)
02325                         count++;
02326         return count;
02327 }
02328 
02329 /* Usage:
02330    mech      = Mech who's looking for people
02331    mech_map  = Map mech's on
02332    x,y       = Target hex
02333    needlos   = Bitvector
02334    1 = Require LOS
02335    2 = We actually want a mech that is friendly and has LOS to hex
02336  */
02337 MECH *find_mech_in_hex(MECH * mech, MAP * mech_map, int x, int y, int needlos)
02338 {
02339         int loop;
02340         MECH *target;
02341 
02342         for(loop = 0; loop < mech_map->first_free; loop++)
02343                 if(mech_map->mechsOnMap[loop] != mech->mynum &&
02344                    mech_map->mechsOnMap[loop] != -1) {
02345                         target = (MECH *) FindObjectsData(mech_map->mechsOnMap[loop]);
02346                         if(!target)
02347                                 continue;
02348                         if(!(MechX(target) == x && MechY(target) == y) && !(needlos & 2))
02349                                 continue;
02350                         if(needlos) {
02351                                 if(needlos & 1)
02352                                         if(!InLineOfSight(mech, target, x, y,
02353                                                                           FlMechRange(mech_map, mech, target)))
02354                                                 continue;
02355                                 if(needlos & 2) {
02356                                         if(MechTeam(mech) != MechTeam(target))
02357                                                 continue;
02358                                         if(!(MechSeesHex(target, mech_map, x, y)))
02359                                                 continue;
02360                                         if(mech == target)
02361                                                 continue;
02362                                 }
02363                         }
02364                         return target;
02365                 }
02366         return NULL;
02367 }
02368 
02369 int FindAndCheckAmmo(MECH * mech,
02370                                          int weapindx,
02371                                          int section,
02372                                          int critical,
02373                                          int *ammoLoc,
02374                                          int *ammoCrit, int *ammoLoc1, int *ammoCrit1,
02375                                          int *wGattlingShots)
02376 {
02377         int mod, nmod = 0;
02378         int wMaxShots = 0;
02379         int wRoundsToCheck = 1;
02380         int wWeapMode = GetPartFireMode(mech, section, critical);
02381         int tResetMode = 0;
02382         dbref player = GunPilot(mech);
02383 
02384         /* Return if it's an energy or PC weapon */
02385         if(MechWeapons[weapindx].type == TBEAM ||
02386            MechWeapons[weapindx].type == THAND)
02387                 return 1;
02388 
02389         /* Check for rocket launchers */
02390         if(MechWeapons[weapindx].special == ROCKET) {
02391                 DOCHECK0(wWeapMode & ROCKET_FIRED,
02392                                  "That weapon has already been used!");
02393                 return 1;
02394         }
02395 
02396         /* Check for One-Shots */
02397         if(wWeapMode & OS_MODE) {
02398                 DOCHECK0(GetPartFireMode(mech, section, critical) & OS_USED,
02399                                  "That weapon has already been used!");
02400                 return 1;
02401         }
02402         /* Check RACs - No special ammo type possible */
02403         if(MechWeapons[weapindx].special & RAC) {
02404                 wMaxShots = CountAmmoForWeapon(mech, weapindx);
02405 
02406                 if((wWeapMode & RAC_TWOSHOT_MODE) && (wMaxShots < 2)) {
02407                         GetPartFireMode(mech, section, critical) &= ~RAC_TWOSHOT_MODE;
02408 
02409                         return 1;
02410                 }
02411 
02412                 if((wWeapMode & RAC_FOURSHOT_MODE) && (wMaxShots < 4)) {
02413                         GetPartFireMode(mech, section, critical) &= ~RAC_FOURSHOT_MODE;
02414 
02415                         return 1;
02416                 }
02417 
02418                 if((wWeapMode & RAC_SIXSHOT_MODE) && (wMaxShots < 6)) {
02419                         GetPartFireMode(mech, section, critical) &= ~RAC_SIXSHOT_MODE;
02420 
02421                         return 1;
02422                 }
02423         }
02424         /* Check GMGs */
02425         if(wWeapMode & GATTLING_MODE) {
02426                 wMaxShots = CountAmmoForWeapon(mech, weapindx);
02427 
02428                 /*
02429                  * Gattling MGs suck up damage * 3 in ammo
02430                  */
02431 
02432                 if((wMaxShots / 3) < *wGattlingShots)
02433                         *wGattlingShots = MAX((wMaxShots / 3), 1);
02434         }
02435         /* If we're an ULTRA or RFAC, we need to check for multiple rounds */
02436         if((wWeapMode & ULTRA_MODE) || (wWeapMode & RFAC_MODE))
02437                 wRoundsToCheck = 2;
02438 
02439         mod = GetPartAmmoMode(mech, section, critical) & AMMO_MODES;
02440 
02441         if(!mod) {
02442                 DOCHECK0(!FindAmmoForWeapon_sub(mech, section, critical, weapindx,
02443                                                                                 section, ammoLoc, ammoCrit,
02444                                                                                 AMMO_MODES, 0),
02445                                  "You don't have any ammo for that weapon stored on this mech!");
02446 
02447                 DOCHECK0(!GetPartData(mech, *ammoLoc, *ammoCrit),
02448                                  "You are out of ammo for that weapon!");
02449 
02450                 if(wRoundsToCheck > 1) {
02451                         GetPartData(mech, *ammoLoc, *ammoCrit)--;
02452 
02453                         if(FindAmmoForWeapon_sub(mech, section, critical, weapindx,
02454                                                                          section, ammoLoc1, ammoCrit1, AMMO_MODES,
02455                                                                          0)) {
02456                                 if(!GetPartData(mech, *ammoLoc1, *ammoCrit1))
02457                                         tResetMode = 1;
02458                         } else
02459                                 tResetMode = 1;
02460 
02461                         if(tResetMode)
02462                                 GetPartFireMode(mech, section, critical) &= ~wWeapMode;
02463 
02464                         GetPartData(mech, *ammoLoc, *ammoCrit)++;
02465                 }
02466         } else {
02467                 if(IsArtillery(weapindx))
02468                         nmod = (~mod) & ARTILLERY_MODES;
02469                 else
02470                         nmod = (~mod) & AMMO_MODES;
02471                 mod = (mod & AMMO_MODES);
02472 
02473                 DOCHECK0(!FindAmmoForWeapon_sub(mech, section, critical, weapindx,
02474                                                                                 section, ammoLoc, ammoCrit, nmod,
02475                                                                                 mod),
02476                                  "You don't have any ammo for that weapon stored on this mech!");
02477 
02478                 DOCHECK0(!GetPartData(mech, *ammoLoc, *ammoCrit),
02479                                  "You are out of the special ammo type for that weapon!");
02480 
02481                 if(wRoundsToCheck > 1) {
02482                         GetPartData(mech, *ammoLoc, *ammoCrit)--;
02483 
02484                         if(FindAmmoForWeapon_sub(mech, section, critical, weapindx,
02485                                                                          section, ammoLoc1, ammoCrit1, nmod,
02486                                                                          mod)) {
02487                                 if(!GetPartData(mech, *ammoLoc1, *ammoCrit1))
02488                                         tResetMode = 1;
02489                         } else
02490                                 tResetMode = 1;
02491 
02492                         if(tResetMode)
02493                                 GetPartFireMode(mech, section, critical) &= ~wWeapMode;
02494 
02495                         GetPartData(mech, *ammoLoc, *ammoCrit)++;
02496                 }
02497         }
02498 
02499         return 1;
02500 }
02501 
02502 void ChannelEmitKill(MECH * mech, MECH * attacker)
02503 {
02504         if(!attacker)
02505                 attacker = mech;
02506 
02507         SendDebug(tprintf("#%d has been killed by #%d", mech->mynum,
02508                                           attacker->mynum));
02509         if(IsDS(mech))
02510                 SendDSInfo(tprintf("#%d has been killed by #%d", mech->mynum,
02511                                                    attacker->mynum));
02512         if(mech->mynum > 0 && attacker->mynum > 0)
02513                 did_it(attacker->mynum, mech->mynum, 0, NULL, 0, NULL, A_AMECHDEST,
02514                            (char **) NULL, 0);
02515 }
02516 
02517 #define NUM_NEIGHBORS   6
02518 int dirs[6][2] = {
02519         {0, -1},
02520         {1, 0},
02521         {1, 1},
02522         {0, 1},
02523         {-1, 1},
02524         {-1, 0}
02525 };
02526 
02527 void visit_neighbor_hexes(MAP * map, int tx, int ty,
02528                                                   void (*callback) (MAP *, int, int))
02529 {
02530         int x1, y1;
02531         int i;
02532 
02533         for(i = 0; i < NUM_NEIGHBORS; i++) {
02534                 x1 = tx + dirs[i][0];
02535                 y1 = ty + dirs[i][1];
02536                 if(tx % 2 && !(x1 % 2))
02537                         y1--;
02538                 if(x1 < 0 || x1 >= map->map_width || y1 < 0 || y1 >= map->map_height)
02539                         continue;
02540                 callback(map, x1, y1);
02541         }
02542 }
02543 
02544 int GetPartWeight(int part)
02545 {
02546         if(IsWeapon(part))
02547                 return 10.24 * MechWeapons[Weapon2I(part)].weight;
02548         else if(IsAmmo(part))
02549                 return 1024;
02550         else if(IsBomb(part))
02551                 return 102 * BombWeight(Bomb2I(part));
02552 #ifndef BT_PART_WEIGHTS
02553         else if(IsSpecial(part) && part <= I2Special(CLAW))
02554                 return 1024;
02555 #else
02556         else if(IsSpecial(part))        /* && i <= I2Special(LAMEQUIP) */
02557                 return internalsweight[Special2I(part)];
02558         else if(IsCargo(part))
02559                 return cargoweight[Cargo2I(part)];
02560 #endif /* BT_PART_WEIGHTS */
02561         else
02562 /* hmm.. tricky, suppose we'll make things light */
02563                 return 102;
02564 }
02565 
02566 #ifdef BT_ADVANCED_ECON
02567 unsigned long long int GetPartCost(int p)
02568 {
02569         extern unsigned long long int specialcost[SPECIALCOST_SIZE];
02570         extern unsigned long long int ammocost[AMMOCOST_SIZE];
02571         extern unsigned long long int weapcost[WEAPCOST_SIZE];
02572         extern unsigned long long int cargocost[CARGOCOST_SIZE];
02573         extern unsigned long long int bombcost[BOMBCOST_SIZE];
02574 
02575         if(IsWeapon(p))
02576                 return weapcost[Weapon2I(p)];
02577         else if(IsAmmo(p))
02578                 return ammocost[Ammo2I(p)];
02579         else if(IsSpecial(p))
02580                 return specialcost[Special2I(p)];
02581         else if(IsBomb(p))
02582                 return bombcost[Bomb2I(p)];
02583         else if(IsCargo(p))
02584                 return cargocost[Cargo2I(p)];
02585         else
02586                 return 0;
02587 }
02588 
02589 void SetPartCost(int p, unsigned long long int cost)
02590 {
02591         extern unsigned long long int specialcost[SPECIALCOST_SIZE];
02592         extern unsigned long long int ammocost[AMMOCOST_SIZE];
02593         extern unsigned long long int weapcost[WEAPCOST_SIZE];
02594         extern unsigned long long int cargocost[CARGOCOST_SIZE];
02595         extern unsigned long long int bombcost[BOMBCOST_SIZE];
02596 
02597         if(IsWeapon(p))
02598                 weapcost[Weapon2I(p)] = cost;
02599         else if(IsAmmo(p))
02600                 ammocost[Ammo2I(p)] = cost;
02601         else if(IsSpecial(p))
02602                 specialcost[Special2I(p)] = cost;
02603         else if(IsBomb(p))
02604                 bombcost[Bomb2I(p)] = cost;
02605         else if(IsCargo(p))
02606                 cargocost[Cargo2I(p)] = cost;
02607 }
02608 
02609 #define COST_DEBUG 1
02610 
02611 void CalcFasaCost_AddPrice(float * total, char * desc, float value) {
02612    *total += value;
02613    #if COST_DEBUG
02614       SendDebug(tprintf("Addprice - %20s %.0f", desc, value));
02615    #endif
02616 }
02617     
02618 int MechNumHeatsinksInEngine(MECH * mech) {
02619    // Heatsinks in Engine = Engine Rating / 25
02620    return (MechEngineSize(mech) / 25);
02621 }
02622 
02623 void CalcFasaCost_DoArmMath(MECH * mech, int loc, float * total) {
02624     int i = 0;
02625     for (i = 0; i < NUM_CRITICALS; i++) {
02626         int part = GetPartType(mech, loc, i);
02627         if (!IsActuator(part))
02628             continue;
02629         else if (Special2I(part) == SHOULDER_OR_HIP)
02630             continue;
02631             // BMR Says don't count this.
02632             //CalcFasaCost_AddPrice(total, "Shoulder Actuator", 0);
02633         else if (Special2I(part) == UPPER_ACTUATOR)
02634             CalcFasaCost_AddPrice(total, "Upper Actuator", (MechTons(mech) * 100));
02635         else if (Special2I(part) == LOWER_ACTUATOR)
02636             CalcFasaCost_AddPrice(total, "Lower Actuator", (MechTons(mech) * 50));
02637         else if (Special2I(part) == HAND_OR_FOOT_ACTUATOR)
02638             CalcFasaCost_AddPrice(total, "Hand Actuator", (MechTons(mech) * 80));        
02639     }
02640 }
02641     
02642 void CalcFasaCost_DoLegMath(MECH * mech, int loc, float * total) {
02643     int i = 0;
02644     for (i = 0; i < NUM_CRITICALS; i++) {
02645         int part = GetPartType(mech, loc, i);
02646         if (!IsActuator(part))
02647             continue;
02648         else if (Special2I(part) == SHOULDER_OR_HIP || 
02649            Special2I(part) == UPPER_ACTUATOR)
02650             CalcFasaCost_AddPrice(total, "Hip Actuator", (MechTons(mech) * 150));
02651         else if (Special2I(part) == LOWER_ACTUATOR)
02652             CalcFasaCost_AddPrice(total, "Lower Actuator", (MechTons(mech) * 180));
02653         else if (Special2I(part) == HAND_OR_FOOT_ACTUATOR)
02654             CalcFasaCost_AddPrice(total, "Foot Actuator", (MechTons(mech) * 120));        
02655     }
02656 }
02657 
02658 /* 
02659  * Calculate the FASA cost of a unit as per an approximation of Maxtech
02660  * construction/cost rules. 
02661  */
02662 unsigned long long int CalcFasaCost(MECH * mech)
02663 {
02664         int ii, i, part;
02665         float total = 0;
02666         float mod = 1.0;
02667 
02668         if(!mech)
02669                 return -1;
02670 
02671         if(!
02672            (MechType(mech) == CLASS_MECH || MechType(mech) == CLASS_VEH_GROUND
02673                 || MechType(mech) == CLASS_VEH_NAVAL || MechType(mech) == CLASS_VTOL
02674                 || MechType(mech) == CLASS_BSUIT)
02675            || is_aero(mech) || IsDS(mech))
02676                 return 0;
02677 
02678         if(MechType(mech) == CLASS_MECH) {
02679 /* Cockpit */
02680 #if 0
02681 /* NULLTODO : Port any of these techs ASAP */
02682                 if(MechSpecials2(mech) & SMALLCOCKPIT_TECH)
02683                         ADDPRICE("SmallCockpit", 175000)
02684                                 else
02685                 if(MechSpecials2(mech) & TORSOCOCKPIT_TECH)
02686                         ADDPRICE("TorsoCockpit", 750000)
02687                                 else
02688 #endif
02689       CalcFasaCost_AddPrice(&total, "Cockpit", 200000);
02690 
02691 /* Life Support */
02692       CalcFasaCost_AddPrice(&total, "LifeSupport", 50000);
02693 
02694 /* Sensors */
02695       CalcFasaCost_AddPrice(&total, "Sensors", (MechTons(mech) * 2000));
02696 
02697 /* Myomer */
02698                 if(MechSpecials(mech) & TRIPLE_MYOMER_TECH)
02699                         CalcFasaCost_AddPrice(&total, "TS Myomer", (MechTons(mech) * 16000));
02700                 else
02701                         CalcFasaCost_AddPrice(&total, "Myomer", (MechTons(mech) * 2000));
02702 
02703 /* Internal Structure */
02704                 if(MechSpecials(mech) & ES_TECH || MechSpecials(mech) & COMPI_TECH)
02705                         CalcFasaCost_AddPrice(&total, "ES/Co Internals", (MechTons(mech) * 1600));
02706                 else if(MechSpecials(mech) & REINFI_TECH)
02707          CalcFasaCost_AddPrice(&total, "RE Internals", (MechTons(mech) * 6400));
02708                 else
02709                         CalcFasaCost_AddPrice(&total, "Internals", (MechTons(mech) * 400));
02710 
02711 /* Actuators */
02712       CalcFasaCost_DoArmMath(mech, LARM, &total);
02713       CalcFasaCost_DoArmMath(mech, RARM, &total);
02714                 /*
02715       CalcFasaCost_DoLegMath(mech, LLEG, &total);
02716       CalcFasaCost_DoLegMath(mech, RLEG, &total);
02717                 */
02718 /* Gyro */
02719                 i = MechEngineSize(mech);
02720                 if(i % 100)
02721                         i += (100 - (MechEngineSize(mech) % 100));
02722                 i /= 100;
02723 
02724                 if(MechSpecials2(mech) & XLGYRO_TECH)
02725                         CalcFasaCost_AddPrice(&total, "XL Gyro", (i * 750000));
02726                 else if(MechSpecials2(mech) & CGYRO_TECH)
02727                            CalcFasaCost_AddPrice(&total, "Compact Gyro", (i * 400000));
02728                 else if(MechSpecials2(mech) & HDGYRO_TECH)
02729                                 CalcFasaCost_AddPrice(&total, "HD Gyro", (i * 500000));
02730                 else
02731                    CalcFasaCost_AddPrice(&total, "Gyro", (i * 300000));
02732         } else if (MechType(mech) == CLASS_BSUIT) {
02733         /* ---------------------------------
02734          * BSuit Costs
02735          */
02736         if (MechSpecials(mech) & CLAN_TECH) {
02737             CalcFasaCost_AddPrice(&total, "Clan Point", 3500000);
02738         } else {
02739             CalcFasaCost_AddPrice(&total, "IS Squad", 2400000);
02740         }
02741         
02742         } else {
02743         /* ---------------------------------
02744          * Vehicle Costs
02745          */
02746                 int pamp = 0, turret = 0;
02747 
02748                 for(i = 0; i < NUM_SECTIONS; i++)
02749                         for(ii = 0; ii < NUM_CRITICALS; ii++) {
02750                                 if(!(part = GetPartType(mech, i, ii)))
02751                                         continue;
02752                                 if(!IsWeapon(part))
02753                                         continue;
02754                                 if(i == TURRET)
02755                                         turret += crit_weight(mech, part);
02756                                 if(IsEnergy(part)) {
02757                                         pamp += crit_weight(mech, part);
02758                                         SendDebug(tprintf("PAmp Weight: %d", crit_weight(mech, part)));
02759                                 }
02760                         }
02761 /* 
02762  * Internals 
02763  * 10,000 * Structure Tonnage
02764  */
02765                 int internals = (float)MechTons(mech) * 1000;
02766                 CalcFasaCost_AddPrice(&total, "Internals", internals);
02767 /* 
02768  * Control Components
02769  * 10,000 * Control Tonnage 
02770  * Control Tonnage = .05 * Tons
02771  */
02772                 int control_eq = 10000 * 0.05 * MechTons(mech);
02773                 CalcFasaCost_AddPrice(&total, "Cockpit & Controls", control_eq);
02774 /* 
02775  * Power Amp 
02776  * 20,000 * Amplifier Tonnage
02777  */
02778                 if(MechSpecials(mech) & ICE_TECH) {
02779                         int power_amp =  20000 * ( pamp / 1024 ) / 10;
02780                         CalcFasaCost_AddPrice(&total, "Power Amplifiers", power_amp);
02781                 }
02782                 
02783 /* 
02784  * Turret 
02785  * Standard: 5,000 * Turret Tonnage
02786  */
02787                 int turret_price = 5000 * (turret / 10) / 1024;
02788                 CalcFasaCost_AddPrice(&total, "Turret", turret_price);
02789 /* 
02790  * Lift/Dive Equip (Hovercraft, Hydrofoils, Submarines)
02791  * 20,000 * Equipment Tonnage
02792  */
02793                 if(MechMove(mech) == MOVE_HOVER
02794                         || MechMove(mech) == MOVE_FOIL
02795                         || MechMove(mech) == MOVE_SUB) {
02796                         float lift_dive = 20000 * (0.1 * MechTons(mech));
02797                         CalcFasaCost_AddPrice(&total, "Lift/Dive Equip", lift_dive);
02798                 }
02799 
02800                 if(MechMove(mech) == MOVE_VTOL) {
02801                         float vtol_eq = 40000 * (0.1 * MechTons(mech));
02802                         CalcFasaCost_AddPrice(&total, "Rotor", vtol_eq);
02803                 }
02804         } // end if (Vehicle Calcs)
02805 
02806 /* ----------------------------
02807  * General Calculations
02808  */
02809  
02810 if (MechType(mech) != CLASS_BSUIT) {
02811     /* Engine Math 
02812      * (Engine Basecost * Engine Rating * Tonnage) / 75
02813      */
02814     int engine_basecost = (MechSpecials(mech) & CE_TECH ? 10000 :
02815         MechSpecials(mech) & LE_TECH ? 15000 :
02816         MechSpecials(mech) & XL_TECH ? 20000 :
02817         MechSpecials(mech) & XXL_TECH ? 100000 :
02818         MechSpecials(mech) & ICE_TECH ? 1250 : 5000);
02819             
02820     int engine_size = MechEngineSize(mech);   
02821         
02822     if (MechMove(mech) == MOVE_WHEEL ||
02823         MechMove(mech) == MOVE_FOIL ||
02824         MechMove(mech) == MOVE_HOVER ||
02825         MechMove(mech) == MOVE_HULL || 
02826         MechMove(mech) == MOVE_SUB ||
02827         MechMove(mech) == MOVE_VTOL) {
02828         engine_size = engine_size - susp_factor(mech);
02829     }
02830                     
02831         int engine_price = (engine_basecost * engine_size * MechTons(mech)) / 75;
02832             
02833         CalcFasaCost_AddPrice(&total, "Engine", engine_price);
02834     
02835     /* Jump Jets 
02836      * Standard: Tonnage * (number of JJs^2) * 200
02837      * Improved: Tonnage * (number of JJs^2) * 500
02838      * Mechanical: Tonnage * (Jumping MP) * 150
02839      */
02840         int num_jjs = MechJumpSpeed(mech) * MP_PER_KPH;
02841         int jj_price = MechTons(mech) * pow(num_jjs, 2) * 200.0;
02842         if (num_jjs > 0)
02843                 CalcFasaCost_AddPrice(&total, "Jumpjets", jj_price);
02844     
02845     /* 
02846        Heat Sinks 
02847     */
02848         int numsinks = MechRealNumsinks(mech);
02849         
02850         int sinkcost;
02851         if(MechSpecials(mech) & DOUBLE_HEAT_TECH || MechSpecials(mech) & CLAN_TECH)
02852             sinkcost = 6000;
02853         else if(MechSpecials2(mech) & COMPACT_HS_TECH)
02854             sinkcost = 3000;
02855         else
02856             sinkcost = 2000;
02857     
02858         if((MechSpecials(mech) & DOUBLE_HEAT_TECH || MechSpecials(mech) & CLAN_TECH)) {
02859                 /* We want to divide the heat dissipation by two if DHS */
02860                 numsinks = BOUNDED(0, numsinks/2, 500);
02861         }
02862     
02863        // For single heatsinks, we only charge for every heatsink over 10.
02864        if(MechSpecials(mech) & DOUBLE_HEAT_TECH || MechSpecials(mech) & CLAN_TECH
02865           || MechSpecials2(mech) & COMPACT_HS_TECH || MechSpecials(mech) & ICE_TECH)
02866            CalcFasaCost_AddPrice(&total, "Heat Sinks", (numsinks * sinkcost));
02867        else {
02868            CalcFasaCost_AddPrice(&total, "Heat Sinks", 
02869              (BOUNDED(0, numsinks - 10, 500) * sinkcost));
02870        }
02871     
02872        
02873     #if COST_DEBUG
02874         SendDebug(tprintf("Heat Sinks: %d, Cost Per Sink: %d", numsinks, sinkcost));
02875     #endif
02876     
02877     /* Armor */
02878         int total_armor = 0;
02879         int armor_section = 0;
02880         for(armor_section = 0; armor_section < NUM_SECTIONS; ++armor_section) {
02881                 total_armor += GetSectOArmor(mech, armor_section);
02882                 total_armor += GetSectORArmor(mech, armor_section);
02883         }
02884         float armor_tons = total_armor / 16.0;
02885     
02886         int armor_cost_point = (MechSpecials(mech) & FF_TECH ? 20000 : MechSpecials2(mech) & 
02887                 STEALTH_ARMOR_TECH ? 50830 : MechSpecials(mech) &
02888                 HARDA_TECH ? 15000 : MechSpecials2(mech) & LT_FF_ARMOR_TECH ?
02889                  15000 : MechSpecials2(mech) & HVY_FF_ARMOR_TECH ? 25000 :
02890                  10000);
02891     #if COST_DEBUG
02892         SendDebug(tprintf("Armor Tons %.1f(%d pts) * Armor Cost Per Point %d", 
02893                 armor_tons, total_armor, armor_cost_point));
02894     #endif
02895         int armor_price = armor_tons * armor_cost_point;
02896         CalcFasaCost_AddPrice(&total, "Armor", armor_price);
02897 } // End Non-BSuit General Calculations
02898 
02899 /* Parts */
02900         for(i = 0; i < NUM_SECTIONS; i++)
02901                 for(ii = 0; ii < NUM_CRITICALS; ii++) {
02902                         part = GetPartType(mech, i, ii);
02903                         if(IsActuator(part) || part == EMPTY)
02904                                 continue;
02905                         if(IsSpecial(part))
02906                                 /* These parts are handled above, don't count their crits */
02907                                 switch (Special2I(part)) {
02908                                         case LIFE_SUPPORT:
02909                                                 continue;
02910                                         case SENSORS:
02911                                                 continue;
02912                                         case COCKPIT:
02913                                                 continue;
02914                                         case ENGINE:
02915                                                 continue;
02916                                         case GYRO:
02917                                                 continue;
02918                                         case HEAT_SINK:
02919                                                 continue;
02920                                         case JUMP_JET:
02921                                                 continue;
02922                                         case FERRO_FIBROUS:
02923                                                 continue;
02924                                         case ENDO_STEEL:
02925                                                 continue;
02926                                         case TRIPLE_STRENGTH_MYOMER:
02927                                                 continue;
02928                                         case STEALTH_ARMOR:
02929                                                 continue;
02930 #if 0
02931 /* NULLTODO : Port any of these techs ASAP */
02932                                                 case HARDPOINT:
02933                                                         continue;
02934 #endif
02935                                         default:
02936                                                 break;
02937                                 }
02938                                 if(IsAmmo(part)) {
02939                                         part = FindAmmoType(mech, i, ii);
02940                                         int ammo_part_cost = GetPartCost(part) * GetPartData(mech,i,ii);
02941                                         CalcFasaCost_AddPrice(&total, (char*)part_name(part, 0), 
02942                                            ammo_part_cost);
02943                                 } else {
02944                                     //MechWeapons[weapindx].criticals
02945                                     
02946                                     int indiv_part_cost = GetPartCost(part);
02947                                     if (MechType(mech) != CLASS_MECH && IsWeapon(part)) {
02948                                         indiv_part_cost *= MechWeapons[part-1].criticals;
02949                                         //SendDebug(tprintf("Part#: %s(%d) Crits: %d", MechWeapons[part-1].name, part-1, MechWeapons[part-1].criticals));
02950                                     }
02951                                         CalcFasaCost_AddPrice(&total, (char*)part_name(part, 0), 
02952                                            indiv_part_cost);
02953                                 }
02954                         }
02955 
02956         if(MechType(mech) != CLASS_MECH && MechType(mech) != CLASS_BSUIT) {
02957                 switch (MechMove(mech)) {
02958                         case MOVE_TRACK:
02959                                 mod = (float) 1 + (float) ((float) MechTons(mech) / (float) 100);
02960                                 break;
02961                         case MOVE_WHEEL:
02962                                 mod = (float) 1 + (float) ((float) MechTons(mech) / (float) 200);
02963                                 break;
02964                         case MOVE_HOVER:
02965                                 mod = (float) 1 + (float) ((float) MechTons(mech) / (float) 50);
02966                                 break;
02967                         case MOVE_VTOL:
02968                                 mod = (float) 1 + (float) ((float) MechTons(mech) / (float) 30);
02969                                 break;
02970                         case MOVE_HULL:
02971                                 mod = (float) 1 + (float) ((float) MechTons(mech) / (float) 200);
02972                                 break;
02973                         case MOVE_FOIL:
02974                                 mod = (float) 1 + (float) ((float) MechTons(mech) / (float) 75);
02975                                 break;
02976                         case MOVE_SUB:
02977                                 mod = (float) 1 + (float) ((float) MechTons(mech) / (float) 50);
02978                                 break;
02979                 }
02980         } else if (MechType(mech) == CLASS_BSUIT) {
02981             // There's nothing in Maxtech about this, but we're going to knock the prices
02982             // down to be competitive with other unit types.
02983             mod = 0.75;
02984         } else {
02985             // The standard mech modifier.
02986                 mod = (float) 1 + (float) ((float) MechTons(mech) / (float) 100);
02987         }
02988 
02989         if (MechIsOmniMech(mech)) {
02990                 SendDebug(tprintf("Mech is Omni, multiplying %lld by .25", total));
02991                 total *= .25;
02992         }
02993 
02994 #if COST_DEBUG
02995         SendDebug(tprintf("Price Total %.0f * Mod - %f = %.0f", total, mod, total*mod));
02996 #endif
02997 
02998         return (total * mod);
02999 } /* End Function */
03000 
03001 #endif
03002 
03003 #ifdef BT_CALCULATE_BV
03004 int FindAverageGunnery(MECH * mech) {
03005 #if 1
03006 /* NULLTODO : Get the multiple skills for gunnery and such ported or working here so this is usefull again. */
03007                         return FindPilotGunnery(mech, 0);
03008 #else
03009                         int runtot = 0;
03010                         int i;
03011 
03012                         if(!mech)
03013                                 return 12;
03014 
03015                         for(i = 0; i < 5; i++) {
03016                                 runtot +=
03017                                         FindPilotGunnery(mech,
03018                                                                          (i == 0 ? 0 : i == 1 ? 4 : i ==
03019                                                                           2 ? 5 : i == 3 ? 6 : i == 4 ? 103 : 0));
03020                         }
03021                         return (runtot / 5);
03022 #endif
03023                 }
03024 
03025 #undef DEBUG_BV
03026 #define HIGH_SKILL      8
03027 #define LOW_SKILL       0
03028                 float skillmul[HIGH_SKILL][HIGH_SKILL] = {
03029                         {2.05, 2.00, 1.95, 1.90, 1.85, 1.80, 1.75, 1.70},
03030                         {1.85, 1.80, 1.75, 1.70, 1.65, 1.60, 1.55, 1.50},
03031                         {1.65, 1.60, 1.55, 1.50, 1.45, 1.40, 1.35, 1.30},
03032                         {1.45, 1.40, 1.35, 1.30, 1.25, 1.20, 1.15, 1.10},
03033                         {1.25, 1.20, 1.15, 1.10, 1.05, 1.00, 0.95, 0.90},
03034                         {1.15, 1.10, 1.05, 1.00, 0.95, 0.90, 0.85, 0.80},
03035                         {1.05, 1.00, 0.95, 0.90, 0.85, 0.80, 0.75, 0.70},
03036                         {0.95, 0.90, 0.85, 0.80, 0.75, 0.70, 0.65, 0.60}
03037                 };
03038 
03039 #define LAZY_SKILLMUL(n)  (n < LOW_SKILL ? LOW_SKILL : n >= HIGH_SKILL - 1 ? HIGH_SKILL - 1 : n)
03040 
03041                 int CalculateBV(MECH * mech, int gunstat, int pilstat) {
03042                         int defbv = 0, offbv = 0, i, ii, temp, temp2, deduct =
03043                                 0, offweapbv = 0, defweapbv = 0, armor = 0, intern =
03044                                 0, weapindx, mostheat = 0, tempheat =
03045                                 0, mechspec, mechspec2, type, move, pilskl = pilstat, gunskl =
03046                                 gunstat;
03047                         int debug1 = 0, debug2 = 0, debug3 = 0, debug4 = 0;
03048                         float maxspeed, mul = 1.00;
03049 
03050                         if(!mech)
03051                                 return 0;
03052 
03053                         if(gunstat == 100 || pilstat == 100) {
03054                                 if(muxevent_tick - MechBVLast(mech) < 30)
03055                                         return MechBV(mech);
03056                                 else
03057                                         MechBVLast(mech) = muxevent_tick;
03058                         }
03059 
03060                         type = MechType(mech);
03061                         move = MechMove(mech);
03062                         mechspec = MechSpecials(mech);
03063                         mechspec2 = MechSpecials2(mech);
03064                         if(gunstat == 100)
03065                                 pilskl = FindPilotPiloting(mech);
03066                         if(pilstat == 100)
03067                                 gunskl = FindAverageGunnery(mech);
03068 
03069                         for(i = 0; i < NUM_SECTIONS; i++) {
03070                                 armor += (debug1 =
03071                                                   GetSectArmor(mech,
03072                                                                            i) *
03073                                                   (mechspec & HARDA_TECH ? 200 : 100));
03074                                 if(type == CLASS_MECH
03075                                    && (i == CTORSO || i == LTORSO || i == RTORSO)) {
03076                                         armor += (debug2 =
03077                                                           GetSectRArmor(mech,
03078                                                                                         i) *
03079                                                           (mechspec & HARDA_TECH ? 200 : 100));
03080 #if 0
03081 /* NULLTODO : Port any of these techs ASAP */
03082                                         if(mechspec2 & TORSOCOCKPIT_TECH && i == CTORSO)
03083                                                 armor += (debug4 =
03084                                                                   (((GetSectArmor(mech, i) +
03085                                                                          GetSectRArmor(mech,
03086                                                                                                    i)) * 2) *
03087                                                                    (mechspec & HARDA_TECH ? 200 : 100)));
03088 #endif
03089                                 }
03090                                 if(!is_aero(mech))
03091                                         intern += (debug3 =
03092                                                            GetSectInt(mech,
03093                                                                                   i) *
03094                                                            (mechspec & COMPI_TECH ? 50 : mechspec &
03095                                                                 REINFI_TECH ? 200 : 100));
03096                                 else
03097                                         intern = (debug3 = AeroSI(mech));
03098 #ifdef DEBUG_BV
03099                                 SendDebug(tprintf
03100                                                   ("Armoradd : %d ArmorRadd : %d Internadd : %d",
03101                                                    debug1 / 100, debug2 / 100, debug3 / 100));
03102                                 if(mechspec2 & TORSOCOCKPIT_TECH && i == CTORSO)
03103                                         SendDebug(tprintf("TorsoCockpit Armoradd : %d", debug4));
03104 #endif
03105 
03106                                 debug1 = debug2 = debug3 = debug4 = 0;
03107                                 for(ii = 0; ii < CritsInLoc(mech, i); ii++) {
03108                                         if(IsWeapon(temp = GetPartType(mech, i, ii))) {
03109                                                 weapindx = (Weapon2I(temp));
03110                                                 if(PartIsNonfunctional(mech, i, ii)) {
03111                                                         if(type == CLASS_MECH)
03112                                                                 ii += (MechWeapons[weapindx].criticals - 1);
03113                                                         continue;
03114                                                 }
03115                                                 if(MechWeapons[weapindx].special & AMS) {
03116                                                         defweapbv += (debug1 =
03117                                                                                   (MechWeapons[weapindx].battlevalue *
03118                                                                                    100) * (float) (3000 /
03119                                                                                                                    (MechWeapons
03120                                                                                                                         [weapindx].vrt *
03121                                                                                                                         100)));
03122 
03123 #ifdef DEBUG_BV
03124                                                         SendDebug(tprintf
03125                                                                           ("DefWeapBVadd (%s) : %d - Total : %d",
03126                                                                            MechWeapons[weapindx].name,
03127                                                                            debug1 / 100, defweapbv / 100));
03128 #endif
03129 
03130                                                 } else {
03131                                                         offweapbv += (debug1 =
03132                                                                                   (MechWeapons[weapindx].battlevalue *
03133                                                                                    (GetPartFireMode(mech, i, ii) &
03134                                                                                         REAR_MOUNT ? 50 : 100)) *
03135                                                                                   (float) ((float) 3000 /
03136                                                                                                    (float) (MechWeapons
03137                                                                                                                         [weapindx].vrt *
03138                                                                                                                         100)));
03139                                                         if(MechWeapons[weapindx].type == TMISSILE)
03140                                                                 if(FindArtemisForWeapon(mech, i, ii))
03141                                                                         offweapbv +=
03142                                                                                 (MechWeapons[weapindx].battlevalue *
03143                                                                                  20);
03144 #ifdef DEBUG_BV
03145                                                         SendDebug(tprintf
03146                                                                           ("OffWeapBVadd (%s) : %d - Total : %d",
03147                                                                            MechWeapons[weapindx].name,
03148                                                                            debug1 / 100, offweapbv / 100));
03149 #endif
03150 
03151                                                 }
03152                                                 if(type == CLASS_MECH) {
03153                                                         if(!(GetPartFireMode(mech, i, ii) & REAR_MOUNT)) {
03154                                                                 tempheat =
03155                                                                         ((MechWeapons[weapindx].heat * 100) *
03156                                                                          (float) ((float) 3000 /
03157                                                                                           (float) (MechWeapons[weapindx].
03158                                                                                                            vrt * 100)));
03159                                                                 if(MechWeapons[weapindx].special & ULTRA)
03160                                                                         tempheat = (tempheat * 2);
03161                                                                 if(MechWeapons[weapindx].special & STREAK)
03162                                                                         tempheat = (tempheat / 2);
03163                                                                 mostheat += tempheat;
03164 #ifdef DEBUG_BV
03165                                                                 SendDebug(tprintf
03166                                                                                   ("Tempheatadded (%s) : %d - Total : %d",
03167                                                                                    MechWeapons[weapindx].name,
03168                                                                                    tempheat / 100, mostheat / 100));
03169 #endif
03170                                                                 tempheat = 0;
03171                                                         }
03172                                                 }
03173                                                 if(type == CLASS_MECH)
03174                                                         ii += (MechWeapons[weapindx].criticals - 1);
03175                                         } else if(IsAmmo(temp)) {
03176                                                 if(PartIsNonfunctional(mech, i, ii)
03177                                                    || !GetPartData(mech, i, ii))
03178                                                         continue;
03179 #if 0
03180 /* NULLTODO : Port any of these techs ASAP */
03181                                                 mul =
03182                                                         ((temp2 =
03183                                                           GetPartAmmoMode(mech, i,
03184                                                                                           ii)) & AC_AP_MODE ? 4 : temp2 &
03185                                                          AC_PRECISION_MODE ? 6 : temp2 & (TRACER_MODE |
03186                                                                                                                           STINGER_MODE |
03187                                                                                                                           SWARM_MODE |
03188                                                                                                                           SWARM1_MODE |
03189                                                                                                                           SGUIDED_MODE) ?
03190                                                          1.5 : 1);
03191 #else
03192                                                 mul =
03193                                                         ((temp2 =
03194                                                           GetPartAmmoMode(mech, i,
03195                                                                                           ii)) & AC_AP_MODE ? 4 : temp2 &
03196                                                          AC_PRECISION_MODE ? 6 : temp2 & (SWARM_MODE |
03197                                                                                                                           SWARM1_MODE |
03198                                                                                                                           STINGER_MODE) ?
03199                                                          1.5 : 1);
03200 #endif
03201                                                 mul =
03202                                                         (mul *
03203                                                          ((float)
03204                                                           ((float) GetPartData(mech, i, ii) /
03205                                                            (float) MechWeapons[weapindx =
03206                                                                                                    Ammo2WeaponI(temp)].
03207                                                            ammoperton)));
03208 
03209 #ifdef DEBUG_BV
03210                                                 SendDebug(tprintf
03211                                                                   ("AmmoBVmul (%s) : %.2f",
03212                                                                    MechWeapons[weapindx].name, mul));
03213 #endif
03214 
03215                                                 if(MechWeapons[weapindx].special & AMS) {
03216                                                         defweapbv += (debug1 =
03217                                                                                   (((MechWeapons[weapindx].
03218                                                                                          battlevalue / 10) * 100) * mul) *
03219                                                                                   (float) ((float) 3000 /
03220                                                                                                    (float) (MechWeapons
03221                                                                                                                         [weapindx].vrt *
03222                                                                                                                         100)));
03223 
03224 #ifdef DEBUG_BV
03225                                                         SendDebug(tprintf
03226                                                                           ("AmmoDefWeapBVadd (%s) : %d - Total : %d",
03227                                                                            MechWeapons[weapindx].name,
03228                                                                            debug1 / 100, defweapbv / 100));
03229 #endif
03230 
03231                                                 } else {
03232 
03233 #ifdef DEBUG_BV
03234                                                         SendDebug(tprintf
03235                                                                           ("Abattlebalue (%s) : %d",
03236                                                                            MechWeapons[weapindx].name,
03237                                                                            (MechWeapons[weapindx].battlevalue /
03238                                                                                 10)));
03239 #endif
03240 
03241                                                         offweapbv += (debug1 =
03242                                                                                   (((MechWeapons[weapindx].
03243                                                                                          battlevalue / 10) * 100) * mul) *
03244                                                                                   (float) ((float) 3000 /
03245                                                                                                    (float) (MechWeapons
03246                                                                                                                         [weapindx].vrt *
03247                                                                                                                         100)));
03248 
03249 #ifdef DEBUG_BV
03250                                                         SendDebug(tprintf
03251                                                                           ("AmmoOffWeapBVadd (%s)  : %d - Total : %d",
03252                                                                            MechWeapons[weapindx].name,
03253                                                                            debug1 / 100, offweapbv / 100));
03254 #endif
03255 
03256                                                 }
03257                                         }
03258                                         if((IsAmmo(temp)
03259                                                 || (IsWeapon(temp)
03260                                                         && MechWeapons[(Weapon2I(temp))].special & GAUSS))
03261                                            && type == CLASS_MECH) {
03262                                                 if(mechspec & CLAN_TECH)
03263                                                         if(i == CTORSO || i == HEAD || i == RLEG
03264                                                            || i == LLEG) {
03265 
03266 #ifdef DEBUG_BV
03267                                                                 SendDebug("20 deduct added for ammo");
03268 #endif
03269                                                                 deduct += 2000;
03270                                                                 continue;
03271                                                         }
03272                                                 if(mechspec &
03273                                                    (XL_TECH | XXL_TECH | ICE_TECH | LE_TECH)) {
03274 
03275 #ifdef DEBUG_BV
03276                                                         SendDebug("20/2000 deduct added for ammo");
03277 #endif
03278 
03279                                                         deduct += 2000;
03280                                                         continue;
03281                                                 }
03282                                                 if((i == CTORSO || i == RLEG || i == LLEG
03283                                                         || i == HEAD)
03284                                                    && !(MechSections(mech)[i].config & CASE_TECH)) {
03285 
03286 #ifdef DEBUG_BV
03287                                                         SendDebug("20 deduct added for ammo");
03288 #endif
03289 
03290                                                         deduct += 2000;
03291                                                         continue;
03292                                                 }
03293                                                 if((i == RARM || i == LARM)
03294                                                    && (!(MechSections(mech)[i].config & CASE_TECH)
03295                                                            &&
03296                                                            !(MechSections(mech)
03297                                                                  [(i ==
03298                                                                    RARM ? RTORSO : LTORSO)].
03299                                                                  config & CASE_TECH))) {
03300 
03301 #ifdef DEBUG_BV
03302                                                         SendDebug("20 deduct added for ammo");
03303 #endif
03304 
03305                                                         deduct += 2000;
03306                                                         continue;
03307                                                 }
03308                                         }
03309 
03310                                 }
03311                         }
03312                         if(type == CLASS_MECH) {
03313                                 mostheat +=
03314                                         (MechJumpSpeed(mech) >
03315                                          0 ? MAX((MechJumpSpeed(mech) / MP1) * 100, 300) : 200);
03316                                 if(mechspec2 & (NULLSIGSYS_TECH | STEALTH_ARMOR_TECH))
03317                                         mostheat += 1000;
03318                                 if((temp = (mostheat - (MechActiveNumsinks(mech) * 100))) > 0) {
03319                                         deduct += temp * 5;
03320 #ifdef DEBUG_BV
03321                                         SendDebug(tprintf
03322                                                           ("Deduct add for heat : %d", (temp * 5) / 100));
03323 #endif
03324                                 }
03325                         }
03326 #ifdef DEBUG_BV
03327                         SendDebug(tprintf("DeductTotal : %d", deduct / 100));
03328 #endif
03329 
03330                         if(mechspec & ECM_TECH)
03331                                 defweapbv += 6100;
03332 
03333                         if(mechspec & BEAGLE_PROBE_TECH) {
03334                                 if(mechspec & CLAN_TECH)
03335                                         offweapbv += 1200;
03336                                 else
03337                                         offweapbv += 1000;
03338                         }
03339 #if 0
03340 /* NULLTODO : Port any of these techs ASAP */
03341                         if(mechspec2 & HDGYRO_TECH)
03342                                 defweapbv += 3000;
03343 #endif
03344 
03345                         if(mechspec & (XL_TECH | XXL_TECH | LE_TECH)) {
03346                                 if(mechspec & (CLAN_TECH | LE_TECH))
03347                                         mul = 1.125;
03348                                 else
03349                                         mul = 0.75;
03350                         } else if(mechspec & ICE_TECH
03351                                           || MechType(mech) == CLASS_VEH_GROUND
03352                                           || MechType(mech) == CLASS_VEH_NAVAL) {
03353                                 mul = 0.5;
03354                         } else {
03355                                 mul = 1.5;
03356                         }
03357 
03358 #ifdef DEBUG_BV
03359                         SendDebug(tprintf("InternMul : %.2f", mul));
03360 #endif
03361 
03362                         armor = (armor * (MechType(mech) == CLASS_MECH ? 2 : 1));
03363                         intern = intern * mul;
03364                         mul = 1.00;
03365 
03366 #ifdef DEBUG_BV
03367                         SendDebug(tprintf
03368                                           ("ArmorEnd : %d IntEnd : %d", armor / 100,
03369                                            intern / 100));
03370 #endif
03371 
03372                         maxspeed = MMaxSpeed(mech);
03373                         if(mechspec & MASC_TECH || mechspec2 & SUPERCHARGER_TECH) {
03374                                 if(mechspec & MASC_TECH && mechspec2 & SUPERCHARGER_TECH)
03375                                         maxspeed = maxspeed * 2.5;
03376                                 else
03377                                         maxspeed = maxspeed * 1.5;
03378                         }
03379                         if(mechspec & TRIPLE_MYOMER_TECH)
03380                                 maxspeed = ((WalkingSpeed(maxspeed) + MP1) * 1.5);
03381 
03382                         if(maxspeed <= MP2) {
03383                                 mul = 1.0;
03384                         } else if(maxspeed <= MP4) {
03385                                 mul = 1.1;
03386                         } else if(maxspeed <= MP6) {
03387                                 mul = 1.2;
03388                         } else if(maxspeed <= MP9) {
03389                                 mul = 1.3;
03390                         } else if(maxspeed <= MP1 * 13) {
03391                                 mul = 1.4;
03392                         } else if(maxspeed <= MP1 * 18) {
03393                                 mul = 1.5;
03394                         } else if(maxspeed <= MP1 * 24) {
03395                                 mul = 1.6;
03396                         } else {
03397                                 mul = 1.7;
03398                         }
03399 
03400                         if(IsDS(mech))
03401                                 mul = 1.0;
03402                         else if(is_aero(mech))
03403                                 mul = 1.1;
03404 
03405                         if(mechspec2 & (NULLSIGSYS_TECH | STEALTH_ARMOR_TECH))
03406                                 mul += 1.5;
03407                         if(MechInfantrySpecials(mech) & DC_KAGE_STEALTH_TECH)
03408                                 mul += .75;
03409                         if(MechInfantrySpecials(mech) & FWL_ACHILEUS_STEALTH_TECH)
03410                                 mul += 1.5;
03411                         if(MechInfantrySpecials(mech) & CS_PURIFIER_STEALTH_TECH)
03412                                 mul += 2.0;
03413                         if(MechInfantrySpecials(mech) & FC_INFILTRATOR_STEALTH_TECH)
03414                                 mul += .75;
03415                         if(MechInfantrySpecials(mech) & FC_INFILTRATOR_STEALTH_TECH)
03416                                 mul += 2.0;
03417 
03418 #ifdef DEBUG_BV
03419                         SendDebug(tprintf("DefBVMul : %.2f", mul));
03420 #endif
03421 
03422                         defbv = (armor + intern + (MechTons(mech) * 100) + defweapbv);
03423 
03424 #ifdef DEBUG_BV
03425                         SendDebug(tprintf("DefBV Tonnage added : %d", MechTons(mech)));
03426 #endif
03427 
03428                         if((defbv - deduct) < 1)
03429                                 defbv = 1;
03430                         else
03431                                 defbv -= deduct;
03432                         if(type != CLASS_MECH)
03433                                 defbv =
03434                                         ((defbv *
03435                                           (move == MOVE_TRACK ? 0.8 : move ==
03436                                            MOVE_WHEEL ? 0.7 : move == MOVE_HOVER ? 0.6 : move ==
03437                                            MOVE_VTOL ? 0.4 : move == MOVE_FOIL || move == MOVE_SUB
03438                                            || move == MOVE_HULL ? 0.5 : 1.0)) - deduct);
03439                         defbv = defbv * mul;
03440 
03441 #ifdef DEBUG_BV
03442                         SendDebug(tprintf("DefBV : %d", defbv / 100));
03443 #endif
03444 
03445                         if((type == CLASS_MECH || is_aero(mech))
03446                            && mostheat > (MechActiveNumsinks(mech) * 100)) {
03447 #ifdef DEBUG_BV
03448                                 SendDebug(tprintf
03449                                                   ("Pre-Heat OffWeapBV : %d", offweapbv / 100));
03450 #endif
03451                                 i = (((MechActiveNumsinks(mech) / 100) * offweapbv) /
03452                                          mostheat);
03453                                 ii = ((offweapbv - i) / 2);
03454                                 offweapbv = i + ii;
03455 
03456 #ifdef DEBUG_BV
03457                                 SendDebug(tprintf
03458                                                   ("Post-Heat OffWeapBV : %d", offweapbv / 100));
03459 #endif
03460                         }
03461 /*
03462 mul = pow(((((MMaxSpeed(mech) / MP1) + (type == CLASS_AERO || type == CLASS_DS ? 0 : (MechJumpSpeed(mech) / MP1)) + (mechspec & MASC_TECH ? 1 : 0) + (mechspec & TRIPLE_MYOMER_TECH ? 1 : 0)+ (mechspec2 & SUPERCHARGER_TECH ? 1 : 0) - 5) / 10) + 1), 1.2);
03463 */
03464                         mul =
03465                                 pow((((((IsDS(mech) ? WalkingSpeed(MMaxSpeed(mech)) :
03466                                                  MMaxSpeed(mech)) / MP1) +
03467                                            (mechspec & MASC_TECH ? 1 : 0) +
03468                                            (mechspec & TRIPLE_MYOMER_TECH ? 1 : 0) +
03469                                            (mechspec2 & SUPERCHARGER_TECH ? 1 : 0) - 5) / 10) +
03470                                          1), 1.2);
03471 
03472 #ifdef DEBUG_BV
03473                         SendDebug(tprintf("DumbMul : %.2f", mul));
03474 #endif
03475 
03476                         if(mechspec2 & OMNIMECH_TECH)
03477                                 mul += .3;
03478 
03479                         offweapbv = offweapbv * mul;
03480                         if(type != CLASS_AERO && type != CLASS_DS
03481                            && MechJumpSpeed(mech) > 0)
03482                                 offweapbv +=
03483                                         ((MechJumpSpeed(mech) / MP1) *
03484                                          (100 * (MechTons(mech) / 5)));
03485                         offbv = offweapbv;
03486 
03487 #ifdef DEBUG_BV
03488                         SendDebug(tprintf("OffWeapBVAfter : %d", offweapbv / 100));
03489                         SendDebug(tprintf
03490                                           ("DefBV : %d OffBV : %d TotalBV : %d", defbv / 100,
03491                                            offbv / 100, (offbv + defbv) / 100));
03492 #endif
03493 
03494                         mul = (skillmul[LAZY_SKILLMUL(gunskl)][LAZY_SKILLMUL(pilskl)]);
03495 
03496 #ifdef DEBUG_BV
03497                         SendDebug(tprintf
03498                                           ("SkillMul : %.2f (%d/%d)", mul, gunskl, pilskl));
03499 #endif
03500                         return ((offbv + defbv) / 100) * mul;
03501                 }
03502 #endif
03503 
03504                 int MechFullNoRecycle(MECH * mech, int num) {
03505                         int i;
03506 
03507                         for(i = 0; i < NUM_SECTIONS; i++) {
03508                                 if(num & CHECK_WEAPS && SectHasBusyWeap(mech, i))
03509                                         return 1;
03510                                 if(num & CHECK_PHYS && MechSections(mech)[i].recycle > 0)
03511                                         return 2;
03512                         }
03513                         return 0;
03514                 }
03515 
03516 #ifdef BT_COMPLEXREPAIRS
03517                 int GetPartMod(MECH * mech, int t) {
03518                         int val, div, bound;
03519 
03520                         div = (t && t == Special(GYRO) ? 100 : t
03521                                    && t == Special(ENGINE) ? 20 : 10);
03522                         bound = (t && t == Special(GYRO) ? 3 : t
03523                                          && t == Special(ENGINE) ? 19 : 9);
03524                         val = (t
03525                                    && (t == Special(GYRO)
03526                                            || t ==
03527                                            Special(ENGINE)) ? MechEngineSize(mech) :
03528                                    MechTons(mech));
03529 
03530                         if(val % div != 0)
03531                                 val = val + (div - (val % div));
03532 
03533                         return BOUNDED(0, (val / div) - 1, bound);
03534                 }
03535 
03536                 int ProperArmor(MECH * mech) {
03537 /* For now they all use the same basic cargo parts. */
03538                         return Cargo(MechSpecials(mech) & FF_TECH ? FF_ARMOR :
03539                                                  MechSpecials(mech) & HARDA_TECH ? HD_ARMOR :
03540                                                  MechSpecials2(mech) & HVY_FF_ARMOR_TECH ?
03541                                                  HVY_FF_ARMOR : MechSpecials2(mech) & LT_FF_ARMOR_TECH
03542                                                  ? LT_FF_ARMOR : MechSpecials2(mech) &
03543                                                  STEALTH_ARMOR_TECH ? STH_ARMOR : S_ARMOR);
03544                 }
03545 
03546                 int ProperInternal(MECH * mech) {
03547                         int part = 0;
03548 
03549                         if(mudconf.btech_complexrepair) {
03550                                 part = (MechSpecials(mech) & ES_TECH ? TON_ESINTERNAL_FIRST :
03551                                                 MechSpecials(mech) & REINFI_TECH ?
03552                                                 TON_REINTERNAL_FIRST : MechSpecials(mech) & COMPI_TECH
03553                                                 ? TON_COINTERNAL_FIRST : TON_INTERNAL_FIRST);
03554                                 part += GetPartMod(mech, 0);
03555                         } else {
03556                                 part = (MechSpecials(mech) & ES_TECH ? ES_INTERNAL :
03557                                                 MechSpecials(mech) & REINFI_TECH ? RE_INTERNAL :
03558                                                 MechSpecials(mech) & COMPI_TECH ? CO_INTERNAL :
03559                                                 S_INTERNAL);
03560                         }
03561                         return Cargo(part);
03562                 }
03563 
03564                 int alias_part(MECH * mech, int t, int loc) {
03565                         int part = 0;
03566 
03567                         if(!IsSpecial(t))
03568                                 return t;
03569 
03570                         if(mudconf.btech_complexrepair) {
03571                                 int tonmod = GetPartMod(mech, t);
03572                                 int locmod;
03573                                 if(MechIsQuad(mech))
03574                                         locmod = (loc == RARM || loc == LARM || loc == RLEG
03575                                                           || loc == LLEG ? 2 : 0);
03576                                 else
03577                                         locmod = (loc == RARM || loc == LARM ? 1 : loc == LLEG
03578                                                           || loc == RLEG ? 2 : 0);
03579 
03580                                 part = (locmod
03581                                                 && (t == Special(SHOULDER_OR_HIP)
03582                                                         || t == Special(UPPER_ACTUATOR)) ? (locmod ==
03583                                                                                                                                 1 ?
03584                                                                                                                                 Cargo
03585                                                                                                                                 (TON_ARMUPPER_FIRST
03586                                                                                                                                  +
03587                                                                                                                                  tonmod) :
03588                                                                                                                                 Cargo
03589                                                                                                                                 (TON_LEGUPPER_FIRST
03590                                                                                                                                  +
03591                                                                                                                                  tonmod)) :
03592                                                 locmod
03593                                                 && t == Special(LOWER_ACTUATOR) ? (locmod ==
03594                                                                                                                    1 ?
03595                                                                                                                    Cargo
03596                                                                                                                    (TON_ARMLOWER_FIRST
03597                                                                                                                         +
03598                                                                                                                         tonmod) :
03599                                                                                                                    Cargo
03600                                                                                                                    (TON_LEGLOWER_FIRST
03601                                                                                                                         +
03602                                                                                                                         tonmod)) : locmod
03603                                                 && t == Special(HAND_OR_FOOT_ACTUATOR) ? (locmod ==
03604                                                                                                                                   1 ?
03605                                                                                                                                   Cargo
03606                                                                                                                                   (TON_ARMHAND_FIRST
03607                                                                                                                                    +
03608                                                                                                                                    tonmod) :
03609                                                                                                                                   Cargo
03610                                                                                                                                   (TON_LEGFOOT_FIRST
03611                                                                                                                                    +
03612                                                                                                                                    tonmod)) :
03613                                                 t == Special(ENGINE)
03614                                                 && MechSpecials(mech) & XL_TECH ?
03615                                                 Cargo(TON_ENGINE_XL_FIRST + tonmod) : t ==
03616                                                 Special(ENGINE)
03617                                                 && MechSpecials(mech) & ICE_TECH ?
03618                                                 Cargo(TON_ENGINE_ICE_FIRST + tonmod) : t ==
03619                                                 Special(ENGINE)
03620                                                 && MechSpecials(mech) & CE_TECH ?
03621                                                 Cargo(TON_ENGINE_COMP_FIRST + tonmod) : t ==
03622                                                 Special(ENGINE)
03623                                                 && MechSpecials(mech) & XXL_TECH ?
03624                                                 Cargo(TON_ENGINE_XXL_FIRST + tonmod) : t ==
03625                                                 Special(ENGINE)
03626                                                 && MechSpecials(mech) & LE_TECH ?
03627                                                 Cargo(TON_ENGINE_LIGHT_FIRST + tonmod) : t ==
03628                                                 Special(ENGINE) ? Cargo(TON_ENGINE_FIRST +
03629                                                                                                 tonmod) : t ==
03630                                                 Special(HEAT_SINK)
03631                                                 && MechSpecials(mech) & (DOUBLE_HEAT_TECH | CLAN_TECH)
03632                                                 ? Cargo(DOUBLE_HEAT_SINK) : t == Special(HEAT_SINK)
03633                                                 && MechSpecials2(mech) & COMPACT_HS_TECH ?
03634                                                 Cargo(COMPACT_HEAT_SINK) : t == Special(GYRO)
03635                                                 && MechSpecials2(mech) & XLGYRO_TECH ?
03636                                                 Cargo(TON_XLGYRO_FIRST + tonmod) : t == Special(GYRO)
03637                                                 && MechSpecials2(mech) & HDGYRO_TECH ?
03638                                                 Cargo(TON_HDGYRO_FIRST + tonmod) : t == Special(GYRO)
03639                                                 && MechSpecials2(mech) & CGYRO_TECH ?
03640                                                 Cargo(TON_CGYRO_FIRST + tonmod) : t ==
03641                                                 Special(GYRO) ? Cargo(TON_GYRO_FIRST + tonmod) : t ==
03642                                                 Special(SENSORS) ? Cargo(TON_SENSORS_FIRST +
03643                                                                                                  tonmod) : t ==
03644                                                 Special(JUMP_JET) ? Cargo(TON_JUMPJET_FIRST +
03645                                                                                                   tonmod) : t);
03646                         } else {
03647                                 part = (IsActuator(t) ? Cargo(S_ACTUATOR) :
03648                                                 t == Special(ENGINE)
03649                                                 && MechSpecials(mech) & XL_TECH ? Cargo(XL_ENGINE) : t
03650                                                 == Special(ENGINE)
03651                                                 && MechSpecials(mech) & ICE_TECH ? Cargo(IC_ENGINE) :
03652                                                 t == Special(ENGINE)
03653                                                 && MechSpecials(mech) & CE_TECH ? Cargo(COMP_ENGINE) :
03654                                                 t == Special(ENGINE)
03655                                                 && MechSpecials(mech) & XXL_TECH ? Cargo(XXL_ENGINE) :
03656                                                 t == Special(ENGINE)
03657                                                 && MechSpecials(mech) & LE_TECH ? Cargo(LIGHT_ENGINE)
03658                                                 : t == Special(HEAT_SINK)
03659                                                 && MechSpecials(mech) & (DOUBLE_HEAT_TECH | CLAN_TECH)
03660                                                 ? Cargo(DOUBLE_HEAT_SINK) : t == Special(HEAT_SINK)
03661                                                 && MechSpecials2(mech) & COMPACT_HS_TECH ?
03662                                                 Cargo(COMPACT_HEAT_SINK) : t == Special(GYRO)
03663                                                 && MechSpecials2(mech) & XLGYRO_TECH ? Cargo(XL_GYRO)
03664                                                 : t == Special(GYRO)
03665                                                 && MechSpecials2(mech) & HDGYRO_TECH ? Cargo(HD_GYRO)
03666                                                 : t == Special(GYRO)
03667                                                 && MechSpecials2(mech) & CGYRO_TECH ? Cargo(COMP_GYRO)
03668                                                 : t);
03669                         }
03670                         return part;
03671                 }
03672 
03673                 int ProperMyomer(MECH * mech) {
03674                         int part;
03675 
03676                         part =
03677                                 (MechSpecials(mech) & TRIPLE_MYOMER_TECH ?
03678                                  TON_TRIPLEMYOMER_FIRST : TON_MYOMER_FIRST);
03679                         part += GetPartMod(mech, 0);
03680 
03681                         return Cargo(part);
03682                 }
03683 #endif
03684 
03685 /* Function to return a value of how much heat a unit is putting out*/
03686 /* TODO: Double check how Stealth Armor and Null Sig are coded */
03687                 int HeatFactor(MECH * mech) {
03688 
03689                         int factor = 0;
03690                         char buf[LBUF_SIZE];
03691 
03692                         if(MechType(mech) != CLASS_MECH) {
03693                                 factor = (((MechSpecials(mech) & ICE_TECH)) ? -1 : 21);
03694                                 return factor;
03695                         } else {
03696                                 factor =
03697                                         (MechPlusHeat(mech) +
03698                                          (2 * (MechPlusHeat(mech) - MechMinusHeat(mech))));
03699                                 return ((NullSigSysActive(mech) || HasWorkingECMSuite(mech)
03700                                                  || StealthArmorActive(mech)) ? -1 : factor);
03701                         }
03702                         snprintf(buf, LBUF_SIZE,
03703                                          "HeatFactor : Invalid heat factor calculation on #%d.",
03704                                          mech->mynum);
03705                         SendDebug(buf);
03706                 }
03707 
03708 /* Function to determine if a weapon is functional or not
03709    Returns 0 if fully functional.
03710    Returns 1 if non functional.
03711    Returns 2 if fully damaged.
03712    Returns -(# of crits) if partially damaged.
03713    remember that values 3 means the weapon IS NOT destroyed.  */
03714                 int WeaponIsNonfunctional(MECH * mech, int section, int crit,
03715                                                                   int numcrits) {
03716                         int sum = 0, disabled = 0, dested = 0;
03717 
03718                         if(numcrits <= 0)
03719                                 numcrits =
03720                                         GetWeaponCrits(mech,
03721                                                                    Weapon2I(GetPartType
03722                                                                                         (mech, section, crit)));
03723 
03724                         while (sum < numcrits) {
03725                                 if(PartIsDestroyed(mech, section, crit + sum))
03726                                         dested++;
03727                                 else if(PartIsDisabled(mech, section, crit + sum))
03728                                         disabled++;
03729                                 sum++;
03730                         }
03731 
03732                         if(disabled > 0)
03733                                 return 1;
03734 
03735                         if((numcrits == 1 && (dested || disabled)) ||
03736                            (numcrits > 1 && (dested + disabled) >= numcrits / 2))
03737                                 return 2;
03738 
03739                         if(dested)
03740                                 return 0 - (dested + disabled);
03741 
03742                         return 0;
03743                 }

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