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