/** A generic comparer routine to compare two values of any sort type. * \param player Player doing the comparison * \param a Key 1 to compare * \param b Key 2 to compare * \param sort_type SortType describing what kind of comparison to make. */ int gencomp(dbref player, char *a, char *b, SortType sort_type) { char *ptr; int i, len; int result; s_rec s1, s2; ListTypeInfo *lti; ptr = NULL; if (!sort_type) { /* Advance i to the default */ for (i = 0; ltypelist[i].name; i++) ; } else if ((ptr = strchr(sort_type, ':'))) { len = ptr - sort_type; ptr += 1; if (!*ptr) ptr = NULL; for (i = 0; ltypelist[i].name && strncasecmp(ltypelist[i].name, sort_type, len); i++) ; } else { for (i = 0; ltypelist[i].name && strcasecmp(ltypelist[i].name, sort_type); i++) ; } lti = get_list_type_info(sort_type); if (ltypelist[i].flags & IS_DB) { s1.db = parse_objid(a); s2.db = parse_objid(b); if (!RealGoodObject(s1.db)) s1.db = NOTHING; if (!RealGoodObject(s2.db)) s2.db = NOTHING; } else { s1.db = s2.db = 0; } s1.val = a; s2.val = b; genrecord(&s1, player, lti); genrecord(&s2, player, lti); result = lti->sorter((const void *) &s1, (const void *) &s2); if (lti->flags & IS_STRING) { if (s1.memo.str.freestr) mush_free(s1.memo.str.s, "genrecord"); if (s2.memo.str.freestr) mush_free(s2.memo.str.s, "genrecord"); } free_list_type_info(lti); return result; }
/* spawn a single drone */ void hs_spawn(dbref player, char *which) { dbref obj; hship *ship; obj = match_result(player, which, TYPE_THING, MAT_NEAR_THINGS); if (!RealGoodObject(obj)) { notify(player, "HSPACE: Unable to find that drone template."); return; } if (!IsDrone(obj)) { notify(player, "HSPACE: That is not a valid drone template."); return; } ship = create_drone(obj); if (!ship) { notify(player, "HSPACE: Failed to create the drone."); return; } notify_format(player, "HSPACE: Drone created at %s(#%d) %.0f %.0f %.0f.", Name(ship->uid->objnum), ship->uid->objnum, ship->x, ship->y, ship->z); return; }
/** * Given a player dbref (For use with viewing permissions for attrs, etc), * list of keys, list of strings it maps to (sortkey()-style), * # of keys+strings and a list type info, build an array of * s_rec structures representing each item. * \param player the player executing the sort. * \param keys the array of items to sort. * \param strs If non-NULL, these are what to sort <keys> using. * \param n Number of items in <keys> and <strs> * \param lti List Type Info describing how it's sorted and built. * \retval A pointer to the first s_rec of an <n> s_rec array. */ s_rec * slist_build(dbref player, char *keys[], char *strs[], int n, ListTypeInfo * lti) { int i; s_rec *sp; sort_order = lti->sort_order; sp = mush_calloc(n, sizeof(s_rec), "do_gensort"); for (i = 0; i < n; i++) { /* Elements are 0 by default thanks to calloc. Only need to touch those that need other values. */ sp[i].val = keys[i]; if (strs) sp[i].ptr = strs[i]; if (lti->flags & IS_DB) { sp[i].db = parse_objid(keys[i]); if (!RealGoodObject(sp[i].db)) sp[i].db = NOTHING; } genrecord(&sp[i], player, lti); } return sp; }
/* board a ship through the ship object */ void board_ship(dbref player, char *which, char *code) { ATTR *a; char *bcode; dbref obj, nav, bay; int security; /* find the shipobj */ obj = match_result(player, which, TYPE_THING, MAT_NEAR_THINGS); if (!IsShipObj(obj)) { notify(player, "Can't find that ship."); return; } /* see if it's got an HSNAV */ nav = atr_parse_dbref(obj, "HSNAV"); if (!IsShip(nav)) { notify(player, "That is not a valid ship object."); return; } /* check the boarding code, if necessary */ security = atr_parse_integer(nav, "SECURITY", 0); if (security) { a = atr_get(nav, "BOARDING_CODE"); if (a) { bcode = atr_value(a); if (strcmp(bcode, code)) { notify(player, "Invalid boarding code."); return; } } } /* check for a BAY on the nav, otherwise go to the nav's location */ bay = atr_parse_dbref(nav, "BAY"); if (!RealGoodObject(bay)) { bay = Location(nav); } atr_add(player, "HSPACE", unparse_dbref(nav), hs_options.space_wiz, 0); notify_except(obj, Location(player), player, tprintf("%s boards the %s.", Name(player), Name(obj)), 0); notify_except(obj, bay, player, tprintf("%s boards through the main hatch.", Name(player)), 0); moveto(player, bay, hs_options.space_wiz, NULL); }
/** This is the place where speech, poses, and \@emits by thing should be * heard. For things and players, it's the loc; for rooms, it's the room * itself; for exits, it's the source. */ dbref speech_loc(dbref thing) { if (!RealGoodObject(thing)) return NOTHING; switch (Typeof(thing)) { case TYPE_ROOM: return thing; case TYPE_EXIT: return Source(thing); default: return Location(thing); } }
/** Parse a softcode timezone request. * * \verbatim * * If arg is a objid, look up that object's @TZ attribute and parse * that. Otherwise, parse arg. * * If an object doesn't have a @TZ set, offset is set to 0 and tznotset to 1, to be able to tell * that case apart from a UTC timezone. * * If a timezone database is present, try to read the given zone from * it. Integers are treated as 'Etc/GMT[+-]N' first. * * If no tzinfo database, or reading the given zone from one fails, * and the arg is an integer, treat it as the number of hours * difference from GMT. Otherwise fail. * * \endverbatim * * \param arg The string to parse for a dbref, number or symbolic tz name * \param when When to calculate the offset for. * \param res Structure to store the parsed results in. * \return 1 for success, 0 for failure in parsing the time zone. */ bool parse_timezone_arg(const char *arg, time_t when, struct tz_result *res) { if (!res) return 0; memset(res, 0, sizeof *res); res->tz_when = when; if (strcasecmp(arg, "UTC") == 0) { res->tz_utc = 1; return 1; } else if (is_objid(arg)) { ATTR *a; dbref thing = parse_objid(arg); if (!RealGoodObject(thing)) return 0; a = atr_get(thing, "TZ"); if (!a) { /* No timezone attribute isn't an error. Just use the server's zone. */ res->tz_attr_missing = 1; return 1; } arg = atr_value(a); } #ifdef HAVE_ZONEINFO { struct tzinfo *tz = NULL; static char tz_path[BUFFER_LEN]; if (is_valid_tzname(arg)) { tz = read_tzfile(arg); snprintf(tz_path, sizeof tz_path, ":%s", arg); } else if (is_strict_integer(arg)) { int offset; char tzname[100]; offset = parse_integer(arg); /* GMT-8 is 8 hours ahead, GMT+8 is 8 hours behind, which makes no sense to me. */ offset = -offset; snprintf(tzname, sizeof tzname, "Etc/GMT%+d", offset); tz = read_tzfile(tzname); snprintf(tz_path, sizeof tz_path, ":%s", tzname); } if (tz) { res->tz_offset = offset_for_tzinfo(tz, when); free_tzinfo(tz); res->tz_name = tz_path; res->tz_has_file = 1; return 1; } /* Fall through to gross numeric offset on failure */ } #endif if (is_strict_number(arg)) { double n = parse_number(arg); if (fabs(n) >= 24.0) return 0; res->tz_offset = floor(n * 3600.0); return 1; } return 0; }
void hs_move(dbref executor, char *arg_left, char *arg_right) { huniverse *uid; hcelestial *cel; hship *dship; hship *ship; int i, dx, dy, dz; dbref obj; dbref udb, ndb; char *r, *s; int len; dbref bot, top; obj = match_result(executor, arg_left, TYPE_THING, MAT_EVERYTHING); if (!IsShip(obj) && !IsCelestial(obj) && !IsConsole(obj)) { notify(executor, "HSPACE: Unable to move that object."); return; } s = arg_right; r = split_token(&s, '/'); if (!r || !*r) { notify(executor, "HSPACE: No destination specified."); return; } len = strlen(r); ndb = match_result(executor, r, TYPE_THING, MAT_EVERYTHING); if (!RealGoodObject(ndb)) { ndb = parse_dbref(r); } if (!RealGoodObject(ndb)) { bot = 0; top = db_top; } else { bot = ndb; top = bot + 1; } uid = NULL; /* cycle through the db and try to match a space object */ for (udb = bot; udb < top; udb++) { if (strncasecmp(Name(udb), r, len) && udb != ndb) continue; if (IsUniverse(udb)) { uid = find_universe(udb); } else if (IsCelestial(udb)) { cel = find_celestial(udb); if (cel) { uid = cel->uid; dx = cel->x; dy = cel->y; dz = cel->z; } } else if (IsShip(udb) || IsShipObj(udb)) { dship = find_ship(udb); if (dship) { dx = dship->x; dy = dship->y; dz = dship->z; uid = dship->uid; } } else { /* false positive */ continue; } break; } if (!uid) { notify(executor, "HSPACE: Unable to locate destination."); return; } if (s) { r = split_token(&s, ' '); if (r) { dx = parse_integer(r); r = split_token(&s, ' '); if (!r || !*r) { dy = 0; dz = 0; } else { dy = parse_integer(r); r = split_token(&s, ' '); if (!r || !*r) dz = 0; else dz = parse_integer(r); } } else { /* all blanks */ dx = 0; dy = 0; dz = 0; } } if (IsShip(obj) || IsConsole(obj)) { ship = find_ship(obj); move_ship(ship, uid, dx, dy, dz); } else if (IsCelestial(obj)) { cel = find_celestial(obj); move_celestial(cel, uid, dx, dy, dz); } notify(executor, "HSPACE: Moved."); }
/* list various hspace objects */ void hs_list(dbref executor, char *arg_left, char *arg_right) { huniverse *uid; hcelestial *cel; hship *ship; int i; dbref obj = NOTHING; /* list various informations */ if (!arg_left || !*arg_left) { notify(executor, "HSPACE: You must specify one of: configuration, universes, celestials, ships"); /* list configuration info */ } else if (!strncasecmp("CONFIGURATION", arg_left, strlen(arg_left))) { hs_print_config(executor, arg_right); /* list universe details */ } else if (!strncasecmp("UNIVERSES", arg_left, strlen(arg_left))) { notify(executor, "HSPACE: Listing universes..."); for (i = 0; i < hs_num_universes; i++) { uid = &hs_universes[i]; notify_format(executor, "%-3d: %s(#%d) %d celestials, %d ships, %d drones", i, Name(uid->objnum), uid->objnum, uid->num_celestials, uid->num_ships, uid->num_drones); } /* list celestial details */ } else if (!strncasecmp("CELESTIALS", arg_left, strlen(arg_left))) { notify(executor, "HSPACE: Listing celestials..."); for (i = 0; i < hs_num_celestials; i++) { cel = &hs_celestials[i]; if (cel->uid) { notify_format(executor, "%-3d: %s(#%d) %d flags, [%s(#%d)] %.0f,%.0f,%.0f", i, Name(cel->objnum), cel->objnum, cel->type, Name(cel->uid->objnum), cel->uid->objnum, cel->x, cel->y, cel->z); } else notify(executor, "HSPACE: Error! Invalid universe."); } /* list ship details */ } else if (!strncasecmp("SHIPS", arg_left, strlen(arg_left))) { notify(executor, "HSPACE: Listing ships..."); for (i = 0; i < hs_num_ships; i++) { ship = &hs_ships[i]; if (ship->uid) obj = ship->uid->objnum; else if (ship->landed) obj = ship->landed->objnum; else if (ship->docked) obj = atr_parse_dbref(ship->docked->objnum, "SHIPOBJ"); notify_format(executor, "%-3d: %s(#%d) [%s(#%d)] (%9.0f %9.0f %9.0f) %.0fm%.0f (%.0fm%.0f) @ %.0f (%.0f) Mm/s", i, ship_name(ship), ship->objnum, RealGoodObject(obj) ? Name(obj) : "*Unknown*", obj, ship->x, ship->y, ship->z, ship->xyhead, ship->zhead, ship->desired_xyhead, ship->desired_zhead, ship->speed, ship->desired_speed); } } return; }
/* leave a flying ship through the escape pod */ void emergency_eject(dbref player) { dbref nav, pad; hship *ship; hcelestial *cel, *min_cel; ATTR *a; char *r, *s; char buff[512]; double dist, min_dist; dbref min_pad; hship *sptr, *min_ship; /* check for a BAY */ a = atr_get(Location(player), "BAY"); if (!a) { /* no BAY, see if we're next to the nav console */ ship = find_ship(player); if (ship) { if (Location(ship->objnum) != Location(player)) { notify(player, "You can't eject from here."); return; } } } else { /* there's a BAY, see if the ship is valid */ nav = parse_dbref(atr_value(a)); if (!IsShip(nav)) { notify(player, "You can't eject from here."); return; } ship = find_ship_by_nav(nav); } if (!ship) { notify(player, "You can't eject from here."); return; } /* only eject when flying, not when landing or docking */ if (!ship->uid || ship->landed || ship->docked) { notify(player, "You may only eject while flying."); return; } /* find a planet with a drop pad */ min_pad = NOTHING; min_dist = 1000000.0; min_cel = NULL; for (cel = ship->uid->head_celestial; cel; cel = cel->next) { if (!HasFlag(cel->type, HS_PLANET)) continue; pad = atr_parse_dbref(cel->objnum, "DROPPADS"); if (!RealGoodObject(pad)) continue; dist = ship_celestial_distance(ship, cel); if (dist < min_dist) { min_dist = dist; min_pad = pad; min_cel = cel; } } min_ship = NULL; for (sptr = ship->uid->head_ship; sptr; sptr = sptr->next) { if (min_cel) break; if (!HasFlag(sptr->type, HS_STATION | HS_CAPITAL)) continue; pad = atr_parse_dbref(sptr->objnum, "BAY"); if (!RealGoodObject(pad)) continue; dist = ship_distance(ship, sptr); if (dist < min_dist) { min_cel = NULL; min_ship = sptr; min_dist = dist; min_pad = pad; } } if (!RealGoodObject(min_pad)) { notify(player, "There is nowhere to eject to!"); return; } /* finish up by setting HSPACE and notifying everybody of the move */ if (min_ship) { atr_add(player, "HSPACE", unparse_dbref(min_ship->objnum), hs_options.space_wiz, 0); } else if (min_cel) { atr_add(player, "HSPACE", unparse_dbref(min_cel->objnum), hs_options.space_wiz, 0); } else { SPACEWALL("Weird problem in eject."); notify(player, "Bad space object. Contact an administrator."); return; } notify_except(Location(player), Location(player), player, tprintf("%s ejects in an emergency escape pod!", Name(player)), 0); notify_except(min_pad, min_pad, player, tprintf("%s crash lands in an emergency escape pod!", Name(player)), 0); if (min_ship) { notify_consoles(min_ship, tprintf("%s%s-%s Emergency ejection pod automatically tractored into the docking back.", ANSI_HILITE, ANSI_GREEN, ANSI_NORMAL)); } moveto(player, min_pad, hs_options.space_wiz, NULL); }
/* leave a landed/docked ship through the hatch */ void disembark(dbref player) { dbref nav, obj, newobj; hship *ship; ATTR *a; int security; /* check if we can disembark from here */ a = atr_get(Location(player), "BAY"); if (!a) { /* no BAY, check if we're near the nav console */ ship = find_ship(player); if (ship) { if (Location(ship->objnum) != Location(player)) { notify(player, "You can't disembark from here."); return; } } } else { /* there's a BAY here, make sure it's a good one */ nav = parse_dbref(atr_value(a)); if (!IsShip(nav)) { notify(player, "You can't disembark from here."); return; } ship = find_ship_by_nav(nav); } if (!ship) { notify(player, "You can't disembark from here."); return; } /* no ditching in space, or early after launching, or prematurely when landing */ if ((ship->uid || ship->landing || ship->launching) && !ship->linked) { notify(player, "You can't disembark while in space."); return; } obj = atr_parse_dbref(ship->objnum, "SHIPOBJ"); if (!RealGoodObject(obj)) { notify(player, "This ship can not be disembarked."); return; } /* check whether we're docking or landing, save the new space object */ if (ship->landed) { newobj = ship->landed->objnum; } else if (ship->docked) { newobj = ship->docked->objnum; } else if (ship->linked) { newobj = ship->linked->objnum; } else { notify(player, "You can't disembark while in space."); return; } if (ship->linked) { /* check the boarding code, if necessary */ security = atr_parse_integer(ship->linked->objnum, "SECURITY", 0); if (security) { notify(player, "Unable to use boarding link while the other ship has security enabled."); return; } security = atr_parse_integer(ship->objnum, "SECURITY", 0); if (security) { notify(player, "Unable to use boarding link while security is enabled."); return; } obj = atr_parse_dbref(ship->linked->objnum, "BAY"); if (!RealGoodObject(obj)) obj = Location(ship->linked->objnum); moveto(player, obj, hs_options.space_wiz, NULL); } else { moveto(player, Location(obj), hs_options.space_wiz, NULL); } /* finish up by setting HSPACE attribute and notifying everybody about the move */ atr_add(player, "HSPACE", unparse_dbref(newobj), hs_options.space_wiz, 0); notify_except(obj, Location(player), player, tprintf("%s disembarks through the main hatch.", Name(player)), 0); notify_except(obj, Location(obj), player, tprintf("%s disembarks from the %s.", Name(player), Name(obj)), 0); return; }
/* send a standard radio communication */ void send_com(dbref from, char *arg_left, char *arg_right) { dbref com, obj; hship *ship; hcelestial *cel; huniverse *uid; double xmit, rcv; char contact[32]; char *r, *s; char buff[128]; ATTR *a; double sx, sy, sz, tx, ty, tz, dist; char pre[128]; char *mesg; int sent_to_from, send_to_com; if (!IsComm(from)) { notify(from, "You do not have the HS_COMM flag."); return; } uid = NULL; obj = atr_parse_dbref(from, "HSPACE"); if (!RealGoodObject(obj)) { notify(from, "You do not have a valid space id. Board, disembark, eject, or man a console."); return; } if (IsShip(obj)) { ship = find_ship_by_nav(obj); if (!ship) { notify(from, "Your space id is not a valid ship."); return; } if (ship->uid) { sx = ship->x; sy = ship->y; sz = ship->z; uid = ship->uid; } else if (ship->landed) { sx = ship->landed->x; sy = ship->landed->y; sz = ship->landed->z; uid = ship->landed->uid; } else if (ship->docked) { sx = ship->docked->x; sy = ship->docked->y; sz = ship->docked->z; uid = ship->docked->uid; } strncpy(contact, ship_name(ship), 10); } else if (IsCelestial(obj)) { cel = find_celestial(obj); if (!cel) { notify(from, "Your space id is not a valid celestial."); return; } sx = cel->x; sy = cel->y; sz = cel->z; uid = cel->uid; strncpy(contact, celestial_name(cel), 10); } contact[10] = '\0'; if (!uid) { notify(from, "Your space id does not have a valid uid."); return; } if (arg_left && arg_right && *arg_right) { xmit = strtod(arg_left, &s); if (s && *s) { return; } mesg = arg_right; } else { xmit = atr_parse_double(from, "TRANSMIT", 0.0); mesg = arg_left; } if (xmit < 100.0 || xmit > 999.9) { notify(from, "Transmission frequency must be between 100 and 999 MHz."); return; } a = atr_get(from, "CALLSIGN"); if (!a) { snprintf(pre, 127, "%s%s[%s%5.1f MHz%s%s]-[%s%-10s%s]-[%s ", ANSI_HILITE, ANSI_BLUE, ANSI_NORMAL, xmit, ANSI_HILITE, ANSI_BLUE, ANSI_GREEN, contact, ANSI_BLUE, ANSI_NORMAL); } else { snprintf(pre, 127, "%s%s[%s%5.1f MHz%s%s]-[%s%-10s%s]-[%s %s<%s%s%s>%s ", ANSI_HILITE, ANSI_BLUE, ANSI_NORMAL, xmit, ANSI_HILITE, ANSI_BLUE, ANSI_GREEN, contact, ANSI_BLUE, ANSI_NORMAL, ANSI_CYAN, ANSI_NORMAL, atr_value(a), ANSI_CYAN, ANSI_NORMAL); } /* go through the comm list and check each one */ sent_to_from = 0; for (com = 0; com < db_top; com++) { if (!IsComm(com)) continue; /* check if the user is in the same uid */ obj = atr_parse_dbref(com, "HSPACE"); if (IsShip(obj)) { ship = find_ship_by_nav(obj); if (!ship) continue; if (ship->uid && ship->uid != uid) continue; else if (ship->landed && ship->landed->uid != uid) continue; else if (ship->docked && ship->docked->uid != uid) continue; if (ship->uid) { tx = ship->x; ty = ship->y; tz = ship->z; } else if (ship->landed) { tx = ship->landed->x; ty = ship->landed->y; tz = ship->landed->z; } else if (ship->docked) { tx = ship->docked->x; ty = ship->docked->y; tz = ship->docked->z; } } else if (IsCelestial(obj)) { cel = find_celestial(obj); if (!cel) continue; if (cel->uid != uid) continue; tx = cel->x; ty = cel->y; tz = cel->z; } else { continue; } dist = dist3d(sx, sy, sz, tx, ty, tz) / hs_options.max_comm_dist; if (dist > 1.0) continue; a = atr_get(com, "FREQUENCY"); if (!a) continue; /* check all frequencies to see if we need to send to this com */ send_to_com = 0; snprintf(buff, 127, atr_value(a)); s = buff; while (s) { r = split_token(&s, ' '); rcv = parse_number(r); /* check to see if we're on the right frequency */ if (fabs(rcv - xmit) < 0.1) { send_to_com = 1; break; } } if (send_to_com) { if (com == from) sent_to_from = 1; notify_format(com, "%s%s%s%s]%s", pre, decay_msg(mesg, dist), ANSI_HILITE, ANSI_BLUE, ANSI_NORMAL); } } if (!sent_to_from) { notify_format(from, "You send \"%s\" on frequency %5.1f.", mesg, xmit); } }