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; }
/* * Actually get the commod * * First, try to forage in the sector * Second look for a warehouse or headquarters to leech * Third, look for a ship we own in a harbor * Fourth, look for supplies in a supply unit we own * (one good reason to do this last is that the supply * unit will then call resupply, taking more time) * * May want to put code to resupply with SAMs here, later --ts */ static int s_commod(struct empobj *sink, short *vec, i_type type, int wanted, int limit, int actually_doit) { natid own = sink->own; coord x = sink->x; coord y = sink->y; int lookrange; struct sctstr sect; struct nstr_sect ns; struct nstr_item ni; struct lchrstr *lcp; struct shpstr ship; struct lndstr land; /* leave at least 1 military in sectors/ships */ int minimum = 0; int can_move; double move_cost, weight, mobcost; int packing; struct dchrstr *dp; struct ichrstr *ip; if (wanted > limit) wanted = limit; if (wanted <= vec[type]) return 1; wanted -= vec[type]; /* try to get it from sector we're in */ if (sink->ef_type != EF_SECTOR) { getsect(x, y, §); if (sect.sct_own == own) { if (!opt_NOFOOD && type == I_FOOD) minimum = 1 + (int)ceil(food_needed(sect.sct_item, etu_per_update)); if (sect.sct_item[type] - wanted >= minimum) { sect.sct_item[type] -= wanted; if (actually_doit) { vec[type] += wanted; putsect(§); put_empobj(sink->ef_type, sink->uid, sink); } return 1; } else if (sect.sct_item[type] - minimum > 0) { wanted -= sect.sct_item[type] - minimum; sect.sct_item[type] = minimum; if (actually_doit) { vec[type] += sect.sct_item[type] - minimum; putsect(§); } } } } /* look for a headquarters or warehouse */ lookrange = tfact(own, 10.0); snxtsct_dist(&ns, x, y, lookrange); while (nxtsct(&ns, §) && wanted) { if (ns.curdist == 0) continue; if (sect.sct_own != own) continue; if ((sect.sct_type != SCT_WAREH) && (sect.sct_type != SCT_HEADQ) && (sect.sct_type != SCT_HARBR)) continue; if ((sect.sct_type == SCT_HEADQ) && (sect.sct_dist_x == sect.sct_x) && (sect.sct_dist_y == sect.sct_y)) continue; if (sect.sct_effic < 60) continue; move_cost = path_find(sect.sct_x, sect.sct_y, x, y, own, MOB_MOVE); if (move_cost < 0) continue; if (!opt_NOFOOD && type == I_FOOD) minimum = 1 + (int)ceil(food_needed(sect.sct_item, etu_per_update)); if (sect.sct_item[type] <= minimum) continue; ip = &ichr[type]; dp = &dchr[sect.sct_type]; packing = ip->i_pkg[dp->d_pkg]; if (packing > 1 && sect.sct_effic < 60) packing = 1; weight = (double)ip->i_lbs / packing; mobcost = move_cost * weight; if (mobcost > 0) can_move = (double)sect.sct_mobil / mobcost; else can_move = sect.sct_item[type] - minimum; if (can_move > sect.sct_item[type] - minimum) can_move = sect.sct_item[type] - minimum; if (can_move >= wanted) { int n; sect.sct_item[type] -= wanted; /* take off mobility for delivering sect */ n = roundavg(wanted * weight * move_cost); sect.sct_mobil -= LIMIT_TO(n, 0, sect.sct_mobil); if (actually_doit) { vec[type] += wanted; putsect(§); put_empobj(sink->ef_type, sink->uid, sink); } return 1; } else if (can_move > 0) { int n; wanted -= can_move; sect.sct_item[type] -= can_move; /* take off mobility for delivering sect */ n = roundavg(can_move * weight * move_cost); sect.sct_mobil -= LIMIT_TO(n, 0, sect.sct_mobil); if (actually_doit) { vec[type] += can_move; putsect(§); } } } /* look for an owned ship in a harbor */ snxtitem_dist(&ni, EF_SHIP, x, y, lookrange); while (nxtitem(&ni, &ship) && wanted) { if (sink->ef_type == EF_SHIP && sink->uid == ship.shp_uid) continue; if (ship.shp_own != own) continue; if (!(mchr[(int)ship.shp_type].m_flags & M_SUPPLY)) continue; getsect(ship.shp_x, ship.shp_y, §); if (sect.sct_type != SCT_HARBR) continue; if (sect.sct_effic < 2) continue; move_cost = path_find(sect.sct_x, sect.sct_y, x, y, own, MOB_MOVE); if (move_cost < 0) continue; if (!opt_NOFOOD && type == I_FOOD) minimum = 1 + (int)ceil(food_needed(ship.shp_item, etu_per_update)); if (ship.shp_item[type] <= minimum) continue; ip = &ichr[type]; dp = &dchr[sect.sct_type]; packing = ip->i_pkg[dp->d_pkg]; if (packing > 1 && sect.sct_effic < 60) packing = 1; weight = (double)ip->i_lbs / packing; mobcost = move_cost * weight; if (mobcost > 0) can_move = (double)sect.sct_mobil / mobcost; else can_move = ship.shp_item[type] - minimum; if (can_move > ship.shp_item[type] - minimum) can_move = ship.shp_item[type] - minimum; if (can_move >= wanted) { int n; ship.shp_item[type] -= wanted; n = roundavg(wanted * weight * move_cost); sect.sct_mobil -= LIMIT_TO(n, 0, sect.sct_mobil); if (actually_doit) { vec[type] += can_move; putship(ship.shp_uid, &ship); if (n) putsect(§); put_empobj(sink->ef_type, sink->uid, sink); } return 1; } else if (can_move > 0) { int n; wanted -= can_move; ship.shp_item[type] -= can_move; n = roundavg(can_move * weight * move_cost); sect.sct_mobil -= LIMIT_TO(n, 0, sect.sct_mobil); if (actually_doit) { vec[type] += can_move; putship(ship.shp_uid, &ship); if (n) putsect(§); } } } /* look for an owned supply unit */ snxtitem_dist(&ni, EF_LAND, x, y, lookrange); while (nxtitem(&ni, &land) && wanted) { int min; if (sink->ef_type == EF_LAND && sink->uid == land.lnd_uid) continue; if (land.lnd_own != own) continue; lcp = &lchr[(int)land.lnd_type]; if (!(lcp->l_flags & L_SUPPLY)) continue; if (land.lnd_item[type] <= get_minimum(&land, type)) continue; if (land.lnd_ship >= 0) { getsect(land.lnd_x, land.lnd_y, §); if (sect.sct_type != SCT_HARBR || sect.sct_effic < 2) continue; } move_cost = path_find(land.lnd_x, land.lnd_y, x, y, own, MOB_MOVE); if (move_cost < 0) continue; #if 0 /* * Recursive supply is disabled for now. It can introduce * cycles into the "resupplies from" relation. The code below * attempts to break these cycles by temporarily zapping the * commodity being supplied. That puts the land file in a * funny state temporarily, risking loss of supplies when * something goes wrong on the way. Worse, it increases * lnd_seqno even when !actually_doit, which can lead to * spurious seqno mismatch oopses in users of * lnd_could_be_supplied(). I can't be bothered to clean up * this mess right now, because recursive resupply is too dumb * to be really useful anyway: each step uses the first source * it finds, without consideration of mobility cost. If you * re-enable it, don't forget to uncomment its documentation * in supply.t as well. */ if (land.lnd_item[type] - wanted < get_minimum(&land, type)) { struct lndstr save; /* * Temporarily zap this unit's store, so the recursion * avoids it. */ save = land; land.lnd_item[type] = 0; putland(land.lnd_uid, &land); save.lnd_seqno = land.lnd_seqno; s_commod((struct empobj *)&land, land.lnd_item, type, wanted, lchr[land.lnd_type].l_item[type] - wanted, actually_doit); land.lnd_item[type] += save.lnd_item[type]; if (actually_doit) putland(land.lnd_uid, &land); else putland(save.lnd_uid, &save); } #endif min = get_minimum(&land, type); ip = &ichr[type]; weight = ip->i_lbs; mobcost = move_cost * weight; if (mobcost > 0) can_move = (double)land.lnd_mobil / mobcost; else can_move = land.lnd_item[type] - min; if (can_move > land.lnd_item[type] - min) can_move = land.lnd_item[type] - min; if (can_move >= wanted) { land.lnd_item[type] -= wanted; land.lnd_mobil -= roundavg(wanted * weight * move_cost); if (actually_doit) { vec[type] += wanted; putland(land.lnd_uid, &land); put_empobj(sink->ef_type, sink->uid, sink); } return 1; } else if (can_move > 0) { wanted -= can_move; land.lnd_item[type] -= can_move; land.lnd_mobil -= roundavg(can_move * weight * move_cost); if (actually_doit) { vec[type] += can_move; putland(land.lnd_uid, &land); } } } if (actually_doit) put_empobj(sink->ef_type, sink->uid, sink); return 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, §)) { rad[ns.dy][ns.dx] = rad_char(§, 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"); }
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, §); 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, §)) { 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(§, 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(§); 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, §1); 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, §1); 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, §1); 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); }