]> git.pond.sub.org Git - empserver/blob - src/lib/subs/retreat.c
Import of Empire 4.2.12
[empserver] / src / lib / subs / retreat.c
1 /*
2  *  Empire - A multi-player, client/server Internet based war game.
3  *  Copyright (C) 1986-2000, Dave Pare, Jeff Bailey, Thomas Ruschak,
4  *                           Ken Stevens, Steve McClure
5  *
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.
10  *
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.
15  *
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
19  *
20  *  ---
21  *
22  *  See the "LEGAL", "LICENSE", "CREDITS" and "README" files for all the
23  *  related information and legal notices. It is expected that any future
24  *  projects/authors will amend these files as needed.
25  *
26  *  ---
27  *
28  *  retreat.c: Retreat subroutines
29  * 
30  *  Known contributors to this file:
31  *     Steve McClure, 2000
32  *     
33  */
34
35 #include "misc.h"
36 #include "player.h"
37 #include "nat.h"
38 #include "var.h"
39 #include "retreat.h"
40 #include "ship.h"
41 #include "land.h"
42 #include "sect.h"
43 #include "news.h"
44 #include "xy.h"
45 #include "nsc.h"
46 #include "path.h"
47 #include "deity.h"
48 #include "file.h"
49 #include "options.h"
50 #include "damage.h"
51 #include "prototypes.h"
52 #include "optlist.h"
53
54 struct  ccode{
55         s_char  code;
56         s_char  *desc[2];
57 } conditions[] = {
58         { 'i', {
59                 "retreated with a damaged friend",
60                 "was damaged",
61                 }, },
62         { 't', {
63                 "retreated with a torpedoed ship",
64                 "was hit by a torpedo",
65                 }, },
66         { 's', {
67                 "retreated with a ship scared by sonar",
68                 "detected a sonar ping",
69                 }, },
70         { 'h', {
71                 "retreated with a helpless ship",
72                 "was fired upon with no one able to defend it",
73                 }, },
74         { 'b', {
75                 "retreated with a bombed friend",
76                 "was bombed",
77                 }, },
78         { 'd', {
79                 "retreated with a depth-charged ship",
80                 "was depth-charged",
81                 }, },
82         { 'u', {
83                 "retreated with a boared ship",
84                 "was boarded",
85                 }, },
86         { 0, {"",""} },
87 };
88
89 int
90 check_retreat_and_do_shipdamage(struct shpstr *sp, int dam)
91 {
92         if (dam <=0)
93                 return 0;
94
95         shipdamage(sp,dam);
96         if (sp->shp_rflags & RET_INJURED)
97                 retreat_ship(sp, 'i');
98
99         return 1;
100 }
101
102 void
103 retreat_ship(struct shpstr *sp, s_char code)
104 {
105         struct  nstr_item ni;
106         struct  shpstr ship;
107         s_char  buf[2];
108
109         if (sp->shp_rflags & RET_GROUP){
110                 bzero(buf,2);
111                 buf[0] = sp->shp_fleet;
112                 snxtitem(&ni, EF_SHIP, buf);
113                 while(nxtitem(&ni,(s_char *)&ship))
114                         if ((ship.shp_fleet == buf[0]) &&
115                             (ship.shp_own == sp->shp_own)) {
116                                 if (ship.shp_uid == sp->shp_uid){
117                                         retreat_ship1(sp,code,1);
118                                         if (sp->shp_rpath[0] == 0)
119                                                 sp->shp_rflags = 0;
120                                 } else {
121                                         retreat_ship1(&ship,code,0);
122                                         getship(ship.shp_uid,&ship);
123                                         if (ship.shp_rpath[0] == 0){
124                                                 ship.shp_rflags = 0;
125                                                 putship(ship.shp_uid,&ship);
126                                         }
127                                 }
128                         }
129         } else {
130                 retreat_ship1(sp,code,1);
131                 if (sp->shp_rpath[0] == 0)
132                         sp->shp_rflags = 0;
133         }
134 }
135
136 int
137 retreat_ship1(struct shpstr *sp, s_char code, int orig)
138                           
139                      
140                         /* Is this the originally scared ship, or a follower */
141 {
142         extern double techfact(int, double);
143         struct sctstr sect;
144         register int n;
145         register int m;
146         int     max;
147         int     dir;
148         coord     newx;
149         coord     newy;
150         coord     dx;
151         coord     dy;
152         int     stopping;
153         int     mines;
154         int     shells;
155         double  mobcost;
156         struct mchrstr *mcp;
157         int     vec[I_MAX+1];
158         int     time_to_stop;
159         s_char  buf[RET_LEN-1];
160
161         sp->shp_mission = 0;
162         if (sp->shp_own == 0)
163                 return 0;
164
165         if (isupper(code))
166                 code = tolower(code);
167
168         n = 0;
169         if (sp->shp_effic < SHIP_MINEFF){
170                 wu(0, sp->shp_own, "%s %s,\nbut it died in the attack, and so couldn't retreat!\n", prship(sp),
171                    conditions[findcondition(code)].desc[orig]);
172                 if (!orig) putship(sp->shp_uid,sp);
173                 return 0;
174         }
175
176         if (opt_SAIL) {
177             /* can't retreat a ship that's sailin, bad things happend */
178             if (*sp->shp_path){
179                 wu(0, sp->shp_own, "%s %s,\nbut had sailing orders, and couldn't retreat!\n", prship(sp),
180                    conditions[findcondition(code)].desc[orig]);
181                 if (!orig) putship(sp->shp_uid,sp);
182                 return 0;
183             }
184         }
185         /* check crew - uws don't count */
186         getvec(VT_ITEM, vec, (s_char *)sp, EF_SHIP);
187         if (vec[I_MILIT] == 0 && vec[I_CIVIL] == 0){
188                 wu(0, sp->shp_own, "%s %s,\nbut had no crew, and couldn't retreat!\n", prship(sp),
189                    conditions[findcondition(code)].desc[orig]);
190                 if (!orig) putship(sp->shp_uid,sp);
191                 return 0;
192         }
193
194         getsect(sp->shp_x,sp->shp_y,&sect);
195         switch (check_nav(&sect)) {
196         case CN_CONSTRUCTION:
197                 wu(0, sp->shp_own, "%s %s,\nbut was caught in a construction zone, and couldn't retreat!\n", prship(sp),
198                    conditions[findcondition(code)].desc[orig]);
199                         if (!orig) putship(sp->shp_uid,sp);
200                         return 0;
201         case CN_LANDLOCKED:
202                 wu(0, sp->shp_own, "%s %s,\nbut was landlocked, and couldn't retreat!\n", prship(sp),
203                    conditions[findcondition(code)].desc[orig]);
204                         if (!orig) putship(sp->shp_uid,sp);
205                         return 0;
206                         /*NOTREACHED*/
207                 case CN_NAVIGABLE:
208                         break;
209                 case CN_ERROR:
210         default:
211                 wu(0, sp->shp_own, "%s %s,\nbut was subject to an empire error, and couldn't retreat!\n", prship(sp),
212                    conditions[findcondition(code)].desc[orig]);
213                         if (!orig) putship(sp->shp_uid,sp);
214                         return 0;
215                         /*NOTREACHED*/
216         }
217
218         if (sp->shp_mobil <= 0.0) {
219                 wu(0, sp->shp_own, "%s %s,\nbut had no mobility, and couldn't retreat!\n", prship(sp),
220                    conditions[findcondition(code)].desc[orig]);
221                 if (!orig) putship(sp->shp_uid,sp);
222                 return 0;
223         }
224
225         n=(-1*MAX_RETREAT);
226         stopping = 0;
227         time_to_stop = 0;
228         while ((!stopping) && n){
229                 dx = dy = 0;
230                 if (sp->shp_rpath[0] == 0 || sp->shp_rpath[0] == 0){
231                         stopping=1;
232                         continue;
233                 }
234                 if (sp->shp_mobil <= 0.0) {
235                         wu(0, sp->shp_own, "%s %s,\nbut ran out of mobility, and couldn't retreat fully!\n", prship(sp),
236                            conditions[findcondition(code)].desc[orig]);
237                         if (!orig) putship(sp->shp_uid,sp);
238                         return 0;
239                 }
240                 dir = chkdir(sp->shp_rpath[0], DIR_STOP, DIR_VIEW);
241                 bzero(buf,RET_LEN-1);
242                 bcopy(&sp->shp_rpath[1],buf,RET_LEN-1);
243                 bzero(sp->shp_rpath,RET_LEN);
244                 bcopy(buf,sp->shp_rpath,RET_LEN-1);
245                 if (dir == -1)
246                         continue;
247                 if (dir == DIR_STOP)
248                         stopping++;
249                 else {
250                         dx = diroff[dir][0];
251                         dy = diroff[dir][1];
252                 }
253                 n++;
254
255                 mcp = &mchr[(int)sp->shp_type];
256                 newx = xnorm(sp->shp_x + dx);
257                 newy = ynorm(sp->shp_y + dy);
258                 mobcost = sp->shp_effic * 0.01 * sp->shp_speed;
259                 mobcost = 480.0 / (mobcost + techfact(sp->shp_tech, mobcost));
260
261                 getsect(newx, newy, &sect);
262                 if (check_nav(&sect) != CN_NAVIGABLE ||
263                             (sect.sct_own && !player->owner &&
264                              getrel(getnatp(sect.sct_own), sp->shp_own) < FRIENDLY)) {
265                         wu(0, sp->shp_own, "%s %s,\nbut could not retreat to %s!\n", prship(sp),
266                            conditions[findcondition(code)].desc[orig],
267                                         xyas(newx, newy, sp->shp_own));
268                                 if (!orig) putship(sp->shp_uid,sp);
269                                 return 0;
270                 }
271                 sp->shp_x = newx;
272                 sp->shp_y = newy;
273                 sp->shp_mobil -= mobcost;
274                 if (stopping)
275                         continue;
276
277                 mines = getvar(V_MINE, (s_char *)&sect, EF_SECTOR);
278                 if ((mcp->m_flags & M_SWEEP) && mines > 0 && !player->owner) {
279                         max = vl_find(V_SHELL, mcp->m_vtype,
280                                 mcp->m_vamt, (int) mcp->m_nv);
281                         shells = getvar(V_SHELL, (s_char *)sp, EF_SHIP);
282                         for (m=0; mines > 0 && m < 5; m++) {
283                                 if (chance(0.66)) {
284                                         mines--;
285                                         shells = min(max, shells + 1);
286                                 }
287                         }
288                         putvar(V_MINE, mines, (s_char *)&sect, EF_SECTOR);
289                         putvar(V_SHELL, shells, (s_char *)sp, EF_SHIP);
290                         putsect(&sect);
291                 }
292                 if (mines > 0 && !player->owner &&
293                         chance(DMINE_HITCHANCE(mines))) {
294                         wu(0, sp->shp_own, "%s %s,\nand hit a mine in %s while retreating!\n", prship(sp),
295                            conditions[findcondition(code)].desc[orig],
296                            xyas(newx, newy, sp->shp_own));
297                         nreport(sp->shp_own, N_HIT_MINE, 0, 1);
298                         m = MINE_DAMAGE();
299                         shipdamage(sp, m);
300                         mines--;
301                         putvar(V_MINE, mines, (s_char *)&sect, EF_SECTOR);
302                         putsect(&sect);
303                         if (sp->shp_effic < SHIP_MINEFF)
304                                 time_to_stop = 1;
305                         if (!orig) putship(sp->shp_uid,sp);
306                         return 0;
307                 }
308                 if (time_to_stop)
309                         stopping = 1;
310         }
311
312         if (orig) {
313                 wu(0, sp->shp_own, "%s %s, and retreated to %s\n", prship(sp),
314                         conditions[findcondition(code)].desc[orig],
315                         xyas(sp->shp_x, sp->shp_y, sp->shp_own));
316         }else{
317                 wu(0, sp->shp_own, "%s %s, and ended up at %s\n",
318                    prship(sp),
319                    conditions[findcondition(code)].desc[orig],
320                    xyas(sp->shp_x, sp->shp_y, sp->shp_own));
321         }
322         if (!orig) putship(sp->shp_uid,sp);
323         return 1;
324 }
325
326 #if 0
327 static int 
328 check_nav(sect)
329         struct  sctstr *sect;
330 {
331         extern struct dchrstr dchr[];
332
333         switch (dchr[sect->sct_type].d_flg & 03) {
334         case NAVOK:
335                 break;
336
337         case NAV_02:
338                 if (sect->sct_effic < 2)
339                         return CN_CONSTRUCTION;
340                 break;
341         case NAV_60:
342                 if (sect->sct_effic < 60)
343                         return CN_CONSTRUCTION;
344                 break;
345         default:
346                 return CN_LANDLOCKED;
347         }
348         return CN_NAVIGABLE;
349 }
350 #endif
351 int
352 findcondition(s_char code)
353 {
354         int     x;
355
356         x=0;
357         while (conditions[x].code){
358                 if (conditions[x].code == code)
359                         return(x);
360                 x++;
361         }
362
363         return(x);
364 }
365
366 int
367 check_retreat_and_do_landdamage(struct lndstr *lp, int dam)
368 {
369         if (dam <=0)
370                 return 0;
371
372         landdamage(lp,dam);
373         if (lp->lnd_rflags & RET_INJURED)
374                 retreat_land(lp, 'i');
375
376         return 1;
377 }
378
379 void
380 retreat_land(struct lndstr *lp, s_char code)
381 {
382         struct  nstr_item ni;
383         struct  lndstr land;
384         s_char  buf[2];
385
386         if (lp->lnd_rflags & RET_GROUP){
387                 bzero(buf,2);
388                 buf[0] = lp->lnd_army;
389                 snxtitem(&ni, EF_SHIP, buf);
390                 while(nxtitem(&ni,(s_char *)&land))
391                         if ((land.lnd_army == buf[0]) &&
392                             (land.lnd_own == lp->lnd_own)) {
393                                 if (land.lnd_uid == lp->lnd_uid){
394                                         retreat_land1(lp,code,1);
395                                         if (lp->lnd_rpath[0] == 0)
396                                                 lp->lnd_rflags = 0;
397                                 }else{
398                                         retreat_land1(&land,code,0);
399                                         getland(land.lnd_uid,&land);
400                                         if (land.lnd_rpath[0] == 0){
401                                                 land.lnd_rflags = 0;
402                                                 putland(land.lnd_uid,&land);
403                                         }
404                                 }
405                         }
406         }else{
407                 retreat_land1(lp,code,1);
408                 if (lp->lnd_rpath[0] == 0)
409                         lp->lnd_rflags = 0;
410         }
411 }
412
413 int
414 retreat_land1(struct lndstr *lp, s_char code, int orig)
415                           
416                      
417                         /* Is this the originally scared unit, or a follower */
418 {
419         extern double techfact(int, double);
420         struct sctstr sect;
421         register int n;
422         register int m;
423         int     max;
424         int     dir;
425         coord     newx;
426         coord     newy;
427         coord     dx;
428         coord     dy;
429         int     stopping;
430         int     mines;
431         int     shells;
432         double  mobcost;
433         struct lchrstr *lcp;
434         int     time_to_stop;
435         s_char  buf[RET_LEN-1];
436
437         lp->lnd_mission = 0;
438         if (lp->lnd_own == 0)
439                 return 0;
440
441         if (isupper(code))
442                 code = tolower(code);
443
444         n = 0;
445         if (lp->lnd_effic < LAND_MINEFF){
446                 wu(0, lp->lnd_own, "%s %s,\nbut it died in the attack, and so couldn't retreat!\n", prland(lp),
447                    conditions[findcondition(code)].desc[orig]);
448                 if (!orig) putland(lp->lnd_uid,lp);
449                 return 0;
450         }
451
452         getsect(lp->lnd_x,lp->lnd_y,&sect);
453
454         if (lp->lnd_mobil <= 0.0) {
455                 wu(0, lp->lnd_own, "%s %s,\nbut had no mobility, and couldn't retreat!\n",
456                    prland(lp),
457                    conditions[findcondition(code)].desc[orig]);
458                 if (!orig) putland(lp->lnd_uid,lp);
459                 return 0;
460         }
461
462         n=(-1*MAX_RETREAT);
463         stopping = 0;
464         time_to_stop = 0;
465         while ((!stopping) && n){
466                 dx = dy = 0;
467                 if (lp->lnd_rpath[0] == 0 || lp->lnd_rpath[0] == 0){
468                         stopping=1;
469                         continue;
470                 }
471                 if (lp->lnd_mobil <= 0.0) {
472                         wu(0, lp->lnd_own, "%s %s,\nbut ran out of mobility, and couldn't retreat fully!\n",
473                            prland(lp),
474                            conditions[findcondition(code)].desc[orig]);
475                         if (!orig) putland(lp->lnd_uid,lp);
476                         return 0;
477                 }
478                 dir = chkdir(lp->lnd_rpath[0], DIR_STOP, DIR_VIEW);
479                 bzero(buf,RET_LEN-1);
480                 bcopy(&lp->lnd_rpath[1],buf,RET_LEN-1);
481                 bzero(lp->lnd_rpath,RET_LEN);
482                 bcopy(buf,lp->lnd_rpath,RET_LEN-1);
483                 if (dir == -1)
484                         continue;
485                 if (dir == DIR_STOP)
486                         stopping++;
487                 else {
488                         dx = diroff[dir][0];
489                         dy = diroff[dir][1];
490                 }
491                 n++;
492
493                 lcp = &lchr[(int)lp->lnd_type];
494                 newx = xnorm(lp->lnd_x + dx);
495                 newy = ynorm(lp->lnd_y + dy);
496
497                 getsect(newx, newy, &sect);
498                 if ((sect.sct_type == SCT_WATER) ||
499                         (sect.sct_type == SCT_MOUNT) ||
500                         (sect.sct_type == SCT_SANCT) ||
501                         (sect.sct_type == SCT_WASTE) ||
502                         (sect.sct_own != lp->lnd_own)){
503                                 wu(0, lp->lnd_own, "%s %s,\nbut could not retreat to %s!\n",
504                                    prland(lp),
505                                    conditions[findcondition(code)].desc[orig],
506                                    xyas(newx, newy, lp->lnd_own));
507                                 if (!orig) putland(lp->lnd_uid,lp);
508                                 return 0;
509                 }
510                 mobcost = lnd_mobcost(lp, &sect, MOB_ROAD);
511                 lp->lnd_x = newx;
512                 lp->lnd_y = newy;
513                 lp->lnd_mobil -= mobcost;
514                 if (stopping)
515                         continue;
516
517                 mines = getvar(V_MINE, (s_char *)&sect, EF_SECTOR);
518                 if ((lcp->l_flags & L_ENGINEER) && mines > 0 &&
519                         (sect.sct_oldown != lp->lnd_own)){
520                         max = vl_find(V_SHELL, lcp->l_vtype,
521                                 lcp->l_vamt, (int) lcp->l_nv);
522                         shells = getvar(V_SHELL, (s_char *)lp, EF_LAND);
523                         for (m=0; mines > 0 && m < 5; m++) {
524                                 if (chance(0.66)) {
525                                         mines--;
526                                         shells = min(max, shells + 1);
527                                 }
528                         }
529                         putvar(V_MINE, mines, (s_char *)&sect, EF_SECTOR);
530                         putvar(V_SHELL, shells, (s_char *)lp, EF_LAND);
531                         putsect(&sect);
532                 }
533                 if (mines > 0 && (sect.sct_oldown != lp->lnd_own) &&
534                         chance(DMINE_HITCHANCE(mines))) {
535                         wu(0, lp->lnd_own, "%s %s,\nand hit a mine while retreating!\n",
536                            prland(lp),
537                            conditions[findcondition(code)].desc[orig],
538                            xyas(newx, newy, lp->lnd_own));
539                         nreport(lp->lnd_own, N_LHIT_MINE, 0, 1);
540                         m = MINE_LDAMAGE();
541                         landdamage(lp, m);
542                         mines--;
543                         putvar(V_MINE, mines, (s_char *)&sect, EF_SECTOR);
544                         putsect(&sect);
545                         if (lp->lnd_effic < LAND_MINEFF)
546                                 time_to_stop = 1;
547                         if (!orig) putland(lp->lnd_uid,lp);
548                         return 0;
549                 }
550                 if (time_to_stop)
551                         stopping = 1;
552         }
553
554         if (orig){
555                 wu(0, lp->lnd_own, "%s %s, and retreated to %s\n",
556                    prland(lp),
557                    conditions[findcondition(code)].desc[orig],
558                    xyas(lp->lnd_x, lp->lnd_y, lp->lnd_own));
559         }else{
560                 wu(0, lp->lnd_own, "%s %s, and ended up at %s\n",
561                    prland(lp),
562                    conditions[findcondition(code)].desc[orig],
563                    xyas(lp->lnd_x, lp->lnd_y, lp->lnd_own));
564         }
565         if (!orig) putland(lp->lnd_uid,lp);
566         return 1;
567 }