]> git.pond.sub.org Git - empserver/blob - src/lib/commands/torp.c
Import of Empire 4.2.12
[empserver] / src / lib / commands / torp.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  *  torp.c: Fire torpedoes at enemy ships
29  * 
30  *  Known contributors to this file:
31  *     Dave Pare
32  *     Thomas Ruschak, 1992
33  *     Ken Stevens, 1995
34  *     Steve McClure, 2000
35  */
36
37 #include <stdio.h>
38 #include "misc.h"
39 #include "player.h"
40 #include "var.h"
41 #include "ship.h"
42 #include "file.h"
43 #include "xy.h"
44 #include "nat.h"
45 #include "nsc.h"
46 #include "news.h"
47 #include "retreat.h"
48 #include "damage.h"
49 #include "commands.h"
50
51 void anti_torp(int f, int ntorping, int vshipown);
52 void fire_dchrg(struct shpstr *sp, struct shpstr *targ, int range, int ntargets);
53
54 s_char *prsub(struct shpstr *sp);
55
56 int
57 torp(void)
58 {
59         extern  int torpedo_damage;
60         natid   vshipown;
61         int     range;
62         int     dam;
63         int     shells;
64         int     subno;
65         int     victno;
66         double  erange;
67         double  hitchance;
68         struct  shpstr vship;
69         struct  shpstr sub;
70         s_char  *ptr;
71         double  mobcost;
72         struct  mchrstr *mcp;
73         struct  nstr_item nbst;
74         s_char  buf[1024];
75         s_char  *sav;
76         int     ntorping=0;
77         s_char  prompt[128];
78
79         if (!(sav = getstarg(player->argp[1], "From ship(s)? ", buf)))
80                 return RET_SYN;
81         if (!snxtitem(&nbst, EF_SHIP, sav))
82                 return RET_SYN;
83         while (nxtitem(&nbst, (s_char *)&sub)){
84                 if (sub.shp_own != player->cnum)
85                         continue;
86                 if ((mchr[(int)sub.shp_type].m_flags & M_TORP) == 0)
87                         continue;
88                 shells = getvar(V_SHELL, (s_char *)&sub, EF_SHIP);
89                 if (shells < 3)
90                         shells += supply_commod(sub.shp_own,sub.shp_x,sub.shp_y,I_SHELL,
91                                 3-shells);
92                 if (getvar(V_GUN, (s_char *)&sub, EF_SHIP) == 0 || shells < 3)
93                         continue;
94                 if (getvar(V_MILIT, (s_char *)&sub, EF_SHIP) < 1)
95                         continue;
96                 if (sub.shp_effic < 60)
97                         continue;
98                 if (sub.shp_mobil <= 0)
99                         continue;
100                 ntorping++;
101         }
102         pr("%d ships are eligible to torp\n",ntorping);
103         snxtitem(&nbst, EF_SHIP, sav);
104         while (nxtitem(&nbst, (s_char *)&sub)) {
105                 if (!sub.shp_own)
106                         continue;
107                 if (sub.shp_own != player->cnum) {
108                         continue;
109                 }
110                 if ((mchr[(int)sub.shp_type].m_flags & M_TORP) == 0) {
111                         pr("Ship # %d: A %s can't fire torpedoes!\n", sub.shp_uid,
112                                mchr[(int)sub.shp_type].m_name);
113                         continue;
114                 }
115                 shells = getvar(V_SHELL, (s_char *)&sub, EF_SHIP);
116                 if (shells < 3)
117                         shells += supply_commod(sub.shp_own,sub.shp_x,sub.shp_y
118 ,I_SHELL,
119                                 3-shells);
120                 if (getvar(V_GUN, (s_char *)&sub, EF_SHIP) == 0 || shells < 3) {
121                         pr("Ship #%d has insufficient armament\n",sub.shp_uid);
122                         continue;
123                 }
124                 if (getvar(V_MILIT, (s_char *)&sub, EF_SHIP) < 1){
125                         pr("Ship #%d has insufficient crew\n",sub.shp_uid);
126                         continue;
127                 }
128                 if (sub.shp_effic < 60) {
129                         pr("Ship #%d torpedo tubes inoperative.\n",sub.shp_uid);
130                         continue;
131                 }
132                 if (sub.shp_mobil <= 0) {
133                         pr("Ship #%d has insufficient mobility\n",sub.shp_uid);
134                         continue;
135                 }
136                 bzero(buf,80);
137                 subno=sub.shp_uid;
138                 sprintf(prompt, "Ship %d, target? ",sub.shp_uid);
139                 if ((ptr = getstarg(player->argp[2],prompt, buf)) == 0)
140                         return RET_SYN;
141                 if (!check_ship_ok(&sub))
142                     return RET_FAIL;
143                 if ((victno = atoi(ptr)) < 0)
144                         return RET_SYN;
145                 if (!getship(victno, &vship))
146                         return RET_FAIL;
147                 if (!vship.shp_own)
148                         return RET_FAIL;
149                 vshipown=vship.shp_own;
150                 if (victno == subno) {
151                         pr("Shooting yourself, eh?  How strange...\n");
152                         continue;
153                 }
154                 if (mchr[(int)vship.shp_type].m_flags & M_SUB) {
155                         if (!(mchr[(int)sub.shp_type].m_flags & M_SUBT)){
156                                 pr("You can't torpedo a submarine!\n");
157                                 continue;
158                         }
159                 }
160                 if ((mchr[(int)sub.shp_type].m_flags & M_SUB) == 0)
161                         anti_torp(sub.shp_uid,ntorping,vshipown);
162                 getship(sub.shp_uid,&sub);
163                 if (sub.shp_own == 0){
164                         continue;
165                 }
166                 erange = ((double)sub.shp_effic/100.0) *
167                         techfact(sub.shp_tech, ((double)sub.shp_frnge));
168                 erange = (double)roundrange(erange);
169                 pr("Effective torpedo range is %.1f\n", erange);
170                 shells -= 3;
171                 putvar(V_SHELL, shells, (s_char *)&sub, EF_SHIP);
172                 putship(sub.shp_uid,&sub);
173                 mcp = &mchr[(int)sub.shp_type];
174                 mobcost = sub.shp_effic * 0.01 * sub.shp_speed;
175                 mobcost = (480.0 / (mobcost + techfact(sub.shp_tech, mobcost)));
176
177                 /* Mob cost for a torp is equal to the cost of 1/2 sector of movement */
178                 mobcost /= 2.0;
179                 sub.shp_mobil -= mobcost;
180                 pr("Whooosh... ");
181                 getship(victno, &vship);
182                 vshipown = vship.shp_own;
183                 range = mapdist(sub.shp_x, sub.shp_y, vship.shp_x, vship.shp_y);
184                 hitchance = DTORP_HITCHANCE(range, sub.shp_visib);
185                 if (range <= erange) {
186                         pr("Hitchance = %d%%\n",(int)(hitchance*100));
187                 }
188                 /* Now, can the torpedo even get there? */
189                 if (!line_of_sight((s_char **)0, sub.shp_x, sub.shp_y,
190                                    vship.shp_x, vship.shp_y)) {
191                     pr("BOOM!... Torpedo slams into land before reaching target.\n");
192                     /* We only tell the victim if we were within range. */
193                     if (range <= erange) {
194                         if (vshipown != 0)
195                             wu(0, vshipown, "Torpedo sighted @ %s by %s\n",
196                                xyas(sub.shp_x, sub.shp_y, vshipown),
197                                prship(&vship));
198                     }
199                 } else if (range > erange) {
200                         pr("Out of range\n");
201                 } else if (hitchance >= 1.0 || chance(hitchance)) {
202                         pr("BOOM!...\n");
203                         dam = TORP_DAMAGE();
204                         if(vshipown != 0)
205                         wu(0, vshipown, "%s in %s torpedoed %s for %d damage.\n", prsub(&sub),
206                            xyas(sub.shp_x, sub.shp_y, vshipown),
207                            prship(&vship), dam);
208                         if (vship.shp_rflags & RET_TORPED){
209                                 retreat_ship(&vship, 't');
210                                 shipdamage(&vship, dam);
211                         }else
212                                 shipdamage(&vship, dam);
213                         pr("Torpedo hit %s for %d damage.\n",
214                            prship(&vship),
215                            dam);
216
217                         if (vship.shp_effic < SHIP_MINEFF)
218                                 pr("%s sunk!\n",
219                                    prship(&vship));
220                         putship(vship.shp_uid, &vship);
221                         if (mchr[(int)sub.shp_type].m_flags & M_SUB)
222                                 nreport(vshipown, N_TORP_SHIP, 0, 1);
223                         else
224                                 nreport(vshipown, N_SHIP_TORP, player->cnum, 1);
225                 } else {
226                         pr("Missed\n");
227                         if (vshipown != 0)
228                             wu(0, vshipown, "Torpedo sighted @ %s by %s\n",
229                                xyas(sub.shp_x, sub.shp_y, vshipown),
230                                prship(&vship));
231                 }
232                 sub.shp_mission=0;
233                 putship(sub.shp_uid, &sub);
234                 if (mchr[(int)sub.shp_type].m_flags & M_SUB)
235                         anti_torp(sub.shp_uid,ntorping,vshipown);
236         }
237         return RET_OK;
238 }
239
240 void
241 anti_torp(int f, int ntorping, int vshipown)
242 {
243         int     range;
244         double  erange;
245         struct  shpstr sub;
246         struct  shpstr dd;
247         int     x;
248
249         getship(f,&sub);
250
251         if (sub.shp_own == vshipown)
252                 return;
253
254         if ((mchr[(int)sub.shp_type].m_flags & M_SUB) == 0)
255                 pr("Starting our attack run...\n");
256
257         x=0;
258         while (getship(x++,&dd) && sub.shp_effic >= SHIP_MINEFF){
259                 if (dd.shp_own == 0)
260                         continue;
261                 if (dd.shp_own != vshipown)
262                         continue;
263                 if (dd.shp_effic < 60)
264                         continue;
265
266                 if (!canshoot(&dd,&sub))
267                         continue;
268
269                 erange = techfact(dd.shp_tech,
270                         ((double)dd.shp_frnge))/ 2.0;
271
272                 erange = (double)roundrange(erange);
273
274                 range = mapdist(sub.shp_x, sub.shp_y, dd.shp_x, dd.shp_y);
275
276                 if (range > erange)
277                         continue;
278
279                 if (!line_of_sight((s_char **)0, sub.shp_x, sub.shp_y,
280                                    dd.shp_x, dd.shp_y))
281                     continue;
282
283                 if (cantorp(&dd,&sub)){
284                         /* Try torping.. if we can, maybe we can fire */
285                         if (!fire_torp(&dd,&sub,range,ntorping))
286                                 if (candchrg(&dd,&sub))
287                                         fire_dchrg(&dd,&sub,range,ntorping);
288                 }else
289                         fire_dchrg(&dd,&sub,range,ntorping);
290         }
291 }
292
293 /* Can ship A shoot at ship B? */
294 int
295 canshoot(struct shpstr *a, struct shpstr *b)
296 {
297         /* Anyone can shoot a normal ship */
298         if ((mchr[(int)b->shp_type].m_flags & M_SUB) == 0)
299                 return 1;
300
301         /* You can depth-charge a sub */
302         if (mchr[(int)a->shp_type].m_flags & M_DCH)
303                 return 1;
304
305         /* If you have SUBT flag, you can torp a sub */
306         if (mchr[(int)a->shp_type].m_flags & M_SUBT)
307                 return 1;
308
309         return 0;
310 }
311
312 /* Can ship A torp ship B? */
313 int
314 cantorp(struct shpstr *a, struct shpstr *b)
315 {
316         if ((mchr[(int)a->shp_type].m_flags & M_TORP) == 0)
317                 return 0;
318
319         /* Anyone with TORP flag can torp a normal ship */
320         if ((mchr[(int)b->shp_type].m_flags & M_SUB) == 0)
321                 return 1;
322
323         /* Ship b is a sub, so we need to have the SUBT flag */
324         if (mchr[(int)a->shp_type].m_flags & M_SUBT)
325                 return 1;
326
327         return 0;
328 }
329
330 /* Can ship A depth-charge (or fire guns at) ship B? */
331 int
332 candchrg(struct shpstr *a, struct shpstr *b)
333 {
334         if ((mchr[(int)b->shp_type].m_flags & M_SUB) == 0){
335                 if ((mchr[(int)a->shp_type].m_flags & M_SUB) == 0)
336                         return 1;
337
338                 return 0;
339         }
340
341         if ((mchr[(int)a->shp_type].m_flags & M_DCH) == 0)
342                 return 0;
343
344         return 1;
345 }
346
347 void
348 fire_dchrg(struct shpstr *sp, struct shpstr *targ, int range, int ntargets)
349 {
350         int     dam;
351         int     shells;
352         int     gun;
353         double  guneff;
354
355         shells = getvar(V_SHELL, (s_char *)sp, EF_SHIP);
356         gun = getvar(V_GUN, (s_char *)sp, EF_SHIP);
357         gun = min(gun, sp->shp_glim);
358         gun = min(gun, getvar(V_MILIT, (s_char *)sp, EF_SHIP)/2);
359
360         shells+=supply_commod(sp->shp_own,sp->shp_x,sp->shp_y,I_SHELL,(gun+1)/2-shells);
361
362         gun = min(gun, shells*2);
363         if (gun == 0) return;
364
365         /* ok, all set.. now, we shoot */
366         shells -= ldround(((double)gun)/2.0,1);
367         putvar(V_SHELL, shells, (s_char *)sp, EF_SHIP);
368         putship(sp->shp_uid,sp);
369
370         guneff = seagun(sp->shp_effic, gun);
371         dam = (int)guneff;
372
373         if ((mchr[(int)targ->shp_type].m_flags & M_SUB) == 0){
374                 pr_beep();
375                 pr("Kaboom!!! Incoming shells!\n");
376                 if(sp->shp_own != 0)
377                         wu(0, sp->shp_own,
378                            "%s fired at %s\n",
379                            prship(sp),
380                            prship(targ));
381
382                 if (ntargets > 2)
383                         dam /= ((float)ntargets/2.0);
384                 pr_beep();
385                 pr("BLAM! %d damage!\n", dam);
386                 shipdamage(targ, dam);
387                 putship(targ->shp_uid,targ);
388         }else{
389                 pr("\nCAPTAIN!  !!Depth charges!!...\n");
390                 if(sp->shp_own != 0)
391                         wu(0, sp->shp_own,
392                                 "%s depth charged %s\n",
393                            prship(sp), prsub(targ));
394
395                 if (ntargets>2)
396                         dam /= ((float)ntargets/2.0);
397
398                 pr("click...WHAM!  %d damage!\n", dam);
399                 shipdamage(targ, dam);
400                 putship(targ->shp_uid,targ);
401         }
402 }
403
404 int
405 fire_torp(struct shpstr *sp, struct shpstr *targ, int range, int ntargets)
406 {
407         extern  int torpedo_damage;
408         int     dam;
409         int     shells;
410         double  hitchance;
411         double  mobcost;
412         struct  mchrstr *mcp;
413
414         shells = getvar(V_SHELL, (s_char *)sp, EF_SHIP);
415
416         if (shells < 3)
417                 shells += supply_commod(sp->shp_own,sp->shp_x,sp->shp_y,I_SHELL,
418                         3-shells);
419
420         if (getvar(V_GUN, (s_char *)sp, EF_SHIP) == 0 || shells < 3)
421                 return 0;
422
423         if (getvar(V_MILIT, (s_char *)sp, EF_SHIP) < 1)
424                 return 0;
425
426         if (sp->shp_effic < 60)
427                 return 0;
428
429         if (sp->shp_mobil <= 0)
430                 return 0;
431
432         /* All set.. fire! */
433         shells -= 3;
434         putvar(V_SHELL, shells, (s_char *)sp, EF_SHIP);
435         putship(sp->shp_uid,sp);
436
437         mcp = &mchr[(int)sp->shp_type];
438         mobcost = sp->shp_effic * 0.01 * sp->shp_speed;
439         mobcost = (480.0 / (mobcost + techfact(sp->shp_tech, mobcost)));
440
441         /* Mob cost for a torp is equal to the cost of 1/2 sector of movement */
442         mobcost /= 2.0;
443         sp->shp_mobil -= mobcost;
444
445         hitchance = DTORP_HITCHANCE(range, sp->shp_visib);
446
447         pr("Captain! Torpedoes sighted!\n");
448
449         if (chance(hitchance)) {
450                 pr("BOOM!...\n");
451                 if(sp->shp_own != 0)
452                 wu(0, sp->shp_own, "%s @ %s torpedoed %s\n",
453                    prship(sp),
454                    xyas(sp->shp_x, sp->shp_y, sp->shp_own),
455                    prsub(targ));
456                 dam = TORP_DAMAGE();
457
458                 if (ntargets>2)
459                         dam /= ((float)ntargets/2.0);
460
461                 shipdamage(targ, dam);
462                 putship(targ->shp_uid, targ);
463
464                 if (mchr[(int)sp->shp_type].m_flags & M_SUB)
465                         nreport(targ->shp_own, N_TORP_SHIP, 0, 1);
466                 else
467                         nreport(targ->shp_own, N_SHIP_TORP, player->cnum, 1);
468         } else {
469                 pr("Missed!\n");
470                 if(sp->shp_own != 0)
471                 wu(0, sp->shp_own,
472                    "%s missed %s with a torp at %s\n",
473                    prship(sp), prsub(targ),
474                    xyas(sp->shp_x, sp->shp_y, sp->shp_own));
475         }
476
477         return 1;
478 }
479
480 s_char *
481 prsub(struct shpstr *sp)
482 {
483         if (mchr[(int)sp->shp_type].m_flags & M_SUB)
484                 return "sub";
485         else
486                 return prship(sp);
487 }