/* * $Id: mech.utils.c,v 1.9 2005/08/03 21:40:54 av1-op Exp $ * * Author: Markus Stenberg <fingon@iki.fi> * * Copyright (c) 1996 Markus Stenberg * Copyright (c) 1998-2002 Thomas Wouters * Copyright (c) 2000-2002 Cord Awtry * Copyright (c) 1999-2005 Kevin Stevens * All rights reserved * * Last modified: Fri Dec 11 00:54:46 1998 fingon * */ #include "config.h" #include <stdio.h> #include <stdlib.h> #include <math.h> #include <sys/file.h> #include "mech.h" #include "map.h" #include "mech.events.h" #include "p.mech.restrict.h" #include "p.mech.utils.h" #include "p.mech.startup.h" #include "p.ds.bay.h" #include "p.btechstats.h" #include "p.mechrep.h" #include "p.crit.h" #include "p.mech.combat.h" #include "p.mech.damage.h" #include "p.template.h" #include "p.bsuit.h" #include "p.mech.los.h" #include "p.aero.bomb.h" #include "autopilot.h" #ifdef BT_ADVANCED_ECON #include "p.mech.custom.h" #include "p.mech.tech.do.h" #endif #ifdef BT_PART_WEIGHTS /* From template.c */ extern int internalsweight[]; extern int cargoweight[]; #endif #ifdef BT_MOVEMENT_MODES #include "failures.h" #endif extern dbref pilot_override; const char *mechtypenames[CLASS_LAST + 1] = { "mech", "tank", "VTOL", "vessel", "aerofighter", "DropShip" }; const char *mechtypename(MECH * foo) { return mechtypenames[(int) MechType(foo)]; } int MNumber(MECH * mech, int low, int high) { if ((muxevent_tick / RANDOM_TICK) != MechLastRndU(mech)) { MechRnd(mech) = random(); MechLastRndU(mech) = muxevent_tick / RANDOM_TICK; } return (low + MechRnd(mech) % (high - low + 1)); } char *MechIDS(MECH * mech, int islower) { static char buf[3]; if (mech) { buf[0] = MechID(mech)[0]; buf[1] = MechID(mech)[1]; } else { buf[0] = '*'; buf[1] = '*'; } buf[2] = 0; if (islower) { buf[0] = tolower(buf[0]); buf[1] = tolower(buf[1]); } return buf; } char *MyToUpper(char *string) { if (*string) *string = toupper(*string); return string; } int CritsInLoc(MECH * mech, int index) { if (MechType(mech) == CLASS_MECH) switch (index) { case HEAD: case RLEG: case LLEG: return 6; case RARM: case LARM: if (MechIsQuad(mech)) return 6; } else if (MechType(mech) == CLASS_MW) return 2; else if (MechType(mech) == CLASS_AERO && index == AERO_COCKPIT) return 5; return NUM_CRITICALS; } int SectHasBusyWeap(MECH * mech, int sect) { int i = 0, count, critical[MAX_WEAPS_SECTION]; unsigned char weaptype[MAX_WEAPS_SECTION]; unsigned char weapdata[MAX_WEAPS_SECTION]; count = FindWeapons(mech, sect, weaptype, weapdata, critical); for (i = 0; i < count; i++) if (WpnIsRecycling(mech, sect, critical[i])) return 1; return 0; } MAP *ValidMap(dbref player, dbref map) { char *str; MAP *maps; DOCHECKN(!Good_obj(map), "Index out of range!"); str = silly_atr_get(map, A_XTYPE); DOCHECKN(!str || !*str, "That is not a valid map! (no XTYPE!)"); DOCHECKN(strcmp("MAP", str), "That is not a valid map!"); DOCHECKN(!(maps = getMap(map)), "The map has not been allocated!!"); return maps; } dbref FindMechOnMap(MAP * map, char *mechid) { int loop; MECH *tempMech; for (loop = 0; loop < map->first_free; loop++) if (map->mechsOnMap[loop] != -1) { tempMech = getMech(map->mechsOnMap[loop]); if (tempMech && !strncasecmp(MechID(tempMech), mechid, 2)) return tempMech->mynum; } return -1; } dbref FindTargetDBREFFromMapNumber(MECH * mech, char *mapnum) { MAP *map; if (mech->mapindex == -1) return -1; map = getMap(mech->mapindex); if (!map) { SendError(tprintf("FTDBREFFMN:invalid map:Mech: %d Index: %d", mech->mynum, mech->mapindex)); mech->mapindex = -1; return -1; } return FindMechOnMap(map, mapnum); } void FindComponents(float magnitude, int degrees, float *x, float *y) { *x = magnitude * fcos((float) (TWOPIOVER360 * (degrees + 90))); *y = magnitude * fsin((float) (TWOPIOVER360 * (degrees + 90))); *x = -(*x); /* because 90 is to the right */ *y = -(*y); /* because y increases downwards */ } static int Leave_Hangar(MAP * map, MECH * mech) { MECH *car = NULL; int mapob; mapobj *mapo; /* For now, leaving leads to finding yourself on the new map at a predetermined position */ mapob = mech->mapindex; if (MechCarrying(mech) > 0) car = getMech(MechCarrying(mech)); DOCHECKMA0(!map->cf, "The entrance is still filled with rubble!"); MechLOSBroadcast(mech, "has left the hangar."); mech_Rsetmapindex(GOD, (void *) mech, tprintf("%d", (int) map->mapobj[TYPE_LEAVE]->obj)); if (car) mech_Rsetmapindex(GOD, (void *) car, tprintf("%d", (int) map->mapobj[TYPE_LEAVE]->obj)); map = getMap(mech->mapindex); if (mech->mapindex == mapob) { SendError(tprintf("#%d %s attempted to leave, but no target map?", mech->mynum, GetMechID(mech))); mech_notify(mech, MECHALL, "Exit of this map is.. fubared. Please contact a wizard"); return 0; } if (!(mapo = find_entrance_by_target(map, mapob))) { SendError(tprintf ("#%d %s attempted to leave, but no target place was found? setting the mech at 0,0 at %d.", mech->mynum, GetMechID(mech), mech->mapindex)); mech_notify(mech, MECHALL, "Weird bug happened during leave. Please contact a wizard. "); return 1; } StopBSuitSwarmers(FindObjectsData(mech->mapindex), mech, 1); mech_notify(mech, MECHALL, tprintf("You have left %s.", structure_name(mapo))); mech_Rsetxy(GOD, (void *) mech, tprintf("%d %d", mapo->x, mapo->y)); ContinueFlying(mech); if (car) MirrorPosition(mech, car, 0); MechLOSBroadcast(mech, tprintf("has left %s at %d,%d.", structure_name(mapo), MechX(mech), MechY(mech))); loud_teleport(mech->mynum, mech->mapindex); if (car) loud_teleport(car->mynum, mech->mapindex); if (In_Character(mech->mynum) && Location(MechPilot(mech)) != mech->mynum) { mech_notify(mech, MECHALL, "%ch%cr%cf%ciINTRUDER ALERT! INTRUDER ALERT!%c"); mech_notify(mech, MECHALL, "%ch%cr%cfAutomatic self-destruct sequence initiated...%c"); mech_shutdown(GOD, (void *) mech, ""); } auto_cal_mapindex(mech); if (MechSpeed(mech) > MMaxSpeed(mech)) MechSpeed(mech) = MMaxSpeed(mech); return 1; } void CheckEdgeOfMap(MECH * mech) { int pinned = 0; int linked; MAP *map; map = getMap(mech->mapindex); if (!map) { mech_notify(mech, MECHPILOT, "You are on an invalid map! Map index reset!"); mech_shutdown(MechPilot(mech), (void *) mech, ""); SendError(tprintf("CheckEdgeofMap:invalid map:Mech: %d Index: %d", mech->mynum, mech->mapindex)); mech->mapindex = -1; return; } linked = map_linked(mech->mapindex); /* Prevents you from going off the map */ /* Eventually this could wrap and all that.. */ if (MechX(mech) < 0) { if (linked) { MechX(mech) += map->map_width; pinned = -1; } else { MechX(mech) = 0; pinned = 4; } } else if (MechX(mech) >= map->map_width) { if (linked) { MechX(mech) -= map->map_width; pinned = -1; } else { MechX(mech) = map->map_width - 1; pinned = 2; } } if (MechY(mech) < 0) { if (linked) { pinned = -1; MechY(mech) += map->map_height; } else { MechY(mech) = 0; pinned = 1; } } else if (MechY(mech) >= map->map_height) { if (linked) { pinned = -1; MechY(mech) -= map->map_height; } else { MechY(mech) = map->map_height - 1; pinned = 3; } } if (pinned > 0) { /* This is a DS bay. First, we need to check if the bay's doors are blocked, one way or another. */ if (map->onmap && IsMech(map->onmap)) { if (Leave_DS(map, mech)) return; } else if (map->flags & MAPFLAG_MAPO && map->mapobj[TYPE_LEAVE]) if (Leave_Hangar(map, mech)) return; } if (pinned) { MapCoordToRealCoord(MechX(mech), MechY(mech), &MechFX(mech), &MechFY(mech)); if (pinned > 0) { mech_notify(mech, MECHALL, "You cannot move off this map!"); if (Jumping(mech) && !is_aero(mech)) LandMech(mech); MechCocoon(mech) = 0; MechSpeed(mech) = 0.0; MechDesiredSpeed(mech) = 0.0; if (is_aero(mech)) { MechStartFX(mech) = 0.0; MechStartFY(mech) = 0.0; MechStartFZ(mech) = 0.0; if (!Landed(mech)) MaybeMove(mech); } } } } int FindZBearing(float x0, float y0, float z0, float x1, float y1, float z1) { float hyp, opp, deg; hyp = FindRange(x0, y0, z0, x1, y1, z1); if (hyp <= 0.0) return 0; opp = FindRange(0, 0, 0, 0, 0, fabsf(z1 - z0)); deg = asin(opp / hyp) * (180 / PI); return ceilf(deg); } int FindBearing(float x0, float y0, float x1, float y1) { float deltax, deltay; float temp, rads; int degrees; deltax = (x0 - x1); deltay = (y0 - y1); if (deltax == 0.0) { /* Quick handling inserted here */ if (deltay > 0.0) return 0; else return 180; } temp = deltay / deltax; if (temp < 0.0) temp = -temp; rads = fatan(temp); degrees = (int) (rads * 10.0 / TWOPIOVER360); /* Round off degrees */ degrees = (degrees + 5) / 10; if (deltax < 0.0 && deltay < 0.0) degrees += 180; else if (deltax < 0.0) degrees = 180 - degrees; else if (deltay < 0.0) degrees = 360 - degrees; return AcceptableDegree(degrees - 90); } int InWeaponArc(MECH * mech, float x, float y) { int relat; int bearingToTarget; int res = NOARC; bearingToTarget = FindBearing(MechFX(mech), MechFY(mech), x, y); relat = MechFacing(mech) - bearingToTarget; if (MechType(mech) == CLASS_MECH || MechType(mech) == CLASS_MW || MechType(mech) == CLASS_BSUIT) { if (MechStatus(mech) & TORSO_RIGHT) relat += 59; else if (MechStatus(mech) & TORSO_LEFT) relat -= 59; } relat = AcceptableDegree(relat); if (relat >= 300 || relat <= 60) res |= FORWARDARC; if (relat > 120 && relat < 240) res |= REARARC; if (relat >= 240 && relat < 300) res |= RSIDEARC; if (relat > 60 && relat <= 120) res |= LSIDEARC; if (MechHasTurret(mech)) { relat = AcceptableDegree((MechFacing(mech) + MechTurretFacing(mech)) - bearingToTarget); if (relat >= 330 || relat <= 30) res |= TURRETARC; } if (res == NOARC) SendError(tprintf("NoArc: #%d: BearingToTarget:%d Facing:%d", mech->mynum, bearingToTarget, MechFacing(mech))); return res; } char *FindGunnerySkillName(MECH * mech, int weapindx) { #ifndef BT_EXILE_MW3STATS switch (MechType(mech)) { case CLASS_BSUIT: return "Gunnery-BSuit"; case CLASS_MECH: return "Gunnery-Battlemech"; case CLASS_VEH_GROUND: case CLASS_VEH_NAVAL: return "Gunnery-Conventional"; case CLASS_VTOL: case CLASS_AERO: return "Gunnery-Aerospace"; case CLASS_SPHEROID_DS: case CLASS_DS: return "Gunnery-Spacecraft"; case CLASS_MW: if (weapindx >= 0) { if (!strcmp(MechWeapons[weapindx].name, "PC.Sword")) return "Blade"; if (!strcmp(MechWeapons[weapindx].name, "PC.Vibroblade")) return "Blade"; } return "Small_Arms"; } #else if (weapindx < 0) return NULL; if (MechType(mech) == CLASS_MW) { if (weapindx >= 0) { if (!strcmp(MechWeapons[weapindx].name, "PC.Blade")) return "Blade"; if (!strcmp(MechWeapons[weapindx].name, "PC.Vibroblade")) return "Blade"; if (!strcmp(MechWeapons[weapindx].name, "PC.Blazer")) return "Support_Weapons"; if (!strcmp(MechWeapons[weapindx].name, "PC.HeavyGyrojetGun")) return "Support_Weapons"; return "Small_Arms"; } } else if (IsArtillery(weapindx)) return "Gunnery-Artillery"; else if (IsMissile(weapindx)) return "Gunnery-Missile"; else if (IsBallistic(weapindx)) return "Gunnery-Ballistic"; else if (IsEnergy(weapindx)) return "Gunnery-Laser"; else if (IsFlamer(weapindx)) return "Gunnery-Flamer"; #endif return NULL; } char *FindPilotingSkillName(MECH * mech) { #ifndef BT_EXILE_MW3STATS switch (MechType(mech)) { case CLASS_MW: return "Running"; case CLASS_BSUIT: return "Piloting-BSuit"; case CLASS_MECH: return "Piloting-Battlemech"; case CLASS_VEH_GROUND: case CLASS_VEH_NAVAL: return "Drive"; case CLASS_VTOL: case CLASS_AERO: return "Piloting-Aerospace"; case CLASS_SPHEROID_DS: case CLASS_DS: return "Piloting-Spacecraft"; } #else if (MechType(mech) == CLASS_MW && MechRTerrain(mech) == WATER) return "Swimming"; switch (MechType(mech)) { case CLASS_MW: return "Running"; case CLASS_BSUIT: return "Piloting-Bsuit"; case CLASS_VEH_NAVAL: return "Piloting-Naval"; case CLASS_DS: case CLASS_SPHEROID_DS: return "Piloting-Spacecraft"; case CLASS_VTOL: case CLASS_AERO: return "Piloting-Aerospace"; } switch (MechMove(mech)) { case MOVE_BIPED: return "Piloting-Biped"; case MOVE_QUAD: return "Piloting-Quad"; case MOVE_TRACK: return "Piloting-Tracked"; case MOVE_HOVER: return "Piloting-Hover"; case MOVE_WHEEL: return "Piloting-Wheeled"; } #endif return NULL; } #define MECHSKILL_PILOTING 0 #define MECHSKILL_GUNNERY 1 #define MECHSKILL_SPOTTING 2 #define MECHSKILL_ARTILLERY 3 #define NUM_MECHSKILLS 4 #define GENERIC_FIND_MECHSKILL(num,n) \ if (Quiet(mech->mynum)) \ { str = silly_atr_get(mech->mynum, A_MECHSKILLS); \ if (*str) if (sscanf (str, "%d %d %d %d", &i[0], &i[1], &i[2], &i[3]) > num) \ return i[num] - n; } int FindPilotPiloting(MECH * mech) { char *str; int i[NUM_MECHSKILLS]; GENERIC_FIND_MECHSKILL(MECHSKILL_PILOTING, 0); if (RGotPilot(mech)) if ((str = FindPilotingSkillName(mech))) return char_getskilltarget(MechPilot(mech), str, 0); return DEFAULT_PILOTING; } int FindSPilotPiloting(MECH * mech) { return FindPilotPiloting(mech) + (MechMove(mech) == MOVE_QUAD ? -2 : 0); } int FindPilotSpotting(MECH * mech) { char *str; int i[NUM_MECHSKILLS]; GENERIC_FIND_MECHSKILL(MECHSKILL_SPOTTING, 0); if (RGotPilot(mech)) return (char_getskilltarget(MechPilot(mech), "Gunnery-Spotting", 0)); return DEFAULT_SPOTTING; } int FindPilotArtyGun(MECH * mech) { char *str; int i[NUM_MECHSKILLS]; GENERIC_FIND_MECHSKILL(MECHSKILL_ARTILLERY, 0); if (RGotGPilot(mech)) return (char_getskilltarget(GunPilot(mech), "Gunnery-Artillery", 0)); return DEFAULT_ARTILLERY; } int FindPilotGunnery(MECH * mech, int weapindx) { char *str; int i[NUM_MECHSKILLS]; GENERIC_FIND_MECHSKILL(MECHSKILL_GUNNERY, 0); if (RGotGPilot(mech)) if ((str = FindGunnerySkillName(mech, weapindx))) return char_getskilltarget(GunPilot(mech), str, 0); return DEFAULT_GUNNERY; } char *FindTechSkillName(MECH * mech) { switch (MechType(mech)) { case CLASS_MECH: case CLASS_BSUIT: return "Technician-Battlemech"; case CLASS_VEH_GROUND: case CLASS_VEH_NAVAL: return "Technician-Mechanic"; case CLASS_AERO: case CLASS_VTOL: case CLASS_SPHEROID_DS: case CLASS_DS: return "Technician-Aerospace"; #if 0 /* Used to be DS tech */ return (char_getskilltarget(player, "Technician-Spacecraft", 0)); #endif } return NULL; } int FindTechSkill(dbref player, MECH * mech) { char *skname; if ((skname = FindTechSkillName(mech))) return (char_getskilltarget(player, skname, 0)); return 18; } int MadePilotSkillRoll(MECH * mech, int mods) { return MadePilotSkillRoll_Advanced(mech, mods, 1); } int MechPilotSkillRoll_BTH(MECH *mech, int mods) { mods += FindSPilotPiloting(mech) + MechPilotSkillBase(mech); if (In_Character(mech->mynum) && Location(MechPilot(mech)) != mech->mynum) mods += 5; return mods; } int MadePilotSkillRoll_Advanced(MECH * mech, int mods, int succeedWhenFallen) { int roll, roll_needed; if (Fallen(mech) && succeedWhenFallen) return 1; if (Uncon(mech) || !Started(mech) || Blinded(mech)) return 0; roll = Roll(); roll_needed = MechPilotSkillRoll_BTH(mech, mods); SendDebug(tprintf("Attempting to make pilot skill roll. " "SPilot: %d, mods: %d, MechPilot: %d, BTH: %d", FindSPilotPiloting(mech), mods, MechPilotSkillBase(mech), roll_needed)); mech_notify(mech, MECHPILOT, "You make a piloting skill roll!"); mech_notify(mech, MECHPILOT, tprintf("Modified Pilot Skill: BTH %d\tRoll: %d", roll_needed, roll)); if (roll >= roll_needed) { if (roll_needed > 2) AccumulatePilXP(MechPilot(mech), mech, BOUNDED(1, roll_needed - 7, MAX(2, 1 + mods)), 1); return 1; } return 0; } void FindXY(float x0, float y0, int bearing, float range, float *x1, float *y1) { float xscale, correction; correction = (float) (bearing % 60) / 60.0; if (correction > 0.5) correction = 1.0 - correction; correction = -correction * 2.0; /* 0 - 1 correction */ xscale = (1.0 + XSCALE * correction) * SCALEMAP; *y1 = y0 - cos((float) bearing * 6.283185307 / 360.0) * range * SCALEMAP; *x1 = x0 + sin((float) bearing * 6.283185307 / 360.0) * range * xscale; } float FindRange(float x0, float y0, float z0, float x1, float y1, float z1) { /* range in hexes */ float xscale; float XYrange; float Zrange; xscale = 1.0 / SCALEMAP; xscale = xscale * xscale; XYrange = sqrt(xscale * (x0 - x1) * (x0 - x1) + YSCALE2 * (y0 - y1) * (y0 - y1)); Zrange = (z0 - z1) / SCALEMAP; return sqrt(XYrange * XYrange + Zrange * Zrange); } float FindXYRange(float x0, float y0, float x1, float y1) { /* range in hexes */ float xscale; float XYrange; xscale = 1.0 / SCALEMAP; xscale = xscale * xscale; XYrange = sqrt(xscale * (x0 - x1) * (x0 - x1) + YSCALE2 * (y0 - y1) * (y0 - y1)); return XYrange; } float FindHexRange(float x0, float y0, float x1, float y1) { return FindXYRange(x0, y0, x1, y1); } /* CONVERSION ROUTINES courtesy Mike :) (Whoever that may be -focus) */ /* Picture blatantly ripped from the MUSH code by Dizzledorf and co. If only I had found it _before_ reverse-engineering the code :) - Focus, July 2002. */ /* Convert floating-point cartesian coordinates into hex coordinates. To do this, split the hex map into a repeatable region, which itself has 4 distinct regions, each part of a different hex. (See picture.) The hex is normalized so that it is 1 unit high, and so is the repeatable region. It works out that the repeatable region is exactly sqrt(3) wide, and can be split up in six portions of each 1/6th sqrt(3), called 'alpha'. Section I is 2 alpha wide at the top and bottom, and 3 alpha in the middle. Sections II and III are reversed, being 3 alpha at the top and bottom of the region, and 2 alpha in the middle. Section IV is 1 alpha in the middle and 0 at the top and bottom. The whole region encompasses exactly two x-columns and one y-row. All calculations are now done in 'real' scale, to avoid rounding errors (isn't floating point arithmatic fun ?) Alpha also returns in the angle of the hexsides, that being 2*alpha (flipped or rotated when necessary) making the calculations look confusing. ANGLE_ALPHA is alpha (unscaled) for use in angle calculations. ________________________ | \ /| | \ III / | | \ / | | \________/ IV| | I / \ | | / II \ | | / \ | |________/______________\| */ /* Doubles for added accuracy; most calculations are doubles internally anyway, so we suffer little to no performance hit. */ #define ALPHA 93.097730906827152 /* sqrt(3) * SCALEMAP */ #define ROOT3 558.58638544096289 /* ROOT3 / 6 */ #define ANGLE_ALPHA 0.28867513459481287 /* sqrt(3) / 6 */ #define FULL_Y (1 * SCALEMAP) #define HALF_Y (0.5 * FULL_Y) void RealCoordToMapCoord(short *hex_x, short *hex_y, float cart_x, float cart_y) { float x, y; int x_count, y_count; if (cart_x < ALPHA) { /* Special case: we are in section IV of x-column 0 or off the map */ *hex_x = cart_x < 0 ? -1 : 0; *hex_y = floor(cart_y / SCALEMAP); return; } /* 'shift' the map to the left so the repeatable box starts at 0 */ cart_x -= ALPHA; /* Figure out the x-coordinate of the 'repeatable box' we're in. */ x_count = cart_x / ROOT3; /* And the offset inside the box, from the left edge. */ x = cart_x - x_count * ROOT3; /* The repbox holds two x-columns, we want the real X coordinate. */ x_count *= 2; /* Do the same for the y-coordinate; this is easy */ y_count = floor(cart_y / FULL_Y); y = cart_y - y_count * FULL_Y; if (x < 2 * ALPHA) { /* Clean in area I. Nothing to do */ } else if (x >= 3 * ALPHA && x < 5 * ALPHA) { /* Clean in either area II or III. Up x one, and y if in the lower half of the box. */ x_count++; if (y >= HALF_Y) /* Area II */ y_count++; } else if (x >= 2 * ALPHA && x < 3 * ALPHA) { /* Any of areas I, II and III. */ if (y >= HALF_Y) { /* Area I or II */ if (2 * ANGLE_ALPHA * (FULL_Y - y) <= x - 2 * ALPHA) { /* Area II, up both */ x_count++; y_count++; } } else { /* Area I or III */ if (2 * ANGLE_ALPHA * y <= x - 2 * ALPHA) /* Area III, up only x */ x_count++; } } else if (y >= HALF_Y) { /* Area II or IV. Up x at least one, maybe two, and y maybe one. */ x_count++; if (2 * ANGLE_ALPHA * (y - HALF_Y) > (x - 5.0 * ALPHA)) /* Area II */ y_count++; else /* Area IV */ x_count++; } else { /* Area III or IV, up x at least one, maybe two */ x_count++; if (2 * ANGLE_ALPHA * y > ROOT3 - x) /* Area IV */ x_count++; } *hex_x = x_count; *hex_y = y_count; } /* If hex_x is odd, it falls smack in the middle of area III, right at the top edge of the repeatable box. Subtract one and multiply by one half sqrt(3) (or 3 alpha) to get the repeatable box coordinate, then add 5 alpha for offset inside the box. The y coordinate is not modified. If hex_x is even, just multiply by 3 alpha to get the box coordinate, and add 2 alpha for offset inside the box. The center is in the middle of the box, so y is increased by half the box height. */ void MapCoordToRealCoord(int hex_x, int hex_y, float *cart_x, float *cart_y) { if (hex_x % 2) { *cart_x = (hex_x - 1.0) * 3.0 * ALPHA + 5.0 * ALPHA; *cart_y = hex_y * FULL_Y; } else { *cart_x = hex_x * 3.0 * ALPHA + 2.0 * ALPHA; *cart_y = hex_y * FULL_Y + HALF_Y; } } /* Sketch a 'mech on a Navigate map. Done here since it fiddles directly with cartesian coords. Navigate is 9 rows high, and a hex is exactly 1*SCALEMAP high, so each row is FULL_Y/9 cartesian y-coords high. Navigate is 21 hexes wide, at its widest point. This corresponds to the hex width, which is 4 * ALPHA, so each column is 4*ALPHA/21 cartesian x-coords wide. The actual navigate map starts two rows from the top and four columns from the left. */ #define NAV_ROW_HEIGHT (FULL_Y / 9.0) #define NAV_COLUMN_WIDTH (4 * ALPHA / 21.0) #define NAV_Y_OFFSET 2 #define NAV_X_OFFSET 4 #define NAV_MAX_HEIGHT 2+9+2 #define NAV_MAX_WIDTH 4+21+2 void navigate_sketch_mechs(MECH * mech, MAP * map, int x, int y, char buff[NAVIGATE_LINES][MBUF_SIZE]) { float corner_fx, corner_fy, fx, fy; int i, row, column; MECH *other; MapCoordToRealCoord(x, y, &corner_fx, &corner_fy); corner_fx -= 2 * ALPHA; corner_fy -= HALF_Y; for (i = 0; i < map->first_free; i++) { if (map->mechsOnMap[i] < 0) continue; if (!(other = FindObjectsData(map->mechsOnMap[i]))) continue; if (other == mech) continue; if (MechX(other) != x || MechY(other) != y) continue; if (!InLineOfSight(mech, other, x, y, 0.5)) continue; fx = MechFX(other) - corner_fx; column = fx / NAV_COLUMN_WIDTH + NAV_X_OFFSET; fy = MechFY(other) - corner_fy; row = fy / NAV_ROW_HEIGHT + NAV_Y_OFFSET; if (column < 0 || column > NAV_MAX_WIDTH || row < 0 || row > NAV_MAX_HEIGHT) continue; buff[row][column] = MechSeemsFriend(mech, other) ? 'x' : 'X'; } /* Draw 'mech last so we always see it. */ fx = MechFX(mech) - corner_fx; column = fx / NAV_COLUMN_WIDTH + NAV_X_OFFSET; fy = MechFY(mech) - corner_fy; row = fy / NAV_ROW_HEIGHT + NAV_Y_OFFSET; if (column < 0 || column > NAV_MAX_WIDTH || row < 0 || row > NAV_MAX_HEIGHT) return; buff[row][column] = '*'; } int FindTargetXY(MECH * mech, float *x, float *y, float *z) { MECH *tempMech; if (MechTarget(mech) != -1) { tempMech = getMech(MechTarget(mech)); if (tempMech) { *x = MechFX(tempMech); *y = MechFY(tempMech); *z = MechFZ(tempMech); return 1; } } else if (MechTargX(mech) != -1 && MechTargY(mech) != -1) { MapCoordToRealCoord(MechTargX(mech), MechTargY(mech), x, y); *z = (float) ZSCALE *(MechTargZ(mech)); return 1; } return 0; } int global_silence = 0; #define UGLYTEST \ if (num_crits) \ { \ if (num_crits != (i = GetWeaponCrits (mech, lastweap))) \ { \ if (whine && !global_silence) \ SendError (tprintf ("Error in the numcriticals for weapon on #%d! (Should be: %d, is: %d)", mech->mynum, i, num_crits)); \ return -1; \ } \ num_crits = 0; \ } /* ASSERTION: Weapons must be located next to each other in criticals */ /* This is a hacked function. Sorry. */ int FindWeapons_Advanced(MECH * mech, int index, unsigned char *weaparray, unsigned char *weapdataarray, int *critical, int whine) { int loop; int weapcount = 0; int temp, data, lastweap = -1; int num_crits = 0, i; for (loop = 0; loop < MAX_WEAPS_SECTION; loop++) { temp = GetPartType(mech, index, loop); data = GetPartData(mech, index, loop); if (IsWeapon(temp)) { temp = Weapon2I(temp); if (weapcount == 0) { lastweap = temp; weapdataarray[weapcount] = data; weaparray[weapcount] = temp; critical[weapcount] = loop; weapcount++; num_crits = 1; continue; } if (!num_crits || temp != lastweap || (num_crits == GetWeaponCrits(mech, temp))) { UGLYTEST; weaparray[weapcount] = temp; weapdataarray[weapcount] = data; critical[weapcount] = loop; lastweap = temp; num_crits = 1; weapcount++; } else num_crits++; } else UGLYTEST; } UGLYTEST; return (weapcount); } int FindAmmunition(MECH * mech, unsigned char *weaparray, unsigned short *ammoarray, unsigned short *ammomaxarray, unsigned int *modearray) { int loop; int weapcount = 0; int temp, data, mode; int index, i, j, duplicate; for (index = 0; index < NUM_SECTIONS; index++) for (loop = 0; loop < MAX_WEAPS_SECTION; loop++) { temp = GetPartType(mech, index, loop); if (IsAmmo(temp)) { data = GetPartData(mech, index, loop); mode = (GetPartAmmoMode(mech, index, loop) & AMMO_MODES); temp = Ammo2Weapon(temp); duplicate = 0; for (i = 0; i < weapcount; i++) { if (temp == weaparray[i] && mode == modearray[i]) { if (!(PartIsNonfunctional(mech, index, loop))) ammoarray[i] += data; ammomaxarray[i] += FullAmmo(mech, index, loop); duplicate = 1; } } if (!duplicate) { weaparray[weapcount] = temp; if (!(PartIsNonfunctional(mech, index, loop))) ammoarray[weapcount] = data; else ammoarray[weapcount] = 0; ammomaxarray[weapcount] = FullAmmo(mech, index, loop); modearray[weapcount] = mode; weapcount++; } } } /* Then, prune entries with 0 ammo left */ for (i = 0; i < weapcount; i++) if (!ammoarray[i]) { for (j = i + 1; j < weapcount; j++) { weaparray[j - 1] = weaparray[j]; ammoarray[j - 1] = ammoarray[j]; ammomaxarray[j - 1] = ammomaxarray[j]; modearray[j - 1] = modearray[j]; } i--; weapcount--; } return (weapcount); } int FindLegHeatSinks(MECH * mech) { int loop; int heatsinks = 0; for (loop = 0; loop < NUM_CRITICALS; loop++) { if (GetPartType(mech, LLEG, loop) == I2Special((HEAT_SINK)) && !PartIsNonfunctional(mech, LLEG, loop)) heatsinks++; if (GetPartType(mech, RLEG, loop) == I2Special((HEAT_SINK)) && !PartIsNonfunctional(mech, RLEG, loop)) heatsinks++; /* * Added by Kipsta on 8/5/99 * Quads can get 'arm' HS in the water too */ if (MechIsQuad(mech)) { if (GetPartType(mech, LARM, loop) == I2Special((HEAT_SINK)) && !PartIsNonfunctional(mech, LARM, loop)) heatsinks++; if (GetPartType(mech, RARM, loop) == I2Special((HEAT_SINK)) && !PartIsNonfunctional(mech, RARM, loop)) heatsinks++; } } return (heatsinks); } /* Added for tic support. */ /* returns the weapon index- -1 for not found, -2 for destroyed, -3, -4 */ /* for reloading/recycling */ int FindWeaponNumberOnMech_Advanced(MECH * mech, int number, int *section, int *crit, int sight) { int loop; unsigned char weaparray[MAX_WEAPS_SECTION]; unsigned char weapdata[MAX_WEAPS_SECTION]; int critical[MAX_WEAPS_SECTION]; int running_sum = 0; int num_weaps; int index; for (loop = 0; loop < NUM_SECTIONS; loop++) { num_weaps = FindWeapons(mech, loop, weaparray, weapdata, critical); if (num_weaps <= 0) continue; if (number < running_sum + num_weaps) { /* we found it... */ index = number - running_sum; if (PartIsNonfunctional(mech, loop, critical[index])) { *section = loop; *crit = critical[index]; return TIC_NUM_DESTROYED; } else if (weapdata[index] > 0 && !sight) { *section = loop; *crit = critical[index]; return (MechWeapons[weaparray[index]].type == TBEAM) ? TIC_NUM_RECYCLING : TIC_NUM_RELOADING; } else { if (MechSections(mech)[loop].recycle && (MechType(mech) == CLASS_MECH || MechType(mech) == CLASS_VEH_GROUND || MechType(mech) == CLASS_VTOL) && !sight) { *section = loop; *crit = critical[index]; /* just did a physical attack */ return TIC_NUM_PHYSICAL; } /* The recylce data for the weapon is clear- it is ready to fire! */ *section = loop; *crit = critical[index]; return weaparray[index]; } } else running_sum += num_weaps; } return -1; } int FindWeaponNumberOnMech(MECH * mech, int number, int *section, int *crit) { return FindWeaponNumberOnMech_Advanced(mech, number, section, crit, 0); } int FindWeaponFromIndex(MECH * mech, int weapindx, int *section, int *crit) { int loop; unsigned char weaparray[MAX_WEAPS_SECTION]; unsigned char weapdata[MAX_WEAPS_SECTION]; int critical[MAX_WEAPS_SECTION]; int num_weaps; int index; for (loop = 0; loop < NUM_SECTIONS; loop++) { num_weaps = FindWeapons(mech, loop, weaparray, weapdata, critical); for (index = 0; index < num_weaps; index++) if (weaparray[index] == weapindx) { *section = loop; *crit = critical[index]; if (!PartIsNonfunctional(mech, loop, index) && !WpnIsRecycling(mech, loop, index)) return 1; /* Return if not Recycling/Destroyed */ /* Otherwise keep looking */ } } return 0; } int FindWeaponIndex(MECH * mech, int number) { int loop; unsigned char weaparray[MAX_WEAPS_SECTION]; unsigned char weapdata[MAX_WEAPS_SECTION]; int critical[MAX_WEAPS_SECTION]; int running_sum = 0; int num_weaps; int index; if (number < 0) return -1; /* Anti-crash */ for (loop = 0; loop < NUM_SECTIONS; loop++) { num_weaps = FindWeapons(mech, loop, weaparray, weapdata, critical); if (num_weaps <= 0) continue; if (number < running_sum + num_weaps) { /* we found it... */ index = number - running_sum; return weaparray[index]; } running_sum += num_weaps; } return -1; } int findAmmoInSection(MECH * mech, int section, int type, int nogof, int gof) { int wIter; /* Can't use LBX ammo as normal, but can use Narc and Artemis as normal */ for (wIter = 0; wIter < NUM_CRITICALS; wIter++) { if (GetPartType(mech, section, wIter) == type && !PartIsNonfunctional(mech, section, wIter) && (!nogof || !(GetPartAmmoMode(mech, section, wIter) & nogof)) && (!gof || (GetPartAmmoMode(mech, section, wIter) & gof))) { if (!PartIsNonfunctional(mech, section, wIter) && GetPartData(mech, section, wIter) > 0) return wIter; } } return -1; } int FindAmmoForWeapon_sub(MECH * mech, int weapSection, int weapCritical, int weapindx, int start, int *section, int *critical, int nogof, int gof) { int loop; int foundSlot; int desired; int wCritType = 0; int wWeapSize = 0; int wFirstCrit = 0; int wDesiredLoc = -1; desired = I2Ammo(weapindx); /* The data on the desired location */ if ((weapSection > -1) && (weapCritical > -1)) { wCritType = GetPartType(mech, weapSection, weapCritical); wWeapSize = GetWeaponCrits(mech, Weapon2I(wCritType)); wFirstCrit = FindFirstWeaponCrit(mech, weapSection, weapCritical, 0, wCritType, wWeapSize); wDesiredLoc = GetPartDesiredAmmoLoc(mech, weapSection, wFirstCrit); if (wDesiredLoc >= 0) { foundSlot = findAmmoInSection(mech, wDesiredLoc, desired, nogof, gof); if (foundSlot >= 0) { *section = wDesiredLoc; *critical = foundSlot; return 1; } } } /* Now lets search the current section */ foundSlot = findAmmoInSection(mech, start, desired, nogof, gof); if (foundSlot >= 0) { *section = start; *critical = foundSlot; return 1; } /* If all else fails, start hunting for ammo */ for (loop = 0; loop < NUM_SECTIONS; loop++) { if ((loop == start) || (loop == wDesiredLoc)) continue; foundSlot = findAmmoInSection(mech, loop, desired, nogof, gof); if (foundSlot >= 0) { *section = loop; *critical = foundSlot; return 1; } } return 0; } int FindAmmoForWeapon(MECH * mech, int weapindx, int start, int *section, int *critical) { return FindAmmoForWeapon_sub(mech, -1, -1, weapindx, start, section, critical, AMMO_MODES, 0); } int CountAmmoForWeapon(MECH * mech, int weapindx) { int wSecIter; int wSlotIter; int wcAmmo = 0; int wAmmoIdx; wAmmoIdx = I2Ammo(weapindx); for (wSecIter = 0; wSecIter < NUM_SECTIONS; wSecIter++) { for (wSlotIter = 0; wSlotIter < NUM_CRITICALS; wSlotIter++) { if ((GetPartType(mech, wSecIter, wSlotIter) == wAmmoIdx) && !PartIsNonfunctional(mech, wSecIter, wSlotIter) && (GetPartData(mech, wSecIter, wSlotIter) > 0)) wcAmmo += GetPartData(mech, wSecIter, wSlotIter); } } return wcAmmo; } int FindArtemisForWeapon(MECH * mech, int section, int critical) { int critloop; int desired; desired = I2Special(ARTEMIS_IV); for (critloop = 0; critloop < NUM_CRITICALS; critloop++) if (GetPartType(mech, section, critloop) == desired && !PartIsNonfunctional(mech, section, critloop)) { if (GetPartData(mech, section, critloop) == critical) return 1; } return 0; } int FindDestructiveAmmo(MECH * mech, int *section, int *critical) { int loop; int critloop; int maxdamage = 0; int damage; int weapindx; int i; int type, data; for (loop = 0; loop < NUM_SECTIONS; loop++) for (critloop = 0; critloop < NUM_CRITICALS; critloop++) if (IsAmmo(GetPartType(mech, loop, critloop)) && !PartIsDestroyed(mech, loop, critloop)) { data = GetPartData(mech, loop, critloop); type = GetPartType(mech, loop, critloop); weapindx = Ammo2WeaponI(type); damage = data * MechWeapons[weapindx].damage; if (MechWeapons[weapindx].special & GAUSS) continue; if (IsMissile(weapindx) || IsArtillery(weapindx)) { for (i = 0; MissileHitTable[i].key != -1; i++) if (MissileHitTable[i].key == weapindx) damage *= MissileHitTable[i].num_missiles[10]; } if (damage > maxdamage) { *section = loop; *critical = critloop; maxdamage = damage; } } return (maxdamage); } int FindRoundsForWeapon(MECH * mech, int weapindx) { int loop; int critloop; int desired; int found = 0; desired = I2Ammo(weapindx); for (loop = 0; loop < NUM_SECTIONS; loop++) for (critloop = 0; critloop < NUM_CRITICALS; critloop++) if (GetPartType(mech, loop, critloop) == desired && !PartIsNonfunctional(mech, loop, critloop)) found += GetPartData(mech, loop, critloop); return found; } const char *quad_locs[NUM_SECTIONS + 1] = { "Front Left Leg", "Front Right Leg", "Left Torso", "Right Torso", "Center Torso", "Rear Left Leg", "Rear Right Leg", "Head", NULL }; const char *mech_locs[NUM_SECTIONS + 1] = { "Left Arm", "Right Arm", "Left Torso", "Right Torso", "Center Torso", "Left Leg", "Right Leg", "Head", NULL }; const char *bsuit_locs[NUM_BSUIT_MEMBERS + 1] = { "Suit 1", "Suit 2", "Suit 3", "Suit 4", "Suit 5", "Suit 6", "Suit 7", "Suit 8", NULL }; const char *veh_locs[NUM_VEH_SECTIONS + 1] = { "Left Side", "Right Side", "Front Side", "Aft Side", "Turret", "Rotor", NULL }; const char *aero_locs[NUM_AERO_SECTIONS + 1] = { "Nose", "Left Wing", "Right Wing", "Fuselage", "Cockpit", "Engine", NULL }; const char *ds_locs[NUM_DS_SECTIONS + 1] = { "Right Wing", "Left Wing", "Left Rear Wing", "Right Rear Wing", "Aft", "Nose", NULL }; const char *ds_spher_locs[NUM_DS_SECTIONS + 1] = { "Front Right Side", "Front Left Side", "Rear Left Side", "Rear Right Side", "Aft", "Nose", NULL }; const char **ProperSectionStringFromType(int type, int mtype) { switch (type) { case CLASS_BSUIT: return bsuit_locs; case CLASS_MECH: case CLASS_MW: if (mtype == MOVE_QUAD) return quad_locs; return mech_locs; case CLASS_VEH_GROUND: case CLASS_VEH_NAVAL: case CLASS_VTOL: return veh_locs; case CLASS_AERO: return aero_locs; case CLASS_SPHEROID_DS: return ds_spher_locs; case CLASS_DS: return ds_locs; } return NULL; } void ArmorStringFromIndex(int index, char *buffer, char type, char mtype) { const char **locs = ProperSectionStringFromType(type, mtype); int high = 0; switch (type) { case CLASS_MECH: case CLASS_MW: high = NUM_SECTIONS; break; case CLASS_VEH_GROUND: case CLASS_VEH_NAVAL: high = (NUM_VEH_SECTIONS - 1); break; case CLASS_VTOL: high = NUM_VEH_SECTIONS; break; case CLASS_AERO: high = NUM_AERO_SECTIONS; break; case CLASS_SPHEROID_DS: high = NUM_DS_SECTIONS; case CLASS_DS: high = NUM_DS_SECTIONS; break; case CLASS_BSUIT: high = NUM_BSUIT_MEMBERS; break; default: strcpy(buffer, "Invalid!!"); return; } if (high > 0 && index < high && locs) { strcpy(buffer, locs[index]); return; } strcpy(buffer, "Invalid!!"); } int IsInWeaponArc(MECH * mech, float x, float y, int section, int critical) { int weaponarc, isrear; int wantarc = NOARC; if (MechType(mech) == CLASS_MECH && (section == LLEG || section == RLEG || (MechIsQuad(mech) && (section == LARM || section == RARM)))) { int ts = MechStatus(mech) & (TORSO_LEFT | TORSO_RIGHT); MechStatus(mech) &= ~(ts); weaponarc = InWeaponArc(mech, x, y); MechStatus(mech) |= ts; } else weaponarc = InWeaponArc(mech, x, y); switch (MechType(mech)) { case CLASS_MECH: case CLASS_BSUIT: case CLASS_MW: if (GetPartFireMode(mech, section, critical) & REAR_MOUNT) wantarc = REARARC; else if (section == LARM && (MechStatus(mech) & FLIPPED_ARMS)) wantarc = REARARC | LSIDEARC; else if (section == LARM) wantarc = FORWARDARC | LSIDEARC; else if (section == RARM && (MechStatus(mech) & FLIPPED_ARMS)) wantarc = REARARC | RSIDEARC; else if (section == RARM) wantarc = FORWARDARC | RSIDEARC; else wantarc = FORWARDARC; break; case CLASS_VEH_GROUND: case CLASS_VEH_NAVAL: case CLASS_VTOL: switch (section) { case TURRET: wantarc = TURRETARC; break; case FSIDE: wantarc = FORWARDARC; break; case LSIDE: wantarc = LSIDEARC; break; case RSIDE: wantarc = RSIDEARC; break; case BSIDE: wantarc = REARARC; break; } break; case CLASS_DS: switch (section) { case DS_NOSE: wantarc = FORWARDARC; break; case DS_LWING: case DS_LRWING: wantarc = LSIDEARC; break; case DS_RWING: case DS_RRWING: wantarc = RSIDEARC; break; case DS_AFT: wantarc = REARARC; break; } break; case CLASS_SPHEROID_DS: switch (section) { case DS_NOSE: wantarc = FORWARDARC; break; case DS_LWING: wantarc = FORWARDARC|LSIDEARC; break; case DS_LRWING: wantarc = REARARC|LSIDEARC; break; case DS_RWING: wantarc = FORWARDARC|RSIDEARC; break; case DS_RRWING: wantarc = REARARC|RSIDEARC; break; case DS_AFT: wantarc = REARARC; break; } break; case CLASS_AERO: isrear = (GetPartFireMode(mech, section, critical) & REAR_MOUNT); switch (section) { case AERO_NOSE: wantarc = FORWARDARC | LSIDEARC | RSIDEARC; break; case AERO_FUSEL: wantarc = FORWARDARC | REARARC | LSIDEARC | RSIDEARC; break; case AERO_LWING: wantarc = LSIDEARC | (isrear ? REARARC : FORWARDARC); break; case AERO_RWING: wantarc = RSIDEARC | (isrear ? REARARC : FORWARDARC); break; case AERO_ENGINE: wantarc = REARARC; break; } break; } return wantarc ? (wantarc & weaponarc) : 0; } int GetWeaponCrits(MECH * mech, int weapindx) { return (MechType(mech) == CLASS_MECH) ? (MechWeapons[weapindx].criticals) : 1; } int listmatch(char **foo, char *mat) { int i; for (i = 0; foo[i]; i++) if (!strcasecmp(foo[i], mat)) return i; return -1; } /* Takes care of : JumpSpeed Numsinks TODO: More support(?) */ void do_sub_magic(MECH * mech, int loud) { int jjs = 0; int hses = 0; int wanths, wanths_f; int shs_size = HS_Size(mech); int hs_eff = HS_Efficiency(mech); int i, j; int inthses = MechEngineSize(mech) / 25; int dest_hses = 0; int maxjjs = (int) ((float) MechMaxSpeed(mech) * MP_PER_KPH * 2 / 3); if (MechSpecials(mech) & ICE_TECH) inthses = 0; for (i = 0; i < NUM_SECTIONS; i++) for (j = 0; j < CritsInLoc(mech, i); j++) switch (Special2I(GetPartType(mech, i, j))) { case HEAT_SINK: hses++; if (PartIsNonfunctional(mech, i, j)) dest_hses++; break; case JUMP_JET: jjs++; break; } hses += MIN(MechRealNumsinks(mech) * shs_size / hs_eff, inthses * shs_size); if (jjs > maxjjs) { if (loud) SendError(tprintf ("Error in #%d (%s): %d JJs, yet %d maximum available (due to walk MPs)?", mech->mynum, MechType_Ref(mech), jjs, maxjjs)); jjs = maxjjs; } MechJumpSpeed(mech) = MP1 * jjs; wanths_f = (hses / shs_size) * hs_eff; wanths = wanths_f - (dest_hses * hs_eff / shs_size); if (loud) MechNumOsinks(mech) = wanths - MIN(MechRealNumsinks(mech), inthses * hs_eff); if (wanths != MechRealNumsinks(mech) && loud) { SendError(tprintf ("Error in #%d (%s): Set HS: %d. Existing HS: %d. Difference: %d. Please %s.", mech->mynum, MechType_Ref(mech), MechRealNumsinks(mech), wanths, MechRealNumsinks(mech) - wanths, wanths < MechRealNumsinks(mech) ? "add the extra HS critical(s)" : "fix the template")); } else MechRealNumsinks(mech) = wanths; MechNumOsinks(mech) = wanths_f; } #define CV(fun) fun(mech) = fun(&opp) /* Values to take care of: - JumpSpeed - MaxSpeed - Numsinks - EngineHeat - PilotSkillBase - LRS/Tac/ScanRange - BTH Status: - Destroyed Critstatus: - kokonaan paitsi section(s) / basetohit */ void do_magic(MECH * mech) { MECH opp; int i, j, t; int mask = 0; int tankCritMask = 0; if (MechType(mech) != CLASS_MECH) tankCritMask = (TURRET_LOCKED | TURRET_JAMMED | TAIL_ROTOR_DESTROYED | CREW_STUNNED); /* stop the burning */ StopBurning(mech); StopPerformingAction(mech); memcpy(&opp, mech, sizeof(MECH)); mech_loadnew(GOD, &opp, MechType_Ref(mech)); MechEngineSizeV(mech) = MechEngineSizeC(&opp); /* From intact template */ opp.mynum = -1; /* Ok.. It's at perfect condition. Start inflicting some serious crits.. */ for (i = 0; i < NUM_SECTIONS; i++) for (j = 0; j < CritsInLoc(mech, i); j++) { SetPartType(&opp, i, j, GetPartType(mech, i, j)); SetPartBrand(&opp, i, j, GetPartBrand(mech, i, j)); SetPartData(&opp, i, j, 0); SetPartFireMode(&opp, i, j, 0); SetPartAmmoMode(&opp, i, j, 0); } if (MechType(mech) == CLASS_MECH) do_sub_magic(&opp, 0); MechNumOsinks(mech) = MechNumOsinks(&opp); for (i = 0; i < NUM_SECTIONS; i++) { if (MechType(mech) == CLASS_MECH) { for (j = 0; j < CritsInLoc(mech, i); j++) { if (PartIsDestroyed(mech, i, j)) { if (!PartIsDestroyed(&opp, i, j)) { if (!IsAmmo((t = GetPartType(mech, i, j)))) { if (!IsWeapon(t)) HandleMechCrit(&opp, NULL, 0, i, j, t, GetPartData(mech, i, j)); } } } else { t = GetPartType(mech, i, j); if (IsAMS(Weapon2I(t))) { if (MechWeapons[Weapon2I(t)].special & CLAT) MechSpecials(mech) |= CL_ANTI_MISSILE_TECH; else MechSpecials(mech) |= IS_ANTI_MISSILE_TECH; } GetPartFireMode(mech, i, j) &= ~(OS_USED|ROCKET_FIRED|IS_JETTISONED_MODE); } } } MechSections(mech)[i].config &= ~STABILIZERS_DESTROYED; if (SectIsDestroyed(mech, i)) DestroySection(&opp, NULL, 0, i); if (MechStall(mech) > 0) UnSetSectBreached(mech, i); /* Just in case ; this leads to 'unbreachable' legs once you've 'done your time' once */ } CV(MechJumpSpeed); CV(MechMaxSpeed); CV(MechRealNumsinks); CV(MechEngineHeat); CV(MechPilotSkillBase); CV(MechLRSRange); CV(MechTacRange); CV(MechScanRange); CV(MechBTH); MechCritStatus(mech) &= mask; MechCritStatus(mech) |= MechCritStatus(&opp) & (~mask); MechTankCritStatus(mech) &= tankCritMask; MechTankCritStatus(mech) |= MechTankCritStatus(&opp) & (~tankCritMask); for (i = 0; i < NUM_SECTIONS; i++) { MechSections(mech)[i].basetohit = MechSections(&opp)[i].basetohit; MechSections(mech)[i].specials = MechSections(&opp)[i].specials; MechSections(mech)[i].specials &= ~(INARC_HOMING_ATTACHED | INARC_HAYWIRE_ATTACHED | INARC_ECM_ATTACHED | INARC_NEMESIS_ATTACHED); } /* Case of undestroying */ if (!Destroyed(&opp) && Destroyed(mech)) MechStatus(mech) &= ~DESTROYED; else if (Destroyed(&opp) && !Destroyed(mech)) MechStatus(mech) |= DESTROYED; if (!Destroyed(mech) && MechType(mech) != CLASS_MECH) EvalBit(MechStatus(mech), FALLEN, Fallen(&opp)); update_specials(mech); } void mech_RepairPart(MECH * mech, int loc, int pos) { int t = GetPartType(mech, loc, pos); UnDestroyPart(mech, loc, pos); if (IsWeapon(t) || IsAmmo(t)) { SetPartData(mech, loc, pos, 0); GetPartFireMode(mech, loc, pos) &= ~(OS_USED | IS_JETTISONED_MODE | ROCKET_FIRED); } else if (IsSpecial(t)) { switch (Special2I(t)) { case TARGETING_COMPUTER: case HEAT_SINK: case LIFE_SUPPORT: case COCKPIT: case SENSORS: case JUMP_JET: case ENGINE: case GYRO: case SHOULDER_OR_HIP: case LOWER_ACTUATOR: case UPPER_ACTUATOR: case HAND_OR_FOOT_ACTUATOR: case C3_MASTER: case C3_SLAVE: case C3I: case ECM: case ANGELECM: case NULL_SIGNATURE_SYSTEM: case BEAGLE_PROBE: case ARTEMIS_IV: case TAG: case BLOODHOUND_PROBE: /* Magic stuff here :P */ if (MechType(mech) == CLASS_MECH) do_magic(mech); break; } } } int no_locations_destroyed(MECH * mech) { int i; for (i = 0; i < NUM_SECTIONS; i++) if (GetSectOInt(mech, i) && SectIsDestroyed(mech, i)) return 0; return 1; } void mech_ReAttach(MECH * mech, int loc) { if (!SectIsDestroyed(mech, loc)) return; UnSetSectDestroyed(mech, loc); UnSetSectFlooded(mech, loc); SetSectInt(mech, loc, GetSectOInt(mech, loc)); if (is_aero(mech)) SetSectInt(mech, loc, 1); if (MechType(mech) != CLASS_MECH) { if (no_locations_destroyed(mech) && IsDS(mech)) MechStatus(mech) &= ~DESTROYED; return; } } void mech_ReplaceSuit(MECH * mech, int loc) { if (!SectIsDestroyed(mech, loc)) return; UnSetSectDestroyed(mech, loc); SetSectInt(mech, loc, GetSectOInt(mech, loc)); } /* * Added for new flood code by Kipsta * 8/4/99 */ void mech_ReSeal(MECH * mech, int loc) { int i; if (SectIsDestroyed(mech, loc)) return; if (!SectIsFlooded(mech, loc)) return; UnSetSectFlooded(mech, loc); for (i = 0; i < CritsInLoc(mech, loc); i++) { if (PartIsDisabled(mech, loc, i)) { if (!PartIsBroken(mech, loc, i) && !PartIsDamaged(mech, loc, i)) mech_RepairPart(mech, loc, i); else UnDisablePart(mech, loc, i); } } } void mech_Detach(MECH * mech, int loc) { if (SectIsDestroyed(mech, loc)) return; DestroySection(mech, NULL, 0, loc); } /* Figures out how much ammo there is when we're 'fully loaded', and fills it */ void mech_FillPartAmmo(MECH * mech, int loc, int pos) { int t, to; t = GetPartType(mech, loc, pos); if (!IsAmmo(t)) return; if (!(to = MechWeapons[Ammo2Weapon(t)].ammoperton)) return; SetPartData(mech, loc, pos, FullAmmo(mech, loc, pos)); } int AcceptableDegree(int d) { while (d < 0) d += 360; while (d >= 360) d -= 360; return d; } void MarkForLOSUpdate(MECH * mech) { MAP *mech_map; if (!(mech_map = getMap(mech->mapindex))) return; mech_map->moves++; mech_map->mechflags[mech->mapnumber] = 1; /* We need to remove this baby from the calculated ranges list.. *sniff* */ RCache_Remove(mech); } void multi_weap_sel(MECH * mech, dbref player, char *buffer, int bitbybit, int (*foo) (MECH *, dbref, int, int)) { /* Insight: buffer contains stuff in form: <num> <num>-<num> <num>,.. <num>-<num>,.. */ /* Ugly recursive piece of code :> */ char *c; int i1, i2, i3; int section, critical; skipws(buffer); if ((c = strstr(buffer, ","))) { *c = 0; c++; } if (sscanf(buffer, "%d-%d", &i1, &i2) == 2) { DOCHECK(i1 < 0 || i1 >= MAX_WEAPONS_PER_MECH, tprintf("Invalid first number in range (%d)", i1)); DOCHECK(i2 < 0 || i2 >= MAX_WEAPONS_PER_MECH, tprintf("Invalid second number in range (%d)", i2)); if (i1 > i2) { i3 = i1; i1 = i2; i2 = i3; } } else { DOCHECK(Readnum(i1, buffer), tprintf("Invalid value: %s", buffer)); DOCHECK(i1 < 0 || i1 >= MAX_WEAPONS_PER_MECH, tprintf("Invalid weapon number: %d", i1)); i2 = i1; } if (bitbybit / 2) { DOCHECK(i2 >= NUM_TICS, tprintf("There are only %d tics!", i2)); } else { DOCHECK(!(FindWeaponNumberOnMech(mech, i2, §ion, &critical) != -1), tprintf("Error: the mech doesn't HAVE %d weapons!", i2 + 1)); } if (bitbybit % 2) { for (i3 = i1; i3 <= i2; i3++) if (foo(mech, player, i3, i3)) return; } else if (foo(mech, player, i1, i2)) return; if (c) multi_weap_sel(mech, player, c, bitbybit, foo); } int Roll() { int i = Number(1, 6) + Number(1, 6); rollstat.rolls[i - 2]++; rollstat.totrolls++; return i; } int MyHexDist(int x1, int y1, int x2, int y2, int tc) { int xd = abs(x2 - x1); int yd = abs(y2 - y1); int hm; /* _the_ base case */ if (x1 == x2) return yd; /* + + + + */ if ((hm = (xd / 2)) <= yd) return (yd - hm) + tc + xd; /* + + + + + + + */ if (!yd) return (xd + tc); /* + + + + + + + */ /* For now, same as above */ return (xd + tc); } int CountDestroyedLegs(MECH * objMech) { int wcDeadLegs = 0; if (MechType(objMech) != CLASS_MECH) return 0; if (MechIsQuad(objMech)) { if (IsLegDestroyed(objMech, LARM)) wcDeadLegs++; if (IsLegDestroyed(objMech, RARM)) wcDeadLegs++; } if (IsLegDestroyed(objMech, LLEG)) wcDeadLegs++; if (IsLegDestroyed(objMech, RLEG)) wcDeadLegs++; return wcDeadLegs; } int IsLegDestroyed(MECH * objMech, int wLoc) { return (SectIsDestroyed(objMech, wLoc) || SectIsBreached(objMech, wLoc) || SectIsFlooded(objMech, wLoc)); } int IsMechLegLess(MECH * objMech) { int wcMaxLegs = 0; if (MechType(objMech) != CLASS_MECH) return 0; if (MechIsQuad(objMech)) wcMaxLegs = 4; else wcMaxLegs = 2; if (CountDestroyedLegs(objMech) >= wcMaxLegs) return 1; return 0; } int FindFirstWeaponCrit(MECH * objMech, int wLoc, int wSlot, int wStartSlot, int wCritType, int wMaxCrits) { int wCritsInLoc = 0; int wCritIter, wFirstCrit; /* * First let's count the number of crits in this loc, incase * we have two of the same weapon */ wFirstCrit = -1; for (wCritIter = wStartSlot; wCritIter < NUM_CRITICALS; wCritIter++) { if (GetPartType(objMech, wLoc, wCritIter) == wCritType) { wCritsInLoc++; if (wFirstCrit == -1) wFirstCrit = wCritIter; } } if ((wFirstCrit > -1) && (wSlot == -1)) return wFirstCrit; /* * Now, if there are more crits than our max crit, then we have * two of the same weapon in this location. We need to figure * out which weapon this crit actually belongs to. */ if (wCritsInLoc > wMaxCrits) { /* * Well, we have thje first crit of the first instance, so * let's see if our crit falls out of that range.. if so, then * we need to figure out what range it actually falls into. */ if ((wFirstCrit + wMaxCrits) <= wSlot) wFirstCrit = FindFirstWeaponCrit(objMech, wLoc, wSlot, (wFirstCrit + wMaxCrits), wCritType, wMaxCrits); } return wFirstCrit; } int checkAllSections(MECH * mech, int specialToFind) { int i; for (i = 0; i < NUM_SECTIONS; i++) { if (checkSectionForSpecial(mech, specialToFind, i)) return 1; } return 0; } int checkSectionForSpecial(MECH * mech, int specialToFind, int wSec) { if (SectIsDestroyed(mech, wSec)) return 0; if (MechSections(mech)[wSec].specials & specialToFind) return 1; return 0; } int getRemainingInternalPercent(MECH * mech) { int i; float wMax = 0; float wRemaining = 0; for (i = 0; i < NUM_SECTIONS; i++) { wMax += GetSectOInt(mech, i); wRemaining += GetSectInt(mech, i); } if (wMax == 0) return 0; return ((wRemaining / wMax) * 100); } int getRemainingArmorPercent(MECH * mech) { int i; float wMax = 0; float wRemaining = 0; for (i = 0; i < NUM_SECTIONS; i++) { wMax += GetSectOArmor(mech, i); wMax += GetSectORArmor(mech, i); wRemaining += GetSectArmor(mech, i); wRemaining += GetSectRArmor(mech, i); } if (wMax == 0) return 0; return ((wRemaining / wMax) * 100); } int FindObj(MECH * mech, int loc, int type) { int count = 0, i; for (i = 0; i < NUM_CRITICALS; i++) if (GetPartType(mech, loc, i) == type) if (!PartIsNonfunctional(mech, loc, i)) count++; return count; } int FindObjWithDest(MECH * mech, int loc, int type) { int count = 0, i; for (i = 0; i < NUM_CRITICALS; i++) if (GetPartType(mech, loc, i) == type) count++; return count; } /* Usage: mech = Mech who's looking for people mech_map = Map mech's on x,y = Target hex needlos = Bitvector 1 = Require LOS 2 = We actually want a mech that is friendly and has LOS to hex */ MECH *find_mech_in_hex(MECH * mech, MAP * mech_map, int x, int y, int needlos) { int loop; MECH *target; for (loop = 0; loop < mech_map->first_free; loop++) if (mech_map->mechsOnMap[loop] != mech->mynum && mech_map->mechsOnMap[loop] != -1) { target = (MECH *) FindObjectsData(mech_map->mechsOnMap[loop]); if (!target) continue; if (!(MechX(target) == x && MechY(target) == y) && !(needlos & 2)) continue; if (needlos) { if (needlos & 1) if (!InLineOfSight(mech, target, x, y, FlMechRange(mech_map, mech, target))) continue; if (needlos & 2) { if (MechTeam(mech) != MechTeam(target)) continue; if (!(MechSeesHex(target, mech_map, x, y))) continue; if (mech == target) continue; } } return target; } return NULL; } int FindAndCheckAmmo(MECH * mech, int weapindx, int section, int critical, int *ammoLoc, int *ammoCrit, int *ammoLoc1, int *ammoCrit1, int *wGattlingShots) { int mod, nmod = 0; int wMaxShots = 0; int wRoundsToCheck = 1; int wWeapMode = GetPartFireMode(mech, section, critical); int tResetMode = 0; dbref player = GunPilot(mech); /* Return if it's an energy or PC weapon */ if (MechWeapons[weapindx].type == TBEAM || MechWeapons[weapindx].type == THAND) return 1; /* Check for rocket launchers */ if (MechWeapons[weapindx].special == ROCKET) { DOCHECK0(wWeapMode & ROCKET_FIRED, "That weapon has already been used!"); return 1; } /* Check for One-Shots */ if (wWeapMode & OS_MODE) { DOCHECK0(GetPartFireMode(mech, section, critical) & OS_USED, "That weapon has already been used!"); return 1; } /* Check RACs - No special ammo type possible */ if (MechWeapons[weapindx].special & RAC) { wMaxShots = CountAmmoForWeapon(mech, weapindx); if ((wWeapMode & RAC_TWOSHOT_MODE) && (wMaxShots < 2)) { GetPartFireMode(mech, section, critical) &= ~RAC_TWOSHOT_MODE; return 1; } if ((wWeapMode & RAC_FOURSHOT_MODE) && (wMaxShots < 4)) { GetPartFireMode(mech, section, critical) &= ~RAC_FOURSHOT_MODE; return 1; } if ((wWeapMode & RAC_SIXSHOT_MODE) && (wMaxShots < 6)) { GetPartFireMode(mech, section, critical) &= ~RAC_SIXSHOT_MODE; return 1; } } /* Check GMGs */ if (wWeapMode & GATTLING_MODE) { wMaxShots = CountAmmoForWeapon(mech, weapindx); /* * Gattling MGs suck up damage * 3 in ammo */ if ((wMaxShots / 3) < *wGattlingShots) *wGattlingShots = MAX((wMaxShots / 3), 1); } /* If we're an ULTRA or RFAC, we need to check for multiple rounds */ if ((wWeapMode & ULTRA_MODE) || (wWeapMode & RFAC_MODE)) wRoundsToCheck = 2; mod = GetPartAmmoMode(mech, section, critical) & AMMO_MODES; if (!mod) { DOCHECK0(!FindAmmoForWeapon_sub(mech, section, critical, weapindx, section, ammoLoc, ammoCrit, AMMO_MODES, 0), "You don't have any ammo for that weapon stored on this mech!"); DOCHECK0(!GetPartData(mech, *ammoLoc, *ammoCrit), "You are out of ammo for that weapon!"); if (wRoundsToCheck > 1) { GetPartData(mech, *ammoLoc, *ammoCrit)--; if (FindAmmoForWeapon_sub(mech, section, critical, weapindx, section, ammoLoc1, ammoCrit1, AMMO_MODES, 0)) { if (!GetPartData(mech, *ammoLoc1, *ammoCrit1)) tResetMode = 1; } else tResetMode = 1; if (tResetMode) GetPartFireMode(mech, section, critical) &= ~wWeapMode; GetPartData(mech, *ammoLoc, *ammoCrit)++; } } else { if (IsArtillery(weapindx)) nmod = (~mod) & ARTILLERY_MODES; else nmod = (~mod) & AMMO_MODES; mod = (mod & AMMO_MODES); DOCHECK0(!FindAmmoForWeapon_sub(mech, section, critical, weapindx, section, ammoLoc, ammoCrit, nmod, mod), "You don't have any ammo for that weapon stored on this mech!"); DOCHECK0(!GetPartData(mech, *ammoLoc, *ammoCrit), "You are out of the special ammo type for that weapon!"); if (wRoundsToCheck > 1) { GetPartData(mech, *ammoLoc, *ammoCrit)--; if (FindAmmoForWeapon_sub(mech, section, critical, weapindx, section, ammoLoc1, ammoCrit1, nmod, mod)) { if (!GetPartData(mech, *ammoLoc1, *ammoCrit1)) tResetMode = 1; } else tResetMode = 1; if (tResetMode) GetPartFireMode(mech, section, critical) &= ~wWeapMode; GetPartData(mech, *ammoLoc, *ammoCrit)++; } } return 1; } void ChannelEmitKill(MECH * mech, MECH * attacker) { if (!attacker) attacker = mech; SendDebug(tprintf("#%d has been killed by #%d", mech->mynum, attacker->mynum)); if (IsDS(mech)) SendDSInfo(tprintf("#%d has been killed by #%d", mech->mynum, attacker->mynum)); if (mech->mynum > 0 && attacker->mynum > 0) did_it(attacker->mynum, mech->mynum, 0, NULL, 0, NULL, A_AMECHDEST, (char **) NULL, 0); } #define NUM_NEIGHBORS 6 int dirs[6][2] = { {0, -1}, {1, 0}, {1, 1}, {0, 1}, {-1, 1}, {-1, 0} }; void visit_neighbor_hexes(MAP * map, int tx, int ty, void (*callback)(MAP *, int, int)) { int x1, y1; int i; for (i = 0; i < NUM_NEIGHBORS; i++) { x1 = tx + dirs[i][0]; y1 = ty + dirs[i][1]; if (tx % 2 && !(x1 % 2)) y1--; if (x1 < 0 || x1 >= map->map_width || y1 < 0 || y1 >= map->map_height ) continue; callback(map, x1, y1); } } int GetPartWeight(int part) { if (IsWeapon(part)) return 10.24 * MechWeapons[Weapon2I(part)].weight; else if (IsAmmo(part)) return 1024; else if (IsBomb(part)) return 102 * BombWeight(Bomb2I(part)); #ifndef BT_PART_WEIGHTS else if (IsSpecial(part) && part <= I2Special(CLAW)) return 1024; #else else if (IsSpecial(part)) /* && i <= I2Special(LAMEQUIP) */ return internalsweight[Special2I(part)]; else if (IsCargo(part)) return cargoweight[Cargo2I(part)]; #endif /* BT_PART_WEIGHTS */ else /* hmm.. tricky, suppose we'll make things light */ return 102; } #ifdef BT_ADVANCED_ECON unsigned long long int GetPartCost(int p) { extern unsigned long long int specialcost[SPECIALCOST_SIZE]; extern unsigned long long int ammocost[AMMOCOST_SIZE]; extern unsigned long long int weapcost[WEAPCOST_SIZE]; extern unsigned long long int cargocost[CARGOCOST_SIZE]; extern unsigned long long int bombcost[BOMBCOST_SIZE]; if (IsWeapon(p)) return weapcost[Weapon2I(p)]; else if (IsAmmo(p)) return ammocost[Ammo2I(p)]; else if (IsSpecial(p)) return specialcost[Special2I(p)]; else if (IsBomb(p)) return bombcost[Bomb2I(p)]; else if (IsCargo(p)) return cargocost[Cargo2I(p)]; else return 0; } void SetPartCost(int p, unsigned long long int cost) { extern unsigned long long int specialcost[SPECIALCOST_SIZE]; extern unsigned long long int ammocost[AMMOCOST_SIZE]; extern unsigned long long int weapcost[WEAPCOST_SIZE]; extern unsigned long long int cargocost[CARGOCOST_SIZE]; extern unsigned long long int bombcost[BOMBCOST_SIZE]; if (IsWeapon(p)) weapcost[Weapon2I(p)] = cost; else if (IsAmmo(p)) ammocost[Ammo2I(p)] = cost; else if (IsSpecial(p)) specialcost[Special2I(p)] = cost; else if (IsBomb(p)) bombcost[Bomb2I(p)] = cost; else if (IsCargo(p)) cargocost[Cargo2I(p)] = cost; } #define COST_DEBUG 0 #if COST_DEBUG #define ADDPRICE(desc, add) \ { SendDebug(tprintf("AddPrice - %s %d", desc, add)); \ total += add; } #else #define ADDPRICE(desc, add) \ total += add; #endif #define DoArmMath(loc) \ for (i = 0; i < NUM_CRITICALS; i++) { \ part = GetPartType(mech, loc, i); \ if (!IsActuator(part)) \ continue; \ else if (Special2I(part) == SHOULDER_OR_HIP || Special2I(part) == UPPER_ACTUATOR) \ ADDPRICE("Shoulder/Upper Actuator", (MechTons(mech) * 100)) \ else if (Special2I(part) == LOWER_ACTUATOR) \ ADDPRICE("LowerArm Actuator", (MechTons(mech) * 50)) \ else if (Special2I(part) == HAND_OR_FOOT_ACTUATOR) \ ADDPRICE("Hand Actuator", (MechTons(mech) * 80)) \ } #define DoLegMath(loc) \ for (i = 0; i < NUM_CRITICALS; i++) { \ part = GetPartType(mech, loc, i); \ if (!IsActuator(part)) \ continue; \ else if (Special2I(part) == SHOULDER_OR_HIP || Special2I(part) == UPPER_ACTUATOR) \ ADDPRICE("Hip/Upper Actuator", (MechTons(mech) * 150)) \ else if (Special2I(part) == LOWER_ACTUATOR) \ ADDPRICE("LowerLeg Actuator", (MechTons(mech) * 80)) \ else if (Special2I(part) == HAND_OR_FOOT_ACTUATOR) \ ADDPRICE("Foot Actuator", (MechTons(mech) * 120)) \ } /* Some would say it's better for scode. I prolly would do. But since it's the FASA cals, let's put it in binary. Plus I'm lazy today */ unsigned long long int CalcFasaCost(MECH * mech) { int ii, i, part; unsigned long long int total = 0; float mod = 1.0; if (!mech) return -1; if (!(MechType(mech) == CLASS_MECH || MechType(mech) == CLASS_VEH_GROUND || MechType(mech) == CLASS_VEH_NAVAL || MechType(mech) == CLASS_VTOL ) || is_aero(mech) || IsDS(mech)) return 0; if (MechType(mech) == CLASS_MECH) { /* Cockpit */ #if 0 /* NULLTODO : Port any of these techs ASAP */ if (MechSpecials2(mech) & SMALLCOCKPIT_TECH) ADDPRICE("SmallCockpit", 175000) else if (MechSpecials2(mech) & TORSOCOCKPIT_TECH) ADDPRICE("TorsoCockpit", 750000) else #endif ADDPRICE("Cockpit", 200000) /* Life Support */ ADDPRICE("LifeSupport", 50000) /* Sensors */ ADDPRICE("Sensors", (MechTons(mech) * 2000)) /* Myomer stuffage */ if (MechSpecials(mech) & TRIPLE_MYOMER_TECH) ADDPRICE("TripleMyomer", (MechTons(mech) * 16000)) else ADDPRICE("Myomer", (MechTons(mech) * 2000)) /* Internal Structure */ if (MechSpecials(mech) & ES_TECH || MechSpecials(mech) & COMPI_TECH) ADDPRICE("ES/CO Internal", (MechTons(mech) * 1600)) else if (MechSpecials(mech) & REINFI_TECH) ADDPRICE("RE Internal", (MechTons(mech) * 6400)) else ADDPRICE("Internal", (MechTons(mech) * 400)) /* Actuators */ DoArmMath(RARM) DoArmMath(LARM) DoLegMath(LLEG) DoLegMath(RLEG) /* Gyro */ i = MechEngineSize(mech); if (i % 100) i += (100 - (MechEngineSize(mech) % 100)); i /= 100; /* NULLTODO : Port any of these techs ASAP */ if (MechSpecials2(mech) & XLGYRO_TECH) ADDPRICE("XLGyro", i * 750000) else if (MechSpecials2(mech) & CGYRO_TECH) ADDPRICE("Compact Gyro", i * 400000) else if (MechSpecials2(mech) & HDGYRO_TECH) ADDPRICE("HD Gyro", i * 500000) else ADDPRICE("Gyro", i * 300000) } else { int pamp = 0, turret = 0; for (i = 0; i < NUM_SECTIONS; i++) for (ii = 0; ii < NUM_CRITICALS; ii++) { if (!(part = GetPartType(mech, i, ii))) continue; if (!IsWeapon(part)) continue; if (i == TURRET) turret += crit_weight(mech, part); if (IsEnergy(part)) pamp += crit_weight(mech, part); } /* Internals */ ADDPRICE("TankInternals", MechTons(mech) * 10000) /* Control Components */ ADDPRICE("Control Components", (float) 10000 * (float) ((float) 0.05 * (float) MechTons(mech))) /* Power Amp */ if (MechSpecials(mech) & ICE_TECH) ADDPRICE("Power Amplifiers", 20000 * (float) (((float) pamp / (float) 10) / (float) 1024)) /* Turret */ ADDPRICE("Turret", (float) 5000 * (float) (((float) turret / (float) 10) / (float) 1024)) /* Lift/Dive Equip */ if (MechMove(mech) == MOVE_HOVER || MechMove(mech) == MOVE_FOIL || MechMove(mech) == MOVE_SUB) ADDPRICE("Lift/Dive Equipment", (float) 20000 * (float) ((float) 0.1 * (float) MechTons(mech))) if (MechMove(mech) == MOVE_VTOL) ADDPRICE("VTOL Equipment", (float) 40000 * (float) ((float) 0.1 * (float) MechTons(mech))) } /* Engine Math */ i = (MechSpecials(mech) & CE_TECH ? 10000 : MechSpecials(mech) & LE_TECH ? 15000 : MechSpecials(mech) & XL_TECH ? 20000 : MechSpecials(mech) & XXL_TECH ? 100000 : MechSpecials(mech) & ICE_TECH ? 1250 : 5000); ADDPRICE("Engine", ((i * MechEngineSize(mech) * MechTons(mech)) / 75)) /* Jump Jets */ i = MechJumpSpeed(mech) * MP_PER_KPH; if (i > 0) ADDPRICE("JumpJets", MechTons(mech) * (i * i) * 200) /* Heat Sinks */ i = MechRealNumsinks(mech); ii = (MechSpecials(mech) & DOUBLE_HEAT_TECH || MechSpecials(mech) & CLAN_TECH ? 6000 : MechSpecials2(mech) & COMPACT_HS_TECH ? 3000 : 2000); if (!(MechSpecials(mech) & ICE_TECH || MechSpecials(mech) & DOUBLE_HEAT_TECH || MechSpecials(mech) & CLAN_TECH)) i = BOUNDED(0, i - 10, 500); ADDPRICE("Heat Sinks", i * ii) ii = 0; for (i = 0; i < NUM_SECTIONS; ++i) ii += GetSectOArmor(mech, i); i = (MechSpecials(mech) & FF_TECH ? 20000 : MechSpecials(mech) & HARDA_TECH ? 15000 : MechSpecials2(mech) & LT_FF_ARMOR_TECH ? 15000 : MechSpecials2(mech) & HVY_FF_ARMOR_TECH ? 25000 : 10000); #if COST_DEBUG SendDebug(tprintf("Armor Total %d - Armor Cost %d", ii, i)); #endif ADDPRICE("Armor", (i / 16) * ii) /* Parts */ for (i = 0; i < NUM_SECTIONS; i++) for (ii = 0; ii < NUM_CRITICALS; ii++) { part = GetPartType(mech, i, ii); if (IsActuator(part) || part == EMPTY) continue; if (IsSpecial(part)) switch (Special2I(part)) { case LIFE_SUPPORT: case SENSORS: case COCKPIT: case ENGINE: case GYRO: case HEAT_SINK: case JUMP_JET: case FERRO_FIBROUS: case ENDO_STEEL: case TRIPLE_STRENGTH_MYOMER: #if 0 /* NULLTODO : Port any of these techs ASAP */ case HARDPOINT: continue; #endif default: break; } if (IsAmmo(part)) { part = FindAmmoType(mech, i, ii); ADDPRICE(part_name(part, 0), GetPartCost(part) * GetPartData(mech, i, ii)); } else { ADDPRICE(part_name(part, 0), GetPartCost(part)) } } if (MechType(mech) != CLASS_MECH) { switch (MechMove(mech)) { case MOVE_TRACK: mod = (float) 1 + (float) ((float) MechTons(mech) / (float) 100); break; case MOVE_WHEEL: mod = (float) 1 + (float) ((float) MechTons(mech) / (float) 200); break; case MOVE_HOVER: mod = (float) 1 + (float) ((float) MechTons(mech) / (float) 50); break; case MOVE_VTOL: mod = (float) 1 + (float) ((float) MechTons(mech) / (float) 30); break; case MOVE_HULL: mod = (float) 1 + (float) ((float) MechTons(mech) / (float) 200); break; case MOVE_FOIL: mod = (float) 1 + (float) ((float) MechTons(mech) / (float) 75); break; case MOVE_SUB: mod = (float) 1 + (float) ((float) MechTons(mech) / (float) 50); break; } } else { mod = (float) 1 + (float) ((float) MechTons(mech) / (float) 100); } #if COST_DEBUG SendDebug(tprintf("Price Total - %lld Mod - %f", total, mod)); #endif return ((float) total * (float) mod); } #endif #ifdef BT_CALCULATE_BV int FindAverageGunnery(MECH * mech) { #if 1 /* NULLTODO : Get the multiple skills for gunnery and such ported or working here so this is usefull again. */ return FindPilotGunnery(mech, 0); #else int runtot = 0; int i; if (!mech) return 12; for (i = 0; i < 5; i++) { runtot += FindPilotGunnery(mech, (i == 0 ? 0 : i == 1 ? 4 : i == 2 ? 5 : i == 3 ? 6 : i == 4 ? 103 : 0)); } return (runtot / 5); #endif } #undef DEBUG_BV #define HIGH_SKILL 8 #define LOW_SKILL 0 float skillmul[HIGH_SKILL][HIGH_SKILL] = { { 2.05 , 2.00 , 1.95 , 1.90 , 1.85 , 1.80 , 1.75 , 1.70 }, { 1.85 , 1.80 , 1.75 , 1.70 , 1.65 , 1.60 , 1.55 , 1.50 }, { 1.65 , 1.60 , 1.55 , 1.50 , 1.45 , 1.40 , 1.35 , 1.30 }, { 1.45 , 1.40 , 1.35 , 1.30 , 1.25 , 1.20 , 1.15 , 1.10 }, { 1.25 , 1.20 , 1.15 , 1.10 , 1.05 , 1.00 , 0.95 , 0.90 }, { 1.15 , 1.10 , 1.05 , 1.00 , 0.95 , 0.90 , 0.85 , 0.80 }, { 1.05 , 1.00 , 0.95 , 0.90 , 0.85 , 0.80 , 0.75 , 0.70 }, { 0.95 , 0.90 , 0.85 , 0.80 , 0.75 , 0.70 , 0.65 , 0.60 } }; #define LAZY_SKILLMUL(n) (n < LOW_SKILL ? LOW_SKILL : n >= HIGH_SKILL - 1 ? HIGH_SKILL - 1 : n) int CalculateBV(MECH *mech, int gunstat, int pilstat) { int defbv = 0, offbv = 0, i, ii, temp, temp2, deduct = 0, offweapbv = 0, defweapbv = 0, armor = 0, intern = 0, weapindx, mostheat = 0, tempheat = 0, mechspec, mechspec2, type, move, pilskl= pilstat, gunskl = gunstat; int debug1 = 0, debug2 = 0, debug3 = 0, debug4 = 0; float maxspeed, mul = 1.00; if (!mech) return 0; if (gunstat == 100 || pilstat == 100) { if (muxevent_tick - MechBVLast(mech) < 30) return MechBV(mech); else MechBVLast(mech) = muxevent_tick; } type = MechType(mech); move = MechMove(mech); mechspec = MechSpecials(mech); mechspec2 = MechSpecials2(mech); if (gunstat == 100) pilskl = FindPilotPiloting(mech); if (pilstat == 100) gunskl = FindAverageGunnery(mech); for (i = 0; i < NUM_SECTIONS; i++) { armor += (debug1 = GetSectArmor(mech, i) * (mechspec & HARDA_TECH ? 200 : 100)); if (type == CLASS_MECH && (i == CTORSO || i == LTORSO || i == RTORSO)) { armor += (debug2 = GetSectRArmor(mech, i) * (mechspec & HARDA_TECH ? 200 : 100)); #if 0 /* NULLTODO : Port any of these techs ASAP */ if (mechspec2 & TORSOCOCKPIT_TECH && i == CTORSO) armor += (debug4 = (((GetSectArmor(mech, i) + GetSectRArmor(mech, i)) * 2) * (mechspec & HARDA_TECH ? 200 : 100))); #endif } if (!is_aero(mech)) intern += (debug3 = GetSectInt(mech, i) * (mechspec & COMPI_TECH ? 50 : mechspec & REINFI_TECH ? 200 : 100)); else intern = (debug3 = AeroSI(mech)); #ifdef DEBUG_BV SendDebug(tprintf("Armoradd : %d ArmorRadd : %d Internadd : %d", debug1 / 100, debug2 / 100, debug3 / 100)); if (mechspec2 & TORSOCOCKPIT_TECH && i == CTORSO) SendDebug(tprintf("TorsoCockpit Armoradd : %d", debug4)); #endif debug1 = debug2 = debug3 = debug4 = 0; for (ii = 0; ii < CritsInLoc(mech, i); ii++) { if (IsWeapon(temp = GetPartType(mech, i, ii))) { weapindx = (Weapon2I(temp)); if (PartIsNonfunctional(mech, i, ii)) { if (type == CLASS_MECH) ii += (MechWeapons[weapindx].criticals - 1); continue; } if (MechWeapons[weapindx].special & AMS) { defweapbv += (debug1 = (MechWeapons[weapindx].battlevalue * 100) * (float) (3000 / (MechWeapons[weapindx].vrt * 100))); #ifdef DEBUG_BV SendDebug(tprintf("DefWeapBVadd (%s) : %d - Total : %d", MechWeapons[weapindx].name, debug1 / 100, defweapbv / 100)); #endif } else { offweapbv += (debug1 = (MechWeapons[weapindx].battlevalue * (GetPartFireMode(mech, i, ii) & REAR_MOUNT ? 50 : 100)) * (float) ((float) 3000 / (float) (MechWeapons[weapindx].vrt * 100))); if (MechWeapons[weapindx].type == TMISSILE) if (FindArtemisForWeapon(mech, i, ii)) offweapbv += (MechWeapons[weapindx].battlevalue * 20); #ifdef DEBUG_BV SendDebug(tprintf("OffWeapBVadd (%s) : %d - Total : %d", MechWeapons[weapindx].name, debug1 / 100, offweapbv / 100)); #endif } if (type == CLASS_MECH) { if (!(GetPartFireMode(mech, i, ii) & REAR_MOUNT)) { tempheat = ((MechWeapons[weapindx].heat * 100) * (float) ((float) 3000 / (float) (MechWeapons[weapindx].vrt * 100))); if (MechWeapons[weapindx].special & ULTRA) tempheat = (tempheat * 2); if (MechWeapons[weapindx].special & STREAK) tempheat = (tempheat / 2); mostheat += tempheat; #ifdef DEBUG_BV SendDebug(tprintf("Tempheatadded (%s) : %d - Total : %d", MechWeapons[weapindx].name, tempheat / 100, mostheat / 100)); #endif tempheat = 0; } } if (type == CLASS_MECH) ii += (MechWeapons[weapindx].criticals - 1); } else if (IsAmmo(temp)) { if (PartIsNonfunctional(mech, i, ii) || !GetPartData(mech, i, ii)) continue; #if 0 /* NULLTODO : Port any of these techs ASAP */ mul = ((temp2 = GetPartAmmoMode(mech, i, ii)) & AC_AP_MODE ? 4 : temp2 & AC_PRECISION_MODE ? 6 : temp2 & (TRACER_MODE|STINGER_MODE|SWARM_MODE|SWARM1_MODE|SGUIDED_MODE) ? 1.5 : 1); #else mul = ((temp2 = GetPartAmmoMode(mech, i, ii)) & AC_AP_MODE ? 4 : temp2 & AC_PRECISION_MODE ? 6 : temp2 & (SWARM_MODE|SWARM1_MODE) ? 1.5 : 1); #endif mul = (mul * ((float) ((float) GetPartData(mech, i, ii) / (float) MechWeapons[weapindx = Ammo2WeaponI(temp)].ammoperton))); #ifdef DEBUG_BV SendDebug(tprintf("AmmoBVmul (%s) : %.2f", MechWeapons[weapindx].name, mul)); #endif if (MechWeapons[weapindx].special & AMS) { defweapbv += (debug1 = (((MechWeapons[weapindx].battlevalue / 10) * 100) * mul) * (float) ((float) 3000 / (float) (MechWeapons[weapindx].vrt * 100))); #ifdef DEBUG_BV SendDebug(tprintf("AmmoDefWeapBVadd (%s) : %d - Total : %d", MechWeapons[weapindx].name, debug1 / 100, defweapbv / 100)); #endif } else { #ifdef DEBUG_BV SendDebug(tprintf("Abattlebalue (%s) : %d", MechWeapons[weapindx].name, (MechWeapons[weapindx].battlevalue / 10))); #endif offweapbv += (debug1 = (((MechWeapons[weapindx].battlevalue / 10) * 100) * mul) * (float) ((float) 3000 / (float) (MechWeapons[weapindx].vrt* 100))); #ifdef DEBUG_BV SendDebug(tprintf("AmmoOffWeapBVadd (%s) : %d - Total : %d", MechWeapons[weapindx].name, debug1 / 100, offweapbv / 100)); #endif } } if ((IsAmmo(temp) || (IsWeapon(temp) && MechWeapons[(Weapon2I(temp))].special & GAUSS)) && type == CLASS_MECH) { if (mechspec & CLAN_TECH) if (i == CTORSO || i == HEAD || i == RLEG || i == LLEG) { #ifdef DEBUG_BV SendDebug("20 deduct added for ammo"); #endif deduct += 2000; continue; } if (mechspec & (XL_TECH|XXL_TECH|ICE_TECH|LE_TECH)) { #ifdef DEBUG_BV SendDebug("20/2000 deduct added for ammo"); #endif deduct += 2000; continue; } if ((i == CTORSO || i == RLEG || i == LLEG || i == HEAD) && !(MechSections(mech)[i].config & CASE_TECH)) { #ifdef DEBUG_BV SendDebug("20 deduct added for ammo"); #endif deduct += 2000; continue; } if ((i == RARM || i == LARM) && (!(MechSections(mech)[i].config & CASE_TECH) && !(MechSections(mech)[(i == RARM ? RTORSO : LTORSO)].config & CASE_TECH))) { #ifdef DEBUG_BV SendDebug("20 deduct added for ammo"); #endif deduct += 2000; continue; } } } } if (type == CLASS_MECH) { mostheat += (MechJumpSpeed(mech) > 0 ? MAX((MechJumpSpeed(mech) / MP1) * 100, 300) : 200); if (mechspec2 & (NULLSIGSYS_TECH|STEALTH_ARMOR_TECH)) mostheat += 1000; if ((temp = (mostheat - (MechActiveNumsinks(mech) * 100))) > 0) { deduct += temp * 5; #ifdef DEBUG_BV SendDebug(tprintf("Deduct add for heat : %d", (temp * 5) / 100)); #endif } } #ifdef DEBUG_BV SendDebug(tprintf("DeductTotal : %d", deduct / 100)); #endif if (mechspec & ECM_TECH) defweapbv += 6100; if (mechspec & BEAGLE_PROBE_TECH) { if (mechspec & CLAN_TECH) offweapbv += 1200; else offweapbv += 1000; } #if 0 /* NULLTODO : Port any of these techs ASAP */ if (mechspec2 & HDGYRO_TECH) defweapbv += 3000; #endif if (mechspec & (XL_TECH|XXL_TECH|LE_TECH)) { if (mechspec & (CLAN_TECH|LE_TECH)) mul = 1.125; else mul = 0.75; } else if (mechspec & ICE_TECH || MechType(mech) == CLASS_VEH_GROUND || MechType(mech) == CLASS_VEH_NAVAL) { mul = 0.5; } else { mul = 1.5; } #ifdef DEBUG_BV SendDebug(tprintf("InternMul : %.2f", mul)); #endif armor = (armor * (MechType(mech) == CLASS_MECH ? 2 : 1)); intern = intern * mul; mul = 1.00; #ifdef DEBUG_BV SendDebug(tprintf("ArmorEnd : %d IntEnd : %d", armor / 100, intern / 100)); #endif maxspeed = MMaxSpeed(mech); if (mechspec & MASC_TECH || mechspec2 & SUPERCHARGER_TECH) { if (mechspec & MASC_TECH && mechspec2 & SUPERCHARGER_TECH) maxspeed = maxspeed * 2.5; else maxspeed = maxspeed * 1.5; } if (mechspec & TRIPLE_MYOMER_TECH) maxspeed = ((WalkingSpeed(maxspeed) + MP1) * 1.5); if (maxspeed <= MP2) { mul = 1.0; } else if (maxspeed <= MP4) { mul = 1.1; } else if (maxspeed <= MP6) { mul = 1.2; } else if (maxspeed <= MP9) { mul = 1.3; } else if (maxspeed <= MP1 * 13) { mul = 1.4; } else if (maxspeed <= MP1 * 18) { mul = 1.5; } else if (maxspeed <= MP1 * 24) { mul = 1.6; } else { mul = 1.7; } if (IsDS(mech)) mul = 1.0; else if (is_aero(mech)) mul = 1.1; if (mechspec2 & (NULLSIGSYS_TECH|STEALTH_ARMOR_TECH)) mul += 1.5; if (MechInfantrySpecials(mech) & DC_KAGE_STEALTH_TECH) mul += .75; if (MechInfantrySpecials(mech) & FWL_ACHILEUS_STEALTH_TECH) mul += 1.5; if (MechInfantrySpecials(mech) & CS_PURIFIER_STEALTH_TECH) mul += 2.0; if (MechInfantrySpecials(mech) & FC_INFILTRATOR_STEALTH_TECH) mul += .75; if (MechInfantrySpecials(mech) & FC_INFILTRATOR_STEALTH_TECH) mul += 2.0; #ifdef DEBUG_BV SendDebug(tprintf("DefBVMul : %.2f", mul)); #endif defbv = (armor + intern + (MechTons(mech) * 100) + defweapbv); #ifdef DEBUG_BV SendDebug(tprintf("DefBV Tonnage added : %d", MechTons(mech))); #endif if ((defbv - deduct) < 1) defbv = 1; else defbv -= deduct; if (type != CLASS_MECH) defbv = ((defbv * (move == MOVE_TRACK ? 0.8 : move == MOVE_WHEEL ? 0.7 : move == MOVE_HOVER ? 0.6 : move == MOVE_VTOL ? 0.4 : move == MOVE_FOIL || move == MOVE_SUB || move == MOVE_HULL? 0.5 : 1.0)) - deduct); defbv = defbv * mul; #ifdef DEBUG_BV SendDebug(tprintf("DefBV : %d", defbv / 100)); #endif if ((type == CLASS_MECH || is_aero(mech)) && mostheat > (MechActiveNumsinks(mech) * 100)) { #ifdef DEBUG_BV SendDebug(tprintf("Pre-Heat OffWeapBV : %d", offweapbv / 100)); #endif i = (((MechActiveNumsinks(mech) / 100) * offweapbv) / mostheat); ii = ((offweapbv - i) / 2); offweapbv = i + ii; #ifdef DEBUG_BV SendDebug(tprintf("Post-Heat OffWeapBV : %d", offweapbv / 100)); #endif } /* 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); */ mul = pow((((((IsDS(mech) ? WalkingSpeed(MMaxSpeed(mech)) : MMaxSpeed(mech)) / MP1) + (mechspec & MASC_TECH ? 1 : 0) + (mechspec & TRIPLE_MYOMER_TECH ? 1 : 0) + (mechspec2 & SUPERCHARGER_TECH ?1 : 0) - 5) / 10) + 1), 1.2); #ifdef DEBUG_BV SendDebug(tprintf("DumbMul : %.2f", mul)); #endif if (mechspec2 & OMNIMECH_TECH) mul += .3; offweapbv = offweapbv * mul; if (type != CLASS_AERO && type != CLASS_DS && MechJumpSpeed(mech) > 0) offweapbv += ((MechJumpSpeed(mech) / MP1) * (100 * (MechTons(mech) / 5))); offbv = offweapbv; #ifdef DEBUG_BV SendDebug(tprintf("OffWeapBVAfter : %d", offweapbv / 100)); SendDebug(tprintf("DefBV : %d OffBV : %d TotalBV : %d", defbv / 100, offbv / 100, (offbv + defbv) / 100)); #endif mul = (skillmul[LAZY_SKILLMUL(gunskl)][LAZY_SKILLMUL(pilskl)]); #ifdef DEBUG_BV SendDebug(tprintf("SkillMul : %.2f (%d/%d)", mul, gunskl, pilskl)); #endif return ((offbv + defbv) / 100) * mul; } #endif int MechFullNoRecycle(MECH * mech, int num) { int i; for (i = 0; i < NUM_SECTIONS; i++) { if (num & CHECK_WEAPS && SectHasBusyWeap(mech, i)) return 1; if (num & CHECK_PHYS && MechSections(mech)[i].recycle > 0) return 2; } return 0; } #ifdef BT_COMPLEXREPAIRS int GetPartMod(MECH * mech, int t) { int val, div, bound; div = (t && t == Special(GYRO) ? 100 : t && t == Special(ENGINE) ? 20 : 10); bound = (t && t == Special(GYRO) ? 3 : t && t == Special(ENGINE) ? 19 : 9); val = (t && (t == Special(GYRO) || t == Special(ENGINE)) ? MechEngineSize(mech) : MechTons(mech)); if (val % div != 0) val = val + (div - (val % div)); return BOUNDED(0, (val / div) - 1, bound); } int ProperArmor(MECH * mech) { /* For now they all use the same basic cargo parts. */ return Cargo(MechSpecials(mech) & FF_TECH ? FF_ARMOR : MechSpecials(mech) & HARDA_TECH ? HD_ARMOR : MechSpecials2(mech) & HVY_FF_ARMOR_TECH ? HVY_FF_ARMOR : MechSpecials2(mech) & LT_FF_ARMOR_TECH ? LT_FF_ARMOR : MechSpecials2(mech) & STEALTH_ARMOR_TECH ? STH_ARMOR : S_ARMOR); } int ProperInternal(MECH * mech) { int part = 0; if (mudconf.btech_complexrepair) { part = (MechSpecials(mech) & ES_TECH ? TON_ESINTERNAL_FIRST : MechSpecials(mech) & REINFI_TECH ? TON_REINTERNAL_FIRST : MechSpecials(mech) & COMPI_TECH ? TON_COINTERNAL_FIRST : TON_INTERNAL_FIRST); part += GetPartMod(mech, 0); } else { part = (MechSpecials(mech) & ES_TECH ? ES_INTERNAL : MechSpecials(mech) & REINFI_TECH ? RE_INTERNAL : MechSpecials(mech) & COMPI_TECH ? CO_INTERNAL : S_INTERNAL); } return Cargo(part); } int alias_part(MECH * mech, int t, int loc) { int part = 0; if (!IsSpecial(t)) return t; if (mudconf.btech_complexrepair) { int tonmod = GetPartMod(mech, t); int locmod; if (MechIsQuad(mech)) locmod = (loc == RARM || loc == LARM || loc == RLEG || loc == LLEG ? 2 : 0); else locmod = (loc == RARM || loc == LARM ? 1 : loc == LLEG || loc == RLEG ? 2 : 0); part = (locmod && (t == Special(SHOULDER_OR_HIP) || t == Special(UPPER_ACTUATOR)) ? (locmod == 1 ? Cargo(TON_ARMUPPER_FIRST + tonmod) : Cargo(TON_LEGUPPER_FIRST + tonmod)) : locmod && t == Special(LOWER_ACTUATOR) ? (locmod == 1 ? Cargo(TON_ARMLOWER_FIRST + tonmod) : Cargo(TON_LEGLOWER_FIRST + tonmod)) : locmod && t == Special(HAND_OR_FOOT_ACTUATOR) ? (locmod == 1 ? Cargo(TON_ARMHAND_FIRST + tonmod) : Cargo(TON_LEGFOOT_FIRST + tonmod)) : t == Special(ENGINE) && MechSpecials(mech) & XL_TECH ? Cargo(TON_ENGINE_XL_FIRST + tonmod) : t == Special(ENGINE) && MechSpecials(mech) & ICE_TECH ? Cargo(TON_ENGINE_ICE_FIRST + tonmod) : t == Special(ENGINE) && MechSpecials(mech) & CE_TECH ? Cargo(TON_ENGINE_COMP_FIRST + tonmod): t == Special(ENGINE) && MechSpecials(mech) & XXL_TECH ? Cargo(TON_ENGINE_XXL_FIRST + tonmod) : t == Special(ENGINE) && MechSpecials(mech) & LE_TECH ? Cargo(TON_ENGINE_LIGHT_FIRST + tonmod) : t == Special(ENGINE) ? Cargo(TON_ENGINE_FIRST + tonmod) : t == Special(HEAT_SINK) && MechSpecials(mech) & (DOUBLE_HEAT_TECH|CLAN_TECH) ? Cargo(DOUBLE_HEAT_SINK) : t == Special(HEAT_SINK) && MechSpecials2(mech) & COMPACT_HS_TECH ? Cargo(COMPACT_HEAT_SINK) : t == Special(GYRO) && MechSpecials2(mech) & XLGYRO_TECH ? Cargo(TON_XLGYRO_FIRST + tonmod) : t == Special(GYRO) && MechSpecials2(mech) & HDGYRO_TECH ? Cargo(TON_HDGYRO_FIRST + tonmod) : t == Special(GYRO) && MechSpecials2(mech) & CGYRO_TECH ? Cargo(TON_CGYRO_FIRST + tonmod) : t == Special(GYRO) ? Cargo(TON_GYRO_FIRST + tonmod) : t == Special(SENSORS) ? Cargo(TON_SENSORS_FIRST + tonmod) : t == Special(JUMP_JET) ? Cargo(TON_JUMPJET_FIRST + tonmod) : t); } else { part = (IsActuator(t) ? Cargo(S_ACTUATOR) : t == Special(ENGINE) && MechSpecials(mech) & XL_TECH ? Cargo(XL_ENGINE) : t == Special(ENGINE) && MechSpecials(mech) & ICE_TECH ? Cargo(IC_ENGINE) : t == Special(ENGINE) && MechSpecials(mech) & CE_TECH ? Cargo(COMP_ENGINE) : t == Special(ENGINE) && MechSpecials(mech) & XXL_TECH ? Cargo(XXL_ENGINE) : t == Special(ENGINE) && MechSpecials(mech) & LE_TECH ? Cargo(LIGHT_ENGINE) : t == Special(HEAT_SINK) && MechSpecials(mech) & (DOUBLE_HEAT_TECH|CLAN_TECH) ? Cargo(DOUBLE_HEAT_SINK) : t == Special(HEAT_SINK) && MechSpecials2(mech) & COMPACT_HS_TECH ? Cargo(COMPACT_HEAT_SINK) : t == Special(GYRO) && MechSpecials2(mech) & XLGYRO_TECH ? Cargo(XL_GYRO) : t == Special(GYRO) && MechSpecials2(mech) & HDGYRO_TECH ? Cargo(HD_GYRO) : t == Special(GYRO) && MechSpecials2(mech) & CGYRO_TECH ? Cargo(COMP_GYRO) : t); } return part; } int ProperMyomer(MECH * mech) { int part; part = (MechSpecials(mech) & TRIPLE_MYOMER_TECH ? TON_TRIPLEMYOMER_FIRST : TON_MYOMER_FIRST); part += GetPartMod(mech, 0); return Cargo(part); } #endif /* Function to return a value of how much heat a unit is putting out*/ /* TODO: Double check how Stealth Armor and Null Sig are coded */ int HeatFactor(MECH * mech) { int factor = 0; char buf[LBUF_SIZE]; if (MechType(mech) != CLASS_MECH) { factor = (((MechSpecials(mech) & ICE_TECH)) ? -1 : 21); return factor; } else { factor = (MechPlusHeat(mech) + (2 * (MechPlusHeat(mech) - MechMinusHeat(mech)))); return ((NullSigSysActive(mech) || HasWorkingECMSuite(mech) || StealthArmorActive(mech)) ? -1 : factor); } snprintf(buf, LBUF_SIZE, "HeatFactor : Invalid heat factor calculation on #%d.", mech->mynum); SendDebug(buf); } /* Function to determine if a weapon is functional or not Returns 0 if fully functional. Returns 1 if non functional. Returns 2 if fully damaged. Returns -(# of crits) if partially damaged. remember that values 3 means the weapon IS NOT destroyed. */ int WeaponIsNonfunctional(MECH * mech, int section, int crit, int numcrits) { int sum = 0, disabled = 0, dested = 0; if (numcrits <= 0) numcrits = GetWeaponCrits(mech, Weapon2I(GetPartType(mech, section, crit))); while (sum < numcrits) { if (PartIsDestroyed(mech, section, crit + sum)) dested++; else if (PartIsDisabled(mech, section, crit + sum)) disabled++; sum++; } if (disabled > 0) return 1; if ((numcrits == 1 && (dested || disabled)) || (numcrits > 1 && (dested + disabled) >= numcrits / 2)) return 2; if (dested) return 0 - (dested + disabled); return 0; }