]> git.pond.sub.org Git - empserver/blob - src/lib/subs/fortdef.c
Update copyright notice
[empserver] / src / lib / subs / fortdef.c
1 /*
2  *  Empire - A multi-player, client/server Internet based war game.
3  *  Copyright (C) 1986-2020, Dave Pare, Jeff Bailey, Thomas Ruschak,
4  *                Ken Stevens, Steve McClure, Markus Armbruster
5  *
6  *  Empire 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 3 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, see <http://www.gnu.org/licenses/>.
18  *
19  *  ---
20  *
21  *  See files README, COPYING and CREDITS in the root of the source
22  *  tree for related information and legal notices.  It is expected
23  *  that future projects/authors will amend these files as needed.
24  *
25  *  ---
26  *
27  *  fortdef.c: Fort defends an area.
28  *
29  *  Known contributors to this file:
30  *     Markus Armbruster, 2006-2011
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 <config.h>
40
41 #include "nat.h"
42 #include "news.h"
43 #include "optlist.h"
44 #include "prototypes.h"
45 #include "sect.h"
46 #include "ship.h"
47
48 #define NOISY   1
49
50 static int sb(natid, natid, struct sctstr *, coord, coord, int, int);
51
52 /*
53  * See if any nearby ships will open up on the attacker
54  * Return damage done to attacker, if any.
55  * Subtracts shells used for firing.  Responding ships
56  * require military, shells, and guns.
57  */
58 int
59 shipdef(natid att, natid own, coord x, coord y)
60 {
61     return sd(att, own, x, y, NOISY, 1, 1);
62 }
63
64 int
65 sd(natid att, natid own, coord x, coord y, int noisy, int defending,
66    int usesubs)
67 {
68     int range;
69     double eff;
70     struct shpstr ship;
71     struct nstr_item ni;
72     int dam;
73
74     if (own == 0)
75         return 0;
76     if (att == own)
77         return 0;
78     eff = 1.0;
79     snxtitem_dist(&ni, EF_SHIP, x, y, 8);
80     while (nxtitem(&ni, &ship) && eff > 0.30) {
81         if (!feels_like_helping(ship.shp_own, own, att))
82             continue;
83
84         if ((mchr[(int)ship.shp_type].m_flags & M_SUB) && !usesubs)
85             continue;
86         range = roundrange(shp_fire_range(&ship));
87         if (range < ni.curdist)
88             continue;
89         dam = shp_fire(&ship);
90         putship(ship.shp_uid, &ship);
91         if (dam < 0)
92             continue;
93         if (defending)
94             nreport(ship.shp_own, N_FIRE_BACK, att, 1);
95         else
96             nreport(ship.shp_own, N_FIRE_S_ATTACK, att, 1);
97         eff *= (1.0 - (0.01 * dam));
98         if (noisy) {
99             pr_beep();
100             pr("Incoming shells do %d damage!\n", dam);
101         }
102         if (noisy || (ship.shp_own != own)) {
103             if (ship.shp_own == own)
104                 wu(0, own, "%s fired on %s at %s doing %d damage.\n",
105                    prship(&ship), cname(att), xyas(x, y, own), dam);
106             else {
107                 if (defending)
108                     wu(0, ship.shp_own,
109                        "%s fired on %s at %s in defense of %s, doing %d damage.\n",
110                        prship(&ship), cname(att), xyas(x, y, ship.shp_own),
111                        cname(own), dam);
112                 else
113                     wu(0, ship.shp_own,
114                        "%s supported %s attacks against %s at %s, doing %d damage.\n",
115                        prship(&ship), cname(own), cname(att),
116                        xyas(x, y, ship.shp_own), dam);
117             }
118         }
119     }
120     return (int)(100 - eff * 100);
121 }
122
123 int
124 dd(natid att, natid def_own, coord ax, coord ay, int noisy, int defending)
125 {
126     int dam;
127     struct sctstr firing;
128     struct nstr_sect ns;
129
130     if (opt_NO_FORT_FIRE)       /* Forts can't fire! */
131         return 0;
132     if (def_own == 0)
133         return 0;
134     if (att == def_own)
135         return 0;
136     dam = 0;
137     snxtsct_dist(&ns, ax, ay, 8);
138     while (nxtsct(&ns, &firing) && dam < 80) {
139         if (!feels_like_helping(firing.sct_own, def_own, att))
140             continue;
141         /* XXX defdef damage is additive, but ship or land unit damage isn't */
142         dam += sb(att, def_own, &firing, ax, ay, noisy, defending);
143     }
144     return dam;
145 }
146
147 /*
148  * Shall @cn attempt to help @friend against @foe?
149  */
150 int
151 feels_like_helping(natid cn, natid friend, natid foe)
152 {
153     if (cn == 0)
154         return 0;               /* never helps anybody */
155     if (cn == foe)
156         return 0;               /* don't help anybody against self */
157     if (cn == friend)
158         return 1;               /* help self against anybody else */
159     /* third party helps ally if at war with foe: */
160     return relations_with(cn, friend) == ALLIED
161         && relations_with(cn, foe) == AT_WAR;
162 }
163
164 /* Shoot back
165  *
166  * See if the sector being fired at will defend itself.
167  */
168 static int
169 sb(natid att, natid def, struct sctstr *sp, coord tx, coord ty, int noisy,
170    int defending)
171 {
172     int damage;
173     natid own;
174     int range, range2;
175
176     own = sp->sct_own;
177     if (own == 0)
178         return 0;
179     if (att == own)
180         return 0;
181     range = roundrange(fortrange(sp));
182     range2 = mapdist(sp->sct_x, sp->sct_y, tx, ty);
183     if (range < range2)
184         return 0;
185     damage = fort_fire(sp);
186     putsect(sp);
187     if (damage < 0)
188         return 0;
189     if (sp->sct_own != def)
190         wu(0, sp->sct_own,
191            "%s fired on %s in %s in defense of %s, doing %d damage!\n",
192            xyas(sp->sct_x, sp->sct_y, sp->sct_own), cname(att),
193            xyas(tx, ty, sp->sct_own), cname(def), damage);
194     if (defending)
195         nreport(sp->sct_own, N_FIRE_BACK, att, 1);
196     else
197         nreport(sp->sct_own, N_FIRE_F_ATTACK, att, 1);
198     if (noisy)
199         pr("Incoming shell! %d damage done.\007\n", damage);
200     return damage;
201 }