00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035 #include <config.h>
00036
00037 #include "commands.h"
00038 #include "map.h"
00039 #include "optlist.h"
00040 #include "path.h"
00041 #include "plane.h"
00042 #include "retreat.h"
00043 #include "ship.h"
00044
00045 static int blankrow(char *);
00046
00047 int
00048 sona(void)
00049 {
00050 struct nstr_item ni, nit;
00051 struct sctstr sect;
00052 struct shpstr ship;
00053 struct shpstr targ;
00054 struct natstr *natp;
00055 struct mchrstr *mcp;
00056 struct mchrstr *tmcp;
00057 struct nstr_sect ns;
00058 int range;
00059 int pingrange;
00060 int srange;
00061 int vrange;
00062 int dist;
00063 int x, y;
00064 int cx, cy;
00065 int changed = 0;
00066 int row;
00067
00068 static char **rad = NULL;
00069 static char *radbuf = NULL;
00070 static signed char **vis = NULL;
00071 static signed char *visbuf = NULL;
00072
00073 if (!snxtitem(&ni, EF_SHIP, player->argp[1]))
00074 return RET_SYN;
00075 if (!radbuf)
00076 radbuf = malloc((WORLD_Y * (WORLD_X + 1)));
00077 if (!visbuf)
00078 visbuf = malloc((WORLD_Y * (WORLD_X + 1)));
00079 if (!rad && radbuf) {
00080 rad = malloc(WORLD_Y * sizeof(char *));
00081 if (rad) {
00082 for (x = 0; x < WORLD_Y; x++) {
00083 rad[x] = &radbuf[(WORLD_X + 1) * x];
00084 }
00085 }
00086 }
00087 if (!vis && visbuf) {
00088 vis = malloc(WORLD_Y * sizeof(signed char *));
00089 if (vis) {
00090 for (x = 0; x < WORLD_Y; x++) {
00091 vis[x] = &visbuf[(WORLD_X + 1) * x];
00092 }
00093 }
00094 }
00095 if (!radbuf || !visbuf || !rad || !vis) {
00096 pr("Memory error, tell the deity.\n");
00097 logerror("malloc failed in sona\n");
00098 return RET_FAIL;
00099 }
00100 while (nxtitem(&ni, &ship)) {
00101 if (!player->owner)
00102 continue;
00103 mcp = &mchr[(int)ship.shp_type];
00104 if (!(mcp->m_flags & M_SONAR))
00105 continue;
00106 getsect(ship.shp_x, ship.shp_y, §);
00107 if (sect.sct_type != SCT_WATER)
00108 continue;
00109 range = (int)techfact(ship.shp_tech, mcp->m_vrnge);
00110 srange = MIN(7, 7 * range * ship.shp_effic / 200);
00111 pr("%s at %s efficiency %d%%, max range %d\n",
00112 prship(&ship),
00113 xyas(ship.shp_x, ship.shp_y, player->cnum),
00114 ship.shp_effic, srange);
00115 snxtsct_dist(&ns, ship.shp_x, ship.shp_y, srange);
00116 blankfill(radbuf, &ns.range, 1);
00117 while (nxtsct(&ns, §)) {
00118 if (player->owner || sect.sct_type == SCT_WATER)
00119 rad[ns.dy][ns.dx] = dchr[sect.sct_type].d_mnem;
00120 else {
00121 rad[ns.dy][ns.dx] = '?';
00122 }
00123 }
00124 snxtsct_dist(&ns, ship.shp_x, ship.shp_y, srange);
00125 cx = deltax(ship.shp_x, ns.range.lx);
00126 cy = deltay(ship.shp_y, ns.range.ly);
00127 while (nxtsct(&ns, §)) {
00128 if (!line_of_sight(rad, cx, cy, ns.dx, ns.dy)) {
00129 rad[ns.dy][ns.dx] = ' ';
00130 continue;
00131 }
00132 if (ship.shp_tech >= 310 && sect.sct_type == SCT_WATER) {
00133 if (sect.sct_mines) {
00134 pr("Sonar detects %d mines in %s!\n",
00135 sect.sct_mines,
00136 xyas(sect.sct_x, sect.sct_y, player->cnum));
00137 rad[ns.dy][ns.dx] = 'X';
00138 }
00139 }
00140 changed |= map_set(player->cnum, sect.sct_x, sect.sct_y,
00141 rad[ns.dy][ns.dx], 0);
00142
00143 }
00144 memset(visbuf, 0, (WORLD_Y * (WORLD_X + 1)));
00145 snxtitem_dist(&nit, EF_SHIP, ship.shp_x, ship.shp_y, range);
00146 while (nxtitem(&nit, &targ)) {
00147 if (targ.shp_own == player->cnum || targ.shp_own == 0)
00148 continue;
00149 tmcp = &mchr[(int)targ.shp_type];
00150 pingrange = MIN(7, MAX(targ.shp_visib, 10) * range / 10);
00151 vrange = pingrange * ship.shp_effic / 200;
00152 dist = mapdist(targ.shp_x, targ.shp_y, ship.shp_x, ship.shp_y);
00153 pingrange = (MAX(pingrange, 2) * targ.shp_effic) / 100;
00154 if (dist > pingrange)
00155 continue;
00156 if (tmcp->m_flags & M_SONAR && targ.shp_own) {
00157 natp = getnatp(targ.shp_own);
00158 if (natp->nat_flags & NF_SONAR)
00159 wu(0, targ.shp_own,
00160 "Sonar ping from %s detected by %s!\n",
00161 xyas(ship.shp_x, ship.shp_y,
00162 targ.shp_own), prship(&targ));
00163 if (targ.shp_rflags & RET_SONARED) {
00164 retreat_ship(&targ, 's');
00165 putship(targ.shp_uid, &targ);
00166 }
00167 }
00168 if (dist > vrange)
00169 continue;
00170 x = deltx(&ns.range, (int)targ.shp_x);
00171 y = delty(&ns.range, (int)targ.shp_y);
00172 if (rad[y][x] != dchr[SCT_WATER].d_mnem && rad[y][x] != 'X')
00173 continue;
00174 if (tmcp->m_flags & M_SUB &&
00175 getrel(getnatp(targ.shp_own), player->cnum) < FRIENDLY) {
00176 if (mcp->m_vrnge + targ.shp_visib < 8)
00177 pr("Sonar detects sub #%d @ %s\n",
00178 targ.shp_uid,
00179 xyas(targ.shp_x, targ.shp_y, player->cnum));
00180 else if (mcp->m_vrnge + targ.shp_visib < 10)
00181 pr("Sonar detects %s @ %s\n",
00182 prship(&targ),
00183 xyas(targ.shp_x, targ.shp_y, player->cnum));
00184 else
00185 pr("Sonar detects %s %s @ %s\n",
00186 cname(targ.shp_own), prship(&targ),
00187 xyas(targ.shp_x, targ.shp_y, player->cnum));
00188 } else
00189 pr("Sonar detects %s %s @ %s\n",
00190 cname(targ.shp_own), prship(&targ),
00191 xyas(targ.shp_x, targ.shp_y, player->cnum));
00192
00193 if (targ.shp_visib > vis[y][x]) {
00194 vis[y][x] = targ.shp_visib;
00195
00196 rad[y][x] = (*mchr[(int)targ.shp_type].m_name) & ~0x20;
00197 }
00198 }
00199 if (!player->argp[2]) {
00200 rad[cy][cx] = '0';
00201 for (row = 0; row < ns.range.height; row++)
00202 if (!blankrow(rad[row]))
00203 pr("%s\n", rad[row]);
00204 }
00205 pr("\n");
00206
00207 }
00208 if (changed)
00209 writemap(player->cnum);
00210 return RET_OK;
00211 }
00212
00213 void
00214 plane_sona(struct emp_qelem *plane_list, int x, int y,
00215 struct shiplist **head)
00216 {
00217 struct plnstr *pp;
00218 struct plchrstr *pcp;
00219 struct mchrstr *tmcp;
00220 struct shpstr *targ, s;
00221 struct natstr *natp;
00222 struct emp_qelem *qp;
00223 struct emp_qelem *next;
00224 struct plist *ip;
00225 struct sctstr sect;
00226 int found = 0;
00227 int range, i;
00228 int pingrange;
00229 int vrange;
00230 int dist;
00231
00232 getsect(x, y, §);
00233 if ((sect.sct_type != SCT_WATER) && (sect.sct_type != SCT_HARBR))
00234 return;
00235 for (qp = plane_list->q_forw; qp != plane_list; qp = next) {
00236 next = qp->q_forw;
00237 ip = (struct plist *)qp;
00238 pp = &ip->plane;
00239 pcp = ip->pcp;
00240 if (!(pcp->pl_flags & P_A))
00241 continue;
00242 range = (int)techfact(pp->pln_tech, (100.0 - pp->pln_acc) / 10.0);
00243 for (i = 0; getship(i, &s); i++) {
00244 targ = &s;
00245 if (targ->shp_own == pp->pln_own || targ->shp_own == 0)
00246 continue;
00247 if (on_shiplist(targ->shp_uid, *head))
00248 continue;
00249 tmcp = &mchr[(int)targ->shp_type];
00250 if (!(tmcp->m_flags & M_SUB))
00251 continue;
00252 if (roll(100) > pln_identchance(pp, shp_hardtarget(targ),
00253 EF_SHIP))
00254 continue;
00255 pingrange = MAX(targ->shp_visib, 10) * range / 10;
00256 vrange = pingrange * (pp->pln_effic / 200.0);
00257 dist = mapdist(targ->shp_x, targ->shp_y, x, y);
00258 pingrange = (MAX(pingrange, 2) * targ->shp_effic);
00259 pingrange = roundavg(pingrange / 100.0);
00260 if (dist > pingrange)
00261 continue;
00262 if (tmcp->m_flags & M_SONAR && targ->shp_own) {
00263 natp = getnatp(targ->shp_own);
00264 if (natp->nat_flags & NF_SONAR)
00265 wu(0, targ->shp_own,
00266 "Sonar ping from %s detected by %s!\n",
00267 xyas(x, y, targ->shp_own), prship(targ));
00268 }
00269 if ((dist > vrange))
00270 continue;
00271 add_shiplist(targ->shp_uid, head);
00272 if (!found) {
00273 mpr(pp->pln_own,
00274 "\nSonar contact in %s\n", xyas(x, y, pp->pln_own));
00275 found = 1;
00276 }
00277 if (getrel(getnatp(targ->shp_own), pp->pln_own) < FRIENDLY &&
00278 roll(100) > pln_identchance(pp, shp_hardtarget(targ),
00279 EF_SHIP))
00280 if (roll(100) > pln_identchance(pp, shp_hardtarget(targ),
00281 EF_SHIP))
00282 mpr(pp->pln_own, "sub #%d %s\n", targ->shp_uid,
00283 xyas(targ->shp_x, targ->shp_y, pp->pln_own));
00284 else
00285 mpr(pp->pln_own, "%s %s\n",
00286 prship(targ),
00287 xyas(targ->shp_x, targ->shp_y, pp->pln_own));
00288 else
00289 mpr(pp->pln_own, "%s %s @ %s\n",
00290 cname(targ->shp_own), prship(targ),
00291 xyas(targ->shp_x, targ->shp_y, pp->pln_own));
00292 }
00293 }
00294 }
00295
00296
00297
00298
00299
00300
00301 #define DOT(ax,ay,bx,by) ((ax)*(bx) + (ay)*(by))
00302 #define LEN(x,y) ((x)*(x) + (y)*(y))
00303 #define DIST(ax,ay,bx,by) LEN(bx - ax, by -ay)
00304
00305 int
00306 line_of_sight(char **rad, int ax, int ay, int bx, int by)
00307 {
00308 int dxn = XNORM(bx - ax);
00309 int dyn = YNORM(by - ay);
00310 int dx = dxn > WORLD_X / 2 ? dxn - WORLD_X : dxn;
00311 int dy = dyn > WORLD_Y / 2 ? dyn - WORLD_Y : dyn;
00312 int dlen = LEN(dx, dy);
00313 int n;
00314 int cx = 0;
00315 int cy = 0;
00316 int tx, ty;
00317 double cd_dist = dlen;
00318 double md_dist;
00319 double td_dist;
00320 double td_proj;
00321 int closest;
00322 int blocked = 0;
00323 struct sctstr *sectp;
00324
00325 while (cd_dist) {
00326 if (blocked)
00327 return 0;
00328 md_dist = 100;
00329 closest = -1;
00330 for (n = 1; n <= 6; ++n) {
00331 tx = cx + diroff[n][0];
00332 ty = cy + diroff[n][1];
00333 if (DIST(tx, ty, dx, dy) >= cd_dist)
00334 continue;
00335 td_proj = (double)DOT(tx, ty, dx, dy) / dlen;
00336 td_dist = DIST(tx, ty, td_proj * dx, td_proj * dy);
00337 if (td_dist < md_dist) {
00338 md_dist = td_dist;
00339 closest = n;
00340 }
00341 }
00342 if (CANT_HAPPEN(closest < 0))
00343 return 0;
00344 cx = cx + diroff[closest][0];
00345 cy = cy + diroff[closest][1];
00346 if (rad) {
00347 blocked = (rad[YNORM(ay + cy)][XNORM(ax + cx)]
00348 != dchr[SCT_WATER].d_mnem);
00349 } else {
00350 sectp = getsectp((ax + cx), (ay + cy));
00351 if (sectp) {
00352 if (sectp->sct_type == SCT_WATER ||
00353 sectp->sct_type == SCT_BSPAN) {
00354 blocked = 0;
00355 } else {
00356 blocked = 1;
00357 }
00358 }
00359 }
00360 cd_dist = DIST(cx, cy, dx, dy);
00361 }
00362 return 1;
00363 }
00364
00365 static int
00366 blankrow(char *s)
00367 {
00368 while (*s) {
00369 if (*s != ' ')
00370 return 0;
00371 ++s;
00372 }
00373 return 1;
00374 }