/* * $Id: glue.c,v 1.4 2005/08/08 09:43:09 murrayma Exp $ * * Original author: unknown * * Copyright (c) 1996-2002 Markus Stenberg * Copyright (c) 1998-2002 Thomas Wouters * Copyright (c) 2000-2002 Cord Awtry * * Last modified: Thu Jul 9 02:40:16 1998 fingon * * This includes the basic code to allow objects to have hardcoded * commands / properties. * */ #include "config.h" #include <stdio.h> #include <sys/file.h> #include <string.h> #include <math.h> #define FAST_WHICHSPECIAL #include "create.h" #define _GLUE_C /*** #include all the prototype here! ****/ #include "mech.h" #include "mech.events.h" #include "debug.h" #include "mechrep.h" #include "mech.tech.h" #include "autopilot.h" #include "turret.h" #include "p.ds.turret.h" #include "coolmenu.h" #include "mech.custom.h" #include "p.bsuit.h" #include "scen.h" #include "glue.h" #include "mux_tree.h" #include "powers.h" #include "ansi.h" #include "coolmenu.h" #include "mycool.h" #include "p.mux_tree.h" #include "p.mechfile.h" #include "p.mech.stat.h" #include "p.mech.partnames.h" /* Prototypes */ /*************CALLABLE PROTOS*****************/ /* Main entry point */ int HandledCommand(dbref player, dbref loc, char *command); /* called when user creates/removes hardcode flag */ void CreateNewSpecialObject(dbref player, dbref key); void DisposeSpecialObject(dbref player, dbref key); void list_hashstat(dbref player, const char *tab_name, HASHTAB * htab); void raw_notify(dbref player, const char *msg); void AddEntry(Tree * tree, muxkey_t key, dtype_t type, dsize_t size, void *data); void DeleteEntry(Tree * tree, muxkey_t key); int SaveTree(FILE * f, Tree tree); void UpdateTree(FILE * f, Tree * tree, int (*sizefunc)(int)); void GoThruTree(Tree tree, int (*func) (Node *)); /*************PERSONAL PROTOS*****************/ void *NewSpecialObject(int id, int type); void *FindObjectsData(dbref key); static Node *FindObjectsNode(dbref key); static void DoSpecialObjectHelp(dbref player, char *type, int id, int loc, int powerneeded, int objid, char *arg); void initialize_colorize(); #ifndef FAST_WHICHSPECIAL #define WhichSpecialS WhichSpecial #define WhichType(node) WhichSpecial(NodeKey(node)) int WhichSpecial(dbref key); #else #define WhichType(node) NodeType(node) int WhichSpecial(dbref key); static int WhichSpecialS(dbref key); #endif /*********************************************/ HASHTAB SpecialCommandHash[NUM_SPECIAL_OBJECTS]; Tree xcode_tree = NULL; extern int map_sizefun(); static int Can_Use_Command(MECH * mech, int cmdflag) { #define TYPE2FLAG(a) \ ((a)==CLASS_MECH?GFLAG_MECH:(a)==CLASS_VEH_GROUND?GFLAG_GROUNDVEH:\ (a)==CLASS_AERO?GFLAG_AERO:DropShip(a)?GFLAG_DS:(a)==CLASS_VTOL?GFLAG_VTOL:\ (a)==CLASS_VEH_NAVAL?GFLAG_NAVAL:\ (a)==CLASS_BSUIT?GFLAG_BSUIT:\ (a)==CLASS_MW?GFLAG_MW:0) int i; if (!cmdflag) return 1; if (!mech || !(i = TYPE2FLAG(MechType(mech)))) return 0; if (cmdflag > 0) { if (cmdflag & i) return 1; } else if (!((0 - cmdflag) & i)) return 1; return 0; } int HandledCommand_sub(dbref player, dbref location, char *command) { struct SpecialObjectStruct *typeOfObject; Node *n = NULL; int type; CommandsStruct *cmd; HASHTAB *damnedhash; char *tmpc, *tmpchar; int ishelp; type = WhichSpecial(location); if (type < 0 || (SpecialObjects[type].datasize > 0 && !(n = FindNode(xcode_tree, location)))) { if (type >= 0 || !Hardcode(location) || Zombie(location)) return 0; if ((type = WhichSpecialS(location)) >= 0) { if (SpecialObjects[type].datasize > 0) return 0; } else return 0; } #ifdef FAST_WHICHSPECIAL if (type > NUM_SPECIAL_OBJECTS) return 0; #endif typeOfObject = &SpecialObjects[type]; damnedhash = &SpecialCommandHash[type]; tmpc = strstr(command, " "); if (tmpc) *tmpc = 0; ishelp = !strcmp(command, "HELP"); for (tmpchar = command; *tmpchar; tmpchar++) *tmpchar = ToLower(*tmpchar); cmd = (CommandsStruct *) hashfind(command, &SpecialCommandHash[type]); if (tmpc) *tmpc = ' '; if (cmd && (type != GTYPE_MECH || (type == GTYPE_MECH && Can_Use_Command(((MECH *) (NodeData(n))), cmd->flag)))) { #define SKIPSTUFF(a) while (*a && *a != ' ') a++;while (*a == ' ') a++ if (cmd->helpmsg[0] != '@' || Have_MechPower(Owner(player), typeOfObject->power_needed)) { SKIPSTUFF(command); cmd->func(player, !n ? NULL : NodeData(n), command); } else notify(player, "Sorry, that command is restricted!"); return 1; } else if (ishelp) { SKIPSTUFF(command); DoSpecialObjectHelp(player, typeOfObject->type, type, location, typeOfObject->power_needed, location, command); return 1; } return 0; } #define OkayHcode(a) (a >= 0 && Hardcode(a) && !Zombie(a)) /* Main entry point */ int HandledCommand(dbref player, dbref loc, char *command) { dbref curr, temp; if (Slave(player)) return 0; if (strlen(command) > (LBUF_SIZE - MBUF_SIZE)) return 0; if (OkayHcode(player) && HandledCommand_sub(player, player, command)) return 1; if (OkayHcode(loc) && HandledCommand_sub(player, loc, command)) return 1; SAFE_DOLIST(curr, temp, Contents(player)) { if (OkayHcode(curr)) if (HandledCommand_sub(player, curr, command)) return 1; #if 0 /* Recursion is evil ; let's not do that, this time */ if (Has_contents(curr)) if (HandledCommand_contents(player, curr, command)) return 1; #endif } return 0; } void InitSpecialHash(int which); void initialize_partname_tables(); static MECH *global_kludge_mech; int global_specials = NUM_SPECIAL_OBJECTS; static int remove_from_all_maps_func(Node * tmp) { if (WhichType(tmp) == GTYPE_MAP) { MAP *map; int i; if (!(map = getMap(NodeKey(tmp)))) return 1; for (i = 0; i < map->first_free; i++) if (map->mechsOnMap[i] == global_kludge_mech->mynum) map->mechsOnMap[i] = -1; } return 1; } void mech_remove_from_all_maps(MECH * mech) { global_kludge_mech = mech; GoThruTree(xcode_tree, remove_from_all_maps_func); } static dbref except_map = -1; static int remove_from_all_maps_except_func(Node * tmp) { if (WhichType(tmp) == GTYPE_MAP) { int i; MAP *map; if (NodeKey(tmp) == except_map) return 1; if (!(map = getMap(NodeKey(tmp)))) return 1; for (i = 0; i < map->first_free; i++) if (map->mechsOnMap[i] == global_kludge_mech->mynum) map->mechsOnMap[i] = -1; } return 1; } void mech_remove_from_all_maps_except(MECH * mech, int num) { global_kludge_mech = mech; except_map = num; GoThruTree(xcode_tree, remove_from_all_maps_except_func); except_map = -1; } static int load_update2(Node * tmp) { int i = WhichType(tmp);; if (i == GTYPE_MECH) mech_map_consistency_check(NodeData(tmp)); return 1; } static int load_update4(Node * tmp) { MECH *mech; MAP *map; #ifdef BT_ENABLED if (WhichType(tmp) == GTYPE_MECH) { mech = NodeData(tmp); if (!(map = getMap(mech->mapindex))) { /* Ugly kludge */ if ((map = getMap(Location(mech->mynum)))) mech_Rsetmapindex(GOD, mech, tprintf("%d", Location(mech->mynum))); if (!(map = getMap(mech->mapindex))) return 1; } if (!Started(mech)) return 1; StartSeeing(mech); MaybeRecycle(mech, 1); MaybeMove(mech); if (!FlyingT(mech) && Started(mech) && Jumping(mech)) mech_Rsetxy(GOD, (void *) mech, tprintf("%d %d", MechX(mech), MechY(mech))); } #endif return 1; } static int load_update3(Node * tmp) { int i = WhichType(tmp); if (i == GTYPE_MAP) { eliminate_empties((MAP *) NodeData(tmp)); recalculate_minefields((MAP *) NodeData(tmp)); } return 1; } static FILE *global_file_kludge; static int load_update1(Node * tmp) { MAP *map; int doh; char mapbuffer[MBUF_SIZE]; MECH *mech; int i; switch ((i = WhichType(tmp))) { #ifdef BT_ENABLED case GTYPE_MAP: map = (MAP *) NodeData(tmp); bzero(map->mapobj, sizeof(map->mapobj)); map->map = NULL; strcpy(mapbuffer, map->mapname); doh = (map->flags & MAPFLAG_MAPO); if (strcmp(map->mapname, "Default Map")) map_loadmap(1, map, mapbuffer); if (!strcmp(map->mapname, "Default Map") || !map->map) initialize_map_empty(map, NodeKey(tmp)); if (!feof(global_file_kludge)) { load_mapdynamic(global_file_kludge, map); if (!feof(global_file_kludge)) if (doh) load_mapobjs(global_file_kludge, map); } if (feof(global_file_kludge)) { map->first_free = 0; map->mechflags = NULL; map->mechsOnMap = NULL; map->LOSinfo = NULL; } debug_fixmap(GOD, map, NULL); break; case GTYPE_MECH: mech = (MECH *) NodeData(tmp); if (!(FlyingT(mech) && !Landed(mech))) { MechDesiredSpeed(mech) = 0; MechSpeed(mech) = 0; MechVerticalSpeed(mech) = 0; } MechCocoon(mech) = 0; MechStatus(mech) &= ~(BLINDED | UNCONSCIOUS | JUMPING | TOWED); MechSpecials2(mech) &= ~(ECM_ENABLED | ECM_DISTURBANCE | ECM_PROTECTED | ECCM_ENABLED | ANGEL_ECM_ENABLED | ANGEL_ECCM_ENABLED | ANGEL_ECM_PROTECTED | ANGEL_ECM_DISTURBED); MechCritStatus(mech) &= ~(JELLIED | LOAD_OK | OWEIGHT_OK | SPEED_OK); MechWalkXPFactor(mech) = 999; MechCarrying(mech) = -1; MechBoomStart(mech) = 0; MechC3iNetworkSize(mech) = -1; MechHeatLast(mech) = 0; MechCommLast(mech) = 0; for (i = 0; i < FREQS; i++) if (mech->freq[i] < 0) mech->freq[i] = 0; break; #endif } return 1; } /* * Read in autopilot data */ static int load_autopilot_data(Node *tmp) { AUTO *autopilot; int i; if (WhichType(tmp) == GTYPE_AUTO) { autopilot = (AUTO *) NodeData(tmp); /* Save the AI Command List */ auto_load_commands(global_file_kludge, autopilot); /* Reset the Astar Path */ autopilot->astar_path = NULL; /* Reset the weaplist */ autopilot->weaplist = NULL; /* Reset the profile */ for (i = 0; i < AUTO_PROFILE_MAX_SIZE; i++) { autopilot->profile[i] = NULL; } /* Check to see if the AI is in a mech */ /* Need to make this better, check if its got a target whatnot */ if (!autopilot->mymechnum || !(autopilot->mymech = getMech(autopilot->mymechnum))) { DoStopGun(autopilot); } else { if (Gunning(autopilot)) DoStartGun(autopilot); } } return 1; } static int get_specialobjectsize(int type) { if (type < 0 || type >= NUM_SPECIAL_OBJECTS) return -1; return SpecialObjects[type].datasize; } #ifdef BT_ADVANCED_ECON static void load_econdb() { FILE *f; /* Econ DB */ 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]; int count; fprintf(stderr, "LOADING: %s\n", mudconf.econ_db); f = fopen(mudconf.econ_db, "r"); if (!f) { fprintf(stderr, "ERROR: %s not found.\n", mudconf.econ_db); return; } count = fread(&specialcost, sizeof(unsigned long long int), SPECIALCOST_SIZE, f); if (count < SPECIALCOST_SIZE) { fprintf(stderr, "ERROR: %s specialcost read : %d expected %d\n", mudconf.econ_db, count, SPECIALCOST_SIZE); fclose(f); return; } count = fread(&ammocost, sizeof(unsigned long long int), AMMOCOST_SIZE, f); if (count < AMMOCOST_SIZE) { fprintf(stderr, "ERROR: %s ammocost read : %d expected %d\n", mudconf.econ_db, count, AMMOCOST_SIZE); fclose(f); return; } count = fread(&weapcost, sizeof(unsigned long long int), WEAPCOST_SIZE, f); if (count < WEAPCOST_SIZE) { fprintf(stderr, "ERROR: %s weapcost read : %d expected %d\n", mudconf.econ_db, count, WEAPCOST_SIZE); fclose(f); return; } count = fread(&cargocost, sizeof(unsigned long long int), CARGOCOST_SIZE, f); if (count < CARGOCOST_SIZE) { fprintf(stderr, "ERROR: %s cargocost read : %d expected %d\n", mudconf.econ_db, count, CARGOCOST_SIZE); fclose(f); return; } count = fread(&bombcost, sizeof(unsigned long long int), BOMBCOST_SIZE, f); if (count < BOMBCOST_SIZE) { fprintf(stderr, "ERROR: %s bombcost read : %d expected %d\n", mudconf.econ_db, count, BOMBCOST_SIZE); fclose(f); return; } fclose(f); fprintf(stderr, "LOADING: %s (done\n", mudconf.econ_db); } #endif static void load_xcode() { FILE *f; byte xcode_version; int filemode; RCache_Flush(); initialize_colorize(); fprintf(stderr, "LOADING: %s\n", mudconf.hcode_db); f = my_open_file(mudconf.hcode_db, "r", &filemode); if (!f) { fprintf(stderr, "ERROR: %s not found.\n", mudconf.hcode_db); return; } fread(&xcode_version, 1, 1, f); if (xcode_version != XCODE_VERSION) { fprintf(stderr, "LOADING: %s (skipped xcodetree - version difference: %d vs %d)\n", mudconf.hcode_db, (int) xcode_version, (int) XCODE_VERSION); return; } UpdateTree(f, &xcode_tree, get_specialobjectsize); global_file_kludge = f; GoThruTree(xcode_tree, load_update1); GoThruTree(xcode_tree, load_update2); GoThruTree(xcode_tree, load_update3); GoThruTree(xcode_tree, load_update4); /* Read in autopilot data */ GoThruTree(xcode_tree, load_autopilot_data); #ifdef BT_ENABLED if (!feof(f)) loadrepairs(f); #endif my_close_file(f, &filemode); fprintf(stderr, "LOADING: %s (done)\n", mudconf.hcode_db); #ifdef BT_ADVANCED_ECON load_econdb(); #endif } static int zappable_node; static int zap_check(Node * n) { if (zappable_node >= 0) return 0; if (!Hardcode(NodeKey(n))) { zappable_node = NodeKey(n); return 0; } return 1; } void zap_unneccessary_hcode() { while (1) { zappable_node = -1; GoThruTree(xcode_tree, zap_check); if (zappable_node >= 0) DeleteEntry(&xcode_tree, zappable_node); else break; } } void LoadSpecialObjects(void) { dbref i; int id, brand; int type; void *tmpdat; muxevent_initialize(); muxevent_count_initialize(); #ifdef BT_ENABLED init_stat(); initialize_partname_tables(); for (i = 0; MissileHitTable[i].key != -1; i++) { if (find_matching_vlong_part(MissileHitTable[i].name, NULL, &id, &brand)) MissileHitTable[i].key = Weapon2I(id); else MissileHitTable[i].key = -2; } #endif /* Loop through the entire database, and if it has the special */ /* object flag, add it to our linked list. */ for (i = 0; i < mudstate.db_top; i++) if (Hardcode(i) && !Going(i) && !Halted(i)) { type = WhichSpecialS(i); if (type >= 0) { if (SpecialObjects[type].datasize > 0) tmpdat = NewSpecialObject(i, type); else tmpdat = NULL; } else c_Hardcode(i); /* Reset the flag */ } for (i = 0; i < NUM_SPECIAL_OBJECTS; i++) { InitSpecialHash(i); if (!SpecialObjects[i].updatefunc) SpecialObjects[i].updateTime = 0; } #ifdef BT_ENABLED init_btechstats(); #endif load_xcode(); zap_unneccessary_hcode(); } #ifdef BT_ENABLED static FILE *global_file_kludge; static int save_maps_func(Node * tmp) { MAP *map; if (WhichType(tmp) == GTYPE_MAP) { /* Write mapobjs, if neccessary */ map = (MAP *) NodeData(tmp); save_mapdynamic(global_file_kludge, map); if (map->flags & MAPFLAG_MAPO) save_mapobjs(global_file_kludge, map); } return 1; } /* * Save any extra info for the autopilots * * Like their command lists * or the Astar path if there is one * */ static int save_autopilot_data(Node *tmp) { AUTO *a; if (WhichType(tmp) == GTYPE_AUTO) { a = (AUTO *) NodeData(tmp); /* Save the AI Command List */ auto_save_commands(global_file_kludge, a); /* Save the AI Astar Path */ } return 1; } #endif void ChangeSpecialObjects(int i) { /* XXX Unneccessary for now ; 'latest' db (db.new) is equivalent to 'db' because we don't _have_ new-db concept ; this is to-be-done project, however */ } #ifdef BT_ADVANCED_ECON static void save_econdb(char *target, int i) { FILE *f; 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]; int count; switch (i) { case DUMP_KILLED: sprintf(target, "%s.KILLED", mudconf.econ_db); break; case DUMP_CRASHED: sprintf(target, "%s.CRASHED", mudconf.econ_db); break; default: /* RESTART / normal */ sprintf(target, "%s.tmp", mudconf.econ_db); break; } f = fopen(target, "w"); if (!f) { log_perror("SAVE", "FAIL", "Opening econ-save file", target); SendDB("ERROR occured during opening of new econ-savefile."); return; } count = fwrite(&specialcost, sizeof(unsigned long long int), SPECIALCOST_SIZE, f); if (count < SPECIALCOST_SIZE) { log_perror("SAVE", "FAIL", tprintf("ERROR: %s specialcost wrote : %d expected %d", target, count, SPECIALCOST_SIZE), target); SendDB("ERROR occured during saving of econ-save file"); fclose(f); return; } count = fwrite(&ammocost, sizeof(unsigned long long int), AMMOCOST_SIZE, f); if (count < AMMOCOST_SIZE) { log_perror("SAVE", "FAIL", tprintf("ERROR: %s ammocost wrote : %d expected %d", target, count, AMMOCOST_SIZE), target); SendDB("ERROR occured during saving of econ-save file"); fclose(f); return; } count = fwrite(&weapcost, sizeof(unsigned long long int), WEAPCOST_SIZE, f); if (count < WEAPCOST_SIZE) { log_perror("SAVE", "FAIL", tprintf("ERROR: %s weapcost wrote : %d expected %d", target, count, WEAPCOST_SIZE), target); SendDB("ERROR occured during saving of econ-save file"); fclose(f); return; } count = fwrite(&cargocost, sizeof(unsigned long long int), CARGOCOST_SIZE, f); if (count < CARGOCOST_SIZE) { log_perror("SAVE", "FAIL", tprintf("ERROR: %s cargocost wrote : %d expected %d", target, count, CARGOCOST_SIZE), target); SendDB("ERROR occured during saving of econ-save file"); fclose(f); return; } count = fwrite(&bombcost, sizeof(unsigned long long int), BOMBCOST_SIZE, f); if (count < BOMBCOST_SIZE) { log_perror("SAVE", "FAIL", tprintf("ERROR: %s bombcost wrote : %d expected %d", target, count, BOMBCOST_SIZE), target); SendDB("ERROR occured during saving of econ-save file"); fclose(f); return; } fclose(f); if (i == DUMP_RESTART || i == DUMP_NORMAL) { if (rename(target, mudconf.econ_db) < 0) { log_perror("SAV", "FAIL", "Renaming econ-save file ", target); SendDB("ERROR occured during renaming of econ save-file."); } } } #endif void SaveSpecialObjects(int i) { FILE *f; int filemode, count; byte xcode_version = XCODE_VERSION; char target[LBUF_SIZE]; switch (i) { case DUMP_KILLED: sprintf(target, "%s.KILLED", mudconf.hcode_db); break; case DUMP_CRASHED: sprintf(target, "%s.CRASHED", mudconf.hcode_db); break; default: /* RESTART / normal */ sprintf(target, "%s.tmp", mudconf.hcode_db); break; } f = my_open_file(target, "w", &filemode); if (!f) { log_perror("SAV", "FAIL", "Opening new hcode-save file", target); SendDB("ERROR occured during opening of new hcode-savefile."); return; } fwrite(&xcode_version, 1, 1, f); count = SaveTree(f, xcode_tree); #ifdef BT_ENABLED global_file_kludge = f; /* Then, check each xcode thing for stuff */ GoThruTree(xcode_tree, save_maps_func); /* Save autopilot data */ GoThruTree(xcode_tree, save_autopilot_data); saverepairs(f); #endif my_close_file(f, &filemode); if (i == DUMP_RESTART || i == DUMP_NORMAL) { if (rename(mudconf.hcode_db, tprintf("%s.prev", mudconf.hcode_db)) < 0) { log_perror("SAV", "FAIL", "Renaming old hcode-save file ", target); SendDB ("ERROR occured during renaming of old hcode save-file."); } if (rename(target, mudconf.hcode_db) < 0) { log_perror("SAV", "FAIL", "Renaming new hcode-save file ", target); SendDB ("ERROR occured during renaming of new hcode save-file."); } } if (count) SendDB(tprintf("Hcode saved. %d xcode entries dumped.", count)); #ifdef BT_ADVANCED_ECON save_econdb(target, i); #endif } static int UpdateSpecialObject_func(Node * tmp) { int i; i = WhichType(tmp); if (!SpecialObjects[i].updateTime) return 1; if ((mudstate.now % SpecialObjects[i].updateTime)) return 1; SpecialObjects[i].updatefunc(NodeKey(tmp), NodeData(tmp)); return 1; } /* This is called once a second for each special object */ /* Note the new handling for calls being done at <1second intervals, or possibly at >1second intervals */ static time_t lastrun = 0; void UpdateSpecialObjects(void) { char *cmdsave; int i; int times = lastrun ? (mudstate.now - lastrun) : 1; if (times > 20) times = 20; /* Machine's hopelessly lagged, we don't want to make it [much] worse */ cmdsave = mudstate.debug_cmd; for (i = 0; i < times; i++) { muxevent_run(); mudstate.debug_cmd = (char *) "< Generic hcode update handler>"; GoThruTree(xcode_tree, UpdateSpecialObject_func); } lastrun = mudstate.now; mudstate.debug_cmd = cmdsave; } void *NewSpecialObject(int id, int type) { void *foo; int i; dbref *t; if (SpecialObjects[type].datasize) { Create(foo, char, (i = SpecialObjects[type].datasize)); t = (dbref *) foo; *t = id; if (SpecialObjects[type].allocfreefunc) SpecialObjects[type].allocfreefunc(id, &(foo), SPECIAL_ALLOC); AddEntry(&xcode_tree, id, type, i, foo); } return foo; } void CreateNewSpecialObject(dbref player, dbref key) { void *new; struct SpecialObjectStruct *typeOfObject; int type; char *str; str = silly_atr_get(key, A_XTYPE); if (!(str && *str)) { notify(player, "You must first set the XTYPE using @xtype <object>=<type>"); notify(player, "Valid XTYPEs include: MECH, MECHREP, MAP, DEBUG, " "CHARGEN, AUTOPILOT, TURRET, CUSTOM, SCEN, SSIDE, SSOBJ, " "SSINS, SSEXT"); notify(player, "Resetting hardcode flag."); c_Hardcode(key); /* Reset the flag */ return; } /* Find the special objects */ type = WhichSpecialS(key); if (type > -1) { /* We found the proper special object */ typeOfObject = &SpecialObjects[type]; if (typeOfObject->datasize) { new = NewSpecialObject(key, type); if (!new) notify(player, "Memory allocation failure!"); } } else { notify(player, "That is not a valid XTYPE!"); notify(player, "Valid XTYPEs include: MECH, MECHREP, MAP, DEBUG, " "CHARGEN, AUTOPILOT, TURRET, CUSTOM, SCEN, SSIDE, SSOBJ, " "SSINS, SSEXT"); notify(player, "Resetting HARDCODE flag."); c_Hardcode(key); } } void DisposeSpecialObject(dbref player, dbref key) { Node *tmp; int i; struct SpecialObjectStruct *typeOfObject; tmp = FindNode(xcode_tree, key); i = WhichSpecialS(key); if (i < 0) { notify(player, "CRITICAL: Unable to free data, inconsistency somewhere. Please"); notify(player, "contact a wizard about this _NOW_!"); return; } typeOfObject = &SpecialObjects[i]; if (typeOfObject->datasize > 0 && WhichSpecial(key) != i) { notify(player, "Semi-critical error has occured. For some reason the object's data differs\nfrom the data on the object. Please contact a wizard about this."); i = WhichSpecial(key); } if (tmp) { void *t = NodeData(tmp); if (typeOfObject->allocfreefunc) typeOfObject->allocfreefunc(key, &NodeData(tmp), SPECIAL_FREE); NodeData(tmp) = NULL; DeleteEntry(&xcode_tree, key); muxevent_remove_data(t); free(t); } else if (typeOfObject->datasize > 0) { notify(player, "This object is not in the special object DBASE."); notify(player, "Please contact a wizard about this bug. "); } } void Dump_Mech(dbref player, int type, char *typestr) { notify(player, "Support discontinued. Bother a wiz if this bothers you."); #if 0 MECH *mech; char buff[100]; int i, running = 0, count = 0; Node *temp; notify(player, "ID # STATUS MAP # PILOT #"); notify(player, "----------------------------------------"); for (temp = TreeTop(xcode_tree); temp; temp = TreeNext(temp)) if (WhichSpecial((i = NodeKey(temp))) == type) { mech = (MECH *) NodeData(temp); sprintf(buff, "#%5d %-8s #%5d #%5d", mech->mynum, !Started(mech) ? "SHUTDOWN" : "RUNNING", mech->mapindex, MechPilot(mech)); notify(player, buff); if (MechStatus(mech) & STARTED) running++; count++; } sprintf(buff, "%d %ss running out of %d %ss allocated.", running, typestr, count, typestr); notify(player, buff); notify(player, "Done listing"); #endif } void DumpMechs(dbref player) { Dump_Mech(player, GTYPE_MECH, "mech"); } void DumpMaps(dbref player) { notify(player, "Support discontinued. Bother a wiz if this bothers you."); #if 0 MAP *map; char buff[100]; int j, count; Node *temp; notify(player, "MAP # NAME X x Y MECHS"); notify(player, "-------------------------------------------"); for (temp = TreeTop(xcode_tree); temp; temp = TreeNext(temp)) if (WhichSpecial(NodeKey(temp)) == GTYPE_MAP) { count = 0; map = (MAP *) NodeData(temp); for (j = 0; j < map->first_free; j++) if (map->mechsOnMap[j] != -1) count++; sprintf(buff, "#%5d %-17.17s %3d x%3d %d", map->mynum, map->mapname, map->map_width, map->map_height, count); notify(player, buff); } notify(player, "Done listing"); #endif } /***************** INTERNAL ROUTINES *************/ #ifdef FAST_WHICHSPECIAL int WhichSpecial(dbref key) { Node *n; if (!Hardcode(key)) return -1; if (!(n = FindObjectsNode(key))) return -1; return NodeType(n); } #endif #ifdef FAST_WHICHSPECIAL static int WhichSpecialS(dbref key) #else int WhichSpecial(dbref key) #endif { int i; int returnValue = -1; char *str; if (!Hardcode(key)) return -1; str = silly_atr_get(key, A_XTYPE); if (str && *str) { for (i = 0; i < NUM_SPECIAL_OBJECTS; i++) { if (!strcmp(SpecialObjects[i].type, str)) { returnValue = i; break; } } } return (returnValue); } int IsMech(dbref num) { return WhichSpecial(num) == GTYPE_MECH; } int IsAuto(dbref num) { return WhichSpecial(num) == GTYPE_AUTO; } int IsMap(dbref num) { return WhichSpecial(num) == GTYPE_MAP; } /*** Support routines ***/ static Node *FindObjectsNode(dbref key) { Node *tmp; if ((tmp = FindNode(xcode_tree, (int) key))) return tmp; return NULL; } void *FindObjectsData(dbref key) { Node *tmp; if ((tmp = FindObjectsNode(key))) return NodeData(tmp); return NULL; } char *center_string(char *c, int len) { static char buf[LBUF_SIZE]; int l = strlen(c); int p, i; p = MAX(0, (len - l) / 2); for (i = 0; i < p; i++) buf[i] = ' '; strcpy(buf + p, c); return buf; } static void help_color_initialize(char *from, char *to) { int i; char buf[LBUF_SIZE]; for (i = 0; from[i] && from[i] != ' '; i++); if (from[i]) { /* from[i]=0; */ strncpy(buf, from, i); buf[i] = 0; sprintf(to, "%s%s%s %s", "%ch%cb", buf, "%cn", &from[i + 1]); /* from[i]=' '; */ } else sprintf(to, "%s%s%s", "%cc", from, "%cn"); } #define ONE_LINE_TEXTS #ifdef ONE_LINE_TEXTS #define MLen CM_ONE #else #define MLen CM_TWO #endif static char *do_ugly_things(coolmenu ** d, char *msg, int len, int initial) { coolmenu *c = *d; char *e; int i; char buf[LBUF_SIZE]; char msg2[LBUF_SIZE]; strcpy(msg2, msg); #ifndef ONE_LINE_TEXTS if (!msg) { sim(" ", MLen); *d = c; return NULL; } #endif if (strlen(msg) < len) { if (initial) { if (initial > 0) help_color_initialize(msg, buf); else { for (i = 0; i < -initial; i++) buf[i] = ' '; strcpy(&buf[i], msg); } sim(buf, MLen); } else sim(msg, MLen); *d = c; return NULL; } for (e = msg2 + len - 1; *e != ' '; e--); *e = 0; if (initial) { if (initial > 0) help_color_initialize(msg2, buf); else { for (i = 0; i < -initial; i++) buf[i] = ' '; strcpy(&buf[i], msg2); } sim(buf, MLen); } else sim(msg2, MLen); *e = ' '; *d = c; if ((*e + 1)) return e + 1; return NULL; } #define Len(s) ((!s || !*s) ? 0 : strlen(s)) #define TAB 3 static void cut_apart_helpmsgs(coolmenu ** d, char *msg1, char *msg2, int len, int initial) { int l1 = Len(msg1); int l2 = Len(msg2); int nl1, nl2; #ifndef ONE_LINE_TEXTS msg1 = do_ugly_things(d, msg1, len, initial); msg2 = do_ugly_things(d, msg2, initial ? len : len - TAB, initial ? 0 : 0 - TAB); if (!msg1 && !msg2) return; nl1 = Len(msg1); nl2 = Len(msg2); if (nl1 != l1 || nl2 != l2) /* To prevent infinite loops */ cut_apart_helpmsgs(d, msg1, msg2, len, 0); #else int first = 1; while (msg1 && *msg1) { msg1 = do_ugly_things(d, msg1, len * 2 - 1, first); nl1 = Len(msg1); if (nl1 == l1) break; l1 = nl1; first = 0; } while (msg2 && *msg2) { msg2 = do_ugly_things(d, msg2, len * 2 - TAB, 0 - TAB); nl2 = Len(msg2); if (nl2 == l2) break; l2 = nl2; } #endif } static void DoSpecialObjectHelp(dbref player, char *type, int id, int loc, int powerneeded, int objid, char *arg) { int i, j; MECH *mech = NULL; int pos[100][2]; int count = 0, csho = 0; coolmenu *c = NULL; char buf[LBUF_SIZE]; char *d; int dc; if (id == GTYPE_MECH) mech = getMech(loc); bzero(pos, sizeof(pos)); for (i = 0; SpecialObjects[id].commands[i].name; i++) { if (!SpecialObjects[id].commands[i].func && (SpecialObjects[id].commands[i].helpmsg[0] != '@' || Have_MechPower(Owner(player), powerneeded))) if (id != GTYPE_MECH || Can_Use_Command(mech, SpecialObjects[id].commands[i].flag)) { if (count) pos[count - 1][1] = i - pos[count - 1][0]; pos[count][0] = i; count++; } } if (count) pos[count - 1][1] = i - pos[count - 1][0]; else { pos[0][0] = 0; pos[0][1] = i; count = 1; } sim(NULL, CM_ONE | CM_LINE); if (!arg || !*arg) { #define HELPMSG(a) \ &SpecialObjects[id].commands[a].helpmsg[SpecialObjects[id].commands[a].helpmsg[0]=='@'] for (i = 0; i < count; i++) { if (count > 1) { d = center_string(HELPMSG(pos[i][0]), 70); sim(tprintf("%s%s%s", "%cg", d, "%c"), CM_ONE); } else sim(tprintf("%s command listing: ", type), CM_ONE | CM_CENTER); for (j = pos[i][0] + (count == 1 ? 0 : 1); j < pos[i][0] + pos[i][1]; j++) if (SpecialObjects[id].commands[j].helpmsg[0] != '@' || Have_MechPower(Owner(player), powerneeded)) if (id != GTYPE_MECH || Can_Use_Command(mech, SpecialObjects[id].commands[j].flag)) { strcpy(buf, SpecialObjects[id].commands[j].name); d = buf; while (*d && *d != ' ') d++; if (*d == ' ') *d = 0; sim(buf, CM_FOUR); csho++; } } if (!csho) vsi(tprintf ("There are no commands you are authorized to use here.")); else { sim(NULL, CM_ONE | CM_LINE); if (count > 1) vsi("Additional info available with 'HELP SUBTOPIC'"); else vsi("Additional info available with 'HELP ALL'"); } } else { /* Try to find matching subtopic, or ALL */ if (!strcasecmp(arg, "all")) { if (count > 1) { vsi("ALL not available for objects with subcategories."); dc = -2; } else dc = -1; } else { if (count == 1) { vsi("This object doesn't have any other detailed help than 'HELP ALL'"); dc = -2; } else { for (i = 0; i < count; i++) if (!strcasecmp(arg, HELPMSG(pos[i][0]))) break; if (i == count) { vsi("Subcategory not found."); dc = -2; } else dc = i; } } if (dc > -2) { for (i = 0; i < count; i++) if (dc == -1 || i == dc) { if (count > 1) vsi(tprintf("%s%s%s", "%cg", center_string(HELPMSG(pos[i][0]), 70), "%c")); for (j = pos[i][0] + (count == 1 ? 0 : 1); j < pos[i][0] + pos[i][1]; j++) if (SpecialObjects[id].commands[j].helpmsg[0] != '@' || Have_MechPower(Owner(player), powerneeded)) if (id != GTYPE_MECH || Can_Use_Command(mech, SpecialObjects[id].commands[j].flag)) cut_apart_helpmsgs(&c, SpecialObjects[id].commands[j].name, HELPMSG(j), 37, 1); } } } sim(NULL, CM_ONE | CM_LINE); ShowCoolMenu(player, c); KillCoolMenu(c); } void InitSpecialHash(int which) { char *tmp, *tmpc; int i; char buf[MBUF_SIZE]; hashinit(&SpecialCommandHash[which], 20 * HASH_FACTOR); for (i = 0; (tmp = SpecialObjects[which].commands[i].name); i++) { if (!SpecialObjects[which].commands[i].func) continue; tmpc = buf; for (; *tmp && *tmp != ' '; tmp++) *(tmpc++) = ToLower(*tmp); *tmpc = 0; if ((tmpc = strstr(buf, " "))) *tmpc = 0; hashadd(buf, (int *) &SpecialObjects[which].commands[i], &SpecialCommandHash[which]); } } void handle_xcode(dbref player, dbref obj, int from, int to) { if (from == to) return; if (!to) { s_Hardcode(obj); DisposeSpecialObject(player, obj); c_Hardcode(obj); } else CreateNewSpecialObject(player, obj); } #define DEFAULT 0 /* Normal */ #define ANSI_START "\033[" #define ANSI_START_LEN 2 #define ANSI_END "m" #define ANSI_END_LEN 1 struct color_entry { int bit; int negbit; char ltr; char *string; char *sstring; } color_table[] = { { 0x0008, 7, 'n', ANSI_NORMAL, NULL}, { 0x0001, 0, 'h', ANSI_HILITE, NULL}, { 0x0002, 0, 'i', ANSI_INVERSE, NULL}, { 0x0004, 0, 'f', ANSI_BLINK, NULL}, { 0x0010, 0, 'x', ANSI_BLACK, NULL}, { 0x0010, 0x10, 'l', ANSI_BLACK, NULL}, { 0x0020, 0, 'r', ANSI_RED, NULL}, { 0x0040, 0, 'g', ANSI_GREEN, NULL}, { 0x0080, 0, 'y', ANSI_YELLOW, NULL}, { 0x0100, 0, 'b', ANSI_BLUE, NULL}, { 0x0200, 0, 'm', ANSI_MAGENTA, NULL}, { 0x0400, 0, 'c', ANSI_CYAN, NULL}, { 0x0800, 0, 'w', ANSI_WHITE, NULL}, { 0, 0, 0, NULL, NULL} }; #define CHARS 256 char colorc_reverse[CHARS]; void initialize_colorize() { int i; char buf[20]; char *c; c = buf + ANSI_START_LEN; for (i = 0; i < CHARS; i++) colorc_reverse[i] = DEFAULT; for (i = 0; color_table[i].string; i++) { colorc_reverse[(short) color_table[i].ltr] = i; strcpy(buf, color_table[i].string); buf[strlen(buf) - ANSI_END_LEN] = 0; color_table[i].sstring = strdup(c); } } #undef notify char *colorize(dbref player, char *from) { char *to; char *p, *q; int color_wanted = 0; int i; int cnt; q = to = alloc_lbuf("colorize"); #if 1 for (p = from; *p; p++) { if (*p == '%' && *(p + 1) == 'c') { p += 2; if (*p <= 0) i = DEFAULT; else i = colorc_reverse[(short) *p]; if (i == DEFAULT && *p != 'n') p--; color_wanted &= ~color_table[i].negbit; color_wanted |= color_table[i].bit; } else { if (color_wanted && Ansi(player)) { *q = 0; /* Generate efficient color string */ strcpy(q, ANSI_START); q += ANSI_START_LEN; cnt = 0; for (i = 0; color_table[i].string; i++) if (color_wanted & color_table[i].bit && color_table[i].bit != color_table[i].negbit) { if (cnt) *q++ = ';'; strcpy(q, color_table[i].sstring); q += strlen(color_table[i].sstring); cnt++; } strcpy(q, ANSI_END); q += ANSI_END_LEN; color_wanted = 0; } *q++ = *p; } } *q = 0; if (color_wanted && Ansi(player)) { /* Generate efficient color string */ strcpy(q, ANSI_START); q += ANSI_START_LEN; cnt = 0; for (i = 0; color_table[i].string; i++) if (color_wanted & color_table[i].bit && color_table[i].bit != color_table[i].negbit) { if (cnt) *q++ = ';'; strcpy(q, color_table[i].sstring); q += strlen(color_table[i].sstring); cnt++; } strcpy(q, ANSI_END); q += ANSI_END_LEN; color_wanted = 0; } #else strcpy(to, p); #endif return to; } void mecha_notify(dbref player, char *msg) { char *tmp; tmp = colorize(player, msg); raw_notify(player, tmp); free_lbuf(tmp); } void mecha_notify_except(dbref loc, dbref player, dbref exception, char *msg) { dbref first; if (loc != exception) notify_checked(loc, player, msg, (MSG_ME_ALL | MSG_F_UP | MSG_S_INSIDE | MSG_NBR_EXITS_A | MSG_COLORIZE)); DOLIST(first, Contents(loc)) { if (first != exception) { notify_checked(first, player, msg, (MSG_ME | MSG_F_DOWN | MSG_S_OUTSIDE | MSG_COLORIZE)); } } } void list_chashstats(dbref player) { int i; for (i = 0; i < NUM_SPECIAL_OBJECTS; i++) list_hashstat(player, tprintf("HCCmd:%s", SpecialObjects[i].type), &SpecialCommandHash[i]); #ifdef BT_ENABLED list_phashstats(player); #endif } /* Basically, finish all the repairs etc in one fell swoop. That's the best we can do for now, I'm afraid. */ void ResetSpecialObjects() { #if 0 /* Nowadays no longer neccessary, see mech.tech.saverepair.c */ int i; for (i = FIRST_TECH_EVENT; i <= LAST_TECH_EVENT; i++) while (muxevent_run_by_type(i)); #endif muxevent_run_by_type(EVENT_HIDE); muxevent_run_by_type(EVENT_BLINDREC); } MAP *getMap(dbref d) { Node *tmp; if (!(tmp = FindObjectsNode(d))) return NULL; if (NodeType(tmp) != GTYPE_MAP) return NULL; return (MAP *) NodeData(tmp); } MECH *getMech(dbref d) { Node *tmp; if (d < 0) return NULL; if (!(tmp = FindObjectsNode(d))) return NULL; if (NodeType(tmp) != GTYPE_MECH) return NULL; return (MECH *) NodeData(tmp); }