]> git.pond.sub.org Git - empserver/blob - src/lib/subs/fortdef.c
Import of Empire 4.2.12
[empserver] / src / lib / subs / fortdef.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  *  fortdef.c: Fort defends an area.
29  * 
30  *  Known contributors to this file:
31  *    
32  */
33 /*
34  * The base routines can also be used for general purposes.
35  * Noisy tells whther to send teles, print things, etc.
36  * Defending tells whether they are being defensive, or offensive.
37  */
38
39 #include "misc.h"
40 #include "var.h"
41 #include "xy.h"
42 #include "nat.h"
43 #include "sect.h"
44 #include "ship.h"
45 #include "land.h"
46 #include "news.h"
47 #include "nsc.h"
48 #include "file.h"
49 #include "options.h"
50 #include "optlist.h"
51 #include "prototypes.h"
52
53 #define QUIET   0
54 #define NOISY   1
55
56 extern double tfactfire(natid, double);
57
58 /*
59  * See if any nearby ships will open up on the attacker
60  * Return damage done to attacker, if any.
61  * Subtracts shells used for firing.  Responding ships
62  * require military, shells, and guns.
63  */
64 int
65 shipdef(natid att, natid own, coord x, coord y)
66 {
67         return sd(att, own, x, y, NOISY, 1, 1);
68 }
69
70 int
71 sd(natid att, natid own, coord x, coord y, int noisy, int defending, int usesubs)
72 {
73         int     nshot;
74         double  range;
75         double  eff;
76         struct  shpstr ship;
77         struct  nstr_item ni;
78         int     vec[I_MAX+1];
79         int     dam, rel, rel2;
80
81         if (own == 0)
82                 return 0;
83         if (att == own)
84                 return 0;
85         eff = 1.0;
86         snxtitem_dist(&ni, EF_SHIP, x, y, 8);
87         while (nxtitem(&ni, (caddr_t)&ship) && eff > 0.30) {
88                 if (ship.shp_own == att)
89                         continue;
90                 if (ship.shp_own == 0)
91                         continue;
92
93                 rel = getrel(getnatp(ship.shp_own),own);
94                 rel2 = getrel(getnatp(ship.shp_own),att);
95                 if ((ship.shp_own != own) &&
96                         ((rel != ALLIED) || (rel2 != AT_WAR)))
97                         continue;
98                 if (ship.shp_effic < 60)
99                         continue;
100                 if ((mchr[(int)ship.shp_type].m_flags & M_SUB) && (!usesubs))
101                         continue;
102                 range = techfact(ship.shp_tech, 
103                         ship.shp_frnge * ship.shp_effic / 200.0);
104                 range = (double)roundrange(range);
105                 if (range < ni.curdist)
106                         continue;
107                 /* must have gun, shell, and milit to fire */
108                 if (getvec(VT_ITEM, vec, (caddr_t)&ship, EF_SHIP) < 3)
109                         continue;
110                 if (vec[I_SHELL] < ship.shp_glim)
111                         vec[I_SHELL] += supply_commod(ship.shp_own,ship.shp_x,
112                                 ship.shp_y,I_SHELL,
113                                 vec[I_SHELL]-ship.shp_glim);
114                 nshot = min(min(vec[I_GUN], vec[I_SHELL]), vec[I_MILIT]);
115                 nshot = min(nshot, ship.shp_glim);
116                 if (nshot <= 0)
117                         continue;
118                 (void)putvar(V_SHELL,vec[I_SHELL]-nshot,(caddr_t)&ship,EF_SHIP);
119                 putship(ship.shp_uid, &ship);
120                 if (defending)
121                         nreport(ship.shp_own, N_FIRE_BACK, att, 1);
122                 else
123                         nreport(ship.shp_own, N_FIRE_S_ATTACK, att, 1);
124                 dam = seagun(ship.shp_effic, nshot);
125                 eff *= (1.0 - (0.01 * dam));
126                 if (noisy) {
127                         pr_beep();
128                         pr("Incoming shell%s %d damage!\n",
129                                 nshot == 1 ? " does" : "s do", dam);
130                 }
131                 if (noisy || (ship.shp_own != own)){
132                         if (ship.shp_own == own)
133                                 wu(0, own, "%s fired on %s at %s doing %d damage.\n", prship(&ship),
134                                    cname(att), xyas(x, y,own),dam);
135                         else{
136                                 if (defending)
137                                         wu(0, ship.shp_own, "%s fired on %s at %s in defense of %s, doing %d damage.\n", prship(&ship),
138                                            cname(att),
139                                            xyas(x, y, ship.shp_own), 
140                                            cname(own),dam);
141                                 else
142                                         wu(0, ship.shp_own,"%s supported %s attacks against %s at %s, doing %d damage.\n", prship(&ship),
143                                            cname(own),
144                                            cname(att),
145                                            xyas(x, y, ship.shp_own), dam);
146                         }
147                 }
148         }
149         return (int) 100 - (eff * 100);
150 }
151
152 /*
153  * Determine if any nearby gun-equipped sectors are within
154  * range and able to fire at an attacker.  Firing sectors
155  * need to have guns, shells, and military.  Sector being
156  * attacked is x,y -- attacker is at ax,ay.
157  */
158 #if 0
159 /* defdef isn't called anywhere, and uses wrong
160  * number of arguments for dd */
161 int
162 defdef(att, def_own, defval, ax, ay)
163         natid   att;
164         natid   def_own;
165         int     defval;
166         coord   ax;
167         coord   ay;
168 {
169         return dd(att, def_own, defval, ax, ay, NOISY, 1);
170 }
171 #endif
172
173 int
174 dd(natid att, natid def_own, coord ax, coord ay, int noisy, int defending)
175 {
176         int     dam, rel, rel2;
177         double  tech;
178         double  range;
179         struct  sctstr firing;
180         struct  nstr_sect ns;
181         int     vec[I_MAX+1];
182
183         if (opt_NO_FORT_FIRE) /* Forts can't fire! */
184                 return 0;
185         if (def_own == 0)
186                 return 0;
187         if (att == def_own)
188                 return 0;
189         tech = tfactfire(def_own, 1.0);
190         dam = 0;
191         snxtsct_dist(&ns, ax, ay, 8);
192         while (nxtsct(&ns, &firing) && dam < 80) {
193                 if (firing.sct_own == att)
194                         continue;
195                 if (firing.sct_own == 0)
196                         continue;
197                 if (firing.sct_effic < (u_char)FORTEFF )
198                         continue;
199                 rel = getrel(getnatp(firing.sct_own),def_own);
200                 rel2 = getrel(getnatp(firing.sct_own),att);
201                 if ((firing.sct_own != def_own) &&
202                         ((rel != ALLIED) || (rel2 != AT_WAR)))
203                         continue;
204                 if (getvec(VT_ITEM, vec, (caddr_t)&firing, EF_SECTOR) < 0)
205                         continue;
206
207                 range = tfactfire(def_own, 7.0);
208                 if (firing.sct_effic > 59)
209                         range++;
210                 /* Here we round down the range, and then add 1 to it
211                    to determine if we could possibly hit the sector.  If
212                    we do, we call sb where the range is re-calculated and
213                    the percentages are checked. */
214                 range = (double)((int)(range) + 1);
215                 if (range < ns.curdist)
216                         continue;
217         /* XXX defdef damage is additive, but ship or land unit damage isn't */
218                 dam += sb(att, def_own, &firing,
219                                 ax, ay, noisy, defending);
220         }
221         return dam;
222 }
223
224 /* Shoot back
225  *
226  * See if the sector being fired at will defend itself.
227  */
228 int
229 sb(natid att, natid def, struct sctstr *sp, coord tx, coord ty, int noisy, int defending)
230 {
231         register int damage;
232         natid   own;
233         int     shell;
234         double  range;
235         int     range2, gun;
236
237         if (sp->sct_type != SCT_FORTR) {
238                 /* XXX I don't like this restriction */
239                 return 0;
240         }
241
242         if (sp->sct_effic < (u_char)FORTEFF)
243                 return 0;
244
245         own = sp->sct_own;
246         if (own == 0)
247                 return 0;
248         if (att == own)
249                 return 0;
250         range = tfactfire(own, 7.0);
251         if (sp->sct_effic > 59)
252                 range++;
253         range = (double)roundrange(range);
254         range2 = mapdist((int)sp->sct_x, (int)sp->sct_y, tx, ty);
255         if (range < range2)
256                 return 0;
257         gun = getvar(V_GUN, (caddr_t)sp, EF_SECTOR);
258         if (gun == 0)
259                 return 0;
260         shell = getvar(V_SHELL, (caddr_t)sp, EF_SECTOR);
261         if (shell <= 0)
262                 shell += supply_commod(sp->sct_own,sp->sct_x,sp->sct_y,I_SHELL,
263                         1);
264         if (shell <= 0)
265                 return 0;
266         putvar(V_SHELL, shell - 1, (caddr_t)sp, EF_SECTOR);
267         putsect(sp);
268         damage = landgun((int)sp->sct_effic,gun);
269         if (sp->sct_own != def)
270                 wu(0,sp->sct_own, "%s fired on %s in %s in defense of %s, doing %d damage!\n",
271                         xyas(sp->sct_x,sp->sct_y,sp->sct_own),
272                         cname(att), xyas(tx,ty,sp->sct_own),
273                         cname(def), damage);
274         if (defending)
275                 nreport(sp->sct_own, N_FIRE_BACK, att, 1);
276         else
277                 nreport(sp->sct_own, N_FIRE_F_ATTACK, att, 1);
278         if (noisy)
279                 pr("Incoming shell! %d damage done.\007\n", damage);
280         return damage;
281 }