/* * Range of a radar with @eff efficiency, @tlev tech, and @spy power. */ static int rad_range(int eff, double tlev, int spy) { int range; range = (int)techfact(tlev, spy); range = (int)(range * (eff / 100.0)); if (range < 1) range = 1; return range; }
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); }
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, §); 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, §)) { 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, §)) { 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; }
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, §); 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"); }
double speed_factor(double effspd, int tech) { return 480.0 / (effspd + techfact(tech, effspd)); }
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, §); sectdamage(§, dam); putsect(§); } } #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; }
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); } }
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, §); 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); } }