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
00036 #include <config.h>
00037
00038 #include <math.h>
00039 #include <stdlib.h>
00040 #include "damage.h"
00041 #include "file.h"
00042 #include "map.h"
00043 #include "misc.h"
00044 #include "mission.h"
00045 #include "nsc.h"
00046 #include "optlist.h"
00047 #include "path.h"
00048 #include "player.h"
00049 #include "prototypes.h"
00050 #include "queue.h"
00051 #include "server.h"
00052 #include "xy.h"
00053 #include "empobj.h"
00054 #include "unit.h"
00055
00056 static int shp_check_one_mines(struct ulist *);
00057 static int shp_hit_mine(struct shpstr *, struct mchrstr *);
00058 static void shp_mess(char *, struct ulist *);
00059
00060 void
00061 shp_sel(struct nstr_item *ni, struct emp_qelem *list)
00062
00063
00064
00065
00066
00067 {
00068 struct shpstr ship;
00069 struct mchrstr *mcp;
00070 struct ulist *mlp;
00071
00072 emp_initque(list);
00073 while (nxtitem(ni, &ship)) {
00074 if (!player->owner)
00075 continue;
00076 mcp = &mchr[(int)ship.shp_type];
00077
00078
00079
00080
00081
00082 if (opt_MARKET) {
00083 if (ontradingblock(EF_SHIP, &ship)) {
00084 pr("ship #%d inelligible - it's for sale.\n",
00085 ship.shp_uid);
00086 continue;
00087 }
00088 }
00089
00090
00091
00092
00093
00094
00095
00096
00097
00098
00099
00100
00101 ship.shp_mission = 0;
00102 ship.shp_rflags = 0;
00103 memset(ship.shp_rpath, 0, sizeof(ship.shp_rpath));
00104 putship(ship.shp_uid, &ship);
00105 mlp = malloc(sizeof(struct ulist));
00106 mlp->chrp = (struct empobj_chr *)mcp;
00107 mlp->unit.ship = ship;
00108 mlp->mobil = ship.shp_mobil;
00109 emp_insque(&mlp->queue, list);
00110 }
00111 }
00112
00113
00114 void
00115 shp_nav(struct emp_qelem *list, double *minmobp, double *maxmobp,
00116 int *togetherp, natid actor)
00117 {
00118 struct emp_qelem *qp;
00119 struct emp_qelem *next;
00120 struct ulist *mlp;
00121 struct sctstr sect;
00122 struct shpstr ship;
00123 coord allx;
00124 coord ally;
00125 int first = 1;
00126
00127 *minmobp = 9876.0;
00128 *maxmobp = -9876.0;
00129 *togetherp = 1;
00130 for (qp = list->q_back; qp != list; qp = next) {
00131 next = qp->q_back;
00132 mlp = (struct ulist *)qp;
00133 getship(mlp->unit.ship.shp_uid, &ship);
00134 if (ship.shp_own != actor) {
00135 mpr(actor, "%s was sunk at %s\n",
00136 prship(&ship), xyas(ship.shp_x, ship.shp_y, actor));
00137 emp_remque((struct emp_qelem *)mlp);
00138 free(mlp);
00139 continue;
00140 }
00141 if (opt_SAIL) {
00142 if (*ship.shp_path && !update_running) {
00143 shp_mess("has a sail path", mlp);
00144 mpr(actor, "Use `sail <#> -' to reset\n");
00145 continue;
00146 }
00147 }
00148
00149 if (ship.shp_item[I_MILIT] == 0 && ship.shp_item[I_CIVIL] == 0) {
00150 shp_mess("is crewless", mlp);
00151 continue;
00152 }
00153 if (!getsect(ship.shp_x, ship.shp_y, §)) {
00154 shp_mess("was sucked into the sky by a strange looking spaceship", mlp);
00155 continue;
00156 }
00157 switch (shp_check_nav(§, &ship)) {
00158 case CN_CONSTRUCTION:
00159 shp_mess("is caught in a construction zone", mlp);
00160 continue;
00161 case CN_LANDLOCKED:
00162 shp_mess("is landlocked", mlp);
00163 continue;
00164 case CN_NAVIGABLE:
00165 break;
00166 case CN_ERROR:
00167 default:
00168 shp_mess("was just swallowed by a big green worm", mlp);
00169 continue;
00170 }
00171 if (first) {
00172 allx = ship.shp_x;
00173 ally = ship.shp_y;
00174 first = 0;
00175 }
00176 if (ship.shp_x != allx || ship.shp_y != ally)
00177 *togetherp = 0;
00178 if (ship.shp_mobil + 1 < (int)mlp->mobil) {
00179 mlp->mobil = ship.shp_mobil;
00180 }
00181 if (mlp->mobil < *minmobp)
00182 *minmobp = mlp->mobil;
00183 if (mlp->mobil > *maxmobp)
00184 *maxmobp = mlp->mobil;
00185 mlp->unit.ship = ship;
00186 }
00187 }
00188
00189 int
00190 shp_sweep(struct emp_qelem *ship_list, int verbose, int takemob, natid actor)
00191 {
00192 struct emp_qelem *qp;
00193 struct emp_qelem *next;
00194 struct ulist *mlp;
00195 struct sctstr sect;
00196 int mines, m, max, shells;
00197 int changed = 0;
00198 int stopping = 0;
00199
00200 for (qp = ship_list->q_back; qp != ship_list; qp = next) {
00201 next = qp->q_back;
00202 mlp = (struct ulist *)qp;
00203 if (!(((struct mchrstr *)mlp->chrp)->m_flags & M_SWEEP)) {
00204 if (verbose)
00205 mpr(actor, "%s doesn't have minesweeping capability!\n",
00206 prship(&mlp->unit.ship));
00207 continue;
00208 }
00209 if (takemob && mlp->mobil <= 0.0) {
00210 if (verbose)
00211 mpr(actor, "%s is out of mobility!\n",
00212 prship(&mlp->unit.ship));
00213 continue;
00214 }
00215 getsect(mlp->unit.ship.shp_x, mlp->unit.ship.shp_y, §);
00216 if (sect.sct_type != SCT_WATER) {
00217 if (verbose)
00218 mpr(actor, "%s is not at sea. No mines there!\n",
00219 prship(&mlp->unit.ship));
00220 continue;
00221 }
00222 if (takemob) {
00223 mlp->mobil -= shp_mobcost(&mlp->unit.ship);
00224 mlp->unit.ship.shp_mobil = (int)mlp->mobil;
00225 }
00226 putship(mlp->unit.ship.shp_uid, &mlp->unit.ship);
00227 if (!(mines = sect.sct_mines))
00228 continue;
00229 max = ((struct mchrstr *)mlp->chrp)->m_item[I_SHELL];
00230 shells = mlp->unit.ship.shp_item[I_SHELL];
00231 for (m = 0; mines > 0 && m < 5; m++) {
00232 if (chance(0.66)) {
00233 mpr(actor, "Sweep...\n");
00234 mines--;
00235 shells = MIN(max, shells + 1);
00236 changed |= map_set(actor, sect.sct_x, sect.sct_y, 'X', 0);
00237 }
00238 }
00239 sect.sct_mines = mines;
00240 mlp->unit.ship.shp_item[I_SHELL] = shells;
00241 if (shp_check_one_mines(mlp)) {
00242 stopping = 1;
00243 emp_remque(qp);
00244 free(qp);
00245 }
00246 putship(mlp->unit.ship.shp_uid, &mlp->unit.ship);
00247 putsect(§);
00248 }
00249 if (changed)
00250 writemap(actor);
00251 return stopping;
00252 }
00253
00254 static int
00255 shp_check_one_mines(struct ulist *mlp)
00256 {
00257 struct sctstr sect;
00258 int actor;
00259
00260 getsect(mlp->unit.ship.shp_x, mlp->unit.ship.shp_y, §);
00261 if (sect.sct_type != SCT_WATER)
00262 return 0;
00263 if (!sect.sct_mines)
00264 return 0;
00265 if (chance(DMINE_HITCHANCE(sect.sct_mines))) {
00266 actor = mlp->unit.ship.shp_own;
00267 shp_hit_mine(&mlp->unit.ship, ((struct mchrstr *)mlp->chrp));
00268 sect.sct_mines--;
00269 if (map_set(actor, sect.sct_x, sect.sct_y, 'X', 0))
00270 writemap(actor);
00271 putsect(§);
00272 putship(mlp->unit.ship.shp_uid, &mlp->unit.ship);
00273 if (!mlp->unit.ship.shp_own)
00274 return 1;
00275 }
00276 return 0;
00277 }
00278
00279 static int
00280 shp_check_mines(struct emp_qelem *ship_list)
00281 {
00282 struct emp_qelem *qp;
00283 struct emp_qelem *next;
00284 struct ulist *mlp;
00285 int stopping = 0;
00286
00287 for (qp = ship_list->q_back; qp != ship_list; qp = next) {
00288 next = qp->q_back;
00289 mlp = (struct ulist *)qp;
00290 if (shp_check_one_mines(mlp)) {
00291 stopping = 1;
00292 emp_remque(qp);
00293 free(qp);
00294 }
00295 }
00296 return stopping;
00297 }
00298
00299
00300 static void
00301 shp_mess(char *str, struct ulist *mlp)
00302 {
00303 mpr(mlp->unit.ship.shp_own, "%s %s & stays in %s\n",
00304 prship(&mlp->unit.ship),
00305 str, xyas(mlp->unit.ship.shp_x, mlp->unit.ship.shp_y,
00306 mlp->unit.ship.shp_own));
00307 mlp->unit.ship.shp_mobil = (int)mlp->mobil;
00308 putship(mlp->unit.ship.shp_uid, &mlp->unit.ship);
00309 emp_remque((struct emp_qelem *)mlp);
00310 free(mlp);
00311 }
00312
00313 int
00314 shp_check_nav(struct sctstr *sect, struct shpstr *shp)
00315 {
00316 switch (dchr[sect->sct_type].d_nav) {
00317 case NAVOK:
00318 break;
00319 case NAV_CANAL:
00320 if (mchr[(int)shp->shp_type].m_flags & M_CANAL) {
00321 if (sect->sct_effic < 2)
00322 return CN_CONSTRUCTION;
00323 } else
00324 return CN_LANDLOCKED;
00325 break;
00326 case NAV_02:
00327 if (sect->sct_effic < 2)
00328 return CN_CONSTRUCTION;
00329 break;
00330 case NAV_60:
00331 if (sect->sct_effic < 60)
00332 return CN_CONSTRUCTION;
00333 break;
00334 default:
00335 return CN_LANDLOCKED;
00336 }
00337 return CN_NAVIGABLE;
00338 }
00339
00340 int
00341 sect_has_dock(struct sctstr *sect)
00342 {
00343 switch (dchr[sect->sct_type].d_nav) {
00344 case NAV_02:
00345 case NAV_CANAL:
00346 return 1;
00347 default:
00348 return 0;
00349 }
00350 }
00351
00352 static int
00353 shp_count(struct emp_qelem *list, int wantflags, int nowantflags,
00354 int x, int y)
00355 {
00356 struct emp_qelem *qp;
00357 struct emp_qelem *next;
00358 struct ulist *mlp;
00359 int count = 0;
00360
00361 for (qp = list->q_back; qp != list; qp = next) {
00362 next = qp->q_back;
00363 mlp = (struct ulist *)qp;
00364 if (mlp->unit.ship.shp_x != x || mlp->unit.ship.shp_y != y)
00365 continue;
00366 if (wantflags &&
00367 (((struct mchrstr *)mlp->chrp)->m_flags & wantflags) != wantflags)
00368 continue;
00369 if (nowantflags &&
00370 ((struct mchrstr *)mlp->chrp)->m_flags & nowantflags)
00371 continue;
00372 ++count;
00373 }
00374 return count;
00375 }
00376
00377 static void
00378 shp_damage_one(struct ulist *mlp, int dam)
00379 {
00380 shipdamage(&mlp->unit.ship, dam);
00381 putship(mlp->unit.ship.shp_uid, &mlp->unit.ship);
00382 if (!mlp->unit.ship.shp_own) {
00383 emp_remque((struct emp_qelem *)mlp);
00384 free(mlp);
00385 }
00386 }
00387
00388 static int
00389 shp_damage(struct emp_qelem *list, int totdam, int wantflags,
00390 int nowantflags, int x, int y)
00391 {
00392 struct emp_qelem *qp;
00393 struct emp_qelem *next;
00394 struct ulist *mlp;
00395 int dam;
00396 int count;
00397
00398 if (!totdam
00399 || !(count = shp_count(list, wantflags, nowantflags, x, y)))
00400 return 0;
00401 dam = ldround((double)totdam / count, 1);
00402 for (qp = list->q_back; qp != list; qp = next) {
00403 next = qp->q_back;
00404 mlp = (struct ulist *)qp;
00405 if (mlp->unit.ship.shp_x != x || mlp->unit.ship.shp_y != y)
00406 continue;
00407 if (wantflags &&
00408 (((struct mchrstr *)mlp->chrp)->m_flags & wantflags) != wantflags)
00409 continue;
00410 if (nowantflags &&
00411 ((struct mchrstr *)mlp->chrp)->m_flags & nowantflags)
00412 continue;
00413 shp_damage_one(mlp, dam);
00414 }
00415 return dam;
00416 }
00417
00418 static int
00419 shp_contains(struct emp_qelem *list, int newx, int newy, int wantflags,
00420 int nowantflags)
00421 {
00422 struct emp_qelem *qp;
00423 struct emp_qelem *next;
00424 struct ulist *mlp;
00425
00426 for (qp = list->q_back; qp != list; qp = next) {
00427 next = qp->q_back;
00428 mlp = (struct ulist *)qp;
00429
00430 if (newx != mlp->unit.ship.shp_x || newy != mlp->unit.ship.shp_y)
00431 continue;
00432 if (wantflags &&
00433 (((struct mchrstr *)mlp->chrp)->m_flags & wantflags) != wantflags)
00434 continue;
00435 if (nowantflags &&
00436 ((struct mchrstr *)mlp->chrp)->m_flags & nowantflags)
00437 continue;
00438 return 1;
00439 }
00440 return 0;
00441 }
00442
00443 static struct ulist *
00444 most_valuable_ship(struct emp_qelem *list)
00445 {
00446 struct emp_qelem *qp;
00447 struct emp_qelem *next;
00448 struct ulist *mlp;
00449 struct ulist *mvs = 0;
00450
00451 for (qp = list->q_back; qp != list; qp = next) {
00452 next = qp->q_back;
00453 mlp = (struct ulist *)qp;
00454 if (((struct mchrstr *)mlp->chrp)->m_flags & M_SUB)
00455 continue;
00456 if (!((struct mchrstr *)mlp->chrp)->m_nxlight &&
00457 !((struct mchrstr *)mlp->chrp)->m_nchoppers &&
00458 ((struct mchrstr *)mlp->chrp)->m_cost < 1000 &&
00459 !((struct mchrstr *)mlp->chrp)->m_nplanes &&
00460 !((struct mchrstr *)mlp->chrp)->m_nland)
00461 continue;
00462 if (!mvs) {
00463 mvs = mlp;
00464 continue;
00465 }
00466 if (((struct mchrstr *)mlp->chrp)->m_cost * mlp->unit.ship.shp_effic >
00467 ((struct mchrstr *)mlp->chrp)->m_cost * mvs->unit.ship.shp_effic)
00468 mvs = mlp;
00469 }
00470 return mvs;
00471 }
00472
00473 static int
00474 shp_easiest_target(struct emp_qelem *list, int wantflags, int nowantflags)
00475 {
00476 struct emp_qelem *qp;
00477 struct emp_qelem *next;
00478 struct ulist *mlp;
00479 int hard;
00480 int easiest = 9876;
00481 int count = 0;
00482
00483 for (qp = list->q_back; qp != list; qp = next) {
00484 next = qp->q_back;
00485 mlp = (struct ulist *)qp;
00486 if (wantflags &&
00487 (((struct mchrstr *)mlp->chrp)->m_flags & wantflags) != wantflags)
00488 continue;
00489 if (nowantflags &&
00490 ((struct mchrstr *)mlp->chrp)->m_flags & nowantflags)
00491 continue;
00492 hard = shp_hardtarget(&mlp->unit.ship);
00493 if (hard < easiest)
00494 easiest = hard;
00495 ++count;
00496 }
00497 return easiest - count;
00498 }
00499
00500 static int
00501 shp_missile_interdiction(struct emp_qelem *list, coord newx, coord newy,
00502 natid victim)
00503 {
00504 int dam;
00505 int twotries;
00506 int stopping = 0;
00507 struct emp_qelem msl_list, *qp, *newqp;
00508 struct ulist *mvs;
00509 char what[512];
00510
00511 msl_sel(&msl_list, newx, newy, victim, P_T | P_MAR, 0, MI_INTERDICT);
00512
00513 twotries = 0;
00514 while (!QEMPTY(&msl_list) && (mvs = most_valuable_ship(list))) {
00515 sprintf(what, "%s", prship(&mvs->unit.ship));
00516 dam = msl_launch_mindam(&msl_list, newx, newy,
00517 shp_hardtarget(&mvs->unit.ship),
00518 EF_SHIP, 1, what, victim, MI_INTERDICT);
00519 if (dam) {
00520 mpr(victim,
00521 "missile interdiction mission does %d damage to %s!\n",
00522 dam, what);
00523 shp_damage_one(mvs, dam);
00524 twotries = 0;
00525 stopping |= 1;
00526 } else if (++twotries >= 2) {
00527 break;
00528 }
00529 }
00530 qp = msl_list.q_forw;
00531 while (qp != msl_list.q_forw) {
00532 newqp = qp->q_forw;
00533 emp_remque(qp);
00534 free(qp);
00535 qp = newqp;
00536 }
00537
00538 return stopping;
00539 }
00540
00541
00542
00543
00544
00545 static int
00546 notify_coastguard(struct emp_qelem *list, int trange, struct sctstr *sectp)
00547 {
00548 struct emp_qelem *qp;
00549 struct emp_qelem *next;
00550 struct ulist *mlp;
00551 struct natstr *natp;
00552 int vrange;
00553
00554 natp = getnatp(sectp->sct_own);
00555
00556 vrange = sectp->sct_type == SCT_RADAR ? 14 : 4;
00557 vrange *= tfact(sectp->sct_own, 1.0) * sectp->sct_effic / 100.0;
00558
00559 if (vrange < 1)
00560 vrange = 1;
00561
00562 if (vrange < trange)
00563 return 0;
00564
00565 for (qp = list->q_back; qp != list; qp = next) {
00566 next = qp->q_back;
00567 mlp = (struct ulist *)qp;
00568 if (((struct mchrstr *)mlp->chrp)->m_flags & M_SUB)
00569 continue;
00570 if (natp->nat_flags & NF_COASTWATCH)
00571 wu(0, sectp->sct_own,
00572 "%s %s sighted at %s\n",
00573 cname(mlp->unit.ship.shp_own),
00574 prship(&mlp->unit.ship),
00575 xyas(mlp->unit.ship.shp_x, mlp->unit.ship.shp_y,
00576 sectp->sct_own));
00577 if (opt_HIDDEN)
00578 setcont(sectp->sct_own, mlp->unit.ship.shp_own, FOUND_COAST);
00579 }
00580
00581 return 1;
00582 }
00583
00584 static int
00585 shp_fort_interdiction(struct emp_qelem *list, coord newx, coord newy,
00586 natid victim)
00587 {
00588 struct nstr_sect ns;
00589 struct sctstr fsect;
00590 int trange, range;
00591 double guneff;
00592 int shell, gun;
00593 int dam;
00594 int totdam = 0;
00595 signed char notified[MAXNOC];
00596 int i;
00597
00598
00599 for (i = 0; i < MAXNOC; ++i) {
00600 if (getrel(getnatp(i), victim) <= NEUTRAL)
00601 notified[i] = 0;
00602 else
00603 notified[i] = 1;
00604 }
00605
00606 snxtsct_dist(&ns, newx, newy, fort_max_interdiction_range);
00607 while (nxtsct(&ns, &fsect)) {
00608 if (!fsect.sct_own)
00609 continue;
00610 if (fsect.sct_own == victim)
00611 continue;
00612 if (notified[fsect.sct_own])
00613 continue;
00614 trange = mapdist(newx, newy, fsect.sct_x, fsect.sct_y);
00615 if (notify_coastguard(list, trange, &fsect))
00616 notified[fsect.sct_own] = 1;
00617 }
00618 if (opt_NO_FORT_FIRE)
00619 return 0;
00620
00621 for (i = 0; i < MAXNOC; ++i) {
00622 if (getrel(getnatp(i), victim) >= NEUTRAL)
00623 notified[i] = 0;
00624 }
00625 snxtsct_dist(&ns, newx, newy, fort_max_interdiction_range);
00626 while (nxtsct(&ns, &fsect)) {
00627 if (!notified[fsect.sct_own])
00628 continue;
00629 gun = fsect.sct_item[I_GUN];
00630 if (gun < 1)
00631 continue;
00632 range = roundrange(fortrange(&fsect));
00633 trange = mapdist(newx, newy, fsect.sct_x, fsect.sct_y);
00634 if (trange > range)
00635 continue;
00636 if (fsect.sct_item[I_MILIT] < 5)
00637 continue;
00638 shell = fsect.sct_item[I_SHELL];
00639 if (shell < 1)
00640 shell += supply_commod(fsect.sct_own, fsect.sct_x, fsect.sct_y,
00641 I_SHELL, 1);
00642 if (shell < 1)
00643 continue;
00644 shell--;
00645 fsect.sct_item[I_SHELL] = shell;
00646 putsect(&fsect);
00647 if (gun > 7)
00648 gun = 7;
00649 guneff = landgun((int)fsect.sct_effic, gun);
00650 dam = (int)guneff;
00651 totdam += dam;
00652 mpr(victim, "Incoming fire does %d damage!\n", dam);
00653
00654
00655
00656
00657
00658 wu(0, fsect.sct_own,
00659 "%s fires at %s ships in %s for %d!\n",
00660 xyas(fsect.sct_x, fsect.sct_y,
00661 fsect.sct_own),
00662 cname(victim), xyas(newx, newy, fsect.sct_own), dam);
00663 nreport(fsect.sct_own, N_SHP_SHELL, victim, 1);
00664 }
00665 if (totdam > 0)
00666 return shp_damage(list, totdam, 0, M_SUB, newx, newy);
00667 return 0;
00668 }
00669
00670 static int
00671 shp_interdict(struct emp_qelem *list, coord newx, coord newy, natid victim)
00672 {
00673 int stopping = 0;
00674
00675 if (shp_contains(list, newx, newy, 0, M_SUB)) {
00676 stopping |= shp_fort_interdiction(list, newx, newy, victim);
00677
00678 if (shp_contains(list, newx, newy, 0, M_SUB)) {
00679 stopping |=
00680 shp_damage(list,
00681 unit_interdict(newx, newy, victim, "ships",
00682 shp_easiest_target(list, 0, M_SUB),
00683 MI_INTERDICT),
00684 0, M_SUB, newx, newy);
00685 if (most_valuable_ship(list)) {
00686 stopping |=
00687 shp_missile_interdiction(list, newx, newy, victim);
00688 }
00689 }
00690 }
00691 if (shp_contains(list, newx, newy, M_SUB, 0)) {
00692 stopping |=
00693 shp_damage(list,
00694 unit_interdict(newx, newy, victim, "subs",
00695 shp_easiest_target(list, M_SUB, 0),
00696 MI_SINTERDICT),
00697 M_SUB, 0, newx, newy);
00698 }
00699 return stopping;
00700 }
00701
00702
00703 int
00704 shp_hardtarget(struct shpstr *sp)
00705 {
00706 struct sctstr sect;
00707 int vis, onsea;
00708 struct mchrstr *mcp = mchr + sp->shp_type;
00709
00710 vis = sp->shp_visib;
00711 getsect(sp->shp_x, sp->shp_y, §);
00712 onsea = sect.sct_type == SCT_WATER;
00713 if (mcp->m_flags & M_SUB)
00714 vis *= 4;
00715 return (int)((sp->shp_effic / 100.0) *
00716 (20 + sp->shp_speed * onsea / 2.0 - vis));
00717 }
00718
00719 static int
00720 shp_hit_mine(struct shpstr *sp, struct mchrstr *mcp)
00721 {
00722 double m;
00723
00724 mpr(sp->shp_own, "Kawhomp! Mine detected in %s!\n",
00725 xyas(sp->shp_x, sp->shp_y, sp->shp_own));
00726
00727 nreport(sp->shp_own, N_HIT_MINE, 0, 1);
00728
00729 m = MINE_DAMAGE();
00730 if (mcp->m_flags & M_SWEEP)
00731 m /= 2.0;
00732
00733 shipdamage(sp, ldround(m, 1));
00734
00735 return (int)m;
00736 }
00737
00738 int
00739 shp_nav_one_sector(struct emp_qelem *list, int dir, natid actor,
00740 int together)
00741 {
00742 struct sctstr sect;
00743 struct emp_qelem *qp;
00744 struct emp_qelem *next;
00745 struct ulist *mlp;
00746 struct emp_qelem done;
00747 coord dx;
00748 coord dy;
00749 coord newx;
00750 coord newy;
00751 int stopping = 0;
00752 double mobcost;
00753 double tech;
00754 double tf;
00755 char dp[80];
00756 int navigate;
00757
00758 if (dir <= DIR_STOP || dir >= DIR_VIEW) {
00759 unit_put(list, actor);
00760 return 1;
00761 }
00762 dx = diroff[dir][0];
00763 dy = diroff[dir][1];
00764 for (qp = list->q_back; qp != list; qp = next) {
00765 next = qp->q_back;
00766 mlp = (struct ulist *)qp;
00767 newx = xnorm(mlp->unit.ship.shp_x + dx);
00768 newy = ynorm(mlp->unit.ship.shp_y + dy);
00769 getsect(newx, newy, §);
00770 navigate = shp_check_nav(§, &mlp->unit.ship);
00771 if (navigate != CN_NAVIGABLE ||
00772 (sect.sct_own && actor != sect.sct_own &&
00773 getrel(getnatp(sect.sct_own), actor) < FRIENDLY)) {
00774 if (dchr[sect.sct_type].d_nav == NAV_CANAL &&
00775 !(((struct mchrstr *)mlp->chrp)->m_flags & M_CANAL) &&
00776 navigate == CN_LANDLOCKED)
00777 sprintf(dp,
00778 "is too large to fit into the canal system at %s",
00779 xyas(newx, newy, actor));
00780 else
00781 sprintf(dp, "can't go to %s", xyas(newx, newy, actor));
00782 if (together) {
00783 mpr(actor, "%s\n", dp);
00784 return 2;
00785 } else {
00786 shp_mess(dp, mlp);
00787 continue;
00788 }
00789 }
00790
00791 if (mlp->mobil <= 0.0) {
00792 shp_mess("is out of mobility", mlp);
00793 continue;
00794 }
00795 mobcost = shp_mobcost(&mlp->unit.ship);
00796 mlp->unit.ship.shp_x = newx;
00797 mlp->unit.ship.shp_y = newy;
00798 if (mlp->mobil - mobcost < -127) {
00799 mlp->mobil = -127;
00800 } else {
00801 mlp->mobil -= mobcost;
00802 }
00803 mlp->unit.ship.shp_mobil = (int)mlp->mobil;
00804 putship(mlp->unit.ship.shp_uid, &mlp->unit.ship);
00805
00806
00807 tech = techfact(mlp->unit.ship.shp_tech,
00808 ((struct mchrstr *)mlp->chrp)->m_vrnge);
00809 if (((struct mchrstr *)mlp->chrp)->m_flags & M_SONAR)
00810 tf = techfact(mlp->unit.ship.shp_tech, 1.0);
00811 else
00812 tf = 0.0;
00813 radmapupd(mlp->unit.ship.shp_own,
00814 mlp->unit.ship.shp_x, mlp->unit.ship.shp_y,
00815 (int)mlp->unit.ship.shp_effic, (int)tech, tf);
00816 }
00817 if (QEMPTY(list))
00818 return stopping;
00819 stopping |= shp_sweep(list, 0, 0, actor);
00820 if (QEMPTY(list))
00821 return stopping;
00822 stopping |= shp_check_mines(list);
00823 if (QEMPTY(list))
00824 return stopping;
00825
00826
00827 emp_initque(&done);
00828 while (!QEMPTY(list)) {
00829 mlp = (struct ulist *)list->q_back;
00830 newx = mlp->unit.ship.shp_x;
00831 newy = mlp->unit.ship.shp_y;
00832 stopping |= shp_interdict(list, newx, newy, actor);
00833
00834 for (qp = list->q_back; qp != list; qp = next) {
00835 next = qp->q_back;
00836 mlp = (struct ulist *)qp;
00837 if (mlp->unit.ship.shp_x == newx &&
00838 mlp->unit.ship.shp_y == newy) {
00839 emp_remque(qp);
00840 emp_insque(qp, &done);
00841 }
00842 }
00843 }
00844
00845 emp_insque(list, &done);
00846 emp_remque(&done);
00847
00848 return stopping;
00849 }
00850
00851
00852
00853
00854
00855
00856
00857
00858
00859
00860 int
00861 shp_missile_defense(coord dx, coord dy, natid bombown, int hardtarget)
00862 {
00863 struct nstr_item ni;
00864 struct shpstr ship;
00865 int hitchance;
00866 int shell;
00867 double gun, eff, teff;
00868
00869 snxtitem_dist(&ni, EF_SHIP, dx, dy, 1);
00870
00871 while (nxtitem(&ni, &ship)) {
00872 if (!ship.shp_own)
00873 continue;
00874
00875 if (!(mchr[(int)ship.shp_type].m_flags & M_ANTIMISSILE))
00876 continue;
00877
00878 if (getrel(getnatp(ship.shp_own), bombown) >= NEUTRAL)
00879 continue;
00880
00881 if (ship.shp_effic < 60)
00882 continue;
00883
00884 shell = ship.shp_item[I_SHELL];
00885 if (ship.shp_item[I_MILIT] < 1)
00886 continue;
00887 if (shell < 2) {
00888 shell += supply_commod(ship.shp_own, ship.shp_x, ship.shp_y,
00889 I_SHELL, 2);
00890 if (shell < 2)
00891 continue;
00892 }
00893 if (ship.shp_item[I_GUN] < 1)
00894 continue;
00895
00896
00897 gun = MIN(ship.shp_item[I_GUN], ship.shp_glim);
00898 eff = ship.shp_effic / 100.0;
00899 teff = ship.shp_tech / (ship.shp_tech + 200.0);
00900
00901 hitchance = (int)(gun * eff * teff * 4.5) - hardtarget;
00902 if (hitchance < 0)
00903 hitchance = 0;
00904 if (hitchance > 100)
00905 hitchance = 100;
00906
00907 mpr(bombown, "%s anti-missile system activated...",
00908 cname(ship.shp_own));
00909 mpr(ship.shp_own, "Ship #%i anti-missile system activated!\n",
00910 ship.shp_uid);
00911 mpr(ship.shp_own, "%d%% hitchance...", hitchance);
00912
00913 ship.shp_item[I_SHELL] = shell - 2;
00914 putship(ship.shp_uid, &ship);
00915
00916 if (roll(100) <= hitchance) {
00917 mpr(bombown, "KABOOOM!! Missile destroyed\n\n");
00918 mpr(ship.shp_own,
00919 "KABOOOM!! Incoming missile destroyed!\n\n");
00920 return 1;
00921 } else {
00922 mpr(bombown, "SWOOSH!! anti-missile system failed!!\n");
00923 mpr(ship.shp_own,
00924 "SWOOSH!! Missile evades anti-missile systems\n\n");
00925 }
00926 }
00927 return 0;
00928 }
00929
00930
00931
00932 void
00933 shp_missdef(struct shpstr *sp, natid victim)
00934 {
00935 struct emp_qelem list;
00936 struct ulist *mlp;
00937 int eff;
00938 char buf[512];
00939
00940 emp_initque(&list);
00941
00942 mlp = malloc(sizeof(struct ulist));
00943 mlp->chrp = (struct empobj_chr *)&mchr[(int)sp->shp_type];
00944 mlp->unit.ship = *sp;
00945 mlp->mobil = sp->shp_mobil;
00946 emp_insque(&mlp->queue, &list);
00947 sprintf(buf, "%s", prship(&mlp->unit.ship));
00948
00949 eff = sp->shp_effic;
00950 if (most_valuable_ship(&list)) {
00951 shp_missile_interdiction(&list, sp->shp_x, sp->shp_y, sp->shp_own);
00952 getship(sp->shp_uid, sp);
00953
00954 if (!sp->shp_own) {
00955 wu(0, victim,
00956 "missiles launched in defense did 100%% damage to %s\n",
00957 buf);
00958 wu(0, victim, "%s sunk!\n", buf);
00959 } else if (eff > 0 && sp->shp_effic < eff) {
00960 wu(0, victim,
00961 "missiles launched in defense did %d%% damage to %s\n",
00962 100 * (eff - sp->shp_effic) / eff, buf);
00963 }
00964 }
00965 if (!QEMPTY(&list))
00966 free(mlp);
00967 }
00968
00969 double
00970 shp_mobcost(struct shpstr *sp)
00971 {
00972 return speed_factor(sp->shp_effic * 0.01 * sp->shp_speed,
00973 sp->shp_tech);
00974 }
00975
00976
00977
00978
00979 void
00980 shp_set_tech(struct shpstr *sp, int tlev)
00981 {
00982 struct mchrstr *mcp = mchr + sp->shp_type;
00983 int tech_diff = tlev - mcp->m_tech;
00984
00985 if (CANT_HAPPEN(tech_diff < 0)) {
00986 tlev -= tech_diff;
00987 tech_diff = 0;
00988 }
00989
00990 sp->shp_tech = tlev;
00991 sp->shp_armor = (short)SHP_DEF(mcp->m_armor, tech_diff);
00992 sp->shp_speed = (short)SHP_SPD(mcp->m_speed, tech_diff);
00993 sp->shp_visib = (short)SHP_VIS(mcp->m_visib, tech_diff);
00994 sp->shp_frnge = (short)SHP_RNG(mcp->m_frnge, tech_diff);
00995 sp->shp_glim = (short)SHP_FIR(mcp->m_glim, tech_diff);
00996 }