src/lib/subs/plnsub.c

Go to the documentation of this file.
00001 /*
00002  *  Empire - A multi-player, client/server Internet based war game.
00003  *  Copyright (C) 1986-2007, Dave Pare, Jeff Bailey, Thomas Ruschak,
00004  *                           Ken Stevens, Steve McClure
00005  *
00006  *  This program is free software; you can redistribute it and/or modify
00007  *  it under the terms of the GNU General Public License as published by
00008  *  the Free Software Foundation; either version 2 of the License, or
00009  *  (at your option) any later version.
00010  *
00011  *  This program is distributed in the hope that it will be useful,
00012  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  *  GNU General Public License for more details.
00015  *
00016  *  You should have received a copy of the GNU General Public License
00017  *  along with this program; if not, write to the Free Software
00018  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00019  *
00020  *  ---
00021  *
00022  *  See files README, COPYING and CREDITS in the root of the source
00023  *  tree for related information and legal notices.  It is expected
00024  *  that future projects/authors will amend these files as needed.
00025  *
00026  *  ---
00027  *
00028  *  plnsub.c: Plane subroutine stuff
00029  * 
00030  *  Known contributors to this file:
00031  *     Dave Pare, 1986
00032  *     Ken Stevens, 1995
00033  *     Steve McClure, 1998-2000
00034  *     Markus Armbruster, 2004-2005
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  * Get assembly point argument.
00063  * If INPUT is not empty, use it, else prompt for more input using PROMPT.
00064  * If this yields a valid assembly point, read it into *AP_SECT and
00065  * return AP_SECT.
00066  * Else complain and return NULL.
00067  * *AP_SECT and BUF[1024] may be modified in either case.
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     /* over own or allied sector is fine */
00084     if (ap_sect->sct_own == player->cnum
00085         || getrel(getnatp(ap_sect->sct_own), player->cnum) == ALLIED)
00086         return ap_sect;
00087 
00088     /* over own or allied ship is fine */
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     /* offer carriers */
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             /* clear to land on ship#CNO */
00140             pr("landing on carrier %d\n", cno);
00141             flags |= fl;
00142             *shipno = cno;
00143             *flagp = flags;
00144             return 0;
00145         }
00146     }
00147 
00148     /* try to land at sector */
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     /* clear to land at sector */
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     /* for both lists */
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 /*                                      plp->plane.pln_own = ship.shp_own;*/
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, &sect);
00229             if (plp->plane.pln_own != sect.sct_own) {
00230 /*                              plp->plane.pln_own = sect.sct_own;*/
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  * Has PP's type capabilities satisfying WANTFLAGS and NOWANTFLAGS?
00347  * A plane type is capable unless
00348  * - it lacks all of the P_F, P_ESC in WANTFLAGS, or
00349  * - it lacks all of the P_E, P_L, P_K in WANTFLAGS, or
00350  * - it lacks any of the other capabilities in WANTFLAGS, or
00351  * - it has any of the capabilities in NOWANTFLAGS.
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  * Find plane types that can operate from carrier SP.
00381  * If MSL find missile types, else non-missile types.
00382  * Return a combination of P_L, P_K, P_E.
00383  * It's zero if SP can't support air operations due to its type or
00384  * state (low efficiency).
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         /* ship: needs to be own or allied, efficient */
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         /* land: needs to be own or allied, efficient, not embarked */
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         /* sector: needs to be own or allied, efficient airfield */
00454         if (!getsect(pp->pln_x, pp->pln_y, &sect)) {
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         /* need airfield unless VTOL */
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             /* no stealth on this mission */
00574             mission_flags &= ~P_H;
00575         if (!(plp->pcp->pl_flags & P_X))
00576             /* no stealth on this mission */
00577             mission_flags &= ~P_X;
00578         if (!(plp->pcp->pl_flags & P_A)) {
00579             /* no asw on this mission */
00580             mission_flags &= ~P_A;
00581             /* FIXME escorts turn ASW patrol into ordinary recon */
00582         }
00583         if (!(plp->pcp->pl_flags & P_MINE)) {
00584             /* no asw on this mission */
00585             mission_flags &= ~P_MINE;
00586             /* FIXME no effect */
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, &sect);
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             /* Supply is broken somewhere, so don't use it for now */
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(&sect, 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(&sect);
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     /* Here is where planes return home from bombing runs.
00736        We need to make sure they still have somewhere to return
00737        home to! */
00738     qp = list->q_forw;
00739     while (qp != list) {
00740         plp = (struct plist *)qp;
00741         pp = &plp->plane;
00742         /* Ok, check out where it wants to land */
00743         if (pp->pln_ship >= 0) {
00744             /* It is landing on a carrier */
00745             getship(pp->pln_ship, &ship);
00746             /* We should do more, like make sure it's really
00747                a carrier, etc. but for now just make sure it's
00748                not sunk. */
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             /* Presume we are landing back in a sector. */
00758             getsect(pp->pln_x, pp->pln_y, &sect);
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  * Fit a plane of PP's type on ship SP.
00807  * Adjust SP's plane counters.
00808  * Updating the plane accordingly is the caller's job.
00809  * Return whether it fits.
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         /* chopper, try chopper slot first */
00820         if (sp->shp_nchoppers < mcp->m_nchoppers)
00821             return ++sp->shp_nchoppers;
00822         /* else try plane slot */
00823         wanted = M_FLY;
00824     } else if (pcp->pl_flags & P_E) {
00825         /* x-light, try x-light slot first */
00826         if (sp->shp_nxlight < mcp->m_nxlight)
00827             return ++sp->shp_nxlight;
00828         /* else try plane slot */
00829         wanted = M_MSL | M_FLY;
00830     } else if (!(pcp->pl_flags & P_L)) {
00831         /* not light, no go */
00832         wanted = 0;
00833     } else if (pcp->pl_flags & P_M) {
00834         /* missile, use plane slot */
00835         wanted = M_MSL | M_FLY;
00836     } else {
00837         /* fixed-wing plane, use plane slot */
00838         wanted = M_FLY;
00839     }
00840 
00841     if ((mcp->m_flags & wanted) == 0)
00842         return 0;               /* ship not capable */
00843 
00844     if (sp->shp_nplane < mcp->m_nplanes)
00845         return ++sp->shp_nplane;
00846 
00847     return 0;
00848 }
00849 
00850 /*
00851  * Fit a plane of PP's type off ship SP.
00852  * Adjust SP's plane counters, badly.  You need to run count_planes()
00853  * before the next fit_plane_on_ship().
00854  * Updating the plane accordingly is the caller's job.
00855  */
00856 static void
00857 fit_plane_off_ship(struct plnstr *pp, struct shpstr *sp)
00858 {
00859     /*
00860      * Frees chopper and nxlight slots first, which is why we need to
00861      * run count_planes() before fit_plane_on_ship().
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;               /* Already on ship */
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  * Fit a plane of PP's type on land unit LP.
00913  * Adjust LP's plane counters.
00914  * Updating the plane accordingly is the caller's job.
00915  * Return whether it fits.
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  * Fit a plane of PP's type off land unit LP.
00931  * Adjust LP's plane counters.
00932  * Updating the plane accordingly is the caller's job.
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;               /* Already on unit */
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  * Could a plane of PP's type be on on ship SP?
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, &sect);
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)) /* if it isn't an sweep plane */
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(&sect);
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     /* smooth out the bottom of the graph with asymtote at 5 -KHS */
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 /* return 0 if there was a nuclear detonation */
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)          /* e.g. ab, blowing up on launch pad */
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  * Set PP's tech to TLEV along with everything else that depends on it.
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 }

Generated on Fri Mar 28 11:01:15 2008 for empserver by  doxygen 1.5.2