phaser.c 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386
  1. /* $NetBSD: phaser.c,v 1.9 2003/08/07 09:37:53 agc Exp $ */
  2. /*
  3. * Copyright (c) 1980, 1993
  4. * The Regents of the University of California. All rights reserved.
  5. *
  6. * Redistribution and use in source and binary forms, with or without
  7. * modification, are permitted provided that the following conditions
  8. * are met:
  9. * 1. Redistributions of source code must retain the above copyright
  10. * notice, this list of conditions and the following disclaimer.
  11. * 2. Redistributions in binary form must reproduce the above copyright
  12. * notice, this list of conditions and the following disclaimer in the
  13. * documentation and/or other materials provided with the distribution.
  14. * 3. Neither the name of the University nor the names of its contributors
  15. * may be used to endorse or promote products derived from this software
  16. * without specific prior written permission.
  17. *
  18. * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  19. * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  20. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  21. * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  22. * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  23. * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  24. * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  25. * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  26. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  27. * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  28. * SUCH DAMAGE.
  29. */
  30. #include <sys/cdefs.h>
  31. #ifndef lint
  32. #if 0
  33. static char sccsid[] = "@(#)phaser.c 8.1 (Berkeley) 5/31/93";
  34. #else
  35. __RCSID("$NetBSD: phaser.c,v 1.9 2003/08/07 09:37:53 agc Exp $");
  36. #endif
  37. #endif /* not lint */
  38. #include <stdio.h>
  39. #include <math.h>
  40. #include "trek.h"
  41. #include "getpar.h"
  42. /* factors for phaser hits; see description below */
  43. # define ALPHA 3.0 /* spread */
  44. # define BETA 3.0 /* franf() */
  45. # define GAMMA 0.30 /* cos(angle) */
  46. # define EPSILON 150.0 /* dist ** 2 */
  47. # define OMEGA 10.596 /* overall scaling factor */
  48. /* OMEGA ~= 100 * (ALPHA + 1) * (BETA + 1) / (EPSILON + 1) */
  49. /*
  50. ** Phaser Control
  51. **
  52. ** There are up to NBANKS phaser banks which may be fired
  53. ** simultaneously. There are two modes, "manual" and
  54. ** "automatic". In manual mode, you specify exactly which
  55. ** direction you want each bank to be aimed, the number
  56. ** of units to fire, and the spread angle. In automatic
  57. ** mode, you give only the total number of units to fire.
  58. **
  59. ** The spread is specified as a number between zero and
  60. ** one, with zero being minimum spread and one being maximum
  61. ** spread. You will normally want zero spread, unless your
  62. ** short range scanners are out, in which case you probably
  63. ** don't know exactly where the Klingons are. In that case,
  64. ** you really don't have any choice except to specify a
  65. ** fairly large spread.
  66. **
  67. ** Phasers spread slightly, even if you specify zero spread.
  68. **
  69. ** Uses trace flag 30
  70. */
  71. struct cvntab Matab[] =
  72. {
  73. { "m", "anual", (cmdfun) 1, 0 },
  74. { "a", "utomatic", (cmdfun) 0, 0 },
  75. { NULL, NULL, NULL, 0 }
  76. };
  77. struct banks
  78. {
  79. int units;
  80. double angle;
  81. double spread;
  82. };
  83. /*ARGSUSED*/
  84. void
  85. phaser(v)
  86. int v __attribute__((__unused__));
  87. {
  88. int i;
  89. int j;
  90. struct kling *k;
  91. double dx, dy;
  92. double anglefactor, distfactor;
  93. struct banks *b;
  94. int manual, flag, extra = 0;
  95. int hit;
  96. double tot;
  97. int n;
  98. int hitreqd[NBANKS];
  99. struct banks bank[NBANKS];
  100. const struct cvntab *ptr;
  101. if (Ship.cond == DOCKED) {
  102. printf("Phasers cannot fire through starbase shields\n");
  103. return;
  104. }
  105. if (damaged(PHASER)) {
  106. out(PHASER);
  107. return;
  108. }
  109. if (Ship.shldup) {
  110. printf("Sulu: Captain, we cannot fire through shields.\n");
  111. return;
  112. }
  113. if (Ship.cloaked)
  114. {
  115. printf("Sulu: Captain, surely you must realize that we cannot fire\n");
  116. printf(" phasers with the cloaking device up.\n");
  117. return;
  118. }
  119. /* decide if we want manual or automatic mode */
  120. manual = 0;
  121. if (testnl())
  122. {
  123. if (damaged(COMPUTER))
  124. {
  125. printf("%s", Device[COMPUTER].name);
  126. manual++;
  127. }
  128. else
  129. if (damaged(SRSCAN))
  130. {
  131. printf("%s", Device[SRSCAN].name);
  132. manual++;
  133. }
  134. if (manual)
  135. printf(" damaged, manual mode selected\n");
  136. }
  137. if (!manual)
  138. {
  139. ptr = getcodpar("Manual or automatic", Matab);
  140. manual = (long) ptr->value;
  141. }
  142. if (!manual && damaged(COMPUTER))
  143. {
  144. printf("Computer damaged, manual selected\n");
  145. skiptonl(0);
  146. manual++;
  147. }
  148. /* initialize the bank[] array */
  149. flag = 1;
  150. for (i = 0; i < NBANKS; i++)
  151. bank[i].units = 0;
  152. if (manual)
  153. {
  154. /* collect manual mode statistics */
  155. while (flag)
  156. {
  157. printf("%d units available\n", Ship.energy);
  158. extra = 0;
  159. flag = 0;
  160. for (i = 0; i < NBANKS; i++)
  161. {
  162. b = &bank[i];
  163. printf("\nBank %d:\n", i);
  164. hit = getintpar("units");
  165. if (hit < 0)
  166. return;
  167. if (hit == 0)
  168. break;
  169. extra += hit;
  170. if (extra > Ship.energy)
  171. {
  172. printf("available energy exceeded. ");
  173. skiptonl(0);
  174. flag++;
  175. break;
  176. }
  177. b->units = hit;
  178. hit = getintpar("course");
  179. if (hit < 0 || hit > 360)
  180. return;
  181. b->angle = hit * 0.0174532925;
  182. b->spread = getfltpar("spread");
  183. if (b->spread < 0 || b->spread > 1)
  184. return;
  185. }
  186. Ship.energy -= extra;
  187. }
  188. extra = 0;
  189. }
  190. else
  191. {
  192. /* automatic distribution of power */
  193. if (Etc.nkling <= 0) {
  194. printf("Sulu: But there are no Klingons in this quadrant\n");
  195. return;
  196. }
  197. printf("Phasers locked on target. ");
  198. while (flag)
  199. {
  200. printf("%d units available\n", Ship.energy);
  201. hit = getintpar("Units to fire");
  202. if (hit <= 0)
  203. return;
  204. if (hit > Ship.energy)
  205. {
  206. printf("available energy exceeded. ");
  207. skiptonl(0);
  208. continue;
  209. }
  210. flag = 0;
  211. Ship.energy -= hit;
  212. extra = hit;
  213. n = Etc.nkling;
  214. if (n > NBANKS)
  215. n = NBANKS;
  216. tot = n * (n + 1) / 2;
  217. for (i = 0; i < n; i++)
  218. {
  219. k = &Etc.klingon[i];
  220. b = &bank[i];
  221. distfactor = k->dist;
  222. anglefactor = ALPHA * BETA * OMEGA / (distfactor * distfactor + EPSILON);
  223. anglefactor *= GAMMA;
  224. distfactor = k->power;
  225. distfactor /= anglefactor;
  226. hitreqd[i] = distfactor + 0.5;
  227. dx = Ship.sectx - k->x;
  228. dy = k->y - Ship.secty;
  229. b->angle = atan2(dy, dx);
  230. b->spread = 0.0;
  231. b->units = ((n - i) / tot) * extra;
  232. # ifdef xTRACE
  233. if (Trace)
  234. {
  235. printf("b%d hr%d u%d df%.2f af%.2f\n",
  236. i, hitreqd[i], b->units,
  237. distfactor, anglefactor);
  238. }
  239. # endif
  240. extra -= b->units;
  241. hit = b->units - hitreqd[i];
  242. if (hit > 0)
  243. {
  244. extra += hit;
  245. b->units -= hit;
  246. }
  247. }
  248. /* give out any extra energy we might have around */
  249. if (extra > 0)
  250. {
  251. for (i = 0; i < n; i++)
  252. {
  253. b = &bank[i];
  254. hit = hitreqd[i] - b->units;
  255. if (hit <= 0)
  256. continue;
  257. if (hit >= extra)
  258. {
  259. b->units += extra;
  260. extra = 0;
  261. break;
  262. }
  263. b->units = hitreqd[i];
  264. extra -= hit;
  265. }
  266. if (extra > 0)
  267. printf("%d units overkill\n", extra);
  268. }
  269. }
  270. }
  271. # ifdef xTRACE
  272. if (Trace)
  273. {
  274. for (i = 0; i < NBANKS; i++)
  275. {
  276. b = &bank[i];
  277. printf("b%d u%d", i, b->units);
  278. if (b->units > 0)
  279. printf(" a%.2f s%.2f\n", b->angle, b->spread);
  280. else
  281. printf("\n");
  282. }
  283. }
  284. # endif
  285. /* actually fire the shots */
  286. Move.free = 0;
  287. for (i = 0; i < NBANKS; i++)
  288. {
  289. b = &bank[i];
  290. if (b->units <= 0)
  291. {
  292. continue;
  293. }
  294. printf("\nPhaser bank %d fires:\n", i);
  295. n = Etc.nkling;
  296. k = Etc.klingon;
  297. for (j = 0; j < n; j++)
  298. {
  299. if (b->units <= 0)
  300. break;
  301. /*
  302. ** The formula for hit is as follows:
  303. **
  304. ** zap = OMEGA * [(sigma + ALPHA) * (rho + BETA)]
  305. ** / (dist ** 2 + EPSILON)]
  306. ** * [cos(delta * sigma) + GAMMA]
  307. ** * hit
  308. **
  309. ** where sigma is the spread factor,
  310. ** rho is a random number (0 -> 1),
  311. ** GAMMA is a crud factor for angle (essentially
  312. ** cruds up the spread factor),
  313. ** delta is the difference in radians between the
  314. ** angle you are shooting at and the actual
  315. ** angle of the klingon,
  316. ** ALPHA scales down the significance of sigma,
  317. ** BETA scales down the significance of rho,
  318. ** OMEGA is the magic number which makes everything
  319. ** up to "* hit" between zero and one,
  320. ** dist is the distance to the klingon
  321. ** hit is the number of units in the bank, and
  322. ** zap is the amount of the actual hit.
  323. **
  324. ** Everything up through dist squared should maximize
  325. ** at 1.0, so that the distance factor is never
  326. ** greater than one. Conveniently, cos() is
  327. ** never greater than one, but the same restric-
  328. ** tion applies.
  329. */
  330. distfactor = BETA + franf();
  331. distfactor *= ALPHA + b->spread;
  332. distfactor *= OMEGA;
  333. anglefactor = k->dist;
  334. distfactor /= anglefactor * anglefactor + EPSILON;
  335. distfactor *= b->units;
  336. dx = Ship.sectx - k->x;
  337. dy = k->y - Ship.secty;
  338. anglefactor = atan2(dy, dx) - b->angle;
  339. anglefactor = cos((anglefactor * b->spread) + GAMMA);
  340. if (anglefactor < 0.0)
  341. {
  342. k++;
  343. continue;
  344. }
  345. hit = anglefactor * distfactor + 0.5;
  346. k->power -= hit;
  347. printf("%d unit hit on Klingon", hit);
  348. if (!damaged(SRSCAN))
  349. printf(" at %d,%d", k->x, k->y);
  350. printf("\n");
  351. b->units -= hit;
  352. if (k->power <= 0)
  353. {
  354. killk(k->x, k->y);
  355. continue;
  356. }
  357. k++;
  358. }
  359. }
  360. /* compute overkill */
  361. for (i = 0; i < NBANKS; i++)
  362. extra += bank[i].units;
  363. if (extra > 0)
  364. printf("\n%d units expended on empty space\n", extra);
  365. }