xref: /dragonfly/games/sail/dr_2.c (revision 7b728a631c9003a1e68026d9619af346838b0be3)
1 /*        $NetBSD: dr_2.c,v 1.27 2019/02/03 10:48:46 mrg Exp $        */
2 
3 /*
4  * Copyright (c) 1983, 1993
5  *        The Regents of the University of California.  All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. Neither the name of the University nor the names of its contributors
16  *    may be used to endorse or promote products derived from this software
17  *    without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29  * SUCH DAMAGE.
30  */
31 
32 #include <sys/cdefs.h>
33 #ifndef lint
34 #if 0
35 static char sccsid[] = "@(#)dr_2.c      8.1 (Berkeley) 5/31/93";
36 #else
37 __RCSID("$NetBSD: dr_2.c,v 1.27 2019/02/03 10:48:46 mrg Exp $");
38 #endif
39 #endif /* not lint */
40 
41 #include <stdbool.h>
42 #include <stdio.h>
43 #include <stdlib.h>
44 #include <string.h>
45 #include "extern.h"
46 #include "driver.h"
47 
48 #define couldwin(f,t) (f->specs->crew2 > t->specs->crew2 * 1.5)
49 
50 static int str_end(const char *);
51 static int score(struct ship *, struct ship *, char *, size_t, int);
52 static void move_ship(struct ship *, const char *, unsigned char *,
53                           short *, short *, int *);
54 static void try(struct ship *f, struct ship *t,
55                     char *command, size_t commandmax, char *temp, size_t tempmax,
56                     int ma, int ta, bool af, int vma, int dir, int *high,
57                     int rakeme);
58 static void rmend(char *);
59 
60 const int dtab[] = {0,1,1,2,3,4,4,5};   /* diagonal distances in x==y */
61 
62 void
thinkofgrapples(void)63 thinkofgrapples(void)
64 {
65           struct ship *sp, *sq;
66           bool friendly;
67 
68           foreachship(sp) {
69                     if (sp->file->captain[0] || sp->file->dir == 0)
70                               continue;
71                     foreachship(sq) {
72                               friendly = sp->nationality == capship(sq)->nationality;
73                               if (!friendly) {
74                                         if (sp->file->struck || sp->file->captured != 0)
75                                                   continue;
76                                         if (range(sp, sq) != 1)
77                                                   continue;
78                                         if (grappled2(sp, sq)) {
79                                                   if (is_toughmelee(sp, sq, 0, 0))
80                                                             ungrap(sp, sq);
81                                                   else
82                                                             grap(sp, sq);
83                                         } else if (couldwin(sp, sq)) {
84                                                   grap(sp, sq);
85                                                   sp->file->loadwith = L_GRAPE;
86                                         }
87                               } else
88                                         ungrap(sp, sq);
89                     }
90           }
91 }
92 
93 void
checkup(void)94 checkup(void)
95 {
96           struct ship *sp, *sq;
97           char explode, sink;
98 
99           foreachship(sp) {
100                     if (sp->file->dir == 0)
101                               continue;
102                     explode = sp->file->explode;
103                     sink = sp->file->sink;
104                     if (explode != 1 && sink != 1)
105                               continue;
106                     if (dieroll() < 5)
107                               continue;
108                     if (sink == 1) {
109                               send_sink(sp, 2);
110                     } else {
111                               send_explode(sp, 2);
112                     }
113                     send_dir(sp, 0);
114                     if (snagged(sp))
115                               foreachship(sq)
116                                         cleansnag(sp, sq, 1);
117                     if (sink != 1) {
118                               makemsg(sp, "exploding!");
119                               foreachship(sq) {
120                                         if (sp != sq && sq->file->dir &&
121                                             range(sp, sq) < 4)
122                                                   table(sp, sq, RIGGING, L_EXPLODE,
123                                                         sp->specs->guns/13, 6);
124                               }
125                     } else {
126                               makemsg(sp, "sinking!");
127                     }
128           }
129 }
130 
131 void
prizecheck(void)132 prizecheck(void)
133 {
134           struct ship *sp;
135 
136           foreachship(sp) {
137                     if (sp->file->captured == 0)
138                               continue;
139                     if (sp->file->struck || sp->file->dir == 0)
140                               continue;
141                     if (sp->specs->crew1 + sp->specs->crew2 + sp->specs->crew3 >
142                         sp->file->pcrew * 6) {
143                               send_signal(sp, "prize crew overthrown");
144                               send_points(sp->file->captured,
145                                     sp->file->captured->file->points
146                                         - 2 * sp->specs->pts);
147                               send_captured(sp, -1);
148                     }
149           }
150 }
151 
152 static int
str_end(const char * str)153 str_end(const char *str)
154 {
155           const char *p;
156 
157           for (p = str; *p; p++)
158                     ;
159           return p == str ? 0 : p[-1];
160 }
161 
162 void
closeon(struct ship * from,struct ship * to,char * command,size_t commandmax,int ta,int ma,bool af)163 closeon(struct ship *from, struct ship *to, char *command, size_t commandmax,
164           int ta, int ma, bool af)
165 {
166           int high;
167           char temp[10];
168 
169           temp[0] = command[0] = '\0';
170           high = -30000;
171           try(from, to, command, commandmax, temp, sizeof(temp),
172               ma, ta, af, ma, from->file->dir, &high, 0);
173 }
174 
175 static int
score(struct ship * ship,struct ship * to,char * movement,size_t movementmax,int onlytemp)176 score(struct ship *ship, struct ship *to, char *movement, size_t movementmax,
177       int onlytemp)
178 {
179           int drift;
180           int row, col, dir, total, ran;
181           struct File *fp = ship->file;
182 
183           if ((dir = fp->dir) == 0)
184                     return 0;
185           row = fp->row;
186           col = fp->col;
187           drift = fp->drift;
188           move_ship(ship, movement, &fp->dir, &fp->row, &fp->col, &drift);
189           if (!*movement)
190                     strlcpy(movement, "d", movementmax);
191 
192           ran = range(ship, to);
193           total = -50 * ran;
194           if (ran < 4 && gunsbear(ship, to))
195                     total += 60;
196           if ((ran = portside(ship, to, 1) - fp->dir) == 4 || ran == -4)
197                     total = -30000;
198 
199           if (!onlytemp) {
200                     fp->row = row;
201                     fp->col = col;
202                     fp->dir = dir;
203           }
204           return total;
205 }
206 
207 static void
move_ship(struct ship * ship,const char * p,unsigned char * dir,short * row,short * col,int * drift)208 move_ship(struct ship *ship, const char *p, unsigned char *dir,
209             short *row, short *col, int *drift)
210 {
211           int dist;
212           char moved = 0;
213 
214           for (; *p; p++) {
215                     switch (*p) {
216                     case 'r':
217                               if (++*dir == 9)
218                                         *dir = 1;
219                               break;
220                     case 'l':
221                               if (--*dir == 0)
222                                         *dir = 8;
223                               break;
224                     case '1': case '2': case '3': case '4':
225                     case '5': case '6': case '7':
226                               moved++;
227                               if (*dir % 2 == 0)
228                                         dist = dtab[*p - '0'];
229                               else
230                                         dist = *p - '0';
231                               *row -= dr[*dir] * dist;
232                               *col -= dc[*dir] * dist;
233                               break;
234                     }
235           }
236           if (!moved) {
237                     if (windspeed != 0 && ++*drift > 2) {
238                               if ((ship->specs->class >= 3 && !snagged(ship))
239                                   || (turn & 1) == 0) {
240                                         *row -= dr[winddir];
241                                         *col -= dc[winddir];
242                               }
243                     }
244           } else
245                     *drift = 0;
246 }
247 
248 static void
try(struct ship * f,struct ship * t,char * command,size_t commandmax,char * temp,size_t tempmax,int ma,int ta,bool af,int vma,int dir,int * high,int rakeme)249 try(struct ship *f, struct ship *t,
250     char *command, size_t commandmax,
251     char *temp, size_t tempmax,
252     int ma, int ta, bool af, int vma, int dir, int *high, int rakeme)
253 {
254           int new, n;
255           char st[11];
256 #define rakeyou (gunsbear(f, t) && !gunsbear(t, f))
257 
258           if ((n = str_end(temp)) < '1' || n > '9')
259                     for (n = 1; vma - n >= 0; n++) {
260                               snprintf(st, sizeof(st), "%d", n);
261                               strlcat(temp, st, tempmax);
262                               new = score(f, t, temp, tempmax, rakeme);
263                               if (new > *high && (!rakeme || rakeyou)) {
264                                         *high = new;
265                                         strlcpy(command, temp, commandmax);
266                               }
267                               try(f, t, command, commandmax, temp, tempmax,
268                                   ma-n, ta, af, vma-n,
269                                   dir, high, rakeme);
270                               rmend(temp);
271                     }
272           if ((ma > 0 && ta > 0 && (n = str_end(temp)) != 'l' && n != 'r') ||
273               !strlen(temp)) {
274                     strlcat(temp, "r", tempmax);
275                     new = score(f, t, temp, tempmax, rakeme);
276                     if (new > *high && (!rakeme ||
277                                             (gunsbear(f, t) && !gunsbear(t, f)))) {
278                               *high = new;
279                               strlcpy(command, temp, commandmax);
280                     }
281                     try(f, t, command, commandmax, temp, tempmax,
282                         ma-1, ta-1, af,
283                         min(ma-1, maxmove(f, (dir == 8 ? 1 : dir+1), 0)),
284                         (dir == 8 ? 1 : dir+1), high, rakeme);
285                     rmend(temp);
286           }
287           if ((ma > 0 && ta > 0 && (n = str_end(temp)) != 'l' && n != 'r') ||
288               !strlen(temp)) {
289                     strlcat(temp, "l", tempmax);
290                     new = score(f, t, temp, tempmax, rakeme);
291                     if (new > *high && (!rakeme ||
292                                             (gunsbear(f, t) && !gunsbear(t, f)))) {
293                               *high = new;
294                               strlcpy(command, temp, commandmax);
295                     }
296                     try(f, t, command, commandmax, temp, tempmax,
297                         ma-1, ta-1, af,
298                         (min(ma-1,maxmove(f, (dir-1 ? dir-1 : 8), 0))),
299                         (dir-1 ? dir -1 : 8), high, rakeme);
300                     rmend(temp);
301           }
302 }
303 
304 static void
rmend(char * str)305 rmend(char *str)
306 {
307           char *p;
308 
309           for (p = str; *p; p++)
310                     ;
311           if (p != str)
312                     *--p = 0;
313 }
314