/* * $Id: mech.consistency.c,v 1.4 2005/06/24 04:39:07 av1-op Exp $ * * Author: Markus Stenberg <fingon@iki.fi> * * Copyright (c) 1997 Markus Stenberg * All rights reserved * * Created: Tue Mar 4 17:17:12 1997 fingon * Last modified: Thu Jul 9 02:33:13 1998 fingon * */ #include "config.h" #include "mech.h" #include "coolmenu.h" #include "mycool.h" #include "p.mech.custom.h" #include "p.mech.utils.h" #include "mech.partnames.h" #include <math.h> static char mech_loc_table[][2] = { {CTORSO, 1}, {LTORSO, 2}, {RTORSO, 2}, {LARM, 3}, {RARM, 3}, {LLEG, 4}, {RLEG, 4}, {-1, 0} }; static char quad_loc_table[][2] = { {CTORSO, 1}, {LTORSO, 2}, {RTORSO, 2}, {LARM, 4}, {RARM, 4}, {LLEG, 4}, {RLEG, 4}, {-1, 0} }; static char int_data[][5] = { {10, 4, 3, 1, 2}, {15, 5, 4, 2, 3}, {20, 6, 5, 3, 4}, {25, 8, 6, 4, 6}, {30, 10, 7, 5, 7}, {35, 11, 8, 6, 8}, {40, 12, 10, 6, 10}, {45, 14, 11, 7, 11}, {50, 16, 12, 8, 12}, {55, 18, 13, 9, 13}, {60, 20, 14, 10, 14}, {65, 21, 15, 10, 15}, {70, 22, 15, 11, 15}, {75, 23, 16, 12, 16}, {80, 25, 17, 13, 17}, {85, 27, 18, 14, 18}, {90, 29, 19, 15, 19}, {95, 30, 20, 16, 20}, {100, 31, 21, 17, 21}, {-1, 0, 0, 0, 0} }; static short engine_data[][2] = { {0, 0}, {10, 1}, {15, 1}, {20, 1}, {25, 1}, {30, 2}, {35, 2}, {40, 2}, {45, 2}, {50, 3}, {55, 3}, {60, 3}, {65, 4}, {70, 4}, {75, 4}, {80, 5}, {85, 5}, {90, 6}, {95, 6}, {100, 6}, {105, 7}, {110, 7}, {115, 8}, {120, 8}, {125, 8}, {130, 9}, {135, 9}, {140, 10}, {145, 10}, {150, 11}, {155, 11}, {160, 12}, {165, 12}, {170, 12}, {175, 14}, {180, 14}, {185, 15}, {190, 15}, {195, 16}, {200, 17}, {205, 17}, {210, 18}, {215, 19}, {220, 20}, {225, 20}, {230, 21}, {235, 22}, {240, 23}, {245, 24}, {250, 25}, {255, 26}, {260, 27}, {265, 28}, {270, 29}, {275, 31}, {280, 32}, {285, 33}, {290, 35}, {295, 36}, {300, 38}, {305, 39}, {310, 41}, {315, 43}, {320, 45}, {325, 47}, {330, 49}, {335, 51}, {340, 54}, {345, 57}, {350, 59}, {355, 63}, {360, 66}, {365, 69}, {370, 73}, {375, 77}, {380, 82}, {385, 87}, {390, 92}, {395, 98}, {400, 105}, {405, 113}, {410, 122}, {415, 133}, {420, 145}, {425, 159}, {430, 87 * 2 + 1}, {435, 97 * 2}, {440, 107 * 2 + 1}, {445, 119 * 2 + 1}, {450, 133 * 2 + 1}, {455, 150 * 2}, {460, 168 * 2 + 1}, {465, 190 * 2}, {470, 214 * 2 + 1}, {475, 243 * 2}, {480, 275 * 2 + 1}, {485, 313 * 2}, {490, 356 * 2}, {495, 405 * 2 + 1}, {500, 462 * 2 + 1}, {-1, 0} }; int susp_factor(MECH * mech) { int t = MechTons(mech); if (MechMove(mech) == MOVE_TRACK) return 0; if (MechMove(mech) == MOVE_WHEEL) return 20; #define MAP(a,b) if (t <= a) return b if (MechMove(mech) == MOVE_FOIL) { MAP(10, 60); MAP(20, 105); MAP(30, 150); MAP(40, 195); MAP(50, 255); MAP(60, 300); MAP(70, 345); MAP(80, 390); MAP(90, 435); return 480; } if (MechMove(mech) == MOVE_HOVER) { MAP(10, 40); MAP(20, 85); MAP(30, 130); MAP(40, 175); return 235; } if (MechMove(mech) == MOVE_HULL || MechMove(mech) == MOVE_SUB) return 30; if (MechMove(mech) == MOVE_VTOL) { MAP(10, 50); MAP(20, 95); return 140; } return 0; } static int round_to_halfton(int weight) { int over = weight % 512; if (!over) return weight; if (over < 2) return weight - over; return weight + (512 - over); } static int engine_weight(MECH * mech) { int s = MechEngineSize(mech); int i; if (MechType(mech) != CLASS_MECH) s -= susp_factor(mech); for (i = 0; engine_data[i][0] >= 0; i++) if (s == engine_data[i][0]) { int weight = engine_data[i][1] * 512; if (MechSpecials(mech) & ICE_TECH) return weight * 2; if (MechType(mech) == CLASS_VEH_GROUND || MechType(mech) == CLASS_VTOL || MechType(mech) == CLASS_VEH_NAVAL) /* Vehicles need extra shielding in case of a fusion engine */ weight = round_to_halfton(weight + weight / 2); if (MechSpecials(mech) & XL_TECH) return round_to_halfton(weight / 2); if (MechSpecials(mech) & XXL_TECH) return round_to_halfton(weight / 3); if (MechSpecials(mech) & LE_TECH) return round_to_halfton(weight * 3/4); if (MechSpecials(mech) & CE_TECH) return round_to_halfton(weight + weight / 2); return weight; } SendError(tprintf("Error in #%d (%s) : No engine found!", mech->mynum, Name(mech->mynum))); return 0; } static void calc_ints(MECH * mech, int *n, int *tot) { int i; *n = 0; *tot = 0; for (i = 0; i < NUM_SECTIONS; i++) { *n += GetSectInt(mech, i); *tot += GetSectOInt(mech, i); } *tot = MAX(1, *tot); } static int ammo_weight(MECH * mech) { int i, j, t, w = 0; for (i = 0; i < NUM_SECTIONS; i++) if (!SectIsDestroyed(mech, i)) for (j = 0; j < CritsInLoc(mech, i); j++) if (IsAmmo((t = GetPartType(mech, i, j)))) w += GetPartData(mech, i, j) * 1024 / MechWeapons[Ammo2I(GetPartType(mech, i, j))].ammoperton; return w; } #define MyGetSectOArmor(m,l) (interactive>=0?GetSectOArmor(m,l):GetSectArmor(m,l)) #define MyGetSectORArmor(m,l) (interactive>=0?GetSectORArmor(m,l):GetSectRArmor(m,l)) #define PLOC(a) if (interactive >= 0 || !SectIsDestroyed(mech,a)) #define MyMechNumOsinks(m) ((interactive >= 0) ? (MechNumOsinks(m)) : (MechRealNumsinks(m))) int mech_weight_sub_mech(dbref player, MECH * mech, int interactive) { int pile[NUM_ITEMS_M]; int i, j, w, cl, id; int armor = 0, armor_o; int total = 0; coolmenu *c = NULL; int shs_size; int hs_eff; char buf[MBUF_SIZE]; int ints_c, ints_tot; float gyro_calc; bzero(pile, sizeof(pile)); if (interactive > 0) { addline(); cent(tprintf("Weight totals for %s", GetMechID(mech))); addline(); } calc_ints(mech, &ints_c, &ints_tot); for (i = 0; i < NUM_SECTIONS; i++) { if (!GetSectOInt(mech, i)) continue; armor += MyGetSectOArmor(mech, i); armor += MyGetSectORArmor(mech, i); PLOC(i) for (j = 0; j < NUM_CRITICALS; j++) if (interactive >= 0 || !IsAmmo(GetPartType(mech, i, j))) pile[GetPartType(mech, i, j)] += AmmoMod(mech, i, j); } shs_size = HS_Size(mech); hs_eff = HS_Efficiency(mech); cl = MechSpecials(mech) & CLAN_TECH; #define ADDENTRY(text,weight) \ if (weight) { if (interactive>0) { addmenu(text);addmenu(tprintf(" %6.1f", (float) (weight) / 1024.0));}; total += weight; } #define ADDENTRY_C(text,count,weight) \ if (weight) { if (interactive>0) { addmenu(text);addmenu(tprintf("%5d %6.1f", count, (float) (weight) / 1024.0)); }; total += weight; } sprintf(buf, "%-12s(%d rating)", MechSpecials(mech) & XL_TECH ? "Engine (XL)" : MechSpecials(mech) & XXL_TECH ? "Engine (XXL)" : MechSpecials(mech) & CE_TECH ? "Engine (Compact)" : MechSpecials(mech) & LE_TECH ? "Engine (Light)" : "Engine", MechEngineSize(mech)); PLOC(CTORSO) ADDENTRY(buf, engine_weight(mech)); PLOC(HEAD) ADDENTRY("Cockpit", 3 * 1024); PLOC(CTORSO) /* Store the base-line gyro weight */ gyro_calc = (MechEngineSize(mech) / 100.0) * 1024; /* Figure out what kind of gyro we have and adjust weight accordingly */ if (MechSpecials2(mech) & XLGYRO_TECH) { /* XL Gyro is 1/2 normal gyro weight. */ ADDENTRY("Gyro (XL)", (int) ceil(gyro_calc * 0.5)); } else if (MechSpecials2(mech) & HDGYRO_TECH) { /* Hardened Gyro is 2x normal gyro weight. */ ADDENTRY("Gyro (Hardened)", (int) ceil(gyro_calc * 2)); } else if (MechSpecials2(mech) & CGYRO_TECH) { /* Compact Gyro is 1.5x normal gyro weight. */ ADDENTRY("Gyro (Compact)", (int) ceil(gyro_calc * 1.5)); } else { /* Standard Gyro. */ ADDENTRY("Gyro", (int) ceil(gyro_calc)); } ADDENTRY(MechSpecials(mech) & REINFI_TECH ? "Internals (Reinforced)" : MechSpecials(mech) & COMPI_TECH ? "Internals (Composite)" : MechSpecials(mech) & ES_TECH ? "Internals (ES)" : "Internals", round_to_halfton(MechTons(mech) * 1024 * (interactive >= 0 ? ints_tot : ints_c) / 5 / ints_tot / (MechSpecials(mech) & REINFI_TECH ? 1 : (MechSpecials(mech) & (ES_TECH | COMPI_TECH)) ? 4 : 2))); armor_o = armor; if (MechSpecials(mech) & FF_TECH) armor = armor * 50 / (cl ? 60 : 56); else if (MechSpecials2(mech) & HVY_FF_ARMOR_TECH) armor = armor * 50 / 62; else if (MechSpecials2(mech) & LT_FF_ARMOR_TECH) armor = armor * 50 / 53; ADDENTRY_C(MechSpecials2(mech) & STEALTH_ARMOR_TECH ? "Armor (Stealth)" : MechSpecials2(mech) & HVY_FF_ARMOR_TECH ? "Armor (Hvy FF)" : MechSpecials2(mech) & LT_FF_ARMOR_TECH ? "Armor (Lt FF)" : MechSpecials(mech) & HARDA_TECH ? "Armor (Hardened)" : MechSpecials(mech) & FF_TECH ? "Armor (FF)" : "Armor", armor_o, ceil(armor / (8. * (MechSpecials(mech) & HARDA_TECH ? 2 : 1))) * 512); if (MyMechNumOsinks(mech)) { pile[Special(HEAT_SINK)] = MAX(0, MyMechNumOsinks(mech) * shs_size / hs_eff - (MechSpecials(mech) & ICE_TECH ? 0 : 10) * shs_size); } else if (interactive > 0) cent(tprintf ("WARNING: HS count may be off, due to certain odd things.")); for (i = 1; i < NUM_ITEMS_M; i++) if (pile[i]) { if (IsWeapon(i)) { id = Weapon2I(i); ADDENTRY_C(MechWeapons[id].name, pile[i] / GetWeaponCrits(mech, id), crit_weight(mech, i) * pile[i]); } else { if ((w = crit_weight(mech, i))) ADDENTRY_C(get_parts_long_name(i, 0), pile[i], w * pile[i]); } } if (CargoSpace(mech)) ADDENTRY(tprintf("CargoSpace (%.2ft)", (float) CargoSpace(mech) / 100), (int) (((float) CargoSpace(mech) / (MechSpecials2(mech) & CARRIER_TECH ? 1000 : MechSpecials(mech) & CARGO_TECH ? 100 : 500)) * 1024)); if (interactive > 0) { addline(); vsi(tprintf("%%cgTotal: %s%.1f tons (offset: %.1f)%%cn", (total / 1024) > MechTons(mech) ? "%ch%cr" : "", (float) (total) / 1024.0, MechTons(mech) - (float) (total) / 1024.0)); addline(); ShowCoolMenu(player, c); } KillCoolMenu(c); if (interactive < 0) total += ammo_weight(mech); return MAX(1, total); } static int tank_in_pieces(MECH * mech) { int i; for (i = 0; i < NUM_SECTIONS; i++) if (GetSectInt(mech, i)) return 0; return 1; } int mech_weight_sub_veh(dbref player, MECH * mech, int interactive) { int pile[NUM_ITEMS_M]; int i, j, w, cl, id, t; int armor = 0, armor_o; int total = 0; coolmenu *c = NULL; int shs_size; int hs_eff; char buf[MBUF_SIZE]; int es; int turr_stuff = 0; int ints_c, ints_tot; bzero(pile, sizeof(pile)); calc_ints(mech, &ints_c, &ints_tot); if (interactive > 0) { addline(); cent(tprintf("Weight totals for %s", GetMechID(mech))); addline(); } for (i = 0; i < NUM_SECTIONS; i++) { if (!(GetSectOInt(mech, i))) continue; armor += MyGetSectOArmor(mech, i); armor += MyGetSectORArmor(mech, i); for (j = 0; j < CritsInLoc(mech, i); j++) { if (!(t = GetPartType(mech, i, j))) continue; if (interactive >= 0 || !SectIsDestroyed(mech, i)) { if (interactive >= 0 || !IsAmmo(t)) pile[t] += AmmoMod(mech, i, j); if (i == TURRET && (MechType(mech) == CLASS_VEH_GROUND || MechType(mech) == CLASS_VEH_NAVAL)) if (IsWeapon(t)) turr_stuff += crit_weight(mech, t); } } } shs_size = HS_Size(mech); hs_eff = HS_Efficiency(mech); cl = MechSpecials(mech) & CLAN_TECH; es = susp_factor(mech); if (es) sprintf(buf, "%-12s(%d->%d eff/wt rat)", MechSpecials(mech) & LE_TECH ? "Engine (Light)" : MechSpecials(mech) & CE_TECH ? "Engine (Compact)" : MechSpecials(mech) & XXL_TECH ? "Engine (XXL)" : MechSpecials(mech) & XL_TECH ? "Engine (XL)" : MechSpecials(mech) & ICE_TECH ? "Engine (ICE)" : "Engine", MechEngineSize(mech), MechEngineSize(mech) - susp_factor(mech)); else sprintf(buf, "%-12s(%d rating)", MechSpecials(mech) & LE_TECH ? "Engine (Light)" : MechSpecials(mech) & CE_TECH ? "Engine (Compact)" : MechSpecials(mech) & XXL_TECH ? "Engine (XXL)" : MechSpecials(mech) & XL_TECH ? "Engine (XL)" : MechSpecials(mech) & ICE_TECH ? "Engine (ICE)" : "Engine", MechEngineSize(mech)); if (!tank_in_pieces(mech)) { ADDENTRY(buf, (es = engine_weight(mech))); if (MechMove(mech) == MOVE_HOVER && es < (MechTons(mech) * 1024 / 5)) ADDENTRY("Engine size fix (-> 1/5 hover wt.)", MechTons(mech) * 1024 / 5 - es); ADDENTRY("Cockpit", round_to_halfton(MechTons(mech) * 1024 / 20)); if (MechType(mech) == CLASS_VTOL || MechMove(mech) == MOVE_HOVER || MechMove(mech) == MOVE_HULL || MechMove(mech) == MOVE_SUB) ADDENTRY("SpecialComponents", round_to_halfton(MechTons(mech) * 1024 / 10)); } PLOC(TURRET) if (turr_stuff) ADDENTRY("Turret", round_to_halfton(turr_stuff / 10)); ADDENTRY(MechSpecials(mech) & REINFI_TECH ? "Internals (Reinforced)" : MechSpecials(mech) & COMPI_TECH ? "Internals (Composite)" : MechSpecials(mech) & ES_TECH ? "Internals (ES)" : "Internals", round_to_halfton(MechTons(mech) * 1024 * (interactive >= 0 ? ints_tot : ints_c) / 5 / ints_tot / (MechSpecials(mech) & REINFI_TECH ? 1 : (MechSpecials(mech) & (ES_TECH | COMPI_TECH)) ? 4 : 2))); armor_o = armor; if (MechSpecials(mech) & FF_TECH) armor = armor * 50 / (cl ? 60 : 56); else if (MechSpecials2(mech) & HVY_FF_ARMOR_TECH) armor = armor * 50 / 62; else if (MechSpecials2(mech) & LT_FF_ARMOR_TECH) armor = armor * 50 / 53; else if (MechSpecials(mech) & HARDA_TECH) armor *= 2; ADDENTRY_C(MechSpecials2(mech) & STEALTH_ARMOR_TECH ? "Armor (Stealth)" : MechSpecials2(mech) & HVY_FF_ARMOR_TECH ? "Armor (Hvy FF)" : MechSpecials2(mech) & LT_FF_ARMOR_TECH ? "Armor (Lt FF)" : MechSpecials(mech) & HARDA_TECH ? "Armor (Hardened)" : MechSpecials(mech) & FF_TECH ? "Armor (FF)" : "Armor", armor_o, round_to_halfton(armor * 1024 / 16)); pile[Special(HEAT_SINK)] = MAX(0, MechRealNumsinks(mech) * shs_size / hs_eff - (MechSpecials(mech) & ICE_TECH ? 0 : 10) * shs_size); for (i = 1; i < NUM_ITEMS_M; i++) if (pile[i]) { if (IsWeapon(i)) { id = Weapon2I(i); ADDENTRY_C(MechWeapons[id].name, pile[i] / GetWeaponCrits(mech, id), crit_weight(mech, i) * pile[i]); } else if ((w = crit_weight(mech, i))) ADDENTRY_C(get_parts_long_name(i, 0), pile[i], w * pile[i]); } if (CargoSpace(mech)) ADDENTRY(tprintf("CargoSpace (%.2ft)", (float) CargoSpace(mech) / 100), (int) (((float) CargoSpace(mech) / (MechSpecials2(mech) & CARRIER_TECH ? 1000 : MechSpecials(mech) & CARGO_TECH ? 100 : 500)) * 1024)); if (interactive > 0) { addline(); vsi(tprintf("%%cgTotal: %s%.1f tons (offset: %.1f)%%cn", (total / 1024) > MechTons(mech) ? "%ch%cr" : "", (float) (total) / 1024.0, MechTons(mech) - (float) (total) / 1024.0)); addline(); ShowCoolMenu(player, c); } KillCoolMenu(c); if (interactive < 0) total += ammo_weight(mech); return MAX(1, total); } /* Returns: 1024 * MechWeight(in tons) */ int mech_weight_sub(dbref player, MECH * mech, int interactive) { if (MechType(mech) == CLASS_MECH) return mech_weight_sub_mech(player, mech, interactive); if (MechType(mech) == CLASS_VEH_GROUND || MechType(mech) == CLASS_VTOL || MechType(mech) == CLASS_VEH_NAVAL) return mech_weight_sub_veh(player, mech, interactive); if (interactive > 0) notify(player, "Invalid vehicle type!"); return 1; } void mech_weight(dbref player, void *data, char *buffer) { MECH *mech = (MECH *) data; mech_weight_sub(player, mech, 1); } #define Table(i,j) \ (MechIsQuad(mech) ? quad_loc_table[i][j] : mech_loc_table[i][j]) static int real_int(MECH * mech, int loc, int ti) { int i; if (loc == HEAD) return 3; for (i = 0; Table(i, 0) >= 0; i++) if (loc == Table(i, 0)) break; if (Table(i, 0) < 0) return 0; return int_data[ti][Table(i, 1)]; } #define tank_int(mech) MAX((MechTons(mech) + 5) / 10, 1) void vehicle_int_check(MECH * mech, int noisy) { int i, j; j = tank_int(mech); for (i = 0; i < NUM_SECTIONS; i++) if (GetSectOInt(mech, i) && GetSectOInt(mech, i) != j) { if (noisy) SendError(tprintf ("Template %s / mech #%d: Invalid internals in loc %d (should be %d, are %d)", MechType_Ref(mech), mech->mynum, i, j, GetSectOInt(mech, i))); SetSectOInt(mech, i, j); SetSectInt(mech, i, j); } } void mech_int_check(MECH * mech, int noisy) { int i, j, k; if (MechType(mech) != CLASS_MECH) { if (MechType(mech) == CLASS_VEH_GROUND || MechType(mech) == CLASS_VTOL || MechType(mech) == CLASS_VEH_NAVAL) vehicle_int_check(mech, noisy); return; } for (i = 0; int_data[i][0] >= 0; i++) if (MechTons(mech) == int_data[i][0]) break; if (int_data[i][0] < 0) { if (noisy) SendError(tprintf("VERY odd tonnage for #%d: %d.", mech->mynum, MechTons(mech))); return; } k = i; for (i = 0; i < NUM_SECTIONS; i++) { if (GetSectOInt(mech, i) != (j = real_int(mech, i, k))) { if (noisy) SendError(tprintf ("Template %s / mech #%d: Invalid internals in loc %d (should be %d, are %d)", MechType_Ref(mech), mech->mynum, i, j, GetSectOInt(mech, i))); SetSectOInt(mech, i, j); SetSectInt(mech, i, j); } } }