1286438Sbapt/* $NetBSD: dr_3.c,v 1.18 2009/03/14 20:04:43 dholland Exp $ */ 2286438Sbapt 3286438Sbapt/* 4286438Sbapt * Copyright (c) 1983, 1993 5286438Sbapt * The Regents of the University of California. All rights reserved. 6286438Sbapt * 7286438Sbapt * Redistribution and use in source and binary forms, with or without 8286438Sbapt * modification, are permitted provided that the following conditions 9286438Sbapt * are met: 10286438Sbapt * 1. Redistributions of source code must retain the above copyright 11286438Sbapt * notice, this list of conditions and the following disclaimer. 12286438Sbapt * 2. Redistributions in binary form must reproduce the above copyright 13286438Sbapt * notice, this list of conditions and the following disclaimer in the 14286438Sbapt * documentation and/or other materials provided with the distribution. 15286438Sbapt * 3. Neither the name of the University nor the names of its contributors 16286438Sbapt * may be used to endorse or promote products derived from this software 17286438Sbapt * without specific prior written permission. 18286438Sbapt * 19286438Sbapt * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20286438Sbapt * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21286438Sbapt * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22286438Sbapt * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 23286438Sbapt * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24286438Sbapt * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25286438Sbapt * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26286438Sbapt * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27286438Sbapt * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28286438Sbapt * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29286438Sbapt * SUCH DAMAGE. 30286438Sbapt */ 31286438Sbapt 32286438Sbapt#include <sys/cdefs.h> 33286438Sbapt#ifndef lint 34286438Sbapt#if 0 35286438Sbaptstatic char sccsid[] = "@(#)dr_3.c 8.1 (Berkeley) 5/31/93"; 36286438Sbapt#else 37286438Sbapt__RCSID("$NetBSD: dr_3.c,v 1.18 2009/03/14 20:04:43 dholland Exp $"); 38286438Sbapt#endif 39286438Sbapt#endif /* not lint */ 40286438Sbapt 41286438Sbapt#include <stdlib.h> 42286438Sbapt#include <string.h> 43286438Sbapt#include "extern.h" 44286438Sbapt#include "driver.h" 45286438Sbapt 46286438Sbaptstatic int stillmoving(int); 47286438Sbaptstatic int is_isolated(struct ship *); 48286438Sbaptstatic int push(struct ship *, struct ship *); 49286438Sbaptstatic void step(struct ship *, int, char *); 50325928Sbapt 51325928Sbapt/* move all comp ships */ 52325928Sbaptvoid 53286438Sbaptmoveall(void) 54286438Sbapt{ 55312336Sbapt struct ship *sp, *sq; 56312336Sbapt int n; 57312336Sbapt int k, l; 58312336Sbapt int row[NSHIP], col[NSHIP], dir[NSHIP], drift[NSHIP]; 59312336Sbapt char moved[NSHIP]; 60312336Sbapt 61312336Sbapt /* 62312336Sbapt * first try to create moves for OUR ships 63312336Sbapt */ 64312336Sbapt foreachship(sp) { 65312336Sbapt struct ship *closest; 66312336Sbapt int ma, ta; 67312336Sbapt bool af; 68312336Sbapt 69312336Sbapt if (sp->file->captain[0] || sp->file->dir == 0) 70286438Sbapt continue; 71286438Sbapt if (!sp->file->struck && windspeed && !snagged(sp) 72286438Sbapt && sp->specs->crew3) { 73286438Sbapt ta = maxturns(sp, &af); 74286438Sbapt ma = maxmove(sp, sp->file->dir, 0); 75286438Sbapt closest = closestenemy(sp, 0, 0); 76312336Sbapt if (closest == 0) 77312336Sbapt *sp->file->movebuf = '\0'; 78312336Sbapt else 79312336Sbapt closeon(sp, closest, sp->file->movebuf, 80312336Sbapt sizeof(sp->file->movebuf), 81312336Sbapt ta, ma, af); 82312336Sbapt } else 83325928Sbapt *sp->file->movebuf = '\0'; 84286438Sbapt } 85286438Sbapt /* 86286438Sbapt * Then execute the moves for ALL ships (dead ones too), 87286438Sbapt * checking for collisions and snags at each step. 88286438Sbapt * The old positions are saved in row[], col[], dir[]. 89286438Sbapt * At the end, we compare and write out the changes. 90286438Sbapt */ 91286438Sbapt n = 0; 92286438Sbapt foreachship(sp) { 93286438Sbapt if (snagged(sp)) 94286438Sbapt strcpy(sp->file->movebuf, "d"); 95286438Sbapt else 96286438Sbapt if (*sp->file->movebuf != 'd') 97286438Sbapt strcat(sp->file->movebuf, "d"); 98286438Sbapt row[n] = sp->file->row; 99286438Sbapt col[n] = sp->file->col; 100286438Sbapt dir[n] = sp->file->dir; 101286438Sbapt drift[n] = sp->file->drift; 102286438Sbapt moved[n] = 0; 103286438Sbapt n++; 104286438Sbapt } 105286438Sbapt /* 106286438Sbapt * Now resolve collisions. 107286438Sbapt * This is the tough part. 108286438Sbapt */ 109286438Sbapt for (k = 0; stillmoving(k); k++) { 110286438Sbapt /* 111286438Sbapt * Step once. 112286438Sbapt * And propagate the nulls at the end of sp->file->movebuf. 113286438Sbapt */ 114286438Sbapt n = 0; 115286438Sbapt foreachship(sp) { 116286438Sbapt if (!sp->file->movebuf[k]) 117286438Sbapt sp->file->movebuf[k+1] = '\0'; 118286438Sbapt else if (sp->file->dir) 119286438Sbapt step(sp, sp->file->movebuf[k], &moved[n]); 120286438Sbapt n++; 121286438Sbapt } 122286438Sbapt /* 123286438Sbapt * The real stuff. 124286438Sbapt */ 125286438Sbapt n = 0; 126286438Sbapt foreachship(sp) { 127286438Sbapt if (sp->file->dir == 0 || is_isolated(sp)) 128286438Sbapt goto cont1; 129286438Sbapt l = 0; 130286438Sbapt foreachship(sq) { 131286438Sbapt char snap = 0; 132286438Sbapt 133286438Sbapt if (sp == sq) 134286438Sbapt goto cont2; 135286438Sbapt if (sq->file->dir == 0) 136286438Sbapt goto cont2; 137286438Sbapt if (!push(sp, sq)) 138286438Sbapt goto cont2; 139286438Sbapt if (snagged2(sp, sq) && range(sp, sq) > 1) 140286438Sbapt snap++; 141286438Sbapt if (!range(sp, sq) && !fouled2(sp, sq)) { 142286438Sbapt makesignal(sp, "collision with $$", sq); 143286438Sbapt if (dieroll() < 4) { 144286438Sbapt makesignal(sp, "fouled with $$", 145286438Sbapt sq); 146286438Sbapt send_foul(sp, l); 147286438Sbapt send_foul(sq, n); 148286438Sbapt } 149286438Sbapt snap++; 150286438Sbapt } 151286438Sbapt if (snap) { 152286438Sbapt sp->file->movebuf[k + 1] = 0; 153286438Sbapt sq->file->movebuf[k + 1] = 0; 154286438Sbapt sq->file->row = sp->file->row - 1; 155286438Sbapt if (sp->file->dir == 1 156286438Sbapt || sp->file->dir == 5) 157286438Sbapt sq->file->col = 158286438Sbapt sp->file->col - 1; 159286438Sbapt else 160286438Sbapt sq->file->col = sp->file->col; 161286438Sbapt sq->file->dir = sp->file->dir; 162286438Sbapt } 163286438Sbapt cont2: 164286438Sbapt l++; 165286438Sbapt } 166286438Sbapt cont1: 167286438Sbapt n++; 168286438Sbapt } 169286438Sbapt } 170286438Sbapt /* 171286438Sbapt * Clear old moves. And write out new pos. 172286438Sbapt */ 173286438Sbapt n = 0; 174286438Sbapt foreachship(sp) { 175286438Sbapt if (sp->file->dir != 0) { 176286438Sbapt *sp->file->movebuf = 0; 177286438Sbapt if (row[n] != sp->file->row) 178286438Sbapt send_row(sp, sp->file->row); 179286438Sbapt if (col[n] != sp->file->col) 180286438Sbapt send_col(sp, sp->file->col); 181286438Sbapt if (dir[n] != sp->file->dir) 182286438Sbapt send_dir(sp, sp->file->dir); 183286438Sbapt if (drift[n] != sp->file->drift) 184286438Sbapt send_drift(sp, sp->file->drift); 185286438Sbapt } 186286438Sbapt n++; 187286438Sbapt } 188286438Sbapt} 189286438Sbapt 190286438Sbaptstatic int 191286438Sbaptstillmoving(int k) 192286438Sbapt{ 193286438Sbapt struct ship *sp; 194286438Sbapt 195286438Sbapt foreachship(sp) 196286438Sbapt if (sp->file->movebuf[k]) 197286438Sbapt return 1; 198286438Sbapt return 0; 199286438Sbapt} 200286438Sbapt 201286438Sbaptstatic int 202286438Sbaptis_isolated(struct ship *ship) 203286438Sbapt{ 204286438Sbapt struct ship *sp; 205286438Sbapt 206286438Sbapt foreachship(sp) { 207286438Sbapt if (ship != sp && range(ship, sp) <= 10) 208286438Sbapt return 0; 209325928Sbapt } 210325928Sbapt return 1; 211325928Sbapt} 212286438Sbapt 213286438Sbaptstatic int 214312336Sbaptpush(struct ship *from, struct ship *to) 215312336Sbapt{ 216312336Sbapt int bs, sb; 217312336Sbapt 218312336Sbapt sb = to->specs->guns; 219312336Sbapt bs = from->specs->guns; 220312336Sbapt if (sb > bs) 221312336Sbapt return 1; 222312336Sbapt if (sb < bs) 223312336Sbapt return 0; 224312336Sbapt return from < to; 225312336Sbapt} 226312336Sbapt 227312336Sbaptstatic void 228312336Sbaptstep(struct ship *sp, int com, char *moved) 229286438Sbapt{ 230286438Sbapt int dist; 231286438Sbapt 232286438Sbapt switch (com) { 233286438Sbapt case 'r': 234286438Sbapt if (++sp->file->dir == 9) 235312336Sbapt sp->file->dir = 1; 236312336Sbapt break; 237312336Sbapt case 'l': 238312336Sbapt if (--sp->file->dir == 0) 239312336Sbapt sp->file->dir = 8; 240312336Sbapt break; 241312336Sbapt case '0': case '1': case '2': case '3': 242325928Sbapt case '4': case '5': case '6': case '7': 243286438Sbapt if (sp->file->dir % 2 == 0) 244286438Sbapt dist = dtab[com - '0']; 245286438Sbapt else 246286438Sbapt dist = com - '0'; 247286438Sbapt sp->file->row -= dr[sp->file->dir] * dist; 248286438Sbapt sp->file->col -= dc[sp->file->dir] * dist; 249286438Sbapt *moved = 1; 250286438Sbapt break; 251286438Sbapt case 'b': 252286438Sbapt break; 253286438Sbapt case 'd': 254286438Sbapt if (!*moved) { 255286438Sbapt if (windspeed != 0 && ++sp->file->drift > 2 && 256286438Sbapt ((sp->specs->class >= 3 && !snagged(sp)) 257286438Sbapt || (turn & 1) == 0)) { 258286438Sbapt sp->file->row -= dr[winddir]; 259286438Sbapt sp->file->col -= dc[winddir]; 260286438Sbapt } 261286438Sbapt } else { 262286438Sbapt sp->file->drift = 0; 263286438Sbapt } 264286438Sbapt break; 265286438Sbapt } 266286438Sbapt} 267286438Sbapt 268286438Sbaptvoid 269286438Sbaptsendbp(struct ship *from, struct ship *to, int sections, int isdefense) 270286438Sbapt{ 271286438Sbapt int n; 272286438Sbapt struct BP *bp; 273286438Sbapt 274286438Sbapt bp = isdefense ? from->file->DBP : from->file->OBP; 275286438Sbapt for (n = 0; n < NBP && bp[n].turnsent; n++) 276286438Sbapt ; 277286438Sbapt if (n < NBP && sections) { 278286438Sbapt if (isdefense) { 279286438Sbapt send_dbp(from, n, turn, to->file->index, sections); 280286438Sbapt } else { 281286438Sbapt send_obp(from, n, turn, to->file->index, sections); 282286438Sbapt } 283286438Sbapt if (isdefense) 284286438Sbapt makemsg(from, "repelling boarders"); 285286438Sbapt else 286286438Sbapt makesignal(from, "boarding the $$", to); 287286438Sbapt } 288286438Sbapt} 289286438Sbapt 290286438Sbaptint 291286438Sbaptis_toughmelee(struct ship *ship, struct ship *to, int isdefense, int count) 292286438Sbapt{ 293286438Sbapt struct BP *bp; 294286438Sbapt int obp = 0; 295286438Sbapt int n, OBP = 0, DBP = 0, dbp = 0; 296286438Sbapt int qual; 297286438Sbapt 298286438Sbapt qual = ship->specs->qual; 299286438Sbapt bp = isdefense ? ship->file->DBP : ship->file->OBP; 300286438Sbapt for (n = 0; n < NBP; n++, bp++) { 301286438Sbapt if (bp->turnsent && (to == bp->toship || isdefense)) { 302286438Sbapt obp += bp->mensent / 100 303286438Sbapt ? ship->specs->crew1 * qual : 0; 304286438Sbapt obp += (bp->mensent % 100)/10 305286438Sbapt ? ship->specs->crew2 * qual : 0; 306286438Sbapt obp += bp->mensent % 10 307286438Sbapt ? ship->specs->crew3 * qual : 0; 308286438Sbapt } 309286438Sbapt } 310286438Sbapt if (count || isdefense) 311286438Sbapt return obp; 312286438Sbapt OBP = is_toughmelee(to, ship, 0, count + 1); 313286438Sbapt dbp = is_toughmelee(ship, to, 1, count + 1); 314286438Sbapt DBP = is_toughmelee(to, ship, 1, count + 1); 315286438Sbapt if (OBP > obp + 10 || OBP + DBP >= obp + dbp + 10) 316286438Sbapt return 1; 317286438Sbapt else 318286438Sbapt return 0; 319286438Sbapt} 320286438Sbapt 321286438Sbaptvoid 322286438Sbaptreload(void) 323286438Sbapt{ 324286438Sbapt struct ship *sp; 325286438Sbapt 326286438Sbapt foreachship(sp) { 327286438Sbapt sp->file->loadwith = 0; 328286438Sbapt } 329286438Sbapt} 330286438Sbapt 331286438Sbaptvoid 332286438Sbaptchecksails(void) 333286438Sbapt{ 334286438Sbapt struct ship *sp; 335286438Sbapt int rig, full; 336286438Sbapt struct ship *close; 337286438Sbapt 338286438Sbapt foreachship(sp) { 339286438Sbapt if (sp->file->captain[0] != 0) 340286438Sbapt continue; 341286438Sbapt rig = sp->specs->rig1; 342286438Sbapt if (windspeed == 6 || (windspeed == 5 && sp->specs->class > 4)) 343286438Sbapt rig = 0; 344286438Sbapt if (rig && sp->specs->crew3) { 345286438Sbapt close = closestenemy(sp, 0, 0); 346286438Sbapt if (close != 0) { 347286438Sbapt if (range(sp, close) > 9) 348286438Sbapt full = 1; 349286438Sbapt else 350286438Sbapt full = 0; 351286438Sbapt } else { 352286438Sbapt full = 0; 353286438Sbapt } 354286438Sbapt } else { 355286438Sbapt full = 0; 356286438Sbapt } 357286438Sbapt if ((sp->file->FS != 0) != full) 358286438Sbapt send_fs(sp, full); 359286438Sbapt } 360286438Sbapt} 361286438Sbapt