Ejemplo n.º 1
0
int
sona(void)
{
    struct nstr_item ni, nit;
    struct sctstr sect;
    struct shpstr ship;
    struct shpstr targ;
    struct natstr *natp;
    struct mchrstr *mcp;
    struct mchrstr *tmcp;
    struct nstr_sect ns;
    int range;
    int visib, pingrange;
    int srange;
    int vrange;
    int dist;
    int x, y;
    int cx, cy;
    int changed = 0;
    int row;
    /* Where these are used are non-re-entrant, so we keep 'em around */
    static char **rad = NULL;
    static char *radbuf = NULL;
    static signed char **vis = NULL;
    static signed char *visbuf = NULL;

    if (!snxtitem(&ni, EF_SHIP, player->argp[1], NULL))
	return RET_SYN;
    if (!radbuf)
	radbuf = malloc(WORLD_Y * MAPWIDTH(1));
    if (!visbuf)
	visbuf = malloc(WORLD_Y * MAPWIDTH(1));
    if (!rad && radbuf) {
	rad = malloc(WORLD_Y * sizeof(char *));
	if (rad) {
	    for (x = 0; x < WORLD_Y; x++) {
		rad[x] = &radbuf[(WORLD_X + 1) * x];
	    }
	}
    }
    if (!vis && visbuf) {
	vis = malloc(WORLD_Y * sizeof(signed char *));
	if (vis) {
	    for (x = 0; x < WORLD_Y; x++) {
		vis[x] = &visbuf[(WORLD_X + 1) * x];
	    }
	}
    }
    if (!radbuf || !visbuf || !rad || !vis) {
	pr("Memory error, tell the deity.\n");
	logerror("malloc failed in sona\n");
	return RET_FAIL;
    }
    while (nxtitem(&ni, &ship)) {
	if (!player->owner)
	    continue;
	mcp = &mchr[(int)ship.shp_type];
	if (!(mcp->m_flags & M_SONAR))
	    continue;
	getsect(ship.shp_x, ship.shp_y, &sect);
	if (sect.sct_type != SCT_WATER)
	    continue;
	range = (int)techfact(ship.shp_tech, mcp->m_vrnge);
	srange = MIN(7, 7 * range * ship.shp_effic / 200);
	pr("%s at %s efficiency %d%%, max range %d\n",
	   prship(&ship),
	   xyas(ship.shp_x, ship.shp_y, player->cnum),
	   ship.shp_effic, srange);
	snxtsct_dist(&ns, ship.shp_x, ship.shp_y, srange);
	blankfill(radbuf, &ns.range, 1);
	while (nxtsct(&ns, &sect)) {
	    if (player->owner || sect.sct_type == SCT_WATER)
		rad[ns.dy][ns.dx] = dchr[sect.sct_type].d_mnem;
	    else {
		rad[ns.dy][ns.dx] = '?';
	    }
	}
	snxtsct_dist(&ns, ship.shp_x, ship.shp_y, srange);
	cx = deltx(&ns.range, ship.shp_x);
	cy = delty(&ns.range, ship.shp_y);
	while (nxtsct(&ns, &sect)) {
	    if (!line_of_sight(rad, cx, cy, ns.dx, ns.dy)) {
		rad[ns.dy][ns.dx] = ' ';
		continue;
	    }
	    if (ship.shp_tech >= 310 && sect.sct_type == SCT_WATER) {
		if (sect.sct_mines) {
		    pr("Sonar detects %d mines in %s!\n",
		       sect.sct_mines,
		       xyas(sect.sct_x, sect.sct_y, player->cnum));
		    rad[ns.dy][ns.dx] = 'X';
		}
	    }
	    changed |= map_set(player->cnum, sect.sct_x, sect.sct_y,
			       rad[ns.dy][ns.dx], 0);

	}
	memset(visbuf, 0, (WORLD_Y * (WORLD_X + 1)));
	snxtitem_dist(&nit, EF_SHIP, ship.shp_x, ship.shp_y, range);
	while (nxtitem(&nit, &targ)) {
	    if (targ.shp_own == player->cnum || targ.shp_own == 0)
		continue;
	    tmcp = &mchr[(int)targ.shp_type];
	    visib = shp_visib(&targ);
	    pingrange = MIN(7, MAX(visib, 10) * range / 10);
	    vrange = pingrange * ship.shp_effic / 200;
	    dist = mapdist(targ.shp_x, targ.shp_y, ship.shp_x, ship.shp_y);
	    pingrange = (MAX(pingrange, 2) * targ.shp_effic) / 100;
	    if (dist > pingrange)
		continue;
	    if (tmcp->m_flags & M_SONAR && targ.shp_own) {
		natp = getnatp(targ.shp_own);
		if (natp->nat_flags & NF_SONAR)
		    wu(0, targ.shp_own,
		       "Sonar ping from %s detected by %s!\n",
		       xyas(ship.shp_x, ship.shp_y,
			    targ.shp_own), prship(&targ));
		if (targ.shp_rflags & RET_SONARED)
		    retreat_ship(&targ, targ.shp_own, 's');
	    }
	    if (dist > vrange)
		continue;
	    x = deltx(&ns.range, (int)targ.shp_x);
	    y = delty(&ns.range, (int)targ.shp_y);
	    if (rad[y][x] != dchr[SCT_WATER].d_mnem && rad[y][x] != 'X')
		continue;
	    if (tmcp->m_flags & M_SUB &&
		relations_with(targ.shp_own, player->cnum) < FRIENDLY) {
		if (mcp->m_vrnge + visib < 8)
		    pr("Sonar detects sub #%d @ %s\n",
		       targ.shp_uid,
		       xyas(targ.shp_x, targ.shp_y, player->cnum));
		else if (mcp->m_vrnge + visib < 10)
		    pr("Sonar detects %s @ %s\n",
		       prship(&targ),
		       xyas(targ.shp_x, targ.shp_y, player->cnum));
		else
		    pr("Sonar detects %s %s @ %s\n",
		       cname(targ.shp_own), prship(&targ),
		       xyas(targ.shp_x, targ.shp_y, player->cnum));
	    } else
		pr("Sonar detects %s %s @ %s\n",
		   cname(targ.shp_own), prship(&targ),
		   xyas(targ.shp_x, targ.shp_y, player->cnum));

	    if (visib > vis[y][x]) {
		vis[y][x] = visib;
		/* &~0x20 makes it a cap letter */
		rad[y][x] = (*mchr[(int)targ.shp_type].m_name) & ~0x20;
	    }
	}
	if (!player->argp[2]) {
	    rad[cy][cx] = '0';
	    for (row = 0; row < ns.range.height; row++)
		if (!blankrow(rad[row]))
		    pr("%s\n", rad[row]);
	}
	pr("\n");

    }
    if (changed)
	writemap(player->cnum);
    return RET_OK;
}
Ejemplo n.º 2
0
void
plane_sona(struct emp_qelem *plane_list, int x, int y,
	   struct shiplist **head)
{
    struct plnstr *pp;
    struct plchrstr *pcp;
    struct mchrstr *tmcp;
    struct shpstr *targ, s;
    struct natstr *natp;
    struct emp_qelem *qp;
    struct emp_qelem *next;
    struct plist *ip;
    struct sctstr sect;
    int found = 0;
    int range, i, vis;
    int pingrange;
    int vrange;
    int dist;

    getsect(x, y, &sect);
    if ((sect.sct_type != SCT_WATER) && (sect.sct_type != SCT_HARBR))
	return;
    for (qp = plane_list->q_forw; qp != plane_list; qp = next) {
	next = qp->q_forw;
	ip = (struct plist *)qp;
	pp = &ip->plane;
	pcp = ip->pcp;
	if (!(pcp->pl_flags & P_A))	/* if it isn't an ASW plane */
	    continue;
	range = (int)techfact(pp->pln_tech, (100.0 - pln_acc(pp)) / 10.0);
	for (i = 0; getship(i, &s); i++) {
	    targ = &s;
	    if (targ->shp_own == pp->pln_own || targ->shp_own == 0)
		continue;
	    if (on_shiplist(targ->shp_uid, *head))
		continue;
	    tmcp = &mchr[(int)targ->shp_type];
	    if (!(tmcp->m_flags & M_SUB))
		continue;
	    if (!pct_chance(pln_identchance(pp, shp_hardtarget(targ),
					    EF_SHIP)))
		continue;
	    vis = shp_visib(targ);
	    pingrange = MAX(vis, 10) * range / 10;
	    vrange = pingrange * (pp->pln_effic / 200.0);
	    dist = mapdist(targ->shp_x, targ->shp_y, x, y);
	    pingrange = (MAX(pingrange, 2) * targ->shp_effic);
	    pingrange = roundavg(pingrange / 100.0);
	    if (dist > pingrange)
		continue;
	    if (tmcp->m_flags & M_SONAR && targ->shp_own) {
		natp = getnatp(targ->shp_own);
		if (natp->nat_flags & NF_SONAR)
		    wu(0, targ->shp_own,
		       "Sonar ping from %s detected by %s!\n",
		       xyas(x, y, targ->shp_own), prship(targ));
	    }
	    if ((dist > vrange))
		continue;
	    add_shiplist(targ->shp_uid, head);
	    if (!found) {
		pr("Sonar contact in %s\n", xyas(x, y, player->cnum));
		found = 1;
	    }
	    if (relations_with(targ->shp_own, pp->pln_own) < FRIENDLY &&
		!pct_chance(pln_identchance(pp, shp_hardtarget(targ),
					    EF_SHIP)))
		if (!pct_chance(pln_identchance(pp, shp_hardtarget(targ),
						EF_SHIP)))
		    pr("sub #%d %s\n", targ->shp_uid,
		       xyas(targ->shp_x, targ->shp_y, player->cnum));
		else
		    pr("%s %s\n", prship(targ),
		       xyas(targ->shp_x, targ->shp_y, player->cnum));
	    else
		pr("%s %s @ %s\n", cname(targ->shp_own), prship(targ),
		   xyas(targ->shp_x, targ->shp_y, player->cnum));
	}
    }
    if (found)
	pr("\n");
}
Ejemplo n.º 3
0
int
sdump(void)
{
    int nships;
    struct nstr_item ni;
    struct shpstr ship;
    int field[128];
    struct natstr *np;
    int n, i, npln, nch, nxl;
    time_t now;

    if (!snxtitem(&ni, EF_SHIP, player->argp[1], NULL))
	return RET_SYN;
    prdate();

    if (!player->argp[2]) {
	for (n = 1; n <= 34; n++)
	    field[n - 1] = n;
	field[n - 1] = 0;
    } else {
	n = 2;
	i = 0;
	while (player->argp[n]) {
	    if (!strcmp("type", player->argp[n])) {
		field[i++] = 1;
	    } else if (!strcmp("x", player->argp[n])) {
		field[i++] = 2;
	    } else if (!strcmp("y", player->argp[n])) {
		field[i++] = 3;
	    } else if (!strcmp("flt", player->argp[n])) {
		field[i++] = 4;
	    } else if (!strcmp("eff", player->argp[n])) {
		field[i++] = 5;
	    } else if (!strcmp("civ", player->argp[n])) {
		field[i++] = 6;
	    } else if (!strcmp("mil", player->argp[n])) {
		field[i++] = 7;
	    } else if (!strcmp("uw", player->argp[n])) {
		field[i++] = 8;
	    } else if (!strcmp("food", player->argp[n])) {
		field[i++] = 9;
	    } else if (!strcmp("pln", player->argp[n])) {
		field[i++] = 10;
	    } else if (!strcmp("he", player->argp[n])) {
		field[i++] = 11;
	    } else if (!strcmp("xl", player->argp[n])) {
		field[i++] = 12;
	    } else if (!strcmp("land", player->argp[n])) {
		field[i++] = 13;
	    } else if (!strcmp("mob", player->argp[n])) {
		field[i++] = 14;
	    } else if (!strcmp("fuel", player->argp[n])) {
		field[i++] = 15;
	    } else if (!strcmp("tech", player->argp[n])) {
		field[i++] = 16;
	    } else if (!strcmp("shell", player->argp[n])) {
		field[i++] = 17;
	    } else if (!strcmp("gun", player->argp[n])) {
		field[i++] = 18;
	    } else if (!strcmp("petrol", player->argp[n])) {
		field[i++] = 19;
	    } else if (!strcmp("iron", player->argp[n])) {
		field[i++] = 20;
	    } else if (!strcmp("dust", player->argp[n])) {
		field[i++] = 21;
	    } else if (!strcmp("bar", player->argp[n])) {
		field[i++] = 22;
	    } else if (!strcmp("oil", player->argp[n])) {
		field[i++] = 23;
	    } else if (!strcmp("lcm", player->argp[n])) {
		field[i++] = 24;
	    } else if (!strcmp("hcm", player->argp[n])) {
		field[i++] = 25;
	    } else if (!strcmp("rad", player->argp[n])) {
		field[i++] = 26;
	    } else if (!strcmp("def", player->argp[n])) {
		field[i++] = 27;
	    } else if (!strcmp("spd", player->argp[n])) {
		field[i++] = 28;
	    } else if (!strcmp("vis", player->argp[n])) {
		field[i++] = 29;
	    } else if (!strcmp("rng", player->argp[n])) {
		field[i++] = 30;
	    } else if (!strcmp("fir", player->argp[n])) {
		field[i++] = 31;
	    } else if (!strcmp("origx", player->argp[n])) {
		field[i++] = 32;
	    } else if (!strcmp("origy", player->argp[n])) {
		field[i++] = 33;
	    } else if (!strcmp("name", player->argp[n])) {
		field[i++] = 34;
	    } else {
		pr("Unrecognized field %s\n", player->argp[n]);
	    }
	    if (n++ > 100) {
		pr("Too many fields\n");
		return RET_FAIL;
	    }
	}
	field[i] = 0;
    }

    if (player->god)
	pr("   ");
    time(&now);
    pr("DUMP SHIPS %ld\n", (long)now);
    if (player->god)
	pr("own ");
    pr("id");
    n = 0;
    while (field[n]) {
	switch (field[n]) {
	case 1:
	    pr(" type");
	    break;
	case 2:
	    pr(" x");
	    break;
	case 3:
	    pr(" y");
	    break;
	case 4:
	    pr(" flt");
	    break;
	case 5:
	    pr(" eff");
	    break;
	case 6:
	    pr(" civ");
	    break;
	case 7:
	    pr(" mil");
	    break;
	case 8:
	    pr(" uw");
	    break;
	case 9:
	    pr(" food");
	    break;
	case 10:
	    pr(" pln");
	    break;
	case 11:
	    pr(" he");
	    break;
	case 12:
	    pr(" xl");
	    break;
	case 13:
	    pr(" land");
	    break;
	case 14:
	    pr(" mob");
	    break;
	case 15:
	    pr(" fuel");
	    break;
	case 16:
	    pr(" tech");
	    break;
	case 17:
	    pr(" shell");
	    break;
	case 18:
	    pr(" gun");
	    break;
	case 19:
	    pr(" petrol");
	    break;
	case 20:
	    pr(" iron");
	    break;
	case 21:
	    pr(" dust");
	    break;
	case 22:
	    pr(" bar");
	    break;
	case 23:
	    pr(" oil");
	    break;
	case 24:
	    pr(" lcm");
	    break;
	case 25:
	    pr(" hcm");
	    break;
	case 26:
	    pr(" rad");
	    break;
	case 27:
	    pr(" def");
	    break;
	case 28:
	    pr(" spd");
	    break;
	case 29:
	    pr(" vis");
	    break;
	case 30:
	    pr(" rng");
	    break;
	case 31:
	    pr(" fir");
	    break;
	case 32:
	    pr(" origx");
	    break;
	case 33:
	    pr(" origy");
	    break;
	case 34:
	    pr(" name");
	    break;
	}
	n++;
    }
    pr("\n");

    nships = 0;
    np = getnatp(player->cnum);
    while (nxtitem(&ni, &ship)) {
	if (!player->owner || ship.shp_own == 0)
	    continue;
	nships++;
	npln = shp_nplane(&ship, &nch, &nxl, NULL);
	if (player->god)
	    pr("%d ", ship.shp_own);
	pr("%d", ni.cur);
	n = 0;
	while (field[n]) {
	    switch (field[n++]) {
	    case 1:
		pr(" %.4s", mchr[(int)ship.shp_type].m_name);
		break;
	    case 2:
		pr(" %d", xrel(np, ship.shp_x));
		break;
	    case 3:
		pr(" %d", yrel(np, ship.shp_y));
		break;
	    case 4:
		pr(" %c", ship.shp_fleet ? ship.shp_fleet : '~');
		break;
	    case 5:
		pr(" %d", ship.shp_effic);
		break;
	    case 6:
		pr(" %d", ship.shp_item[I_CIVIL]);
		break;
	    case 7:
		pr(" %d", ship.shp_item[I_MILIT]);
		break;
	    case 8:
		pr(" %d", ship.shp_item[I_UW]);
		break;
	    case 9:
		pr(" %d", ship.shp_item[I_FOOD]);
		break;
	    case 10:
		pr(" %d", npln - nch - nxl);
		break;
	    case 11:
		pr(" %d", nch);
		break;
	    case 12:
		pr(" %d", nxl);
		break;
	    case 13:
		pr(" %d", shp_nland(&ship));
		break;
	    case 14:
		pr(" %d", ship.shp_mobil);
		break;
	    case 15:
		pr(" 0");
		break;
	    case 16:
		pr(" %d", ship.shp_tech);
		break;
	    case 17:
		pr(" %d", ship.shp_item[I_SHELL]);
		break;
	    case 18:
		pr(" %d", ship.shp_item[I_GUN]);
		break;
	    case 19:
		pr(" %d", ship.shp_item[I_PETROL]);
		break;
	    case 20:
		pr(" %d", ship.shp_item[I_IRON]);
		break;
	    case 21:
		pr(" %d", ship.shp_item[I_DUST]);
		break;
	    case 22:
		pr(" %d", ship.shp_item[I_BAR]);
		break;
	    case 23:
		pr(" %d", ship.shp_item[I_OIL]);
		break;
	    case 24:
		pr(" %d", ship.shp_item[I_LCM]);
		break;
	    case 25:
		pr(" %d", ship.shp_item[I_HCM]);
		break;
	    case 26:
		pr(" %d", ship.shp_item[I_RAD]);
		break;
	    case 27:
		pr(" %d", shp_armor(&ship));
		break;
	    case 28:
		pr(" %d", shp_speed(&ship));
		break;
	    case 29:
		pr(" %d", shp_visib(&ship));
		break;
	    case 30:
		pr(" %d", shp_frnge(&ship));
		break;
	    case 31:
		pr(" %d", shp_glim(&ship));
		break;
	    case 32:
		/*
		 * Disclosing construction site allows pirates to find
		 * harbors.  Disclose it only to the original owner
		 * and to deities.  Else dump illegal coordinates
		 * 1,0
		 */
		if (ship.shp_own == ship.shp_orig_own || player->god)
		    pr(" %d", xrel(np, ship.shp_orig_x));
		else
		    pr(" 1");
		break;
	    case 33:
		/* see case 32 */
		if (ship.shp_own == ship.shp_orig_own || player->god)
		    pr(" %d", yrel(np, ship.shp_orig_y));
		else
		    pr(" 0");
		break;
	    case 34:
		pr(" %c%s%c", '"', ship.shp_name, '"');
		break;
	    }
	}
	pr("\n");
    }
    if (nships == 0) {
	if (player->argp[1])
	    pr("%s: No ship(s)\n", player->argp[1]);
	else
	    pr("%s: No ship(s)\n", "");
	return RET_FAIL;
    } else
	pr("%d ship%s\n", nships, splur(nships));
    return RET_OK;
}
Ejemplo n.º 4
0
/*
 * Draw a radar map for radar at @cx,@cy.
 * @eff is the radar's efficiency, @tlev its tech level, @spy its power.
 * Submarines are detected at fraction @seesub of the range.
 */
void
radmap(int cx, int cy, int eff, double tlev, int spy, double seesub)
{
    int visib, rng;
    struct sctstr sect;
    struct shpstr ship;
    struct plnstr plane;
    struct nstr_sect ns;
    struct nstr_item ni;
    int x, y;
    int row;
    int n;
    int range = rad_range(eff, tlev, spy);
    int changed = 0;

    if (!radbuf)
	radbuf = malloc(WORLD_Y * MAPWIDTH(1));
    if (!visbuf)
	visbuf = malloc(WORLD_Y * MAPWIDTH(1));
    if (!rad) {
	rad = malloc(WORLD_Y * sizeof(char *));
	if (rad && radbuf) {
	    for (x = 0; x < WORLD_Y; x++)
		rad[x] = &radbuf[(WORLD_X + 1) * x];
	}
    }
    if (!vis) {
	vis = malloc(WORLD_Y * sizeof(signed char *));
	if (vis && visbuf) {
	    for (x = 0; x < WORLD_Y; x++)
		vis[x] = &visbuf[(WORLD_X + 1) * x];
	}
    }
    if (!radbuf || !visbuf || !rad || !vis) {
	pr("Memory error in radmap2, tell the deity.\n");
	return;
    }

    memset(visbuf, 0, (WORLD_Y * (WORLD_X + 1)));
    pr("%s efficiency %d%%, max range %d\n",
       xyas(cx, cy, player->cnum), eff, range);
    snxtsct_dist(&ns, cx, cy, range);
    blankfill(radbuf, &ns.range, 1);
    while (nxtsct(&ns, &sect)) {
	rad[ns.dy][ns.dx] = rad_char(&sect, ns.curdist, range,
				     player->cnum);
	changed += map_set(player->cnum, ns.x, ns.y, rad[ns.dy][ns.dx], 0);
    }
    if (changed)
	writemap(player->cnum);
    snxtitem_dist(&ni, EF_PLANE, cx, cy, range);
    while (nxtitem(&ni, &plane)) {
	if (plane.pln_own == 0)
	    continue;
	/* Used to have 'ghosts' when scanning whole world --ts */
	x = deltx(&ns.range, (int)plane.pln_x);
	y = delty(&ns.range, (int)plane.pln_y);

	if (pln_is_in_orbit(&plane) && plane.pln_own != player->cnum) {
	    vis[y][x] = 100;
	    rad[y][x] = '$';
	}
    }
    snxtitem_dist(&ni, EF_SHIP, cx, cy, range);
    while (nxtitem(&ni, &ship)) {
	if (ship.shp_own == 0)
	    continue;
	/* Used to have 'ghosts' when scanning whole world --ts */
	x = deltx(&ns.range, (int)ship.shp_x);
	y = delty(&ns.range, (int)ship.shp_y);

	visib = shp_visib(&ship);
	rng = (int)(range * visib / 20.0);
	if (ni.curdist > rng)
	    continue;
	if ((mchr[(int)ship.shp_type].m_flags & M_SUB) &&
	    ni.curdist > rng * seesub)
	    continue;
	if (visib > vis[y][x]) {
	    vis[y][x] = visib;
	    /* &~0x20 makes it a cap letter */
	    rad[y][x] = (*mchr[(int)ship.shp_type].m_name) & ~0x20;
	}
    }
    /*
     * make the center of the display 0
     * so ve et al can find it.
     */
    rad[delty(&ns.range, cy)][deltx(&ns.range, cx)] = '0';

    n = ns.range.height;
    for (row = 0; row < n; row++)
	pr("%s\n", rad[row]);
    pr("\n");
}
Ejemplo n.º 5
0
static void
look_ship(struct shpstr *lookship)
{
    struct shpstr *sp;
    struct mchrstr *smcp;
    struct mchrstr *tmcp;
    struct sctstr sect;
    int range;
    int vrange;
    int i;
    int dist;

    range = (int)techfact(lookship->shp_tech,
			  mchr[(int)lookship->shp_type].m_vrnge);
    range = range * (lookship->shp_effic / 100.0);
    smcp = &mchr[(int)lookship->shp_type];
    if (smcp->m_flags & M_SUB)
	range = MIN(range, 1);
    for (i = 0; NULL != (sp = getshipp(i)); i++) {
	if (sp->shp_own == player->cnum || sp->shp_own == 0)
	    continue;
	dist = mapdist(sp->shp_x, sp->shp_y,
		       lookship->shp_x, lookship->shp_y);
	if (dist > ship_max_interdiction_range)
	    continue;
	tmcp = &mchr[(int)sp->shp_type];
	if (smcp->m_flags & M_SUB)
	    vrange = (int)(shp_visib(sp) * range / 30.0);
	else
	    vrange = (int)(shp_visib(sp) * range / 20.0);
	getsect(sp->shp_x, sp->shp_y, &sect);
	if (sect.sct_type != SCT_WATER)
	    vrange = MAX(1, vrange);
	if (dist > vrange)
	    continue;
	if (smcp->m_flags & M_SUB) {
	    if (tmcp->m_flags & M_SONAR && dist < 2) {
		if (sp->shp_own != 0)
		    wu(0, sp->shp_own,
		       "%s detected surfacing noises in %s.\n",
		       prship(sp),
		       xyas(lookship->shp_x, lookship->shp_y,
			    sp->shp_own));
	    }
	    if (dist == 0 && (tmcp->m_flags & M_SUB) == 0)
		if (sp->shp_own != 0)
		    wu(0, sp->shp_own,
		       "Periscope spotted in %s by %s\n",
		       xyas(lookship->shp_x, lookship->shp_y,
			    sp->shp_own), prship(sp));
	}
	/* subs at sea only seen by sonar */
	if (tmcp->m_flags & M_SUB && sect.sct_type == SCT_WATER)
	    continue;
	pr("%s %s @ %s\n",
	   prnatid(sp->shp_own), prship(sp),
	   xyas(sp->shp_x, sp->shp_y, player->cnum));
	if (opt_HIDDEN)
	    setcont(player->cnum, sp->shp_own, FOUND_LOOK);
    }
}