home *** CD-ROM | disk | FTP | other *** search
/ Amiga ACS 1998 #6 / amigaacscoverdisc1998-061998.iso / games / descent / source / main / cntrlcen.c < prev    next >
Text File  |  1998-06-08  |  13KB  |  408 lines

  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.  
  103. #pragma off (unreferenced)
  104. static char rcsid[] = "$Id: cntrlcen.c 2.1 1995/03/21 14:40:25 john Exp $";
  105. #pragma on (unreferenced)
  106.  
  107. #include <stdlib.h>
  108.  
  109. #include "error.h"
  110. #include "mono.h"
  111.  
  112. #include "inferno.h"
  113. #include "cntrlcen.h"
  114. #include "game.h"
  115. #include "laser.h"
  116. #include "gameseq.h"
  117. #include "ai.h"
  118. #include "multi.h"
  119. #include "fuelcen.h"
  120. #include "wall.h"
  121. #include "object.h"
  122. #include "robot.h"
  123.  
  124. vms_vector controlcen_gun_points[MAX_CONTROLCEN_GUNS];
  125. vms_vector controlcen_gun_dirs[MAX_CONTROLCEN_GUNS];
  126. int    N_controlcen_guns;
  127. int    Control_center_been_hit;
  128. int    Control_center_player_been_seen;
  129. int    Control_center_next_fire_time;
  130. int    Control_center_present;
  131.  
  132. vms_vector    Gun_pos[MAX_CONTROLCEN_GUNS], Gun_dir[MAX_CONTROLCEN_GUNS];
  133.  
  134. //    -----------------------------------------------------------------------------
  135. //return the position & orientation of a gun on the control center object 
  136. void calc_controlcen_gun_point(vms_vector *gun_point,vms_vector *gun_dir,object *obj,int gun_num)
  137. {
  138.     vms_matrix m;
  139.  
  140.     Assert(obj->type == OBJ_CNTRLCEN);
  141.     Assert(obj->render_type==RT_POLYOBJ);
  142.  
  143.     Assert(gun_num < N_controlcen_guns);
  144.  
  145.     //instance gun position & orientation
  146.  
  147.     vm_copy_transpose_matrix(&m,&obj->orient);
  148.  
  149.     vm_vec_rotate(gun_point,&controlcen_gun_points[gun_num],&m);
  150.     vm_vec_add2(gun_point,&obj->pos);
  151.     vm_vec_rotate(gun_dir,&controlcen_gun_dirs[gun_num],&m);
  152. }
  153.  
  154. //    -----------------------------------------------------------------------------
  155. //    Look at control center guns, find best one to fire at *objp.
  156. //    Return best gun number (one whose direction dotted with vector to player is largest).
  157. //    If best gun has negative dot, return -1, meaning no gun is good.
  158. int calc_best_gun(int num_guns, vms_vector *gun_pos, vms_vector *gun_dir, vms_vector *objpos)
  159. {
  160.     int    i;
  161.     fix    best_dot;
  162.     int    best_gun;
  163.  
  164.     best_dot = -F1_0*2;
  165.     best_gun = -1;
  166.  
  167.     for (i=0; i<num_guns; i++) {
  168.         fix            dot;
  169.         vms_vector    gun_vec;
  170.  
  171.         vm_vec_sub(&gun_vec, objpos, &gun_pos[i]);
  172.         vm_vec_normalize_quick(&gun_vec);
  173.         dot = vm_vec_dot(&gun_dir[i], &gun_vec);
  174.  
  175.         if (dot > best_dot) {
  176.             best_dot = dot;
  177.             best_gun = i;
  178.         }
  179.     }
  180.  
  181.     Assert(best_gun != -1);        // Contact Mike.  This is impossible.  Or maybe you're getting an unnormalized vector somewhere.
  182.  
  183.     if (best_dot < 0)
  184.         return -1;
  185.     else
  186.         return best_gun;
  187.  
  188. }
  189.  
  190. extern fix Player_time_of_death;        //    object.c
  191.  
  192. int    Dead_controlcen_object_num=-1;
  193.  
  194. //    -----------------------------------------------------------------------------
  195. //    Called every frame.  If control center been destroyed, then actually do something.
  196. void do_controlcen_dead_frame(void)
  197. {
  198.     if (!Control_center_present)
  199.         return;
  200.  
  201.     if ((Dead_controlcen_object_num != -1) && (Fuelcen_seconds_left > 0))
  202.         if (rand() < FrameTime*4)
  203.             create_small_fireball_on_object(&Objects[Dead_controlcen_object_num], F1_0*3, 1);
  204. }
  205.  
  206. //    -----------------------------------------------------------------------------
  207. //    Called when control center gets destroyed.
  208. //    This code is common to whether control center is implicitly imbedded in a boss,
  209. //    or is an object of its own.
  210. //    if objp == NULL that means the boss was the control center and don't set Dead_controlcen_object_num
  211. void do_controlcen_destroyed_stuff(object *objp)
  212. {
  213.     int    i;
  214.  
  215.     // Must toggle walls whether it is a boss or control center.
  216.     for (i=0;i<ControlCenterTriggers.num_links;i++)
  217.         wall_toggle(&Segments[ControlCenterTriggers.seg[i]], ControlCenterTriggers.side[i]); 
  218.  
  219.     // And start the countdown stuff.
  220.     Fuelcen_control_center_destroyed = 1;
  221.  
  222.  
  223.     if (!Control_center_present)
  224.         return;
  225.  
  226.     if (objp != NULL)
  227.         Dead_controlcen_object_num = objp-Objects;
  228.  
  229. }
  230.  
  231. //    -----------------------------------------------------------------------------
  232. //do whatever this thing does in a frame
  233. void do_controlcen_frame(object *obj)
  234. {
  235.     int            best_gun_num;
  236.  
  237.     //    If a boss level, then Control_center_present will be 0.
  238.     if (!Control_center_present)
  239.         return;
  240.  
  241. #ifndef NDEBUG
  242.     if (!Robot_firing_enabled || (Game_suspended & SUSP_ROBOTS))
  243.         return;
  244. #else
  245.     if (!Robot_firing_enabled)
  246.         return;
  247. #endif
  248.  
  249.     if (!(Control_center_been_hit || Control_center_player_been_seen)) {
  250.         if (!(FrameCount % 8)) {        //    Do every so often...
  251.             vms_vector    vec_to_player;
  252.             fix            dist_to_player;
  253.             int            i;
  254.             segment        *segp = &Segments[obj->segnum];
  255.  
  256.             // This is a hack.  Since the control center is not processed by
  257.             // ai_do_frame, it doesn't know to deal with cloaked dudes.  It
  258.             // seems to work in single-player mode because it is actually using
  259.             // the value of Believed_player_position that was set by the last
  260.             // person to go through ai_do_frame.  But since a no-robots game
  261.             // never goes through ai_do_frame, I'm making it so the control
  262.             // center can spot cloaked dudes.  
  263.  
  264.             if (Game_mode & GM_MULTI)
  265.                 Believed_player_pos = Objects[Players[Player_num].objnum].pos;
  266.  
  267.             //    Hack for special control centers which are isolated and not reachable because the
  268.             //    real control center is inside the boss.
  269.             for (i=0; i<MAX_SIDES_PER_SEGMENT; i++)
  270.                 if (segp->children[i] != -1)
  271.                     break;
  272.             if (i == MAX_SIDES_PER_SEGMENT)
  273.                 return;
  274.  
  275.             vm_vec_sub(&vec_to_player, &ConsoleObject->pos, &obj->pos);
  276.             dist_to_player = vm_vec_normalize_quick(&vec_to_player);
  277.             if (dist_to_player < F1_0*200) {
  278.                 Control_center_player_been_seen = player_is_visible_from_object(obj, &obj->pos, 0, &vec_to_player);
  279.                 Control_center_next_fire_time = 0;
  280.             }
  281.         }            
  282.  
  283.         return;
  284.     }
  285.  
  286.     if ((Control_center_next_fire_time < 0) && !(Player_is_dead && (GameTime > Player_time_of_death+F1_0*2))) {
  287.         if (Players[Player_num].flags & PLAYER_FLAGS_CLOAKED)
  288.             best_gun_num = calc_best_gun(N_controlcen_guns, Gun_pos, Gun_dir, &Believed_player_pos);
  289.         else
  290.             best_gun_num = calc_best_gun(N_controlcen_guns, Gun_pos, Gun_dir, &ConsoleObject->pos);
  291.  
  292.         if (best_gun_num != -1) {
  293.             vms_vector    vec_to_goal;
  294.             fix            dist_to_player;
  295.             fix            delta_fire_time;
  296.  
  297.             if (Players[Player_num].flags & PLAYER_FLAGS_CLOAKED) {
  298.                 vm_vec_sub(&vec_to_goal, &Believed_player_pos, &Gun_pos[best_gun_num]);
  299.                 dist_to_player = vm_vec_normalize_quick(&vec_to_goal);
  300.             } else {
  301.                 vm_vec_sub(&vec_to_goal, &ConsoleObject->pos, &Gun_pos[best_gun_num]);
  302.                 dist_to_player = vm_vec_normalize_quick(&vec_to_goal);
  303.             }
  304.  
  305.             if (dist_to_player > F1_0*300)
  306.             {
  307.                 Control_center_been_hit = 0;
  308.                 Control_center_player_been_seen = 0;
  309.                 return;
  310.             }
  311.     
  312.             #ifdef NETWORK
  313.             if (Game_mode & GM_MULTI)
  314.                 multi_send_controlcen_fire(&vec_to_goal, best_gun_num, obj-Objects);    
  315.             #endif
  316.             Laser_create_new_easy( &vec_to_goal, &Gun_pos[best_gun_num], obj-Objects, CONTROLCEN_WEAPON_NUM, 1);
  317.  
  318.             //    1/4 of time, fire another thing, not directly at player, so it might hit him if he's constantly moving.
  319.             if (rand() < 32767/4) {
  320.                 vms_vector    randvec;
  321.  
  322.                 make_random_vector(&randvec);
  323.                 vm_vec_scale_add2(&vec_to_goal, &randvec, F1_0/4);
  324.                 vm_vec_normalize_quick(&vec_to_goal);
  325.                 #ifdef NETWORK
  326.                 if (Game_mode & GM_MULTI)
  327.                     multi_send_controlcen_fire(&vec_to_goal, best_gun_num, obj-Objects);
  328.                 #endif
  329.                 Laser_create_new_easy( &vec_to_goal, &Gun_pos[best_gun_num], obj-Objects, CONTROLCEN_WEAPON_NUM, 1);
  330.             }
  331.  
  332.             delta_fire_time = (NDL - Difficulty_level) * F1_0/4;
  333.             if (Game_mode & GM_MULTI) // slow down rate of fire in multi player
  334.                 delta_fire_time *= 2;
  335.  
  336.             Control_center_next_fire_time = delta_fire_time;
  337.  
  338.         }
  339.     } else
  340.         Control_center_next_fire_time -= FrameTime;
  341.  
  342. }
  343.  
  344. //    -----------------------------------------------------------------------------
  345. //    This must be called at the start of each level.
  346. //    If this level contains a boss and mode != multiplayer, don't do control center stuff.  (Ghost out control center object.)
  347. //    If this level contains a boss and mode == multiplayer, do control center stuff.
  348. void init_controlcen_for_level(void)
  349. {
  350.     int        i;
  351.     object    *objp;
  352.     int        cntrlcen_objnum=-1, boss_objnum=-1;
  353.  
  354.     for (i=0; i<=Highest_object_index; i++) {
  355.         objp = &Objects[i];
  356.         if (objp->type == OBJ_CNTRLCEN)
  357.             if (cntrlcen_objnum != -1)
  358.                 mprintf((1, "Warning: Two or more control centers including %i and %i\n", i, cntrlcen_objnum));
  359.             else
  360.                 cntrlcen_objnum = i;
  361.  
  362.         if ((objp->type == OBJ_ROBOT) && (Robot_info[objp->id].boss_flag)) {
  363. //             mprintf((0, "Found boss robot %d.\n", objp->id));
  364.             if (boss_objnum != -1)
  365.                 mprintf((1, "Warning: Two or more bosses including %i and %i\n", i, boss_objnum));
  366.             else
  367.                 boss_objnum = i;
  368.         }
  369.     }
  370.  
  371. #ifndef NDEBUG
  372.     if (cntrlcen_objnum == -1) {
  373.         mprintf((1, "Warning: No control center.\n"));
  374.         return;
  375.     }
  376.  
  377. #endif
  378.     if ( (boss_objnum != -1) && !((Game_mode & GM_MULTI) && !(Game_mode & GM_MULTI_ROBOTS)) ) {
  379.         if (cntrlcen_objnum != -1) {
  380. //            mprintf((0, "Ghosting control center\n"));
  381.             Objects[cntrlcen_objnum].type = OBJ_GHOST;
  382.             Objects[cntrlcen_objnum].render_type = RT_NONE;
  383.             Control_center_present = 0;
  384.         }
  385.     } else {
  386.         //    Compute all gun positions.
  387.         objp = &Objects[cntrlcen_objnum];
  388.         for (i=0; i<N_controlcen_guns; i++)
  389.             calc_controlcen_gun_point(&Gun_pos[i], &Gun_dir[i], objp, i);
  390.         Control_center_present = 1;
  391.  
  392.         //    Boost control center strength at higher levels.
  393.         if (Current_level_num >= 0)
  394.             objp->shields = F1_0*200 + (F1_0*200/4) * Current_level_num;
  395.         else
  396.             objp->shields = F1_0*200 - Current_level_num*F1_0*100;
  397.     }
  398.  
  399.     //    Say the control center has not yet been hit.
  400.     Control_center_been_hit = 0;
  401.     Control_center_player_been_seen = 0;
  402.     Control_center_next_fire_time = 0;
  403.     
  404.     Dead_controlcen_object_num = -1;
  405. }
  406.  
  407. 
  408.