src/lib/subs/retreat.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  *  retreat.c: Retreat subroutines
00029  * 
00030  *  Known contributors to this file:
00031  *     Steve McClure, 2000
00032  */
00033 
00034 #include <config.h>
00035 
00036 #include "damage.h"
00037 #include "file.h"
00038 #include "land.h"
00039 #include "map.h"
00040 #include "misc.h"
00041 #include "nat.h"
00042 #include "news.h"
00043 #include "nsc.h"
00044 #include "optlist.h"
00045 #include "path.h"
00046 #include "player.h"
00047 #include "prototypes.h"
00048 #include "retreat.h"
00049 #include "sect.h"
00050 #include "ship.h"
00051 #include "xy.h"
00052 
00053 static int findcondition(char);
00054 static int retreat_land1(struct lndstr *, char, int);
00055 static int retreat_ship1(struct shpstr *, char, int);
00056 
00057 struct ccode {
00058     char code;
00059     char *desc[2];
00060 };
00061 
00062 static struct ccode conditions[] = {
00063     { 'i', { "retreated with a damaged friend",
00064              "was damaged" } },
00065     { 't', { "retreated with a torpedoed ship",
00066              "was hit by a torpedo" } },
00067     { 's', { "retreated with a ship scared by sonar",
00068              "detected a sonar ping" } },
00069     { 'h', { "retreated with a helpless ship",
00070              "was fired upon with no one able to defend it" } },
00071     { 'b', { "retreated with a bombed friend",
00072              "was bombed" } },
00073     { 'd', { "retreated with a depth-charged ship",
00074              "was depth-charged" } },
00075     { 'u', { "retreated with a boarded ship", "was boarded" } },
00076     { 0,   { "panicked", "panicked"} }
00077 };
00078 
00079 int
00080 check_retreat_and_do_shipdamage(struct shpstr *sp, int dam)
00081 {
00082     if (dam <= 0)
00083         return 0;
00084 
00085     shipdamage(sp, dam);
00086     if (sp->shp_rflags & RET_INJURED)
00087         retreat_ship(sp, 'i');
00088 
00089     return 1;
00090 }
00091 
00092 void
00093 retreat_ship(struct shpstr *sp, char code)
00094 {
00095     struct nstr_item ni;
00096     struct shpstr ship;
00097 
00098     if (sp->shp_rflags & RET_GROUP) {
00099         snxtitem_group(&ni, EF_SHIP, sp->shp_fleet);
00100         while (nxtitem(&ni, &ship))
00101             if (ship.shp_own == sp->shp_own) {
00102                 if (ship.shp_uid == sp->shp_uid) {
00103                     retreat_ship1(sp, code, 1);
00104                     if (sp->shp_rpath[0] == 0)
00105                         sp->shp_rflags = 0;
00106                 } else {
00107                     retreat_ship1(&ship, code, 0);
00108                     getship(ship.shp_uid, &ship);
00109                     if (ship.shp_rpath[0] == 0) {
00110                         ship.shp_rflags = 0;
00111                         putship(ship.shp_uid, &ship);
00112                     }
00113                 }
00114             }
00115     } else {
00116         retreat_ship1(sp, code, 1);
00117         if (sp->shp_rpath[0] == 0)
00118             sp->shp_rflags = 0;
00119     }
00120 }
00121 
00122 static int
00123 retreat_ship1(struct shpstr *sp, char code, int orig)
00124 
00125 
00126                         /* Is this the originally scared ship, or a follower */
00127 {
00128     struct sctstr sect;
00129     int n;
00130     int m;
00131     int max;
00132     int dir;
00133     coord newx;
00134     coord newy;
00135     coord dx;
00136     coord dy;
00137     int stopping;
00138     int mines;
00139     int shells;
00140     double mobcost;
00141     struct mchrstr *mcp;
00142     int changed;
00143 
00144     sp->shp_mission = 0;
00145     if (sp->shp_own == 0)
00146         return 0;
00147 
00148     n = 0;
00149     if (sp->shp_effic < SHIP_MINEFF) {
00150         wu(0, sp->shp_own,
00151            "%s %s,\nbut it died in the attack, and so couldn't retreat!\n",
00152            prship(sp), conditions[findcondition(code)].desc[orig]);
00153         if (!orig)
00154             putship(sp->shp_uid, sp);
00155         return 0;
00156     }
00157 
00158     if (opt_SAIL) {
00159         /* can't retreat a ship that's sailin, bad things happend */
00160         if (*sp->shp_path) {
00161             wu(0, sp->shp_own,
00162                "%s %s,\nbut had sailing orders, and couldn't retreat!\n",
00163                prship(sp), conditions[findcondition(code)].desc[orig]);
00164             if (!orig)
00165                 putship(sp->shp_uid, sp);
00166             return 0;
00167         }
00168     }
00169     /* check crew - uws don't count */
00170     if (sp->shp_item[I_MILIT] == 0 && sp->shp_item[I_CIVIL] == 0) {
00171         wu(0, sp->shp_own,
00172            "%s %s,\nbut had no crew, and couldn't retreat!\n", prship(sp),
00173            conditions[findcondition(code)].desc[orig]);
00174         if (!orig)
00175             putship(sp->shp_uid, sp);
00176         return 0;
00177     }
00178 
00179     getsect(sp->shp_x, sp->shp_y, &sect);
00180     switch (shp_check_nav(&sect, sp)) {
00181     case CN_CONSTRUCTION:
00182         wu(0, sp->shp_own,
00183            "%s %s,\nbut was caught in a construction zone, and couldn't retreat!\n",
00184            prship(sp), conditions[findcondition(code)].desc[orig]);
00185         if (!orig)
00186             putship(sp->shp_uid, sp);
00187         return 0;
00188     case CN_LANDLOCKED:
00189         wu(0, sp->shp_own,
00190            "%s %s,\nbut was landlocked, and couldn't retreat!\n",
00191            prship(sp), conditions[findcondition(code)].desc[orig]);
00192         if (!orig)
00193             putship(sp->shp_uid, sp);
00194         return 0;
00195         /*NOTREACHED*/
00196     case CN_NAVIGABLE:
00197         break;
00198     case CN_ERROR:
00199     default:
00200         wu(0, sp->shp_own,
00201            "%s %s,\nbut was subject to an empire error, and couldn't retreat!\n",
00202            prship(sp), conditions[findcondition(code)].desc[orig]);
00203         if (!orig)
00204             putship(sp->shp_uid, sp);
00205         return 0;
00206         /*NOTREACHED*/
00207     }
00208 
00209     if (sp->shp_mobil <= 0.0) {
00210         wu(0, sp->shp_own,
00211            "%s %s,\nbut had no mobility, and couldn't retreat!\n",
00212            prship(sp), conditions[findcondition(code)].desc[orig]);
00213         if (!orig)
00214             putship(sp->shp_uid, sp);
00215         return 0;
00216     }
00217 
00218     n = -MAX_RETREAT;
00219     stopping = 0;
00220     while (!stopping && n) {
00221         dx = dy = 0;
00222         if (sp->shp_rpath[0] == 0) {
00223             stopping = 1;
00224             continue;
00225         }
00226         if (sp->shp_mobil <= 0.0) {
00227             wu(0, sp->shp_own,
00228                "%s %s,\nbut ran out of mobility, and couldn't retreat fully!\n",
00229                prship(sp), conditions[findcondition(code)].desc[orig]);
00230             if (!orig)
00231                 putship(sp->shp_uid, sp);
00232             return 0;
00233         }
00234         dir = chkdir(sp->shp_rpath[0], DIR_STOP, DIR_LAST);
00235         memmove(sp->shp_rpath, sp->shp_rpath+1, sizeof(sp->shp_rpath) - 1);
00236         if (dir < 0)
00237             continue;
00238         if (dir == DIR_STOP)
00239             stopping++;
00240         else {
00241             dx = diroff[dir][0];
00242             dy = diroff[dir][1];
00243         }
00244         n++;
00245 
00246         mcp = &mchr[(int)sp->shp_type];
00247         newx = xnorm(sp->shp_x + dx);
00248         newy = ynorm(sp->shp_y + dy);
00249         mobcost = shp_mobcost(sp);
00250 
00251         getsect(newx, newy, &sect);
00252         if (shp_check_nav(&sect, sp) != CN_NAVIGABLE ||
00253             (sect.sct_own && sect.sct_own != sp->shp_own &&
00254              getrel(getnatp(sect.sct_own), sp->shp_own) < FRIENDLY)) {
00255             wu(0, sp->shp_own, "%s %s,\nbut could not retreat to %s!\n",
00256                prship(sp), conditions[findcondition(code)].desc[orig],
00257                xyas(newx, newy, sp->shp_own));
00258             if (!orig)
00259                 putship(sp->shp_uid, sp);
00260             return 0;
00261         }
00262         sp->shp_x = newx;
00263         sp->shp_y = newy;
00264         sp->shp_mobil -= mobcost;
00265         if (stopping)
00266             continue;
00267 
00268         mines = sect.sct_mines;
00269         changed = 0;
00270         if ((mcp->m_flags & M_SWEEP) && sect.sct_type == SCT_WATER) {
00271             max = mcp->m_item[I_SHELL];
00272             shells = sp->shp_item[I_SHELL];
00273             for (m = 0; mines > 0 && m < 5; m++) {
00274                 if (chance(0.66)) {
00275                     mines--;
00276                     shells = MIN(max, shells + 1);
00277                     changed |= map_set(sp->shp_own, sp->shp_x, sp->shp_y,
00278                                        'X', 0);
00279                 }
00280             }
00281             if (sect.sct_mines != mines) {
00282                 wu(0, sp->shp_own,
00283                    "%s cleared %d mine%s in %s while retreating\n",
00284                    prship(sp), sect.sct_mines-mines, splur(sect.sct_mines-mines),
00285                    xyas(newx, newy, sp->shp_own));
00286                 sect.sct_mines = mines;
00287                 sp->shp_item[I_SHELL] = shells;
00288                 putsect(&sect);
00289             }
00290             if (changed)
00291                 writemap(sp->shp_own);
00292         }
00293         if (sect.sct_type == SCT_WATER && mines > 0
00294             && chance(DMINE_HITCHANCE(mines))) {
00295             wu(0, sp->shp_own,
00296                "%s %s,\nand hit a mine in %s while retreating!\n",
00297                prship(sp), conditions[findcondition(code)].desc[orig],
00298                xyas(newx, newy, sp->shp_own));
00299             nreport(sp->shp_own, N_HIT_MINE, 0, 1);
00300             m = MINE_DAMAGE();
00301             shipdamage(sp, m);
00302             mines--;
00303             if (map_set(sp->shp_own, sp->shp_x, sp->shp_y, 'X', 0))
00304                 writemap(sp->shp_own);
00305             sect.sct_mines = mines;
00306             putsect(&sect);
00307             if (!orig)
00308                 putship(sp->shp_uid, sp);
00309             return 0;
00310         }
00311     }
00312 
00313     if (orig) {
00314         wu(0, sp->shp_own, "%s %s, and retreated to %s\n",
00315            prship(sp), conditions[findcondition(code)].desc[orig],
00316            xyas(sp->shp_x, sp->shp_y, sp->shp_own));
00317     } else {
00318         wu(0, sp->shp_own, "%s %s, and ended up at %s\n",
00319            prship(sp),
00320            conditions[findcondition(code)].desc[orig],
00321            xyas(sp->shp_x, sp->shp_y, sp->shp_own));
00322     }
00323     if (!orig)
00324         putship(sp->shp_uid, sp);
00325     return 1;
00326 }
00327 
00328 static int
00329 findcondition(char code)
00330 {
00331     int i;
00332 
00333     for (i = 0; conditions[i].code && conditions[i].code != code; i++) ;
00334     CANT_HAPPEN(!conditions[i].code);
00335     return i;
00336 }
00337 
00338 int
00339 check_retreat_and_do_landdamage(struct lndstr *lp, int dam)
00340 {
00341     if (dam <= 0)
00342         return 0;
00343 
00344     landdamage(lp, dam);
00345     if (lp->lnd_rflags & RET_INJURED)
00346         retreat_land(lp, 'i');
00347 
00348     return 1;
00349 }
00350 
00351 void
00352 retreat_land(struct lndstr *lp, char code)
00353 {
00354     struct nstr_item ni;
00355     struct lndstr land;
00356 
00357     if (lp->lnd_rflags & RET_GROUP) {
00358         snxtitem_group(&ni, EF_SHIP, lp->lnd_army);
00359         while (nxtitem(&ni, &land))
00360             if (land.lnd_own == lp->lnd_own) {
00361                 if (land.lnd_uid == lp->lnd_uid) {
00362                     retreat_land1(lp, code, 1);
00363                     if (lp->lnd_rpath[0] == 0)
00364                         lp->lnd_rflags = 0;
00365                 } else {
00366                     retreat_land1(&land, code, 0);
00367                     getland(land.lnd_uid, &land);
00368                     if (land.lnd_rpath[0] == 0) {
00369                         land.lnd_rflags = 0;
00370                         putland(land.lnd_uid, &land);
00371                     }
00372                 }
00373             }
00374     } else {
00375         retreat_land1(lp, code, 1);
00376         if (lp->lnd_rpath[0] == 0)
00377             lp->lnd_rflags = 0;
00378     }
00379 }
00380 
00381 static int
00382 retreat_land1(struct lndstr *lp, char code, int orig)
00383 
00384 
00385                         /* Is this the originally scared unit, or a follower */
00386 {
00387     struct sctstr sect;
00388     int n;
00389     int m;
00390     int max;
00391     int dir;
00392     coord newx;
00393     coord newy;
00394     coord dx;
00395     coord dy;
00396     int stopping;
00397     int mines;
00398     int shells;
00399     double mobcost;
00400     struct lchrstr *lcp;
00401 
00402     lp->lnd_mission = 0;
00403     if (lp->lnd_own == 0)
00404         return 0;
00405 
00406     n = 0;
00407     if (lp->lnd_effic < LAND_MINEFF) {
00408         wu(0, lp->lnd_own,
00409            "%s %s,\nbut it died in the attack, and so couldn't retreat!\n",
00410            prland(lp), conditions[findcondition(code)].desc[orig]);
00411         if (!orig)
00412             putland(lp->lnd_uid, lp);
00413         return 0;
00414     }
00415 
00416     getsect(lp->lnd_x, lp->lnd_y, &sect);
00417 
00418     if (lp->lnd_mobil <= 0.0) {
00419         wu(0, lp->lnd_own,
00420            "%s %s,\nbut had no mobility, and couldn't retreat!\n",
00421            prland(lp), conditions[findcondition(code)].desc[orig]);
00422         if (!orig)
00423             putland(lp->lnd_uid, lp);
00424         return 0;
00425     }
00426 
00427     n = -MAX_RETREAT;
00428     stopping = 0;
00429     while (!stopping && n) {
00430         dx = dy = 0;
00431         if (lp->lnd_rpath[0] == 0) {
00432             stopping = 1;
00433             continue;
00434         }
00435         if (lp->lnd_mobil <= 0.0) {
00436             wu(0, lp->lnd_own,
00437                "%s %s,\nbut ran out of mobility, and couldn't retreat fully!\n",
00438                prland(lp), conditions[findcondition(code)].desc[orig]);
00439             if (!orig)
00440                 putland(lp->lnd_uid, lp);
00441             return 0;
00442         }
00443         dir = chkdir(lp->lnd_rpath[0], DIR_STOP, DIR_LAST);
00444         memmove(lp->lnd_rpath, lp->lnd_rpath+1, sizeof(lp->lnd_rpath) - 1);
00445         if (dir < 0)
00446             continue;
00447         if (dir == DIR_STOP)
00448             stopping++;
00449         else {
00450             dx = diroff[dir][0];
00451             dy = diroff[dir][1];
00452         }
00453         n++;
00454 
00455         lcp = &lchr[(int)lp->lnd_type];
00456         newx = xnorm(lp->lnd_x + dx);
00457         newy = ynorm(lp->lnd_y + dy);
00458 
00459         getsect(newx, newy, &sect);
00460         mobcost = lnd_mobcost(lp, &sect);
00461         if (mobcost < 0
00462             || sect.sct_type == SCT_MOUNT
00463             || sect.sct_own != lp->lnd_own) {
00464             wu(0, lp->lnd_own, "%s %s,\nbut could not retreat to %s!\n",
00465                prland(lp),
00466                conditions[findcondition(code)].desc[orig],
00467                xyas(newx, newy, lp->lnd_own));
00468             if (!orig)
00469                 putland(lp->lnd_uid, lp);
00470             return 0;
00471         }
00472         lp->lnd_x = newx;
00473         lp->lnd_y = newy;
00474         lp->lnd_mobil -= mobcost;
00475         if (stopping)
00476             continue;
00477 
00478         mines = sect.sct_mines;
00479         if ((lcp->l_flags & L_ENGINEER) && mines > 0 &&
00480             (sect.sct_oldown != lp->lnd_own)) {
00481             max = lcp->l_item[I_SHELL];
00482             shells = lp->lnd_item[I_SHELL];
00483             for (m = 0; mines > 0 && m < 5; m++) {
00484                 if (chance(0.66)) {
00485                     mines--;
00486                     shells = MIN(max, shells + 1);
00487                 }
00488             }
00489             sect.sct_mines = mines;
00490             lp->lnd_item[I_SHELL] = shells;
00491             putsect(&sect);
00492         }
00493         if (mines > 0 && (sect.sct_oldown != lp->lnd_own) &&
00494             chance(DMINE_LHITCHANCE(mines))) {
00495             wu(0, lp->lnd_own,
00496                "%s %s,\nand hit a mine in %s while retreating!\n",
00497                prland(lp),
00498                conditions[findcondition(code)].desc[orig],
00499                xyas(newx, newy, lp->lnd_own));
00500             nreport(lp->lnd_own, N_LHIT_MINE, 0, 1);
00501             m = MINE_LDAMAGE();
00502             if (lcp->l_flags & L_ENGINEER)
00503                 m /= 2;
00504             landdamage(lp, m);
00505             mines--;
00506             sect.sct_mines = mines;
00507             putsect(&sect);
00508             if (!orig)
00509                 putland(lp->lnd_uid, lp);
00510             return 0;
00511         }
00512     }
00513 
00514     if (orig) {
00515         wu(0, lp->lnd_own, "%s %s, and retreated to %s\n",
00516            prland(lp),
00517            conditions[findcondition(code)].desc[orig],
00518            xyas(lp->lnd_x, lp->lnd_y, lp->lnd_own));
00519     } else {
00520         wu(0, lp->lnd_own, "%s %s, and ended up at %s\n",
00521            prland(lp),
00522            conditions[findcondition(code)].desc[orig],
00523            xyas(lp->lnd_x, lp->lnd_y, lp->lnd_own));
00524     }
00525     if (!orig)
00526         putland(lp->lnd_uid, lp);
00527     return 1;
00528 }

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