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