2 * Empire - A multi-player, client/server Internet based war game.
3 * Copyright (C) 1986-2007, Dave Pare, Jeff Bailey, Thomas Ruschak,
4 * Ken Stevens, Steve McClure
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 * See files README, COPYING and CREDITS in the root of the source
23 * tree for related information and legal notices. It is expected
24 * that future projects/authors will amend these files as needed.
28 * plnsub.c: Plane subroutine stuff
30 * Known contributors to this file:
33 * Steve McClure, 1998-2000
34 * Markus Armbruster, 2004-2005
53 #include "prototypes.h"
58 static int pln_equip(struct plist *, struct ichrstr *, int, char);
61 * Get assembly point argument.
62 * If INPUT is not empty, use it, else prompt for more input using PROMPT.
63 * If this yields a valid assembly point, read it into *AP_SECT and
65 * Else complain and return NULL.
66 * *AP_SECT and BUF[1024] may be modified in either case.
69 get_assembly_point(char *input, struct sctstr *ap_sect, char *buf)
76 p = getstarg(input, "assembly point? ", buf);
79 if (!sarg_xy(p, &x, &y) || !getsect(x, y, ap_sect))
82 /* over own or allied sector is fine */
83 if (ap_sect->sct_own == player->cnum
84 || getrel(getnatp(ap_sect->sct_own), player->cnum) == ALLIED)
87 /* over own or allied ship is fine */
88 snxtitem_xy(&ni, EF_SHIP, x, y);
89 while (nxtitem(&ni, &ship)) {
90 if (ship.shp_effic < SHIP_MINEFF || ship.shp_own == 0)
92 if (ship.shp_own == player->cnum
93 || getrel(getnatp(ship.shp_own), player->cnum) == ALLIED)
97 pr("Assembly point not owned by you or an ally!\n");
102 pln_onewaymission(struct sctstr *target, int *shipno, int *flagp)
114 nships = carriersatxy(target->sct_x, target->sct_y,
115 M_FLY | M_CHOPPER, 0, player->cnum);
118 if (!(p = getstarg(0, "Carrier #? ", buf)) || !*p)
122 || !getship(cno, &ship)
124 && (getrel(getnatp(ship.shp_own), player->cnum)
129 if (ship.shp_x != target->sct_x || ship.shp_y != target->sct_y) {
130 pr("Ship #%d not in %s\n", cno,
131 xyas(target->sct_x, target->sct_y, player->cnum));
134 if ((!(mchr[(int)ship.shp_type].m_flags & M_FLY)
135 && !(mchr[(int)ship.shp_type].m_flags & M_XLIGHT)
136 && !(mchr[(int)ship.shp_type].m_flags & M_CHOPPER))
137 || ship.shp_effic < SHP_AIROPS_EFF) {
138 pr("Can't land on %s.\n", prship(&ship));
142 /* clear to land on ship#CNO */
143 pr("landing on carrier %d\n", cno);
144 if (mchr[(int)ship.shp_type].m_flags & M_FLY)
146 if (mchr[(int)ship.shp_type].m_flags & M_CHOPPER)
148 if (mchr[(int)ship.shp_type].m_flags & M_XLIGHT)
156 /* try to land at sector */
157 if (target->sct_own != player->cnum
158 && getrel(getnatp(target->sct_own), player->cnum) != ALLIED) {
159 pr("Nowhere to land at sector %s!\n",
160 xyas(target->sct_x, target->sct_y, player->cnum));
163 if (target->sct_type == SCT_MOUNT) {
164 pr("Nowhere to land at sector %s!\n",
165 xyas(target->sct_x, target->sct_y, player->cnum));
168 if (target->sct_type != SCT_AIRPT || target->sct_effic < 60)
171 /* clear to land at sector */
178 pln_oneway_to_carrier_ok(struct emp_qelem *bomb_list,
179 struct emp_qelem *esc_list, int cno)
181 struct emp_qelem *list, *qp;
183 struct plchrstr *pcp;
186 int nchoppers, nxlight, nplane;
188 if (cno < 0 || !getship(cno, &ship))
192 nchoppers = ship.shp_nchoppers;
193 nxlight = ship.shp_nxlight;
194 nplane = ship.shp_nplane;
195 mcp = &mchr[(int)ship.shp_type];
198 for (list = bomb_list;
200 list = list == bomb_list ? esc_list : NULL) {
201 for (qp = list->q_forw; qp != list; qp = qp->q_forw) {
202 /* FIXME duplicates put_plane_on_ship() logic; refactor */
203 plp = (struct plist *)qp;
204 pcp = &plchr[(int)plp->plane.pln_type];
205 if (plp->plane.pln_ship == ship.shp_uid)
207 /* try chopper space */
208 if ((pcp->pl_flags & P_K) && (mcp->m_flags & M_CHOPPER)
209 && nchoppers < mcp->m_nchoppers)
211 /* try xlight space */
212 else if ((pcp->pl_flags & P_E) && (mcp->m_flags & M_XLIGHT)
213 && nxlight < mcp->m_nxlight)
215 /* try plane space */
216 else if ((((pcp->pl_flags & P_L) && (mcp->m_flags & M_FLY))
217 || ((pcp->pl_flags & P_M) && (pcp->pl_flags & P_L)
218 && (mcp->m_flags & M_MSL)))
219 && nplane < mcp->m_nplanes)
222 return 0; /* won't be able to land */
229 pln_newlanding(struct emp_qelem *list, coord tx, coord ty, int cno)
231 struct emp_qelem *qp;
238 for (qp = list->q_forw; qp != list; qp = qp->q_forw) {
239 plp = (struct plist *)qp;
242 if (!can_be_on_ship(plp->plane.pln_uid, ship.shp_uid))
243 pr("\t%s cannot land on ship #%d! %s aborts!\n",
244 prplane(&plp->plane), cno, prplane(&plp->plane));
245 else if (!put_plane_on_ship(&plp->plane, &ship))
246 pr("\tNo room on ship #%d! %s aborts!\n",
247 cno, prplane(&plp->plane));
249 if (plp->plane.pln_own != ship.shp_own) {
250 /* plp->plane.pln_own = ship.shp_own;*/
251 wu(0, ship.shp_own, "%s %s lands on your %s\n",
252 cname(player->cnum), prplane(&plp->plane),
257 plp->plane.pln_x = tx;
258 plp->plane.pln_y = ty;
259 getsect(tx, ty, §);
260 if (plp->plane.pln_own != sect.sct_own) {
261 /* plp->plane.pln_own = sect.sct_own;*/
263 "%s %s lands at your sector %s\n",
265 prplane(&plp->plane), xyas(tx, ty, sect.sct_own));
267 plp->plane.pln_ship = cno;
271 putship(ship.shp_uid, &ship);
275 pln_dropoff(struct emp_qelem *list, struct ichrstr *ip, coord tx, coord ty,
278 struct emp_qelem *qp;
281 struct sctstr *sectp;
290 for (qp = list->q_forw; qp != list; qp = qp->q_forw) {
291 plp = (struct plist *)qp;
294 if (type == EF_SECTOR) {
296 if (!sectp->sct_own) {
297 if (sectp->sct_type == SCT_WATER)
298 pr("Your %s sink like a rock!\n", ip->i_name);
300 pr("Your %s vanish without a trace.\n", ip->i_name);
303 if (sectp->sct_own != player->cnum
304 && getrel(getnatp(sectp->sct_own), player->cnum) != ALLIED) {
305 pr("You don't own %s! Cargo jettisoned...\n",
306 xyas(tx, ty, player->cnum));
309 if (ip->i_uid == I_CIVIL && sectp->sct_own != sectp->sct_oldown) {
310 pr("%s is occupied. Your civilians suffer from identity crisis and die.\n",
311 xyas(tx, ty, player->cnum));
314 there = sectp->sct_item[ip->i_uid];
318 there = sp->shp_item[ip->i_uid];
319 mp = &mchr[(int)sp->shp_type];
320 max = mp->m_item[ip->i_uid];
324 pr("%d excess %s discarded\n", max - there, ip->i_name);
328 pr("%d %s landed safely", amt, ip->i_name);
329 if (type == EF_SECTOR) {
331 sectp->sct_item[ip->i_uid] = there;
332 if (sectp->sct_own != player->cnum)
333 wu(0, sectp->sct_own, "%s planes drop %d %s in %s\n",
334 cname(player->cnum), amt, ip->i_name,
335 xyas(sectp->sct_x, sectp->sct_y, sectp->sct_own));
336 pr(" at %s\n", xyas(tx, ty, player->cnum));
337 putsect((struct sctstr *)ptr);
339 struct shpstr *sp = (struct shpstr *)ptr;
340 sp->shp_item[ip->i_uid] = there;
341 if (sp->shp_own != player->cnum)
342 wu(0, sp->shp_own, "%s planes land %d %s on carrier %d\n",
343 cname(player->cnum), amt, ip->i_name, sp->shp_uid);
344 pr(" on carrier #%d\n", sp->shp_uid);
345 putship(sp->shp_uid, sp);
350 pln_mine(struct emp_qelem *list, struct sctstr *sectp)
352 struct emp_qelem *qp;
357 for (qp = list->q_forw; qp != list; qp = qp->q_forw) {
358 plp = (struct plist *)qp;
363 if (sectp->sct_type != SCT_WATER) {
364 pr("Your seamines have no effect here.\n");
367 sectp->sct_mines = MIN(sectp->sct_mines + amt, MINES_MAX);
368 pr("%d mines laid in %s.\n", amt,
369 xyas(sectp->sct_x, sectp->sct_y, player->cnum));
370 if (map_set(player->cnum, sectp->sct_x, sectp->sct_y, 'X', 0))
371 writemap(player->cnum);
377 pln_sel(struct nstr_item *ni, struct emp_qelem *list, struct sctstr *ap,
378 int ap_to_target, int rangemult, int wantflags, int nowantflags)
385 struct plchrstr *pcp;
392 while (nxtitem(ni, &plane)) {
395 if (plane.pln_mobil <= 0)
398 if (ontradingblock(EF_PLANE, &plane)) {
399 pr("plane #%d inelligible - it's for sale.\n",
405 range = mapdist(plane.pln_x, plane.pln_y, ap->sct_x, ap->sct_y);
407 pr("%s too far from assembly point\n", prplane(&plane));
410 if (plane.pln_effic < 40) {
411 pr("%s not efficient enough (must be 40%%)\n",
415 range += ap_to_target;
417 pcp = &plchr[(int)plane.pln_type];
421 for (x = 0; x < sizeof(wantflags) * 8; x++) {
423 if ((wantflags & y) == y)
424 if ((pcp->pl_flags & y) != y) {
443 if ((pcp->pl_flags & P_ESC) || (pcp->pl_flags & P_F))
447 if ((wantflags & P_L) && (pcp->pl_flags & P_L))
449 if ((wantflags & P_K) && (pcp->pl_flags & P_K))
451 if ((wantflags & P_E) && (pcp->pl_flags & P_E))
460 for (x = 0; x < sizeof(nowantflags) * 8; x++) {
462 if ((nowantflags & y) == y)
463 if ((pcp->pl_flags & y) == y)
469 if (plane.pln_range < range) {
470 pr("%s out of range (%d:%d)\n",
471 prplane(&plane), plane.pln_range, range);
474 if (plane.pln_ship >= 0) {
475 if (!getship(plane.pln_ship, &ship) ||
476 plane.pln_own != player->cnum) {
479 pr("(note) ship not valid for %s\n", prplane(&plane));
480 putplane(plane.pln_uid, &plane);
483 if (!can_be_on_ship(plane.pln_uid, ship.shp_uid))
485 if (ship.shp_effic < SHIP_MINEFF)
487 if (ship.shp_effic < SHP_AIROPS_EFF)
489 /* Can't fly off non-owned ships or non-allied ship */
490 if ((ship.shp_own != player->cnum) &&
491 (getrel(getnatp(ship.shp_own), player->cnum) != ALLIED)) {
492 pr("(note) An ally does not own the ship %s is on\n",
497 if (plane.pln_land >= 0) {
498 if (!getland(plane.pln_land, &land) ||
499 (plane.pln_own != player->cnum)) {
502 pr("(note) land unit not valid for %s\n", prplane(&plane));
503 putplane(plane.pln_uid, &plane);
506 if (!(plchr[(int)plane.pln_type].pl_flags & P_E))
508 if (land.lnd_effic < LAND_MINEFF)
510 if (land.lnd_effic < LND_AIROPS_EFF)
512 /* Can't fly off units in ships or other units */
513 if ((land.lnd_ship >= 0) || (land.lnd_land >= 0))
515 /* Can't fly off non-owned units or non-allied unit */
516 if ((land.lnd_own != player->cnum) &&
517 (getrel(getnatp(land.lnd_own), player->cnum) != ALLIED)) {
518 pr("(note) An ally does not own the unit %s is on\n",
523 /* Now, check the sector status if not on a plane or unit */
524 if ((plane.pln_ship < 0) && (plane.pln_land < 0)) {
525 if (!getsect(plane.pln_x, plane.pln_y, §))
527 /* First, check allied status */
528 /* Can't fly from non-owned sectors or non-allied sectors */
529 if ((sect.sct_own != player->cnum) &&
530 (getrel(getnatp(sect.sct_own), player->cnum) != ALLIED)) {
531 pr("(note) An ally does not own the sector %s is in\n",
536 if ((pcp->pl_flags & P_V) == 0) {
537 if (sect.sct_type != SCT_AIRPT) {
538 pr("%s not at airport\n", prplane(&plane));
541 if (sect.sct_effic < 40) {
542 pr("%s is not 40%% efficient, %s can't take off from there.\n", xyas(sect.sct_x, sect.sct_y, plane.pln_own), prplane(&plane));
545 if (rangemult == 2 && sect.sct_effic < 60) {
546 pr("%s is not 60%% efficient, %s can't land there.\n",
547 xyas(sect.sct_x, sect.sct_y, plane.pln_own),
553 pr("%s standing by\n", prplane(&plane));
554 plane.pln_mission = 0;
555 putplane(plane.pln_uid, &plane);
556 plp = malloc(sizeof(struct plist));
561 emp_insque(&plp->queue, list);
566 pln_arm(struct emp_qelem *list, int dist, char mission, struct ichrstr *ip,
567 int flags, int mission_flags)
569 struct emp_qelem *qp;
570 struct emp_qelem *next;
573 for (qp = list->q_forw; qp != list; qp = next) {
575 plp = (struct plist *)qp;
576 if (pln_equip(plp, ip, flags, mission) < 0) {
581 if (flags & (P_S | P_I)) {
582 if (plp->pcp->pl_flags & P_S)
583 mission_flags |= P_S;
584 if (plp->pcp->pl_flags & P_I)
585 mission_flags |= P_I;
587 if (!(plp->pcp->pl_flags & P_H))
588 /* no stealth on this mission */
589 mission_flags &= ~P_H;
590 if (!(plp->pcp->pl_flags & P_X))
591 /* no stealth on this mission */
592 mission_flags &= ~P_X;
593 if (!(plp->pcp->pl_flags & P_A)) {
594 /* no asw on this mission */
595 mission_flags &= ~P_A;
596 /* FIXME escorts turn ASW patrol into ordinary recon */
598 if (!(plp->pcp->pl_flags & P_MINE)) {
599 /* no asw on this mission */
600 mission_flags &= ~P_MINE;
601 /* FIXME no effect */
603 plp->plane.pln_mobil -= pln_mobcost(dist, &plp->plane, flags);
604 pr("%s equipped\n", prplane(&plp->plane));
606 return mission_flags;
610 pln_equip(struct plist *plp, struct ichrstr *ip, int flags, char mission)
612 struct plchrstr *pcp;
626 if (pp->pln_ship >= 0) {
627 getship(pp->pln_ship, &ship);
628 item = ship.shp_item;
630 } else if (pp->pln_land >= 0) {
631 getland(pp->pln_land, &land);
632 item = land.lnd_item;
635 getsect(pp->pln_x, pp->pln_y, §);
636 item = sect.sct_item;
637 own = sect.sct_oldown;
640 if (ip->i_uid == I_CIVIL) {
641 if (pp->pln_own != own) {
642 pr("You don't control those civilians!\n");
647 if (pcp->pl_fuel > item[I_PETROL]) {
648 pr("%s not enough petrol there!\n", prplane(pp));
651 item[I_PETROL] -= pcp->pl_fuel;
653 if ((flags & P_F) == 0) {
659 if (pp->pln_nuketype == -1) {
661 needed = pp->pln_load;
666 if ((pcp->pl_flags & P_C) == 0 || ip == 0)
669 needed = (pp->pln_load * 2) / ip->i_lbs;
672 if ((pcp->pl_flags & P_MINE) == 0)
675 needed = (pp->pln_load * 2) / ip->i_lbs;
678 if ((pcp->pl_flags & (P_V | P_C)) == 0)
681 needed = pp->pln_load / ip->i_lbs;
684 if (pp->pln_nuketype == -1)
690 if (rval < 0 || (itype != I_NONE && needed <= 0)) {
691 pr("%s can't contribute to mission\n", prplane(pp));
694 if (itype != I_NONE) {
696 /* Supply is broken somewhere, so don't use it for now */
697 if (itype == I_SHELL && item[itype] < needed)
698 item[itype] += supply_commod(plp->plane.pln_own,
703 abandon_needed = !!would_abandon(§, itype, needed, NULL);
704 if (item[itype] < needed + abandon_needed) {
705 pr("Not enough %s for %s\n", ichr[itype].i_name, prplane(pp));
708 item[itype] -= needed;
710 if (itype == I_SHELL && (mission == 's' || mission == 'p'))
715 if (pp->pln_ship >= 0) {
716 if (pp->pln_own != ship.shp_own) {
718 "%s %s prepares for takeoff from ship %s\n",
719 cname(pp->pln_own), prplane(pp), prship(&ship));
721 putship(ship.shp_uid, &ship);
722 } else if (pp->pln_land >= 0) {
723 if (pp->pln_own != land.lnd_own) {
725 "%s %s prepares for takeoff from unit %s\n",
726 cname(pp->pln_own), prplane(pp), prland(&land));
728 putland(land.lnd_uid, &land);
730 if (pp->pln_own != sect.sct_own) {
731 wu(0, sect.sct_own, "%s %s prepares for takeoff from %s\n",
732 cname(pp->pln_own), prplane(pp),
733 xyas(sect.sct_x, sect.sct_y, sect.sct_own));
741 pln_put(struct emp_qelem *list)
743 struct emp_qelem *qp;
744 struct emp_qelem *newqp;
750 /* Here is where planes return home from bombing runs.
751 We need to make sure they still have somewhere to return
755 plp = (struct plist *)qp;
757 /* Ok, check out where it wants to land */
758 if (pp->pln_ship >= 0) {
759 /* It is landing on a carrier */
760 getship(pp->pln_ship, &ship);
761 /* We should do more, like make sure it's really
762 a carrier, etc. but for now just make sure it's
764 if (ship.shp_effic < SHIP_MINEFF) {
766 "Ship #%d has been sunk, plane #%d has nowhere to land, and\n"
767 "splashes into the sea.\n",
768 pp->pln_ship, pp->pln_uid);
772 /* Presume we are landing back in a sector. */
773 getsect(pp->pln_x, pp->pln_y, §);
774 if (sect.sct_type == SCT_WATER || sect.sct_type == SCT_WASTE) {
776 "Nowhere to land at %s, plane #%d crashes and burns...\n",
777 xyas(pp->pln_x, pp->pln_y, pp->pln_own), pp->pln_uid);
781 putplane(pp->pln_uid, pp);
790 pln_removedupes(struct emp_qelem *bomb_list, struct emp_qelem *esc_list)
792 struct emp_qelem *bomb;
793 struct emp_qelem *esc;
797 if (QEMPTY(bomb_list) || QEMPTY(esc_list))
799 bomb = bomb_list->q_forw;
800 while (bomb != bomb_list) {
801 if (QEMPTY(esc_list)) {
805 esc = esc_list->q_forw;
806 bombp = (struct plist *)bomb;
807 while (esc != esc_list) {
808 escp = (struct plist *)esc;
809 if (escp->plane.pln_uid == bombp->plane.pln_uid) {
821 put_plane_on_ship(struct plnstr *plane, struct shpstr *ship)
823 struct plchrstr *pcp;
826 pcp = &plchr[(int)plane->pln_type];
827 mcp = &mchr[(int)ship->shp_type];
829 if (((int)plane->pln_ship) == ((int)ship->shp_uid))
830 return 1; /* Already on ship */
832 /* Try to put on ship as a chopper plane */
833 if ((pcp->pl_flags & P_K) &&
834 (mcp->m_flags & M_CHOPPER) &&
835 (ship->shp_nchoppers < mcp->m_nchoppers)) {
837 ship->shp_nchoppers++;
838 plane->pln_x = ship->shp_x;
839 plane->pln_y = ship->shp_y;
840 plane->pln_ship = ship->shp_uid;
841 putship(ship->shp_uid, ship);
842 putplane(plane->pln_uid, plane);
846 /* Try to put on ship as an xlight plane */
847 if ((pcp->pl_flags & P_E) &&
848 (mcp->m_flags & M_XLIGHT) &&
849 (ship->shp_nxlight < mcp->m_nxlight)) {
852 plane->pln_x = ship->shp_x;
853 plane->pln_y = ship->shp_y;
854 plane->pln_ship = ship->shp_uid;
855 putship(ship->shp_uid, ship);
856 putplane(plane->pln_uid, plane);
860 /* Try to put on ship as a normal plane */
861 if ((((pcp->pl_flags & P_L) && (mcp->m_flags & M_FLY)) ||
862 ((pcp->pl_flags & P_M) && (pcp->pl_flags & P_L) &&
863 (mcp->m_flags & M_MSL))) &&
864 (ship->shp_nplane < mcp->m_nplanes)) {
867 plane->pln_x = ship->shp_x;
868 plane->pln_y = ship->shp_y;
869 plane->pln_ship = ship->shp_uid;
870 putship(ship->shp_uid, ship);
871 putplane(plane->pln_uid, plane);
880 take_plane_off_ship(struct plnstr *plane, struct shpstr *ship)
882 struct plchrstr *pcp;
885 pcp = &plchr[(int)plane->pln_type];
886 mcp = &mchr[(int)ship->shp_type];
888 /* Try to take off ship as a chopper plane */
889 if ((pcp->pl_flags & P_K) &&
890 (mcp->m_flags & M_CHOPPER) && (ship->shp_nchoppers)) {
892 ship->shp_nchoppers--;
893 plane->pln_ship = -1;
894 putship(ship->shp_uid, ship);
895 putplane(plane->pln_uid, plane);
899 /* Try to take off ship as an xlight plane */
900 if ((pcp->pl_flags & P_E) &&
901 (mcp->m_flags & M_XLIGHT) && (ship->shp_nxlight)) {
904 plane->pln_ship = -1;
905 putship(ship->shp_uid, ship);
906 putplane(plane->pln_uid, plane);
910 /* Try to take off ship as a normal plane */
911 if ((((pcp->pl_flags & P_L) && (mcp->m_flags & M_FLY)) ||
912 ((pcp->pl_flags & P_M) && (pcp->pl_flags & P_L) &&
913 (mcp->m_flags & M_MSL))) && (ship->shp_nplane)) {
916 plane->pln_ship = -1;
917 putship(ship->shp_uid, ship);
918 putplane(plane->pln_uid, plane);
927 take_plane_off_land(struct plnstr *plane, struct lndstr *land)
929 struct plchrstr *pcp;
931 pcp = &plchr[(int)plane->pln_type];
933 /* Try to take off ship as an xlight plane */
934 if ((pcp->pl_flags & P_E) && land->lnd_nxlight) {
937 plane->pln_land = -1;
938 putland(land->lnd_uid, land);
939 putplane(plane->pln_uid, plane);
948 can_be_on_ship(int p, int s)
952 struct plchrstr *pcp;
958 pcp = &plchr[(int)plane.pln_type];
959 mcp = &mchr[(int)ship.shp_type];
961 if (pcp->pl_flags & P_L)
962 if (mcp->m_flags & M_FLY)
965 if (pcp->pl_flags & P_K)
966 if (mcp->m_flags & M_CHOPPER)
969 if (pcp->pl_flags & P_M)
970 if (mcp->m_flags & M_MSL)
973 if (pcp->pl_flags & P_E)
974 if (mcp->m_flags & M_XLIGHT)
981 plane_sweep(struct emp_qelem *plane_list, coord x, coord y)
984 struct plchrstr *pcp;
985 struct emp_qelem *qp;
986 struct emp_qelem *next;
992 getsect(x, y, §);
993 mines_there = sect.sct_mines;
995 if (mines_there == 0)
998 if ((sect.sct_type != SCT_WATER) && (sect.sct_type != SCT_HARBR))
1001 for (qp = plane_list->q_forw; ((qp != plane_list) && (mines_there));
1004 ip = (struct plist *)qp;
1007 if (!(pcp->pl_flags & P_SWEEP)) /* if it isn't an sweep plane */
1010 if (chance((100.0 - pp->pln_acc) / 100.0)) {
1011 pr("Sweep! in %s\n",
1012 xyas(sect.sct_x, sect.sct_y, pp->pln_own));
1018 if (found && map_set(player->cnum, sect.sct_x, sect.sct_y, 'X', 0))
1019 writemap(player->cnum);
1020 sect.sct_mines = mines_there;
1025 count_planes(struct shpstr *sp)
1027 struct nstr_item ni;
1028 struct plnstr plane;
1029 struct plchrstr *pcp;
1030 struct mchrstr *mcp;
1035 if (sp->shp_effic < SHIP_MINEFF)
1038 mcp = &mchr[(int)sp->shp_type];
1039 snxtitem_xy(&ni, EF_PLANE, sp->shp_x, sp->shp_y);
1040 while (nxtitem(&ni, &plane)) {
1041 if (plane.pln_own == 0)
1043 if (plane.pln_ship == sp->shp_uid) {
1044 pcp = &plchr[(int)plane.pln_type];
1045 if ((pcp->pl_flags & P_K) && (nchoppers < mcp->m_nchoppers))
1047 else if ((pcp->pl_flags & P_E) && (nxlight < mcp->m_nxlight))
1049 else if ((pcp->pl_flags & P_L) || (pcp->pl_flags & P_M))
1054 if (nplane != sp->shp_nplane ||
1055 nxlight != sp->shp_nxlight || nchoppers != sp->shp_nchoppers) {
1056 sp->shp_nplane = nplane;
1057 sp->shp_nxlight = nxlight;
1058 sp->shp_nchoppers = nchoppers;
1059 putship(sp->shp_uid, sp);
1064 count_land_planes(struct lndstr *lp)
1066 struct nstr_item ni;
1067 struct plnstr plane;
1070 if (lp->lnd_effic < LAND_MINEFF)
1073 snxtitem_all(&ni, EF_PLANE);
1074 while (nxtitem(&ni, &plane)) {
1075 if (plane.pln_own == 0)
1077 if (plane.pln_land == lp->lnd_uid)
1081 if (lp->lnd_nxlight != nplane) {
1082 lp->lnd_nxlight = nplane;
1083 putland(lp->lnd_uid, lp);
1088 count_sect_planes(struct sctstr *sp)
1091 struct nstr_item ni;
1092 struct plnstr plane;
1094 snxtitem_all(&ni, EF_PLANE);
1095 while (nxtitem(&ni, &plane)) {
1098 if (plane.pln_flags & PLN_LAUNCHED)
1100 if (plane.pln_x == sp->sct_x && plane.pln_y == sp->sct_y)
1108 put_plane_on_land(struct plnstr *plane, struct lndstr *land)
1110 struct plchrstr *pcp;
1112 pcp = &plchr[(int)plane->pln_type];
1114 if (((int)plane->pln_land) == ((int)land->lnd_uid))
1115 return 1; /* Already on unit */
1117 /* Try to put on unit as an xlight plane */
1118 if ((pcp->pl_flags & P_E) &&
1119 (land->lnd_nxlight < land->lnd_maxlight)) {
1121 land->lnd_nxlight++;
1122 plane->pln_x = land->lnd_x;
1123 plane->pln_y = land->lnd_y;
1124 plane->pln_land = land->lnd_uid;
1125 putland(land->lnd_uid, land);
1126 putplane(plane->pln_uid, plane);
1130 /* We have failed */
1135 pln_hitchance(struct plnstr *pp, int hardtarget, int type)
1137 struct plchrstr *pcp = plchr + pp->pln_type;
1138 double tfact = (double)(pp->pln_tech - pcp->pl_tech) /
1139 (pp->pln_tech - pcp->pl_tech / 2);
1140 int acc = pp->pln_acc;
1143 if (type == EF_SHIP) {
1144 if (pcp->pl_flags & P_A)
1146 if (!(pcp->pl_flags & P_T))
1149 hitchance = (int)(pp->pln_effic * (1.0 - 0.1 * tfact) *
1150 (1.0 - acc / 100.0)) - hardtarget;
1152 /* smooth out the bottom of the graph with asymtote at 5 -KHS */
1154 hitchance = 5 + ldround(300.0 / (40.0 - hitchance), 1);
1155 if (hitchance > 100)
1160 /* return 0 if there was a nuclear detonation */
1163 pln_damage(struct plnstr *pp, coord x, coord y, char type, int *nukedamp,
1167 struct plchrstr *pcp = plchr + pp->pln_type;
1175 if (pp->pln_nuketype != -1) {
1176 if (nuk_on_plane(&nuke, pp->pln_uid) >= 0) {
1177 mpr(pp->pln_own, "Releasing RV's for %s detonation...\n",
1178 pp->pln_flags & PLN_AIRBURST ? "airburst" : "groundburst");
1179 pp->pln_nuketype = -1;
1180 *nukedamp = detonate(&nuke, x, y,
1181 pp->pln_flags & PLN_AIRBURST);
1188 if (!pp->pln_load) /* e.g. ab, blowing up on launch pad */
1191 i = roll(pp->pln_load) + 1;
1192 if (i > pp->pln_load)
1195 if (pcp->pl_flags & P_M) {
1196 if (pcp->pl_flags & P_MAR)
1198 } else if (pcp->pl_flags & P_T)
1201 aim = 100 - pp->pln_acc;
1215 hitroll = roll(100);
1216 if (hitroll >= 90) {
1219 mpr(pp->pln_own, "BLAM");
1220 } else if (hitroll < aim) {
1223 mpr(pp->pln_own, "Blam");
1227 mpr(pp->pln_own, "blam");
1230 mpr(pp->pln_own, "-");
1233 mpr(pp->pln_own, "\n");
1240 pln_identchance(struct plnstr *pp, int hardtarget, int type)
1243 (100.0 - pln_hitchance(pp, hardtarget, type)) / 100.0;
1244 return (int)(100 - 100 * misschance * misschance);
1248 pln_mobcost(int dist, struct plnstr *pp, int flags)
1252 cost = 20.0 / (pp->pln_effic / 100.0);
1253 if ((flags & P_F) || (flags & P_ESC))
1256 return ldround(cost * dist / pp->pln_range_max + 5, 1);
1260 * Set PP's tech to TLEV along with everything else that depends on it.
1263 pln_set_tech(struct plnstr *pp, int tlev)
1265 struct plchrstr *pcp = plchr + pp->pln_type;
1266 int tech_diff = tlev - pcp->pl_tech;
1267 int limited_range = pp->pln_range < pp->pln_range_max;
1269 if (CANT_HAPPEN(tech_diff < 0)) {
1274 pp->pln_tech = tlev;
1275 pp->pln_att = PLN_ATTDEF(pcp->pl_att, tech_diff);
1276 pp->pln_def = PLN_ATTDEF(pcp->pl_def, tech_diff);
1277 pp->pln_acc = PLN_ACC(pcp->pl_acc, tech_diff);
1278 pp->pln_range_max = PLN_RAN(pcp->pl_range, tech_diff);
1279 pp->pln_load = PLN_LOAD(pcp->pl_load, tech_diff);
1281 if (!limited_range || pp->pln_range > pp->pln_range_max)
1282 pp->pln_range = pp->pln_range_max;