home *** CD-ROM | disk | FTP | other *** search
/ SGI Developer Toolbox 6.1 / SGI Developer Toolbox 6.1 - Disc 4.iso / src / demos / audio / bz / bz.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-08-02  |  125.7 KB  |  5,569 lines

  1. /*
  2.  * Copyright (C) 1992, 1993, 1994, Silicon Graphics, Inc.
  3.  * All Rights Reserved.
  4.  *
  5.  * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics, Inc.;
  6.  * the contents of this file may not be disclosed to third parties, copied or
  7.  * duplicated in any form, in whole or in part, without the prior written
  8.  * permission of Silicon Graphics, Inc.
  9.  *
  10.  * RESTRICTED RIGHTS LEGEND:
  11.  * Use, duplication or disclosure by the Government is subject to restrictions
  12.  * as set forth in subdivision (c)(1)(ii) of the Rights in Technical Data
  13.  * and Computer Software clause at DFARS 252.227-7013, and/or in similar or
  14.  * successor clauses in the FAR, DOD or NASA FAR Supplement. Unpublished -
  15.  * rights reserved under the Copyright Laws of the United States.
  16.  */
  17. /***************************************************************************
  18.  *
  19.  * BZ - Multiplayer tank game.
  20.  *
  21.  * $Id: bz.c,v 1.9 1993/11/29 21:46:00 adele Exp $
  22.  *
  23.  *                    Chris Fouts - Silicon Graphics, Inc.
  24.  *                    October, 1991
  25.  **************************************************************************/
  26. #include <stdio.h>
  27. #include <stdarg.h>
  28. #include <stdlib.h>
  29. #include <string.h>
  30. #include <bstring.h>
  31. #include <sys/types.h>
  32. #include <sys/stat.h>
  33. #include <sys/utsname.h>
  34. #include <fcntl.h>
  35. #include <unistd.h>
  36. #include <device.h>
  37. #include <math.h>
  38. #include <errno.h>
  39. #include <netinet/in.h>
  40. #include <netdb.h>
  41. #include <arpa/inet.h>
  42.  
  43. #include <X11/Intrinsic.h>
  44. #include <X11/StringDefs.h>
  45. #include <Xm/Xm.h>
  46. #include <Xm/BulletinB.h>
  47. #include <X11/Xirisw/GlxMDraw.h>
  48. #include <X11/cursorfont.h>
  49. #include <gl/gl.h>
  50.  
  51. #include "bz.h"
  52. #include "bzobjs.h"
  53. #include "multicast.h"
  54. #if defined( NETDEBUGGER )
  55. #include "bznetdebug.h"
  56. #define BZSCREEN_INTERNAL
  57. #endif /* defined( NETDEBUGGER ) */
  58. #include "bzscreen.h"
  59. #include "bzsound.h"
  60. #include "bzcollide.h"
  61. #include "bzvalidate.h"
  62. #include "bzbase.h"
  63. #include "framerate.h"
  64. #include "bzsolo.h"
  65.  
  66. long    gethostid( void ) ;
  67.  
  68. /* BEGIN PROTOTYPES -S bz.c */
  69. static void     basic_initialization( int *argc, char **argv ) ;
  70. static void     changeTank( Widget w, XEvent *event, String *params,
  71.                     Cardinal *numParams ) ;
  72. static void     changeVolume( Widget w, XEvent *event, String *params,
  73.                     Cardinal *numParams ) ;
  74. static void     choose_tank( int selection )  ;
  75. static void     composeMail( Widget w, XEvent *event, String *params,
  76.                     Cardinal *numParams ) ;
  77. static void     coPilot( Widget w, XEvent *event, String *params,
  78.                     Cardinal *numParams ) ;
  79. static void     detonateMine( Widget w, XEvent *event, String *params,
  80.                     Cardinal *numParams ) ;
  81. static void     do_a_time_step( void )  ;
  82. static void     drawSceneCB( Widget w, XtPointer client_data,
  83.                     XtPointer call_data ) ;
  84. static void     dropFlag( Widget w, XEvent *event, String *params,
  85.                     Cardinal *numParams ) ;
  86. static void     drop_mine( int permanent )  ;
  87. static void     dropMine( Widget w, XEvent *event, String *params,
  88.                     Cardinal *numParams ) ;
  89. static void     dropPermanentMine( Widget w, XEvent *event, String *params,
  90.                     Cardinal *numParams ) ;
  91. static void     fireGuidedShot( Widget w, XEvent *event, String *params,
  92.                     Cardinal *numParams ) ;
  93. static void     fireNormalShot( Widget w, XEvent *event, String *params,
  94.                     Cardinal *numParams ) ;
  95. static int      getview( float x, float y, float heading, unsigned i,
  96.                     int *view, float xref, float yref, float cull_head ) ;
  97. static void     grabFlag( Widget w, XEvent *event, String *params,
  98.                     Cardinal *numParams ) ;
  99. static void     identifyTank( Widget w, XEvent *event, String *params,
  100.                     Cardinal *numParams ) ;
  101. static void     initGlCB( Widget w, XtPointer client_data,
  102.                     XtPointer call_data ) ;
  103. static void     input_message( int init )  ;
  104. static void     installColormapWithOverlay( void )  ;
  105. static void     join_a_team( int team )  ;
  106. static void     joinBlueTeam( Widget w, XEvent *event, String *params,
  107.                     Cardinal *numParams ) ;
  108. static void     joinRedTeam( Widget w, XEvent *event, String *params,
  109.                     Cardinal *numParams ) ;
  110. static void     mouse_interpret( int mouse_x, int mouse_y ) ;
  111. static void     mouseTrack( Widget w, XEvent *event, String *params,
  112.                     Cardinal *numParams ) ;
  113. static void     move_args( int argc, char **argv, int start, int n ) ;
  114. static void     nextCoPilot( Widget w, XEvent *event, String *params,
  115.                     Cardinal *numParams ) ;
  116. static void     next_copilot_view( void )  ;
  117. static void     overlayExposeCB( Widget w, XtPointer client_data,
  118.                     XtPointer call_data ) ;
  119. static void     parse_args( int *argc, char **argv ) ;
  120. static void     pickUpMine( Widget w, XEvent *event, String *params,
  121.                     Cardinal *numParams ) ;
  122. static void     player_dropped_flag( struct BzMember *fumbler )  ;
  123. static void     print_help( float sx, float sy, int prompt ) ;
  124. static void     process_bz_notice( struct BzNotice *input, int team ) ;
  125. static void     quit( Widget w, XEvent *event, String *params,
  126.                     Cardinal *numParams ) ;
  127. static Boolean  randomizerWP( XtPointer ignore )  ;
  128. static void     reinterpret_mouse( void )  ;
  129. static void     resetGun( Widget w, XEvent *event, String *params,
  130.                     Cardinal *numParams ) ;
  131. static void     reset_mouse( void )  ;
  132. static void     selfDestruct( Widget w, XEvent *event, String *params,
  133.                     Cardinal *numParams ) ;
  134. static void     sendPresetMail( Widget w, XEvent *event, String *params,
  135.                     Cardinal *numParams ) ;
  136. static void     sendPresetTeamMail( Widget w, XEvent *event, String *params,
  137.                     Cardinal *numParams ) ;
  138. static void     setName( void )  ;
  139. static void     setTranslations( XtTranslations transTable )  ;
  140. static void     slowDown( Widget w, XEvent *event, String *params,
  141.                     Cardinal *numParams ) ;
  142. static void     stopRandomizing( Widget w, XEvent *event, String *params,
  143.                     Cardinal *numParams ) ;
  144. static void     stopWatch( Widget w, XEvent *event, String *params,
  145.                     Cardinal *numParams ) ;
  146. static void     tankSelect( Widget w, XEvent *event, String *params,
  147.                     Cardinal *numParams ) ;
  148. static Boolean  timeStepWP( XtPointer w )  ;
  149. static void     toggleAudio( Widget w, XEvent *event, String *params,
  150.                     Cardinal *numParams ) ;
  151. static void     toggleBinoculars( Widget w, XEvent *event, String *params,
  152.                     Cardinal *numParams ) ;
  153. static void     toggleLogos( Widget w, XEvent *event, String *params,
  154.                     Cardinal *numParams ) ;
  155. static void     togglePause( Widget w, XEvent *event, String *params,
  156.                     Cardinal *numParams ) ;
  157. static void     toggleShowHelp( Widget w, XEvent *event, String *params,
  158.                     Cardinal *numParams ) ;
  159. static void     toggleShowScore( Widget w, XEvent *event, String *params,
  160.                     Cardinal *numParams ) ;
  161. static void     toggleShowTimings( Widget w, XEvent *event, String *params,
  162.                     Cardinal *numParams ) ;
  163. static void     tran_rot_show( float x, float y, float heading,
  164.                     GL_Object obj ) ;
  165. static void     try_to_grab_flag( int flag_n )  ;
  166. static int      underStaffedTeam( void )  ;
  167. static void     usage( void )  ;
  168. static void     writeMail( Widget w, XEvent *event, String *params,
  169.                     Cardinal *numParams ) ;
  170. static void     writeTeamMail( Widget w, XEvent *event, String *params,
  171.                     Cardinal *numParams ) ;
  172. static void     zoomIn( Widget w, XEvent *event, String *params,
  173.                     Cardinal *numParams ) ;
  174. static void     zoomOut( Widget w, XEvent *event, String *params,
  175.                     Cardinal *numParams ) ;
  176. /* END PROTOTYPES -S bz.c */
  177.  
  178. static char    *version_id = "$Id: bz.c,v 1.9 1993/11/29 21:46:00 adele Exp $" ;
  179.  
  180. /*
  181.  * Various variables for I/O.
  182.  */
  183. static int                    in_fd = -1 ;
  184. static int                    out_fd = -1 ;
  185. static char                    *in_name = NULL ;
  186. static char                    *out_name = NULL ;
  187. static int                    in_addrlen ;
  188. static int                    out_addrlen ;
  189. static struct sockaddr_in    in_addr, out_addr ;
  190. static Boolean                networking = TRUE ;
  191. Packet_Function                read_packets ;
  192. Packet_Function                write_packets ;
  193. Boolean                        solo = FALSE ;
  194. Boolean                        kids_mode = FALSE ;
  195.  
  196.  
  197. /*
  198.  * Screen position variables.
  199.  */
  200. DECLARE( MVIEW ) ;
  201. DECLARE( RADAR ) ;
  202. DECLARE( HEAD ) ;
  203. DECLARE( LOADM ) ;
  204. DECLARE( READY ) ;
  205. DECLARE( SCORE ) ;
  206. DECLARE( LIVES ) ;
  207. DECLARE( LEVEL ) ;
  208. DECLARE( NOPLY ) ;
  209. DECLARE( RIGHT ) ;
  210. DECLARE( LEFTT ) ;
  211. DECLARE( LOGOD ) ;
  212. DECLARE( MESGS ) ;
  213. DECLARE( OUTMS ) ;
  214. DECLARE( GROND ) ;
  215. DECLARE( MINES ) ;
  216. DECLARE( FLAGS ) ;
  217. float            char_width ;
  218. float            char_height ;
  219. float            mv_w ;
  220. float            mv_h ;
  221. float            mv_m ;
  222. static float    aspect_ratio = 1.f ;
  223. long            screen_w, screen_h ;
  224.  
  225.  
  226. /*
  227.  * Mail and messages.
  228.  */
  229. struct BzNotice        mail ;
  230. unsigned int        sending_msg = SENDING_NO_MAIL ;
  231. char                mail_buffer[MAIL_MSG_SIZE] ;
  232. int                    mail_ptr = 0 ;
  233.  
  234. static int            zoom_level = 2 ;
  235. static float        zoom_settings[] = { 1., 1.5, 2., 3., 4., 6., 8. } ;
  236. float                zoom_factor = 2. ;
  237.  
  238.  
  239.  
  240. /*
  241.  * Various timings.
  242.  */
  243. #define    MAX_HIT_COUNT        5        /* half a second */
  244. #define    MAX_HIT_BY_COUNT    ( MAX_DEAD_STATUS - 5 )
  245.  
  246. /*
  247.  * Values for the screen fracturing effect.
  248.  */
  249. struct lineset fracture[30] ;
  250. int fracdest[120] =
  251.     { 300,  0,400,100,  400,100,500,150, 1023,300,875,225,  500,150,475,200,
  252.       875,225,800, 75,  400,100,200,225,  200,225,450,300,  800, 75,850, 25,
  253.       800, 75,700, 50,  450,300,250,375,  838,150,775,175,  875,225,750,275,
  254.       340,340,450,450,  400,400,650,425,  750,275,550, 50,  525,412,550,500,
  255.       660,175,575,300,  575,300,450,250,  200,225,200,350,  575,300,575,360,
  256.       200,300, 75,375,  575,350,500,380,  750,275,650,350,  300,  0,175,125,
  257.       175,125,150,200,  683,325,775,400, 1023,300,950,375,  175,125,125,100,
  258.       200,100,300,125,  950,375,875,350
  259.     } ;
  260.  
  261. /*
  262.  * Identity matrix.
  263.  */
  264. Matrix    id_mat = {
  265.     { 1.0, 0.0, 0.0, 0.0 },
  266.     { 0.0, 1.0, 0.0, 0.0 },
  267.     { 0.0, 0.0, 1.0, 0.0 },
  268.     { 0.0, 0.0, 0.0, 1.0 },
  269.     } ;
  270.  
  271. /*
  272.  * Team related globals.
  273.  */
  274. static long                    teamBonus[N_TEAMS] = { 0, 0, 0 } ;
  275. static char                    time_name[40] ;
  276. static char                    *teamName[] = { "Neutral", "Red", "Blue" } ;
  277. static Boolean                pick_my_team = FALSE ;
  278. Colorindex                    teamColor[N_TEAMS] ;
  279.  
  280. /*
  281.  * Tank velocities.
  282.  */
  283. float            vmax[] = { 28., 35., 28., 42. } ;
  284. float            top_speed = 1.0 ;
  285. float            left_track = 0. ;
  286. float            right_track = 0. ;
  287. float            t_factor ;                    /* turn factor */
  288. static float    left_track_engaged = 0 ;
  289. static float    right_track_engaged = 0 ;
  290. int                tank_body[] = { 0, 1, 0, 2 } ;
  291. float            gm_vel = GM_VEL ;
  292. float            rm_vel = RM_VEL ;
  293.  
  294. #define            FAST_FACTOR        6.0f
  295.  
  296. #define            PERSONAL_BONUS    200
  297.  
  298.  
  299.  
  300. /*
  301.  * Administrative variables.
  302.  */
  303. char            *basename ;
  304. long            over_mode = OVERDRAW ;
  305. int                init_wait = 1 ;
  306. Boolean            picking_tank ;
  307. char            player_name[NAMELEN];
  308. unsigned short    game_key = 0 ;
  309. static int        map_counter = 0 ;
  310. static Window    map_window[3] ;
  311. static int        map_index[3] ;
  312. static unsigned    name_count = 0 ;
  313. extern int        msg_redraw ;
  314. extern int        msg_count ;
  315. extern float    radar_view_angle[3][2] ;
  316. extern float    binocular_radar_view_angle[3][2] ;
  317.  
  318. /*
  319.  * Logo support.
  320.  */
  321. struct BzLogo    logo_packet ;
  322. static char        *logo_file = NULL ;
  323. static int        announce_logo = 1 ;
  324.  
  325. /*
  326.  * Graphics objects.
  327.  */
  328. GL_Object        tank[N_TEAMS][N_TYPES][N_VIEWS];
  329. GL_Object        cube[N_VIEWS];
  330. GL_Object        pyrm[N_VIEWS];
  331. GL_Object        missile[N_VIEWS];
  332. GL_Object        flag[N_FLAGS][N_VIEWS];
  333. GL_Object        null_obj = 0 ;
  334. GL_Object        crosshairs ;
  335. GL_Object        ground ;
  336. GL_Object        sky ;
  337. GL_Object        man_part ;
  338. GL_Object        border ;
  339. GL_Object        mv_black_clear ;
  340. GL_Object        mv_guided_bg ;
  341. GL_Object        mv_normal_bg ;
  342. GL_Object        mv_set_yellow    ;
  343. GL_Object        mv_set_red    ;
  344. GL_Object        mv_set_white ;
  345. GL_Object        lights_on ;
  346. GL_Object        lights_off ;
  347. GL_Object        msl_expl[MEXPL_DURATION] ;
  348. GL_Object        explosion[N_TEAMS][EXPDURATION][N_TYPES] ;
  349. GL_Object        digit[10][2] ;
  350. GL_Object        flag_homes ;
  351. GL_Object        flag_homes_mv ;
  352. GL_Object        tank_logo[MAXPLAYERS] ;
  353. int                tank_logo_side[MAXPLAYERS] ;
  354.  
  355. /*
  356.  * Color values.
  357.  */
  358. Colorindex        black ;
  359. Colorindex        red ;
  360. Colorindex        green ;
  361. Colorindex        yellow ;
  362. Colorindex        white ;
  363. Colorindex        blue ;
  364.  
  365. /*
  366.  * Positions, headings, and velocities of selected objects.
  367.  */
  368. float    obst_x[TOTALOBSTS] ;        /* positions of all objects    */
  369. float    obst_y[TOTALOBSTS] ;
  370. float    flag_x[N_FLAGS] ;            /* positions of all flags */
  371. float    flag_y[N_FLAGS] ;
  372. float    mine_x ;
  373. float    mine_y ;
  374. float    last_msl_x[MAX_ENEMY+1] ;
  375. float    last_msl_y[MAX_ENEMY+1] ;
  376. float    vx[MAX_ENEMY+1] ;            /* velocities of tanks (self and robots) */
  377. float    vy[MAX_ENEMY+1] ;
  378. float    msl_vx[MAX_ENEMY+1] ;        /* velocities of missiles */
  379. float    msl_vy[MAX_ENEMY+1] ;
  380. float    head[TOTALOBSTS] ;            /* headings of objects */
  381.  
  382. /*
  383.  * Sorted view stuff.
  384.  */
  385. float                dst[TOTALOBJS] ;        /* distance from viewer of all obs*/
  386. unsigned            view_order[TOTALOBJS] ;    /* viewing order */
  387. GL_Object            view_object[TOTALOBJS] ;/* view object */
  388. int                    n_view_objs = 0 ;
  389. static Boolean        show_copilot_view = FALSE ;
  390. static unsigned int    copilot_player = 1 ;
  391.  
  392. /*
  393.  * Missile stuff.
  394.  */
  395. Boolean            guiding = FALSE ;
  396. static Boolean    guided_missile = FALSE ;
  397. long            loading_missile = 0 ;
  398. int                missile_duration = 0 ;
  399. Boolean            ricochet = FALSE ;
  400.  
  401. /*
  402.  * Graphics support.
  403.  */
  404. int        screen_mode ;
  405. int        ol_mode = -1 ;
  406. Boolean    use_pups = FALSE ;
  407. Boolean    db_base ;
  408. Boolean    mv_RGB ;
  409. Boolean    use_textures ;
  410.  
  411. unsigned int    lives ;
  412. unsigned int    level ;
  413. unsigned int    practice_level = 0 ;
  414. unsigned int    number_players ;
  415. int                mine_status ;
  416. int                perm_mine = 0 ;
  417. unsigned int    mine_left = 1 ;
  418. int                hit_count ;
  419. Boolean            binoculars = FALSE ;
  420. Boolean            show_logos = TRUE ;
  421. Boolean            randomizer ;
  422. Boolean            showMan ;
  423. Boolean            transparentExplosion ;
  424. Boolean            view_only = FALSE ;
  425. static float    min_cull_angle ;
  426. static float    max_cull_angle ;
  427. static int        no_sfx ;
  428. static int        timeToLive = 0 ;
  429. static short    new_tank_type = 0 ;
  430.  
  431. /*
  432.  * Miscellaneous time things.
  433.  */
  434. float            d_time = 1.0f ;
  435. struct timeval    last_time ;
  436. struct timeval    missile_launch_time ;
  437. struct timeval    missile_explode_time ;
  438. struct timeval    time_of_death ;
  439. struct timeval    hit_time ;
  440. struct timeval    current_time ;
  441. struct timeval    start_up_time ;
  442. struct timeval    deadline[MAXPLAYERS] ;
  443. Boolean            paused = FALSE ;
  444.  
  445. struct BzMember    player[MAXPLAYERS] ;
  446. int                hit_by[MAXPLAYERS] ;
  447. int                activity[MAXPLAYERS] ;
  448.  
  449. /*
  450.  * Flag stuff.
  451.  */
  452. Boolean            never_have_flag = FALSE ;
  453. Boolean            show_flags = FALSE ;
  454. Boolean            red_team_present = FALSE ;
  455. Boolean            blue_team_present = FALSE ;
  456. Boolean            red_flag_held = FALSE ;
  457. Boolean            blue_flag_held = FALSE ;
  458.  
  459. /*
  460.  * Interaction indicators.
  461.  */
  462. static Boolean            need_to_set_tank = FALSE ;
  463. static Boolean            need_to_show_zoom = FALSE ;
  464. static Boolean            need_to_show_out_message = FALSE ;
  465. static Boolean            need_to_show_mine_st = FALSE ;
  466. static Boolean            need_to_show_flag_st = FALSE ;
  467. Boolean                    need_to_show_lives = FALSE ;
  468. Boolean                    need_to_show_score = FALSE ;
  469. Boolean                    need_to_show_msgs = FALSE ;
  470. Boolean                    need_to_show_level = FALSE ;
  471. Boolean                    need_to_show_players = FALSE ;
  472. int                        need_to_show_msgs_vocal = 0 ;
  473. static Boolean            want_to_slow_down = FALSE ;
  474. static Boolean            want_to_see_timings = FALSE ;
  475. static Boolean            want_to_see_score = FALSE ;
  476. static Boolean            want_to_see_help = FALSE ;
  477. static Boolean            want_to_drop_normal_mine = FALSE ;
  478. static Boolean            want_to_drop_permanent_mine = FALSE ;
  479. static Boolean            want_to_pick_mine = FALSE ;
  480. static Boolean            want_to_detonate_mine = FALSE ;
  481. static Boolean            want_to_identify  = FALSE ;
  482. static Boolean            want_to_grab_flag = FALSE ;
  483. static Boolean            want_to_drop_flag = FALSE ;
  484. static Boolean            fire_normal_missile = FALSE ;
  485. static Boolean            fire_guided_missile = FALSE ;
  486. static Boolean            quit_guided_missile = FALSE ;
  487.  
  488.  
  489. /*
  490.  * X stuff.
  491.  */
  492. Widget            toplevel ;
  493. Widget            base_widget ;
  494. Widget            mainview_widget ;
  495. Widget            radar_widget ;
  496. Window            mainview_window ;
  497. Window            base_window ;
  498. Window            radar_window ;
  499. Window            radar_ol_window ;
  500. XtAppContext    appContext ;
  501. Arg                wargs[20] ;
  502. Display            *display ;
  503.  
  504.  
  505. /* The GLX configuration parameter:
  506.  *     Double buffering
  507.  *    RGB mode
  508.  *    Z buffering
  509.  *    nothing else special
  510.  */
  511. static GLXconfig baseGlxConfig[] = {
  512.     { GLX_NORMAL, GLX_DOUBLE, FALSE },
  513.     { 0, 0, 0 }
  514. };
  515.  
  516. static GLXconfig mainviewGlxConfig[] = {
  517.     { GLX_NORMAL, GLX_DOUBLE, TRUE },
  518.     { GLX_NORMAL, GLX_RGB, FALSE },
  519.     { 0, 0, 0 }
  520. };
  521.  
  522. static GLXconfig radarviewGlxConfig[] = {
  523.     { GLX_NORMAL, GLX_DOUBLE, TRUE },
  524.     { GLX_OVERLAY, GLX_BUFSIZE, 2 },        /* Keep in position */
  525.     { 0, 0, 0 }
  526. };
  527.  
  528.  
  529.  
  530. static XtActionsRec actionsTable[] = {
  531.     { "quit",                    quit },
  532.     { "tankSelect",                tankSelect },
  533.     { "changeVolume",            changeVolume },
  534.     { "stopRandomizing",        stopRandomizing },
  535.     { "coPilot",                coPilot },
  536.     { "nextCoPilot",            nextCoPilot },
  537.     { "zoomIn",                    zoomIn },
  538.     { "zoomOut",                zoomOut },
  539.     { "dropMine",                dropMine },
  540.     { "dropPermanentMine",        dropPermanentMine },
  541.     { "detonateMine",            detonateMine },
  542.     { "grabFlag",                grabFlag },
  543.     { "dropFlag",                dropFlag },
  544.     { "pickUpMine",                pickUpMine },
  545.     { "toggleShowTimings",        toggleShowTimings },
  546.     { "toggleShowScore",        toggleShowScore },
  547.     { "toggleShowHelp",            toggleShowHelp },
  548.     { "identifyTank",            identifyTank },
  549.     { "changeTank",                changeTank },
  550.     { "writeMail",                writeMail },
  551.     { "writeTeamMail",            writeTeamMail },
  552.     { "sendPresetMail",            sendPresetMail },
  553.     { "sendPresetTeamMail",        sendPresetTeamMail },
  554.     { "composeMail",            composeMail },
  555.     { "fireNormalShot",            fireNormalShot },
  556.     { "fireGuidedShot",            fireGuidedShot },
  557. #if defined(DEBUG)
  558.     { "selfDestruct",            selfDestruct },
  559.     { "slowDown",                slowDown },
  560.     { "stopWatch",                stopWatch },
  561.     { "resetGun",                resetGun },
  562. #endif /* defined(DEBUG) */
  563.     { "toggleAudio",            toggleAudio },
  564.     { "toggleBinoculars",        toggleBinoculars },
  565.     { "toggleLogos",            toggleLogos },
  566.     { "togglePause",            togglePause },
  567.     { "mouseTrack",                mouseTrack },
  568.     { "joinBlueTeam",            joinBlueTeam },
  569.     { "joinRedTeam",            joinRedTeam },
  570. };
  571.  
  572.  
  573. static char introTranslations[] =
  574.     "<KeyDown>osfCancel:    quit() \n"
  575.     "<KeyDown>:                stopRandomizing() \n"
  576.     "<BtnDown>:                stopRandomizing() \n"
  577.     ;
  578.  
  579. static char introPickTranslations[] =
  580.     "<KeyDown>osfCancel:    quit() \n"
  581.     "<KeyDown>1:            tankSelect(1) \n"
  582.     "<KeyDown>2:            tankSelect(2) \n"
  583.     "<KeyDown>3:            tankSelect(3) \n"
  584.     "<KeyDown>4:            tankSelect(4) \n"
  585.     ;
  586.  
  587. static char *deadTranslations ;
  588.  
  589. static char soloDeadTranslations[] =
  590.     "<KeyDown>osfCancel:    quit() \n"
  591.     "<KeyDown>osfUp:        changeVolume(1) \n"
  592.     "<KeyDown>osfDown:        changeVolume(0) \n"
  593.     "<KeyDown>a:            zoomOut() \n"
  594.     "Shift<KeyDown>p:        togglePause() \n"
  595.     "Shift<KeyDown>z:        zoomOut() \n"
  596.     "<KeyDown>z:            zoomIn() \n"
  597.     ;
  598.  
  599. static char netDeadTranslations[] =
  600.     "<KeyDown>osfCancel:    quit() \n"
  601.     "<KeyDown>osfUp:        changeVolume(1) \n"
  602.     "<KeyDown>osfDown:        changeVolume(0) \n"
  603.     "<KeyDown>a:            zoomOut() \n"
  604.     "<KeyDown>b:            joinBlueTeam() \n"
  605.     "<KeyDown>c:            changeTank() \n"
  606.     "<KeyDown>m:            writeMail() \n"
  607.     "<KeyDown>r:            joinRedTeam() \n"
  608.     "<KeyDown>t:            writeTeamMail() \n"
  609.     "Shift<KeyDown>z:        zoomOut() \n"
  610.     "<KeyDown>z:            zoomIn() \n"
  611.     "Shift<KeyDown>1:        sendPresetTeamMail(1) \n"
  612.     "Shift<KeyDown>2:        sendPresetTeamMail(2) \n"
  613.     "Shift<KeyDown>3:        sendPresetTeamMail(3) \n"
  614.     "Shift<KeyDown>4:        sendPresetTeamMail(4) \n"
  615.     "Shift<KeyDown>5:        sendPresetTeamMail(5) \n"
  616.     "<KeyDown>1:            sendPresetMail(1) \n"
  617.     "<KeyDown>2:            sendPresetMail(2) \n"
  618.     "<KeyDown>3:            sendPresetMail(3) \n"
  619.     "<KeyDown>4:            sendPresetMail(4) \n"
  620.     "<KeyDown>5:            sendPresetMail(5) \n"
  621.     ;
  622.  
  623. static char deadMailTranslations[] =
  624.     "<KeyDown>osfCancel:    quit() \n"
  625.     "<KeyDown>osfUp:        changeVolume(1) \n"
  626.     "<KeyDown>osfDown:        changeVolume(0) \n"
  627.     "<KeyDown>:                composeMail() \n"
  628.     ;
  629.  
  630. static char liveMailTranslations[] =
  631.     "<KeyDown>osfCancel:    quit() \n"
  632.     "<KeyDown>osfUp:        changeVolume(1) \n"
  633.     "<KeyDown>osfDown:        changeVolume(0) \n"
  634.     "<Btn1Down>:            fireNormalShot() \n"
  635.     "<Btn2Down>:            fireGuidedShot() \n"
  636.     "<Motion>:                mouseTrack() \n"
  637.     "<Btn3Down>:            identifyTank() \n"
  638.     "<KeyDown>:                composeMail() \n"
  639.     ;
  640.  
  641. static char *mainTranslations ;
  642.  
  643. static char netMainTranslations[] =
  644. #if defined(DEBUG)
  645.     "<KeyDown>space:        slowDown() \n"
  646.     "Ctrl Alt<KeyDown>b:    selfDestruct() \n"
  647.     "<KeyDown>w:            stopWatch() \n"
  648.     "<KeyDown>r:            resetGun() \n"
  649. #endif /* defined(DEBUG) */
  650.     "<KeyDown>osfUp:        changeVolume(1) \n"
  651.     "<KeyDown>osfDown:        changeVolume(0) \n"
  652.     "<KeyDown>?:            toggleShowTimings() \n"
  653.     "<KeyDown>osfCancel:    quit() \n"
  654.     "<Btn1Down>:            fireNormalShot() \n"
  655.     "<Btn2Down>:            fireGuidedShot() \n"
  656.     "<Motion>:                mouseTrack() \n"
  657.     "<Btn3Down>:            identifyTank() \n"
  658.     "<KeyDown>a:            zoomOut() \n"
  659.     "<KeyDown>b:            toggleBinoculars() \n"
  660.     "Shift<KeyDown>d:        dropPermanentMine() \n"
  661.     "<KeyDown>c:            dropFlag() \n"
  662.     "<KeyDown>d:            dropMine() \n"
  663.     "Shift<KeyDown>f:        dropFlag() \n"
  664.     "<KeyDown>f:            grabFlag() \n"
  665.     "<KeyDown>h:            toggleShowHelp() \n"
  666.     "<KeyDown>l:            toggleLogos() \n"
  667.     "<KeyDown>m:            writeMail() \n"
  668.     "Shift<KeyDown>p:        togglePause() \n"
  669.     "<KeyDown>p:            pickUpMine() \n"
  670.     "Shift<KeyDown>s:        toggleAudio() \n"
  671.     "<KeyDown>s:            toggleShowScore() \n"
  672.     "<KeyDown>t:            writeTeamMail() \n"
  673.     "<KeyDown>x:            detonateMine() \n"
  674.     "Shift<KeyDown>z:        zoomOut() \n"
  675.     "<KeyDown>z:            zoomIn() \n"
  676.     "Shift<KeyDown>1:        sendPresetTeamMail(1) \n"
  677.     "Shift<KeyDown>2:        sendPresetTeamMail(2) \n"
  678.     "Shift<KeyDown>3:        sendPresetTeamMail(3) \n"
  679.     "Shift<KeyDown>4:        sendPresetTeamMail(4) \n"
  680.     "Shift<KeyDown>5:        sendPresetTeamMail(5) \n"
  681.     "<KeyDown>1:            sendPresetMail(1) \n"
  682.     "<KeyDown>2:            sendPresetMail(2) \n"
  683.     "<KeyDown>3:            sendPresetMail(3) \n"
  684.     "<KeyDown>4:            sendPresetMail(4) \n"
  685.     "<KeyDown>5:            sendPresetMail(5) \n"
  686.     ;
  687.  
  688.  
  689. static char viewonlyTranslations[] =
  690. #if defined(DEBUG)
  691.     "<KeyDown>space:        slowDown() \n"
  692.     "Ctrl Alt<KeyDown>b:    selfDestruct() \n"
  693.     "<KeyDown>w:            stopWatch() \n"
  694. #endif /* defined(DEBUG) */
  695.     "<KeyDown>osfUp:        changeVolume(1) \n"
  696.     "<KeyDown>osfDown:        changeVolume(0) \n"
  697.     "<KeyDown>?:            toggleShowTimings() \n"
  698.     "<KeyDown>osfCancel:    quit() \n"
  699.     "<Motion>:                mouseTrack() \n"
  700.     "<Btn1Down>:            identifyTank() \n"
  701.     "<Btn2Down>:            identifyTank() \n"
  702.     "<Btn3Down>:            identifyTank() \n"
  703.     "<KeyDown>a:            zoomOut() \n"
  704.     "<KeyDown>b:            toggleBinoculars() \n"
  705.     "<KeyDown>c:            coPilot() \n"
  706.     "<KeyDown>l:            toggleLogos() \n"
  707.     "Shift<KeyDown>s:        toggleAudio() \n"
  708.     "<KeyDown>s:            toggleShowScore() \n"
  709.     "<KeyDown>h:            toggleShowHelp() \n"
  710.     "<KeyDown>n:            nextCoPilot() \n"
  711.     "Shift<KeyDown>z:        zoomOut() \n"
  712.     "<KeyDown>z:            zoomIn() \n"
  713.     ;
  714.  
  715.  
  716. static XtTranslations introTransTable ;
  717. static XtTranslations introPickTransTable ;
  718. static XtTranslations deadTransTable ;
  719. static XtTranslations deadMailTransTable ;
  720. static XtTranslations liveMailTransTable ;
  721. static XtTranslations mainTransTable ;
  722.  
  723.  
  724. static String    fallbacks[] = {
  725.         "*fontList:                -*-helvetica-bold-r-normal--14-*",
  726.         "*cursorForeground:        yellow",
  727.         "*cursorBackground:        black",
  728.         "*cursor:                diamond_cross",
  729.         "*audio:                TRUE",
  730.         "*keyboardFocusPolicy:    pointer",
  731.         "*mwmDecorations:        0",
  732.         "*geometry:                +0+0",
  733.         NULL
  734.         } ;
  735.  
  736. typedef    struct    {
  737.         Pixel        cursorForeground ;
  738.         Pixel        cursorBackground ;
  739.         Cursor        cursor ;
  740.         Boolean        mvRGBmode ;
  741.         Boolean        audio ;
  742.         Boolean        showMan ;
  743.         Boolean        useTextures ;
  744.         int            initialVolume ;
  745.         int            ttl ;
  746.         char        *identifier ;
  747.         char        *logoFile ;
  748.         char        *message1 ;
  749.         char        *message2 ;
  750.         char        *message3 ;
  751.         char        *message4 ;
  752.         char        *message5 ;
  753.         } AppData, *AppDataPtr ;
  754.  
  755. AppData                AppRes ;
  756.  
  757. static XtResource    resources[] = {
  758.         {    "cursorForeground",        "CursorForeground",     XtRPixel,
  759.             sizeof(Pixel),            XtOffset( AppDataPtr, cursorForeground ),
  760.             XtRString,                "Red"    },
  761.         {    "cursorBackground",        "CursorBackground",     XtRPixel,
  762.             sizeof(Pixel),            XtOffset( AppDataPtr, cursorBackground ),
  763.             XtRString,                "White"    },
  764.         {    "cursor",                "Cursor",                 XtRCursor,
  765.             sizeof(Cursor),            XtOffset( AppDataPtr, cursor ),
  766.             XtRString,                "diamond_cross"    },
  767.         {    "mvRGBmode",            "MvRGBmode",             XtRBoolean,
  768.             sizeof(Boolean),        XtOffset( AppDataPtr, mvRGBmode ),
  769.             XtRString,                "True"    },
  770.         {    "useTextures",            "UseTextures",             XtRBoolean,
  771.             sizeof(Boolean),        XtOffset( AppDataPtr, useTextures ),
  772.             XtRString,                "True"    },
  773.         {    "audio",                "Audio",                 XtRBoolean,
  774.             sizeof(Boolean),        XtOffset( AppDataPtr, audio ),
  775.             XtRString,                "True"    },
  776.         {    "showMan",                "ShowMan",                 XtRBoolean,
  777.             sizeof(Boolean),        XtOffset( AppDataPtr, showMan ),
  778.             XtRString,                "True"    },
  779.         {    "volume",                "Volume",                 XtRInt,
  780.             sizeof(int),            XtOffset( AppDataPtr, initialVolume ),
  781.             XtRString,                "-1"    },
  782.         {    "ttl",                    "Ttl",                     XtRInt,
  783.             sizeof(int),            XtOffset( AppDataPtr, ttl ),
  784.             XtRString,                "8"    },
  785.         {    "identifier",            "Identifier",             XtRString,
  786.             sizeof(char *),            XtOffset( AppDataPtr, identifier ),
  787.             XtRString,                ""    },
  788.         {    "logoFile",                "LogoFile",             XtRString,
  789.             sizeof(char *),            XtOffset( AppDataPtr, logoFile ),
  790.             XtRString,                ""    },
  791.         {    "message1",                "Message1",             XtRString,
  792.             sizeof(char *),            XtOffset( AppDataPtr, message1 ),
  793.             XtRString,                ""    },
  794.         {    "message2",                "Message2",             XtRString,
  795.             sizeof(char *),            XtOffset( AppDataPtr, message2 ),
  796.             XtRString,                ""    },
  797.         {    "message3",                "Message3",             XtRString,
  798.             sizeof(char *),            XtOffset( AppDataPtr, message3 ),
  799.             XtRString,                ""    },
  800.         {    "message4",                "Message4",             XtRString,
  801.             sizeof(char *),            XtOffset( AppDataPtr, message4 ),
  802.             XtRString,                ""    },
  803.         {    "message5",                "Message5",             XtRString,
  804.             sizeof(char *),            XtOffset( AppDataPtr, message5 ),
  805.             XtRString,                ""    },
  806.         } ;
  807.  
  808.  
  809.  
  810. /*------------------------------------------------------------------------------
  811.  * MAIN routine.  Initialize, set up the windows, and fall into X main loop.
  812.  *----------------------------------------------------------------------------*/
  813. int main(
  814.     int     argc,
  815.     char **argv
  816.     )
  817. {
  818.     int        n ;
  819.     Widget    bb ;
  820.  
  821.     basic_initialization( &argc, argv ) ;
  822.  
  823. #if !defined( NETDEBUGGER )
  824. #if defined( SVR3 )
  825.     toplevel = XtAppInitialize( &appContext, "Bz", NULL, 0,
  826.                 (unsigned int *)&argc, argv, fallbacks, NULL, 0 ) ;
  827. #else
  828.     toplevel = XtAppInitialize( &appContext, "Bz", NULL, 0, &argc, argv,
  829.                 fallbacks, NULL, 0 ) ;
  830. #endif /* SVR3 */
  831. #endif /* !defined( NETDEBUGGER ) */
  832.  
  833.     if( argc > 1 ) {
  834.         usage() ;
  835.         }
  836.  
  837. #if !defined( NETDEBUGGER )
  838.     if( !XmIsMotifWMRunning( toplevel ) ) {
  839.         fprintf( stderr, "%s:  No supported window manager (mwm or 4Dwm) is ",
  840.                  "running.  Results are unpredictable.\n", basename ) ;
  841.         }
  842.  
  843.     n = 0 ;
  844.     XtSetArg( wargs[n], XmNmwmDecorations, 0 ) ; n++ ;
  845.     XtSetArg( wargs[n], XmNx, 0 ) ; n++ ;
  846.     XtSetArg( wargs[n], XmNy, 0 ) ; n++ ;
  847.     XtSetArg( wargs[n], XtNborderWidth, 0 ) ; n++ ;
  848.     XtSetValues( toplevel, wargs, n ) ;
  849.     display = XtDisplay( toplevel ) ;
  850.  
  851.     XtGetApplicationResources( toplevel, (XtPointer)&AppRes, resources,
  852.         XtNumber( resources ), NULL, 0 ) ;
  853.  
  854.     if( mv_RGB ) {
  855.         mv_RGB = AppRes.mvRGBmode ;
  856.         }
  857.  
  858.     if( use_textures ) {
  859.         use_textures = AppRes.useTextures ;
  860.         }
  861.  
  862.     if( AppRes.audio == FALSE ) {
  863.         toggle_sound() ;
  864.         }
  865.     else {
  866.         set_volume( AppRes.initialVolume ) ;
  867.         }
  868.  
  869.     showMan = ( kids_mode ) ? FALSE : AppRes.showMan ;
  870.  
  871.     if( timeToLive == 0 ) {
  872.         timeToLive = AppRes.ttl ;
  873.         }
  874.  
  875.     setName() ;
  876.  
  877.     XtAppAddActions( appContext, actionsTable, XtNumber(actionsTable) ) ;
  878.  
  879.     introTransTable     = XtParseTranslationTable( introTranslations ) ;
  880.     introPickTransTable = XtParseTranslationTable( introPickTranslations ) ;
  881.     deadTransTable      = XtParseTranslationTable( deadTranslations ) ;
  882.     deadMailTransTable  = XtParseTranslationTable( deadMailTranslations ) ;
  883.     liveMailTransTable  = XtParseTranslationTable( liveMailTranslations ) ;
  884.     mainTransTable      = XtParseTranslationTable( mainTranslations ) ;
  885.  
  886.     /* if using pups, modify the config parameter */
  887.     if( use_pups ) {
  888.     radarviewGlxConfig[1].buffer = GLX_POPUP;
  889.     radarviewGlxConfig[1].arg = getgdesc( GD_BITS_PUP_SNG_CMODE ) ;
  890.     }
  891.     else {
  892.     radarviewGlxConfig[1].arg = getgdesc( GD_BITS_OVER_SNG_CMODE ) ;
  893.     }
  894.  
  895.     baseGlxConfig[0].arg = db_base ;
  896.  
  897.     n = 0 ;
  898.     XtSetArg( wargs[n], XmNx, 0 ) ; n++ ;
  899.     XtSetArg( wargs[n], XmNy, 0 ) ; n++ ;
  900.     XtSetArg( wargs[n], XmNwidth, screen_w ) ; n++ ;
  901.     XtSetArg( wargs[n], XmNheight, screen_h ) ; n++ ;
  902.     XtSetArg( wargs[n], XmNmarginHeight, 0 ) ; n++ ;
  903.     XtSetArg( wargs[n], XmNmarginWidth, 0 ) ; n++ ;
  904.     bb = XtCreateManagedWidget( "bboard", xmBulletinBoardWidgetClass,
  905.                                 toplevel, wargs, n ) ;
  906.  
  907.     n = 0 ;
  908.     XtSetArg( wargs[n], XmNx, 0 ) ; n++ ;
  909.     XtSetArg( wargs[n], XmNy, 0 ) ; n++ ;
  910.     XtSetArg( wargs[n], XmNwidth, screen_w ) ; n++ ;
  911.     XtSetArg( wargs[n], XmNheight, screen_h ) ; n++ ;
  912.     XtSetArg( wargs[n], GlxNglxConfig, baseGlxConfig ) ; n++ ;
  913.     base_widget = XtCreateManagedWidget( "base", glxMDrawWidgetClass,
  914.                         bb, wargs, n ) ;
  915.     XtAddCallback( base_widget, GlxNexposeCallback, drawBaseCB, 0 ) ;
  916.     XtAddCallback( base_widget, GlxNginitCallback, initBaseGlCB, 0 ) ;
  917.     n = 4 ;
  918.     XtSetValues( base_widget, wargs, n ) ;
  919.  
  920.     mainviewGlxConfig[1].arg = mv_RGB ;
  921.     n = 0 ;
  922.     XtSetArg( wargs[n], XmNx, VPMVIEW_L ) ; n++ ;
  923.     XtSetArg( wargs[n], XmNy, screen_h - VPMVIEW_T - 1 ) ; n++ ;
  924.     XtSetArg( wargs[n], XmNwidth, VPMVIEW_R - VPMVIEW_L + 1 ) ; n++ ;
  925.     XtSetArg( wargs[n], XmNheight, VPMVIEW_T - VPMVIEW_B + 1 ) ; n++ ;
  926.     XtSetArg( wargs[n], GlxNglxConfig, mainviewGlxConfig ) ; n++ ;
  927.     mainview_widget = XtCreateManagedWidget( "mainview", glxMDrawWidgetClass,
  928.                         bb, wargs, n ) ;
  929.     XtAddCallback( mainview_widget, GlxNexposeCallback, drawSceneCB, 0 ) ;
  930.     XtAddCallback( mainview_widget, GlxNginitCallback, initGlCB, 0 ) ;
  931.     n = 4 ;
  932.     XtSetValues( mainview_widget, wargs, n ) ;
  933.     mv_RGB = mainviewGlxConfig[1].arg ;
  934.     if( !mv_RGB ) {
  935.         transparentExplosion = FALSE ;
  936.         use_textures = FALSE ;
  937.         }
  938.  
  939.     n = 0 ;
  940.     XtSetArg( wargs[n], XmNx, VPRADAR_L ) ; n++ ;
  941.     XtSetArg( wargs[n], XmNy, screen_h - VPRADAR_T - 1 ) ; n++ ;
  942.     XtSetArg( wargs[n], XmNwidth, VPRADAR_R - VPRADAR_L + 1 ) ; n++ ;
  943.     XtSetArg( wargs[n], XmNheight, VPRADAR_T - VPRADAR_B + 1 ) ; n++ ;
  944.     if( use_pups ) {
  945.         XtSetArg( wargs[n], GlxNusePopup, TRUE); n++;
  946.         }
  947.     else {
  948.         XtSetArg( wargs[n], GlxNuseOverlay, TRUE ) ; n++ ;
  949.         }
  950.     XtSetArg( wargs[n], GlxNglxConfig, radarviewGlxConfig ) ; n++ ;
  951.     radar_widget = XtCreateManagedWidget( "radar", glxMDrawWidgetClass,
  952.                         bb, wargs, n ) ;
  953.     XtAddCallback( radar_widget, GlxNexposeCallback, drawRadarCB, 0 ) ;
  954.     XtAddCallback( radar_widget,
  955.           ( use_pups ) ? GlxNpopupExposeCallback : GlxNoverlayExposeCallback,
  956.           overlayExposeCB, 0);
  957.     XtAddCallback( radar_widget, GlxNginitCallback, initRadarGlCB, 0 ) ;
  958.     n = 4 ;
  959.     XtSetValues( radar_widget, wargs, n ) ;
  960.  
  961.     setTranslations( introTransTable ) ;
  962.  
  963.     picking_tank = TRUE ;
  964.     screen_mode = INTRO_PICK_SCREEN ;
  965. #endif /* !defined( NETDEBUGGER ) */
  966.  
  967.     init_com();
  968.     if( solo ) {
  969.         set_frame_rate( 2 * DEFAULT_FRAME_RATE ) ;
  970.         }
  971.     else {
  972.         set_frame_rate( DEFAULT_FRAME_RATE ) ;
  973.         }
  974.  
  975. #if !defined( NETDEBUGGER )
  976.     XtRealizeWidget( toplevel ) ;
  977.     installColormapWithOverlay() ;
  978.     change_cursor() ;
  979.     XtAppMainLoop( appContext ) ;
  980.  
  981.     return( 0 ) ;
  982. #else
  983.     start_time( ¤t_time ) ;
  984.     init_census_packet( player[SELF].id ) ;
  985.  
  986.     while( 1 ) {
  987.         do_a_time_step() ;
  988.         }
  989. #endif /* !defined( NETDEBUGGER ) */
  990. }
  991.  
  992.  
  993.  
  994. /*------------------------------------------------------------------------------
  995.  * Work process that gets called as soon as all input has been processed.
  996.  *----------------------------------------------------------------------------*/
  997. static Boolean timeStepWP(
  998.     XtPointer w
  999.     )
  1000. {
  1001.     do_a_time_step() ;
  1002.     return( FALSE ) ;
  1003. }
  1004.  
  1005.  
  1006.  
  1007. /*------------------------------------------------------------------------------
  1008.  * Returns the team with the least number of players (red or blue).
  1009.  *----------------------------------------------------------------------------*/
  1010. static int underStaffedTeam( void )
  1011. {
  1012.     int    i ;
  1013.     int    red_players = 0 ;
  1014.     int    blue_players = 0 ;
  1015.  
  1016.     for( i = ENEMY ; i < number_players ; i++ ) {
  1017.         if( player[i].team == RED_TEAM )
  1018.             red_players++ ;
  1019.         else if( player[i].team == BLUE_TEAM )
  1020.             blue_players++ ;
  1021.         }
  1022.  
  1023.     if( red_players < blue_players )
  1024.         return( RED_TEAM ) ;
  1025.     else if( red_players > blue_players )
  1026.         return( BLUE_TEAM ) ;
  1027.     else
  1028.         return( rand() % 2 ? RED_TEAM : BLUE_TEAM ) ;
  1029. }
  1030.  
  1031.  
  1032.  
  1033. /*------------------------------------------------------------------------------
  1034.  * Master loop.
  1035.  *----------------------------------------------------------------------------*/
  1036. static void do_a_time_step( void )
  1037. {
  1038.     int                        new_life = 0 ;
  1039.     unsigned                enemy_id ;
  1040.     long                    status ;
  1041.     struct timeval            this_time ;
  1042.     static float            total_time = 0.f ;
  1043.     static int                nframes = 0 ;
  1044.  
  1045.     d_time = pace_frame( ¤t_time ) ;
  1046.  
  1047.     GLXwinset( display, base_window ) ;
  1048.  
  1049.     if( paused ) {
  1050.         if( need_to_show_msgs ) {
  1051.             show_msgs( need_to_show_msgs_vocal, msg_redraw ) ;
  1052.             need_to_show_msgs = FALSE ;
  1053.             msg_redraw = 0 ;
  1054.             }
  1055.         if( check_pause() )
  1056.             sfx( SFX_PAUSE_REMINDER ) ;
  1057.         return ;
  1058.         }
  1059.  
  1060. #if !defined( NETDEBUGGER )
  1061.     if( want_to_see_timings ) {
  1062.         total_time += d_time ;
  1063.         nframes++ ;
  1064.         if( total_time >= 1.0f ) {
  1065.             post_new_message( 0, 0, "%d frames in %.1f secs.", nframes,
  1066.                 total_time ) ;
  1067.             total_time = 0.0f ;
  1068.             nframes = 0 ;
  1069.             }
  1070.         }
  1071.  
  1072.     if( name_count < NAME_CHECK_LIMIT ) {
  1073.         if( ++name_count == NAME_CHECK_LIMIT )
  1074.             check_name();
  1075.         }
  1076.  
  1077.     if( IS_ALIVE( player[SELF] ) ) {
  1078.         player[SELF].status = ALIVE_STATUS ;
  1079.         act_on_input();
  1080.         }
  1081.  
  1082.     move_em() ;
  1083.  
  1084.     if( !show_copilot_view )
  1085.         collide() ;
  1086.  
  1087.     write_packets() ;
  1088.     read_packets() ;
  1089.  
  1090.     if( announce_logo ) {
  1091.         announce_logo = 0 ;
  1092.         if( tank_logo[0] != null_obj ) {
  1093.             /*
  1094.              * Send out logo packet.
  1095.              */
  1096.             logo_packet.bz_id = BZLOGO_00 ;
  1097.             logo_packet.id = player[SELF].id ;
  1098.             send_out( &logo_packet, sizeof( logo_packet ) ) ;
  1099.             }
  1100.         }
  1101.  
  1102.     if( view_only && show_copilot_view ) {
  1103.         player[SELF].x = player[copilot_player].x ;
  1104.         player[SELF].y = player[copilot_player].y ;
  1105.         player[SELF].head = player[copilot_player].head ;
  1106.         }
  1107.  
  1108.     /*
  1109.      * Update status flag if dead (countdown to reappearance).
  1110.      */
  1111.     if( IS_DEAD( player[SELF] ) ) {
  1112.         status = MAX_DEAD_STATUS - elapsed_sec_tenths( &time_of_death,
  1113.                                                        ¤t_time ) ;
  1114.         if( status < ALIVE_STATUS ) {
  1115.             player[SELF].status = ALIVE_STATUS ;
  1116.             }
  1117.         else {
  1118.             player[SELF].status = status ;
  1119.             }
  1120.         /*
  1121.          * If sending mail, keep status above a certain (dead) level.
  1122.          */
  1123.         if( sending_msg != SENDING_NO_MAIL ) {
  1124.             if( player[SELF].status < MAILING_STATUS ) {
  1125.                 player[SELF].status = MAILING_STATUS ;
  1126.                 }
  1127.             input_message( 0 ) ;
  1128.             }
  1129.         /*
  1130.          * Not sending mail, check if ready to reappear.
  1131.          */
  1132.         else if( IS_ALIVE( player[SELF] ) ) {
  1133.             /*
  1134.              * Reset to minimum death. If not picking tank, get ready to
  1135.              * reappear.
  1136.              */
  1137.             player[SELF].status = MIN_DEAD_STATUS ;
  1138.             if( !picking_tank )
  1139.                 new_life = 1 ;
  1140.             }
  1141.         }
  1142.     else if( sending_msg != SENDING_NO_MAIL ) {
  1143.         input_message( 0 ) ;
  1144.         }
  1145.  
  1146.     reshapeviewport() ;
  1147.     loadmatrix( id_mat ) ;
  1148.     ortho2( -0.5f, (float)screen_w-0.5f, -0.5f, (float)screen_h-0.5f ) ;
  1149.  
  1150.     show_gun_status( loading_missile - 1 ) ;
  1151.     show_speed();
  1152.     show_heading();
  1153.     if( need_to_show_msgs ) {
  1154.         show_msgs( need_to_show_msgs_vocal, msg_redraw ) ;
  1155.         need_to_show_msgs = FALSE ;
  1156.         msg_redraw = 0 ;
  1157.         }
  1158.  
  1159.     if( need_to_show_lives ) {
  1160.         need_to_show_lives = FALSE ;
  1161.         show_lives() ;
  1162.         }
  1163.  
  1164.     if( need_to_show_level ) {
  1165.         need_to_show_level = FALSE ;
  1166.         show_level() ;
  1167.         }
  1168.  
  1169.     if( need_to_show_players ) {
  1170.         need_to_show_players = FALSE ;
  1171.         show_players() ;
  1172.         }
  1173.  
  1174.     if( need_to_show_out_message ) {
  1175.         need_to_show_out_message = FALSE ;
  1176.         show_out_message() ;
  1177.         }
  1178.  
  1179.     if( msg_count ) {
  1180.         if( --msg_count == 0 ) {
  1181.             post_new_message( 50, 0, " " ) ;
  1182.             }
  1183.         }
  1184.  
  1185.     if( need_to_show_score ) {
  1186.         need_to_show_score = FALSE ;
  1187.         show_score() ;
  1188.         }
  1189.  
  1190.     if( need_to_show_mine_st ) {
  1191.         need_to_show_mine_st = FALSE ;
  1192.         show_mine_status() ;
  1193.         }
  1194.  
  1195.     if( need_to_show_flag_st ) {
  1196.         need_to_show_flag_st = FALSE ;
  1197.         show_flag_status() ;
  1198.         }
  1199.  
  1200.     if( IS_DEAD( player[SELF] ) && sending_msg == SENDING_NO_MAIL &&
  1201.         picking_tank && player[SELF].status < MAILING_STATUS ) {
  1202.             player[SELF].status = MAILING_STATUS ;
  1203.         }
  1204.  
  1205.     if( db_base ) {
  1206.         swapbuffers();
  1207.         }
  1208.     else {
  1209.         gflush() ;
  1210.         }
  1211.  
  1212.     GLXwinset( display, radar_window ) ;
  1213.     radar_view();
  1214.     swapbuffers();
  1215.  
  1216.     if( need_to_show_zoom ) {
  1217.         need_to_show_zoom = FALSE ;
  1218.         GLXwinset( display, radar_ol_window ) ;
  1219.         show_zoom_factor() ;
  1220.         }
  1221.  
  1222.     GLXwinset( display, mainview_window ) ;
  1223.     set_up_main_view() ;
  1224.     main_view();
  1225.     swapbuffers();
  1226.  
  1227.     if( want_to_identify ) {
  1228.         want_to_identify = FALSE ;
  1229.         if( ( enemy_id = id_tank() ) ) {
  1230.             post_new_message( 0, 0, "Looking at %s.", player[enemy_id].name ) ;
  1231.             }
  1232.         }
  1233.  
  1234.     if( want_to_slow_down ) {
  1235.         want_to_slow_down = FALSE ;
  1236.         sleep( 1 ) ;
  1237.         }
  1238.  
  1239.     if( new_life == 1 ) {
  1240.         ol_mode = 0 ;
  1241.         if( solo ) {
  1242.             adjust_lives() ;
  1243.             }
  1244.         else {
  1245.             lives += 1 ;
  1246.             }
  1247.         GLXwinset( display, radar_ol_window ) ;
  1248.         drawOverlay() ;
  1249.         GLXwinset( display, base_window ) ;
  1250.         need_to_show_lives = TRUE ;
  1251.         setTranslations( mainTransTable ) ;
  1252.         if( pick_my_team ) {
  1253.             pick_my_team = FALSE ;
  1254.             join_a_team( underStaffedTeam() ) ;
  1255.             }
  1256.         place_self();
  1257.         reset_mouse() ;
  1258.         }
  1259.  
  1260. #else
  1261.     write_packets() ;
  1262.     read_packets() ;
  1263. #endif /* !defined( NETDEBUGGER ) */
  1264. }
  1265.  
  1266.  
  1267.  
  1268. /*------------------------------------------------------------------------------
  1269.  * Redraw the main view.
  1270.  *----------------------------------------------------------------------------*/
  1271. void redraw_main_view( void )
  1272. {
  1273.     switch( screen_mode ) {
  1274.  
  1275.         case MAIN_SCREEN :
  1276.             main_view() ;
  1277.             break ;
  1278.  
  1279.         case INTRO_PICK_SCREEN :
  1280.         case INTRO_SCREEN :
  1281.             callobj( mv_black_clear ) ;
  1282.             break ;
  1283.  
  1284.         }
  1285.     gflush() ;
  1286.     swapbuffers();
  1287. }
  1288.  
  1289.  
  1290.  
  1291. /*------------------------------------------------------------------------------
  1292.  * Get the view octant of an object.  Return whether or not the object
  1293.  * should be culled.
  1294.  *----------------------------------------------------------------------------*/
  1295. static int
  1296. getview(
  1297.     float x,
  1298.     float y,
  1299.     float heading,
  1300.     unsigned i,
  1301.     int *view,
  1302.     float xref,
  1303.     float yref,
  1304.     float cull_head
  1305.     )
  1306. {
  1307.     float    da ;
  1308.     float    oa ;
  1309.     float    xx = x - xref ;
  1310.     float    yy = y - yref;
  1311.  
  1312.     oa = -getangle( yy, xx ) ;
  1313.     da = 720.0f + oa + heading ;
  1314.     *view = (int)( da / 45.0f ) % 8 ;
  1315.     dst[i] = xx * xx + yy * yy ;
  1316.  
  1317.     da = fmodf( ( 720.0f - oa - cull_head ), 360.0f ) ;
  1318.  
  1319.     return( da > max_cull_angle || da < min_cull_angle ) ;
  1320. }
  1321.  
  1322.  
  1323.  
  1324. /*------------------------------------------------------------------------------
  1325.  * Return the hypotenuse of a right triangle with sides of x and y.
  1326.  *----------------------------------------------------------------------------*/
  1327. float hypotn(
  1328.     float x,
  1329.     float y
  1330.     )
  1331. {
  1332.     return( sqrt( x*x + y*y ) ) ;
  1333. }
  1334.  
  1335.  
  1336.  
  1337. /*------------------------------------------------------------------------------
  1338.  * Return the sum of the squares of two numbers.
  1339.  *----------------------------------------------------------------------------*/
  1340. float square(
  1341.     float x,
  1342.     float y
  1343.     )
  1344. {
  1345.     return( x*x + y*y ) ;
  1346. }
  1347.  
  1348.  
  1349.  
  1350. /*------------------------------------------------------------------------------
  1351.  * Get the angle (degrees) from atan( y/x ) ;
  1352.  *----------------------------------------------------------------------------*/
  1353. float getangle(
  1354.     float x,
  1355.     float y
  1356.     )
  1357. {
  1358.     return( fatan2( y, x ) * RAD2DEG ) ;
  1359. }
  1360.  
  1361.  
  1362.  
  1363. /*------------------------------------------------------------------------------
  1364.  * Check on missile firing/guiding, tank movement, and other actions.
  1365.  *----------------------------------------------------------------------------*/
  1366. void act_on_input( void )
  1367. {
  1368.     float    dv ;
  1369.     float    vtop ;
  1370.     float    ltop ;
  1371.     float    rtop ;
  1372.     float    l ;
  1373.     float    r ;
  1374.  
  1375.     if( !guiding ) {
  1376.         vtop = top_speed ;
  1377.         }
  1378.     else if( player[SELF].tank_type > 0 ) {
  1379.         vtop = gm_vel * (float)player[SELF].msl_status / (float)GM_DURATN ;
  1380.         }
  1381.     else {
  1382.         vtop = 1.2f * gm_vel *
  1383.                sqrt( (float)player[SELF].msl_status / (float)GM_DURATN );
  1384.         }
  1385.  
  1386.     dv = vtop * d_time * 4 ;
  1387.  
  1388.     ltop = left_track_engaged * vtop ;
  1389.     rtop = right_track_engaged * vtop ;
  1390.     if( ltop < left_track ) {
  1391.         left_track -= dv ;
  1392.         if( left_track < ltop )
  1393.             left_track = ltop ;
  1394.         }
  1395.     else if( ltop > left_track ) {
  1396.         left_track += dv ;
  1397.         if( left_track > ltop )
  1398.             left_track = ltop ;
  1399.         }
  1400.     if( rtop < right_track ) {
  1401.         right_track -= dv ;
  1402.         if( right_track < rtop )
  1403.             right_track = rtop ;
  1404.         }
  1405.     else if( rtop > right_track ) {
  1406.         right_track += dv ;
  1407.         if( right_track > rtop )
  1408.             right_track = rtop ;
  1409.         }
  1410.  
  1411.     if( !guiding ) {
  1412.         if( !view_only ) {
  1413.             turn_and_go( left_track, right_track,
  1414.                          &(player[SELF].head), &vx[SELF], &vy[SELF] ) ;
  1415.             }
  1416.         else {
  1417.             turn_and_go( 4.f*left_track, 4.f*right_track,
  1418.                          &(player[SELF].head), &vx[SELF], &vy[SELF] ) ;
  1419.             }
  1420.         }
  1421.     else {
  1422.         l = ( left_track  > 0.f ) ? left_track  : 0.f  ;
  1423.         r = ( right_track > 0.f ) ? right_track : 0.f  ;
  1424.         dv = gm_vel - ( l + r ) / 2.f ;
  1425.         l += dv ;
  1426.         r += dv ;
  1427.         turn_and_go( l, r, &(player[SELF].msl_head), &msl_vx[SELF],
  1428.                      &msl_vy[SELF] ) ;
  1429.         vx[SELF] = vy[SELF] = 0.f ;
  1430.         }
  1431.  
  1432.     if( loading_missile == 0 ) {
  1433.         if( fire_normal_missile || fire_guided_missile ) {
  1434.             sfx( SFX_FIRE ) ;
  1435.             guided_missile = guiding = fire_guided_missile ;
  1436.             ricochet = FALSE ;
  1437.             if( guiding ) {
  1438.                 vx[SELF] = vy[SELF] = 0.f ;
  1439.                 left_track = right_track = gm_vel ;
  1440.                 reset_mouse() ;
  1441.                 missile_duration = GM_DURATN ;
  1442.                 dv = gm_vel ;
  1443.                 }
  1444.             else {
  1445.                 missile_duration = RM_DURATN ;
  1446.                 dv = rm_vel ;
  1447.                 }
  1448.             loading_missile = player[SELF].msl_status = missile_duration ;
  1449.             copy_time( &missile_launch_time, ¤t_time ) ;
  1450.             player[SELF].msl_head = player[SELF].head ;
  1451.             turn_and_go( dv, dv, &(player[SELF].msl_head), &msl_vx[SELF],
  1452.                          &msl_vy[SELF] ) ;
  1453.             last_msl_x[SELF] = player[SELF].msl_x = player[SELF].x ;
  1454.             last_msl_y[SELF] = player[SELF].msl_y = player[SELF].y ;
  1455.             player[SELF].x -= 0.1f * msl_vx[SELF] ;
  1456.             player[SELF].y -= 0.1f * msl_vy[SELF] ;
  1457.             fire_normal_missile = fire_guided_missile = FALSE ;
  1458.             }
  1459.         }
  1460.     else {
  1461.         if( guiding && quit_guided_missile ) {
  1462.             left_track = right_track = 0.f ;
  1463.             guiding = FALSE ;
  1464.             quit_guided_missile = FALSE ;
  1465.             reset_mouse() ;
  1466.             }
  1467.         if( !view_only ) {
  1468.             loading_missile = missile_duration -
  1469.                               elapsed_sec_tenths( &missile_launch_time,
  1470.                                                   ¤t_time ) ;
  1471.             }
  1472.         if( loading_missile <= 0 ) {
  1473.             loading_missile = 0 ;
  1474.             if( guiding ) {
  1475.                 left_track = right_track = 0.f ;
  1476.                 guiding = FALSE ;
  1477.                 reset_mouse() ;
  1478.                 }
  1479.             }
  1480.         }
  1481.  
  1482.     if( want_to_drop_normal_mine ) {
  1483.         want_to_drop_normal_mine = FALSE ;
  1484.         drop_mine( 0 ) ;
  1485.         }
  1486.  
  1487.     if( want_to_drop_permanent_mine ) {
  1488.         want_to_drop_permanent_mine = FALSE ;
  1489.         drop_mine( 1 ) ;
  1490.         }
  1491.  
  1492.     if( want_to_grab_flag ) {
  1493.         if( player[SELF].team == RED_TEAM ) {
  1494.             try_to_grab_flag( BLUE_FLAG ) ;
  1495.             }
  1496.         else if( player[SELF].team == BLUE_TEAM ) {
  1497.             try_to_grab_flag( RED_FLAG ) ;
  1498.             }
  1499.         want_to_grab_flag = FALSE ;
  1500.         }
  1501.  
  1502.     if( want_to_drop_flag && HAS_A_FLAG( player[SELF] ) ) {
  1503.         player_dropped_flag( &player[SELF] ) ;
  1504.         player[SELF].team_flag = 0 ;
  1505.         want_to_drop_flag = FALSE ;
  1506.         }
  1507. }
  1508.  
  1509.  
  1510.  
  1511. static void try_to_grab_flag(
  1512.     int flag_n
  1513.     )
  1514. {
  1515.     if( square( player[SELF].x - flag_x[flag_n],
  1516.                 player[SELF].y - flag_y[flag_n] ) < 25.0f ) {
  1517.         player[SELF].team_flag = 1 << flag_n ;
  1518.         need_to_show_flag_st = TRUE ;
  1519.         set_bulletin_color( teamColor[player[SELF].team] ) ;
  1520.         post_new_message( 0, 1, "Grabbed %s flag.", ( flag_n == RED_FLAG ) ?
  1521.                                                     "red" : "blue" ) ;
  1522.         }
  1523. }
  1524.  
  1525.  
  1526.  
  1527. static void drop_mine(
  1528.     int permanent
  1529.     )
  1530. {
  1531.     if( mine_left ) {
  1532.         if( show_flags && !red_flag_held &&
  1533.             square( player[SELF].x - flag_x[RED_FLAG],
  1534.                     player[SELF].y - flag_y[RED_FLAG] ) < FLAG_MINE_RADIUS_2 ) {
  1535.             post_new_message( 0, 1, "Too close to flag for mine." ) ;
  1536.             return ;
  1537.             }
  1538.         if( show_flags && !blue_flag_held &&
  1539.             square( player[SELF].x - flag_x[BLUE_FLAG],
  1540.                     player[SELF].y - flag_y[BLUE_FLAG] ) < FLAG_MINE_RADIUS_2 ){
  1541.             post_new_message( 0, 1, "Too close to flag for mine." ) ;
  1542.             return ;
  1543.             }
  1544.         perm_mine = permanent ;
  1545.         post_new_message( 0, 0, "Dropped %s mine.",
  1546.             (perm_mine) ? "permanent" : "temporary" ) ;
  1547.         mine_left = 0 ;
  1548.         mine_x = player[SELF].x ;
  1549.         mine_y = player[SELF].y ;
  1550.         mine_status = 1 ;
  1551.         sfx( SFX_DROP_MINE ) ;
  1552.         need_to_show_mine_st = TRUE ;
  1553.         }
  1554. }
  1555.  
  1556.  
  1557.  
  1558. void move_em( void )
  1559. {
  1560.     long    status = 0 ;
  1561.  
  1562.     player[SELF].x += vx[SELF] * d_time ;
  1563.     player[SELF].y += vy[SELF] * d_time ;
  1564.  
  1565.     if( player[SELF].x < -FIELD_SIZE ) {
  1566.         player[SELF].x = -FIELD_SIZE ;
  1567.         status = 1 ;
  1568.         }
  1569.     if( player[SELF].x >  FIELD_SIZE ) {
  1570.         player[SELF].x =  FIELD_SIZE ;
  1571.         status = 1 ;
  1572.         }
  1573.     if( player[SELF].y < -FIELD_SIZE ) {
  1574.         player[SELF].y = -FIELD_SIZE ;
  1575.         status = 1 ;
  1576.         }
  1577.     if( player[SELF].y >  FIELD_SIZE ) {
  1578.         player[SELF].y =  FIELD_SIZE ;
  1579.         status = 1 ;
  1580.         }
  1581.  
  1582.     if( status == 1 ) {
  1583.         blow_up_self( -1 ) ;
  1584.         }
  1585.  
  1586.     if( player[SELF].msl_status > 0 ) {
  1587.         last_msl_x[SELF] = player[SELF].msl_x ;
  1588.         last_msl_y[SELF] = player[SELF].msl_y ;
  1589.         player[SELF].msl_x += msl_vx[SELF] * d_time ;
  1590.         player[SELF].msl_y += msl_vy[SELF] * d_time ;
  1591.  
  1592.         status = 0 ;
  1593.         if( player[SELF].msl_x < -FIELD_SIZE ) {
  1594.             player[SELF].msl_x = -FIELD_SIZE ;
  1595.             status = -1 ;
  1596.             }
  1597.         if( player[SELF].msl_x >  FIELD_SIZE ) {
  1598.             player[SELF].msl_x =  FIELD_SIZE ;
  1599.             status = -1 ;
  1600.             }
  1601.         if( player[SELF].msl_y < -FIELD_SIZE ) {
  1602.             player[SELF].msl_y = -FIELD_SIZE ;
  1603.             status = -1 ;
  1604.             }
  1605.         if( player[SELF].msl_y >  FIELD_SIZE ) {
  1606.             player[SELF].msl_y =  FIELD_SIZE ;
  1607.             status = -1 ;
  1608.             }
  1609.  
  1610.         if( !status ) {
  1611.             status = missile_duration -
  1612.                      elapsed_sec_tenths( &missile_launch_time, ¤t_time ) ;
  1613.             }
  1614.  
  1615.         if( status <= 0 ) {
  1616.             player[SELF].msl_status = -MEXPL_DURATION ;
  1617.             copy_time( &missile_explode_time, ¤t_time ) ;
  1618.             explosion_sfx( player[SELF].msl_x - player[SELF].x,
  1619.                            player[SELF].msl_y - player[SELF].y,
  1620.                            player[SELF].head ) ;
  1621.             if( guiding ) {
  1622.                 left_track = right_track = 0.f ;
  1623.                 guiding = FALSE ;
  1624.                 reset_mouse() ;
  1625.                 }
  1626.             }
  1627.         else {
  1628.             player[SELF].msl_status = status ;
  1629.             }
  1630.         }
  1631.     else if( player[SELF].msl_status < 0 ) {
  1632.         status = -MEXPL_DURATION
  1633.                + elapsed_sec_tenths( &missile_explode_time, ¤t_time ) ;
  1634.         if( status >= 0 ) {
  1635.             player[SELF].msl_status = 0 ;
  1636.             }
  1637.         else {
  1638.             player[SELF].msl_status = status ;
  1639.             }
  1640.         }
  1641. }
  1642.  
  1643.  
  1644. float xp[TOTALOBSTS] = { 0.,-2., 2.,-2., 2.,-2., 2., 0.,-4.,-4., 4., 4.,
  1645.                       -3., 3.,-1., 1.,-1., 1.,-3., 3.,-4., 4., 0., 0. } ;
  1646. float yp[TOTALOBSTS] = { 2., 2., 2., 0., 0.,-2.,-2.,-2.,-4., 4.,-4., 4.,
  1647.                        3., 3., 1., 1.,-1.,-1.,-3.,-3., 0., 0.,-4., 4. } ;
  1648.  
  1649. void init_var( void )
  1650. {
  1651.     unsigned    i ;
  1652.  
  1653.     char_width = (float)strwidth( "ABCDEFGHIJKLM" ) / 13.f ;
  1654.     char_height = (float)getheight() ;
  1655.  
  1656.     screen_mode = INTRO_SCREEN ;
  1657.  
  1658.     XtAppAddWorkProc( appContext, randomizerWP, 0 ) ;
  1659.     randomizer = True ;
  1660.  
  1661.     reset_viewing_order() ;
  1662.     for( i = 0 ; i < TOTALOBSTS ; i++ ) {
  1663.         obst_x[i] = (float)OBJECT_SPACING * xp[i] ;
  1664.         obst_y[i] = (float)OBJECT_SPACING * yp[i] ;
  1665.         head[i] = 0 ;
  1666.         }
  1667.  
  1668.     flag_x[RED_FLAG]  = RED_FLAG_HOME_X ;
  1669.     flag_y[RED_FLAG]  = RED_FLAG_HOME_Y ;
  1670.     flag_x[BLUE_FLAG] = BLUE_FLAG_HOME_X ;
  1671.     flag_y[BLUE_FLAG] = BLUE_FLAG_HOME_Y ;
  1672.  
  1673.     vx[SELF] = vy[SELF] = 0.f ;
  1674.     player[SELF].bz_id = BZ ;
  1675.     player[SELF].msl_x = player[SELF].msl_y = msl_vx[SELF] = msl_vy[SELF] = 0.f;
  1676.     player[SELF].status = ALIVE_STATUS ;
  1677.     player[SELF].msl_head = player[SELF].msl_status = 0 ;
  1678. }
  1679.  
  1680.  
  1681.  
  1682. void place_self( void )
  1683. {
  1684.     int        j ;
  1685.     int        k ;
  1686.     float    r ;
  1687.     float    ang ;
  1688.     float    cx ;
  1689.     float    cy ;
  1690.     int        team_members ;
  1691.  
  1692.     if( need_to_set_tank ) {
  1693.         need_to_set_tank = FALSE ;
  1694.         player[SELF].tank_type = new_tank_type ;
  1695.         }
  1696.  
  1697.     team_members = 0 ;
  1698.     cx = cy = 0.0f ;
  1699.     if( player[SELF].team != NEUTRAL_TEAM && !init_wait ) {
  1700.         for( k = ENEMY ; k < number_players ; k++ ) {
  1701.             if( IS_ALIVE( player[k] ) && player[k].team == player[SELF].team ) {
  1702.                 cx += player[k].x ;
  1703.                 cy += player[k].y ;
  1704.                 team_members++ ;
  1705.                 }
  1706.             }
  1707.         if( team_members > 0 ) {
  1708.             cx /= (float)team_members ;
  1709.             cy /= (float)team_members ;
  1710.             }
  1711.         }
  1712.  
  1713.     do{
  1714.         j = 0 ;
  1715.         if( !init_wait ) {
  1716.             r = (float)OBJECT_SPACING +
  1717.                 fmodf( (float)( rand() ), FIELD_SIZE - OBJECT_SPACING - 50.f ) ;
  1718.             }
  1719.         else {
  1720.             r = (float)( rand() % OBJECT_SPACING ) ;
  1721.             }
  1722.         ang = rand() % 360 ;
  1723.         player[SELF].x = cx + r * COSINE(ang) ;
  1724.         player[SELF].y = cy + r * SINE(ang) ;
  1725.         r = 0.9f * FIELD_SIZE ;
  1726.         if( player[SELF].x < -r ) player[SELF].x = -r ;
  1727.         if( player[SELF].y < -r ) player[SELF].y = -r ;
  1728.         if( player[SELF].x >  r ) player[SELF].x =  r ;
  1729.         if( player[SELF].y >  r ) player[SELF].y =  r ;
  1730.         for( k = 0 ; k < TOTALOBSTS ; k++ ) {
  1731.             if( square( player[SELF].x-obst_x[k], player[SELF].y-obst_y[k] )
  1732.                 < 1600.f )
  1733.                 j = 1 ;
  1734.             }
  1735.         } while( j != 0 );
  1736.     player[SELF].head = ( rand() % 3600 ) / 10.f ;
  1737.     player[SELF].status = ALIVE_STATUS ;
  1738.     player[SELF].killed_by_id = 0 ;
  1739.     if( !perm_mine ) {
  1740.         mine_left = 1 ;
  1741.         mine_status = 0 ;
  1742.         need_to_show_mine_st = TRUE ;
  1743.         }
  1744.     if( !init_wait ) {
  1745.         loading_missile = 2 ;
  1746.         copy_time( &missile_launch_time, ¤t_time ) ;
  1747.         missile_duration = GM_DURATN / 10 ;
  1748.         }
  1749.     else {
  1750.         missile_duration = loading_missile = GM_DURATN ;
  1751.         start_time( &missile_launch_time ) ;
  1752.         }
  1753.     top_speed = vmax[player[SELF].tank_type] ;
  1754.     sfx( SFX_POP ) ;
  1755. }
  1756.  
  1757.  
  1758.  
  1759. void set_up_main_view( void )
  1760. {
  1761.     int            i ;
  1762.     int            kk ;
  1763.     int            culled ;
  1764.     long        status ;
  1765.     int            view ;
  1766.     float        xref ;
  1767.     float        yref ;
  1768.     float        href ;
  1769.  
  1770.     n_view_objs = 0 ;
  1771.  
  1772.     if( !guiding ) {
  1773.         xref = player[SELF].x ;
  1774.         yref = player[SELF].y ;
  1775.         href = player[SELF].head ;
  1776.         }
  1777.     else {
  1778.         xref = player[SELF].msl_x ;
  1779.         yref = player[SELF].msl_y ;
  1780.         href = player[SELF].msl_head ;
  1781.         }
  1782.  
  1783.     for( i = CONES ; i < CUBES ; i++, n_view_objs++ ) {
  1784.         if( getview( obst_x[i], obst_y[i], head[i], n_view_objs, &view,
  1785.                 xref, yref, href ) )
  1786.             view_object[n_view_objs] = pyrm[view] ;
  1787.         else
  1788.             view_object[n_view_objs] = null_obj ;
  1789.         }
  1790.  
  1791.     for( i = CUBES ; i < TOTALOBSTS ; i++, n_view_objs++ ) {
  1792.         if( getview( obst_x[i], obst_y[i], head[i], n_view_objs, &view,
  1793.                 xref, yref, href ) )
  1794.             view_object[n_view_objs] = cube[view] ;
  1795.         else
  1796.             view_object[n_view_objs] = null_obj ;
  1797.         }
  1798.  
  1799.     for( i = 0 ; i < N_FLAGS ; i++, n_view_objs++ ) {
  1800.         if( show_flags ) {
  1801.             if( getview( flag_x[i], flag_y[i], 0.f, n_view_objs, &view,
  1802.                     xref, yref, href ) ) {
  1803.                 view_object[n_view_objs] = flag[i][view] ;
  1804.                 }
  1805.             else {
  1806.                 view_object[n_view_objs] = null_obj ;
  1807.                 }
  1808.             }
  1809.         else {
  1810.             dst[n_view_objs] = 0.f ;
  1811.             view_object[n_view_objs] = null_obj ;
  1812.             }
  1813.         }
  1814.  
  1815.     for( i = SELF ; i < number_players ; i++, n_view_objs += 2 ) {
  1816.         if( i != SELF ) {
  1817.             culled = getview( player[i].x, player[i].y, player[i].head,
  1818.                         n_view_objs, &view, xref, yref, href ) ;
  1819.             if( IS_DEAD( player[i] ) ) {
  1820.                 kk = MAX_DEAD_STATUS - player[i].status ;
  1821.                 if( kk >= EXPDURATION )
  1822.                     kk = EXPDURATION - 1 ;
  1823.                 view_object[n_view_objs] = ( culled ) ?
  1824.                     explosion[player[i].team][kk][tank_body[player[i].tank_type]] :
  1825.                     null_obj ;
  1826.                 }
  1827.             else {
  1828.                 view_object[n_view_objs] = ( culled ) ?
  1829.                     view + 1 : null_obj ;
  1830.                 }
  1831.             }
  1832.         else {
  1833.             dst[n_view_objs] = 0.f ;
  1834.             view_object[n_view_objs] = null_obj ;
  1835.             }
  1836.  
  1837.         if( player[i].msl_status ) {
  1838.             culled = getview( player[i].msl_x, player[i].msl_y,
  1839.                          player[i].msl_head, n_view_objs+1, &view,
  1840.                          xref, yref, href ) ;
  1841.             if( player[i].msl_status > 0 ) {
  1842.                 view_object[n_view_objs+1] = ( culled ) ? 
  1843.                     missile[view] : null_obj ;
  1844.                 }
  1845.             else {
  1846.                 player[i].msl_head = player[SELF].head ;
  1847.                 view_object[n_view_objs+1] = ( culled ) ?
  1848.                         msl_expl[MEXPL_DURATION+player[i].msl_status] :
  1849.                         null_obj ;
  1850.                 }
  1851.             }
  1852.         else {
  1853.             dst[n_view_objs+1] = 0.f ;
  1854.             view_object[n_view_objs+1] = null_obj ;
  1855.             }
  1856.         }
  1857.  
  1858.     sort_view( n_view_objs ) ;
  1859. }
  1860.  
  1861.  
  1862.  
  1863. void main_view( void )
  1864. {
  1865. #if !defined( NETDEBUGGER )
  1866.     float        xx ;
  1867.     float        yy ;
  1868.     unsigned    i ;
  1869.     unsigned    j ;
  1870.     unsigned    l ;
  1871.     unsigned    m ;
  1872.     int            kk ;
  1873.     long        teamScore[N_TEAMS] ;
  1874.     char        info[100] ;
  1875.  
  1876.     reshapeviewport() ;
  1877.     loadmatrix( id_mat ) ;
  1878.     ortho2( 0.f, mv_w, 0.f, mv_h ) ;
  1879.  
  1880.     if( guiding )
  1881.         callobj( mv_guided_bg ) ;
  1882.     else
  1883.         callobj( mv_normal_bg ) ;
  1884.  
  1885.     if( binoculars && !guiding ) {
  1886.         perspective(  30, aspect_ratio, .5f, 10000.f ) ;
  1887.         }
  1888.     else {
  1889.         perspective( 300, aspect_ratio, .5f, 10000.f ) ;
  1890.         }
  1891.  
  1892.     rotate( -900, 'x' ) ;
  1893.  
  1894.     if( guiding )
  1895.         rot( player[SELF].msl_head, 'z' );
  1896.     else
  1897.         rot( player[SELF].head, 'z' );
  1898.  
  1899.     callobj( sky ) ;
  1900.  
  1901.     if( mv_RGB ) {
  1902.         callobj( lights_on ) ;
  1903.         }
  1904.  
  1905.     pushmatrix() ;
  1906.     if( guiding )
  1907.         translate( -fmodf(player[SELF].msl_x, 50.f ),
  1908.                    -fmodf(player[SELF].msl_y, 50.f ), -DROP ) ;
  1909.     else
  1910.         translate( -fmodf(player[SELF].x, 50.f ),
  1911.                    -fmodf(player[SELF].y, 50.f ), -DROP ) ;
  1912.     callobj( ground ) ;
  1913.     popmatrix() ;
  1914.  
  1915.     if( guiding )
  1916.         translate( -player[SELF].msl_x, -player[SELF].msl_y, -DROP ) ;
  1917.     else
  1918.         translate( -player[SELF].x, -player[SELF].y, -DROP ) ;
  1919.  
  1920.     callobj( border ) ;
  1921.  
  1922.     if( show_flags ) {
  1923.         callobj( flag_homes_mv ) ;
  1924.         }
  1925.  
  1926.     for( i = n_view_objs - 1 ; i >= 0 ; i-- ) {
  1927.         j = l = view_order[i] ;
  1928.         if( view_object[j] != null_obj ) {
  1929.             if( j < TOTALOBSTS ) {
  1930.                 tran_rot_show( obst_x[j], obst_y[j], head[j], view_object[j] ) ;
  1931.                 }
  1932.             else {
  1933.                 l -= TOTALOBSTS ;
  1934.                 if( l < N_FLAGS ) {
  1935.                     tran_rot_show( flag_x[l], flag_y[l], 0.f, view_object[j] ) ;
  1936.                     }
  1937.                 else {
  1938.                     l -= N_FLAGS ;
  1939.                     /*
  1940.                      * if l==0, it is SELF, so don't show
  1941.                      */
  1942.                     if( l > 0 ) {
  1943.                         m = l / 2 ;
  1944.                         if( l % 2 ) {
  1945.                             if( m != SELF || !guiding ) {
  1946.                                 tran_rot_show( player[m].msl_x, player[m].msl_y,
  1947.                                                player[m].msl_head,
  1948.                                                view_object[j] ) ;
  1949.                                 }
  1950.                             }
  1951.                         else {
  1952.                             if( IS_DEAD( player[m] ) ||
  1953.                                 view_object[j] == null_obj ) {
  1954.                                 tran_rot_show( player[m].x, player[m].y,
  1955.                                                player[m].head, view_object[j] );
  1956.                                 }
  1957.                             else {
  1958.                                 pushmatrix() ;
  1959.                                 translate( player[m].x, player[m].y, 0.f ) ;
  1960.                                 rot( -player[m].head, 'z' ) ;
  1961.                                 draw_tank( tank_body[player[m].tank_type],
  1962.                                            view_object[j] - 1,
  1963.                                            player[m].team, m ) ;
  1964.                                 popmatrix() ;
  1965.                                 }
  1966.                             }
  1967.                         }
  1968.                     }
  1969.                 }
  1970.             }
  1971.         else if( dst[j] == 0.0f ) {
  1972.             break ;
  1973.             }
  1974.         }
  1975.  
  1976.     if( mv_RGB ) {
  1977.         callobj( lights_off ) ;
  1978.         }
  1979.  
  1980.     callobj( crosshairs );
  1981.     if( IS_DEAD( player[SELF] ) || want_to_see_score || want_to_see_help ) {
  1982.         loadmatrix( id_mat ) ;
  1983.         ortho2( 0.f, 1024.f, 0.f, 550.f ) ;
  1984.  
  1985.         if( IS_DEAD( player[SELF] ) ) {
  1986.             linewidth(3);
  1987.             callobj( mv_set_white );
  1988.             kk = MAX_DEAD_STATUS - player[SELF].status ;
  1989.             for( i=0 ; i < kk ; i++ ) {
  1990.                 if( i < 30 ) {
  1991.                     bgnline() ;
  1992.                         v2f( fracture[i].v0 ) ;
  1993.                         v2f( fracture[i].v1 ) ;
  1994.                     endline() ;
  1995.                     }
  1996.                 }
  1997.             linewidth(1);
  1998.             }
  1999.  
  2000.         ortho2( 0.f, mv_w, 0.f, mv_h ) ;
  2001.  
  2002.         /*
  2003.          * Show help.
  2004.          */
  2005.         if( want_to_see_help ) {
  2006.             callobj( mv_set_red );
  2007.             print_help( mv_w / 2.f, mv_h / 2.f, 0 ) ;
  2008.             }
  2009.         /*
  2010.          * Show scores
  2011.          */
  2012.         else if ( !solo ) {
  2013.             callobj( mv_set_yellow );
  2014.             xx = ( mv_w - 6.f*char_width ) / 2.f ;
  2015.             yy = mv_h - 40.f ;
  2016.             cmov2( xx, yy ) ;
  2017.             charstr( "SCORES" ) ;
  2018.             xx = ( mv_w - 30.f*char_width ) / 2.f ;
  2019.             yy -= 20.f ;
  2020.             teamScore[NEUTRAL_TEAM] = teamBonus[NEUTRAL_TEAM] ;
  2021.             teamScore[RED_TEAM] = teamBonus[RED_TEAM] ;
  2022.             teamScore[BLUE_TEAM] = teamBonus[BLUE_TEAM] ;
  2023.             for( i = ( view_only ) ? 1 : 0 ; i < number_players ;
  2024.                  i++, yy -= 20.f ) {
  2025.                 sprintf( info, "%-12s  %6d  %8s", player[i].name,
  2026.                          player[i].score, teamName[player[i].team] );
  2027.                 cmov2( xx, yy ) ;
  2028.                 charstr( info ) ;
  2029.                 teamScore[player[i].team] += player[i].score ;
  2030.                 }
  2031.             xx = ( mv_w - 11.f*char_width ) / 2.f ;
  2032.             yy -= 20.f ;
  2033.             cmov2( xx, yy ) ;
  2034.             charstr( "TEAM TOTALS" ) ;
  2035.             xx = ( mv_w - 15.f*char_width ) / 2.f ;
  2036.             yy -= 20.f ;
  2037.             for( i = 0 ; i < N_TEAMS ; i++, yy -= 20.f ) {
  2038.                 sprintf( info, "%-7s  %6d", teamName[i], teamScore[i] ) ;
  2039.                 cmov2( xx, yy ) ;
  2040.                 charstr( info ) ;
  2041.                 }
  2042.             }
  2043.         }
  2044.  
  2045. #endif /* !defined( NETDEBUGGER ) */
  2046. }
  2047.  
  2048.  
  2049. void sort_view(
  2050.     int k
  2051.     )
  2052. {
  2053.     qsort( (char *)(&view_order[0]), k, sizeof(view_order[0]), cmpfnc ) ;
  2054. }
  2055.  
  2056.  
  2057.  
  2058. int cmpfnc(
  2059.     const void *ep1,
  2060.     const void *ep2
  2061.     )
  2062. {
  2063.     if( dst[*((unsigned int *)ep1)] > dst[*((unsigned int *)ep2)] ) {
  2064.         return(1) ;
  2065.         }
  2066.     else {
  2067.         return(-1) ;
  2068.         }
  2069. }
  2070.  
  2071.  
  2072. void turn_and_go(
  2073.     float l,
  2074.     float r,
  2075.     float *heading,
  2076.     float *velx,
  2077.     float *vely
  2078.     )
  2079. {
  2080.     float    v ;
  2081.     v = ( l + r ) / 2.f ;
  2082.     *heading += ( ( l - r ) * t_factor * d_time ) ;
  2083.     *heading = fmodf( *heading, 360.0f ) ;
  2084.     *heading = ( *heading < 0 ) ? *heading + 360.0f : *heading ;
  2085.     *velx = v*SINE( *heading ) ;
  2086.     *vely = v*COSINE( *heading ) ;
  2087. }
  2088.  
  2089.  
  2090.  
  2091. void collide( void )
  2092. {
  2093.     unsigned    hit ;
  2094.     unsigned    obst_id ;
  2095.     float        xhit ;
  2096.     float        yhit ;
  2097.     float        radius ;
  2098.     unsigned    enemy_id ;
  2099.     int            mine_flag ;
  2100.     int            side ;
  2101.  
  2102.     hit = 0 ;
  2103.  
  2104.     if( hit_count ) {
  2105.         hit_count = MAX_HIT_COUNT
  2106.                   - elapsed_sec_tenths( &hit_time, ¤t_time ) ;
  2107.         if( hit_count < 0 ) {
  2108.             hit_count = 0 ;
  2109.             player[SELF].hit_by_id = 0 ;
  2110.             }
  2111.         }
  2112.  
  2113.     if( player[SELF].msl_status > 0 ) {
  2114.         switch( check_missile_hit( SELF, &enemy_id, &side ) ) {
  2115.             case 1:
  2116.                 if( enemy_id != SELF || ricochet ) {
  2117.                     if( guiding ) {
  2118.                         left_track = right_track = 0.f ;
  2119.                         guiding = FALSE ;
  2120.                         reset_mouse() ;
  2121.                         }
  2122.                     explosion_sfx( player[SELF].msl_x - player[SELF].x,
  2123.                                    player[SELF].msl_y - player[SELF].y,
  2124.                                    player[SELF].head ) ;
  2125.                     player[SELF].msl_status = -MEXPL_DURATION ;
  2126.                     copy_time( &missile_explode_time, ¤t_time ) ;
  2127.                     player[SELF].msl_x = player[enemy_id].x ;
  2128.                     player[SELF].msl_y = player[enemy_id].y ;
  2129.                     msl_vx[SELF] = msl_vy[SELF] = 0.f ;
  2130.                     player[SELF].hit_type = HIT_BY_MISSILE ;
  2131.                     if( enemy_id == SELF ) {
  2132.                         blow_up_self( 0 ) ;
  2133.                         }
  2134.                     else {
  2135.                         player[SELF].hit_by_id = player[enemy_id].id ;
  2136.                         hit_count = MAX_HIT_COUNT ;
  2137.                         copy_time( &hit_time, ¤t_time ) ;
  2138.                         }
  2139.                     }
  2140.                 break;
  2141.             case 2:
  2142.                 if( guided_missile ){
  2143.                     if( guiding ){
  2144.                         left_track = right_track = 0.f ;
  2145.                         guiding = FALSE ;
  2146.                         reset_mouse() ;
  2147.                         }
  2148.                     player[SELF].msl_status = -MEXPL_DURATION ;
  2149.                     copy_time( &missile_explode_time, ¤t_time ) ;
  2150.                     player[SELF].msl_x -= msl_vx[SELF] * d_time ;
  2151.                     player[SELF].msl_y -= msl_vy[SELF] * d_time ;
  2152.                     msl_vx[SELF] = msl_vy[SELF] = 0.f ;
  2153.                     explosion_sfx( player[SELF].msl_x - player[SELF].x,
  2154.                                    player[SELF].msl_y - player[SELF].y,
  2155.                                    player[SELF].head ) ;
  2156.                     }
  2157.                 else {
  2158.                     player[SELF].msl_x -= msl_vx[SELF] * d_time ;
  2159.                     player[SELF].msl_y -= msl_vy[SELF] * d_time ;
  2160.                     switch( side ) {
  2161.                         case MIN_X_SIDE :
  2162.                         case MAX_X_SIDE :
  2163.                             msl_vx[SELF] = -msl_vx[SELF] ;
  2164.                             break ;
  2165.                         case MIN_Y_SIDE :
  2166.                         case MAX_Y_SIDE :
  2167.                             msl_vy[SELF] = -msl_vy[SELF] ;
  2168.                             break ;
  2169.                         }
  2170.                     player[SELF].msl_head = getangle( msl_vy[SELF],
  2171.                                                       msl_vx[SELF] ) ;
  2172.                     ricochet = TRUE ;
  2173.                     }
  2174.                 break;
  2175.             case 0:
  2176.             default:
  2177.                 break;
  2178.             }
  2179.         }
  2180.  
  2181.     /*
  2182.      * Check for mine interaction.
  2183.      */
  2184.     if( mine_status > 0 ) {
  2185.         /*
  2186.          * If player is alive and not detonating mine, or if player has a
  2187.          * permanent mine, check for normal kill radius.
  2188.          */
  2189.         if( ( IS_ALIVE( player[SELF] ) &&
  2190.             !( mine_flag = want_to_detonate_mine ) ) || perm_mine ) {
  2191.             radius = REG_MINE_RADIUS * REG_MINE_RADIUS ;
  2192.             }
  2193.         /*
  2194.          * Otherwise, player is detonating the mine, so increase the kill
  2195.          * radius.
  2196.          */
  2197.         else {
  2198.             radius = DET_MINE_RADIUS * DET_MINE_RADIUS ;
  2199.             mine_status = 0 ;
  2200.             if( mine_flag ) {
  2201.                 if( no_sfx )
  2202.                     ringbell() ;
  2203.                 else
  2204.                     explosion_sfx( mine_x - player[SELF].x,
  2205.                                    mine_y - player[SELF].y,
  2206.                                    player[SELF].head ) ;
  2207.                 mine_left = 1 ;
  2208.                 need_to_show_mine_st = TRUE ;
  2209.                 }
  2210.             }
  2211.         /*
  2212.          * Check if mine hit any enemy tanks, or self.
  2213.          */
  2214.         switch( check_mine_hit( &enemy_id, radius ) ) {
  2215.             /*
  2216.              * Hit a tank.
  2217.              */
  2218.             case 1:
  2219.                 /*
  2220.                  * Hit an enemy's tank.
  2221.                  */
  2222.                 if( enemy_id ) {
  2223.                     if( IS_ALIVE( player[enemy_id] ) ) {
  2224.                         mine_status = 0 ;
  2225.                         player[SELF].hit_by_id = player[enemy_id].id ;
  2226.                         player[SELF].hit_type = HIT_BY_MINE ;
  2227.                         hit_count = MAX_HIT_COUNT ;
  2228.                         copy_time( &hit_time, ¤t_time ) ;
  2229.                         if( !solo )
  2230.                             level++ ;
  2231.                         need_to_show_level = TRUE ;
  2232.                         mine_left = 1;
  2233.                         need_to_show_mine_st = TRUE ;
  2234.                         }
  2235.                     }
  2236.                 /*
  2237.                  * Close enough to pick up, if so desired.
  2238.                  */
  2239.                 else if( want_to_pick_mine ) {
  2240.                     post_new_message( 0, no_sfx, "Picked up mine." ) ;
  2241.                     mine_left = 1 ;
  2242.                     mine_status = 0 ;
  2243.                     perm_mine = 0 ;
  2244.                     sfx( SFX_PICK_UP_MINE ) ;
  2245.                     need_to_show_mine_st = TRUE ;
  2246.                     }
  2247.                 want_to_pick_mine = FALSE ;
  2248.                 break;
  2249.             /*
  2250.              * Nothing hit.
  2251.              */
  2252.             default:
  2253.                 want_to_pick_mine = FALSE ;
  2254.                 break;
  2255.             }
  2256.         want_to_detonate_mine = FALSE ;
  2257.         }
  2258.  
  2259.     if( IS_ALIVE( player[SELF] ) ) {
  2260.         /*
  2261.          * Check to hit enemy tanks and obstacles.
  2262.          */
  2263.         switch( check_tank_collision( SELF, &obst_id ) ) {
  2264.             /*
  2265.              * Hit an enemy tank (obst_id).
  2266.              */
  2267.             case 1:
  2268.                 hit = 1 ;
  2269.                 xhit = player[obst_id].x ;
  2270.                 yhit = player[obst_id].y ;
  2271.                 break;
  2272.             /*
  2273.              * Hit an obstacle (obst_id).
  2274.              */
  2275.             case 2:
  2276.                 hit = 1 ;
  2277.                 xhit = obst_x[obst_id] ;
  2278.                 yhit = obst_y[obst_id] ;
  2279.                 break;
  2280.             /*
  2281.              * Hit nothing.
  2282.              */
  2283.             case 0:
  2284.             default:
  2285.                 break;
  2286.             }
  2287.         }
  2288.  
  2289.     if( hit ) {
  2290.         sfx( SFX_BUMP ) ;
  2291.         move_after_hit( SELF, xhit, yhit, vx[SELF], vy[SELF] ) ;
  2292.         }
  2293.  
  2294. }
  2295.  
  2296.  
  2297.  
  2298. void move_after_hit(
  2299.     unsigned int tank_id,
  2300.     float xhit,
  2301.     float yhit,
  2302.     float velx,
  2303.     float vely
  2304.     )
  2305. {
  2306.     float        dx ;
  2307.     float        dy ;
  2308.     float        d ;
  2309.     float        dv ;
  2310.  
  2311.     dx = player[tank_id].x - xhit ;
  2312.     dy = player[tank_id].y - yhit ;
  2313.     d = hypotn( dx, dy ) ;
  2314.     if( d != 0.0f ) {
  2315.         dv = 0.1f * vmax[player[tank_id].tank_type] ;
  2316.         player[tank_id].x += dv * dx / d - velx * d_time ;
  2317.         player[tank_id].y += dv * dy / d - vely * d_time ;
  2318.         }
  2319.     else {
  2320.         player[tank_id].x -= 2 * velx * d_time ;
  2321.         player[tank_id].y -= 2 * vely * d_time ;
  2322.         }
  2323. }
  2324.  
  2325.  
  2326.  
  2327. void vertex2f(
  2328.     float x,
  2329.     float y
  2330.     )
  2331. {
  2332.     float pt[2] ;
  2333.  
  2334.     pt[0] = x ;
  2335.     pt[1] = y ;
  2336.     v2f( pt ) ;
  2337. }
  2338.  
  2339.  
  2340.  
  2341. static char *service_msg[] = {
  2342.     "Can't find udp service \"sgi-bznet\"\n\n",
  2343.     "To run bz over the network, you must have the following line\n",
  2344.     "in your /etc/services file.\n\n",
  2345.     "sgi-bznet\t5133/udp\t\t# tank demo\n\n",
  2346.     } ;
  2347.  
  2348.  
  2349. void init_com( void )
  2350. {
  2351. #if !defined( NETDEBUGGER )
  2352.     int                i ;
  2353.     int                port ;
  2354.     int                id ;
  2355.     struct servent    *serv ;
  2356.  
  2357.     if( solo ) {
  2358.         networking = FALSE ;
  2359.         write_packets = do_enemy_stuff ;
  2360.         read_packets = no_op ;
  2361.         }
  2362.     else if( in_name == NULL && out_name == NULL ) {
  2363.  
  2364.         if( ( serv = getservbyname( BZ_SERVICE, NULL ) ) == NULL ) {
  2365.             for( i = 0 ; i < sizeof( service_msg ) / sizeof( service_msg[0] ) ;
  2366.                  i++ ) {
  2367.                 fputs( service_msg[i], stderr ) ;
  2368.                 }
  2369.             system("inform 'Sorry, you must change the line in /etc/services to allow bz to work in network mode: otherwise use bz -solo'");
  2370.             end_program( 1 );
  2371.             }
  2372.         port = serv->s_port ;
  2373.  
  2374. #if defined( BETA )
  2375.         port = 5134 ;
  2376. #endif /* defined( BETA ) */
  2377.  
  2378.         if( timeToLive < BZ_MIN_TTL || timeToLive > BZ_MAX_TTL ) {
  2379.             fprintf( stderr, "Specified time-to-live (%d) does not fall within"
  2380.                      " acceptable range (%d - %d).\n", timeToLive, BZ_MIN_TTL,
  2381.                      BZ_MAX_TTL );
  2382.             fprintf( stderr, "The default value of %d will be used.\n",
  2383.                      BZ_DEFAULT_TTL ) ;
  2384.             timeToLive = BZ_DEFAULT_TTL ;
  2385.             }
  2386.  
  2387.         if( ( in_fd = openMulticastSocket( &in_addr, port, timeToLive, 0,
  2388.                         BZ_GROUP, NULL, "r" ) ) < 0 ) {
  2389.             end_program( 1 ) ;
  2390.             }
  2391.         read_packets = network_in ;
  2392.  
  2393.         /*
  2394.          * Turn on non-blocking I/O
  2395.          */
  2396.         if( fcntl( in_fd, F_SETFL, FNDELAY ) < 0 ) {
  2397.             perror( "fcntl F_SETFL, FNDELAY" ) ;
  2398.             end_program( 1 ) ;
  2399.             }
  2400.  
  2401.         if( view_only ) {
  2402.             write_packets = no_op ;
  2403.             out_fd = -1 ;
  2404.             }
  2405.         else {
  2406.             if( ( out_fd = openMulticastSocket( &out_addr, port, timeToLive, 0,
  2407.                             BZ_GROUP, NULL, "w" ) ) < 0 ) {
  2408.                 end_program( 1 ) ;
  2409.                 }
  2410.             out_addrlen = sizeof( out_addr ) ;
  2411.             write_packets = network_out ;
  2412.             }
  2413.         }
  2414.     else {
  2415.         if( in_name != NULL ) {
  2416.             if( ( in_fd = open( in_name, O_RDONLY ) ) == -1 ) {
  2417.                 perror( in_name ) ;
  2418.                 end_program( 1 ) ;
  2419.                 }
  2420.             else {
  2421.                 if( read( in_fd, &id, sizeof( id ) ) != sizeof( id ) ) {
  2422.                     perror( in_name ) ;
  2423.                     end_program( 1 ) ;
  2424.                     }
  2425.                 if( id != BZ ) {
  2426.                     fprintf( stderr, "%s: input file `%s' is not from this"
  2427.                              " version of %s.\n", basename, in_name,
  2428.                              basename ) ;
  2429.                     end_program( 1 ) ;
  2430.                     }
  2431.                 else {
  2432.                     lseek( in_fd, 0, 0 ) ;
  2433.                     }
  2434.                 }
  2435.             read_packets = file_in ;
  2436.             }
  2437.         else {
  2438.             read_packets = no_op ;
  2439.             in_fd = -1 ;
  2440.             }
  2441.  
  2442.         if( out_name != NULL ) {
  2443.             if( ( out_fd = open( out_name, O_WRONLY|O_CREAT|O_TRUNC, 0644 ) )
  2444.                 == -1 ) {
  2445.                 perror( out_name ) ;
  2446.                 end_program( 1 ) ;
  2447.                 }
  2448.             write_packets = file_out ;
  2449.             }
  2450.         else {
  2451.             write_packets = no_op ;
  2452.             out_fd = -1 ;
  2453.             }
  2454.  
  2455.         }
  2456. #else
  2457.     write_packets = net_debug_out ;
  2458.     read_packets = net_debug_in ;
  2459.     in_fd = 0 ;
  2460.     out_fd = 1 ;
  2461.     read( 0, player[SELF].name, sizeof( player[SELF].name ) ) ;
  2462.     read( 0, &player[SELF].id, sizeof( player[SELF].id ) ) ;
  2463.     player[SELF].bz_id = BZ ;
  2464.     post_new_message( 0, 0, "initiated as %s with an id of %d.",
  2465.                       player[SELF].name, player[SELF].id ) ;
  2466.     /*
  2467.      * Turn on non-blocking I/O
  2468.      */
  2469.     if( fcntl( 0, F_SETFL, FNONBLK ) < 0 ) {
  2470.         fprintf( stderr, "player %s: fcntl F_SETFL, FNONBLK\n",
  2471.                  player[SELF].name ) ;
  2472.         exit( 1 ) ;
  2473.         }
  2474. #endif /* !defined( NETDEBUGGER ) */
  2475.  
  2476. }
  2477.  
  2478.  
  2479.  
  2480. void no_op( void )
  2481. {
  2482. }
  2483.  
  2484.  
  2485.  
  2486. void file_out( void )
  2487. {
  2488.     int    i ;
  2489.  
  2490.     for( i = number_players ; i-- ; ) {
  2491.         if( write( out_fd, (void *)(&player[i]), sizeof(struct BzMember) ) <
  2492.             sizeof(struct BzMember) ) {
  2493.             perror("file_out");
  2494.             end_program(0);
  2495.             }
  2496.         }
  2497. }
  2498.  
  2499.  
  2500.  
  2501. void process_players( void )
  2502. {
  2503.     int i ;
  2504.  
  2505.     red_flag_held = blue_flag_held = FALSE ;
  2506.  
  2507.     for( i = ENEMY ; i < number_players ; i++ ) {
  2508.         activity[i] -= 1 ;
  2509.         if( activity[i] < 0 ) {
  2510.             drop_host( player[i].id ) ;
  2511.             delete_player( i, "was dropped" ) ;
  2512.             }
  2513.         else if( !never_have_flag ) {
  2514.             if( player[i].team == RED_TEAM ) {
  2515.                 if( HAS_BLUE_FLAG( player[i] ) ) {
  2516.                     blue_flag_held = TRUE ;
  2517.                     flag_x[BLUE_FLAG] = player[i].x ;
  2518.                     flag_y[BLUE_FLAG] = player[i].y ;
  2519.                     }
  2520.                 }
  2521.             else if( player[i].team == BLUE_TEAM ) {
  2522.                 if( HAS_RED_FLAG( player[i] ) ) {
  2523.                     red_flag_held = TRUE ;
  2524.                     flag_x[RED_FLAG] = player[i].x ;
  2525.                     flag_y[RED_FLAG] = player[i].y ;
  2526.                     }
  2527.                 }
  2528.             }
  2529.         if( hit_by[i] ) {
  2530.             hit_by[i] = MAX_HIT_BY_COUNT
  2531.                       - elapsed_sec_tenths( &time_of_death, ¤t_time ) ;
  2532.             if( hit_by[i] < 0 )
  2533.                 hit_by[i] = 0 ;
  2534.             }
  2535.         }
  2536.  
  2537.     if( !never_have_flag ) {
  2538.         if( player[SELF].team == RED_TEAM ) {
  2539.             if( HAS_BLUE_FLAG( player[SELF] ) ) {
  2540.                 if( blue_flag_held ) {
  2541.                     set_bulletin_color( teamColor[BLUE_TEAM] ) ;
  2542.                     post_new_message( 0, 1, "BLUE FLAG CONFLICT!!!" ) ;
  2543.                     player[SELF].team_flag = 0 ;
  2544.                     player_dropped_flag( &player[SELF] ) ;
  2545.                     }
  2546.                 else {
  2547.                     blue_flag_held = TRUE ;
  2548.                     flag_x[BLUE_FLAG] = player[SELF].x ;
  2549.                     flag_y[BLUE_FLAG] = player[SELF].y ;
  2550.                     }
  2551.                 }
  2552.             }
  2553.         else if( player[SELF].team == BLUE_TEAM ) {
  2554.             if( HAS_RED_FLAG( player[SELF] ) ) {
  2555.                 if( red_flag_held ) {
  2556.                     set_bulletin_color( teamColor[RED_TEAM] ) ;
  2557.                     post_new_message( 0, 1, "RED FLAG CONFLICT!!!" ) ;
  2558.                     player[SELF].team_flag = 0 ;
  2559.                     player_dropped_flag( &player[SELF] ) ;
  2560.                     }
  2561.                 else {
  2562.                     red_flag_held = TRUE ;
  2563.                     flag_x[RED_FLAG] = player[SELF].x ;
  2564.                     flag_y[RED_FLAG] = player[SELF].y ;
  2565.                     }
  2566.                 }
  2567.             }
  2568.         }
  2569. }
  2570.  
  2571.  
  2572.  
  2573. int read_rest_of_file_packet(
  2574.     void *packet,
  2575.     int size
  2576.     )
  2577. {
  2578.     int    nc_read ;
  2579.  
  2580.     size -= sizeof( BzId ) ;
  2581.  
  2582.     if( ( nc_read = read( in_fd, (char *)packet + sizeof( BzId ), size ) )
  2583.         != size ) {
  2584.         return( nc_read ) ;
  2585.         }
  2586.     else {
  2587.         return( 0 ) ;
  2588.         }
  2589. }
  2590.  
  2591.  
  2592.  
  2593. void file_in( void )
  2594. {
  2595.     int                no_chars_read ;
  2596.     union BzPacket    packet ;
  2597.     struct BzMember    input ;
  2598.     int                st = 0 ;
  2599.     int                i ;
  2600.     int                number ;
  2601.  
  2602.     i = 1 ;
  2603.     do {
  2604.         if( ( no_chars_read =
  2605.               read( in_fd, &(packet.bz_id), sizeof(packet.bz_id) )
  2606.             ) == sizeof(packet.bz_id) ) {
  2607.             switch( packet.bz_id ) {
  2608.                 case BZ :
  2609.                     i++ ;
  2610.                     if( ( st = read_rest_of_file_packet( &packet,
  2611.                         sizeof( packet.member ) ) ) == 0 ) {
  2612.                         packet.member.id++ ;
  2613.                         if( valid_keyed_host( packet.member.id,
  2614.                                               packet.member.key ) ) {
  2615.                             process_bz_packet( &(packet.member) ) ;
  2616.                             }
  2617.                         }
  2618.                     break ;
  2619.  
  2620.                 case BZMSG :
  2621.                     if( ( st = read_rest_of_file_packet( &packet,
  2622.                         sizeof( packet.notice ) ) ) == 0 ) {
  2623.                         packet.notice.id++ ;
  2624.                         process_bz_notice( &(packet.notice), NEUTRAL_TEAM ) ;
  2625.                         }
  2626.                     break ;
  2627.  
  2628.                 case BZREDMSG :
  2629.                     if( ( st = read_rest_of_file_packet( &packet,
  2630.                         sizeof( packet.notice ) ) ) == 0 ) {
  2631.                         packet.notice.id++ ;
  2632.                         process_bz_notice( &(packet.notice), RED_TEAM ) ;
  2633.                         }
  2634.                     break ;
  2635.  
  2636.                 case BZBLUEMSG :
  2637.                     if( ( st = read_rest_of_file_packet( &packet,
  2638.                         sizeof( packet.notice ) ) ) == 0 ) {
  2639.                         packet.notice.id++ ;
  2640.                         process_bz_notice( &(packet.notice), BLUE_TEAM ) ;
  2641.                         }
  2642.                     break ;
  2643.  
  2644.                 case BZLOGO_00 :
  2645.                     if( ( st = read_rest_of_file_packet( &packet,
  2646.                         sizeof( packet.logo ) ) ) == 0 ) {
  2647.                         packet.logo.id++ ;
  2648.                         if( ( number = find_player( packet.logo.id ) ) > 0 &&
  2649.                             tank_logo[number] == null_obj ) {
  2650.                             tank_logo[number] =
  2651.                                 create_logo( packet.logo.logo_info, 1,
  2652.                                              &(tank_logo_side[number]) ) ;
  2653.                             if( write_packets == file_out ) {
  2654.                                 send_to_file( &(packet.logo),
  2655.                                               sizeof( packet.logo ) ) ;
  2656.                                 }
  2657.                             }
  2658.                         }
  2659.                     break ;
  2660.  
  2661.                 case BZQUIT :
  2662.                     if( ( st = read_rest_of_file_packet( &packet,
  2663.                         sizeof( packet.ack ) ) ) == 0 ) {
  2664.                         if( ( number = find_player( packet.ack.id ) ) > 0 ) {
  2665.                             remove_host( packet.ack.id ) ;
  2666.                             delete_player( number, "quit" ) ;
  2667.                             }
  2668.                         }
  2669.                     break ;
  2670.  
  2671.                 case BZACK :
  2672.                 case BZINVALIDATE :
  2673.                     st = read_rest_of_file_packet( &packet,
  2674.                                                    sizeof( packet.ack ) ) ;
  2675.                     break ;
  2676.  
  2677.                 default :
  2678.                     fprintf( stderr, "%s: unknown packet type received in %s.",
  2679.                              basename, in_name ) ;
  2680.                     end_program( 1 ) ;
  2681.                     break ;
  2682.                 }
  2683.             if( st ) {
  2684.                 fprintf( stderr, "%s: bad packet read from %s.", basename,
  2685.                          in_name ) ;
  2686.                 end_program( 1 ) ;
  2687.                 }
  2688.             }
  2689.         else if( no_chars_read == 0 ) {
  2690.             if( lseek( in_fd, 0, SEEK_SET ) != 0 ) {
  2691.                 write_packets = no_op ;
  2692.                 }
  2693.             }
  2694.         else {
  2695.             perror( in_name ) ;
  2696.             end_program( 1 ) ;
  2697.             }
  2698.         } while( i < number_players ) ;
  2699.  
  2700.     process_players() ;
  2701. }
  2702.  
  2703.  
  2704.  
  2705.  
  2706.  
  2707.  
  2708. void process_bz_packet(
  2709.     struct BzMember *input
  2710.     )
  2711. {
  2712.     int        number ;
  2713.     int        killer ;
  2714.     int        score_mod ;
  2715.  
  2716.     /* either update existing player or create a new one */
  2717.     if( !( number = find_player( input->id ) ) ) {
  2718.         add_player( &number ) ;
  2719.         copy_player( number, input ) ;
  2720.         check_id( number ) ;
  2721.         set_bulletin_color( teamColor[input->team] ) ;
  2722.         post_new_message( 0, 1, "Added %s to %s team.", input->name,
  2723.                           teamName[input->team] ) ;
  2724. #if defined( NETDEBUGGER )
  2725.         show_player_list() ;
  2726. #endif /* defined( NETDEBUGGER ) */
  2727.         if( networking && !view_only ) {
  2728.             announce_logo = 1 ;
  2729.             add_host_to_census( input->id ) ;
  2730.             }
  2731.         if( !show_flags && !never_have_flag ) {
  2732.             if( input->team == RED_TEAM ) {
  2733.                 red_team_present = TRUE ;
  2734.                 }
  2735.             else if( input->team == BLUE_TEAM ) {
  2736.                 blue_team_present = TRUE ;
  2737.                 }
  2738.             if( red_team_present && blue_team_present ) {
  2739.                 show_flags = TRUE ;
  2740.                 post_new_message( 0, 1, "Flag capturing enabled." ) ;
  2741.                 }
  2742.             }
  2743.         }
  2744.  
  2745.     activity[number] = MAX_ACTIVITY ;
  2746.  
  2747.     /*
  2748.      * If player team changes....
  2749.      */
  2750.     if( input->team != player[number].team ) {
  2751.         set_bulletin_color( teamColor[input->team] ) ;
  2752.         post_new_message( 0, 1, "%s switched to %s team.", player[number].name,
  2753.             teamName[input->team] ) ;
  2754.         if( !show_flags && !never_have_flag ) {
  2755.             if( input->team == RED_TEAM ) {
  2756.                 red_team_present = TRUE ;
  2757.                 }
  2758.             else if( input->team == BLUE_TEAM ) {
  2759.                 blue_team_present = TRUE ;
  2760.                 }
  2761.             if( red_team_present && blue_team_present ) {
  2762.                 show_flags = TRUE ;
  2763.                 post_new_message( 0, 1, "Flag capturing enabled." ) ;
  2764.                 }
  2765.             }
  2766.         }
  2767.  
  2768.     /*
  2769.      * If player is transitioning from alive to dead...
  2770.      */
  2771.     if( IS_DEAD( *input ) && IS_ALIVE( player[number] ) ) {
  2772.         explosion_sfx( input->x - player[SELF].x,
  2773.                        input->y - player[SELF].y, player[SELF].head ) ;
  2774.         if( input->killed_by_id == player[SELF].id ||
  2775.             input->id == player[SELF].hit_by_id ) {
  2776.             level++ ;
  2777.             need_to_show_level = TRUE ;
  2778.             player[SELF].hit_by_id = 0 ;
  2779.             if( player[SELF].team != 0 &&
  2780.                 player[SELF].team == input->team ) {
  2781.                 score_mod = -1 ;
  2782.                 set_bulletin_color( teamColor[input->team] ) ;
  2783.                 post_new_message( 0, no_sfx, "Oops, killed %s.",
  2784.                     input->name ) ;
  2785.                 }
  2786.             else {
  2787.                 score_mod = 1 ;
  2788.                 post_new_message( 0, no_sfx, "Killed %s.", input->name ) ;
  2789.                 }
  2790.             switch( input->tank_type ) {
  2791.                 case 0:
  2792.                     player[SELF].score +=  50 * score_mod ;
  2793.                     break ;
  2794.                 case 1:
  2795.                     player[SELF].score +=  75 * score_mod ;
  2796.                     break ;
  2797.                 case 2:
  2798.                     player[SELF].score += 100 * score_mod ;
  2799.                     break ;
  2800.                 case 3:
  2801.                     player[SELF].score += 125 * score_mod ;
  2802.                     break ;
  2803.                 }
  2804.             need_to_show_score = TRUE ;
  2805.             }
  2806.         else {
  2807.             if( ( killer = find_player( input->killed_by_id ) ) > 0 ) {
  2808.                 post_new_message( 0, no_sfx, "%s was killed by %s.",
  2809.                                   input->name, player[killer].name ) ;
  2810.                 }
  2811.             else {
  2812.                 post_new_message( 0, no_sfx, "%s is dead.", input->name ) ;
  2813.                 }
  2814.             }
  2815.         }
  2816.  
  2817.     /*
  2818.      * If player's missile is transitioning from active to exploding...
  2819.      */
  2820.     if( input->msl_status < 0 && player[number].msl_status > 0 ) {
  2821.         explosion_sfx( input->msl_x - player[SELF].x,
  2822.                        input->msl_y - player[SELF].y,
  2823.                        player[SELF].head ) ;
  2824.         }
  2825.  
  2826.     /*
  2827.      * If player is transitioning from having a flag to dropping one...
  2828.      */
  2829.     if( !HAS_A_FLAG( *input ) && HAS_A_FLAG( player[number] ) ) {
  2830.         player_dropped_flag( input ) ;
  2831.         }
  2832.  
  2833.     /*
  2834.      * If player is transitioning from not having a flag to having one...
  2835.      */
  2836.     else if( HAS_A_FLAG( *input ) && !HAS_A_FLAG( player[number] ) ) {
  2837.         set_bulletin_color( teamColor[player[SELF].team] ) ;
  2838.         post_new_message( 0, 1, "%s grabbed %s flag.", player[number].name,
  2839.             HAS_RED_FLAG( *input ) ? "red" : "blue" ) ;
  2840.         if( input->team != player[SELF].team &&
  2841.             player[SELF].team != NEUTRAL_TEAM ) {
  2842.             sfx( SFX_FLAG_GRABBED ) ;
  2843.             }
  2844.         }
  2845.  
  2846.     /*
  2847.      * Update player.
  2848.      */
  2849.     copy_player( number, input ) ;
  2850.  
  2851. #if !defined( NETDEBUGGER )
  2852.     /*
  2853.      * If player has hit me, blow up.
  2854.      */
  2855.     if( input->hit_by_id == player[SELF].id && hit_by[number] == 0
  2856.         && IS_ALIVE( player[SELF] ) ) {
  2857.         blow_up_self( number ) ;
  2858.         }
  2859. #endif /* !defined( NETDEBUGGER ) */
  2860. }
  2861.  
  2862.  
  2863.  
  2864. static void process_bz_notice(
  2865.     struct BzNotice    *input,
  2866.     int team
  2867.     )
  2868. {
  2869. #if !defined( NETDEBUGGER )
  2870.     int    number ;
  2871.  
  2872.     if( valid_host( input->id ) && ( number = find_player( input->id ) ) > 0 ) {
  2873.         switch( team ) {
  2874.             case NEUTRAL_TEAM :
  2875.                 post_new_message( 0, 0, "From %s:", player[number].name ) ;
  2876.                 post_new_message( 0, 1, ">%s", input->out_message ) ;
  2877.                 break ;
  2878.  
  2879.             case RED_TEAM :
  2880.                 if( player[SELF].team == team ) {
  2881.                     set_bulletin_color( teamColor[RED_TEAM] ) ;
  2882.                     post_new_message( 0, 0, "From %s to RED team:",
  2883.                         player[number].name ) ;
  2884.                     set_bulletin_color( teamColor[RED_TEAM] ) ;
  2885.                     post_new_message( 0, 1, ">%s", input->out_message ) ;
  2886.                     }
  2887.                 break ;
  2888.  
  2889.             case BLUE_TEAM :
  2890.                 if( player[SELF].team == team ) {
  2891.                     set_bulletin_color( teamColor[BLUE_TEAM] ) ;
  2892.                     post_new_message( 0, 0, "From %s to BLUE team:",
  2893.                         player[number].name ) ;
  2894.                     set_bulletin_color( teamColor[BLUE_TEAM] ) ;
  2895.                     post_new_message( 0, 1, ">%s", input->out_message ) ;
  2896.                     }
  2897.                 break ;
  2898.             }
  2899.  
  2900.         if( write_packets == file_out ) {
  2901.             if( write( out_fd, (void *)input, sizeof(struct BzMember) )
  2902.                 < sizeof(struct BzMember) ) {
  2903.                 perror( "process_bz_notice" ) ;
  2904.                 end_program( 0 ) ;
  2905.                 }
  2906.             }
  2907.         }
  2908. #endif /* !defined( NETDEBUGGER ) */
  2909. }
  2910.  
  2911.  
  2912.  
  2913. /*------------------------------------------------------------------------------
  2914.  * Handle flag droppings...
  2915.  *----------------------------------------------------------------------------*/
  2916. static void player_dropped_flag(
  2917.     struct BzMember *fumbler
  2918.     )
  2919. {
  2920.     int        his_team ;
  2921.     int        other_team ;
  2922.     int        his_flag ;
  2923.     int        other_flag ;
  2924.     int        killer ;
  2925.     float    his_flag_home_x ;
  2926.     float    his_flag_home_y ;
  2927.     float    other_flag_home_x ;
  2928.     float    other_flag_home_y ;
  2929.     Boolean    his_flag_held ;
  2930.  
  2931.     his_team = fumbler->team ;
  2932.  
  2933.     if( player[SELF].id == fumbler->id )
  2934.         need_to_show_flag_st = TRUE ;
  2935.  
  2936.     /*
  2937.      * Initialize his team/other team indicators.
  2938.      */
  2939.     switch( his_team ) {
  2940.  
  2941.         case RED_TEAM :
  2942.             other_team = BLUE_TEAM ;
  2943.             his_flag_home_x = RED_FLAG_HOME_X ;
  2944.             his_flag_home_y = RED_FLAG_HOME_Y ;
  2945.             other_flag_home_x = BLUE_FLAG_HOME_X ;
  2946.             other_flag_home_y = BLUE_FLAG_HOME_Y ;
  2947.             his_flag = RED_FLAG ;
  2948.             other_flag = BLUE_FLAG ;
  2949.             his_flag_held = red_flag_held ;
  2950.             break ;
  2951.  
  2952.         case BLUE_TEAM :
  2953.             other_team = RED_TEAM ;
  2954.             his_flag_home_x = BLUE_FLAG_HOME_X ;
  2955.             his_flag_home_y = BLUE_FLAG_HOME_Y ;
  2956.             other_flag_home_x = RED_FLAG_HOME_X ;
  2957.             other_flag_home_y = RED_FLAG_HOME_Y ;
  2958.             his_flag = BLUE_FLAG ;
  2959.             other_flag = RED_FLAG ;
  2960.             his_flag_held = blue_flag_held ;
  2961.             break ;
  2962.  
  2963.         default :
  2964.             return ;
  2965.  
  2966.         }
  2967.  
  2968.     /*
  2969.      * If dropped flag due to reset, reset it and signal.
  2970.      */
  2971.     if( LOST_FLAG( *fumbler ) ) {
  2972.         flag_x[other_flag] = other_flag_home_x ;
  2973.         flag_y[other_flag] = other_flag_home_y ;
  2974.         set_bulletin_color( teamColor[other_team] ) ;
  2975.         post_new_message( 0, 1, "%s flag was reset.", teamName[other_team] ) ;
  2976.         }
  2977.     else {
  2978.         set_bulletin_color( teamColor[other_team] ) ;
  2979.         post_new_message( 0, 1, "%s flag was dropped by %s.",
  2980.                           teamName[other_team], fumbler->name ) ;
  2981.         if( IS_ALIVE( *fumbler ) ) {
  2982.             flag_x[other_flag] = fumbler->x ;
  2983.             flag_y[other_flag] = fumbler->y ;
  2984.             /*
  2985.              * Check if flag was dropped in home zone for capture.
  2986.              */
  2987.             if( his_flag_home_x - FLAG_HOME_PERIM < flag_x[other_flag] &&
  2988.                 his_flag_home_x + FLAG_HOME_PERIM > flag_x[other_flag] &&
  2989.                 his_flag_home_y - FLAG_HOME_PERIM < flag_y[other_flag] &&
  2990.                 his_flag_home_y + FLAG_HOME_PERIM > flag_y[other_flag] ) {
  2991.                 teamBonus[other_team] -= FLAG_BONUS ;
  2992.                 teamBonus[his_team]   += FLAG_BONUS ;
  2993.                 /*
  2994.                  * If on the same team, signal bonus.
  2995.                  */
  2996.                 if( player[SELF].team == his_team ) {
  2997.                     set_bulletin_color( teamColor[his_team] ) ;
  2998.                     post_new_message( 0, 1, "Team bonus for flag capture "
  2999.                                       "by %s.", fumbler->name ) ;
  3000.                     sfx( SFX_FLAG_WON ) ;
  3001.                     /*
  3002.                      * Personal bonus if I dropped the flag.
  3003.                      */
  3004.                     if( player[SELF].id == fumbler->id ) {
  3005.                         switch( player[SELF].tank_type ) {
  3006.                             case 0:
  3007.                                 player[SELF].score += PERSONAL_BONUS - 50 ;
  3008.                                 break ;
  3009.                             case 1:
  3010.                                 player[SELF].score += PERSONAL_BONUS - 75 ;
  3011.                                 break ;
  3012.                             case 2:
  3013.                                 player[SELF].score += PERSONAL_BONUS - 100 ;
  3014.                                 break ;
  3015.                             case 3:
  3016.                                 player[SELF].score += PERSONAL_BONUS - 125 ;
  3017.                                 break ;
  3018.                             }
  3019.                         need_to_show_score = TRUE ;
  3020.                         }
  3021.                     }
  3022.                 /*
  3023.                  * If on the other team and have his flag, lose it, and signal
  3024.                  * that it has been reset.
  3025.                  */
  3026.                 else if( player[SELF].team == other_team ) {
  3027.                     set_bulletin_color( teamColor[other_team] ) ;
  3028.                     post_new_message( 0, 1, "Team penalty for flag capture "
  3029.                                       "by %s.", fumbler->name ) ;
  3030.                     sfx( SFX_FLAG_LOST ) ;
  3031.                     if( HAS_A_FLAG( player[SELF] ) ) {
  3032.                         set_bulletin_color( teamColor[other_team] ) ;
  3033.                         post_new_message( 0, 0, "%s flag was reset.",
  3034.                                           teamName[his_team] ) ;
  3035.                         player[SELF].team_flag = RESET_FLAG_BIT ;
  3036.                         flag_x[his_flag] = his_flag_home_x ;
  3037.                         flag_y[his_flag] = his_flag_home_y ;
  3038.                         }
  3039.                     }
  3040.                 flag_x[other_flag] = other_flag_home_x ;
  3041.                 flag_y[other_flag] = other_flag_home_y ;
  3042.                 /*
  3043.                  * If his flag isn't held, go ahead and reset it.  (If it
  3044.                  * is held, wait for "holder" to signal that they lost it.)
  3045.                  */
  3046.                 if( !his_flag_held ) {
  3047.                     flag_x[his_flag] = his_flag_home_x ;
  3048.                     flag_y[his_flag] = his_flag_home_y ;
  3049.                     set_bulletin_color( teamColor[his_team] ) ;
  3050.                     post_new_message( 0, 0, "%s flag was reset.",
  3051.                                       teamName[his_team] ) ;
  3052.                     }
  3053.                 }
  3054.             }
  3055.         /*
  3056.          * Player dropped the flag due to death.  Reset flag.
  3057.          */
  3058.         else {
  3059.             flag_x[other_flag] = other_flag_home_x ;
  3060.             flag_y[other_flag] = other_flag_home_y ;
  3061.             teamBonus[other_team] += FLAG_BONUS ;
  3062.             if( player[SELF].team == other_team ) {
  3063.                 set_bulletin_color( teamColor[other_team] ) ;
  3064.                 if( ( killer = find_player( fumbler->killed_by_id ) ) > 0 ) {
  3065.                     post_new_message( 0, 1, "Team bonus for flag defense "
  3066.                                       "by %s.", player[killer].name ) ;
  3067.                     }
  3068.                 else {
  3069.                     post_new_message( 0, 1, "Team bonus for flag defense." ) ;
  3070.                     }
  3071.                 }
  3072.             }
  3073.         }
  3074. }
  3075.  
  3076.  
  3077.  
  3078. void network_out( void )
  3079. {
  3080.     int no_chars_sent ;
  3081.  
  3082.     no_chars_sent = sendto( out_fd, (char *)(&player[SELF]),
  3083.                             sizeof(struct BzMember), 0, &out_addr,
  3084.                             out_addrlen ) ;
  3085.     if( no_chars_sent < sizeof(struct BzMember) ) {
  3086.         perror( "network_out" ) ;
  3087.         end_program( 0 ) ;
  3088.         }
  3089.  
  3090.     if( !never_have_flag ) {
  3091.         check_to_send_census() ;
  3092.         }
  3093. }
  3094.  
  3095.  
  3096.  
  3097. void send_out(
  3098.     void *buf,
  3099.     int size
  3100.     )
  3101. {
  3102. #if !defined( NETDEBUGGER )
  3103.     if( write_packets == network_out ) {
  3104.         send_to_network( buf, size ) ;
  3105.         }
  3106.     else if( write_packets == file_out ) {
  3107.         send_to_file( buf, size ) ;
  3108.         }
  3109. #else
  3110.     write( 1, buf, size ) ;
  3111. #endif /* !defined( NETDEBUGGER ) */
  3112. }
  3113.  
  3114.  
  3115.  
  3116. void send_to_file(
  3117.     void *buf,
  3118.     int size
  3119.     )
  3120. {
  3121.     int no_chars_sent ;
  3122.  
  3123.     no_chars_sent = write( out_fd, buf, size ) ;
  3124.     if( no_chars_sent < size ) {
  3125.         perror( "send_to_file" ) ;
  3126.         end_program( 0 ) ;
  3127.         }
  3128. }
  3129.  
  3130.  
  3131.  
  3132. void send_to_network(
  3133.     char *buf,
  3134.     int size
  3135.     )
  3136. {
  3137.     int no_chars_sent ;
  3138.  
  3139.     no_chars_sent = sendto( out_fd, buf, size, 0, &out_addr, out_addrlen ) ;
  3140.     if( no_chars_sent < size ) {
  3141.         perror( "send_to_network" ) ;
  3142.         end_program( 0 ) ;
  3143.         }
  3144. }
  3145.  
  3146.  
  3147.  
  3148. void network_in( void )
  3149. {
  3150.     int                no_chars_received ;
  3151.     union BzPacket    packet ;
  3152.     struct BzAck    ack ;
  3153.     int                st = 0 ;
  3154.     int                number ;
  3155.     int                socket_empty = 0 ;
  3156.     static int        newer = 0 ;
  3157.  
  3158.     while( !socket_empty ) {
  3159.         no_chars_received = recvfrom( in_fd, (char *)(&packet),
  3160.                                       sizeof(union BzPacket), 0, &in_addr,
  3161.                                       &in_addrlen ) ;
  3162.         if( no_chars_received < 0 && errno == EWOULDBLOCK ) {
  3163.             socket_empty = 1 ;
  3164.             }
  3165.         else {
  3166.             switch( packet.bz_id ) {
  3167.                 case BZ :
  3168.                     if( no_chars_received == sizeof( struct BzMember ) ) {
  3169.                         if( view_only || valid_host( packet.member.id ) ) {
  3170.                             process_bz_packet( &(packet.member) ) ;
  3171.                             }
  3172.                         else if ( view_only ) {
  3173.                             if( valid_keyed_host( packet.ack.id,
  3174.                                                   packet.ack.key ) ) {
  3175.                                 process_bz_packet( &(packet.member) ) ;
  3176.                                 }
  3177.                             }
  3178.                         /*
  3179.                          * New player, send out acknowledge packet.
  3180.                          */
  3181.                         else if( number_players < MAXPLAYERS &&
  3182.                                  should_acknowledge( packet.member.id,
  3183.                                                      packet.member.key ) ) {
  3184.                             send_acknowledgement( packet.member.id ) ;
  3185.                             }
  3186.                         }
  3187.                     else {
  3188.                         st = sizeof( struct BzMember ) ;
  3189.                         }
  3190.                     break ;
  3191.  
  3192.                 case BZMSG :
  3193.                     if( no_chars_received == sizeof( struct BzNotice ) ) {
  3194.                         process_bz_notice( &(packet.notice), NEUTRAL_TEAM ) ;
  3195.                         }
  3196.                     else {
  3197.                         st = sizeof( struct BzNotice ) ;
  3198.                         }
  3199.                     break ;
  3200.  
  3201.                 case BZREDMSG :
  3202.                     if( no_chars_received == sizeof( struct BzNotice ) ) {
  3203.                         process_bz_notice( &(packet.notice), RED_TEAM ) ;
  3204.                         }
  3205.                     else {
  3206.                         st = sizeof( struct BzNotice ) ;
  3207.                         }
  3208.                     break ;
  3209.  
  3210.                 case BZBLUEMSG :
  3211.                     if( no_chars_received == sizeof( struct BzNotice ) ) {
  3212.                         process_bz_notice( &(packet.notice), BLUE_TEAM ) ;
  3213.                         }
  3214.                     else {
  3215.                         st = sizeof( struct BzNotice ) ;
  3216.                         }
  3217.                     break ;
  3218.  
  3219.                 case BZLOGO_00 :
  3220.                     if( no_chars_received == sizeof( packet.logo ) ) {
  3221.                         if( ( number = find_player( packet.logo.id ) ) > 0 &&
  3222.                             tank_logo[number] == null_obj ) {
  3223.                             tank_logo[number] =
  3224.                                 create_logo( packet.logo.logo_info, 1,
  3225.                                              &(tank_logo_side[number]) ) ;
  3226.                             }
  3227.                         }
  3228.                     break ;
  3229.  
  3230.                 case BZQUIT :
  3231.                     if( no_chars_received == sizeof( struct BzAck ) ) {
  3232.                         if( ( number = find_player( packet.ack.id ) ) > 0 ) {
  3233.                             remove_host( packet.ack.id ) ;
  3234.                             delete_player( number, "quit" ) ;
  3235.                             }
  3236.                         /*
  3237.                          * Trial stuff.
  3238.                          */
  3239.                         else {
  3240.                             quit_host( packet.ack.id ) ;
  3241.                             }
  3242.                         }
  3243.                     break ;
  3244.  
  3245.                 case BZACK :
  3246.                     if( no_chars_received == sizeof( struct BzAck ) ) {
  3247.                         /*
  3248.                          * If acknowledging SELF, add to list of valid hosts.
  3249.                          */
  3250.                         if( packet.ack.ack_id == player[SELF].id ) {
  3251.                             valid_keyed_host( packet.ack.id, packet.ack.key ) ;
  3252.                             }
  3253.                         }
  3254.                     else {
  3255.                         st = sizeof( struct BzAck ) ;
  3256.                         }
  3257.                     break ;
  3258.  
  3259.                 case BZDROP :
  3260.                     if( no_chars_received == sizeof( struct BzAck ) ) {
  3261.                         /*
  3262.                          * If dropping SELF, note dropped status with host.
  3263.                          */
  3264.                         if( packet.ack.ack_id == player[SELF].id &&
  3265.                             valid_host( packet.ack.id ) ) {
  3266.                             dropped_by_host( packet.ack.id ) ;
  3267.                             if( ( number = find_player( packet.ack.id ) ) > 0 ){
  3268.                                 delete_player( number, "was dropped" ) ;
  3269.                                 }
  3270.                             }
  3271.                         }
  3272.                     else {
  3273.                         st = sizeof( struct BzAck ) ;
  3274.                         }
  3275.                     break ;
  3276.  
  3277.                 case BZINVALIDATE :
  3278.                     if( no_chars_received == sizeof( struct BzAck ) ) {
  3279.                         /*
  3280.                          * If invalidating SELF, invalidate in kind.
  3281.                          */
  3282.                         if( packet.ack.ack_id == player[SELF].id &&
  3283.                             valid_host( packet.ack.id ) ) {
  3284.                             dprintf( "%s: received invalidate packet from %s\n",
  3285.                                 print_time(),
  3286.                                 host_name_from_id( packet.ack.id ) ) ;
  3287.                             invalidate_host( packet.ack.id ) ;
  3288.                             if( ( number = find_player( packet.ack.id ) ) > 0 ){
  3289.                                 delete_player( number, "was dropped" ) ;
  3290.                                 }
  3291.                             }
  3292.                         }
  3293.                     else {
  3294.                         st = sizeof( struct BzAck ) ;
  3295.                         }
  3296.                     break ;
  3297.  
  3298.                 case BZCENSUS :
  3299.                     if( no_chars_received == sizeof( struct BzCensus ) ) {
  3300.                         if( valid_host( packet.census.id ) ) {
  3301.                             process_bz_census( &(packet.census) ) ;
  3302.                             }
  3303.                         }
  3304.                     else {
  3305.                         st = sizeof( struct BzCensus ) ;
  3306.                         }
  3307.                     break ;
  3308.  
  3309.                 default :
  3310.                     if( packet.bz_id > BZ &&
  3311.                         ( packet.bz_id & 0xffffff00 ) == (BZ & 0xffffff00) &&
  3312.                         newer == 0 ) {
  3313.                         newer = 1 ;
  3314.                         printf( "\n\nAn newer version of %s is being played on "
  3315.                                 "the net.\n\n", basename ) ;
  3316.                         }
  3317.                     break ;
  3318.                 }
  3319.             if( st ) {
  3320.                 fprintf( stderr, "received odd packet size of %d instead of "
  3321.                          "%d! (id = 0x%08x)\n", no_chars_received, st,
  3322.                          packet.bz_id ) ;
  3323.                 st = 0 ;
  3324.                 }
  3325.             }
  3326.         }
  3327.  
  3328.     process_players() ;
  3329. }
  3330.  
  3331.  
  3332.  
  3333. void blow_up_self(
  3334.     int killer
  3335.     )
  3336. {
  3337.     if( !view_only ) {
  3338.         if( killer < 0 ) {
  3339.             post_new_message( 0, no_sfx, "Vaporized by force field." ) ;
  3340.             player[SELF].killed_by_id = 0 ;
  3341.             }
  3342.         else {
  3343.             post_new_message( 0, no_sfx, "%s by %s.",
  3344.                 ( player[killer].hit_type == HIT_BY_MISSILE ) ? "Killed" :
  3345.                 "Mined", player[killer].name ) ;
  3346.             player[SELF].killed_by_id = killer ;
  3347.             hit_by[killer] = MAX_HIT_BY_COUNT ;
  3348.             }
  3349.  
  3350.  
  3351.         sfx( SFX_EXPLOSION ) ;
  3352.  
  3353.         guiding = FALSE ;
  3354.         reset_mouse() ;
  3355.         player[SELF].status = MAX_DEAD_STATUS ;
  3356.         copy_time( &time_of_death, ¤t_time ) ;
  3357.  
  3358.         if( !solo ) {
  3359.             switch( player[SELF].tank_type ) {
  3360.                 case 0:
  3361.                     player[SELF].score -=  50 ;
  3362.                     break ;
  3363.                 case 1:
  3364.                     player[SELF].score -=  75 ;
  3365.                     break ;
  3366.                 case 2:
  3367.                     player[SELF].score -= 100 ;
  3368.                     break ;
  3369.                 case 3:
  3370.                     player[SELF].score -= 125 ;
  3371.                     break ;
  3372.                 }
  3373.             }
  3374.  
  3375.         need_to_show_score = TRUE ;
  3376.         left_track = right_track = 0.0f ;
  3377.         vx[SELF] = vy[SELF] = 0.0f ;
  3378.         loading_missile = 0 ;
  3379.  
  3380.         if( HAS_A_FLAG( player[SELF] ) ) {
  3381.             player_dropped_flag( &player[SELF] ) ;
  3382.             player[SELF].team_flag = 0 ;
  3383.             }
  3384.  
  3385.         if( sending_msg == SENDING_NO_MAIL ) {
  3386.             ol_mode = 1 ;
  3387.             setTranslations( deadTransTable ) ;
  3388.             }
  3389.         else {
  3390.             ol_mode = 0 ;
  3391.             setTranslations( deadMailTransTable ) ;
  3392.             }
  3393.         GLXwinset( display, radar_ol_window ) ;
  3394.         drawOverlay() ;
  3395.         GLXwinset( display, base_window ) ;
  3396.         }
  3397. }
  3398.  
  3399.  
  3400.  
  3401. int find_player(
  3402.     long id
  3403.     )
  3404. {
  3405.     int    i ;
  3406.     int    found ;
  3407.  
  3408.     found = 0 ;
  3409.     i = 1 ;
  3410.     while( i < number_players && !found ) {
  3411.         if( player[i].id == id ) found = i ;
  3412.         i++ ;
  3413.         }
  3414.  
  3415.     return(found);
  3416. }
  3417.  
  3418.  
  3419.  
  3420. void add_player( int *number )
  3421. {
  3422.     if( number_players <= MAXPLAYERS ) {
  3423.         *number = number_players ;
  3424.         number_players++ ;
  3425.         tank_logo[*number] = null_obj ;
  3426.         need_to_show_players = TRUE ;
  3427.         }
  3428.     else {
  3429.         printf( "Maximum number (%d) of players exceeded.\n", MAXPLAYERS ) ;
  3430.         end_program(0);
  3431.         }
  3432. }
  3433.  
  3434.  
  3435.  
  3436. void delete_player(
  3437.     int i,
  3438.     char *verb
  3439.     )
  3440. {
  3441.     int        j ;
  3442.  
  3443.     post_new_message( 0, 1, "%s %s.", player[i].name, verb ) ;
  3444.  
  3445.     if( networking && !view_only ) {
  3446.         remove_host_from_census( player[i].id ) ;
  3447.         dprintf( "%s: %s %s.\n", print_time(),
  3448.                 host_name_from_id( player[i].id ), verb ) ;
  3449.         }
  3450.  
  3451.     for( j = i ; j < number_players-1 ; j++ ) {
  3452.         copy_player( j, &(player[j+1]) ) ;
  3453.         tank_logo[j] = tank_logo[j+1] ;
  3454.         activity[j] = activity[j+1] ;
  3455.         hit_by[j] = hit_by[j+1] ;
  3456.         bcopy( &(deadline[j+1]), &(deadline[j]), sizeof( deadline[j] ) ) ;
  3457.         }
  3458.  
  3459.     reset_viewing_order() ;
  3460.  
  3461.     number_players-- ;
  3462.     hit_by[number_players] = 0 ;
  3463.     activity[number_players] = 0 ;
  3464.     tank_logo[number_players] = null_obj ;
  3465.     need_to_show_players = TRUE ;
  3466. #if defined( NETDEBUGGER )
  3467.     show_player_list() ;
  3468. #endif /* defined( NETDEBUGGER ) */
  3469.  
  3470.     if( view_only && show_copilot_view ) {
  3471.         if( number_players == 1 ) {
  3472.             show_copilot_view = FALSE ;
  3473.             }
  3474.         else if( copilot_player == i ) {
  3475.             next_copilot_view() ;
  3476.             }
  3477.         else if( copilot_player > i ) {
  3478.             copilot_player-- ;
  3479.             }
  3480.         }
  3481. }
  3482.  
  3483.  
  3484.  
  3485. void copy_player(
  3486.     int k,
  3487.     struct BzMember *psrc
  3488.     )
  3489. {
  3490.     bcopy( psrc, &(player[k]), sizeof( struct BzMember ) ) ;
  3491. }
  3492.  
  3493.  
  3494.  
  3495. void check_name( void )
  3496. {
  3497.     char temp[NAMELEN] ;
  3498.     unsigned i ;
  3499.     unsigned duplicate = 0 ;
  3500.  
  3501.     for( i = ENEMY ; i < number_players ; i++ ) {
  3502.         if( !strcmp( player[SELF].name, player[i].name ) ) duplicate = 1 ;
  3503.         }
  3504.  
  3505.     if( duplicate ) {
  3506.         cuserid( temp ) ;
  3507.         if( strncmp( player[SELF].name, temp, NAMELEN-1 ) == 0 ) {
  3508.             i = strlen( player[SELF].name ) ;
  3509.             if( i < NAMELEN - 3 ) {
  3510.                 player[SELF].name[i  ] = '_' ;
  3511.                 player[SELF].name[i+1] = 'a' + ( rand() % 26 ) ;
  3512.                 player[SELF].name[i+2] = '\0' ;
  3513.                 }
  3514.             else if( i < NAMELEN - 2 ) {
  3515.                 player[SELF].name[i  ] = 'a' + ( rand() % 26 ) ;
  3516.                 player[SELF].name[i+1] = '\0' ;
  3517.                 }
  3518.             else {
  3519.                 player[SELF].name[NAMELEN-2] = 'a' + ( rand() % 26 ) ;
  3520.                 }
  3521.             }
  3522.         else {
  3523.             strncpy( player[SELF].name, temp, NAMELEN );
  3524.             }
  3525.         player[SELF].name[NAMELEN-1] = '\0' ;
  3526.         post_new_message( 0, 1, "Modified name to `%s'.", player[SELF].name ) ;
  3527.         name_count = 0 ;
  3528.         }
  3529. }
  3530.  
  3531.  
  3532.  
  3533. void check_id(
  3534.     int n
  3535.     )
  3536. {
  3537.     struct in_addr    addr ;
  3538.     struct hostent    *hp ;
  3539.  
  3540.     if( player[n].id == player[SELF].id ) {
  3541.         addr.s_addr = player[n].id ;
  3542.         hp = gethostbyaddr( &addr, sizeof(addr), AF_INET ) ;
  3543.         fprintf( stderr, "\n%s@%s is using your host id!\n\n", player[n].name,
  3544.                  hp ? hp->h_name : inet_ntoa(addr) ) ;
  3545.         end_program( 1 ) ;
  3546.         }
  3547. }
  3548.  
  3549.  
  3550. void file_name( char *name )
  3551. {
  3552.     char temp[NAMELEN] ;
  3553.     unsigned i ;
  3554.     unsigned l ;
  3555.  
  3556.     cuserid( temp ) ;
  3557.     l = strlen( temp );
  3558.     name[ 0] = '/' ;
  3559.     name[ 1] = 't' ;
  3560.     name[ 2] = 'm' ;
  3561.     name[ 3] = 'p' ;
  3562.     name[ 4] = '/' ;
  3563.     name[ 5] = '.' ;
  3564.     name[ 6] = 'T' ;
  3565.     name[ 7] = 'M' ;
  3566.     name[ 8] = 'P' ;
  3567.     name[ 9] = 'a' ;
  3568.     name[10] = '0' ;
  3569.     name[11] = '0' ;
  3570.     name[12] = '0' ;
  3571.     name[13] = '0' ;
  3572.     name[14] = '0' ;
  3573.     name[15] = '\0';
  3574.     for( i = 0 ; i < l ; i++ )
  3575.         name[10+i] = (char)('0' + temp[i] % 10) ;
  3576. }
  3577.  
  3578.  
  3579.  
  3580. void check_quit_time( void )
  3581. {
  3582.     FILE *f ;
  3583.     long clock_old, clock_new ;
  3584.  
  3585.     player[SELF].score = 0 ;
  3586.     file_name( time_name );
  3587.     if( ( f = fopen( time_name, "r" ) ) != NULL ) {
  3588.         if( fscanf( f, "%ld\n", &clock_old ) == 1 ) {
  3589.             time( &clock_new ) ;
  3590.             if( (clock_new - clock_old) < 120 ) {
  3591.                 fscanf( f, "%d", &(player[SELF].score) ) ;
  3592.                 if( player[SELF].score > 0 )
  3593.                     player[SELF].score = 0 ;
  3594.                 else
  3595.                     player[SELF].score -= 100 ;
  3596.                 }
  3597.             }
  3598.             fclose(f);
  3599.         }
  3600. }
  3601.  
  3602.  
  3603.  
  3604. void set_quit_time( void )
  3605. {
  3606.     FILE *f ;
  3607.     long clock_new ;
  3608.  
  3609.     file_name( time_name );
  3610.     if( ( f = fopen( time_name, "w" ) ) != NULL ) {
  3611.         time( &clock_new ) ;
  3612.         fprintf( f, "%ld\n", clock_new ) ;
  3613.         fprintf( f, "%d", player[SELF].score ) ;
  3614.         fclose(f);
  3615.         }
  3616. }
  3617.  
  3618.  
  3619.  
  3620. void send_out_message( void )
  3621. {
  3622.     int            no_chars_sent ;
  3623.     char        sombuf[80] ;
  3624.     Colorindex    c ;
  3625.  
  3626.     switch( sending_msg ) {
  3627.         case SENDING_ALL_MAIL :
  3628.             mail.bz_id = BZMSG ;
  3629.             mail.id    = player[SELF].id ;
  3630.             sombuf[0] = '\0' ;
  3631.             c = green ;
  3632.             break ;
  3633.         case SENDING_TEAM_MAIL :
  3634.             switch( player[SELF].team ) {
  3635.                 default :
  3636.                 case NEUTRAL_TEAM :
  3637.                     mail.bz_id = BZMSG ;
  3638.                     mail.id    = player[SELF].id ;
  3639.                     sombuf[0] = '\0' ;
  3640.                     c = teamColor[NEUTRAL_TEAM] ;
  3641.                     break ;
  3642.                 case RED_TEAM :
  3643.                     mail.bz_id = BZREDMSG ;
  3644.                     mail.id    = player[SELF].id ;
  3645.                     strcpy( sombuf, " to RED team" ) ;
  3646.                     c = teamColor[RED_TEAM] ;
  3647.                     break ;
  3648.                 case BLUE_TEAM :
  3649.                     mail.bz_id = BZBLUEMSG ;
  3650.                     mail.id    = player[SELF].id ;
  3651.                     strcpy( sombuf, " to BLUE team" ) ;
  3652.                     c = teamColor[BLUE_TEAM] ;
  3653.                     break ;
  3654.                 }
  3655.             break ;
  3656.         default :
  3657.             return ;
  3658.         }
  3659.     set_bulletin_color( c ) ;
  3660.     post_new_message( 0, 0, "Broadcast%s:", sombuf ) ;
  3661.     set_bulletin_color( c ) ;
  3662.     post_new_message( 0, 1, ">%s", mail.out_message ) ;
  3663.     if( write_packets == network_out ) {
  3664.         send_to_network( (char *)&mail, sizeof( mail ) ) ;
  3665.         no_chars_sent = sizeof(struct BzMember) ;
  3666.         }
  3667.     else if( write_packets == file_out ) {
  3668.         no_chars_sent = write( out_fd, (void *)&mail, sizeof(struct BzMember) );
  3669.         }
  3670.     else {
  3671.         no_chars_sent = sizeof(struct BzMember) ;
  3672.         }
  3673.     if( no_chars_sent < sizeof(struct BzMember) ) {
  3674.         perror( "send_out_message" ) ;
  3675.         end_program( 0 ) ;
  3676.         }
  3677. }
  3678.  
  3679.  
  3680.  
  3681. static void tran_rot_show(
  3682.     float x,
  3683.     float y,
  3684.     float heading,
  3685.     GL_Object obj
  3686.     )
  3687. {
  3688.     if( obj != null_obj ) {
  3689.         pushmatrix() ;
  3690.         translate( x, y, 0.f ) ;
  3691.         rot( -heading, 'z' ) ;
  3692.         callobj( obj ) ;
  3693.         popmatrix() ;
  3694.         }
  3695. }
  3696.  
  3697.  
  3698.  
  3699. static void input_message(
  3700.     int init
  3701.     )
  3702. {
  3703.     char        *s ;
  3704.     unsigned    add_char = 0 ;
  3705.     static int    nochars = 0 ;
  3706.  
  3707.     if( init ) {
  3708.         nochars = 0 ;
  3709.         mail.out_message[nochars] = '\0' ;
  3710.         add_char = 1 ;
  3711.         }
  3712.  
  3713.     s = mail_buffer ;
  3714.     while( mail_ptr ) {
  3715.         if( *s == '\r' ) {
  3716.             if( nochars > 0 ) {
  3717.                 send_out_message() ;
  3718.                 }
  3719.             sending_msg = SENDING_NO_MAIL ;
  3720.             mail.out_message[0] = '\0' ;
  3721.             ol_mode = 1 ;
  3722.             if( IS_ALIVE( player[SELF] ) ) {
  3723.                 setTranslations( mainTransTable ) ;
  3724.                 }
  3725.             else {
  3726.                 setTranslations( deadTransTable ) ;
  3727.                 GLXwinset( display, radar_ol_window ) ;
  3728.                 drawOverlay() ;
  3729.                 GLXwinset( display, base_window ) ;
  3730.                 }
  3731.             nochars = 0 ;
  3732.             mail.out_message[nochars] = '\0' ;
  3733.             }
  3734.         else if( *s == '\010' ) {
  3735.             nochars -= ( nochars > 0 ) ? 1 : 0 ;
  3736.             mail.out_message[nochars] = '\0' ;
  3737.             }
  3738.         else if( nochars < MAIL_MSG_SIZE ) {
  3739.             mail.out_message[nochars++] = *s ;
  3740.             mail.out_message[nochars] = '\0' ;
  3741.             }
  3742.         s++ ;
  3743.         mail_ptr-- ;
  3744.         add_char = 1 ;
  3745.         }
  3746.     if( add_char ) {
  3747.         need_to_show_out_message = TRUE ;
  3748.         }
  3749. }
  3750.  
  3751.  
  3752.  
  3753. static void usage( void )
  3754. {
  3755.     fprintf( stderr, "Usage:\n\n" ) ;
  3756.     fprintf( stderr, "\t%s [-n name] [-i infile] [-o outfile] [-T ttl]"
  3757.              " [-red | -blue | -pick]\n", basename );
  3758.     fprintf( stderr, "\t   [-noflag] [-public | -private key]"
  3759.              " [-logo logofile] [-vo] [-fast]\n\n" ) ;
  3760.     fprintf( stderr, "\t%s -solo [-practice level] [-kids] [-n name]"
  3761.              " [-logo logofile] [-fast]\n\n", basename ) ;
  3762.     fprintf( stderr, "\t%s -version\n\n", basename ) ;
  3763.     end_program( 1 ) ;
  3764. }
  3765.  
  3766.  
  3767.  
  3768. static void move_args(
  3769.     int argc,
  3770.     char **argv,
  3771.     int    start,
  3772.     int    n
  3773.      )
  3774. {
  3775.     int i ;
  3776.     char *t ;
  3777.  
  3778.     while( n-- ) {
  3779.         t = argv[start] ;
  3780.         for( i = start ; i < argc - 1 ; i++ ) {
  3781.             argv[i] = argv[i+1] ;
  3782.             }
  3783.         argv[argc-1] = t ;
  3784.         }
  3785. }
  3786.  
  3787.  
  3788.  
  3789. static void parse_args(
  3790.     int *argc,
  3791.     char **argv
  3792.     )
  3793. {
  3794.     int    i ;
  3795.     int    key ;
  3796.     int    argn = 0 ;
  3797.  
  3798.     if( ( basename = strrchr( argv[0], '/' ) ) == NULL )
  3799.         basename = argv[0] ;
  3800.     else
  3801.         basename++ ;
  3802.  
  3803.     for( i = 1 ; i < *argc ; i++ ) {
  3804.         argn++ ;
  3805.         if( argv[i][0] == '-' ) {
  3806.             if( !strcmp( argv[i]+1, "n" ) ) {
  3807.                 if( i + 1 == *argc ) {
  3808.                     usage() ;
  3809.                     }
  3810.                 else {
  3811.                     strncpy( player_name, argv[i+1], NAMELEN ) ;
  3812.                     player_name[NAMELEN-1] = '\0' ;
  3813.                     move_args( *argc, argv, i, 2 ) ;
  3814.                     *argc -= 2 ;
  3815.                     i-- ;
  3816.                     }
  3817.                 }
  3818.             else if( !strcmp( argv[i]+1, "logo" ) ) {
  3819.                 if( i + 1 == *argc ) {
  3820.                     usage() ;
  3821.                     }
  3822.                 else {
  3823.                     logo_file = argv[i+1] ;
  3824.                     move_args( *argc, argv, i, 2 ) ;
  3825.                     *argc -= 2 ;
  3826.                     i-- ;
  3827.                     }
  3828.                 }
  3829.             else if( !strcmp( argv[i]+1, "i" ) ) {
  3830.                 if( solo || i + 1 == *argc ) {
  3831.                     usage() ;
  3832.                     }
  3833.                 else {
  3834.                     in_name = argv[i+1] ;
  3835.                     move_args( *argc, argv, i, 2 ) ;
  3836.                     *argc -= 2 ;
  3837.                     i-- ;
  3838.                     networking = FALSE ;
  3839.                     }
  3840.                 }
  3841.             else if( !strcmp( argv[i]+1, "o" ) ) {
  3842.                 if( solo || i + 1 == *argc ) {
  3843.                     usage() ;
  3844.                     }
  3845.                 else {
  3846.                     out_name = argv[i+1] ;
  3847.                     move_args( *argc, argv, i, 2 ) ;
  3848.                     *argc -= 2 ;
  3849.                     i-- ;
  3850.                     networking = FALSE ;
  3851.                     }
  3852.                 }
  3853.             else if( !strcmp( argv[i]+1, "T" ) ) {
  3854.                 if( solo || i + 1 == *argc ) {
  3855.                     usage() ;
  3856.                     }
  3857.                 else {
  3858.                     timeToLive = atoi( argv[i+1] ) ;
  3859.                     move_args( *argc, argv, i, 2 ) ;
  3860.                     *argc -= 2 ;
  3861.                     i-- ;
  3862.                     }
  3863.                 }
  3864.             else if( !strcmp( argv[i]+1, "public" ) ) {
  3865.                 if( solo || i + 1 == *argc ) {
  3866.                     usage() ;
  3867.                     }
  3868.                 else if( ( game_key & GAME_KEY_MASK ) == 0 ) {
  3869.                     key = (unsigned short)atoi( argv[i+1] ) ;
  3870.                     if( key > GAME_KEY_MASK ) {
  3871.                         fprintf( stderr, "%s: public game key must be between "
  3872.                                  "0 and %d\n", basename, GAME_KEY_MASK ) ;
  3873.                         end_program( 1 ) ;
  3874.                         }
  3875.                     game_key |= key ;
  3876.                     move_args( *argc, argv, i, 2 ) ;
  3877.                     *argc -= 2 ;
  3878.                     i-- ;
  3879.                     }
  3880.                 else {
  3881.                     usage() ;
  3882.                     }
  3883.                 }
  3884.             else if( !strcmp( argv[i]+1, "private" ) ) {
  3885.                 if( solo || i + 1 == *argc ) {
  3886.                     usage() ;
  3887.                     }
  3888.                 else if( ( game_key & GAME_KEY_MASK ) == 0 ) {
  3889.                     key = (unsigned short)atoi( argv[i+1] ) ;
  3890.                     if( key > GAME_KEY_MASK ) {
  3891.                         fprintf( stderr, "%s: private game key must be between"
  3892.                                  " 0 and %d\n", basename, GAME_KEY_MASK ) ;
  3893.                         end_program( 1 ) ;
  3894.                         }
  3895.                     game_key |= PRIVATE_GAME | key ;
  3896.                     move_args( *argc, argv, i, 2 ) ;
  3897.                     *argc -= 2 ;
  3898.                     i-- ;
  3899.                     }
  3900.                 else {
  3901.                     usage() ;
  3902.                     }
  3903.                 }
  3904.             else if( !strcmp( argv[i]+1, "noflag" ) ) {
  3905.                 if( solo ) {
  3906.                     usage() ;
  3907.                     }
  3908.                 else {
  3909.                     never_have_flag = TRUE ;
  3910.                     move_args( *argc, argv, i, 1 ) ;
  3911.                     *argc -= 1 ;
  3912.                     i-- ;
  3913.                     }
  3914.                 }
  3915.             else if( !strcmp( argv[i]+1, "fast" ) ) {
  3916.                 game_key |= FAST_GAME ;
  3917.                 move_args( *argc, argv, i, 1 ) ;
  3918.                 *argc -= 1 ;
  3919.                 i-- ;
  3920.                 }
  3921.             else if( !strcmp( argv[i]+1, "vo" ) ) {
  3922.                 if( solo ) {
  3923.                     usage() ;
  3924.                     }
  3925.                 else {
  3926.                     view_only = TRUE ;
  3927.                     move_args( *argc, argv, i, 1 ) ;
  3928.                     *argc -= 1 ;
  3929.                     i-- ;
  3930.                     }
  3931.                 }
  3932.             else if( !strcmp( argv[i]+1, "red" ) ) {
  3933.                 if( !solo && player[SELF].team == NEUTRAL_TEAM &&
  3934.                     !pick_my_team ) {
  3935.                     player[SELF].team = RED_TEAM ;
  3936.                     red_team_present = TRUE ;
  3937.                     move_args( *argc, argv, i, 1 ) ;
  3938.                     *argc -= 1 ;
  3939.                     i-- ;
  3940.                     }
  3941.                 else {
  3942.                     usage() ;
  3943.                     }
  3944.                 }
  3945.             else if( !strcmp( argv[i]+1, "blue" ) ) {
  3946.                 if( !solo && player[SELF].team == NEUTRAL_TEAM &&
  3947.                     !pick_my_team ) {
  3948.                     player[SELF].team = BLUE_TEAM ;
  3949.                     blue_team_present = TRUE ;
  3950.                     move_args( *argc, argv, i, 1 ) ;
  3951.                     *argc -= 1 ;
  3952.                     i-- ;
  3953.                     }
  3954.                 else {
  3955.                     usage() ;
  3956.                     }
  3957.                 }
  3958.             else if( !strcmp( argv[i]+1, "pick" ) ) {
  3959.                 if( !solo && player[SELF].team == NEUTRAL_TEAM &&
  3960.                     !pick_my_team ) {
  3961.                     pick_my_team = TRUE ;
  3962.                     move_args( *argc, argv, i, 1 ) ;
  3963.                     *argc -= 1 ;
  3964.                     i-- ;
  3965.                     }
  3966.                 else {
  3967.                     usage() ;
  3968.                     }
  3969.                 }
  3970.             else if( !strcmp( argv[i]+1, "solo" ) ) {
  3971.                 if( argn == 1 ) {
  3972.                     solo = TRUE ;
  3973.                     networking = FALSE ;
  3974.                     move_args( *argc, argv, i, 1 ) ;
  3975.                     *argc -= 1 ;
  3976.                     i-- ;
  3977.                     }
  3978.                 else {
  3979.                     usage() ;
  3980.                     }
  3981.                 }
  3982.             else if( !strcmp( argv[i]+1, "kids" ) ) {
  3983.                 if( solo ) {
  3984.                     kids_mode = TRUE ;
  3985.                     move_args( *argc, argv, i, 1 ) ;
  3986.                     *argc -= 1 ;
  3987.                     i-- ;
  3988.                     }
  3989.                 else {
  3990.                     usage() ;
  3991.                     }
  3992.                 }
  3993.             else if( !strcmp( argv[i]+1, "practice" ) ) {
  3994.                 if( !solo || i + 1 == *argc || practice_level != 0 ) {
  3995.                     usage() ;
  3996.                     }
  3997.                 else {
  3998.                     practice_level = atoi( argv[i+1] ) ;
  3999.                     if( practice_level < 1 ) {
  4000.                         fprintf( stderr, "%s: practice level must be greater "
  4001.                                  "than 0\n", basename ) ;
  4002.                         end_program( 1 ) ;
  4003.                         }
  4004.                     else if( practice_level > 999 ) {
  4005.                         practice_level = 999 ;
  4006.                         }
  4007.                     move_args( *argc, argv, i, 2 ) ;
  4008.                     *argc -= 2 ;
  4009.                     i-- ;
  4010.                     }
  4011.                 }
  4012.             else if( !strcmp( argv[i]+1, "version" ) ) {
  4013.                 fprintf( stderr, "%s version %s\n", basename,
  4014.                          print_version() ) ;
  4015.                 exit( 0 ) ;
  4016.                 }
  4017.             }
  4018.         }
  4019.  
  4020.     if( view_only && player[SELF].team != NEUTRAL_TEAM ) {
  4021.         fprintf( stderr, "%s: can not be a team member in view-only mode.\n",
  4022.                  basename ) ;
  4023.         player[SELF].team = NEUTRAL_TEAM ;
  4024.         }
  4025. }
  4026.  
  4027.  
  4028.  
  4029. static void basic_initialization(
  4030.     int *argc,
  4031.     char **argv
  4032.     )
  4033. {
  4034.     int        i ;
  4035.     int        k ;
  4036.  
  4037.     start_time( &start_up_time ) ;
  4038.     number_players = 1 ;
  4039.  
  4040.     player[SELF].team = NEUTRAL_TEAM ;
  4041.     parse_args( argc, argv ) ;
  4042.  
  4043.     if( never_have_flag ) {
  4044.         game_key |= NO_FLAG_GAME ;
  4045.         }
  4046.  
  4047.     if( game_key & FAST_GAME ) {
  4048.         for( i = 0 ; i < sizeof( vmax ) / sizeof( vmax[0] ) ; i++ ) {
  4049.             vmax[i] *= FAST_FACTOR ;
  4050.             }
  4051.         gm_vel *= FAST_FACTOR ;
  4052.         rm_vel *= FAST_FACTOR ;
  4053.         t_factor = FAST_FACTOR * DHEAD / vmax[2] / 6.f ;
  4054.         }
  4055.     else {
  4056.         t_factor = DHEAD / vmax[2] / 2.f ;
  4057.         }
  4058.  
  4059.     register_key( game_key ) ;
  4060.  
  4061. #if !defined( NETDEBUGGER )
  4062.     get_screen_dimensions() ;
  4063.     set_up_screen_dimensions() ;
  4064.  
  4065.     if( getgdesc( GD_BITS_OVER_SNG_CMODE ) < 2 )
  4066.         use_pups = TRUE ;
  4067. #endif /* !defined( NETDEBUGGER ) */
  4068.  
  4069.     player[SELF].name[NAMELEN-1] = '\0' ;
  4070.     for( i = strlen(player[SELF].name)-1; i > 0 && player[SELF].name[i] == ' ' ;
  4071.         i++ ) {
  4072.         player[SELF].name[i] = '\0' ;
  4073.         }
  4074.  
  4075.     player[SELF].key = game_key ;
  4076.     player[SELF].team_flag = 0 ;
  4077.  
  4078.     if( solo ) {
  4079.         lives = 3 ;
  4080.         deadTranslations = soloDeadTranslations ;
  4081.         }
  4082.     else {
  4083.         lives = 1 ;
  4084.         deadTranslations = netDeadTranslations ;
  4085.         }
  4086.     level = practice_level ;
  4087.  
  4088.     if( view_only ) {
  4089.         mainTranslations = viewonlyTranslations ;
  4090.         }
  4091.     else {
  4092.         mainTranslations = netMainTranslations ;
  4093.         }
  4094.  
  4095.     if( networking && !view_only && !solo )
  4096.         check_quit_time();
  4097.  
  4098.     if( view_only || !networking ) {
  4099.         dprintf( "disable" ) ;
  4100.         }
  4101.     else {
  4102.         dprintf( "%s: starting game version %s (%s)\n", print_time(),
  4103.                 print_version(), print_date() ) ;
  4104.         }
  4105.  
  4106. #if !defined( NETDEBUGGER )
  4107.     if( networking || solo ) {
  4108.         player[SELF].id = gethostid() ;
  4109.         }
  4110.     else {
  4111.         player[SELF].id = 1 ;
  4112.         }
  4113.  
  4114.     k = 0 ;
  4115.     for( i = 0 ; i < 30 ; i++ ) {
  4116.         fracture[i].v0[0] = (float)fracdest[k++] ;
  4117.         fracture[i].v0[1] = (float)fracdest[k++] ;
  4118.         fracture[i].v1[0] = (float)fracdest[k++] ;
  4119.         fracture[i].v1[1] = (float)fracdest[k++] ;
  4120.         }
  4121.  
  4122.     no_sfx = init_sound() ;
  4123.  
  4124. #endif /* !defined( NETDEBUGGER ) */
  4125. }
  4126.  
  4127.  
  4128.  
  4129. static void overlayExposeCB(
  4130.     Widget w,
  4131.     XtPointer client_data,
  4132.     XtPointer call_data
  4133.     )
  4134. {
  4135.     GLXwinset( XtDisplay(w), ((GlxDrawCallbackStruct *)call_data)->window ) ;
  4136.     drawOverlay() ;
  4137.     GLXwinset( display, base_window ) ;
  4138. }
  4139.  
  4140.  
  4141.  
  4142. static void drawSceneCB(
  4143.     Widget w,
  4144.     XtPointer client_data,
  4145.     XtPointer call_data
  4146.     )
  4147. {
  4148.     GLXwinset( XtDisplay(w), ((GlxDrawCallbackStruct *)call_data)->window ) ;
  4149.     redraw_main_view() ;
  4150.     GLXwinset( display, base_window ) ;
  4151. }
  4152.  
  4153.  
  4154.  
  4155. void indicate_map_order(
  4156.     Window w,
  4157.     int map
  4158.     )
  4159. {
  4160.     map_window[map_counter] = w ;
  4161.     map_index[map_counter] = map ;
  4162.     map_counter++ ;
  4163. }
  4164.  
  4165.  
  4166.  
  4167. static void initGlCB(
  4168.     Widget w,
  4169.     XtPointer client_data,
  4170.     XtPointer call_data )
  4171. {
  4172. #if !defined( NETDEBUGGER )
  4173.     int                n ;
  4174.     Dimension        wi, hi ;
  4175.     Dimension        x, y ;
  4176.     float            a ;
  4177.  
  4178.     mainview_window = ((GlxDrawCallbackStruct *)call_data)->window ;
  4179.     GLXwinset( XtDisplay(w), mainview_window ) ;
  4180.  
  4181.     n = 0 ;
  4182.     XtSetArg( wargs[n], XmNwidth, &wi ) ; n++ ;
  4183.     XtSetArg( wargs[n], XmNheight, &hi ) ; n++ ;
  4184.     XtSetArg( wargs[n], XmNx, &x ) ; n++ ;
  4185.     XtSetArg( wargs[n], XmNy, &y ) ; n++ ;
  4186.     XtGetValues( w, wargs, n ) ;
  4187.  
  4188.     aspect_ratio = (float)wi / (float)hi ;
  4189.     min_cull_angle = 0.5f * 30.0f * aspect_ratio + 30.f ;
  4190.     max_cull_angle = 360.0f - min_cull_angle ;
  4191.  
  4192.     a = atan( aspect_ratio * tanf( 0.5f * 30.0f * DEG2RAD ) ) / DEG2RAD ;
  4193.     radar_view_angle[0][0] = -800.f * SINE( a ) ;
  4194.     radar_view_angle[0][1] =  800.f * COSINE( a ) ;
  4195.     radar_view_angle[2][0] = -radar_view_angle[0][0] ;
  4196.     radar_view_angle[2][1] =  radar_view_angle[0][1] ;
  4197.  
  4198.     a = atan( aspect_ratio * tanf( 0.5f * 5.0f * DEG2RAD ) ) / DEG2RAD ;
  4199.     binocular_radar_view_angle[0][0] = -800.f * SINE( a ) ;
  4200.     binocular_radar_view_angle[0][1] =  800.f * COSINE( a ) ;
  4201.     binocular_radar_view_angle[2][0] = -binocular_radar_view_angle[0][0] ;
  4202.     binocular_radar_view_angle[2][1] =  binocular_radar_view_angle[0][1] ;
  4203.  
  4204.     zbuffer( FALSE ) ;
  4205.     subpixel( TRUE ) ;
  4206.     mmode( MVIEWING ) ;
  4207.     loadmatrix( id_mat ) ;
  4208.     concave( FALSE ) ;
  4209.     backface( FALSE ) ;
  4210.     shademodel( FLAT ) ;
  4211.  
  4212.     init_color( MAIN_VIEW_MAP, w ) ;
  4213.     indicate_map_order( mainview_window, MAIN_VIEW_MAP ) ;
  4214.  
  4215.     mv_w = FVPMVIEW_R - FVPMVIEW_L ;
  4216.     mv_h = FVPMVIEW_T - FVPMVIEW_B ;
  4217.     mv_m = FVPGROND_T - FVPMVIEW_B ;
  4218.  
  4219.     make_mv_objects() ;
  4220.  
  4221.     tank_logo[0] = null_obj ;
  4222.     if( logo_file == NULL || strlen( logo_file ) == 0 ) {
  4223.         logo_file = AppRes.logoFile ;
  4224.         }
  4225.  
  4226.     if( logo_file != NULL && strlen( logo_file ) > 0 ) {
  4227.         if( ( tank_logo[0] = read_logo( logo_file, logo_packet.logo_info,
  4228.                                         LOGO_SIZE, 0, &n ) ) == 0 ) {
  4229.             tank_logo[0] = null_obj ;
  4230.             }
  4231.         }
  4232.  
  4233.     init_lighting() ;
  4234.  
  4235.     loadmatrix( id_mat ) ;
  4236.     perspective( 300, aspect_ratio, .5f, 10000.f ) ;
  4237.     rotate( -900, 'x' ) ;
  4238.     bind_lighting() ;
  4239. #else
  4240.     tank_logo[SELF] = null_obj ;
  4241. #endif /* !defined( NETDEBUGGER ) */
  4242. }
  4243.  
  4244.  
  4245.  
  4246. static void changeVolume(
  4247.     Widget w,
  4248.     XEvent *event,
  4249.     String *params,
  4250.     Cardinal *numParams
  4251.     )
  4252. {
  4253.     int    selection ;
  4254.  
  4255.     if( !no_sfx ) {
  4256.         if( *numParams == 0 ) {
  4257.             selection = 0 ;
  4258.             }
  4259.         else {
  4260.             selection = atoi( params[0] ) ;
  4261.             }
  4262.  
  4263.         post_new_message( 0, 0, "Volume set to %d.",
  4264.                           volume_change( selection ) ) ;
  4265.         }
  4266. }
  4267.  
  4268.  
  4269.  
  4270. static void tankSelect(
  4271.     Widget w,
  4272.     XEvent *event,
  4273.     String *params,
  4274.     Cardinal *numParams
  4275.     )
  4276. {
  4277.     int                selection ;
  4278.  
  4279.     if( *numParams == 0 ) {
  4280.         selection = '1' ;
  4281.         }
  4282.     else {
  4283.         selection = params[0][0] ;
  4284.         }
  4285.  
  4286.     GLXwinset( display, base_window ) ;
  4287.     choose_tank( selection ) ;
  4288.  
  4289.     if( init_wait ) {
  4290.         setTranslations( mainTransTable ) ;
  4291.         start_time( ¤t_time ) ;
  4292.         init_census_packet( player[SELF].id ) ;
  4293.         reset_mouse() ;
  4294.         reinterpret_mouse() ;
  4295.         ol_mode = 0 ;
  4296.         place_self();
  4297.         init_wait = 0 ;
  4298.         if( solo ) {
  4299.             solo_init() ;
  4300.             }
  4301.         /*
  4302.          * Start up the main loop.
  4303.          */
  4304.         XtAppAddWorkProc( appContext, timeStepWP, (XtPointer)mainview_widget ) ;
  4305.         }
  4306.     else {
  4307.         setTranslations( deadTransTable ) ;
  4308.         ol_mode = 1 ;
  4309.         }
  4310.     GLXwinset( display, radar_ol_window ) ;
  4311.     drawOverlay() ;
  4312. }
  4313.  
  4314.  
  4315.  
  4316. static void choose_tank(
  4317.     int selection
  4318.     )
  4319. {
  4320.     switch( selection ) {
  4321.  
  4322.         case '1' :        /* Regular tank */
  4323.             top_speed = vmax[0] ;
  4324.             new_tank_type = 0 ;
  4325.             post_new_message( 0, 1, "Tank is a regular tank." ) ;
  4326.             break ;
  4327.  
  4328.         case '2' :        /* Super tank */
  4329.             top_speed = vmax[1] ;
  4330.             new_tank_type = 1 ;
  4331.             post_new_message( 0, 1, "Tank is a super tank." ) ;
  4332.             break ;
  4333.  
  4334.         case '3' :        /* Stealth tank */
  4335.             top_speed = vmax[2] ;
  4336.             new_tank_type = 2 ;
  4337.             post_new_message( 0, 1, "Tank is a stealth tank." ) ;
  4338.             break ;
  4339.  
  4340.         case '4' :        /* Runner tank */
  4341.             top_speed = vmax[3] ;
  4342.             new_tank_type = 3 ;
  4343.             post_new_message( 0, 1, "Tank is a runner tank." ) ;
  4344.             break ;
  4345.  
  4346.         default:        /* Bad argument */
  4347.             fprintf( stderr, "Bad argument to tankSelect in resources\n" ) ;
  4348.             fprintf( stderr, "Proper argument is either 1, 2, 3, or 4\n" ) ;
  4349.             end_program( 0 ) ;
  4350.             break ;
  4351.  
  4352.         }
  4353.     picking_tank = FALSE ;
  4354.     need_to_set_tank = TRUE ;
  4355. }
  4356.  
  4357.  
  4358.  
  4359. void send_quit_packet( void )
  4360. {
  4361.     struct BzAck    ack ;
  4362.  
  4363.     ack.bz_id  = BZQUIT ;
  4364.     ack.id     = player[SELF].id ;
  4365.     ack.ack_id = player[SELF].id ;
  4366.     ack.key    = player[SELF].key ;
  4367.  
  4368.     /*
  4369.      * Send out 3 for good measure.
  4370.      */
  4371.     send_out( &ack, sizeof( ack ) ) ;
  4372.     send_out( &ack, sizeof( ack ) ) ;
  4373.     send_out( &ack, sizeof( ack ) ) ;
  4374.  
  4375.     dprintf( "\n%s: quitting game\n", print_time() ) ;
  4376.     if( networking ) {
  4377.         validation_summary() ;
  4378.         }
  4379.  
  4380.     sleep( 1 ) ;
  4381.  
  4382. }
  4383.  
  4384.  
  4385.  
  4386. static void quit(
  4387.     Widget w,
  4388.     XEvent *event,
  4389.     String *params,
  4390.     Cardinal *numParams
  4391.     )
  4392. {
  4393.     if( !solo )
  4394.         send_quit_packet() ;
  4395.  
  4396. #if !defined( NETDEBUGGER )
  4397.     if( networking && !view_only && !solo ) {
  4398.         set_quit_time();
  4399.         }
  4400.  
  4401. #endif /* !defined( NETDEBUGGER ) */
  4402.     end_program( 0 ) ;
  4403. }
  4404.  
  4405.  
  4406.  
  4407. void end_program(
  4408.     int status
  4409.     )
  4410. {
  4411.     end_sound() ;
  4412.     exit( status ) ;
  4413. }
  4414.  
  4415.  
  4416.  
  4417. static void stopRandomizing(
  4418.     Widget w,
  4419.     XEvent *event,
  4420.     String *params,
  4421.     Cardinal *numParams
  4422.     )
  4423. {
  4424.     Cardinal    zero = 0 ;
  4425.     Cardinal    one = 1 ;
  4426.     static char    *two_str = "2" ;
  4427.     static char    *four_str = "4" ;
  4428.  
  4429.     randomizer = False ;
  4430.     screen_mode = INTRO_PICK_SCREEN ;
  4431.     XRaiseWindow( display, radar_window ) ;
  4432.     XRaiseWindow( display, mainview_window ) ;
  4433.  
  4434.     GLXwinset( display, base_window ) ;
  4435.     redraw_base_screen() ;
  4436.  
  4437.     post_new_message( 0, 0, " " ) ;
  4438.     mail.out_message[0] = '\0' ;
  4439.  
  4440.     if( view_only ) {
  4441.         tankSelect( w, event, params, &zero ) ;
  4442.         }
  4443.     else if( solo ) {
  4444.         if( kids_mode ) {
  4445.             tankSelect( w, event, &four_str, &one ) ;
  4446.             }
  4447.         else {
  4448.             tankSelect( w, event, &two_str, &one ) ;
  4449.             }
  4450.         }
  4451.     else {
  4452.         setTranslations( introPickTransTable ) ;
  4453.         ol_mode = 1 ;
  4454.         }
  4455.  
  4456.     XtManageChild( radar_widget ) ;
  4457.  
  4458.     GLXwinset( display, radar_ol_window ) ;
  4459.     drawOverlay() ;
  4460.  
  4461.     GLXwinset( display, mainview_window ) ;
  4462.     redraw_main_view() ;
  4463. }
  4464.  
  4465.  
  4466.  
  4467. static Boolean randomizerWP(
  4468.     XtPointer    ignore
  4469.     )
  4470. {
  4471.     rand() ;
  4472.     return( !randomizer ) ;
  4473. }
  4474.  
  4475.  
  4476.  
  4477. void draw_intro_screen( void )
  4478. {
  4479.     viewport( 0, screen_w, 0, screen_h ) ;
  4480.     ortho2( -0.5f, (float)screen_w-0.5f, -0.5f, (float)screen_h-0.5f ) ;
  4481.     color( black ) ;
  4482.     clear() ;
  4483.     color( yellow ) ;
  4484.     print_help( (float)screen_w / 2.f, (float)screen_h / 2.f, 1 ) ;
  4485. }
  4486.  
  4487.  
  4488.  
  4489. static char *normal_instructions[] = {
  4490.          " left mouse  - fire regular missile",
  4491.          "Nmid mouse   -  fire guided missile",
  4492.          "N             (or return control to",
  4493.          "N                tank from missile)",
  4494.          " right mouse -      identify player",
  4495.          " mouse x,y   -         control tank",
  4496.          "N                 or guided missile",
  4497.          " a           -       zoom out radar",
  4498.          " b           -    toggle binoculars",
  4499.         "Nc           -      drop enemy flag",
  4500.          " d           -            drop mine",
  4501.          "N           (can be detonated by x)",
  4502.          " D           -  drop permanent mine",
  4503.         "Nf           -      grab enemy flag",
  4504.          " l           -         toggle logos",
  4505.          " h           -     show help screen",
  4506.          "Nm           -     send mail to all",
  4507.          " p           -         pick up mine",
  4508.          "SP           -    pause/resume game",
  4509.          "Ns           -          show scores",
  4510.          " S           -        toggle sounds",
  4511.          "Nt           -    send mail to team",
  4512.          " x           -        detonate mine",
  4513.          " z           -        zoom in radar",
  4514.          " up/down     -        adjust volume",
  4515.          " ESC         -                 quit", } ;
  4516.  
  4517. static char *view_only_instructions[] = {
  4518.          " right mouse -      identify player",
  4519.          " mouse x,y   -         control tank",
  4520.          " a           -       zoom out radar",
  4521.          " b           -    toggle binoculars",
  4522.         " c           -  toggle copilot view",
  4523.          " l           -         toggle logos",
  4524.          " h           -     show help screen",
  4525.         " n           -    next copilot view",
  4526.          " s           -          show scores",
  4527.          " S           -        toggle sounds",
  4528.          " z           -        zoom in radar",
  4529.          " up/down     -        adjust volume",
  4530.          " ESC         -                 quit", } ;
  4531.  
  4532.  
  4533. static void print_help(
  4534.     float sx,
  4535.     float sy,
  4536.     int prompt
  4537.     )
  4538. {
  4539.     float    xx ;
  4540.     float    yy ;
  4541.     float    dyi ;
  4542.     float    dyj ;
  4543.     int        i ;
  4544.     int        k ;
  4545.     int        n ;
  4546.     char    key ;
  4547.     char    **line ;
  4548.     char    vers[40] ;
  4549.     char    **instructions ;
  4550.  
  4551.     /*
  4552.      * Indentify the instruction set for view-only mode and determine the
  4553.      * number of lines.
  4554.      */
  4555.     if( view_only ) {
  4556.         instructions = view_only_instructions ;
  4557.         i = sizeof( view_only_instructions ) /
  4558.             sizeof( view_only_instructions[0] ) ;
  4559.         }
  4560.     else {
  4561.         instructions = normal_instructions ;
  4562.         i = sizeof( normal_instructions ) / sizeof( normal_instructions[0] ) ;
  4563.         }
  4564.  
  4565.     /*
  4566.      * Identify a key for which instruction lines should be printed out.
  4567.      */
  4568.     if( solo ) {
  4569.         key = 'S' ;
  4570.         }
  4571.     else {
  4572.         key = 'N' ;
  4573.         }
  4574.  
  4575.     /*
  4576.      * Adjust the number of lines (based on solo or networking).
  4577.      */
  4578.     n = 0 ;
  4579.     for( k = 0 ; k < i ; k++ ) {
  4580.         if( instructions[k][0] == ' ' || instructions[k][0] == key )
  4581.             n++ ;
  4582.         }
  4583.     i = n ;
  4584.  
  4585.     dyi = char_height * 1.25f ;
  4586.     dyj = char_height * 1.1f ;
  4587.  
  4588.     /*
  4589.      * Calculate line spacing.
  4590.      */
  4591.     do {
  4592.         xx = sx - 15.f*char_width/2.f ;
  4593.         yy = ( ( i + 2 ) * dyi + 2 * dyj ) / 2.f + 20.f ;
  4594.         if( view_only )
  4595.             yy += dyi ;
  4596.         if( prompt ) {
  4597.             yy += ( dyi + 3 * dyj ) / 2.f ;
  4598.             }
  4599.         if( yy > sy ) {
  4600.             dyi *= .95f ;
  4601.             dyj *= .95f ;
  4602.             }
  4603.         } while( yy > sy ) ;
  4604.     yy += sy - 20.f ;
  4605.  
  4606.     /*
  4607.      * Start printing headers.
  4608.      */
  4609.     cmov2( xx, yy ) ;
  4610.     charstr( "BZ INSTRUCTIONS" ) ;
  4611.     yy -= dyi ;
  4612. #if defined(BETA)
  4613.     sprintf( vers, "Beta Version %s", print_version() ) ;
  4614. #else
  4615.     sprintf( vers, "Version %s", print_version() ) ;
  4616. #endif /* defined(BETA) */
  4617.     xx = sx - strlen( vers ) * char_width / 2.f ;
  4618.     cmov2( xx, yy ) ;
  4619.     charstr( vers ) ;
  4620.     if( view_only ) {
  4621.         yy -= dyi ;
  4622.         xx = sx - 14.f * char_width / 2.f ;
  4623.         cmov2( xx, yy ) ;
  4624.         charstr( "View Only Mode" ) ;
  4625.         }
  4626.     yy -= 2 * dyi ;
  4627.  
  4628.     /*
  4629.      * Print out the instructions.
  4630.      */
  4631.     xx = sx - strlen( instructions[0] ) * char_width / 2.f ;
  4632.     line = instructions ;
  4633.     while( i-- ) {
  4634.         yy -= dyi ;
  4635.         cmov2( xx, yy ) ;
  4636.         /*
  4637.          * Skip lines not for current solo/networking mode.
  4638.          */
  4639.         while( line[0][0] != ' ' && line[0][0] != key )
  4640.             line++ ;
  4641.         charstr( *(line++) + 1 ) ;
  4642.         }
  4643.  
  4644.     if( prompt ) {
  4645.         yy -=  3 * dyj ;
  4646.         xx = sx - 38.f*char_width/2.f ;
  4647.         cmov2( xx, yy ) ;
  4648.         charstr( "Hit any key to continue (ESC to quit):" ) ;
  4649.         }
  4650. }
  4651.  
  4652.  
  4653.  
  4654. static void setTranslations(
  4655.     XtTranslations transTable
  4656.     )
  4657. {
  4658.     int                    n ;
  4659.  
  4660.     n = 0 ;
  4661.     XtSetArg( wargs[n], XmNtranslations, transTable ) ; n++ ;
  4662.     XtSetValues( mainview_widget, wargs, n ) ;
  4663.     XtSetValues( radar_widget, wargs, n ) ;
  4664.     XtSetValues( base_widget, wargs, n ) ;
  4665. }
  4666.  
  4667.  
  4668. static void identifyTank(
  4669.     Widget w,
  4670.     XEvent *event,
  4671.     String *params,
  4672.     Cardinal *numParams
  4673.     )
  4674. {
  4675.     want_to_identify = TRUE ;
  4676. }
  4677.  
  4678.  
  4679.  
  4680. static void fireNormalShot(
  4681.     Widget w,
  4682.     XEvent *event,
  4683.     String *params,
  4684.     Cardinal *numParams
  4685.     )
  4686. {
  4687.     if( loading_missile == 0 ) {
  4688.         fire_normal_missile = TRUE ;
  4689.         }
  4690. }
  4691.  
  4692.  
  4693.  
  4694. static void fireGuidedShot(
  4695.     Widget w,
  4696.     XEvent *event,
  4697.     String *params,
  4698.     Cardinal *numParams
  4699.     )
  4700. {
  4701.     if( solo && !kids_mode ) {
  4702.         post_new_message( 0, 1, "Can't fire guided missiles in solo mode." ) ;
  4703.         }
  4704.     else if( loading_missile == 0 ) {
  4705.         if( kids_mode || player[SELF].tank_type != 3 ) {
  4706.             fire_guided_missile = TRUE ;
  4707.             }
  4708.         else {
  4709.             post_new_message( 0, 1,
  4710.                 "This tank type can not fire guided missiles." ) ;
  4711.             }
  4712.         }
  4713.     else if( guiding ) {
  4714.         quit_guided_missile = TRUE ;
  4715.         }
  4716. }
  4717.  
  4718.  
  4719.  
  4720. static void toggleShowTimings(
  4721.     Widget w,
  4722.     XEvent *event,
  4723.     String *params,
  4724.     Cardinal *numParams
  4725.     )
  4726. {
  4727.     want_to_see_timings = !want_to_see_timings ;
  4728.     post_new_message( 0, 0, "Timing display %s.\n",
  4729.         ( want_to_see_timings ) ? "on" : "off" ) ;
  4730. }
  4731.  
  4732.  
  4733.  
  4734. static void toggleShowScore(
  4735.     Widget w,
  4736.     XEvent *event,
  4737.     String *params,
  4738.     Cardinal *numParams
  4739.     )
  4740. {
  4741.     if( !solo )
  4742.         want_to_see_score = !want_to_see_score ;
  4743. }
  4744.  
  4745.  
  4746.  
  4747. static void toggleShowHelp(
  4748.     Widget w,
  4749.     XEvent *event,
  4750.     String *params,
  4751.     Cardinal *numParams
  4752.     )
  4753. {
  4754.     want_to_see_help = !want_to_see_help ;
  4755. }
  4756.  
  4757.  
  4758.  
  4759. static void zoomIn(
  4760.     Widget w,
  4761.     XEvent *event,
  4762.     String *params,
  4763.     Cardinal *numParams
  4764.     )
  4765. {
  4766.     if( zoom_level < sizeof( zoom_settings ) / sizeof( zoom_settings[0] ) - 1 ){
  4767.         zoom_factor = zoom_settings[++zoom_level] ;
  4768.         need_to_show_zoom = TRUE ;
  4769.         }
  4770. }
  4771.  
  4772.  
  4773.  
  4774. static void nextCoPilot(
  4775.     Widget w,
  4776.     XEvent *event,
  4777.     String *params,
  4778.     Cardinal *numParams
  4779.     )
  4780. {
  4781.     if( show_copilot_view ) {
  4782.         next_copilot_view() ;
  4783.         }
  4784. }
  4785.  
  4786.  
  4787.  
  4788. static void coPilot(
  4789.     Widget w,
  4790.     XEvent *event,
  4791.     String *params,
  4792.     Cardinal *numParams
  4793.     )
  4794. {
  4795.     if( show_copilot_view ) {
  4796.         show_copilot_view = FALSE ;
  4797.         post_new_message( 0, 0, "Co-pilot mode off." ) ;
  4798.         }
  4799.     else if( number_players > 1 ) {
  4800.         show_copilot_view = TRUE ;
  4801.         if( copilot_player > number_players ) {
  4802.             copilot_player = 1 ;
  4803.             }
  4804.         post_new_message( 0, 0, "Co-pilot view of %s.",
  4805.                           player[copilot_player].name ) ;
  4806.         }
  4807. }
  4808.  
  4809.  
  4810.  
  4811. static void zoomOut(
  4812.     Widget w,
  4813.     XEvent *event,
  4814.     String *params,
  4815.     Cardinal *numParams
  4816.     )
  4817. {
  4818.     if( zoom_level > 0 ) {
  4819.         zoom_factor = zoom_settings[--zoom_level] ;
  4820.         need_to_show_zoom = TRUE ;
  4821.         }
  4822. }
  4823.  
  4824.  
  4825.  
  4826. static void dropMine(
  4827.     Widget w,
  4828.     XEvent *event,
  4829.     String *params,
  4830.     Cardinal *numParams
  4831.     )
  4832. {
  4833.     want_to_drop_normal_mine = TRUE ;
  4834. }
  4835.  
  4836.  
  4837.  
  4838. static void grabFlag(
  4839.     Widget w,
  4840.     XEvent *event,
  4841.     String *params,
  4842.     Cardinal *numParams
  4843.     )
  4844. {
  4845.     if( show_flags && !HAS_A_FLAG( player[SELF] ) )
  4846.         want_to_grab_flag = TRUE ;
  4847. }
  4848.  
  4849.  
  4850.  
  4851. static void dropFlag(
  4852.     Widget w,
  4853.     XEvent *event,
  4854.     String *params,
  4855.     Cardinal *numParams
  4856.     )
  4857. {
  4858.     if( show_flags && HAS_A_FLAG( player[SELF] ) )
  4859.         want_to_drop_flag = TRUE ;
  4860. }
  4861.  
  4862.  
  4863.  
  4864. static void detonateMine(
  4865.     Widget w,
  4866.     XEvent *event,
  4867.     String *params,
  4868.     Cardinal *numParams
  4869.     )
  4870. {
  4871.     if( mine_status > 0 ) {
  4872.         want_to_detonate_mine = TRUE ;
  4873.         }
  4874. }
  4875.  
  4876.  
  4877.  
  4878. static void dropPermanentMine(
  4879.     Widget w,
  4880.     XEvent *event,
  4881.     String *params,
  4882.     Cardinal *numParams
  4883.     )
  4884. {
  4885.     want_to_drop_permanent_mine = TRUE ;
  4886. }
  4887.  
  4888.  
  4889.  
  4890. static void pickUpMine(
  4891.     Widget w,
  4892.     XEvent *event,
  4893.     String *params,
  4894.     Cardinal *numParams
  4895.     )
  4896. {
  4897.     if( mine_status > 0 )
  4898.         want_to_pick_mine = TRUE ;
  4899. }
  4900.  
  4901.  
  4902.  
  4903. static void selfDestruct(
  4904.     Widget w,
  4905.     XEvent *event,
  4906.     String *params,
  4907.     Cardinal *numParams
  4908.     )
  4909. {
  4910.     blow_up_self( SELF ) ;
  4911. }
  4912.  
  4913.  
  4914.  
  4915. static void slowDown(
  4916.     Widget w,
  4917.     XEvent *event,
  4918.     String *params,
  4919.     Cardinal *numParams
  4920.     )
  4921. {
  4922.     want_to_slow_down = TRUE ;
  4923. }
  4924.  
  4925.  
  4926.  
  4927. static void resetGun(
  4928.     Widget w,
  4929.     XEvent *event,
  4930.     String *params,
  4931.     Cardinal *numParams
  4932.     )
  4933. {
  4934.     if( loading_missile > 0 ) {
  4935.         loading_missile = 0 ;
  4936.         if( guiding ) {
  4937.             left_track = right_track = 0.f ;
  4938.             guiding = FALSE ;
  4939.             reset_mouse() ;
  4940.             }
  4941.         }
  4942. }
  4943.  
  4944.  
  4945.  
  4946. static void stopWatch(
  4947.     Widget w,
  4948.     XEvent *event,
  4949.     String *params,
  4950.     Cardinal *numParams
  4951.     )
  4952. {
  4953.     static int                mode = 0 ;
  4954.     static struct timeval    watch_time ;
  4955.     float                    et ;
  4956.  
  4957.     if( mode == 0 ) {
  4958.         start_time( &watch_time ) ;
  4959.         mode = 1 ;
  4960.         }
  4961.     else {
  4962.         mode = 0 ;
  4963.         et = end_time( &watch_time, NULL ) ;
  4964.         post_new_message( 0, 0, "Time: %.3f secs.", et ) ;
  4965.         }
  4966. }
  4967.  
  4968.  
  4969.  
  4970. static void mouseTrack(
  4971.     Widget w,
  4972.     XEvent *event,
  4973.     String *params,
  4974.     Cardinal *numParams
  4975.     )
  4976. {
  4977.     XMotionEvent    *xmotion = &(event->xmotion) ;
  4978.  
  4979.     if( event->type == MotionNotify ) {
  4980.         mouse_interpret( xmotion->x_root, xmotion->y_root ) ;
  4981.         }
  4982. }
  4983.  
  4984.  
  4985.  
  4986. static void reset_mouse( void )
  4987. {
  4988.     int    xc ;
  4989.     int    yc ;
  4990.  
  4991.     xc = ( VPMVIEW_R + VPMVIEW_L ) / 2 ;
  4992.     yc = screen_h - ( VPMVIEW_T + VPMVIEW_B ) / 2 ;
  4993.  
  4994.     XWarpPointer( display, None, XtWindow( toplevel ), 0, 0, 0, 0, xc, yc ) ;
  4995.     XFlush( display ) ;
  4996. }
  4997.  
  4998.  
  4999.  
  5000. static void reinterpret_mouse( void )
  5001. {
  5002.     Window            root_win ;
  5003.     Window            child_win ;
  5004.     int                root_x ;
  5005.     int                root_y ;
  5006.     int                win_x ;
  5007.     int                win_y ;
  5008.     unsigned int    mask ;
  5009.  
  5010.     if( XQueryPointer( display, XtWindow( toplevel ), &root_win, &child_win,
  5011.         &root_x, &root_y, &win_x, &win_y, &mask ) ) {
  5012.         mouse_interpret( win_x, win_y ) ;
  5013.         }
  5014. }
  5015.  
  5016.  
  5017.  
  5018. static void mouse_interpret(
  5019.     int    mouse_x,
  5020.     int mouse_y
  5021.     )
  5022. {
  5023.     static int        xc ;
  5024.     static int        yc ;
  5025.     static int        init = 1 ;
  5026.     float            x ;
  5027.     float            y ;
  5028.     float            s ;
  5029.     float            track_radius ;
  5030.  
  5031.     if( init ) {
  5032.         init = 0 ;
  5033.         xc = ( VPMVIEW_R + VPMVIEW_L ) / 2 ;
  5034.         yc = ( VPMVIEW_T + VPMVIEW_B ) / 2 ;
  5035.         }
  5036.  
  5037.     if( view_only ) {
  5038.         track_radius = VIEW_ONLY_TRACK_RADIUS ;
  5039.         }
  5040.     else {
  5041.         track_radius = NORMAL_TRACK_RADIUS ;
  5042.         }
  5043.  
  5044.     /*
  5045.      * Guiding a missile...
  5046.      */
  5047.     if( guiding ) {
  5048.         x = (float)( mouse_x - xc ) ;
  5049.         y = 0.f ;
  5050.         s = ( x > 0.0f ) ? x : -x ;
  5051.         if( s > 0.0f ) {
  5052.             if( s < 5.f ) {
  5053.                 x = 0.0f ;
  5054.                 }
  5055.             else {
  5056.                 if( s < track_radius )
  5057.                     s = track_radius ;
  5058.                 x /= s ;
  5059.                 }
  5060.             }
  5061.  
  5062.         if( x > 0.0f ) {
  5063.             left_track_engaged  = x ;
  5064.             right_track_engaged = 0.0f ;
  5065.             }
  5066.         else {
  5067.             left_track_engaged  = 0.0f ;
  5068.             right_track_engaged = -x ;
  5069.             }
  5070.         }
  5071.     /*
  5072.      * Steering the tank..
  5073.      */
  5074.     else {
  5075.         x = (float)( mouse_x - xc ) ;
  5076.         y = (float)( yc - ( screen_h - mouse_y ) ) ;
  5077.  
  5078.         if( ( s = hypotn( x, y ) ) > 0.0f ) {
  5079.             if( s < 10.f ) {
  5080.                 x = y = 0.0f ;
  5081.                 }
  5082.             else {
  5083.                 if( s < track_radius )
  5084.                     s = track_radius ;
  5085.                 x /= s ;
  5086.                 y /= s ;
  5087.                 x *= ( x > 0.f ) ? x : -x ;
  5088.                 y *= ( y > 0.f ) ? y : -y ;
  5089.                 }
  5090.             }
  5091.  
  5092.         left_track_engaged  =  x - y ;
  5093.         right_track_engaged = -x - y ;
  5094.         }
  5095. }
  5096.  
  5097.  
  5098.  
  5099. static void changeTank(
  5100.     Widget w,
  5101.     XEvent *event,
  5102.     String *params,
  5103.     Cardinal *numParams
  5104.     )
  5105. {
  5106.     picking_tank = TRUE ;
  5107.     setTranslations( introPickTransTable ) ;
  5108.     GLXwinset( display, radar_ol_window ) ;
  5109.     drawOverlay() ;
  5110.     ringbell() ;
  5111. }
  5112.  
  5113.  
  5114.  
  5115. static void writeMail(
  5116.     Widget w,
  5117.     XEvent *event,
  5118.     String *params,
  5119.     Cardinal *numParams
  5120.     )
  5121. {
  5122.     if( !solo ) {
  5123.         GLXwinset( display, base_window ) ;
  5124.         input_message( 1 ) ;
  5125.         sending_msg = SENDING_ALL_MAIL ;
  5126.         if( IS_ALIVE( player[SELF] ) ) {
  5127.             setTranslations( liveMailTransTable ) ;
  5128.             }
  5129.         else {
  5130.             setTranslations( deadMailTransTable ) ;
  5131.             ol_mode = 0 ;
  5132.             GLXwinset( display, radar_ol_window ) ;
  5133.             drawOverlay() ;
  5134.             }
  5135.         ringbell() ;
  5136.         }
  5137. }
  5138.  
  5139.  
  5140.  
  5141. static void writeTeamMail(
  5142.     Widget w,
  5143.     XEvent *event,
  5144.     String *params,
  5145.     Cardinal *numParams
  5146.     )
  5147. {
  5148.     if( !solo ) {
  5149.         GLXwinset( display, base_window ) ;
  5150.         input_message( 1 ) ;
  5151.         sending_msg = SENDING_TEAM_MAIL ;
  5152.         if( IS_ALIVE( player[SELF] ) ) {
  5153.             setTranslations( liveMailTransTable ) ;
  5154.             }
  5155.         else {
  5156.             setTranslations( deadMailTransTable ) ;
  5157.             ol_mode = 0 ;
  5158.             GLXwinset( display, radar_ol_window ) ;
  5159.             drawOverlay() ;
  5160.             }
  5161.         ringbell() ;
  5162.         }
  5163. }
  5164.  
  5165.  
  5166.  
  5167. static void composeMail(
  5168.     Widget w,
  5169.     XEvent *event,
  5170.     String *params,
  5171.     Cardinal *numParams
  5172.     )
  5173. {
  5174.     XKeyEvent    *xkey = &(event->xkey) ;
  5175.  
  5176.     if( event->type == KeyPress && mail_ptr < MAIL_MSG_SIZE ) {
  5177.         mail_ptr += XLookupString( xkey, mail_buffer+mail_ptr,
  5178.                                    MAIL_MSG_SIZE - 1 - mail_ptr, NULL, NULL ) ;
  5179.         }
  5180. }
  5181.  
  5182.  
  5183.  
  5184. static void toggleBinoculars(
  5185.     Widget w,
  5186.     XEvent *event,
  5187.     String *params,
  5188.     Cardinal *numParams
  5189.     )
  5190. {
  5191.     binoculars = !binoculars ;
  5192.     post_new_message( 0, 0, "Binoculars %s.\n", binoculars ? "on" : "off" ) ;
  5193. }
  5194.  
  5195.  
  5196.  
  5197. /*------------------------------------------------------------------------------
  5198.  * Join the blue team.
  5199.  *----------------------------------------------------------------------------*/
  5200. static void joinBlueTeam(
  5201.     Widget w,
  5202.     XEvent *event,
  5203.     String *params,
  5204.     Cardinal *numParams
  5205.     )
  5206. {
  5207.     if( player[SELF].team == NEUTRAL_TEAM ) {
  5208.         join_a_team( BLUE_TEAM ) ;
  5209.         }
  5210. }
  5211.  
  5212.  
  5213.  
  5214. /*------------------------------------------------------------------------------
  5215.  * Join the red team.
  5216.  *----------------------------------------------------------------------------*/
  5217. static void joinRedTeam(
  5218.     Widget w,
  5219.     XEvent *event,
  5220.     String *params,
  5221.     Cardinal *numParams
  5222.     )
  5223. {
  5224.     if( player[SELF].team == NEUTRAL_TEAM ) {
  5225.         join_a_team( RED_TEAM ) ;
  5226.         }
  5227. }
  5228.  
  5229.  
  5230.  
  5231. static void toggleLogos(
  5232.     Widget w,
  5233.     XEvent *event,
  5234.     String *params,
  5235.     Cardinal *numParams
  5236.     )
  5237. {
  5238.     show_logos = !show_logos ;
  5239.     post_new_message( 0, 0, "Logos %s.\n", show_logos ? "on" : "off" ) ;
  5240. }
  5241.  
  5242.  
  5243.  
  5244. /*------------------------------------------------------------------------------
  5245.  * Toggle pause function on and off.
  5246.  *----------------------------------------------------------------------------*/
  5247. static void togglePause(
  5248.     Widget w,
  5249.     XEvent *event,
  5250.     String *params,
  5251.     Cardinal *numParams
  5252.     )
  5253. {
  5254.     if( solo ) {
  5255.         paused = !paused ;
  5256.         if( paused ) {
  5257.             post_new_message( 0, 0, " " ) ;
  5258.             post_new_message( 0, 0, "Paused...(hit P to continue)." ) ;
  5259.             start_pause() ;
  5260.             }
  5261.         else {
  5262.             post_new_message( 0, 1, "Play resumed." ) ;
  5263.             end_pause() ;
  5264.             }
  5265.         }
  5266. }
  5267.  
  5268.  
  5269.  
  5270. static void toggleAudio(
  5271.     Widget w,
  5272.     XEvent *event,
  5273.     String *params,
  5274.     Cardinal *numParams
  5275.     )
  5276. {
  5277.     no_sfx = !toggle_sound() ;
  5278.     post_new_message( 0, 0, "Sound is %s.\n", no_sfx ? "off" : "on" ) ;
  5279. }
  5280.  
  5281.  
  5282.  
  5283. static void installColormapWithOverlay( void )
  5284. {
  5285.     Window    windows[7];
  5286.     Window    over_lay ;
  5287.     Window    popup ;
  5288.     Window    under_lay ;
  5289.     Arg        args[5] ;
  5290.     int        i ;
  5291.  
  5292.     i = 0 ;
  5293.     XtSetArg( args[i], GlxNoverlayWindow, &over_lay ) ; i++ ;
  5294.     XtSetArg( args[i], GlxNpopupWindow, &popup ) ; i++ ;
  5295.     XtSetArg( args[i], GlxNunderlayWindow, &under_lay ) ; i++ ;
  5296.     XtGetValues( radar_widget, args, i ) ;
  5297.  
  5298.     i = 0 ;
  5299.     if( over_lay ) {
  5300.         windows[i] = over_lay ;
  5301.         i++ ;
  5302.         }
  5303.     if( popup ) {
  5304.         windows[i] = popup ;
  5305.         i++ ;
  5306.         }
  5307.     if( under_lay ) {
  5308.         windows[i] = under_lay ;
  5309.         i++ ;
  5310.         }
  5311.  
  5312.     windows[i] = XtWindow( radar_widget ) ; i++ ;
  5313.     windows[i] = XtWindow( mainview_widget ) ; i++ ;
  5314.     windows[i] = XtWindow( base_widget ) ; i++ ;
  5315.     windows[i] = XtWindow( toplevel ) ; i++ ;
  5316.     XSetWMColormapWindows( XtDisplay( toplevel ), XtWindow( toplevel ),
  5317.                            windows, i ) ;
  5318. }
  5319.  
  5320.  
  5321.  
  5322. void change_cursor( void )
  5323. {
  5324.     Colormap        cmap ;
  5325.     static Cursor    bz_cursor = (Cursor)NULL ;
  5326.     XColor            fg ;
  5327.     XColor            bg ;
  5328.     
  5329.     /* define an appropriate busy cursor */
  5330.     if( bz_cursor == (Cursor)NULL ) {
  5331.         fg.pixel = AppRes.cursorForeground ;
  5332.         bg.pixel = AppRes.cursorBackground ;
  5333.         cmap = DefaultColormap( display, DefaultScreen(display) ) ;
  5334.         XQueryColor( display, cmap, &fg ) ;
  5335.         XQueryColor( display, cmap, &bg ) ;
  5336.         bz_cursor = AppRes.cursor ;
  5337.         XRecolorCursor( display, bz_cursor, &fg, &bg ) ;
  5338.         }
  5339.     XDefineCursor( display, XtWindow( radar_widget ), bz_cursor ) ;
  5340.     XDefineCursor( display, XtWindow( mainview_widget ), bz_cursor ) ;
  5341.     XDefineCursor( display, XtWindow( base_widget ), bz_cursor ) ;
  5342.     XDefineCursor( display, XtWindow( toplevel ), bz_cursor ) ;
  5343.     XFlush( display ) ;
  5344. }
  5345.  
  5346.  
  5347.  
  5348. static void setName( void )
  5349. {
  5350.     char    *name ;
  5351.  
  5352.     if( strlen( player_name ) == 0 ) {
  5353.         if( ( name = getenv( "BZ_ID" ) ) != NULL ) {
  5354.             strncpy( player_name, name, NAMELEN ) ;
  5355.             }
  5356.         else if( AppRes.identifier != NULL && strlen(AppRes.identifier) > 0 ) {
  5357.             strncpy( player_name, AppRes.identifier, NAMELEN ) ;
  5358.             }
  5359.         else {
  5360.             cuserid( player_name ) ;
  5361.             }
  5362.         }
  5363.     strncpy( player[SELF].name, player_name, NAMELEN ) ;
  5364.     player[SELF].name[NAMELEN-1] = '\0' ;
  5365. }
  5366.  
  5367.  
  5368.  
  5369. /*------------------------------------------------------------------------------
  5370.  * Next Co-pilot View - get next player for copilot view.
  5371.  *----------------------------------------------------------------------------*/
  5372. static void next_copilot_view( void )
  5373. {
  5374.     if( number_players > 1 ) {
  5375.         copilot_player++ ;
  5376.         if( copilot_player >= number_players )
  5377.             copilot_player = 1 ;
  5378.         post_new_message( 0, 0, "Co-pilot view of %s.",
  5379.                           player[copilot_player].name ) ;
  5380.         }
  5381.     else {
  5382.         show_copilot_view = FALSE ;
  5383.         }
  5384. }
  5385.  
  5386.  
  5387.  
  5388. /*------------------------------------------------------------------------------
  5389.  * Join a team (either red or blue).
  5390.  *----------------------------------------------------------------------------*/
  5391. static void join_a_team(
  5392.     int team
  5393.     )
  5394. {
  5395.     player[SELF].team = team ;
  5396.     GLXwinset( display, radar_ol_window ) ;
  5397.     drawOverlay() ;
  5398.     set_bulletin_color( teamColor[player[SELF].team] ) ;
  5399.     post_new_message( 0, 1, "Assigned to %s team.", teamName[team] ) ;
  5400.     GLXwinset( display, base_window ) ;
  5401.     redraw_base_screen() ;
  5402.     if( !show_flags && !never_have_flag ) {
  5403.         if( player[SELF].team == RED_TEAM ) {
  5404.             red_team_present = TRUE ;
  5405.             }
  5406.         else if( player[SELF].team == BLUE_TEAM ) {
  5407.             blue_team_present = TRUE ;
  5408.             }
  5409.         if( red_team_present && blue_team_present ) {
  5410.             show_flags = TRUE ;
  5411.             post_new_message( 0, 1, "Flag capturing enabled." ) ;
  5412.             }
  5413.         }
  5414. }
  5415.  
  5416.  
  5417.  
  5418. /*------------------------------------------------------------------------------
  5419.  * Send a preset message to all.
  5420.  *----------------------------------------------------------------------------*/
  5421. static void sendPresetTeamMail(
  5422.     Widget w,
  5423.     XEvent *event,
  5424.     String *params,
  5425.     Cardinal *numParams
  5426.     )
  5427. {
  5428.     int        selection ;
  5429.     char    *s ;
  5430.  
  5431.     if( solo ) {
  5432.         return ;
  5433.         }
  5434.  
  5435.     if( *numParams == 0 ) {
  5436.         selection = 1 ;
  5437.         }
  5438.     else {
  5439.         selection = atoi( params[0] ) ;
  5440.         }
  5441.  
  5442.     switch( selection ) {
  5443.  
  5444.         case 1 :
  5445.             s = AppRes.message1 ;
  5446.             break ;
  5447.  
  5448.         case 2 :
  5449.             s = AppRes.message2 ;
  5450.             break ;
  5451.  
  5452.         case 3 :
  5453.             s = AppRes.message3 ;
  5454.             break ;
  5455.  
  5456.         case 4 :
  5457.             s = AppRes.message4 ;
  5458.             break ;
  5459.  
  5460.         case 5 :
  5461.             s = AppRes.message5 ;
  5462.             break ;
  5463.  
  5464.         default :
  5465.             return ;
  5466.         }
  5467.  
  5468.     if( s && s[0] ) {
  5469.         writeTeamMail( w, event, params, numParams ) ;
  5470.         strncpy( mail_buffer, s, sizeof( mail_buffer ) - 1 ) ;
  5471.         mail_ptr = strlen( mail_buffer ) ;
  5472.         if( mail_buffer[mail_ptr-1] == '&' ) {
  5473.             mail_buffer[mail_ptr-1] = '\r' ;
  5474.             }
  5475.         }
  5476. }
  5477.  
  5478.  
  5479.  
  5480. /*------------------------------------------------------------------------------
  5481.  * Send a preset message to all.
  5482.  *----------------------------------------------------------------------------*/
  5483. static void sendPresetMail(
  5484.     Widget w,
  5485.     XEvent *event,
  5486.     String *params,
  5487.     Cardinal *numParams
  5488.     )
  5489. {
  5490.     int        selection ;
  5491.     char    *s ;
  5492.  
  5493.     if( solo ) {
  5494.         return ;
  5495.         }
  5496.  
  5497.     if( *numParams == 0 ) {
  5498.         selection = 1 ;
  5499.         }
  5500.     else {
  5501.         selection = atoi( params[0] ) ;
  5502.         }
  5503.  
  5504.     switch( selection ) {
  5505.  
  5506.         case 1 :
  5507.             s = AppRes.message1 ;
  5508.             break ;
  5509.  
  5510.         case 2 :
  5511.             s = AppRes.message2 ;
  5512.             break ;
  5513.  
  5514.         case 3 :
  5515.             s = AppRes.message3 ;
  5516.             break ;
  5517.  
  5518.         case 4 :
  5519.             s = AppRes.message4 ;
  5520.             break ;
  5521.  
  5522.         case 5 :
  5523.             s = AppRes.message5 ;
  5524.             break ;
  5525.  
  5526.         default :
  5527.             return ;
  5528.         }
  5529.  
  5530.     if( s && s[0] ) {
  5531.         writeMail( w, event, params, numParams ) ;
  5532.         strncpy( mail_buffer, s, sizeof( mail_buffer ) - 1 ) ;
  5533.         mail_ptr = strlen( mail_buffer ) ;
  5534.         if( mail_buffer[mail_ptr-1] == '&' ) {
  5535.             mail_buffer[mail_ptr-1] = '\r' ;
  5536.             }
  5537.         }
  5538. }
  5539.  
  5540.  
  5541.  
  5542. /*------------------------------------------------------------------------------
  5543.  * Reset the viewing order (intialize).
  5544.  *----------------------------------------------------------------------------*/
  5545. void reset_viewing_order( void )
  5546. {
  5547.     int    i ;
  5548.  
  5549.     for( i = 0 ; i < TOTALOBJS ; i++ ) {
  5550.         view_order[i] = i ;
  5551.         dst[i] = 0.0f ;
  5552.         }
  5553. }
  5554.  
  5555.  
  5556.  
  5557. /*------------------------------------------------------------------------------
  5558.  * Put the version number in a string.
  5559.  *----------------------------------------------------------------------------*/
  5560. char *print_version( void )
  5561. {
  5562.     long        id = ( BZ & 0x00ff ) + 15 ;
  5563.     static char    s[10] ;
  5564.  
  5565.     sprintf( s, "%d.%d.4", id / 10, id % 10 ) ;
  5566.  
  5567.     return( s ) ;
  5568. }
  5569.