CNTRLCEN.C 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408
  1. /*
  2. THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX
  3. SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO
  4. END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A
  5. ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS
  6. IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS
  7. SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE
  8. FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE
  9. CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS
  10. AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE.
  11. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED.
  12. */
  13. /*
  14. * $Source: f:/miner/source/main/rcs/cntrlcen.c $
  15. * $Revision: 2.1 $
  16. * $Author: john $
  17. * $Date: 1995/03/21 14:40:25 $
  18. *
  19. * Code for the control center
  20. *
  21. * $Log: cntrlcen.c $
  22. * Revision 2.1 1995/03/21 14:40:25 john
  23. * Ifdef'd out the NETWORK code.
  24. *
  25. * Revision 2.0 1995/02/27 11:31:25 john
  26. * New version 2.0, which has no anonymous unions, builds with
  27. * Watcom 10.0, and doesn't require parsing BITMAPS.TBL.
  28. *
  29. * Revision 1.22 1995/02/11 01:56:14 mike
  30. * robots don't fire cheat.
  31. *
  32. * Revision 1.21 1995/02/05 13:39:39 mike
  33. * fix stupid bug in control center firing timing.
  34. *
  35. * Revision 1.20 1995/02/03 17:41:21 mike
  36. * fix control cen next fire time in multiplayer.
  37. *
  38. * Revision 1.19 1995/01/29 13:46:41 mike
  39. * adapt to new create_small_fireball_on_object prototype.
  40. *
  41. * Revision 1.18 1995/01/18 16:12:13 mike
  42. * Make control center aware of a cloaked playerr when he fires.
  43. *
  44. * Revision 1.17 1995/01/12 12:53:44 rob
  45. * Trying to fix a bug with having cntrlcen in robotarchy games.
  46. *
  47. * Revision 1.16 1994/12/11 12:37:22 mike
  48. * make control center smarter about firing at cloaked player, don't fire through self, though
  49. * it still looks that way due to prioritization problems.
  50. *
  51. * Revision 1.15 1994/12/01 11:34:33 mike
  52. * fix control center shield strength in multiplayer team games.
  53. *
  54. * Revision 1.14 1994/11/30 15:44:29 mike
  55. * make cntrlcen harder at higher levels.
  56. *
  57. * Revision 1.13 1994/11/29 22:26:23 yuan
  58. * Fixed boss bug.
  59. *
  60. * Revision 1.12 1994/11/27 23:12:31 matt
  61. * Made changes for new mprintf calling convention
  62. *
  63. * Revision 1.11 1994/11/23 17:29:38 mike
  64. * deal with peculiarities going between net and regular game on boss level.
  65. *
  66. * Revision 1.10 1994/11/18 18:27:15 rob
  67. * Fixed some bugs with the last version.
  68. *
  69. * Revision 1.9 1994/11/18 17:13:59 mike
  70. * special case handling for level 8.
  71. *
  72. * Revision 1.8 1994/11/15 12:45:28 mike
  73. * don't let cntrlcen know where a cloaked player is.
  74. *
  75. * Revision 1.7 1994/11/08 12:18:37 mike
  76. * small explosions on control center.
  77. *
  78. * Revision 1.6 1994/11/02 17:59:18 rob
  79. * Changed control centers so they can find people in network games.
  80. * Side effect of this is that control centers can find cloaked players.
  81. * (see in-code comments for explanation).
  82. * Also added network hooks so control center shots 'sync up'.
  83. *
  84. * Revision 1.5 1994/10/22 14:13:21 mike
  85. * Make control center stop firing shortly after player dies.
  86. * Fix bug: If play from editor and die, tries to initialize non-control center object.
  87. *
  88. * Revision 1.4 1994/10/20 15:17:30 mike
  89. * Hack for control center inside boss robot.
  90. *
  91. * Revision 1.3 1994/10/20 09:47:46 mike
  92. * lots stuff.
  93. *
  94. * Revision 1.2 1994/10/17 21:35:09 matt
  95. * Added support for new Control Center/Main Reactor
  96. *
  97. * Revision 1.1 1994/10/17 20:24:01 matt
  98. * Initial revision
  99. *
  100. *
  101. */
  102. #pragma off (unreferenced)
  103. static char rcsid[] = "$Id: cntrlcen.c 2.1 1995/03/21 14:40:25 john Exp $";
  104. #pragma on (unreferenced)
  105. #include <stdlib.h>
  106. #include "error.h"
  107. #include "mono.h"
  108. #include "inferno.h"
  109. #include "cntrlcen.h"
  110. #include "game.h"
  111. #include "laser.h"
  112. #include "gameseq.h"
  113. #include "ai.h"
  114. #include "multi.h"
  115. #include "fuelcen.h"
  116. #include "wall.h"
  117. #include "object.h"
  118. #include "robot.h"
  119. vms_vector controlcen_gun_points[MAX_CONTROLCEN_GUNS];
  120. vms_vector controlcen_gun_dirs[MAX_CONTROLCEN_GUNS];
  121. int N_controlcen_guns;
  122. int Control_center_been_hit;
  123. int Control_center_player_been_seen;
  124. int Control_center_next_fire_time;
  125. int Control_center_present;
  126. vms_vector Gun_pos[MAX_CONTROLCEN_GUNS], Gun_dir[MAX_CONTROLCEN_GUNS];
  127. // -----------------------------------------------------------------------------
  128. //return the position & orientation of a gun on the control center object
  129. void calc_controlcen_gun_point(vms_vector *gun_point,vms_vector *gun_dir,object *obj,int gun_num)
  130. {
  131. vms_matrix m;
  132. Assert(obj->type == OBJ_CNTRLCEN);
  133. Assert(obj->render_type==RT_POLYOBJ);
  134. Assert(gun_num < N_controlcen_guns);
  135. //instance gun position & orientation
  136. vm_copy_transpose_matrix(&m,&obj->orient);
  137. vm_vec_rotate(gun_point,&controlcen_gun_points[gun_num],&m);
  138. vm_vec_add2(gun_point,&obj->pos);
  139. vm_vec_rotate(gun_dir,&controlcen_gun_dirs[gun_num],&m);
  140. }
  141. // -----------------------------------------------------------------------------
  142. // Look at control center guns, find best one to fire at *objp.
  143. // Return best gun number (one whose direction dotted with vector to player is largest).
  144. // If best gun has negative dot, return -1, meaning no gun is good.
  145. int calc_best_gun(int num_guns, vms_vector *gun_pos, vms_vector *gun_dir, vms_vector *objpos)
  146. {
  147. int i;
  148. fix best_dot;
  149. int best_gun;
  150. best_dot = -F1_0*2;
  151. best_gun = -1;
  152. for (i=0; i<num_guns; i++) {
  153. fix dot;
  154. vms_vector gun_vec;
  155. vm_vec_sub(&gun_vec, objpos, &gun_pos[i]);
  156. vm_vec_normalize_quick(&gun_vec);
  157. dot = vm_vec_dot(&gun_dir[i], &gun_vec);
  158. if (dot > best_dot) {
  159. best_dot = dot;
  160. best_gun = i;
  161. }
  162. }
  163. Assert(best_gun != -1); // Contact Mike. This is impossible. Or maybe you're getting an unnormalized vector somewhere.
  164. if (best_dot < 0)
  165. return -1;
  166. else
  167. return best_gun;
  168. }
  169. extern fix Player_time_of_death; // object.c
  170. int Dead_controlcen_object_num=-1;
  171. // -----------------------------------------------------------------------------
  172. // Called every frame. If control center been destroyed, then actually do something.
  173. void do_controlcen_dead_frame(void)
  174. {
  175. if (!Control_center_present)
  176. return;
  177. if ((Dead_controlcen_object_num != -1) && (Fuelcen_seconds_left > 0))
  178. if (rand() < FrameTime*4)
  179. create_small_fireball_on_object(&Objects[Dead_controlcen_object_num], F1_0*3, 1);
  180. }
  181. // -----------------------------------------------------------------------------
  182. // Called when control center gets destroyed.
  183. // This code is common to whether control center is implicitly imbedded in a boss,
  184. // or is an object of its own.
  185. // if objp == NULL that means the boss was the control center and don't set Dead_controlcen_object_num
  186. void do_controlcen_destroyed_stuff(object *objp)
  187. {
  188. int i;
  189. // Must toggle walls whether it is a boss or control center.
  190. for (i=0;i<ControlCenterTriggers.num_links;i++)
  191. wall_toggle(&Segments[ControlCenterTriggers.seg[i]], ControlCenterTriggers.side[i]);
  192. // And start the countdown stuff.
  193. Fuelcen_control_center_destroyed = 1;
  194. if (!Control_center_present)
  195. return;
  196. if (objp != NULL)
  197. Dead_controlcen_object_num = objp-Objects;
  198. }
  199. // -----------------------------------------------------------------------------
  200. //do whatever this thing does in a frame
  201. void do_controlcen_frame(object *obj)
  202. {
  203. int best_gun_num;
  204. // If a boss level, then Control_center_present will be 0.
  205. if (!Control_center_present)
  206. return;
  207. #ifndef NDEBUG
  208. if (!Robot_firing_enabled || (Game_suspended & SUSP_ROBOTS))
  209. return;
  210. #else
  211. if (!Robot_firing_enabled)
  212. return;
  213. #endif
  214. if (!(Control_center_been_hit || Control_center_player_been_seen)) {
  215. if (!(FrameCount % 8)) { // Do every so often...
  216. vms_vector vec_to_player;
  217. fix dist_to_player;
  218. int i;
  219. segment *segp = &Segments[obj->segnum];
  220. // This is a hack. Since the control center is not processed by
  221. // ai_do_frame, it doesn't know to deal with cloaked dudes. It
  222. // seems to work in single-player mode because it is actually using
  223. // the value of Believed_player_position that was set by the last
  224. // person to go through ai_do_frame. But since a no-robots game
  225. // never goes through ai_do_frame, I'm making it so the control
  226. // center can spot cloaked dudes.
  227. if (Game_mode & GM_MULTI)
  228. Believed_player_pos = Objects[Players[Player_num].objnum].pos;
  229. // Hack for special control centers which are isolated and not reachable because the
  230. // real control center is inside the boss.
  231. for (i=0; i<MAX_SIDES_PER_SEGMENT; i++)
  232. if (segp->children[i] != -1)
  233. break;
  234. if (i == MAX_SIDES_PER_SEGMENT)
  235. return;
  236. vm_vec_sub(&vec_to_player, &ConsoleObject->pos, &obj->pos);
  237. dist_to_player = vm_vec_normalize_quick(&vec_to_player);
  238. if (dist_to_player < F1_0*200) {
  239. Control_center_player_been_seen = player_is_visible_from_object(obj, &obj->pos, 0, &vec_to_player);
  240. Control_center_next_fire_time = 0;
  241. }
  242. }
  243. return;
  244. }
  245. if ((Control_center_next_fire_time < 0) && !(Player_is_dead && (GameTime > Player_time_of_death+F1_0*2))) {
  246. if (Players[Player_num].flags & PLAYER_FLAGS_CLOAKED)
  247. best_gun_num = calc_best_gun(N_controlcen_guns, Gun_pos, Gun_dir, &Believed_player_pos);
  248. else
  249. best_gun_num = calc_best_gun(N_controlcen_guns, Gun_pos, Gun_dir, &ConsoleObject->pos);
  250. if (best_gun_num != -1) {
  251. vms_vector vec_to_goal;
  252. fix dist_to_player;
  253. fix delta_fire_time;
  254. if (Players[Player_num].flags & PLAYER_FLAGS_CLOAKED) {
  255. vm_vec_sub(&vec_to_goal, &Believed_player_pos, &Gun_pos[best_gun_num]);
  256. dist_to_player = vm_vec_normalize_quick(&vec_to_goal);
  257. } else {
  258. vm_vec_sub(&vec_to_goal, &ConsoleObject->pos, &Gun_pos[best_gun_num]);
  259. dist_to_player = vm_vec_normalize_quick(&vec_to_goal);
  260. }
  261. if (dist_to_player > F1_0*300)
  262. {
  263. Control_center_been_hit = 0;
  264. Control_center_player_been_seen = 0;
  265. return;
  266. }
  267. #ifdef NETWORK
  268. if (Game_mode & GM_MULTI)
  269. multi_send_controlcen_fire(&vec_to_goal, best_gun_num, obj-Objects);
  270. #endif
  271. Laser_create_new_easy( &vec_to_goal, &Gun_pos[best_gun_num], obj-Objects, CONTROLCEN_WEAPON_NUM, 1);
  272. // 1/4 of time, fire another thing, not directly at player, so it might hit him if he's constantly moving.
  273. if (rand() < 32767/4) {
  274. vms_vector randvec;
  275. make_random_vector(&randvec);
  276. vm_vec_scale_add2(&vec_to_goal, &randvec, F1_0/4);
  277. vm_vec_normalize_quick(&vec_to_goal);
  278. #ifdef NETWORK
  279. if (Game_mode & GM_MULTI)
  280. multi_send_controlcen_fire(&vec_to_goal, best_gun_num, obj-Objects);
  281. #endif
  282. Laser_create_new_easy( &vec_to_goal, &Gun_pos[best_gun_num], obj-Objects, CONTROLCEN_WEAPON_NUM, 1);
  283. }
  284. delta_fire_time = (NDL - Difficulty_level) * F1_0/4;
  285. if (Game_mode & GM_MULTI) // slow down rate of fire in multi player
  286. delta_fire_time *= 2;
  287. Control_center_next_fire_time = delta_fire_time;
  288. }
  289. } else
  290. Control_center_next_fire_time -= FrameTime;
  291. }
  292. // -----------------------------------------------------------------------------
  293. // This must be called at the start of each level.
  294. // If this level contains a boss and mode != multiplayer, don't do control center stuff. (Ghost out control center object.)
  295. // If this level contains a boss and mode == multiplayer, do control center stuff.
  296. void init_controlcen_for_level(void)
  297. {
  298. int i;
  299. object *objp;
  300. int cntrlcen_objnum=-1, boss_objnum=-1;
  301. for (i=0; i<=Highest_object_index; i++) {
  302. objp = &Objects[i];
  303. if (objp->type == OBJ_CNTRLCEN)
  304. if (cntrlcen_objnum != -1)
  305. mprintf((1, "Warning: Two or more control centers including %i and %i\n", i, cntrlcen_objnum));
  306. else
  307. cntrlcen_objnum = i;
  308. if ((objp->type == OBJ_ROBOT) && (Robot_info[objp->id].boss_flag)) {
  309. // mprintf((0, "Found boss robot %d.\n", objp->id));
  310. if (boss_objnum != -1)
  311. mprintf((1, "Warning: Two or more bosses including %i and %i\n", i, boss_objnum));
  312. else
  313. boss_objnum = i;
  314. }
  315. }
  316. #ifndef NDEBUG
  317. if (cntrlcen_objnum == -1) {
  318. mprintf((1, "Warning: No control center.\n"));
  319. return;
  320. }
  321. #endif
  322. if ( (boss_objnum != -1) && !((Game_mode & GM_MULTI) && !(Game_mode & GM_MULTI_ROBOTS)) ) {
  323. if (cntrlcen_objnum != -1) {
  324. // mprintf((0, "Ghosting control center\n"));
  325. Objects[cntrlcen_objnum].type = OBJ_GHOST;
  326. Objects[cntrlcen_objnum].render_type = RT_NONE;
  327. Control_center_present = 0;
  328. }
  329. } else {
  330. // Compute all gun positions.
  331. objp = &Objects[cntrlcen_objnum];
  332. for (i=0; i<N_controlcen_guns; i++)
  333. calc_controlcen_gun_point(&Gun_pos[i], &Gun_dir[i], objp, i);
  334. Control_center_present = 1;
  335. // Boost control center strength at higher levels.
  336. if (Current_level_num >= 0)
  337. objp->shields = F1_0*200 + (F1_0*200/4) * Current_level_num;
  338. else
  339. objp->shields = F1_0*200 - Current_level_num*F1_0*100;
  340. }
  341. // Say the control center has not yet been hit.
  342. Control_center_been_hit = 0;
  343. Control_center_player_been_seen = 0;
  344. Control_center_next_fire_time = 0;
  345. Dead_controlcen_object_num = -1;
  346. }
  347.