예제 #1
0
void
takeover_plane(struct plnstr *pp, natid newown)
{
    int n;

    if ((pp->pln_own == newown) || (pp->pln_own == 0))
	return;
    if (pp->pln_flags & PLN_LAUNCHED)
	return;
    if (pp->pln_ship >= 0 || pp->pln_land >= 0)
	return;
    /*
     * XXX If this was done right, planes could escape,
     * flying to a nearby friendly airport.
     */
    n = pp->pln_effic - (29 + roll(100));
    if (n < 0)
	n = 0;
    pp->pln_effic = n;
    if (pp->pln_effic < PLANE_MINEFF || pp->pln_harden > 0) {
	pp->pln_effic = 0;
	mpr(newown, "%s blown up by the crew!\n", prplane(pp));
	wu(0, pp->pln_own,
	   "%s blown up by the crew to avoid capture by %s at %s!\n",
	   prplane(pp),
	   cname(newown), xyas(pp->pln_x, pp->pln_y, pp->pln_own));
    } else {
	mpr(newown, "We have captured %s!\n", prplane(pp));
	wu(0, pp->pln_own,
	   "%s captured by %s at %s!\n",
	   prplane(pp),
	   cname(newown), xyas(pp->pln_x, pp->pln_y, pp->pln_own));
    }
    takeover_unit((struct empobj *)pp, newown);
}
예제 #2
0
파일: sate.c 프로젝트: fstltna/empserver
int
sate(void)
{
    static int sct_shp_or_lnd[] = { EF_SECTOR, EF_SHIP, EF_LAND, EF_BAD };
    double tech;
    int pln_uid;
    struct plnstr plane;
    int type = EF_BAD;

    if (!player->argp[1] ||
	!*player->argp[1] ||
	!isdigit(*player->argp[1]) ||
	(pln_uid = atoi(player->argp[1])) < 0)
	return RET_SYN;

    if (!getplane(pln_uid, &plane)) {
	pr("No such plane\n");
	return RET_FAIL;
    }

    if (plane.pln_own != player->cnum && !player->god) {
	pr("You don't own plane #%d\n", pln_uid);
	return RET_FAIL;
    }

    if (!pln_is_in_orbit(&plane)) {
	pr("%s isn't in orbit\n", prplane(&plane));
	return RET_FAIL;
    }
    if (plane.pln_mobil < plane_mob_max) {
	pr("%s doesn't have enough mobility (needs %d)\n",
	   prplane(&plane), plane_mob_max);
	return RET_FAIL;
    }
    if (player->argp[2]) {
	type = ef_byname_from(player->argp[2], sct_shp_or_lnd);
	if (type < 0) {
	    return RET_SYN;
	}
    }

    if (plchr[(int)plane.pln_type].pl_flags & P_S)
	pr("Satellite Spy Report:\n");
    else
	pr("Satellite Map Report:\n");
    pr("%s at ", prplane(&plane));
    tech = techfact(plane.pln_tech, 20.0);
    return satmap(plane.pln_x, plane.pln_y, plane.pln_effic,
		  (int)tech, plchr[(int)plane.pln_type].pl_flags, type);
}
예제 #3
0
파일: plnsub.c 프로젝트: fstltna/empserver
void
pln_arm(struct emp_qelem *list, int dist, char mission, struct ichrstr *ip)
{
    struct emp_qelem *qp;
    struct emp_qelem *next;
    struct plist *plp;
    struct plnstr *pp;

    for (qp = list->q_forw; qp != list; qp = next) {
	next = qp->q_forw;
	plp = (struct plist *)qp;
	pp = &plp->plane;
	getplane(pp->pln_uid, pp);
	if ((pp->pln_flags & PLN_LAUNCHED)
	    || pln_equip(plp, ip, mission) < 0) {
	    emp_remque(qp);
	    free(qp);
	    continue;
	}
	pp->pln_flags |= PLN_LAUNCHED;
	pp->pln_mobil -= pln_mobcost(dist, pp, mission);
	putplane(pp->pln_uid, pp);
	pr("%s equipped\n", prplane(pp));
    }
}
예제 #4
0
static void
upd_plane(struct plnstr *pp, int etus,
	  struct natstr *np, struct bp *bp, int build)
{
    struct plchrstr *pcp = &plchr[(int)pp->pln_type];
    int mult, cost, eff_lost;

    if (build == 1) {
	if (!pp->pln_off && np->nat_money >= 0)
	    planerepair(pp, np, bp, etus);
	if (!player->simulation)
	    pp->pln_off = 0;
    } else {
	mult = 1;
	if (np->nat_level[NAT_TLEV] < pp->pln_tech * 0.85)
	    mult = 2;
	cost = -(mult * etus * MIN(0.0, pcp->pl_cost * money_plane));
	if (np->nat_money < cost && !player->simulation) {
	    eff_lost = etus / 5;
	    if (pp->pln_effic - eff_lost < PLANE_MINEFF)
		eff_lost = pp->pln_effic - PLANE_MINEFF;
	    if (eff_lost > 0) {
		wu(0, pp->pln_own, "%s lost %d%% to lack of maintenance\n",
		   prplane(pp), eff_lost);
		pp->pln_effic -= eff_lost;
	    }
	} else {
	    np->nat_money -= cost;
	}
	/* flight pay is 5x the pay received by other military */
	np->nat_money += etus * pcp->pl_crew * money_mil * 5;
    }
}
예제 #5
0
파일: plnsub.c 프로젝트: fstltna/empserver
void
pln_newlanding(struct emp_qelem *list, coord tx, coord ty, int cno)
{
    struct emp_qelem *qp;
    struct plist *plp;
    struct shpstr ship;
    struct sctstr sect;

    if (cno >= 0)
	getship(cno, &ship);
    for (qp = list->q_forw; qp != list; qp = qp->q_forw) {
	plp = (struct plist *)qp;
	if (cno >= 0) {
	    if (!could_be_on_ship(&plp->plane, &ship))
		pr("\t%s cannot land on ship #%d! %s aborts!\n",
		   prplane(&plp->plane), cno, prplane(&plp->plane));
	    else if (!put_plane_on_ship(&plp->plane, &ship))
		pr("\tNo room on ship #%d! %s aborts!\n",
		   cno, prplane(&plp->plane));
	    else {
		if (plp->plane.pln_own != ship.shp_own) {
		    wu(0, ship.shp_own, "%s %s lands on your %s\n",
		       cname(player->cnum), prplane(&plp->plane),
		       prship(&ship));
		}
		if (plp->pcp->pl_crew && plp->pstage == PLG_INFECT
		    && ship.shp_pstage == PLG_HEALTHY)
		    ship.shp_pstage = PLG_EXPOSED;
	    }
	} else {
	    plp->plane.pln_x = tx;
	    plp->plane.pln_y = ty;
	    getsect(tx, ty, &sect);
	    if (plp->plane.pln_own != sect.sct_own) {
		wu(0, sect.sct_own,
		   "%s %s lands at your sector %s\n",
		   cname(player->cnum),
		   prplane(&plp->plane), xyas(tx, ty, sect.sct_own));
	    }
	    if (plp->pcp->pl_crew && plp->pstage == PLG_INFECT
		&& sect.sct_pstage == PLG_HEALTHY)
		sect.sct_pstage = PLG_EXPOSED;
	    plp->plane.pln_ship = cno;
	}
    }
}
예제 #6
0
char *
unit_nameof(struct empobj *gp)
{
    switch (gp->ef_type) {
    case EF_SHIP:
	return prship((struct shpstr *)gp);
    case EF_PLANE:
	return prplane((struct plnstr *)gp);
    case EF_LAND:
	return prland((struct lndstr *)gp);
    case EF_NUKE:
	return prnuke((struct nukstr *)gp);
    }
    CANT_REACH();
    return "The Beast #666";
}
예제 #7
0
static int
showsat(struct sky **skypp, int x, int y)
{
    struct sky *skyp;
    struct sky *todelete = NULL;
    struct sky **prev;
    int nsat = 0;

    prev = NULL;
    skyp = *skypp;
    prev = skypp;
    do {
	/* we delete it, we free it. */
	if (todelete) {
	    free(todelete);
	    todelete = NULL;
	}
	if (skyp->s_sat.pln_x != x || skyp->s_sat.pln_y != y) {
	    prev = &(*prev)->s_next;
	    continue;
	}
	pr(" %12.12s (#%3d) %s @ %s\n",
	   cname(skyp->s_sat.pln_own), skyp->s_sat.pln_own,
	   prplane(&skyp->s_sat), xyas(x, y, player->cnum));
	if (opt_HIDDEN) {
	    /* FOUND_COAST should probably be changed to FOUND_SKY -KHS */
	    setcont(player->cnum, skyp->s_sat.pln_own, FOUND_COAST);
	}
	*prev = skyp->s_next;
	todelete = skyp;
	nsat++;
    } while (NULL != (skyp = skyp->s_next));
    /* check that last one! */
    if (todelete)
	free(todelete);
    return nsat;
}
예제 #8
0
static int
load_plane_ship(struct sctstr *sectp, struct shpstr *sp, int noisy,
		int load_unload, int *nshipsp)
{
    struct nstr_item ni;
    struct plnstr pln;
    int loaded = 0;
    char buf[1024];
    char *p;
    char prompt[512];
    struct mchrstr *mcp = mchr + sp->shp_type;

    if (mcp->m_nplanes + mcp->m_nchoppers + mcp->m_nxlight == 0) {
	if (noisy)
	    pr("%s cannot carry planes\n", prship(sp));
	return 0;
    }
    if (load_unload == LOAD &&
	shp_nplane(sp, NULL, NULL, NULL)
		>= mcp->m_nchoppers + mcp->m_nxlight + mcp->m_nplanes) {
	if (noisy)
	    pr("%s doesn't have room for any more planes\n", prship(sp));
	return 0;
    }
    sprintf(prompt, "Plane(s) to %s %s? ",
	    load_unload == LOAD ? "load onto" : "unload from", prship(sp));
    p = getstarg(player->argp[3], prompt, buf);
    if (!p)
	return RET_SYN;
    if (!snxtitem(&ni, EF_PLANE, p, NULL))
	return RET_SYN;

    if (!still_ok_ship(sectp, sp))
	return RET_SYN;

    if (noisy && p && *p)
	noisy = isdigit(*p);

    while (nxtitem(&ni, &pln)) {
	if (!player->owner)
	    continue;
	if (!(plchr[(int)pln.pln_type].pl_flags & P_L)
	    && !(plchr[(int)pln.pln_type].pl_flags & P_E)
	    && !(plchr[(int)pln.pln_type].pl_flags & P_K)
	    && !(plchr[(int)pln.pln_type].pl_flags & P_M)
	    ) {
	    if (noisy)
		pr("You can only load light planes, helos, xtra-light, or missiles onto ships.\n");
	    continue;
	}
	if (load_unload == LOAD && pln.pln_ship > -1) {
	    if (noisy)
		pr("%s is already on ship #%d!\n",
		   prplane(&pln), pln.pln_ship);
	    continue;
	}
	if (load_unload == LOAD && pln.pln_land > -1) {
	    if (noisy)
		pr("%s is already on land unit #%d!\n",
		   prplane(&pln), pln.pln_land);
	    continue;
	}
	if (pln.pln_harden != 0) {
	    if (noisy)
		pr("%s has been hardened and can't be loaded\n",
		   prplane(&pln));
	    continue;
	}

	if (load_unload == UNLOAD) {
	    if (pln.pln_ship != sp->shp_uid)
		continue;
	} else if (sp->shp_x != pln.pln_x || sp->shp_y != pln.pln_y)
	    continue;

	if (!could_be_on_ship(&pln, sp)) {
	    if (noisy) {
		if (plchr[(int)pln.pln_type].pl_flags & P_K)
		    p = "choppers";
		else if (plchr[(int)pln.pln_type].pl_flags & P_E)
		    p = "extra light planes";
		else if (plchr[(int)pln.pln_type].pl_flags & P_M)
		    p = "missiles";
		else
		    p = "planes";
		pr("%s cannot carry %s.\n", prship(sp), p);
	    }
	    continue;
	}
	/* Fit plane on ship */
	if (load_unload == LOAD) {
	    if (!put_plane_on_ship(&pln, sp)) {
		if (noisy)
		    pr("Can't put plane %d on this ship!\n", pln.pln_uid);
		continue;
	    }
	    sprintf(buf, "loaded on your %s at %s",
		    prship(sp), xyas(sp->shp_x, sp->shp_y, sp->shp_own));
	    gift(sp->shp_own, player->cnum, &pln, buf);
	    putplane(pln.pln_uid, &pln);
	} else {
	    pln.pln_ship = -1;
	    sprintf(buf, "unloaded in your %s at %s",
		    dchr[sectp->sct_type].d_name,
		    xyas(sectp->sct_x, sectp->sct_y, sectp->sct_own));
	    gift(sectp->sct_own, player->cnum, &pln, buf);
	    putplane(pln.pln_uid, &pln);
	}
	pr("%s %s %s at %s.\n",
	   prplane(&pln),
	   (load_unload == UNLOAD) ?
	   "unloaded from" : "loaded onto",
	   prship(sp), xyas(sp->shp_x, sp->shp_y, player->cnum));
	loaded = 1;
    }
    *nshipsp += loaded;
    return 0;
}
예제 #9
0
파일: scra.c 프로젝트: gefla/empserver
int
scra(void)
{
    struct nstr_item ni;
    union empobj_storage item;
    int type, n;
    struct sctstr sect;
    struct mchrstr *mp;
    struct plchrstr *pp;
    struct lchrstr *lp;
    char *p;
    i_type i;
    char prompt[128];
    char buf[1024];
    float eff;
    short *mvec;
    int amt;

    if (!(p = getstarg(player->argp[1], "Ship, land, or plane? ", buf)))
	return RET_SYN;
    switch (*p) {
    case 's':
	type = EF_SHIP;
	break;
    case 'p':
	type = EF_PLANE;
	break;
    case 'l':
	type = EF_LAND;
	break;
    default:
	pr("Ships, land units, or planes only! (s, l, p)\n");
	return RET_SYN;
    }

    if (!snxtitem(&ni, type, player->argp[2], NULL))
	return RET_SYN;
    n = 0;
    while (nxtitem(&ni, &item)) {
	if (!player->owner)
	    continue;
	n++;
    }
    snprintf(prompt, sizeof(prompt), "Really scrap %d %s%s [n]? ",
			    n, ef_nameof(type), splur(n));
    if (!confirm(prompt))
	return RET_FAIL;

    snxtitem_rewind(&ni);
    while (nxtitem(&ni, &item)) {
	if (!player->owner)
	    continue;

	if (opt_MARKET) {
	    if (ontradingblock(type, &item.ship)) {
		pr("You cannot scrap an item on the trading block!\n");
		continue;
	    }
	}

	getsect(item.gen.x, item.gen.y, &sect);
	if (type == EF_SHIP) {
	    if (!player->owner
		&& relations_with(sect.sct_own, player->cnum) < FRIENDLY) {
		pr("%s is not in a friendly harbor!\n",
		   prship(&item.ship));
		continue;
	    }
	    if (sect.sct_type != SCT_HARBR || sect.sct_effic < 60) {
		pr("%s is not in a 60%% efficient harbor!\n",
		   prship(&item.ship));
		continue;
	    }
	    if (mchr[item.ship.shp_type].m_flags & M_TRADE) {
		pr("WARNING: You only collect money from trade ships if you \"scuttle\" them!\n");
		sprintf(prompt,
			"Are you really sure that you want to scrap %s (n)? ",
			prship(&item.ship));
		if (!confirm(prompt)) {
		    pr("%s not scrapped\n", prship(&item.ship));
		    continue;
		}
	    }
	} else {
	    if (!player->owner
		&& relations_with(sect.sct_own, player->cnum) != ALLIED) {
		pr("%s is not in an allied sector!\n",
		   unit_nameof(&item.gen));
		continue;
	    }
	    if (type == EF_PLANE
		&& (sect.sct_type != SCT_AIRPT || sect.sct_effic < 60)) {
		pr("%s is not in a 60%% efficient airfield!\n",
		   prplane(&item.plane));
		continue;
	    }
	}

	pr("%s scrapped in %s\n",
	   unit_nameof(&item.gen),
	   xyas(item.gen.x, item.gen.y, player->cnum));
	unit_drop_cargo(&item.gen, sect.sct_own);
	if (type == EF_SHIP) {
	    eff = item.ship.shp_effic / 100.0;
	    mp = &mchr[(int)item.ship.shp_type];
	    for (i = I_NONE + 1; i <= I_MAX; i++) {
		if (load_comm_ok(&sect, item.ship.shp_own, i,
				 -item.ship.shp_item[i]))
		    sect.sct_item[i] += item.ship.shp_item[i];
	    }
	    mvec = mp->m_mat;
	    if (item.ship.shp_pstage == PLG_INFECT
		&& sect.sct_pstage == PLG_HEALTHY)
		sect.sct_pstage = PLG_EXPOSED;
	} else if (type == EF_LAND) {
	    eff = item.land.lnd_effic / 100.0;
	    lp = &lchr[(int)item.land.lnd_type];
	    for (i = I_NONE + 1; i <= I_MAX; i++) {
		if (load_comm_ok(&sect, item.land.lnd_own, i,
				 -item.land.lnd_item[i]))
		    sect.sct_item[i] += item.land.lnd_item[i];
	    }
	    mvec = lp->l_mat;
	    if (item.land.lnd_pstage == PLG_INFECT
		&& sect.sct_pstage == PLG_HEALTHY)
		sect.sct_pstage = PLG_EXPOSED;
	} else {
	    eff = item.land.lnd_effic / 100.0;
	    pp = &plchr[(int)item.plane.pln_type];
	    mvec = pp->pl_mat;
	}
	item.gen.effic = 0;
	put_empobj(type, item.gen.uid, &item.gen);
	for (i = I_NONE + 1; i <= I_MAX; i++) {
	    if (i == I_CIVIL || i == I_MILIT || i == I_UW)
		amt = sect.sct_item[i] + mvec[i] * eff;
	    else
		amt = sect.sct_item[i] + mvec[i] * 2 / 3 * eff;
	    if (amt > ITEM_MAX)
		amt = ITEM_MAX;
	    sect.sct_item[i] = amt;
	}
	putsect(&sect);
    }
    return RET_OK;
}
예제 #10
0
static int
pupgr(void)
{
    struct sctstr sect;
    struct natstr *natp;
    struct nstr_item ni;
    struct plnstr plane;
    struct plchrstr *pp;
    int n;
    int tlev;
    int avail, cost;
    int cash;

    if (!snxtitem(&ni, EF_PLANE, player->argp[2], NULL))
	return RET_SYN;
    natp = getnatp(player->cnum);
    cash = natp->nat_money;
    tlev = (int)natp->nat_level[NAT_TLEV];
    n = 0;
    while (nxtitem(&ni, &plane)) {
	if (plane.pln_own == 0)
	    continue;
	getsect(plane.pln_x, plane.pln_y, &sect);
	if (sect.sct_own != player->cnum)
	    continue;
	if (sect.sct_type != SCT_AIRPT || sect.sct_effic < 60)
	    continue;
	if (relations_with(plane.pln_own, sect.sct_own) < FRIENDLY) {
	    pr("You are not on friendly terms with the owner of plane %d!\n",
	       plane.pln_uid);
	    continue;
	}
	if (pln_is_in_orbit(&plane)) {
	    pr("Plane %s is in orbit!\n", prplane(&plane));
	    continue;
	}
	if (plane.pln_flags & PLN_LAUNCHED)
	    continue;
	n++;
	pp = &plchr[(int)plane.pln_type];
	avail = (PLN_BLD_WORK(pp->pl_lcm, pp->pl_hcm) * UPGR_COST + 99) / 100;
	if (sect.sct_avail < avail) {
	    pr("Not enough available work in %s to upgrade a %s\n",
	       xyas(sect.sct_x, sect.sct_y, player->cnum), pp->pl_name);
	    pr(" (%d available work required)\n", avail);
	    continue;
	}
	if (plane.pln_effic < 60) {
	    pr("%s is too damaged to upgrade!\n", prplane(&plane));
	    continue;
	}
	if (plane.pln_tech >= tlev) {
	    pr("%s tech: %d, yours is only %d\n",
	       prplane(&plane), plane.pln_tech, tlev);
	    continue;
	}
	cost = pp->pl_cost * UPGR_COST / 100;
	if (cost + player->dolcost > cash) {
	    pr("You don't have enough money to upgrade %s!\n",
	       prplane(&plane));
	    continue;
	}

	sect.sct_avail -= avail;
	plane.pln_effic -= UPGR_EFF;
	pln_set_tech(&plane, tlev);
	plane.pln_harden = 0;
	plane.pln_mission = 0;

	putplane(plane.pln_uid, &plane);
	putsect(&sect);
	player->dolcost += cost;
	pr("%s upgraded to tech %d, at a cost of %d\n",
	   prplane(&plane), plane.pln_tech, cost);
	if (plane.pln_own != player->cnum)
	    wu(0, plane.pln_own,
	       "%s upgraded by %s to tech %d, at a cost of %d\n",
	       prplane(&plane), cname(player->cnum), plane.pln_tech, cost);
    }
    if (n == 0) {
	pr("No planes.\n");
	return RET_SYN;
    }
    return RET_OK;
}
예제 #11
0
/* Knock down a bridge span.  Note that this does NOT write the
 * sector out to the database, it's up to the caller to do that. */
static void
knockdown(struct sctstr *sp)
{
    struct lndstr land;
    struct plnstr plane;
    struct nukstr nuke;
    struct nstr_item ni;

    mpr(sp->sct_own,
	"Crumble... SCREEEECH!  Splash! Bridge%s falls at %s!\n",
	sp->sct_type == SCT_BTOWER ? " tower" : "",
	xyas(sp->sct_x, sp->sct_y, sp->sct_own));
    if (!SCT_MINES_ARE_SEAMINES(sp))
	sp->sct_mines = 0;
    sp->sct_type = SCT_WATER;
    sp->sct_newtype = SCT_WATER;
    sp->sct_own = 0;
    sp->sct_oldown = 0;
    sp->sct_mobil = 0;
    sp->sct_effic = 0;

    /* Sink all the units */
    snxtitem_xy(&ni, EF_LAND, sp->sct_x, sp->sct_y);
    while (nxtitem(&ni, &land)) {
	if (land.lnd_own == 0)
	    continue;
	if (land.lnd_ship >= 0)
	    continue;
	mpr(land.lnd_own, "     AARGH! %s tumbles to its doom!\n",
	    prland(&land));
	land.lnd_effic = 0;
	putland(land.lnd_uid, &land);
    }
    /* Sink all the planes */
    snxtitem_xy(&ni, EF_PLANE, sp->sct_x, sp->sct_y);
    while (nxtitem(&ni, &plane)) {
	if (plane.pln_own == 0)
	    continue;
	if (plane.pln_flags & PLN_LAUNCHED)
	    continue;
	if (plane.pln_ship >= 0)
	    continue;
	mpr(plane.pln_own, "     AARGH! %s tumbles to its doom!\n",
	    prplane(&plane));
	plane.pln_effic = 0;
	putplane(plane.pln_uid, &plane);
    }
    /* Sink all the nukes */
    snxtitem_xy(&ni, EF_NUKE, sp->sct_x, sp->sct_y);
    while (nxtitem(&ni, &nuke)) {
	if (nuke.nuk_own == 0)
	    continue;
	if (nuke.nuk_plane >= 0)
	    continue;
	mpr(nuke.nuk_own, "     %s sinks to the bottom of the sea!\n",
	    prnuke(&nuke));
	nuke.nuk_effic = 0;
	putnuke(nuke.nuk_uid, &nuke);
    }
    memset(sp->sct_item, 0, sizeof(sp->sct_item));
    memset(sp->sct_del, 0, sizeof(sp->sct_del));
    memset(sp->sct_dist, 0, sizeof(sp->sct_dist));
    sp->sct_pstage = PLG_HEALTHY;
    sp->sct_ptime = 0;
    sp->sct_che = 0;
    sp->sct_che_target = 0;
}
예제 #12
0
int
msl_launch(struct plnstr *pp, int type, char *what, coord x, coord y,
	   natid victim, int *sublaunchp)
{
    struct shpstr ship;
    struct nukstr nuke;
    int sublaunch = 0;
    char *base, *in_or_at, *from;

    mpr(pp->pln_own, "Preparing to launch %s at %s %s %s%s\n",
	prplane(pp),
	cname(victim),
	what,
	type != EF_SECTOR ? "in " : "",
	xyas(x, y, pp->pln_own));
    if (pp->pln_ship >= 0) {
	getship(pp->pln_ship, &ship);
	base = prship(&ship);
	in_or_at = " in ";
	if (mchr[(int)ship.shp_type].m_flags & M_SUB) {
	    sublaunch = 1;
	    from = "in hatch";
	} else
	    from = "on deck";
    } else {
	if (pp->pln_harden > 0) {
	    base = "missile silo";
	    in_or_at = " at ";
	    from = "in silo";
	} else {
	    base = in_or_at = "";
	    from = "on launch pad";
	}
    }
    mpr(pp->pln_own, "\tLaunching from %s%s%s\n",
	base, in_or_at, xyas(pp->pln_x, pp->pln_y, pp->pln_own));

    CANT_HAPPEN(pp->pln_flags & PLN_LAUNCHED);
    pp->pln_flags |= PLN_LAUNCHED;
    putplane(pp->pln_uid, pp);

    if (chance((0.05 + (100 - pp->pln_effic) / 100.0)
	       * (1 - techfact(pp->pln_tech, 1.0)))) {
	mpr(pp->pln_own, "KABOOOOM!  Missile explodes %s!\n", from);
	if (getnuke(nuk_on_plane(pp), &nuke)) {
	    mpr(pp->pln_own, "%s lost!\n", prnuke(&nuke));
	    nuke.nuk_effic = 0;
	    putnuke(nuke.nuk_uid, &nuke);
	}
#if 0
	/*
	 * Disabled for now, because it breaks callers that call
	 * msl_launch() for each member of a list of planes, created
	 * by msl_sel() or perform_mission().  Damage to the base can
	 * damage other planes.  Any copies of them in the list become
	 * stale.  When msl_launch() modifies and writes back such a
	 * stale copy, the damage gets wiped out, triggering a seqno
	 * oops.
	 */
	if (chance(0.33)) {
	    struct sctstr sect;
	    int dam;

	    dam = pln_damage(pp, 'p', NULL) / 2;
	    if (pp->pln_ship >= 0) {
		shipdamage(&ship, dam);
		putship(ship.shp_uid, &ship);
	    } else {
		mpr(pp->pln_own, "Explosion damages %s %d%%\n",
		    xyas(pp->pln_x, pp->pln_y, pp->pln_own), dam);
		getsect(pp->pln_x, pp->pln_y, &sect);
		sectdamage(&sect, dam);
		putsect(&sect);
	    }
	}
#endif
	return -1;
    }

    mpr(pp->pln_own, "\tSHWOOOOOSH!  Missile launched!\n");

    if (type != EF_PLANE)
	mpr(victim, "Incoming %s missile sighted at %s...\n",
	    sublaunch ? "sub-launched" : cname(pp->pln_own),
	    xyas(x, y, victim));

    if (type == EF_SECTOR || type == EF_LAND) {
	if (msl_abm_intercept(pp, x, y, sublaunch))
	    return -1;
    }
    if (type == EF_SHIP) {
	if (shp_missile_defense(x, y, pp->pln_own, pln_def(pp))) {
	    return -1;
	}
    }

    if (sublaunchp)
	*sublaunchp = sublaunch;
    return 0;
}
예제 #13
0
파일: plnsub.c 프로젝트: fstltna/empserver
int
pln_equip(struct plist *plp, struct ichrstr *ip, char mission)
{
    struct plchrstr *pcp;
    struct plnstr *pp;
    int load, needed;
    struct lndstr land;
    struct shpstr ship;
    struct sctstr sect;
    i_type itype;
    short *item;
    int own;
    int abandon_needed;

    pp = &plp->plane;
    pcp = plp->pcp;
    if (pp->pln_ship >= 0) {
	getship(pp->pln_ship, &ship);
	plp->pstage = ship.shp_pstage;
	item = ship.shp_item;
	own = ship.shp_own;
    } else if (pp->pln_land >= 0) {
	getland(pp->pln_land, &land);
	plp->pstage = land.lnd_pstage;
	item = land.lnd_item;
	own = land.lnd_own;
    } else {
	getsect(pp->pln_x, pp->pln_y, &sect);
	plp->pstage = sect.sct_pstage;
	item = sect.sct_item;
	own = sect.sct_oldown;
    }
    if (pcp->pl_fuel > item[I_PETROL]) {
	pr("%s not enough petrol there!\n", prplane(pp));
	return -1;
    }
    item[I_PETROL] -= pcp->pl_fuel;
    load = pln_load(pp);
    itype = I_NONE;
    switch (mission) {
    case 's':		/* strategic bomb */
    case 'p':		/* pinpoint bomb */
	itype = I_SHELL;
	break;
    case 't':		/* transport */
	if (!(pcp->pl_flags & P_C) || !ip)
	    break;
	itype = ip->i_uid;
	load *= 2;
	break;
    case 'm':		/* mine */
	if ((pcp->pl_flags & P_MINE) == 0)
	    break;
	itype = I_SHELL;
	load *= 2;
	break;
    case 'd':		/* drop */
	if (!(pcp->pl_flags & P_C) || CANT_HAPPEN(!ip))
	    break;
	itype = ip->i_uid;
	if (pcp->pl_flags & P_V)
	    load *= 2;
	break;
    case 'a':		/* paradrop */
	if (!(pcp->pl_flags & P_P))
	    break;
	itype = I_MILIT;
	if (pcp->pl_flags & P_V)
	    load *= 2;
	break;
    case 'r':		/* reconnaissance */
    case 'e':		/* escort */
	load = 0;
	break;
    case 'i':		/* missile interception */
	if (CANT_HAPPEN(!(pcp->pl_flags & P_M)
			|| !(pcp->pl_flags & (P_N | P_O))))
	    break;
	if (load)
	    itype = I_SHELL;
	break;
    default:
	CANT_REACH();
	load = 0;
    }

    if (itype != I_NONE) {
	needed = load / ichr[itype].i_lbs;
	if (needed <= 0) {
	    pr("%s can't contribute to mission\n", prplane(pp));
	    return -1;
	}
	if (nuk_on_plane(pp) >= 0) {
	    if (mission == 's' || mission == 't')
		needed = 0;
	    else {
		pr("%s can't fly this mission"
		   " while it is carrying a nuclear weapon",
		   prplane(pp));
		return -1;
	    }
	}
	if (itype == I_CIVIL && pp->pln_own != own) {
	    pr("You don't control those civilians!\n");
	    return -1;
	}
#if 0
	/* Supply is broken somewhere, so don't use it for now */
	if (itype == I_SHELL && item[itype] < needed)
	    item[itype] += supply_commod(plp->plane.pln_own,
					 plp->plane.pln_x,
					 plp->plane.pln_y,
					 I_SHELL, needed);
#endif
	if (pp->pln_ship >= 0 || pp->pln_land >= 0)
	    abandon_needed = 0;
	else
	    abandon_needed = !!would_abandon(&sect, itype, needed, NULL);
	if (item[itype] < needed + abandon_needed) {
	    pr("Not enough %s for %s\n", ichr[itype].i_name, prplane(pp));
	    return -1;
	}
	item[itype] -= needed;
	plp->load = needed;
    }

    if (pp->pln_ship >= 0) {
	if (pp->pln_own != ship.shp_own) {
	    wu(0, ship.shp_own,
	       "%s %s prepares for takeoff from ship %s\n",
	       cname(pp->pln_own), prplane(pp), prship(&ship));
	}
	putship(ship.shp_uid, &ship);
    } else if (pp->pln_land >= 0) {
	if (pp->pln_own != land.lnd_own) {
	    wu(0, land.lnd_own,
	       "%s %s prepares for takeoff from unit %s\n",
	       cname(pp->pln_own), prplane(pp), prland(&land));
	}
	putland(land.lnd_uid, &land);
    } else {
	if (pp->pln_own != sect.sct_own) {
	    wu(0, sect.sct_own, "%s %s prepares for takeoff from %s\n",
	       cname(pp->pln_own), prplane(pp),
	       xyas(sect.sct_x, sect.sct_y, sect.sct_own));
	}
	putsect(&sect);
    }
    return 0;
}
예제 #14
0
파일: plnsub.c 프로젝트: fstltna/empserver
void
pln_sel(struct nstr_item *ni, struct emp_qelem *list, struct sctstr *ap,
	int ap_to_target, int rangemult, int wantflags, int nowantflags)
{
    struct plnstr plane;
    int range;
    struct plchrstr *pcp;
    struct plist *plp;

    emp_initque(list);
    while (nxtitem(ni, &plane)) {
	/*
	 * It would be nice to let deities fly foreign planes, but
	 * much of the code assumes that only the plane's owner can
	 * fly it.
	 */
	if (!plane.pln_own || plane.pln_own != player->cnum)
	    continue;
	if (plane.pln_mobil <= 0)
	    continue;
	if (plane.pln_effic < 40) {
	    pr("%s not efficient enough (must be 40%%)\n",
	       prplane(&plane));
	    continue;
	}
	if (!pln_capable(&plane, wantflags, nowantflags))
	    continue;
	if (opt_MARKET) {
	    if (ontradingblock(EF_PLANE, &plane)) {
		pr("plane #%d inelligible - it's for sale.\n",
		   plane.pln_uid);
		continue;
	    }
	}

	range = mapdist(plane.pln_x, plane.pln_y, ap->sct_x, ap->sct_y);
	if (range > 4) {
	    pr("%s too far from assembly point\n", prplane(&plane));
	    continue;
	}
	range += ap_to_target;
	range *= rangemult;
	pcp = &plchr[(int)plane.pln_type];
	if (plane.pln_range < range) {
	    pr("%s out of range (%d:%d)\n",
	       prplane(&plane), plane.pln_range, range);
	    continue;
	}
	if (!pln_airbase_ok(&plane, rangemult != 2, 1))
	    continue;
	pr("%s standing by\n", prplane(&plane));
	plane.pln_mission = 0;
	putplane(plane.pln_uid, &plane);
	plp = malloc(sizeof(struct plist));
	plp->load = 0;
	plp->pstage = PLG_HEALTHY;
	plp->pcp = pcp;
	plp->plane = plane;
	emp_insque(&plp->queue, list);
    }
}
예제 #15
0
파일: plnsub.c 프로젝트: fstltna/empserver
int
pln_airbase_ok(struct plnstr *pp, int oneway, int noisy)
{
    struct shpstr ship;
    struct lndstr land;
    struct sctstr sect;
    struct plchrstr *pcp = plchr + pp->pln_type;

    if (CANT_HAPPEN(noisy && pp->pln_own != player->cnum))
	noisy = 0;

    if (pp->pln_ship >= 0) {
	/* ship: needs to be own or allied, efficient */
	if (!getship(pp->pln_ship, &ship)) {
	    CANT_REACH();
	    return 0;
	}
	if (relations_with(ship.shp_own, pp->pln_own) != ALLIED) {
	    if (noisy)
		pr("(note) An ally does not own the ship %s is on\n",
		   prplane(pp));
	    return 0;
	}
	if (!(carrier_planes(&ship, pcp->pl_flags & P_M) & pcp->pl_flags))
	    return 0;

    } else if (pp->pln_land >= 0) {
	/* land: needs to be own or allied, efficient, not embarked */
	if (!getland(pp->pln_land, &land)) {
	    CANT_REACH();
	    return 0;
	}
	if (relations_with(land.lnd_own, pp->pln_own) != ALLIED) {
	    if (noisy)
		pr("(note) An ally does not own the unit %s is on\n",
		   prplane(pp));
	    return 0;
	}
	if (land.lnd_effic < LND_AIROPS_EFF || !(pcp->pl_flags & P_E))
	    return 0;
	if (land.lnd_ship >= 0 || land.lnd_land >= 0)
	    return 0;

    } else {
	/* sector: needs to be own or allied, efficient airfield */
	if (!getsect(pp->pln_x, pp->pln_y, &sect)) {
	    CANT_REACH();
	    return 0;
	}

	if (relations_with(sect.sct_own, pp->pln_own) != ALLIED) {
	    if (noisy)
		pr("(note) An ally does not own the sector %s is in\n",
		   prplane(pp));
	    return 0;
	}
	/* need airfield unless VTOL */
	if ((pcp->pl_flags & P_V) == 0) {
	    if (sect.sct_type != SCT_AIRPT) {
		if (noisy)
		    pr("%s not at airport\n", prplane(pp));
		return 0;
	    }
	    if (sect.sct_effic < 40) {
		if (noisy)
		    pr("%s is not 40%% efficient, %s can't take off from there.\n",
		       xyas(sect.sct_x, sect.sct_y, player->cnum),
		       prplane(pp));
		return 0;
	    }
	    if (!oneway && sect.sct_effic < 60) {
		if (noisy)
		    pr("%s is not 60%% efficient, %s can't land there.\n",
		       xyas(sect.sct_x, sect.sct_y, player->cnum),
		       prplane(pp));
		return 0;
	    }
	}
    }

    return 1;
}
예제 #16
0
static int
load_plane_land(struct sctstr *sectp, struct lndstr *lp, int noisy,
		int load_unload, int *nunitsp)
{
    struct nstr_item ni;
    struct plnstr pln;
    int loaded = 0;
    char *p;
    char prompt[512];
    char buf[1024];
    struct lchrstr *lcp = lchr + lp->lnd_type;

    if (!lcp->l_nxlight) {
	if (noisy)
	    pr("%s cannot carry extra-light planes.\n", prland(lp));
	return 0;
    }
    if (load_unload == LOAD && lnd_nxlight(lp) >= lcp->l_nxlight) {
	if (noisy)
	    pr("%s doesn't have room for any more extra-light planes\n",
	       prland(lp));
	return 0;
    }
    sprintf(prompt, "Plane(s) to %s %s? ",
	    load_unload == LOAD ? "load onto" : "unload from", prland(lp));
    p = getstarg(player->argp[3], prompt, buf);
    if (!p)
	return RET_SYN;
    if (!snxtitem(&ni, EF_PLANE, p, NULL))
	return RET_SYN;

    if (!still_ok_land(sectp, lp))
	return RET_SYN;

    if (noisy && p && *p)
	noisy = isdigit(*p);

    while (nxtitem(&ni, &pln)) {
	if (!player->owner)
	    continue;

	if (!(plchr[(int)pln.pln_type].pl_flags & P_E)) {
	    if (noisy)
		pr("You can only load xlight planes onto units.\n");
	    continue;
	}

	if (load_unload == LOAD && pln.pln_ship > -1) {
	    if (noisy)
		pr("%s is already on ship #%d!\n",
		   prplane(&pln), pln.pln_ship);
	    continue;
	}
	if (load_unload == LOAD && pln.pln_land > -1) {
	    if (noisy)
		pr("%s is already on unit #%d!\n",
		   prplane(&pln), pln.pln_land);
	    continue;
	}
	if (pln.pln_harden != 0) {
	    if (noisy)
		pr("%s has been hardened and can't be loaded\n",
		   prplane(&pln));
	    continue;
	}

	/* Plane sanity done */
	/* Find the right unit */
	if (load_unload == UNLOAD) {
	    if (pln.pln_land != lp->lnd_uid)
		continue;
	} else if (lp->lnd_x != pln.pln_x || lp->lnd_y != pln.pln_y)
	    continue;

	/* Fit plane on unit */
	if (load_unload == LOAD) {
	    if (!put_plane_on_land(&pln, lp)) {
		if (noisy)
		    pr("Can't put plane %d on this unit!\n", pln.pln_uid);
		continue;
	    }
	    sprintf(buf, "loaded on %s at %s",
		    prland(lp), xyas(lp->lnd_x, lp->lnd_y, lp->lnd_own));
	    gift(lp->lnd_own, player->cnum, &pln, buf);
	    putplane(pln.pln_uid, &pln);
	} else {
	    pln.pln_land = -1;
	    sprintf(buf, "unloaded at your sector at %s",
		    xyas(sectp->sct_x, sectp->sct_y, sectp->sct_own));
	    gift(sectp->sct_own, player->cnum, &pln, buf);
	    putplane(pln.pln_uid, &pln);
	}
	pr("%s %s %s at %s.\n",
	   prplane(&pln),
	   (load_unload == UNLOAD) ?
	   "unloaded from" : "loaded onto",
	   prland(lp), xyas(lp->lnd_x, lp->lnd_y, player->cnum));
	loaded = 1;
    }
    *nunitsp += loaded;
    return 0;
}
예제 #17
0
파일: detonate.c 프로젝트: gefla/empserver
int
detonate(struct nukstr *np, coord x, coord y, int airburst)
{
    int nuketype = np->nuk_type;
    struct nchrstr *ncp;
    struct plnstr plane;
    struct sctstr sect;
    struct shpstr ship;
    struct lndstr land;
    struct nukstr nuke;
    natid own;
    int type;
    int damage;
    int fallout;
    int rad;
    struct nstr_sect ns;
    struct nstr_item ni;
    int changed = 0;

    pr("Releasing RV's for %s detonation...\n",
       airburst ? "airburst" : "groundburst");

    getsect(x, y, &sect);
    ncp = &nchr[nuketype];
    kaboom(x, y, ncp->n_blast);
    rad = ncp->n_blast;
    if (!airburst)
        rad = rad * 2 / 3;
    if (sect.sct_type == SCT_WATER)
        rad = 0;     /* Nukes falling on water affect only 1 sector */
    np->nuk_effic = 0;
    putnuke(np->nuk_uid, np);

    snxtsct_dist(&ns, x, y, rad);
    while (nxtsct(&ns, &sect)) {
        own = sect.sct_own;
        type = sect.sct_type;
        if ((damage = nukedamage(ncp, ns.curdist, airburst)) <= 0)
            continue;
        if (type == SCT_SANCT) {
            pr("bounced off %s\n", xyas(ns.x, ns.y, player->cnum));
            mpr(own, "%s nuclear device bounced off %s\n",
                cname(player->cnum), xyas(ns.x, ns.y, own));
            nreport(player->cnum, N_NUKE, own, 1);
            continue;
        }
        sect_damage(&sect, damage);
        if (opt_FALLOUT) {
            fallout = sect.sct_fallout;
            if (ncp->n_flags & N_NEUT)
                fallout += damage * 30;
            else
                fallout += damage * 3;
            sect.sct_fallout = MIN(fallout, FALLOUT_MAX);
        }
        if (damage > 100) {
            sect.sct_oldown = 0;
            sect.sct_own = 0;
            if (type == SCT_WATER || type == SCT_BSPAN ||
                    type == SCT_BTOWER) {
                if (type != SCT_WATER) {
                    pr("left nothing but water in %s\n",
                       xyas(ns.x, ns.y, player->cnum));
                    if (own != player->cnum)
                        mpr(own,
                            "%s nuclear device left nothing but water in %s\n",
                            cname(player->cnum), xyas(ns.x, ns.y, own));
                    sect.sct_newtype = SCT_WATER;
                    sect.sct_type = SCT_WATER;
                }
            } else {
                sect.sct_newtype = SCT_WASTE;
                sect.sct_type = SCT_WASTE;
                pr("turned %s into a radioactive wasteland\n",
                   xyas(ns.x, ns.y, player->cnum));
                if (own != player->cnum)
                    mpr(own,
                        "%s nuclear device turned %s into a radioactive wasteland\n",
                        cname(player->cnum), xyas(ns.x, ns.y, own));
            }
            changed |= map_set(player->cnum, sect.sct_x, sect.sct_y,
                               dchr[sect.sct_type].d_mnem, 0);
        } else {
            pr("did %d%% damage in %s\n",
               damage, xyas(ns.x, ns.y, player->cnum));
            if (own != player->cnum)
                mpr(own, "%s nuclear device did %d%% damage in %s\n",
                    cname(player->cnum), damage, xyas(ns.x, ns.y, own));
        }
        (void)putsect(&sect);
        if (type != SCT_WATER)
            nreport(player->cnum, N_NUKE, own, 1);
    }

    if (changed)
        writebmap(player->cnum);

    snxtitem_dist(&ni, EF_PLANE, x, y, rad);
    while (nxtitem(&ni, &plane)) {
        if ((own = plane.pln_own) == 0)
            continue;
        if (plane.pln_flags & PLN_LAUNCHED)
            continue;
        damage = nukedamage(ncp, ni.curdist, airburst) - plane.pln_harden;
        if (damage <= 0)
            continue;
        if (plane.pln_ship >= 0) {
            /* Are we on a sub? */
            getship(plane.pln_ship, &ship);

            if (mchr[(int)ship.shp_type].m_flags & M_SUB) {
                struct sctstr sect1;

                /* Should we damage this sub? */
                getsect(ship.shp_x, ship.shp_y, &sect1);

                if (sect1.sct_type == SCT_BSPAN ||
                        sect1.sct_type == SCT_BTOWER ||
                        sect1.sct_type == SCT_WATER) {
                    /* Ok, we're not in a harbor or trapped
                       inland.  Now, did we get pasted
                       directly? */
                    if (ship.shp_x != x || ship.shp_y != y) {
                        /* Nope, so don't mess with it */
                        continue;
                    }
                }
            }
        }
        planedamage(&plane, damage);
        if (own == player->cnum) {
            pr("%s at %s reports %d%% damage\n",
               prplane(&plane),
               xyas(plane.pln_x, plane.pln_y, player->cnum), damage);
        } else {
            mpr(own, "%s nuclear device did %d%% damage to %s at %s\n",
                cname(player->cnum), damage,
                prplane(&plane), xyas(plane.pln_x, plane.pln_y, own));
        }
        putplane(ni.cur, &plane);
    }

    snxtitem_dist(&ni, EF_LAND, x, y, rad);
    while (nxtitem(&ni, &land)) {
        if ((own = land.lnd_own) == 0)
            continue;
        if ((damage = nukedamage(ncp, ni.curdist, airburst)) <= 0)
            continue;

        if (land.lnd_ship >= 0) {
            /* Are we on a sub? */
            getship(land.lnd_ship, &ship);

            if (mchr[(int)ship.shp_type].m_flags & M_SUB) {
                struct sctstr sect1;

                /* Should we damage this sub? */
                getsect(ship.shp_x, ship.shp_y, &sect1);

                if (sect1.sct_type == SCT_BSPAN ||
                        sect1.sct_type == SCT_BTOWER ||
                        sect1.sct_type == SCT_WATER) {
                    /* Ok, we're not in a harbor or trapped
                       inland.  Now, did we get pasted
                       directly? */
                    if (ship.shp_x != x || ship.shp_y != y) {
                        /* Nope, so don't mess with it */
                        continue;
                    }
                }
            }
        }
        land_damage(&land, damage);
        if (own == player->cnum) {
            pr("%s at %s reports %d%% damage\n",
               prland(&land), xyas(land.lnd_x, land.lnd_y, player->cnum),
               damage);
        } else {
            mpr(own, "%s nuclear device did %d%% damage to %s at %s\n",
                cname(player->cnum), damage,
                prland(&land), xyas(land.lnd_x, land.lnd_y, own));
        }
        putland(land.lnd_uid, &land);
    }

    snxtitem_dist(&ni, EF_SHIP, x, y, rad);
    while (nxtitem(&ni, &ship)) {
        if ((own = ship.shp_own) == 0)
            continue;
        if ((damage = nukedamage(ncp, ni.curdist, airburst)) <= 0)
            continue;
        if (mchr[(int)ship.shp_type].m_flags & M_SUB) {
            struct sctstr sect1;

            /* Should we damage this sub? */
            getsect(ship.shp_x, ship.shp_y, &sect1);

            if (sect1.sct_type == SCT_BSPAN ||
                    sect1.sct_type == SCT_BTOWER ||
                    sect1.sct_type == SCT_WATER) {
                /* Ok, we're not in a harbor or trapped
                   inland.  Now, did we get pasted
                   directly? */
                if (ship.shp_x != x || ship.shp_y != y) {
                    /* Nope, so don't mess with it */
                    continue;
                }
            }
        }
        ship_damage(&ship, damage);
        if (own == player->cnum) {
            pr("%s at %s reports %d%% damage\n",
               prship(&ship), xyas(ship.shp_x, ship.shp_y, player->cnum),
               damage);
        } else {
            mpr(own, "%s nuclear device did %d%% damage to %s at %s\n",
                cname(player->cnum), damage, prship(&ship),
                xyas(ship.shp_x, ship.shp_y, own));
        }
        putship(ship.shp_uid, &ship);
    }

    snxtitem_dist(&ni, EF_NUKE, x, y, rad);
    while (nxtitem(&ni, &nuke)) {
        if ((own = nuke.nuk_own) == 0)
            continue;
        if ((damage = nukedamage(ncp, ni.curdist, airburst)) <= 0)
            continue;
        if (!pct_chance(damage))
            continue;
        nuke.nuk_effic = 0;
        if (own == player->cnum) {
            pr("%s at %s destroyed\n",
               prnuke(&nuke), xyas(nuke.nuk_x, nuke.nuk_y, player->cnum));
        } else {
            mpr(own, "%s nuclear device destroyed %s at %s\n",
                cname(player->cnum), prnuke(&nuke),
                xyas(nuke.nuk_x, nuke.nuk_y, own));
        }
        putnuke(ni.cur, &nuke);
    }

    return nukedamage(ncp, 0, airburst);
}
예제 #18
0
static void
look_land(struct lndstr *lookland)
{
    struct plnstr *pp;
    struct lndstr *lp;
    double drange;
    int range;
    int vrange;
    int i;
    int dist;

    drange = techfact(lookland->lnd_tech, lchr[lookland->lnd_type].l_spy);
    drange *= lookland->lnd_effic / 100.0;
    range = ldround(drange, 1);

    if (range == 0)
	return;

    for (i = 0; NULL != (lp = getlandp(i)); i++) {
	if (lp->lnd_own == player->cnum || lp->lnd_own == 0)
	    continue;
	if (lp->lnd_ship >= 0 || lp->lnd_land >= 0)
	    continue;
	/* Don't always see spies */
	if (lchr[(int)lp->lnd_type].l_flags & L_SPY) {
	    /* If it's on a ship or unit, assume it's hidden
	       enough not to be seen */
	    if (lp->lnd_ship >= 0 || lp->lnd_land >= 0)
		continue;
	    if (!(chance(LND_SPY_DETECT_CHANCE(lp->lnd_effic))))
		continue;
	}
	vrange = ldround((lnd_vis(lp) * range) / 20.0, 1);
	dist = mapdist(lp->lnd_x, lp->lnd_y,
		       lookland->lnd_x, lookland->lnd_y);
	if (dist > vrange)
	    continue;

	pr("%s %s (approx %d mil) @ %s\n",
	   prnatid(lp->lnd_own), prland(lp),
	   roundintby(lp->lnd_item[I_MILIT], 20),
	   xyas(lp->lnd_x, lp->lnd_y, player->cnum));
	if (opt_HIDDEN)
	    setcont(player->cnum, lp->lnd_own, FOUND_LOOK);
    }
    for (i = 0; NULL != (pp = getplanep(i)); i++) {
	if (pp->pln_own == player->cnum || pp->pln_own == 0)
	    continue;
	if (pp->pln_ship >= 0 || pp->pln_land >= 0)
	    continue;
	if (pp->pln_flags & PLN_LAUNCHED)
	    continue;
	vrange = ldround((10 * range) / 20.0, 1);
	dist = mapdist(pp->pln_x, pp->pln_y,
		       lookland->lnd_x, lookland->lnd_y);
	if (dist > vrange)
	    continue;

	pr("%s %s @ %s\n",
	   prnatid(pp->pln_own), prplane(pp),
	   xyas(pp->pln_x, pp->pln_y, player->cnum));
	if (opt_HIDDEN)
	    setcont(player->cnum, pp->pln_own, FOUND_LOOK);
    }
}