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 #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
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
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
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, §);
00180 switch (shp_check_nav(§, 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
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
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, §);
00252 if (shp_check_nav(§, 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(§);
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(§);
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
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, §);
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, §);
00460 mobcost = lnd_mobcost(lp, §);
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(§);
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(§);
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 }