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
00037 #include <config.h>
00038
00039 #include <math.h>
00040 #include "file.h"
00041 #include "item.h"
00042 #include "land.h"
00043 #include "lost.h"
00044 #include "map.h"
00045 #include "misc.h"
00046 #include "nat.h"
00047 #include "nsc.h"
00048 #include "nuke.h"
00049 #include "optlist.h"
00050 #include "path.h"
00051 #include "plane.h"
00052 #include "player.h"
00053 #include "prototypes.h"
00054 #include "sect.h"
00055 #include "ship.h"
00056 #include "xy.h"
00057
00058 static int pln_equip(struct plist *, struct ichrstr *, int, char);
00059 static int fit_plane_on_ship(struct plnstr *, struct shpstr *);
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069 struct sctstr *
00070 get_assembly_point(char *input, struct sctstr *ap_sect, char *buf)
00071 {
00072 char *p;
00073 coord x, y;
00074 struct nstr_item ni;
00075 struct shpstr ship;
00076
00077 p = getstarg(input, "assembly point? ", buf);
00078 if (!p || *p == 0)
00079 return NULL;
00080 if (!sarg_xy(p, &x, &y) || !getsect(x, y, ap_sect))
00081 return NULL;
00082
00083
00084 if (ap_sect->sct_own == player->cnum
00085 || getrel(getnatp(ap_sect->sct_own), player->cnum) == ALLIED)
00086 return ap_sect;
00087
00088
00089 snxtitem_xy(&ni, EF_SHIP, x, y);
00090 while (nxtitem(&ni, &ship)) {
00091 if (ship.shp_effic < SHIP_MINEFF || ship.shp_own == 0)
00092 continue;
00093 if (ship.shp_own == player->cnum
00094 || getrel(getnatp(ship.shp_own), player->cnum) == ALLIED)
00095 return ap_sect;
00096 }
00097
00098 pr("Assembly point not owned by you or an ally!\n");
00099 return NULL;
00100 }
00101
00102 int
00103 pln_onewaymission(struct sctstr *target, int *shipno, int *flagp)
00104 {
00105 int nships;
00106 int cno;
00107 int flags, fl;
00108 struct shpstr ship;
00109 char buf[1024];
00110 char *p;
00111
00112 flags = *flagp;
00113
00114
00115 nships = carriersatxy(target->sct_x, target->sct_y, player->cnum);
00116 if (nships) {
00117 for (;;) {
00118 if (!(p = getstarg(0, "Carrier #? ", buf)) || !*p)
00119 break;
00120 cno = atoi(p);
00121 if (cno < 0
00122 || !getship(cno, &ship)
00123 || (!player->owner
00124 && (getrel(getnatp(ship.shp_own), player->cnum)
00125 != ALLIED))) {
00126 pr("Not yours\n");
00127 continue;
00128 }
00129 if (ship.shp_x != target->sct_x || ship.shp_y != target->sct_y) {
00130 pr("Ship #%d not in %s\n", cno,
00131 xyas(target->sct_x, target->sct_y, player->cnum));
00132 continue;
00133 }
00134 fl = carrier_planes(&ship, 0);
00135 if (fl == 0) {
00136 pr("Can't land on %s.\n", prship(&ship));
00137 continue;
00138 }
00139
00140 pr("landing on carrier %d\n", cno);
00141 flags |= fl;
00142 *shipno = cno;
00143 *flagp = flags;
00144 return 0;
00145 }
00146 }
00147
00148
00149 if (target->sct_own != player->cnum
00150 && getrel(getnatp(target->sct_own), player->cnum) != ALLIED) {
00151 pr("Nowhere to land at sector %s!\n",
00152 xyas(target->sct_x, target->sct_y, player->cnum));
00153 return -1;
00154 }
00155 if (target->sct_type == SCT_MOUNT) {
00156 pr("Nowhere to land at sector %s!\n",
00157 xyas(target->sct_x, target->sct_y, player->cnum));
00158 return -1;
00159 }
00160 if (target->sct_type != SCT_AIRPT || target->sct_effic < 60)
00161 flags |= P_V;
00162
00163
00164 *shipno = -1;
00165 *flagp = flags;
00166 return 0;
00167 }
00168
00169 int
00170 pln_oneway_to_carrier_ok(struct emp_qelem *bomb_list,
00171 struct emp_qelem *esc_list, int cno)
00172 {
00173 struct emp_qelem *list, *qp;
00174 struct plist *plp;
00175 struct shpstr ship;
00176
00177 if (cno < 0 || !getship(cno, &ship))
00178 return 0;
00179
00180 count_planes(&ship);
00181
00182
00183 for (list = bomb_list;
00184 list;
00185 list = list == bomb_list ? esc_list : NULL) {
00186 for (qp = list->q_forw; qp != list; qp = qp->q_forw) {
00187 plp = (struct plist *)qp;
00188 if (plp->plane.pln_ship == ship.shp_uid)
00189 continue;
00190 if (!fit_plane_on_ship(&plp->plane, &ship))
00191 return 0;
00192 }
00193 }
00194 return 1;
00195 }
00196
00197 void
00198 pln_newlanding(struct emp_qelem *list, coord tx, coord ty, int cno)
00199 {
00200 struct emp_qelem *qp;
00201 struct plist *plp;
00202 struct shpstr ship;
00203 struct sctstr sect;
00204
00205 if (cno >= 0)
00206 getship(cno, &ship);
00207 for (qp = list->q_forw; qp != list; qp = qp->q_forw) {
00208 plp = (struct plist *)qp;
00209 if (cno >= 0) {
00210 count_planes(&ship);
00211 if (!could_be_on_ship(&plp->plane, &ship))
00212 pr("\t%s cannot land on ship #%d! %s aborts!\n",
00213 prplane(&plp->plane), cno, prplane(&plp->plane));
00214 else if (!put_plane_on_ship(&plp->plane, &ship))
00215 pr("\tNo room on ship #%d! %s aborts!\n",
00216 cno, prplane(&plp->plane));
00217 else {
00218 if (plp->plane.pln_own != ship.shp_own) {
00219
00220 wu(0, ship.shp_own, "%s %s lands on your %s\n",
00221 cname(player->cnum), prplane(&plp->plane),
00222 prship(&ship));
00223 }
00224 }
00225 } else {
00226 plp->plane.pln_x = tx;
00227 plp->plane.pln_y = ty;
00228 getsect(tx, ty, §);
00229 if (plp->plane.pln_own != sect.sct_own) {
00230
00231 wu(0, sect.sct_own,
00232 "%s %s lands at your sector %s\n",
00233 cname(player->cnum),
00234 prplane(&plp->plane), xyas(tx, ty, sect.sct_own));
00235 }
00236 plp->plane.pln_ship = cno;
00237 }
00238 }
00239 if (cno >= 0)
00240 putship(ship.shp_uid, &ship);
00241 }
00242
00243 void
00244 pln_dropoff(struct emp_qelem *list, struct ichrstr *ip, coord tx, coord ty,
00245 void *ptr, int type)
00246 {
00247 struct emp_qelem *qp;
00248 struct plist *plp;
00249 int amt;
00250 struct sctstr *sectp;
00251 struct shpstr *sp;
00252 int there;
00253 int max;
00254 struct mchrstr *mp;
00255
00256 if (ip == 0)
00257 return;
00258 amt = 0;
00259 for (qp = list->q_forw; qp != list; qp = qp->q_forw) {
00260 plp = (struct plist *)qp;
00261 amt += plp->misc;
00262 }
00263 if (type == EF_SECTOR) {
00264 sectp = ptr;
00265 if (!sectp->sct_own) {
00266 if (sectp->sct_type == SCT_WATER)
00267 pr("Your %s sink like a rock!\n", ip->i_name);
00268 else
00269 pr("Your %s vanish without a trace.\n", ip->i_name);
00270 return;
00271 }
00272 if (sectp->sct_own != player->cnum
00273 && getrel(getnatp(sectp->sct_own), player->cnum) != ALLIED) {
00274 pr("You don't own %s! Cargo jettisoned...\n",
00275 xyas(tx, ty, player->cnum));
00276 return;
00277 }
00278 if (ip->i_uid == I_CIVIL && sectp->sct_own != sectp->sct_oldown) {
00279 pr("%s is occupied. Your civilians suffer from identity crisis and die.\n",
00280 xyas(tx, ty, player->cnum));
00281 return;
00282 }
00283 there = sectp->sct_item[ip->i_uid];
00284 max = ITEM_MAX;
00285 } else {
00286 sp = ptr;
00287 there = sp->shp_item[ip->i_uid];
00288 mp = &mchr[(int)sp->shp_type];
00289 max = mp->m_item[ip->i_uid];
00290 }
00291 there += amt;
00292 if (there > max) {
00293 pr("%d excess %s discarded\n", max - there, ip->i_name);
00294 amt = max - there;
00295 there = max;
00296 }
00297 pr("%d %s landed safely", amt, ip->i_name);
00298 if (type == EF_SECTOR) {
00299 sectp = ptr;
00300 sectp->sct_item[ip->i_uid] = there;
00301 if (sectp->sct_own != player->cnum)
00302 wu(0, sectp->sct_own, "%s planes drop %d %s in %s\n",
00303 cname(player->cnum), amt, ip->i_name,
00304 xyas(sectp->sct_x, sectp->sct_y, sectp->sct_own));
00305 pr(" at %s\n", xyas(tx, ty, player->cnum));
00306 putsect((struct sctstr *)ptr);
00307 } else {
00308 struct shpstr *sp = (struct shpstr *)ptr;
00309 sp->shp_item[ip->i_uid] = there;
00310 if (sp->shp_own != player->cnum)
00311 wu(0, sp->shp_own, "%s planes land %d %s on carrier %d\n",
00312 cname(player->cnum), amt, ip->i_name, sp->shp_uid);
00313 pr(" on carrier #%d\n", sp->shp_uid);
00314 putship(sp->shp_uid, sp);
00315 }
00316 }
00317
00318 void
00319 pln_mine(struct emp_qelem *list, struct sctstr *sectp)
00320 {
00321 struct emp_qelem *qp;
00322 struct plist *plp;
00323 int amt;
00324
00325 amt = 0;
00326 for (qp = list->q_forw; qp != list; qp = qp->q_forw) {
00327 plp = (struct plist *)qp;
00328 amt += plp->misc;
00329
00330 }
00331 if (amt > 0) {
00332 if (sectp->sct_type != SCT_WATER) {
00333 pr("Your seamines have no effect here.\n");
00334 return;
00335 }
00336 sectp->sct_mines = MIN(sectp->sct_mines + amt, MINES_MAX);
00337 pr("%d mines laid in %s.\n", amt,
00338 xyas(sectp->sct_x, sectp->sct_y, player->cnum));
00339 if (map_set(player->cnum, sectp->sct_x, sectp->sct_y, 'X', 0))
00340 writemap(player->cnum);
00341 putsect(sectp);
00342 }
00343 }
00344
00345
00346
00347
00348
00349
00350
00351
00352
00353 int
00354 pln_capable(struct plnstr *pp, int wantflags, int nowantflags)
00355 {
00356 int flags = plchr[(int)pp->pln_type].pl_flags;
00357
00358 if (wantflags & (P_F | P_ESC)) {
00359 if ((flags & wantflags & (P_F | P_ESC)) == 0)
00360 return 0;
00361 wantflags &= ~(P_F | P_ESC);
00362 }
00363
00364 if (wantflags & (P_E | P_L | P_K)) {
00365 if ((flags & wantflags & (P_E | P_L | P_K)) == 0)
00366 return 0;
00367 wantflags &= ~(P_E | P_L | P_K);
00368 }
00369
00370 if ((flags & wantflags) != wantflags)
00371 return 0;
00372
00373 if (flags & nowantflags)
00374 return 0;
00375
00376 return 1;
00377 }
00378
00379
00380
00381
00382
00383
00384
00385
00386 int
00387 carrier_planes(struct shpstr *sp, int msl)
00388 {
00389 struct mchrstr *mcp = mchr + sp->shp_type;
00390 int res;
00391
00392 if (sp->shp_effic < SHP_AIROPS_EFF)
00393 return 0;
00394
00395 res = 0;
00396 if (mcp->m_flags & M_FLY)
00397 res |= P_L;
00398 if ((mcp->m_flags & M_MSL) && msl)
00399 res |= P_L;
00400 if (mcp->m_nchoppers && !msl)
00401 res |= P_K;
00402 if (mcp->m_nxlight)
00403 res |= P_E;
00404 return res;
00405 }
00406
00407 int
00408 pln_airbase_ok(struct plnstr *pp, int oneway, int noisy)
00409 {
00410 struct shpstr ship;
00411 struct lndstr land;
00412 struct sctstr sect;
00413 struct plchrstr *pcp = plchr + pp->pln_type;
00414
00415 if (CANT_HAPPEN(noisy && pp->pln_own != player->cnum))
00416 noisy = 0;
00417
00418 if (pp->pln_ship >= 0) {
00419
00420 if (!getship(pp->pln_ship, &ship)) {
00421 CANT_REACH();
00422 return 0;
00423 }
00424 if (ship.shp_own != pp->pln_own
00425 && getrel(getnatp(ship.shp_own), pp->pln_own) != ALLIED) {
00426 if (noisy)
00427 pr("(note) An ally does not own the ship %s is on\n",
00428 prplane(pp));
00429 return 0;
00430 }
00431 if (!(carrier_planes(&ship, pcp->pl_flags & P_M) & pcp->pl_flags))
00432 return 0;
00433
00434 } else if (pp->pln_land >= 0) {
00435
00436 if (!getland(pp->pln_land, &land)) {
00437 CANT_REACH();
00438 return 0;
00439 }
00440 if (land.lnd_own != pp->pln_own
00441 && getrel(getnatp(land.lnd_own), pp->pln_own) != ALLIED) {
00442 if (noisy)
00443 pr("(note) An ally does not own the unit %s is on\n",
00444 prplane(pp));
00445 return 0;
00446 }
00447 if (land.lnd_effic < LND_AIROPS_EFF || !(pcp->pl_flags & P_E))
00448 return 0;
00449 if (land.lnd_ship >= 0 || land.lnd_land >= 0)
00450 return 0;
00451
00452 } else {
00453
00454 if (!getsect(pp->pln_x, pp->pln_y, §)) {
00455 CANT_REACH();
00456 return 0;
00457 }
00458
00459 if (sect.sct_own != pp->pln_own
00460 && getrel(getnatp(sect.sct_own), pp->pln_own) != ALLIED) {
00461 if (noisy)
00462 pr("(note) An ally does not own the sector %s is in\n",
00463 prplane(pp));
00464 return 0;
00465 }
00466
00467 if ((pcp->pl_flags & P_V) == 0) {
00468 if (sect.sct_type != SCT_AIRPT) {
00469 if (noisy)
00470 pr("%s not at airport\n", prplane(pp));
00471 return 0;
00472 }
00473 if (sect.sct_effic < 40) {
00474 if (noisy)
00475 pr("%s is not 40%% efficient, %s can't take off from there.\n",
00476 xyas(sect.sct_x, sect.sct_y, pp->pln_own),
00477 prplane(pp));
00478 return 0;
00479 }
00480 if (!oneway && sect.sct_effic < 60) {
00481 if (noisy)
00482 pr("%s is not 60%% efficient, %s can't land there.\n",
00483 xyas(sect.sct_x, sect.sct_y, pp->pln_own),
00484 prplane(pp));
00485 return 0;
00486 }
00487 }
00488 }
00489
00490 return 1;
00491 }
00492
00493 void
00494 pln_sel(struct nstr_item *ni, struct emp_qelem *list, struct sctstr *ap,
00495 int ap_to_target, int rangemult, int wantflags, int nowantflags)
00496 {
00497 struct plnstr plane;
00498 int range;
00499 struct plchrstr *pcp;
00500 struct plist *plp;
00501
00502 emp_initque(list);
00503 while (nxtitem(ni, &plane)) {
00504 if (!player->owner)
00505 continue;
00506 if (plane.pln_mobil <= 0)
00507 continue;
00508 if (opt_MARKET) {
00509 if (ontradingblock(EF_PLANE, &plane)) {
00510 pr("plane #%d inelligible - it's for sale.\n",
00511 plane.pln_uid);
00512 continue;
00513 }
00514 }
00515
00516 range = mapdist(plane.pln_x, plane.pln_y, ap->sct_x, ap->sct_y);
00517 if (range > 4) {
00518 pr("%s too far from assembly point\n", prplane(&plane));
00519 continue;
00520 }
00521 if (plane.pln_effic < 40) {
00522 pr("%s not efficient enough (must be 40%%)\n",
00523 prplane(&plane));
00524 continue;
00525 }
00526 range += ap_to_target;
00527 range *= rangemult;
00528 pcp = &plchr[(int)plane.pln_type];
00529 if (!pln_capable(&plane, wantflags, nowantflags))
00530 continue;
00531 if (plane.pln_range < range) {
00532 pr("%s out of range (%d:%d)\n",
00533 prplane(&plane), plane.pln_range, range);
00534 continue;
00535 }
00536 if (!pln_airbase_ok(&plane, rangemult != 2, 1))
00537 continue;
00538 pr("%s standing by\n", prplane(&plane));
00539 plane.pln_mission = 0;
00540 putplane(plane.pln_uid, &plane);
00541 plp = malloc(sizeof(struct plist));
00542 plp->misc = 0;
00543 plp->bombs = 0;
00544 plp->pcp = pcp;
00545 plp->plane = plane;
00546 emp_insque(&plp->queue, list);
00547 }
00548 }
00549
00550 int
00551 pln_arm(struct emp_qelem *list, int dist, char mission, struct ichrstr *ip,
00552 int flags, int mission_flags)
00553 {
00554 struct emp_qelem *qp;
00555 struct emp_qelem *next;
00556 struct plist *plp;
00557
00558 for (qp = list->q_forw; qp != list; qp = next) {
00559 next = qp->q_forw;
00560 plp = (struct plist *)qp;
00561 if (pln_equip(plp, ip, flags, mission) < 0) {
00562 emp_remque(qp);
00563 free(qp);
00564 continue;
00565 }
00566 if (flags & (P_S | P_I)) {
00567 if (plp->pcp->pl_flags & P_S)
00568 mission_flags |= P_S;
00569 if (plp->pcp->pl_flags & P_I)
00570 mission_flags |= P_I;
00571 }
00572 if (!(plp->pcp->pl_flags & P_H))
00573
00574 mission_flags &= ~P_H;
00575 if (!(plp->pcp->pl_flags & P_X))
00576
00577 mission_flags &= ~P_X;
00578 if (!(plp->pcp->pl_flags & P_A)) {
00579
00580 mission_flags &= ~P_A;
00581
00582 }
00583 if (!(plp->pcp->pl_flags & P_MINE)) {
00584
00585 mission_flags &= ~P_MINE;
00586
00587 }
00588 plp->plane.pln_mobil -= pln_mobcost(dist, &plp->plane, flags);
00589 pr("%s equipped\n", prplane(&plp->plane));
00590 }
00591 return mission_flags;
00592 }
00593
00594 static int
00595 pln_equip(struct plist *plp, struct ichrstr *ip, int flags, char mission)
00596 {
00597 struct plchrstr *pcp;
00598 struct plnstr *pp;
00599 int needed;
00600 struct lndstr land;
00601 struct shpstr ship;
00602 struct sctstr sect;
00603 i_type itype;
00604 int rval;
00605 short *item;
00606 int own;
00607 int abandon_needed;
00608
00609 pp = &plp->plane;
00610 pcp = plp->pcp;
00611 if (pp->pln_ship >= 0) {
00612 getship(pp->pln_ship, &ship);
00613 item = ship.shp_item;
00614 own = ship.shp_own;
00615 } else if (pp->pln_land >= 0) {
00616 getland(pp->pln_land, &land);
00617 item = land.lnd_item;
00618 own = land.lnd_own;
00619 } else {
00620 getsect(pp->pln_x, pp->pln_y, §);
00621 item = sect.sct_item;
00622 own = sect.sct_oldown;
00623 }
00624 if (ip) {
00625 if (ip->i_uid == I_CIVIL) {
00626 if (pp->pln_own != own) {
00627 pr("You don't control those civilians!\n");
00628 return -1;
00629 }
00630 }
00631 }
00632 if (pcp->pl_fuel > item[I_PETROL]) {
00633 pr("%s not enough petrol there!\n", prplane(pp));
00634 return -1;
00635 }
00636 item[I_PETROL] -= pcp->pl_fuel;
00637 rval = 0;
00638 if ((flags & P_F) == 0) {
00639 itype = I_NONE;
00640 needed = 0;
00641 switch (mission) {
00642 case 's':
00643 case 'p':
00644 if (pp->pln_nuketype == -1) {
00645 itype = I_SHELL;
00646 needed = pp->pln_load;
00647 }
00648 break;
00649 case 't':
00650 case 'd':
00651 if ((pcp->pl_flags & P_C) == 0 || ip == 0)
00652 break;
00653 itype = ip->i_uid;
00654 needed = (pp->pln_load * 2) / ip->i_lbs;
00655 break;
00656 case 'm':
00657 if ((pcp->pl_flags & P_MINE) == 0)
00658 break;
00659 itype = I_SHELL;
00660 needed = (pp->pln_load * 2) / ip->i_lbs;
00661 break;
00662 case 'a':
00663 if ((pcp->pl_flags & (P_V | P_C)) == 0)
00664 break;
00665 itype = I_MILIT;
00666 needed = pp->pln_load / ip->i_lbs;
00667 break;
00668 case 'n':
00669 if (pp->pln_nuketype == -1)
00670 rval = -1;
00671 break;
00672 default:
00673 break;
00674 }
00675 if (rval < 0 || (itype != I_NONE && needed <= 0)) {
00676 pr("%s can't contribute to mission\n", prplane(pp));
00677 return -1;
00678 }
00679 if (itype != I_NONE) {
00680 #if 0
00681
00682 if (itype == I_SHELL && item[itype] < needed)
00683 item[itype] += supply_commod(plp->plane.pln_own,
00684 plp->plane.pln_x,
00685 plp->plane.pln_y,
00686 I_SHELL, needed);
00687 #endif
00688 abandon_needed = !!would_abandon(§, itype, needed, NULL);
00689 if (item[itype] < needed + abandon_needed) {
00690 pr("Not enough %s for %s\n", ichr[itype].i_name, prplane(pp));
00691 return -1;
00692 }
00693 item[itype] -= needed;
00694 }
00695 if (itype == I_SHELL && (mission == 's' || mission == 'p'))
00696 plp->bombs = needed;
00697 else
00698 plp->misc = needed;
00699 }
00700 if (pp->pln_ship >= 0) {
00701 if (pp->pln_own != ship.shp_own) {
00702 wu(0, ship.shp_own,
00703 "%s %s prepares for takeoff from ship %s\n",
00704 cname(pp->pln_own), prplane(pp), prship(&ship));
00705 }
00706 putship(ship.shp_uid, &ship);
00707 } else if (pp->pln_land >= 0) {
00708 if (pp->pln_own != land.lnd_own) {
00709 wu(0, land.lnd_own,
00710 "%s %s prepares for takeoff from unit %s\n",
00711 cname(pp->pln_own), prplane(pp), prland(&land));
00712 }
00713 putland(land.lnd_uid, &land);
00714 } else {
00715 if (pp->pln_own != sect.sct_own) {
00716 wu(0, sect.sct_own, "%s %s prepares for takeoff from %s\n",
00717 cname(pp->pln_own), prplane(pp),
00718 xyas(sect.sct_x, sect.sct_y, sect.sct_own));
00719 }
00720 putsect(§);
00721 }
00722 return rval;
00723 }
00724
00725 void
00726 pln_put(struct emp_qelem *list)
00727 {
00728 struct emp_qelem *qp;
00729 struct emp_qelem *newqp;
00730 struct plist *plp;
00731 struct plnstr *pp;
00732 struct shpstr ship;
00733 struct sctstr sect;
00734
00735
00736
00737
00738 qp = list->q_forw;
00739 while (qp != list) {
00740 plp = (struct plist *)qp;
00741 pp = &plp->plane;
00742
00743 if (pp->pln_ship >= 0) {
00744
00745 getship(pp->pln_ship, &ship);
00746
00747
00748
00749 if (ship.shp_effic < SHIP_MINEFF) {
00750 mpr(pp->pln_own,
00751 "Ship #%d has been sunk, plane #%d has nowhere to land, and\n"
00752 "splashes into the sea.\n",
00753 pp->pln_ship, pp->pln_uid);
00754 pp->pln_effic = 0;
00755 }
00756 } else {
00757
00758 getsect(pp->pln_x, pp->pln_y, §);
00759 if (sect.sct_type == SCT_WATER || sect.sct_type == SCT_WASTE) {
00760 mpr(pp->pln_own,
00761 "Nowhere to land at %s, plane #%d crashes and burns...\n",
00762 xyas(pp->pln_x, pp->pln_y, pp->pln_own), pp->pln_uid);
00763 pp->pln_effic = 0;
00764 }
00765 }
00766 putplane(pp->pln_uid, pp);
00767 newqp = qp->q_forw;
00768 emp_remque(qp);
00769 free(qp);
00770 qp = newqp;
00771 }
00772 }
00773
00774 void
00775 pln_removedupes(struct emp_qelem *bomb_list, struct emp_qelem *esc_list)
00776 {
00777 struct emp_qelem *bomb;
00778 struct emp_qelem *esc;
00779 struct plist *bombp;
00780 struct plist *escp;
00781
00782 if (QEMPTY(bomb_list) || QEMPTY(esc_list))
00783 return;
00784 bomb = bomb_list->q_forw;
00785 while (bomb != bomb_list) {
00786 if (QEMPTY(esc_list)) {
00787 bomb = bomb_list;
00788 continue;
00789 }
00790 esc = esc_list->q_forw;
00791 bombp = (struct plist *)bomb;
00792 while (esc != esc_list) {
00793 escp = (struct plist *)esc;
00794 if (escp->plane.pln_uid == bombp->plane.pln_uid) {
00795 emp_remque(esc);
00796 free(esc);
00797 esc = esc_list;
00798 } else
00799 esc = esc->q_forw;
00800 }
00801 bomb = bomb->q_forw;
00802 }
00803 }
00804
00805
00806
00807
00808
00809
00810
00811 static int
00812 fit_plane_on_ship(struct plnstr *pp, struct shpstr *sp)
00813 {
00814 struct plchrstr *pcp = plchr + pp->pln_type;
00815 struct mchrstr *mcp = mchr + sp->shp_type;
00816 int wanted;
00817
00818 if (pcp->pl_flags & P_K) {
00819
00820 if (sp->shp_nchoppers < mcp->m_nchoppers)
00821 return ++sp->shp_nchoppers;
00822
00823 wanted = M_FLY;
00824 } else if (pcp->pl_flags & P_E) {
00825
00826 if (sp->shp_nxlight < mcp->m_nxlight)
00827 return ++sp->shp_nxlight;
00828
00829 wanted = M_MSL | M_FLY;
00830 } else if (!(pcp->pl_flags & P_L)) {
00831
00832 wanted = 0;
00833 } else if (pcp->pl_flags & P_M) {
00834
00835 wanted = M_MSL | M_FLY;
00836 } else {
00837
00838 wanted = M_FLY;
00839 }
00840
00841 if ((mcp->m_flags & wanted) == 0)
00842 return 0;
00843
00844 if (sp->shp_nplane < mcp->m_nplanes)
00845 return ++sp->shp_nplane;
00846
00847 return 0;
00848 }
00849
00850
00851
00852
00853
00854
00855
00856 static void
00857 fit_plane_off_ship(struct plnstr *pp, struct shpstr *sp)
00858 {
00859
00860
00861
00862
00863 struct plchrstr *pcp = plchr + pp->pln_type;
00864
00865 if (pcp->pl_flags & P_K) {
00866 if (sp->shp_nchoppers) {
00867 sp->shp_nchoppers--;
00868 return;
00869 }
00870 } else if (pcp->pl_flags & P_E) {
00871 if (sp->shp_nxlight) {
00872 sp->shp_nxlight--;
00873 return;
00874 }
00875 }
00876
00877 if (CANT_HAPPEN(sp->shp_nplane == 0))
00878 sp->shp_nplane = 1;
00879 sp->shp_nplane--;
00880 }
00881
00882 int
00883 put_plane_on_ship(struct plnstr *plane, struct shpstr *ship)
00884 {
00885 if (plane->pln_ship == ship->shp_uid)
00886 return 1;
00887
00888 if (!fit_plane_on_ship(plane, ship))
00889 return 0;
00890
00891 plane->pln_x = ship->shp_x;
00892 plane->pln_y = ship->shp_y;
00893 plane->pln_ship = ship->shp_uid;
00894 putplane(plane->pln_uid, plane);
00895 putship(ship->shp_uid, ship);
00896 return 1;
00897 }
00898
00899 void
00900 take_plane_off_ship(struct plnstr *plane, struct shpstr *ship)
00901 {
00902 if (CANT_HAPPEN(plane->pln_ship != ship->shp_uid))
00903 return;
00904
00905 fit_plane_off_ship(plane, ship);
00906 plane->pln_ship = -1;
00907 putship(ship->shp_uid, ship);
00908 putplane(plane->pln_uid, plane);
00909 }
00910
00911
00912
00913
00914
00915
00916
00917 static int
00918 fit_plane_on_land(struct plnstr *pp, struct lndstr *lp)
00919 {
00920 struct plchrstr *pcp = plchr + pp->pln_type;
00921 struct lchrstr *lcp = lchr + lp->lnd_type;
00922
00923 if ((pcp->pl_flags & P_E) && lp->lnd_nxlight < lcp->l_nxlight)
00924 return ++lp->lnd_nxlight;
00925
00926 return 0;
00927 }
00928
00929
00930
00931
00932
00933
00934 static void
00935 fit_plane_off_land(struct plnstr *pp, struct lndstr *lp)
00936 {
00937 struct plchrstr *pcp = plchr + pp->pln_type;
00938
00939 if (CANT_HAPPEN(lp->lnd_nxlight == 0))
00940 lp->lnd_nxlight = 1;
00941 lp->lnd_nxlight--;
00942 }
00943
00944 int
00945 put_plane_on_land(struct plnstr *plane, struct lndstr *land)
00946 {
00947 if (plane->pln_land == land->lnd_uid)
00948 return 1;
00949
00950 if (!fit_plane_on_land(plane, land))
00951 return 0;
00952
00953 plane->pln_x = land->lnd_x;
00954 plane->pln_y = land->lnd_y;
00955 plane->pln_land = land->lnd_uid;
00956 putplane(plane->pln_uid, plane);
00957 putland(land->lnd_uid, land);
00958 return 1;
00959 }
00960
00961 void
00962 take_plane_off_land(struct plnstr *plane, struct lndstr *land)
00963 {
00964 if (CANT_HAPPEN(plane->pln_land != land->lnd_uid))
00965 return;
00966
00967 fit_plane_off_land(plane, land);
00968 plane->pln_land = -1;
00969 putland(land->lnd_uid, land);
00970 putplane(plane->pln_uid, plane);
00971 }
00972
00973
00974
00975
00976 int
00977 could_be_on_ship(struct plnstr *pp, struct shpstr *sp)
00978 {
00979 struct shpstr ship;
00980
00981 ship = *sp;
00982 ship.shp_nplane = ship.shp_nchoppers = ship.shp_nxlight = 0;
00983 return fit_plane_on_ship(pp, &ship);
00984 }
00985
00986 void
00987 plane_sweep(struct emp_qelem *plane_list, coord x, coord y)
00988 {
00989 struct plnstr *pp;
00990 struct plchrstr *pcp;
00991 struct emp_qelem *qp;
00992 struct emp_qelem *next;
00993 struct plist *ip;
00994 struct sctstr sect;
00995 int mines_there;
00996 int found = 0;
00997
00998 getsect(x, y, §);
00999 mines_there = sect.sct_mines;
01000
01001 if (mines_there == 0)
01002 return;
01003
01004 if ((sect.sct_type != SCT_WATER) && (sect.sct_type != SCT_HARBR))
01005 return;
01006
01007 for (qp = plane_list->q_forw; ((qp != plane_list) && (mines_there));
01008 qp = next) {
01009 next = qp->q_forw;
01010 ip = (struct plist *)qp;
01011 pp = &ip->plane;
01012 pcp = ip->pcp;
01013 if (!(pcp->pl_flags & P_SWEEP))
01014 continue;
01015
01016 if (chance((100.0 - pp->pln_acc) / 100.0)) {
01017 pr("Sweep! in %s\n",
01018 xyas(sect.sct_x, sect.sct_y, pp->pln_own));
01019 mines_there--;
01020 found = 1;
01021 }
01022 }
01023
01024 if (found && map_set(player->cnum, sect.sct_x, sect.sct_y, 'X', 0))
01025 writemap(player->cnum);
01026 sect.sct_mines = mines_there;
01027 putsect(§);
01028 }
01029
01030 void
01031 count_planes(struct shpstr *sp)
01032 {
01033 struct nstr_item ni;
01034 struct plnstr plane;
01035 int nplane, nchoppers, nxlight;
01036
01037 if (sp->shp_effic < SHIP_MINEFF)
01038 return;
01039
01040 nplane = sp->shp_nplane;
01041 sp->shp_nplane = 0;
01042 nchoppers = sp->shp_nchoppers;
01043 sp->shp_nchoppers = 0;
01044 nxlight = sp->shp_nxlight;
01045 sp->shp_nxlight = 0;
01046
01047 snxtitem_xy(&ni, EF_PLANE, sp->shp_x, sp->shp_y);
01048 while (nxtitem(&ni, &plane)) {
01049 if (plane.pln_own == 0)
01050 continue;
01051 if (plane.pln_ship == sp->shp_uid) {
01052 if (!fit_plane_on_ship(&plane, sp))
01053 CANT_REACH();
01054 }
01055 }
01056
01057 if (nplane != sp->shp_nplane ||
01058 nxlight != sp->shp_nxlight || nchoppers != sp->shp_nchoppers) {
01059 putship(sp->shp_uid, sp);
01060 }
01061 }
01062
01063 void
01064 count_land_planes(struct lndstr *lp)
01065 {
01066 struct nstr_item ni;
01067 struct plnstr plane;
01068 int nplane;
01069
01070 if (lp->lnd_effic < LAND_MINEFF)
01071 return;
01072
01073 nplane = lp->lnd_nxlight;
01074 lp->lnd_nxlight = 0;
01075
01076 snxtitem_all(&ni, EF_PLANE);
01077 while (nxtitem(&ni, &plane)) {
01078 if (plane.pln_own == 0)
01079 continue;
01080 if (plane.pln_land == lp->lnd_uid)
01081 if (!fit_plane_on_land(&plane, lp))
01082 CANT_REACH();
01083 }
01084
01085 if (lp->lnd_nxlight != nplane)
01086 putland(lp->lnd_uid, lp);
01087 }
01088
01089 int
01090 count_sect_planes(struct sctstr *sp)
01091 {
01092 int count = 0;
01093 struct nstr_item ni;
01094 struct plnstr plane;
01095
01096 snxtitem_all(&ni, EF_PLANE);
01097 while (nxtitem(&ni, &plane)) {
01098 if (!plane.pln_own)
01099 continue;
01100 if (plane.pln_flags & PLN_LAUNCHED)
01101 continue;
01102 if (plane.pln_x == sp->sct_x && plane.pln_y == sp->sct_y)
01103 ++count;
01104 }
01105
01106 return count;
01107 }
01108
01109 int
01110 pln_hitchance(struct plnstr *pp, int hardtarget, int type)
01111 {
01112 struct plchrstr *pcp = plchr + pp->pln_type;
01113 double tfact = (double)(pp->pln_tech - pcp->pl_tech) /
01114 (pp->pln_tech - pcp->pl_tech / 2);
01115 int acc = pp->pln_acc;
01116 int hitchance;
01117
01118 if (type == EF_SHIP) {
01119 if (pcp->pl_flags & P_A)
01120 acc -= 20;
01121 if (!(pcp->pl_flags & P_T))
01122 acc += 35;
01123 }
01124 hitchance = (int)(pp->pln_effic * (1.0 - 0.1 * tfact) *
01125 (1.0 - acc / 100.0)) - hardtarget;
01126
01127
01128 if (hitchance < 20)
01129 hitchance = 5 + ldround(300.0 / (40.0 - hitchance), 1);
01130 if (hitchance > 100)
01131 hitchance = 100;
01132 return hitchance;
01133 }
01134
01135
01136
01137 int
01138 pln_damage(struct plnstr *pp, coord x, coord y, char type, int *nukedamp,
01139 int noisy)
01140 {
01141 struct nukstr nuke;
01142 struct plchrstr *pcp = plchr + pp->pln_type;
01143 int i;
01144 int hitroll;
01145 int dam = 0;
01146 int aim;
01147 int effective = 1;
01148 int pinbomber = 0;
01149
01150 if (pp->pln_nuketype != -1) {
01151 if (nuk_on_plane(&nuke, pp->pln_uid) >= 0) {
01152 mpr(pp->pln_own, "Releasing RV's for %s detonation...\n",
01153 pp->pln_flags & PLN_AIRBURST ? "airburst" : "groundburst");
01154 pp->pln_nuketype = -1;
01155 *nukedamp = detonate(&nuke, x, y,
01156 pp->pln_flags & PLN_AIRBURST);
01157 return 0;
01158 }
01159 CANT_REACH();
01160 }
01161 *nukedamp = 0;
01162
01163 if (!pp->pln_load)
01164 return 0;
01165
01166 i = roll(pp->pln_load) + 1;
01167 if (i > pp->pln_load)
01168 i = pp->pln_load;
01169
01170 if (pcp->pl_flags & P_M) {
01171 if (pcp->pl_flags & P_MAR)
01172 pinbomber = 1;
01173 } else if (pcp->pl_flags & P_T)
01174 pinbomber = 1;
01175
01176 aim = 100 - pp->pln_acc;
01177 if (type == 's') {
01178 if (pinbomber) {
01179 aim = pp->pln_acc;
01180 effective = 0;
01181 }
01182 aim += 30;
01183 } else {
01184 if (!pinbomber) {
01185 effective = 0;
01186 }
01187 }
01188 while (i--) {
01189 dam += roll(6);
01190 hitroll = roll(100);
01191 if (hitroll >= 90) {
01192 dam += 8;
01193 if (noisy)
01194 mpr(pp->pln_own, "BLAM");
01195 } else if (hitroll < aim) {
01196 dam += 5;
01197 if (noisy)
01198 mpr(pp->pln_own, "Blam");
01199 } else {
01200 dam += 1;
01201 if (noisy)
01202 mpr(pp->pln_own, "blam");
01203 }
01204 if (i && noisy)
01205 mpr(pp->pln_own, "-");
01206 }
01207 if (noisy)
01208 mpr(pp->pln_own, "\n");
01209 if (effective)
01210 dam *= 2;
01211 return dam;
01212 }
01213
01214 int
01215 pln_identchance(struct plnstr *pp, int hardtarget, int type)
01216 {
01217 double misschance =
01218 (100.0 - pln_hitchance(pp, hardtarget, type)) / 100.0;
01219 return (int)(100 - 100 * misschance * misschance);
01220 }
01221
01222 int
01223 pln_mobcost(int dist, struct plnstr *pp, int flags)
01224 {
01225 double cost;
01226
01227 cost = 20.0 / (pp->pln_effic / 100.0);
01228 if ((flags & P_F) || (flags & P_ESC))
01229 cost /= 2;
01230
01231 return ldround(cost * dist / pp->pln_range_max + 5, 1);
01232 }
01233
01234
01235
01236
01237 void
01238 pln_set_tech(struct plnstr *pp, int tlev)
01239 {
01240 struct plchrstr *pcp = plchr + pp->pln_type;
01241 int tech_diff = tlev - pcp->pl_tech;
01242 int limited_range = pp->pln_range < pp->pln_range_max;
01243
01244 if (CANT_HAPPEN(tech_diff < 0)) {
01245 tlev -= tech_diff;
01246 tech_diff = 0;
01247 }
01248
01249 pp->pln_tech = tlev;
01250 pp->pln_att = PLN_ATTDEF(pcp->pl_att, tech_diff);
01251 pp->pln_def = PLN_ATTDEF(pcp->pl_def, tech_diff);
01252 pp->pln_acc = PLN_ACC(pcp->pl_acc, tech_diff);
01253 pp->pln_range_max = PLN_RAN(pcp->pl_range, tech_diff);
01254 pp->pln_load = PLN_LOAD(pcp->pl_load, tech_diff);
01255
01256 if (!limited_range || pp->pln_range > pp->pln_range_max)
01257 pp->pln_range = pp->pln_range_max;
01258 }