1 /*- 2 * Copyright (c) 1983, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. Neither the name of the University nor the names of its contributors 14 * may be used to endorse or promote products derived from this software 15 * without specific prior written permission. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 * 29 * @(#)dr_1.c 8.1 (Berkeley) 5/31/93 30 * $FreeBSD: src/games/sail/dr_1.c,v 1.7 1999/11/30 03:49:32 billf Exp $ 31 */ 32 33 #include "driver.h" 34 35 static int fightitout(struct ship *, struct ship *, int); 36 37 void 38 unfoul(void) 39 { 40 struct ship *sp; 41 struct ship *to; 42 int nat; 43 int i; 44 45 foreachship(sp) { 46 if (sp->file->captain[0]) 47 continue; 48 nat = capship(sp)->nationality; 49 foreachship(to) { 50 if (nat != capship(to)->nationality && 51 !toughmelee(sp, to, 0, 0)) 52 continue; 53 for (i = fouled2(sp, to); --i >= 0;) 54 if (die() <= 2) 55 cleanfoul(sp, to, 0); 56 } 57 } 58 } 59 60 void 61 boardcomp(void) 62 { 63 int crew[3]; 64 struct ship *sp, *sq; 65 66 foreachship(sp) { 67 if (*sp->file->captain) 68 continue; 69 if (sp->file->dir == 0) 70 continue; 71 if (sp->file->struck || sp->file->captured != 0) 72 continue; 73 if (!snagged(sp)) 74 continue; 75 crew[0] = sp->specs->crew1 != 0; 76 crew[1] = sp->specs->crew2 != 0; 77 crew[2] = sp->specs->crew3 != 0; 78 foreachship(sq) { 79 if (!Xsnagged2(sp, sq)) 80 continue; 81 if (meleeing(sp, sq)) 82 continue; 83 if (!sq->file->dir 84 || sp->nationality == capship(sq)->nationality) 85 continue; 86 switch (sp->specs->class - sq->specs->class) { 87 case -3: case -4: case -5: 88 if (crew[0]) { 89 /* OBP */ 90 sendbp(sp, sq, crew[0]*100, 0); 91 crew[0] = 0; 92 } else if (crew[1]) { 93 /* OBP */ 94 sendbp(sp, sq, crew[1]*10, 0); 95 crew[1] = 0; 96 } 97 break; 98 case -2: 99 if (crew[0] || crew[1]) { 100 /* OBP */ 101 sendbp(sp, sq, crew[0]*100+crew[1]*10, 102 0); 103 crew[0] = crew[1] = 0; 104 } 105 break; 106 case -1: case 0: case 1: 107 if (crew[0]) { 108 /* OBP */ 109 sendbp(sp, sq, crew[0]*100+crew[1]*10, 110 0); 111 crew[0] = crew[1] = 0; 112 } 113 break; 114 case 2: case 3: case 4: case 5: 115 /* OBP */ 116 sendbp(sp, sq, crew[0]*100+crew[1]*10+crew[2], 117 0); 118 crew[0] = crew[1] = crew[2] = 0; 119 break; 120 } 121 } 122 } 123 } 124 125 static int 126 fightitout(struct ship *from, struct ship *to, int key) 127 { 128 struct ship *fromcap, *tocap; 129 int crewfrom[3], crewto[3], menfrom, mento; 130 int pcto, pcfrom, fromstrength, strengthto, frominjured, toinjured; 131 int topoints; 132 int idx, totalfrom = 0, totalto = 0; 133 int count; 134 char message[60]; 135 136 menfrom = mensent(from, to, crewfrom, &fromcap, &pcfrom, key); 137 mento = mensent(to, from, crewto, &tocap, &pcto, 0); 138 if (fromcap == NULL) 139 fromcap = from; 140 if (tocap == NULL) 141 tocap = to; 142 if (key) { 143 if (!menfrom) { /* if crew surprised */ 144 if (fromcap == from) 145 menfrom = from->specs->crew1 146 + from->specs->crew2 147 + from->specs->crew3; 148 else 149 menfrom = from->file->pcrew; 150 } else { 151 menfrom *= 2; /* DBP's fight at an advantage */ 152 } 153 } 154 fromstrength = menfrom * fromcap->specs->qual; 155 strengthto = mento * tocap->specs->qual; 156 for (count = 0; 157 ((fromstrength < strengthto * 3 && strengthto < fromstrength * 3) 158 || fromstrength == -1) && count < 4; 159 count++) { 160 idx = fromstrength/10; 161 if (idx > 8) 162 idx = 8; 163 toinjured = MT[idx][2 - die() / 3]; 164 totalto += toinjured; 165 idx = strengthto/10; 166 if (idx > 8) 167 idx = 8; 168 frominjured = MT[idx][2 - die() / 3]; 169 totalfrom += frominjured; 170 menfrom -= frominjured; 171 mento -= toinjured; 172 fromstrength = menfrom * fromcap->specs->qual; 173 strengthto = mento * tocap->specs->qual; 174 } 175 if (fromstrength >= strengthto * 3 || count == 4) { 176 unboard(to, from, 0); 177 subtract(from, totalfrom, crewfrom, fromcap, pcfrom); 178 subtract(to, totalto, crewto, tocap, pcto); 179 makesignal(from, "boarders from %s repelled", to); 180 sprintf(message, "killed in melee: %d. %s: %d", 181 totalto, from->shipname, totalfrom); 182 Writestr(W_SIGNAL, to, message); 183 if (key) 184 return 1; 185 } else if (strengthto >= fromstrength * 3) { 186 unboard(from, to, 0); 187 subtract(from, totalfrom, crewfrom, fromcap, pcfrom); 188 subtract(to, totalto, crewto, tocap, pcto); 189 if (key) { 190 if (fromcap != from) 191 Write(W_POINTS, fromcap, 192 fromcap->file->points - 193 from->file->struck 194 ? from->specs->pts 195 : 2 * from->specs->pts, 196 0, 0, 0); 197 198 /* ptr1 points to the shipspec for the ship that was just unboarded. 199 I guess that what is going on here is that the pointer is multiplied 200 or something. */ 201 202 Write(W_CAPTURED, from, to->file->index, 0, 0, 0); 203 topoints = 2 * from->specs->pts + to->file->points; 204 if (from->file->struck) 205 topoints -= from->specs->pts; 206 Write(W_POINTS, to, topoints, 0, 0, 0); 207 mento = crewto[0] ? crewto[0] : crewto[1]; 208 if (mento) { 209 subtract(to, mento, crewto, tocap, pcto); 210 subtract(from, - mento, crewfrom, to, 0); 211 } 212 sprintf(message, "captured by the %s!", 213 to->shipname); 214 Writestr(W_SIGNAL, from, message); 215 sprintf(message, "killed in melee: %d. %s: %d", 216 totalto, from->shipname, totalfrom); 217 Writestr(W_SIGNAL, to, message); 218 mento = 0; 219 return 0; 220 } 221 } 222 return 0; 223 } 224 225 void 226 resolve(void) 227 { 228 int thwart; 229 struct ship *sp, *sq; 230 231 foreachship(sp) { 232 if (sp->file->dir == 0) 233 continue; 234 for (sq = sp + 1; sq < ls; sq++) 235 if (sq->file->dir && meleeing(sp, sq) && 236 meleeing(sq, sp)) 237 fightitout(sp, sq, 0); 238 thwart = 2; 239 foreachship(sq) { 240 if (sq->file->dir && meleeing(sq, sp)) 241 thwart = fightitout(sp, sq, 1); 242 if (!thwart) 243 break; 244 } 245 if (!thwart) { 246 foreachship(sq) { 247 if (sq->file->dir && meleeing(sq, sp)) 248 unboard(sq, sp, 0); 249 unboard(sp, sq, 0); 250 } 251 unboard(sp, sp, 1); 252 } else if (thwart == 2) 253 unboard(sp, sp, 1); 254 } 255 } 256 257 void 258 compcombat(void) 259 { 260 int n; 261 struct ship *sp; 262 struct ship *closest; 263 int crew[3], men = 0, target, temp; 264 int r, guns, ready, load, car; 265 int idx, rakehim, sternrake; 266 int shootat, hit; 267 268 foreachship(sp) { 269 if (sp->file->captain[0] || sp->file->dir == 0) 270 continue; 271 crew[0] = sp->specs->crew1; 272 crew[1] = sp->specs->crew2; 273 crew[2] = sp->specs->crew3; 274 for (n = 0; n < 3; n++) { 275 if (sp->file->OBP[n].turnsent) 276 men += sp->file->OBP[n].mensent; 277 } 278 for (n = 0; n < 3; n++) { 279 if (sp->file->DBP[n].turnsent) 280 men += sp->file->DBP[n].mensent; 281 } 282 if (men) { 283 crew[0] = men/100 ? 0 : crew[0] != 0; 284 crew[1] = (men%100)/10 ? 0 : crew[1] != 0; 285 crew[2] = men%10 ? 0 : crew[2] != 0; 286 } 287 for (r = 0; r < 2; r++) { 288 if (!crew[2]) 289 continue; 290 if (sp->file->struck) 291 continue; 292 if (r) { 293 ready = sp->file->readyR; 294 guns = sp->specs->gunR; 295 car = sp->specs->carR; 296 } else { 297 ready = sp->file->readyL; 298 guns = sp->specs->gunL; 299 car = sp->specs->carL; 300 } 301 if (!guns && !car) 302 continue; 303 if ((ready & R_LOADED) == 0) 304 continue; 305 closest = closestenemy(sp, r ? 'r' : 'l', 0); 306 if (closest == NULL) 307 continue; 308 if (range(closest, sp) > 309 range(sp, closestenemy(sp, r ? 'r' : 'l', 1))) 310 continue; 311 if (closest->file->struck) 312 continue; 313 target = range(sp, closest); 314 if (target > 10) 315 continue; 316 if (!guns && target >= 3) 317 continue; 318 load = L_ROUND; 319 if (target == 1 && sp->file->loadwith == L_GRAPE) 320 load = L_GRAPE; 321 if (target <= 3 && closest->file->FS) 322 load = L_CHAIN; 323 if (target == 1 && load != L_GRAPE) 324 load = L_DOUBLE; 325 if (load > L_CHAIN && target < 6) 326 shootat = HULL; 327 else 328 shootat = RIGGING; 329 rakehim = gunsbear(sp, closest) 330 && !gunsbear(closest, sp); 331 temp = portside(closest, sp, 1) 332 - closest->file->dir + 1; 333 if (temp < 1) 334 temp += 8; 335 if (temp > 8) 336 temp -= 8; 337 sternrake = temp > 4 && temp < 6; 338 idx = guns; 339 if (target < 3) 340 idx += car; 341 idx = (idx - 1) / 3; 342 idx = idx > 8 ? 8 : idx; 343 if (!rakehim) 344 hit = HDT[idx][target-1]; 345 else 346 hit = HDTrake[idx][target-1]; 347 if (rakehim && sternrake) 348 hit++; 349 hit += QUAL[idx][capship(sp)->specs->qual - 1]; 350 for (n = 0; n < 3 && sp->file->captured == 0; n++) { 351 if (!crew[n]) { 352 if (idx <= 5) 353 hit--; 354 else 355 hit -= 2; 356 } 357 } 358 if (ready & R_INITIAL) { 359 if (!r) 360 sp->file->readyL &= ~R_INITIAL; 361 else 362 sp->file->readyR &= ~R_INITIAL; 363 if (idx <= 3) 364 hit++; 365 else 366 hit += 2; 367 } 368 if (sp->file->captured != 0) { 369 if (idx <= 1) 370 hit--; 371 else 372 hit -= 2; 373 } 374 hit += AMMO[idx][load - 1]; 375 temp = sp->specs->class; 376 if ((temp >= 5 || temp == 1) && windspeed == 5) 377 hit--; 378 if (windspeed == 6 && temp == 4) 379 hit -= 2; 380 if (windspeed == 6 && temp <= 3) 381 hit--; 382 if (hit >= 0) { 383 if (load != L_GRAPE) 384 hit = hit > 10 ? 10 : hit; 385 table(shootat, load, hit, closest, sp, die()); 386 } 387 } 388 } 389 } 390 391 int 392 next(void) 393 { 394 if (++turn % 55 == 0) { 395 if (alive) 396 alive = 0; 397 else 398 people = 0; 399 } 400 if (people <= 0 || windspeed == 7) { 401 struct ship *s; 402 struct ship *bestship = NULL; 403 float net, best = 0.0; 404 foreachship(s) { 405 if (*s->file->captain) 406 continue; 407 net = (float)s->file->points / s->specs->pts; 408 if (net > best) { 409 best = net; 410 bestship = s; 411 } 412 } 413 if (best > 0.0) { 414 char *p = getenv("WOTD"); 415 if (p == NULL) { 416 char buf[6] = "Driver"; 417 p = buf; 418 } 419 if (islower(*p)) 420 *p = toupper(*p); 421 strncpy(bestship->file->captain, p, 422 sizeof bestship->file->captain); 423 bestship->file->captain 424 [sizeof bestship->file->captain - 1] = 0; 425 write_log(bestship); 426 } 427 return -1; 428 } 429 Write(W_TURN, SHIP(0), turn, 0, 0, 0); 430 if (turn % 7 == 0 && (die() >= cc->windchange || !windspeed)) { 431 switch (die()) { 432 case 1: 433 winddir = 1; 434 break; 435 case 2: 436 break; 437 case 3: 438 winddir++; 439 break; 440 case 4: 441 winddir--; 442 break; 443 case 5: 444 winddir += 2; 445 break; 446 case 6: 447 winddir -= 2; 448 break; 449 } 450 if (winddir > 8) 451 winddir -= 8; 452 if (winddir < 1) 453 winddir += 8; 454 if (windspeed) 455 switch (die()) { 456 case 1: 457 case 2: 458 windspeed--; 459 break; 460 case 5: 461 case 6: 462 windspeed++; 463 break; 464 } 465 else 466 windspeed++; 467 Write(W_WIND, SHIP(0), winddir, windspeed, 0, 0); 468 } 469 return 0; 470 } 471