Exemple #1
0
/** 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;
}
Exemple #2
0
/* 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;
}
Exemple #3
0
/**
 * 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;
}
Exemple #4
0
/* 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);
}
Exemple #5
0
/** 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);
  }
}
Exemple #6
0
/** 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;
}
Exemple #7
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.");
}
Exemple #8
0
/* 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;
}
Exemple #9
0
/* 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);
}
Exemple #10
0
/* 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;
}
Exemple #11
0
/* 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);
  }
}