]> git.pond.sub.org Git - empserver/blob - src/lib/commands/assa.c
assault: Simplify sneak_ashore()
[empserver] / src / lib / commands / assa.c
1 /*
2  *  Empire - A multi-player, client/server Internet based war game.
3  *  Copyright (C) 1986-2016, 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  *  assa.c: Hit the beaches!
28  *
29  *  Known contributors to this file:
30  *     Ken Stevens, 1995
31  *     Steve McClure, 1997
32  *     Markus Armbruster, 2009-2016
33  */
34
35 #include <config.h>
36
37 #include "chance.h"
38 #include "combat.h"
39 #include "commands.h"
40 #include "empobj.h"
41 #include "unit.h"
42
43 static int only_spies(struct combat[], struct emp_qelem *);
44 static void sneak_ashore(struct emp_qelem *, struct combat *);
45
46 int
47 assa(void)
48 {
49     struct combat off[1];       /* assaulting ship */
50     struct combat def[1];       /* defending sector */
51     int fort_sup, ship_sup, land_sup, plane_sup;
52     struct emp_qelem olist;     /* assaulting units */
53     struct emp_qelem dlist;     /* defending units */
54     int ototal;                 /* total assaulting strength */
55     int a_engineer = 0;         /* assaulter engineers are present */
56     int a_spy = 0;              /* the best assaulter scout */
57     double osupport = 1.0;      /* assault support */
58     double dsupport = 1.0;      /* defense support */
59     char *p;
60     char buf[1024];
61
62     att_combat_init(off, EF_SHIP);
63     att_combat_init(def, EF_SECTOR);
64     /*
65      * Collect input from the assaulter
66      */
67
68     /* What are we assaulting? */
69
70     if (!(p = getstarg(player->argp[1], "Sector :  ", buf)))
71         return RET_SYN;
72     if (!sarg_xy(p, &def->x, &def->y))
73         return RET_SYN;
74     if (att_abort(A_ASSAULT, NULL, def))
75         return RET_FAIL;
76
77     /*
78      * Ask the assaulter what he wants to assault with
79      */
80
81     if ((off->shp_uid =
82          onearg(player->argp[2], "Assault from ship # ")) < 0) {
83         pr("You may only assault from one ship!\n");
84         return RET_FAIL;
85     }
86     if (att_abort(A_ASSAULT, off, def)) {
87         pr("Assault aborted\n");
88         return RET_OK;
89     }
90
91     /* Show what we're assaulting */
92     att_show(def);
93
94     /* Ask about offensive support */
95
96     att_ask_support(3, &fort_sup, &ship_sup, &land_sup, &plane_sup);
97     if (att_abort(A_ASSAULT, off, def)) {
98         att_empty_attack(A_ASSAULT, 0, def);
99         return RET_OK;
100     }
101
102     /* Ask the player what he wants to assault with */
103
104     att_ask_offense(A_ASSAULT, off, def, &olist, &a_spy, &a_engineer);
105     if (att_abort(A_ASSAULT, off, def)) {
106         pr("Assault aborted\n");
107         att_empty_attack(A_ASSAULT, 0, def);
108         return att_free_lists(&olist, NULL);
109     }
110
111     /* If we're assaulting our own sector, end here */
112     if (def->own == player->cnum) {
113         if (off->troops)
114             pr("You reinforce %s with %d troops\n",
115                xyas(def->x, def->y, player->cnum), off->troops);
116         if (off->troops || !QEMPTY(&olist))
117             att_move_in_off(A_ASSAULT, off, &olist, def);
118         return RET_OK;
119     }
120
121     ototal = att_get_offense(A_ASSAULT, off, &olist, def);
122     if (att_abort(A_ASSAULT, off, def)) {
123         pr("Assault aborted\n");
124         att_empty_attack(A_ASSAULT, 0, def);
125         return att_free_lists(&olist, NULL);
126     }
127
128     /*
129      * We have now got all the answers from the assaulter.  From this point
130      * forward, we can assume that this battle is the _only_ thing
131      * happening in the game.
132      */
133
134     /* First, we check to see if the only thing we have are spies
135      * assaulting.  If so, we try to sneak them on land.  If they
136      * make it, the defenders don't see a thing.  If they fail, well,
137      * the spies die, and the defenders see them. */
138
139     /* If no attacking forces (i.e. we got here with only spies)
140      * then try to sneak on-land. */
141     if (only_spies(off, &olist)) {
142         sneak_ashore(&olist, def);
143         return RET_OK;
144     }
145
146     /* Get the real defense */
147
148     att_get_defense(&olist, def, &dlist, a_spy, ototal);
149
150     /* Get assaulter and defender support */
151
152     att_get_support(A_ASSAULT, fort_sup, ship_sup, land_sup, plane_sup,
153                     &olist, off, &dlist, def, &osupport, &dsupport,
154                     a_engineer);
155     if (att_abort(A_ASSAULT, off, def)) {
156         pr("Assault aborted\n");
157         att_empty_attack(A_ASSAULT, 0, def);
158         return att_free_lists(&olist, &dlist);
159     }
160
161     /*
162      * Death, carnage, and destruction.
163      */
164
165     att_fight(A_ASSAULT, off, &olist, osupport, def, &dlist, dsupport);
166
167     return RET_OK;
168 }
169
170 static int
171 only_spies(struct combat off[], struct emp_qelem *olist)
172 {
173     int n;
174     struct emp_qelem *qp;
175     struct ulist *llp;
176
177     for (n = 0; n <= off->last; n++) {
178         if (off[n].type == EF_BAD)
179             continue;
180         if (off[n].troops)
181             return 0;
182     }
183
184     for (qp = olist->q_forw; qp != olist; qp = qp->q_forw) {
185         llp = (struct ulist *)qp;
186         if (!(lchr[llp->unit.land.lnd_type].l_flags & L_SPY))
187             return 0;
188     }
189
190     return 1;
191 }
192
193 static void
194 sneak_ashore(struct emp_qelem *olist, struct combat *def)
195 {
196     struct emp_qelem *qp, *next;
197     struct ulist *llp;
198     struct lndstr *lp;
199     int rel;
200
201     pr("Trying to sneak on shore...\n");
202
203     for (qp = olist->q_forw; qp != olist; qp = next) {
204         next = qp->q_forw;
205         llp = (struct ulist *)qp;
206         lp = &llp->unit.land;
207         rel = relations_with(def->own, player->cnum);
208         if (chance(0.10) || rel == ALLIED || !def->own) {
209             pr("%s made it on shore safely.\n", prland(lp));
210             lp->lnd_x = def->x;
211             lp->lnd_y = def->y;
212             lp->lnd_ship = -1;
213             putland(lp->lnd_uid, lp);
214         } else {
215             pr("%s was spotted", prland(lp));
216             if (rel <= HOSTILE) {
217                 wu(0, def->own, "%s spy shot and killed in %s.\n",
218                    cname(player->cnum), xyas(def->x, def->y,
219                                              def->own));
220                 pr(" and was killed in the attempt.\n");
221                 lp->lnd_effic = 0;
222                 putland(lp->lnd_uid, lp);
223                 lnd_put_one(llp);
224             } else {
225                 wu(0, def->own, "%s spy spotted in %s.\n",
226                    cname(player->cnum), xyas(def->x, def->y,
227                                              def->own));
228                 pr(" but made it ok.\n");
229                 lp->lnd_x = def->x;
230                 lp->lnd_y = def->y;
231                 lp->lnd_ship = -1;
232                 putland(lp->lnd_uid, lp);
233             }
234         }
235     }
236 }