/* * $Id: mech.custom.c,v 1.1.1.1 2005/01/11 21:18:14 kstevens Exp $ * * Author: Markus Stenberg <fingon@iki.fi> * * Copyright (c) 1997 Markus Stenberg * All rights reserved * * Created: Wed Feb 19 18:17:54 1997 fingon * Last modified: Sat Jun 6 22:22:23 1998 fingon * */ /* Mech-customization code */ #include <math.h> #include "mech.h" #include "mux_tree.h" #include "coolmenu.h" #include "mech.custom.h" #include "mycool.h" #include "glue.h" #include "create.h" #include "mech.partnames.h" #include "help.h" #include "p.mech.utils.h" #include "p.mech.tech.h" #include "p.mech.status.h" #include "p.mech.consistency.h" #include "p.mech.build.h" dbref match_thing(dbref player, char *name); void muxevent_remove_data(void *data); /* Basically: We keep a tree of our own with information about the 'mechs that people want, and update it with menu choices. When save/discard is chosen, the data is freed and, in case of save, the new model is saved into @MECHCUSTOM attribute */ /* @MECHCUSTOM syntax: - Each customization starts with string: +#<ref> where <ref> is ref of the guy doing this customization. After that, without spaces, follow all the changes we need to do to a template to make new 'mech exactly like the original, as follows: C<num/num/num> Changes the critical at num/num to num A<num/value> Changes the armor at num to value R<num/value> Changes the rear armor at num to value (seperator ;) Example: +#9;C0/2/12;A1/20 -After that, comes field ';-Accepted by Name<#ref>' if the modification has been approved. If none exist, the application has yet to be reviewed. Alternatively, it can have: ';*Rejected by Name<#ref>' Each custom-entry is seperated by a +, as well. */ coolmenu *semi_static_menu = NULL; extern int global_silence; #define CONVERT_TO(val,loc,pos,extra) \ loc = val % NUM_SECTIONS; \ pos = (val / NUM_SECTIONS - 1) % NUM_CRITICALS ; \ extra = ((val / NUM_SECTIONS - 1) / NUM_CRITICALS) - 1; #define CALC_FROM(loc,pos,extra) \ (loc + NUM_SECTIONS * ( pos + 1 + (1 + extra) * NUM_CRITICALS)) #define CONVERT_FROM(val,loc,pos,extra) \ val = CALC_FROM(loc, pos, extra) #define choiceg(text,id,w) \ CreateMenuEntry_Normal(&c, (char *) text, w|CM_TOGGLE|CM_NORIGHT, id, 1) #define choice(text,id) \ choiceg(text, id, CM_ONE) #define choice2(text,id) \ choiceg(text, id, CM_TWO) #define toggle choice #define numberg(text,id,value,max,w) \ CreateMenuEntry_Killer(&c, (char *) text, w|CM_NUMBER, id, value, max) #define number(text,id,value,max) \ numberg(text,id,value,max,CM_ONE) #define number2(text,id,value,max) \ numberg(text,id,value,max,CM_TWO) #define number2_l(text,id,value,max) \ numberg(text,id,value,max,CM_TWO|CM_NORIGHT) #define number2_r(text,id,value,max) \ numberg(text,id,value,max,CM_TWO|CM_NOTOG) #define OkWeap(i,req,cant) \ (MechWeapons[i].type != THAND && \ (!req || (MechWeapons[i].special & req)) && \ (!cant || !(MechWeapons[i].special & cant))) static void custom_info(coolmenu * c, char *str, MECH * mech, int loc, int pos) { const char **locs = ProperSectionStringFromType(MechType(mech), MechMove(mech)); cent(tprintf("%s for %s/%d:", str, locs[loc], pos + 1)); } static void custom_do_weapon(coolmenu * c, MECH * mech, int loc, int pos, int req, int cant) { int i; custom_info(c, "Weapon selection", mech, loc, pos); for (i = 0; MechWeapons[i].name; i++) if (OkWeap(i, req, cant) && !(MechWeapons[i].special & PCOMBAT)) choice2(MechWeapons[i].name, i); } static void custom_do_ammo(coolmenu * c, MECH * mech, int loc, int pos, int req, int cant) { int i; custom_info(c, "Ammo selection", mech, loc, pos); for (i = 0; MechWeapons[i].name; i++) if (OkWeap(i, req, cant) && MechWeapons[i].ammoperton && !(MechWeapons[i].special & PCOMBAT)) choice2(MechWeapons[i].name, i); } static int ok_specials[][2] = { {HEAT_SINK, 0}, {JUMP_JET, 0}, {AXE, 0}, {SWORD, 1}, {MACE, 2}, {CLAW, 2}, {CASE, 1}, {FERRO_FIBROUS, 1}, {ENDO_STEEL, 1}, {TRIPLE_STRENGTH_MYOMER, 1}, {TARGETING_COMPUTER, 1}, {MASC, 1}, {C3_MASTER, 1}, {C3_SLAVE, 1}, {BEAGLE_PROBE, 1}, {ARTEMIS_IV, 1}, {STEALTH_ARMOR, 1}, {NULL_SIGNATURE_SYSTEM, 1}, {HVY_FERRO_FIBROUS, 1}, {LT_FERRO_FIBROUS, 1}, {C3I, 1}, {BLOODHOUND_PROBE, 1}, {-1, 0} }; static void custom_do_special(coolmenu * c, MECH * mech, int loc, int pos, int spect) { int i; custom_info(c, "Special selection", mech, loc, pos); for (i = 0; ok_specials[i][0] >= 0; i++) if (ok_specials[i][1] == spect) choice(get_parts_long_name(Special(ok_specials[i][0]), 0), ok_specials[i][0]); } #define CHANGE_ARMOR 0 /* Change armor (location, amount) */ #define CHANGE_RARMOR 1 /* Change armor (location, amount) */ #define REMOVE_CRIT 2 /* Removes crit (location, position) */ #define REMOVE_WEAPON 3 /* Removes crit (location, position) */ #define DO_ADD_CRIT 4 /* Adds crit (location, position, type) */ #define DO_ADD_WEAPON 5 /* Adds weapon (location, position, type) */ #define REORIENT_WEAPON 6 /* Reorient the weapon (alter the mode) */ #define ALTER_AMMO 7 /* Changes the ammo type */ #define CHANGE_ERROR1 8 /* Inconsistent original template (location) */ #define CHANGE_ERROR2 9 /* Inconsistent target template (location) */ struct { char *text; int type; } foo_table[] = { /*0 */ { "%s armor: %d points", 1}, /*1 */ { "%s rear armor: %d points", 1}, /*2 */ { "%s/%d (%s): Removed", 2}, /*3 */ { "%s/%s (%s): Removed", 3}, /*4 */ { "%s/%d (%s): Added", 2}, /*5 */ { "%s/%s (%s): Added", 3}, /*6 */ { "%s/%s (%s): Reoriented", 3}, /*7 */ { "%s/%d (%s): Changed ammo type", 2}, /*8 */ { "%s: %%ch%%crFROM wpn crit error%%cn!", 1}, /*9 */ { "%s: %%ch%%crTO wpn crit error%%cn!", 1} }; #define CHANGE_ARMOR_TIME 10 #define REMOVE_CRIT_TIME 60 #define REMOVE_WEAPON_TIME 90 #define ADD_CRIT_TIME 120 #define ADD_WEAPON_TIME 180 #define REORIENT_TIME 30 #define ALTER_AMMO_TIME 20 #define MAX_CHANGES 100 static int changes[MAX_CHANGES][6]; static int last_change = 0; #define addchange(type, loc, pos, val, tons, time) \ { \ if (last_change < 100) \ changes[last_change][0] = type; \ changes[last_change][1] = loc; \ changes[last_change][2] = pos; \ changes[last_change][3] = val; \ changes[last_change][4] = tons; \ changes[last_change++][5] = time; \ } int crit_weight(MECH * mech, int t) { int cl; if (IsWeapon(t)) return MechWeapons[Weapon2I(t)].weight * 1024 / 100 / GetWeaponCrits(mech, Weapon2I(t)); if (IsAmmo(t)) return 512; if (!(IsSpecial(t))) return 1024; t = Special2I(t); cl = MechSpecials(mech) & CLAN_TECH; switch (t) { case HEAT_SINK: return 1024 / HS_Size(mech); case TARGETING_COMPUTER: case AXE: case MACE: case ARTEMIS_IV: case MASC: case C3_SLAVE: case TAG: case LAMEQUIP: return 1024; case C3I: return 1280 * (MechType(mech) == CLASS_MECH ? 1 : 2); case ANGELECM: case BLOODHOUND_PROBE: return 1024 * (MechType(mech) == CLASS_MECH ? 1 : 2); case C3_MASTER: return 1024 * (MechType(mech) == CLASS_MECH ? 1 : 5); case SWORD: /* A Sword weighs 1/20th of the 'mech tonnage, rounded up to the half ton, and is 1/15th (rounded up to int) number of crits. */ return (ceil(MechTons(mech) / 10.) * 512) / (ceil(MechTons(mech) / 15.)); case BEAGLE_PROBE: return 1024 * 3 / (MechType(mech) == CLASS_MECH ? 4 : 2); case ECM: /* IS ECM is 1.5 tons for 2 crits, Clan ECM 1 ton for 1 crit. */ return 1024 * (cl ? 4 : MechType(mech) == CLASS_MECH ? 3 : 6) / 4; case CASE: return 512; case JUMP_JET: if (MechTons(mech) <= 55) return 512; if (MechTons(mech) <= 85) return 1024; return 2048; default: return 0; } } #define CustomWeaponModes (REAR_MOUNT|ON_TC|OS_MODE|HALFTON_MODE) #define CustomAmmoModes (ARTEMIS_MODE|NARC_MODE|INARC_MODES|SWARM_MODE|SWARM1_MODE|INFERNO_MODE|LBX_MODE) int generate_change_list(MECH * from, MECH * to) { int dif, i, j, k, noerror; int ft, cr, crl; unsigned char weaparray_f[MAX_WEAPS_SECTION]; unsigned char weapdata_f[MAX_WEAPS_SECTION]; int critical_f[MAX_WEAPS_SECTION]; unsigned char weaparray_t[MAX_WEAPS_SECTION]; unsigned char weapdata_t[MAX_WEAPS_SECTION]; int critical_t[MAX_WEAPS_SECTION]; int num_weaps_f, num_weaps_t, found; last_change = 0; for (i = 0; i < NUM_SECTIONS; i++) { if ((dif = (GetSectOArmor(to, i) - GetSectOArmor(from, i)))) addchange(CHANGE_ARMOR, i, 0, dif, dif * 64, abs(dif) * CHANGE_ARMOR_TIME); if ((dif = (GetSectORArmor(to, i) - GetSectORArmor(from, i)))) addchange(CHANGE_RARMOR, i, 0, dif, dif * 64, abs(dif) * CHANGE_ARMOR_TIME); } global_silence = 1; for (i = 0; i < NUM_SECTIONS; i++) { noerror = 1; crl = CritsInLoc(from, i); if ((num_weaps_f = FindWeapons_Advanced(from, i, weaparray_f, weapdata_f, critical_f, 1)) < 0) { addchange(CHANGE_ERROR1, i, 0, 0, 0, 0); continue; } if ((num_weaps_t = FindWeapons_Advanced(to, i, weaparray_t, weapdata_t, critical_t, 0)) < 0) { addchange(CHANGE_ERROR2, i, 0, 0, 0, 0); continue; } for (j = 0; j < crl; j++) { if (!(ft = (GetPartType(from, i, j)))) continue; if (GetPartType(to, i, j) == ft) { if (IsAmmo(ft)) if ((GetPartAmmoMode(from, i, j) & CustomAmmoModes) != (GetPartAmmoMode(to, i, j) & CustomAmmoModes)) addchange(ALTER_AMMO, i, j, 0, (GetPartFireMode(from, i, j) & HALFTON_MODE) ? 512 : 0 - (GetPartFireMode(to, i, j) & HALFTON_MODE) ? 512 : 0, ALTER_AMMO_TIME); continue; } if (IsWeapon(ft)) continue; addchange(REMOVE_CRIT, i, j, 0, AmmoMod(from, i, j) * (0 - crit_weight(from, ft)), REMOVE_CRIT_TIME); } for (j = 0; j < num_weaps_f; j++) { found = 0; for (k = 0; k < num_weaps_t; k++) if (weaparray_f[j] == weaparray_t[k] && critical_f[j] == critical_t[k] && (!mudconf.btech_parts || GetPartBrand(from, i, critical_f[j]) == GetPartBrand(to, i, critical_t[k]))) found = 1; if (found) { if ((GetPartFireMode(from, i, critical_f[j]) & CustomWeaponModes) != (GetPartFireMode(to, i, critical_f[j]) & CustomWeaponModes)) { cr = GetWeaponCrits(from, weaparray_f[j]); /* Otherwise reorient the weapon */ addchange(REORIENT_WEAPON, i, critical_f[j], weaparray_f[j], 0, REORIENT_TIME * cr); } continue; } cr = GetWeaponCrits(from, weaparray_f[j]); addchange(REMOVE_WEAPON, i, critical_f[j], weaparray_f[j], 0 - MechWeapons[weaparray_f[j]].weight * 1024 / 100, REMOVE_WEAPON_TIME * cr); } for (j = 0; j < crl; j++) { if (!(ft = (GetPartType(to, i, j)))) continue; if (IsWeapon(ft)) continue; if (GetPartType(from, i, j) == ft) continue; addchange(DO_ADD_CRIT, i, j, ft, AmmoMod(to, i, j) * crit_weight(to, ft), ADD_CRIT_TIME); } for (j = 0; j < num_weaps_t; j++) { found = 0; for (k = 0; k < num_weaps_f; k++) if (weaparray_f[k] == weaparray_t[j] && critical_f[k] == critical_t[j] && (!mudconf.btech_parts || GetPartBrand(from, i, critical_f[k]) == GetPartBrand(to, i, critical_t[j]))) found = 1; if (found) continue; cr = GetWeaponCrits(to, weaparray_t[j]); addchange(DO_ADD_WEAPON, i, critical_t[j], weaparray_t[j], MechWeapons[weaparray_t[j]].weight * 1024 / 100, ADD_WEAPON_TIME * cr); } } global_silence = 0; return last_change; } static void display_change_list(coolmenu * c, MECH * from, MECH * mech) { int i; int total_tons = 0; int total_time = 0; int f, t; int warn = 0; char buf[MBUF_SIZE]; char *str; for (i = 0; i < last_change; i++) { str = ShortArmorSectionString(MechType(mech), MechMove(mech), changes[i][1]); switch (foo_table[changes[i][0]].type) { case 1: sprintf(buf, foo_table[changes[i][0]].text, str, changes[i][3]); break; case 2: sprintf(buf, foo_table[changes[i][0]].text, str, changes[i][2] + 1, pos_part_name(changes[i][0] == REMOVE_CRIT ? from : mech, changes[i][1], changes[i][2])); if (changes[i][0] == REMOVE_CRIT && !PartIsDestroyed(from, changes[i][1], changes[i][2])) { strcat(buf, "(*)"); warn++; } break; case 3: f = changes[i][2] + 1; t = GetWeaponCrits(mech, changes[i][3]) + f - 1; sprintf(buf, foo_table[changes[i][0]].text, str, t == f ? tprintf("%d", f) : tprintf("%d-%d", f, t), pos_part_name(changes[i][0] == REMOVE_WEAPON ? from : mech, changes[i][1], changes[i][2])); if (changes[i][0] == REMOVE_WEAPON && !PartIsDestroyed(from, changes[i][1], changes[i][2])) { strcat(buf, "(*)"); warn++; } break; default: strcpy(buf, "---- BUG ----"); } addmenu(buf); if (changes[i][5]) { sprintf(buf, "%.1f tons / %d mins", changes[i][4] / 1024.0, changes[i][5]); total_time += changes[i][5]; total_tons += changes[i][4]; } else strcpy(buf, " "); addmenu(buf); } if (last_change > 1) { addmenu("Total"); sprintf(buf, "%.1f tons / %d mins", total_tons / 1024.0, total_time); addmenu(buf); } if (warn) { cent("WARNING: Parts marked with (*) haven't been removed yet."); cent("If you do not want to lose parts, remove them first with the"); cent("tech commands."); } } static void custom_do_main(coolmenu * c, MECH * new, dbref player) { MECH *mech = FindObjectsData(new->mynum); if (generate_change_list(mech, new)) { display_change_list(c, mech, new); addline(); } choice2("Alter criticals", ALTER_CRIT); choice2("Alter armor", ALTER_ARMOR); choice2("Discard changes", DISCARD_CHANGES); choice2("Apply for approval", APPLY_FOR_APPROVAL); if (Wiz(player)) choice2("Do it", DO_IT); } static char *ammo_text(int mode) { if (mode & LBX_MODE) return "LBX"; if (mode & ARTEMIS_MODE) return "ArtemisIV"; if (mode & NARC_MODE) return "NARC"; if (mode & INARC_EXPLO_MODE) return "Explosive"; if (mode & INARC_HAYWIRE_MODE) return "Haywire"; if (mode & INARC_ECM_MODE) return "ECM"; if (mode & INARC_NEMESIS_MODE) return "Nemesis"; if (mode & SWARM_MODE) return "Swarm"; if (mode & SWARM1_MODE) return "Swarm1"; if (mode & INFERNO_MODE) return "Inferno"; if (mode & AC_AP_MODE) return "ArmorPiercing"; if (mode & AC_FLECHETTE_MODE) return "Flechette"; if (mode & AC_INCENDIARY_MODE) return "Incendiary"; if (mode & AC_PRECISION_MODE) return "Precision"; return "Normal"; } /* Flag / No-weapon-flag / Weapon-flag / Type */ int ammo_mode_list[][4] = { {LBX_MODE, 0, LBX, TAMMO}, {ARTEMIS_MODE, 0, 0, TMISSILE}, {NARC_MODE, 0, 0, TMISSILE}, {INARC_EXPLO_MODE, 0, 0, TMISSILE}, {INARC_HAYWIRE_MODE, 0, 0, TMISSILE}, {INARC_ECM_MODE, 0, 0, TMISSILE}, {INARC_NEMESIS_MODE, 0, 0, TMISSILE}, {SWARM_MODE, DAR, IDF, TMISSILE}, {SWARM1_MODE, DAR, IDF, TMISSILE}, {INFERNO_MODE, IDF | DAR, 0, TMISSILE}, {0, 0, 0, -1} }; void ToggleAmmo(dbref player, MECH * mech, int loc, int pos) { int idx = Ammo2I(GetPartType(mech, loc, pos)); int m = GetPartAmmoMode(mech, loc, pos); int i, j = 0, prev = 0; #define TB(v) ToggleBit(GetPartAmmoMode(mech, loc, pos), v) for (i = 0; ammo_mode_list[i][0]; i++) if ((m & ammo_mode_list[i][0]) && (ammo_mode_list[j][3] < 0 || (MechWeapons[idx].type == ammo_mode_list[j][3]))) break; if (ammo_mode_list[i][0]) { /* _find_ mode to set */ TB(ammo_mode_list[i][0]); for (j = (i + 1); ammo_mode_list[j][0]; j++) if ((ammo_mode_list[j][3] < 0 || (MechWeapons[idx].type == ammo_mode_list[j][3])) && (ammo_mode_list[j][1] == 0 || (!(MechWeapons[idx].special & ammo_mode_list[j][1]))) && (ammo_mode_list[j][2] == 0 || (MechWeapons[idx].special & ammo_mode_list[j][2]))) break; if (ammo_mode_list[j][0]) { TB(ammo_mode_list[i][0]); return; } prev = 1; } for (j = 0; j < i; j++) if ((ammo_mode_list[j][3] < 0 || (MechWeapons[idx].type == ammo_mode_list[j][3])) && (ammo_mode_list[j][1] == 0 || (!(MechWeapons[idx].special & ammo_mode_list[j][1]))) && (ammo_mode_list[j][2] == 0 || (MechWeapons[idx].special & ammo_mode_list[j][2]))) break; if (j == i && !prev) { notify(player, "Error: That ammo type cannot be changed."); return; } TB(ammo_mode_list[j][0]); } static int custom_flag; static void custom_do_edit(coolmenu * c, dbref player, MECH * mech, int loc, int pos) { if (GetPartType(mech, loc, pos)) { choice("Remove critical", REMOVE); if (IsWeapon(GetPartType(mech, loc, pos))) { if (MechType(mech) == CLASS_MECH && (loc == CTORSO || loc == RTORSO || loc == LTORSO)) choice(tprintf("Toggle rear (now: %s)", GetPartFireMode(mech, loc, pos) & REAR_MOUNT ? "Rear" : "Front"), TOGGLE_REAR); if (Wiz(player) || (custom_flag & 8)) choice(tprintf("Toggle One-Shot (now: %s)", GetPartFireMode(mech, loc, pos) & OS_MODE ? "One-shot" : "Multi-shot"), TOGGLE_OS); if (Wiz(player) || (custom_flag & 4)) choice(tprintf("Toggle TC (now: %s)", GetPartFireMode(mech, loc, pos) & ON_TC ? "On" : "Off"), TOGGLE_TC); } else if (IsAmmo(GetPartType(mech, loc, pos))) { choice(tprintf("Change the ammo type (now: %s)", ammo_text(GetPartAmmoMode(mech, loc, pos))), TOGGLE_AMMO); if (Wiz(player) || (custom_flag & 16)) choice(tprintf("Toggle ammo size (full/half - now: %s)", GetPartFireMode(mech, loc, pos) & HALFTON_MODE ? "half" : " full"), TOGGLE_HALFAMMO); } } else { choice("Add weapon (oldtech)", ADD_WEAPON); if (Wiz(player) || (custom_flag & 1)) choice("Add weapon (newtech)", ADD_NWEAPON); if (Wiz(player) || (custom_flag & 2)) choice("Add weapon (clantech)", ADD_CWEAPON); choice("Add ammo (oldtech)", ADD_AMMO); if (Wiz(player) || (custom_flag & 1)) choice("Add ammo (newtech)", ADD_NAMMO); if (Wiz(player) || (custom_flag & 2)) choice("Add ammo (clantech)", ADD_CAMMO); choice("Add special (oldtech)", ADD_SPECIAL); if (Wiz(player) || (custom_flag & 32)) choice("Add special (clan/newtech)", ADD_NSPECIAL); } } static void custom_do_limb(coolmenu * c, MECH * mech) { int i; const char **locs = ProperSectionStringFromType(MechType(mech), MechMove(mech)); vsi("%cgSelect location to edit%cn"); addline(); for (i = 0; locs[i]; i++) if (GetSectOInt(mech, i)) choice(locs[i], i); } #define SectMax(mech,s) \ (MechType(mech) != CLASS_MECH ? \ ((MechType(mech) == CLASS_VTOL && s == ROTOR) ? 2 : 99) : \ (s == HEAD ? 9 : \ (GetSectOInt(mech, i) * 2))) static void custom_do_armor(coolmenu * c, MECH * new) { int i; const char **locs = ProperSectionStringFromType(MechType(new), MechMove(new)); char buf[MBUF_SIZE]; MECH *mech = FindObjectsData(new->mynum); for (i = 0; locs[i]; i++) { if (!GetSectOInt(mech, i)) continue; number2_l(locs[i], i, GetSectOArmor(new, i), SectMax(new, i) - GetSectORArmor(new, i)); sprintf(buf, "%24s%s", " ", GetSectOArmor(mech, i) == GetSectOArmor(new, i) ? "" : tprintf("%%ch%3d%%cn -> ", GetSectOArmor(mech, i))); number2_r(buf, i, GetSectOArmor(new, i), 0); } for (i = 0; locs[i]; i++) { if (!GetSectOInt(mech, i)) continue; if (!GetSectORArmor(mech, i)) continue; number2_l(tprintf("Rear: %s", locs[i]), i + 8, GetSectORArmor(new, i), SectMax(new, i) - GetSectOArmor(new, i)); sprintf(buf, "%24s%s", " ", GetSectORArmor(mech, i) == GetSectORArmor(new, i) ? "" : tprintf("%%ch%3d%%cn -> ", GetSectORArmor(mech, i))); number2_r(buf, i + 8, GetSectORArmor(new, i), 0); } } static void custom_do_crit(coolmenu * c, MECH * new, int loc) { int i, j, t, ok; const char **locs = ProperSectionStringFromType(MechType(new), MechMove(new)); vsi(tprintf("%%cgSelect critical to edit in %s%%cn", locs[loc])); addline(); for (i = 0; i < CritsInLoc(new, loc); i++) { ok = 1; if (IsSpecial((t = GetPartType(new, loc, i)))) { ok = 0; for (j = 0; ok_specials[j][0] >= 0; j++) if (Special(ok_specials[j][0]) == t) ok = 1; } if (!ok) choiceg(tprintf("%2d - %s", i + 1, pos_part_name(new, loc, i)), i, CM_ONE | CM_NOTOG); else toggle(tprintf("%2d - %s", i + 1, pos_part_name(new, loc, i)), i); } } static void custom_do_brand(coolmenu * c, MECH * mech, int loc, int pos, int type) { int i; for (i = 1; i <= 5; i++) toggle(get_parts_long_name(type, i), i); } static coolmenu *custom_menu(dbref player) { coolmenu *c = NULL; CUSTOM *cu; int loc, pos, s; MECH *mech; if (semi_static_menu) { KillCoolMenu(semi_static_menu); semi_static_menu = NULL; } cu = FindObjectsData(Location(player)); if (!(!cu || cu->user < 0 || (!Wiz(player) && cu->user != player))) { /* First criteria : Non-custom place / non-init'ed custom place -> no menu */ mech = &cu->new; addline(); if (cu->user != player) { cent(tprintf("%s customization in progress (by %s(#%d))", GetMechID(mech), Name(cu->user), cu->user)); addline(); } switch (cu->state) { case STATE_MAIN: custom_do_main(c, mech, player); break; case STATE_LIMB: custom_do_limb(c, mech); break; case STATE_ARMOR: custom_do_armor(c, mech); break; default: if (cu->state <= NUM_SECTIONS) custom_do_crit(c, mech, cu->state - 1); else { CONVERT_TO(cu->state, loc, pos, s); switch (s) { case 0: custom_do_edit(c, player, mech, loc, pos); break; case 1: custom_do_weapon(c, mech, loc, pos, 0, CLAT); break; case 2: custom_do_ammo(c, mech, loc, pos, 0, CLAT); break; case 4: custom_do_weapon(c, mech, loc, pos, 0, 0); break; case 8: custom_do_ammo(c, mech, loc, pos, 0, 0); break; case 16: custom_do_weapon(c, mech, loc, pos, CLAT, 0); break; case 32: custom_do_ammo(c, mech, loc, pos, CLAT, 0); break; case 64: custom_do_special(c, mech, loc, pos, 0); break; case 128: custom_do_special(c, mech, loc, pos, 1); break; default: custom_do_brand(c, mech, loc, pos, s / FIRST_UNUSED_BIT); break; } } } addline(); if (cu->state) addmenu("z - Back"); addmenu("HELP | EDIT <ref> | FINISH"); addline(); } semi_static_menu = c; return c; } static void show_custom(CUSTOM * cu, dbref player) { coolmenu *c; custom_flag = cu->allow; c = custom_menu(player); if (c) ShowCoolMenu(player, c); } static void advance_state(CUSTOM * cu, dbref player, int state) { cu->state = state; show_custom(cu, player); } void custom_edit(dbref player, void *data, char *buffer) { CUSTOM *cu = (CUSTOM *) data; dbref it; MECH *mech; /* This should do a lot of magic */ DOCHECK(cu->user >= 0, "'finish' the previous modification(s) first."); DOCHECK(!Wiz(player) && cu->user != player && cu->user >= 0, "This booth is in use by another guy!"); DOCHECK((it = match_thing(player, buffer)) <= 0, "Invalid target!"); DOCHECK(!Wiz(player) && Location(it) != Location(cu->mynum), "Invalid target!"); DOCHECK(!(mech = FindObjectsData(it)), "Invalid target!"); DOCHECK(figure_latest_tech_event(mech) > 0 && !Wiz(player), "That 'Mech is still under repairs!"); cu->user = player; cu->state = STATE_MAIN; cu->submit = -1; memcpy(&cu->new, mech, sizeof(MECH)); show_custom(cu, player); } void custom_finish(dbref player, void *data, char *buffer) { CUSTOM *cu = (CUSTOM *) data; DOCHECK(cu->user < 0, "You have to start the booth with 'EDIT #<num>'"); DOCHECK(!Wiz(player) && cu->user != player && Location(cu->user) == cu->mynum && Connected(cu->user), "This booth is in use by another guy!"); if (!buffer && Wiz(player)) notify(player, "All changes have been saved and booth freed."); else notify(player, "All changes have been *dumped* and booth is free for anyone to use again."); cu->user = -1; } void custom_back(dbref player, void *data, char *buffer) { CUSTOM *cu = (CUSTOM *) data; int loc, pos, s; DOCHECK(cu->user < 0, "You have to start the booth with 'EDIT #<num>'"); DOCHECK(!Wiz(player) && cu->user != player, "This booth is in use by another guy!"); DOCHECK(cu->state == STATE_MAIN, "There is no going back!"); switch (cu->state) { case STATE_LIMB: case STATE_ARMOR: advance_state(cu, player, STATE_MAIN); break; default: if (cu->state <= NUM_SECTIONS) advance_state(cu, player, STATE_LIMB); else { CONVERT_TO(cu->state, loc, pos, s); switch (s) { case 0: advance_state(cu, player, loc + 1); break; case 1: case 2: case 4: case 8: case 16: case 32: case 64: case 128: advance_state(cu, player, CALC_FROM(loc, pos, 0)); break; default: advance_state(cu, player, CALC_FROM(loc, pos, 1)); break; } } } } void custom_look(dbref player, void *data, char *buffer) { CUSTOM *cu = (CUSTOM *) data; DOCHECK(cu->user < 0, "You have to start the booth with 'EDIT #<num>'"); DOCHECK(!Wiz(player) && cu->user != player, "This booth is in use by another guy!"); show_custom(cu, player); } #define to_be_done(player) \ notify(player, "This function isn't implemented yet!"); void custom_help(dbref player, void *data, char *buffer) { char buf[MBUF_SIZE]; strcpy(buf, "custom"); help_write(player, buf, &mudstate.news_htab, mudconf.news_file, 0); } #define IsError(i) (changes[i][0] == CHANGE_ERROR2) static int do_changes(CUSTOM * cu, dbref player, MECH * from, MECH * to) { int i, j, k, loc, pos; int total_tons = 0; int total_time = 0; char buf[MBUF_SIZE]; if (!generate_change_list(from, to)) { notify(player, "There are no changes to make!"); return 0; } for (i = 0; i < last_change; i++) if (IsError(i)) { notify(player, "Inconsistency detected ; no changes made."); return 0; } for (i = 0; i < last_change; i++) { loc = changes[i][1]; pos = changes[i][2]; switch (changes[i][0]) { case CHANGE_ARMOR: SetSectOArmor(from, loc, (k = GetSectOArmor(to, loc))); if (GetSectArmor(from, loc) > k) SetSectArmor(from, loc, k); if (Wiz(cu->user)) SetSectArmor(from, loc, k); break; case CHANGE_RARMOR: SetSectORArmor(from, loc, (k = GetSectORArmor(to, loc))); if (GetSectRArmor(from, loc) > k) SetSectRArmor(from, loc, k); if (Wiz(cu->user)) SetSectRArmor(from, loc, k); break; case REMOVE_CRIT: SetPartType(from, loc, pos, 0); SetPartFireMode(from, loc, pos, 0); SetPartAmmoMode(from, loc, pos, 0); SetPartBrand(from, loc, pos, 0); SetPartData(from, loc, pos, 0); break; case REMOVE_WEAPON: for (j = pos; j < (pos + GetWeaponCrits(from, changes[i][3])); j++) { SetPartType(from, loc, j, 0); SetPartFireMode(from, loc, j, 0); SetPartAmmoMode(from, loc, j, 0); SetPartBrand(from, loc, j, 0); SetPartData(from, loc, j, 0); } break; case DO_ADD_CRIT: SetPartType(from, loc, pos, GetPartType(to, loc, pos)); SetPartBrand(from, loc, pos, GetPartBrand(to, loc, pos)); SetPartFireMode(from, loc, pos, GetPartFireMode(to, loc, pos)); SetPartAmmoMode(from, loc, pos, GetPartAmmoMode(to, loc, pos)); SetPartData(from, loc, pos, GetPartData(to, loc, pos)); if (!Wiz(cu->user)) DestroyPart(from, loc, pos); break; case ALTER_AMMO: GetPartAmmoMode(from, loc, pos) &= CustomAmmoModes; GetPartAmmoMode(from, loc, pos) |= (GetPartAmmoMode(to, loc, pos) & CustomAmmoModes); GetPartData(from, loc, pos) = 0; break; case REORIENT_WEAPON: for (j = pos; j < (pos + GetWeaponCrits(from, changes[i][3])); j++) { GetPartFireMode(from, loc, j) &= CustomWeaponModes; GetPartFireMode(from, loc, j) |= (GetPartFireMode(to, loc, pos) & CustomWeaponModes); } break; case DO_ADD_WEAPON: for (j = pos; j < (pos + GetWeaponCrits(from, changes[i][3])); j++) { SetPartType(from, loc, j, GetPartType(to, loc, j)); SetPartBrand(from, loc, j, GetPartBrand(to, loc, j)); SetPartFireMode(from, loc, j, GetPartFireMode(to, loc, j)); SetPartAmmoMode(from, loc, j, GetPartAmmoMode(to, loc, j)); SetPartData(from, loc, j, GetPartData(to, loc, j)); if (!Wiz(cu->user)) DestroyPart(from, loc, j); } break; } total_time += changes[i][5]; total_tons += changes[i][4]; } if (!Wiz(cu->user)) tech_addtechtime(cu->user, total_time); strcpy(buf, Name(player)); SendCustom(tprintf("%s(#%d)'s request was granted by %s(#%d)", Name(cu->user), cu->user, buf, player)); /* silly_atr_set(cu->mynum, A_MECHCUSTOM, tprintf("Approved by %s(#%d)", Name(player), player)); */ do_magic(from); muxevent_remove_data((void *) from); return last_change; } static void custom_act_main(CUSTOM * cu, MECH * mech, dbref player, int choice) { switch (choice) { case ALTER_CRIT: advance_state(cu, player, STATE_LIMB); return; case ALTER_ARMOR: advance_state(cu, player, STATE_ARMOR); return; case DISCARD_CHANGES: custom_finish(player, cu, ""); return; case APPLY_FOR_APPROVAL: DOCHECK(Wiz(player), "You can just DO IT! Duh."); if (cu->submit >= 0) notify(player, "You have already submitted a request. Please stand by."); else { notify(player, "An approval request has been submitted. There is NO guaranteed response,"); notify(player, "but if the design is reasonably IC and not munch, chances are that it might"); notify(player, "even get through. Thanks for your co-operation."); SendCustom(tprintf ("%s(#%d) requests customization approval in #%d for #%d.", Name(player), player, cu->mynum, mech->mynum)); cu->submit = 0; } return; case DO_IT: if (do_changes(cu, player, FindObjectsData(mech->mynum), mech)) custom_finish(player, cu, NULL); } } static void custom_act_ammo(CUSTOM * cu, MECH * mech, dbref player, int loc, int pos, int choice) { SetPartType(mech, loc, pos, I2Ammo(choice)); SetPartFireMode(mech, loc, pos, 0); SetPartAmmoMode(mech, loc, pos, 0); SetPartData(mech, loc, pos, FullAmmo(mech, loc, pos)); SetPartBrand(mech, loc, pos, 0); advance_state(cu, player, loc + 1); } static void custom_act_brand(CUSTOM * cu, MECH * mech, dbref player, int loc, int pos, int weapindx, int choice) { SetPartType(mech, loc, pos, weapindx); SetPartData(mech, loc, pos, 0); SetPartFireMode(mech, loc, pos, 0); SetPartAmmoMode(mech, loc, pos, 0); SetPartBrand(mech, loc, pos, choice); advance_state(cu, player, loc + 1); } static void custom_act_weapon(CUSTOM * cu, MECH * mech, dbref player, int loc, int pos, int choice) { advance_state(cu, player, CALC_FROM(loc, pos, FIRST_UNUSED_BIT * (choice + 1))); } static void custom_act_special(CUSTOM * cu, MECH * mech, dbref player, int loc, int pos, int choice) { SetPartType(mech, loc, pos, Special(choice)); SetPartData(mech, loc, pos, 0); SetPartFireMode(mech, loc, pos, 0); SetPartAmmoMode(mech, loc, pos, 0); SetPartBrand(mech, loc, pos, 0); advance_state(cu, player, loc + 1); } static void custom_act_edit(CUSTOM * cu, MECH * mech, dbref player, int loc, int pos, int choice) { switch (choice) { case ADD_WEAPON: advance_state(cu, player, CALC_FROM(loc, pos, 1)); return; case ADD_AMMO: advance_state(cu, player, CALC_FROM(loc, pos, 2)); return; case ADD_NWEAPON: advance_state(cu, player, CALC_FROM(loc, pos, 4)); return; case ADD_NAMMO: advance_state(cu, player, CALC_FROM(loc, pos, 8)); return; case ADD_CWEAPON: advance_state(cu, player, CALC_FROM(loc, pos, 16)); return; case ADD_CAMMO: advance_state(cu, player, CALC_FROM(loc, pos, 32)); return; case ADD_SPECIAL: advance_state(cu, player, CALC_FROM(loc, pos, 64)); return; case ADD_NSPECIAL: advance_state(cu, player, CALC_FROM(loc, pos, 128)); return; case TOGGLE_REAR: ToggleBit(GetPartFireMode(mech, loc, pos), REAR_MOUNT); notify(player, "Toggled!"); break; case TOGGLE_OS: ToggleBit(GetPartFireMode(mech, loc, pos), OS_MODE); notify(player, "Toggled!"); break; case TOGGLE_AMMO: ToggleAmmo(player, mech, loc, pos); notify(player, tprintf("Ammo is now %s.", ammo_text(GetPartAmmoMode(mech, loc, pos)))); break; case TOGGLE_HALFAMMO: ToggleBit(GetPartFireMode(mech, loc, pos), HALFTON_MODE); SetPartData(mech, loc, pos, FullAmmo(mech, loc, pos)); notify(player, tprintf("Changed to %s ton of ammo.", GetPartFireMode(mech, loc, pos) & HALFTON_MODE ? "half" : "full")); break; case TOGGLE_TC: ToggleBit(GetPartFireMode(mech, loc, pos), ON_TC); notify(player, "Toggled!"); break; case REMOVE: SetPartType(mech, loc, pos, 0); advance_state(cu, player, loc + 1); } } static void custom_act_limb(CUSTOM * cu, dbref player, int id) { advance_state(cu, player, id + 1); } static void custom_act_armor(CUSTOM * cu, MECH * mech, int loc, int value) { int isrear = loc >= NUM_SECTIONS; loc = loc % NUM_SECTIONS; if (isrear) { SetSectORArmor(mech, loc, value); SetSectRArmor(mech, loc, value); } else { SetSectOArmor(mech, loc, value); SetSectArmor(mech, loc, value); } } static void custom_act_crit(CUSTOM * cu, MECH * mech, dbref player, int loc, int pos) { advance_state(cu, player, CALC_FROM(loc, pos, 0)); } static void /* Change */ custom_recalculate_menu(dbref player, coolmenu * c, coolmenu * d) { CUSTOM *cu; MECH *mech; int loc, pos, s; cu = FindObjectsData(Location(player)); if (!cu || cu->user < 0 || (!Wiz(player) && cu->user != player)) return; mech = &cu->new; switch (cu->state) { case STATE_MAIN: custom_act_main(cu, mech, player, d->id); break; case STATE_LIMB: custom_act_limb(cu, player, d->id); break; case STATE_ARMOR: custom_act_armor(cu, mech, d->id, d->value); break; default: if (cu->state <= NUM_SECTIONS) custom_act_crit(cu, mech, player, cu->state - 1, d->id); else { CONVERT_TO(cu->state, loc, pos, s); switch (s) { case 0: custom_act_edit(cu, mech, player, loc, pos, d->id); break; case 1: case 4: case 16: if (!mudconf.btech_parts) custom_act_brand(cu, mech, player, loc, pos, s / FIRST_UNUSED_BIT, 0); else custom_act_weapon(cu, mech, player, loc, pos, d->id); break; case 2: case 8: case 32: custom_act_ammo(cu, mech, player, loc, pos, d->id); break; case 64: case 128: custom_act_special(cu, mech, player, loc, pos, d->id); break; default: custom_act_brand(cu, mech, player, loc, pos, s / FIRST_UNUSED_BIT, d->id); break; } } } } #define CUSTOM_COMMON \ CUSTOM *cu = (CUSTOM *) data; \ MECH *mech = &cu->new; \ DOCHECK(!cu || cu->user < 0, "There is nothing to see, yet!"); \ DOCHECK(cu->user != player && !Wiz(player), "Permission denied."); \ global_silence = 1; #define CUSTOM_COMMON_END \ global_silence = 0 void custom_status(dbref player, void *data, char *buffer) { CUSTOM_COMMON; mech_status(player, mech, buffer); CUSTOM_COMMON_END; } void custom_weight1(dbref player, void *data, char *buffer) { CUSTOM_COMMON; mech_weight(player, mech, buffer); CUSTOM_COMMON_END; } void custom_weight2(dbref player, void *data, char *buffer) { CUSTOM_COMMON; if (!(mech = FindObjectsData(mech->mynum))) { notify(player, "Error: Invalid 'mech."); CUSTOM_COMMON_END; return; } mech_weight(player, mech, buffer); CUSTOM_COMMON_END; } void custom_critstatus(dbref player, void *data, char *buffer) { CUSTOM_COMMON; mech_critstatus(player, mech, buffer); CUSTOM_COMMON_END; } void custom_weaponspecs(dbref player, void *data, char *buffer) { CUSTOM_COMMON; mech_weaponspecs(player, mech, buffer); CUSTOM_COMMON_END; } /* This is generated on the fly for each show-menu-request */ /* DasMagic is the one that figures how to get coolmenu struct */ #define DASMAGIC \ coolmenu *c;custom_flag = ((CUSTOM *) data)->allow;\ c = custom_menu(player) /* DasMagic2 is name of the coolmenu struct in the function */ #define DASMAGIC2 c /* DasMagic3 is called if value in the menu changes */ /* c = main menu, d = the changed entry */ #define DASMAGIC3 custom_recalculate_menu(player,c,d) /* If DasMagic4 is set, menu is re-shown every time value changes */ #undef DASMAGIC4 /* Don't want some of the stuff being shown */ #define REAL_SNEAKY_SET void newfreecustom(dbref key, void **data, int selector) { CUSTOM *new = *data; if (selector == SPECIAL_ALLOC) new->user = -1; } #include "coolmenu_interface2.h" COMMANDSET(cu);