home *** CD-ROM | disk | FTP | other *** search
/ Gambler 19 / GAMBLERCD19.BIN / UTILS / 3D / BRONIE / DUAL_LAU.ZIP / src / p_client.c < prev    next >
C/C++ Source or Header  |  1998-01-13  |  25KB  |  1,129 lines

  1. #include "g_local.h"
  2. #include "m_player.h"
  3.  
  4. void ClientUserinfoChanged (edict_t *ent, char *userinfo);
  5.  
  6. void SP_misc_teleporter_dest (edict_t *ent);
  7.  
  8. /*QUAKED info_player_start (1 0 0) (-16 -16 -24) (16 16 32)
  9. The normal starting point for a level.
  10. */
  11. void SP_info_player_start(void)
  12. {
  13. }
  14.  
  15. /*QUAKED info_player_deathmatch (1 0 1) (-16 -16 -24) (16 16 32)
  16. potential spawning position for deathmatch games
  17. */
  18. void SP_info_player_deathmatch(edict_t *self)
  19. {
  20.     if (!deathmatch->value)
  21.     {
  22.         G_FreeEdict (self);
  23.         return;
  24.     }
  25.     SP_misc_teleporter_dest (self);
  26. }
  27.  
  28. /*QUAKED info_player_coop (1 0 1) (-16 -16 -24) (16 16 32)
  29. potential spawning position for coop games
  30. */
  31. void SP_info_player_coop(edict_t *self)
  32. {
  33.     if ( 1) //!coop->value)
  34.     {
  35.         G_FreeEdict (self);
  36.         return;
  37.     }
  38. //    SP_misc_teleporter_dest (self);
  39. }
  40.  
  41.  
  42. /*QUAKED info_player_intermission (1 0 1) (-16 -16 -24) (16 16 32)
  43. The deathmatch intermission point will be at one of these
  44. Use 'angles' instead of 'angle', so you can set pitch or roll as well as yaw.  'pitch yaw roll'
  45. */
  46. void SP_info_player_intermission(void)
  47. {
  48. }
  49.  
  50.  
  51.  
  52. int    SexedSoundIndex (edict_t *ent, char *base)
  53. {
  54.     char    buffer[MAX_QPATH];
  55.  
  56.     Com_sprintf (buffer, sizeof(buffer), "%s/%s.wav", ent->client->pers.sounddir, base);
  57.  
  58.     return gi.soundindex(buffer);
  59. }
  60.  
  61. //=======================================================================
  62.  
  63.  
  64. void player_pain (edict_t *self, edict_t *other, float kick, int damage)
  65. {
  66.     // player pain is handled at the end of the frame in P_DamageFeedback
  67. }
  68.  
  69.  
  70. void ClientObituary (edict_t *self, edict_t *inflictor, edict_t *attacker)
  71. {
  72.     if (attacker == self)
  73.     {
  74.         gi.bprintf (PRINT_MEDIUM,"%s killed self.\n", self->client->pers.netname);
  75.         self->client->resp.score--;
  76.         self->enemy = NULL;
  77.         return;
  78.     }
  79.  
  80.     self->enemy = attacker;
  81.     if (attacker && attacker->client)
  82.     {
  83.         gi.bprintf (PRINT_MEDIUM,"%s was killed by %s\n", self->client->pers.netname, attacker->client->pers.netname);
  84.         attacker->client->resp.score++;
  85.         return;
  86.     }
  87.  
  88.     gi.bprintf (PRINT_MEDIUM,"%s died.\n", self->client->pers.netname);
  89.     self->client->resp.score--;
  90. }
  91.  
  92. void TossClientWeapon (edict_t *self)
  93. {
  94.     gitem_t        *item;
  95.     edict_t        *drop;
  96.  
  97.     if (!deathmatch->value)
  98.         return;
  99.     item = self->client->pers.weapon;
  100.     if (!item)
  101.         return;
  102.     if (! self->client->pers.inventory[self->client->ammo_index] )
  103.         return;
  104.     if (!strcmp (item->pickup_name, "Blaster"))
  105.         return;
  106.     drop = Drop_Item (self, item);
  107.     // let them have some ammo with it
  108.     drop->spawnflags = DROPPED_PLAYER_ITEM;
  109. }
  110.  
  111. /*
  112. ==================
  113. LookAtKiller
  114. ==================
  115. */
  116. void LookAtKiller (edict_t *self, edict_t *inflictor, edict_t *attacker)
  117. {
  118.     vec3_t        dir;
  119.  
  120.     if (attacker && attacker != world && attacker != self)
  121.     {
  122.         VectorSubtract (attacker->s.origin, self->s.origin, dir);
  123.     }
  124.     else if (inflictor && inflictor != world && inflictor != self)
  125.     {
  126.         VectorSubtract (inflictor->s.origin, self->s.origin, dir);
  127.     }
  128.     else
  129.     {
  130.         self->client->killer_yaw = self->s.angles[YAW];
  131.         return;
  132.     }
  133.  
  134.     self->client->killer_yaw = 180/M_PI*atan2(dir[1], dir[0]);
  135. }
  136.  
  137. /*
  138. ==================
  139. player_die
  140. ==================
  141. */
  142. void player_die (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point)
  143. {
  144.     char    sound[MAX_QPATH];
  145.     int        n;
  146.  
  147.     VectorClear (self->avelocity);
  148.  
  149.     self->takedamage = DAMAGE_YES;
  150.     self->movetype = MOVETYPE_TOSS;
  151.  
  152.     self->s.modelindex2 = 0;    // remove linked weapon model
  153.  
  154.     self->s.angles[0] = 0;
  155.     self->s.angles[2] = 0;
  156.  
  157.     self->s.sound = 0;
  158.     self->client->weapon_sound = 0;
  159.  
  160.     self->maxs[2] = -8;
  161.  
  162.     self->solid = SOLID_NOT;
  163.  
  164.     if (!self->deadflag)
  165.     {
  166.         self->client->respawn_time = level.time + 1.0;
  167.         LookAtKiller (self, inflictor, attacker);
  168.         self->client->ps.pmove.pm_type = PM_DEAD;
  169.         ClientObituary (self, inflictor, attacker);
  170.         TossClientWeapon (self);
  171.         if (deathmatch->value)
  172.             Cmd_Help_f (self);        // show scores
  173.         memset (self->client->pers.inventory, 0, sizeof(self->client->pers.inventory));
  174.     }
  175.  
  176.     if (self->health < -40)
  177.     {    // gib
  178.         gi.sound (self, CHAN_BODY, gi.soundindex ("misc/udeath.wav"), 1, ATTN_NORM, 0);
  179.         for (n= 0; n < 4; n++)
  180.             ThrowGib (self, "models/objects/gibs/sm_meat/tris.md2", damage, GIB_ORGANIC);
  181.         ThrowClientHead (self, damage);
  182.  
  183.         self->takedamage = DAMAGE_NO;
  184.     }
  185.     else
  186.     {    // normal death
  187.         if (!self->deadflag)
  188.         {
  189.             static int i;
  190.  
  191.             i = (i+1)%3;
  192.             // start a death animation
  193.             self->client->anim_priority = ANIM_DEATH;
  194.             if (self->client->ps.pmove.pm_flags & PMF_DUCKED)
  195.             {
  196.                 self->s.frame = FRAME_crdeath1-1;
  197.                 self->client->anim_end = FRAME_crdeath5;
  198.             }
  199.             else switch (i)
  200.             {
  201.             case 0:
  202.                 self->s.frame = FRAME_death101-1;
  203.                 self->client->anim_end = FRAME_death106;
  204.                 break;
  205.             case 1:
  206.                 self->s.frame = FRAME_death201-1;
  207.                 self->client->anim_end = FRAME_death206;
  208.                 break;
  209.             case 2:
  210.                 self->s.frame = FRAME_death301-1;
  211.                 self->client->anim_end = FRAME_death308;
  212.                 break;
  213.             }
  214.             Com_sprintf(sound, sizeof(sound), "death%i", (rand()%4)+1);
  215.             gi.sound (self, CHAN_VOICE, SexedSoundIndex(self,sound), 1, ATTN_NORM, 0);
  216.         }
  217.     }
  218.  
  219. // FIXME once we have death frames
  220. //    self->deadflag = DEAD_DYING;
  221.     self->deadflag = DEAD_DEAD;
  222.  
  223.     gi.linkentity (self);
  224. }
  225.  
  226. //=======================================================================
  227.  
  228. /*
  229. ==============
  230. InitClientPersistant
  231.  
  232. This is only called when the game first initializes in single player,
  233. but is called after each death and level change in deathmatch
  234. ==============
  235. */
  236. void InitClientPersistant (gclient_t *client)
  237. {
  238.     gitem_t        *item;
  239.  
  240.     memset (&client->pers, 0, sizeof(client->pers));
  241.  
  242.     item = FindItem("Blaster");
  243.     client->pers.selected_item = ITEM_INDEX(item);
  244.     client->pers.inventory[client->pers.selected_item] = 1;
  245.  
  246.     client->pers.weapon = item;
  247.  
  248.     client->pers.health            = 100;
  249.     client->pers.max_health        = 100;
  250.  
  251.     client->pers.max_bullets    = 200;
  252.     client->pers.max_shells        = 100;
  253.     client->pers.max_rockets    = 50;
  254.     client->pers.max_grenades    = 50;
  255.     client->pers.max_cells        = 200;
  256.     client->pers.max_slugs        = 50;
  257.  
  258.     //Patch
  259.     client->pers.grenade_type    = 0;
  260. }
  261.  
  262.  
  263. void InitClientResp (gclient_t *client)
  264. {
  265.     memset (&client->resp, 0, sizeof(client->resp));
  266.     client->resp.enterframe = level.framenum;
  267. }
  268.  
  269. /*
  270. ==================
  271. SaveClientData
  272.  
  273. Some information that should be persistant, like health, 
  274. is still stored in the edict structure, so it needs to
  275. be mirrored out to the client structure before all the
  276. edicts are wiped.
  277. ==================
  278. */
  279. void SaveClientData (void)
  280. {
  281.     int        i;
  282.     edict_t    *ent;
  283.  
  284.     for (i=0 ; i<game.maxclients ; i++)
  285.     {
  286.         ent = &g_edicts[1+i];
  287.         if (!ent->inuse)
  288.             continue;
  289.         game.clients[i].pers.health = ent->health;
  290.         game.clients[i].pers.max_health = ent->max_health;
  291.     }
  292. }
  293.  
  294. void FetchClientEntData (edict_t *ent)
  295. {
  296.     ent->health = ent->client->pers.health;
  297.     ent->max_health = ent->client->pers.max_health;
  298. }
  299.  
  300.  
  301.  
  302. /*
  303. =======================================================================
  304.  
  305.   SelectSpawnPoint
  306.  
  307. =======================================================================
  308. */
  309.  
  310. /*
  311. ================
  312. PlayersRangeFromSpot
  313.  
  314. Returns the distance to the nearest player from the given spot
  315. ================
  316. */
  317. float    PlayersRangeFromSpot (edict_t *spot)
  318. {
  319.     edict_t    *player;
  320.     float    bestplayerdistance;
  321.     vec3_t    v;
  322.     int        n;
  323.     float    playerdistance;
  324.  
  325.  
  326.     bestplayerdistance = 9999999;
  327.  
  328.     for (n = 1; n <= maxclients->value; n++)
  329.     {
  330.         player = &g_edicts[n];
  331.  
  332.         if (!player->inuse)
  333.             continue;
  334.  
  335.         if (player->health <= 0)
  336.             continue;
  337.  
  338.         VectorSubtract (spot->s.origin, player->s.origin, v);
  339.         playerdistance = VectorLength (v);
  340.  
  341.         if (playerdistance < bestplayerdistance)
  342.             bestplayerdistance = playerdistance;
  343.     }
  344.  
  345.     return bestplayerdistance;
  346. }
  347.  
  348. /*
  349. ================
  350. SelectRandomDeathmatchSpawnPoint
  351.  
  352. go to a random point, but NOT the two points closest
  353. to other players
  354. ================
  355. */
  356. edict_t *SelectRandomDeathmatchSpawnPoint (void)
  357. {
  358.     edict_t    *spot, *spot1, *spot2;
  359.     int        count = 0;
  360.     int        selection;
  361.     float    range, range1, range2;
  362.  
  363.     spot = NULL;
  364.     range1 = range2 = 99999;
  365.     spot1 = spot2 = NULL;
  366.  
  367.     while ((spot = G_Find (spot, FOFS(classname), "info_player_deathmatch")) != NULL)
  368.     {
  369.         count++;
  370.         range = PlayersRangeFromSpot(spot);
  371.         if (range < range1)
  372.         {
  373.             range1 = range;
  374.             spot1 = spot;
  375.         }
  376.         else if (range < range2)
  377.         {
  378.             range2 = range;
  379.             spot2 = spot;
  380.         }
  381.     }
  382.  
  383.     if (!count)
  384.         return NULL;
  385.  
  386.     if (count <= 2)
  387.     {
  388.         spot1 = spot2 = NULL;
  389.     }
  390.     else
  391.         count -= 2;
  392.  
  393.     selection = rand() % count;
  394.  
  395.     spot = NULL;
  396.     do
  397.     {
  398.         spot = G_Find (spot, FOFS(classname), "info_player_deathmatch");
  399.         if (spot == spot1 || spot == spot2)
  400.             selection++;
  401.     } while(selection--);
  402.  
  403.     return spot;
  404. }
  405.  
  406. /*
  407. ================
  408. SelectFarthestDeathmatchSpawnPoint
  409.  
  410. ================
  411. */
  412. edict_t *SelectFarthestDeathmatchSpawnPoint (void)
  413. {
  414.     edict_t    *bestspot;
  415.     float    bestdistance, bestplayerdistance;
  416.     edict_t    *spot;
  417.  
  418.  
  419.     spot = NULL;
  420.     bestspot = NULL;
  421.     bestdistance = 0;
  422.     while ((spot = G_Find (spot, FOFS(classname), "info_player_deathmatch")) != NULL)
  423.     {
  424.         bestplayerdistance = PlayersRangeFromSpot (spot);
  425.  
  426.         if (bestplayerdistance > bestdistance)
  427.         {
  428.             bestspot = spot;
  429.             bestdistance = bestplayerdistance;
  430.         }
  431.     }
  432.  
  433.     if (bestspot)
  434.     {
  435.         return bestspot;
  436.     }
  437.  
  438.     // if there is a player just spawned on each and every start spot
  439.     // we have no choice to turn one into a telefrag meltdown
  440.     spot = G_Find (NULL, FOFS(classname), "info_player_deathmatch");
  441.  
  442.     return spot;
  443. }
  444.  
  445. edict_t *SelectDeathmatchSpawnPoint (void)
  446. {
  447.     if ( (int)(dmflags->value) & DF_SPAWN_FARTHEST)
  448.         return SelectFarthestDeathmatchSpawnPoint ();
  449.     else
  450.         return SelectRandomDeathmatchSpawnPoint ();
  451. }
  452.  
  453.  
  454. edict_t *SelectCoopSpawnPoint (void)
  455. {
  456.     edict_t    *spot = NULL;
  457.  
  458.     while ((spot = G_Find (spot, FOFS(classname), "info_player_coop")) != NULL)
  459.     {
  460.         if (!game.spawnpoint[0] && !spot->targetname)
  461.             break;
  462.  
  463.         if (!game.spawnpoint[0] || !spot->targetname)
  464.             continue;
  465.  
  466.         if (Q_stricmp(game.spawnpoint, spot->targetname) == 0)
  467.             break;
  468.     }
  469.     return spot;
  470. }
  471.  
  472.  
  473. /*
  474. ===========
  475. SelectSpawnPoint
  476.  
  477. Chooses a player start, deathmatch start, coop start, etc
  478. ============
  479. */
  480. void    SelectSpawnPoint (vec3_t origin, vec3_t angles)
  481. {
  482.     edict_t    *spot = NULL;
  483.  
  484.     if (deathmatch->value)
  485.         spot = SelectDeathmatchSpawnPoint ();
  486. #if 0
  487.     else if (coop->value)
  488.         spot = SelectCoopSpawnPoint ();
  489. #endif
  490.  
  491.     // find a single player start spot
  492.     if (!spot)
  493.     {
  494.         while ((spot = G_Find (spot, FOFS(classname), "info_player_start")) != NULL)
  495.         {
  496.             if (!game.spawnpoint[0] && !spot->targetname)
  497.                 break;
  498.  
  499.             if (!game.spawnpoint[0] || !spot->targetname)
  500.                 continue;
  501.  
  502.             if (Q_stricmp(game.spawnpoint, spot->targetname) == 0)
  503.                 break;
  504.         }
  505.  
  506.         if (!spot)
  507.         {
  508.             if (!game.spawnpoint[0])
  509.             {    // there wasn't a spawnpoint without a target, so use any
  510.                 spot = G_Find (spot, FOFS(classname), "info_player_start");
  511.             }
  512.             if (!spot)
  513.                 gi.error ("Couldn't find spawn point %s\n", game.spawnpoint);
  514.         }
  515.     }
  516.  
  517.     VectorCopy (spot->s.origin, origin);
  518.     origin[2] += 9;
  519.     VectorCopy (spot->s.angles, angles);
  520. }
  521.  
  522. //======================================================================
  523.  
  524.  
  525. void InitBodyQue (void)
  526. {
  527.     int        i;
  528.     edict_t    *ent, *head;
  529.  
  530.     head = G_Spawn();
  531.     head->chain = head;
  532.     level.body_que = head;
  533.  
  534.     for (i=0 ; i<7 ; i++)
  535.     {
  536.         ent = G_Spawn();
  537.         ent->chain = head->chain;
  538.         head->chain = ent;
  539.     }
  540. }
  541.  
  542. void CopyToBodyQue (edict_t *ent)
  543. {
  544.     edict_t        *body;
  545.  
  546.     // grab a body que and cycle to the next one
  547.     body = level.body_que;
  548.     level.body_que = body->chain;
  549.  
  550.     // FIXME: send an effect on the removed body
  551.  
  552.     gi.unlinkentity (ent);
  553.  
  554.     gi.unlinkentity (body);
  555.     body->s = ent->s;
  556.     body->s.number = body - g_edicts;
  557.  
  558.     // FIXME: make fall to ground?
  559.     gi.linkentity (body);
  560. }
  561.  
  562.  
  563. void respawn (edict_t *self)
  564. {
  565.     if (deathmatch->value /*|| coop->value */)
  566.     {
  567.         // FIXME: make bodyque objects obey gravity
  568.         CopyToBodyQue (self);
  569.         PutClientInServer (self);
  570.  
  571.         // add a teleportation effect
  572.         self->s.event = EV_PLAYER_TELEPORT;
  573.  
  574.         // hold in place briefly
  575.         self->client->ps.pmove.teleport_time = 50;
  576.         return;
  577.     }
  578.  
  579.     // restart the entire server
  580.     gi.AddCommandString ("menu_loadgame\n");
  581. }
  582.  
  583. //==============================================================
  584.  
  585.  
  586. /*
  587. ===========
  588. PutClientInServer
  589.  
  590. Called when a player connects to a server or respawns in
  591. a deathmatch.
  592. ============
  593. */
  594. void PutClientInServer (edict_t *ent)
  595. {
  596.     vec3_t    mins = {-16, -16, -24};
  597.     vec3_t    maxs = {16, 16, 32};
  598.     int        index;
  599.     vec3_t    spawn_origin, spawn_angles;
  600.     gclient_t    *client;
  601.     int        i;
  602.     client_persistant_t    saved;
  603.     client_respawn_t    resp;
  604.  
  605.     // find a spawn point
  606.     // do it before setting health back up, so farthest
  607.     // ranging doesn't count this client
  608.     SelectSpawnPoint (spawn_origin, spawn_angles);
  609.  
  610.     index = ent-g_edicts-1;
  611.     client = ent->client;
  612.  
  613.     // deathmatch wipes most client data every spawn
  614.     if (deathmatch->value)
  615.     {
  616.         char        userinfo[MAX_INFO_STRING];
  617.  
  618.         resp = ent->client->resp;
  619.         memcpy (userinfo, client->pers.userinfo, sizeof(userinfo));
  620.         InitClientPersistant (client);
  621.         ClientUserinfoChanged (ent, userinfo);
  622.     }
  623.     else
  624.         memset (&resp, 0, sizeof(resp));
  625.  
  626.     // clear everything but the persistant data
  627.     saved = client->pers;
  628.     memset (client, 0, sizeof(*client));
  629.     client->pers = saved;
  630.     client->resp = resp;
  631.  
  632.     // copy some data from the client to the entity
  633.     FetchClientEntData (ent);
  634.  
  635.     // clear entity values
  636.     ent->groundentity = NULL;
  637.     ent->client = &game.clients[index];
  638.     ent->takedamage = DAMAGE_AIM;
  639.     ent->movetype = MOVETYPE_WALK;
  640.     ent->viewheight = 22;
  641.     ent->inuse = true;
  642.     ent->classname = "player";
  643.     ent->mass = 200;
  644.     ent->solid = SOLID_BBOX;
  645.     ent->deadflag = DEAD_NO;
  646.     ent->air_finished = level.time + 12;
  647.     ent->clipmask = MASK_PLAYERSOLID;
  648.     ent->model = "players/male/tris.md2";
  649.     ent->pain = player_pain;
  650.     ent->die = player_die;
  651.     ent->waterlevel = 0;
  652.     ent->watertype = 0;
  653.     ent->flags &= ~FL_NO_KNOCKBACK;
  654.  
  655.     VectorCopy (mins, ent->mins);
  656.     VectorCopy (maxs, ent->maxs);
  657.     VectorClear (ent->velocity);
  658.  
  659.     // clear playerstate values
  660.     memset (&ent->client->ps, 0, sizeof(client->ps));
  661.  
  662.     client->ps.pmove.origin[0] = spawn_origin[0]*8;
  663.     client->ps.pmove.origin[1] = spawn_origin[1]*8;
  664.     client->ps.pmove.origin[2] = spawn_origin[2]*8;
  665.  
  666.     client->ps.fov = 90;
  667.     client->ps.gunindex = gi.modelindex(client->pers.weapon->view_model);
  668.  
  669.     // clear entity state values
  670.     ent->s.effects = 0;
  671.     ent->s.skinnum = ent - g_edicts - 1;
  672.     ent->s.modelindex = 255;        // will use the skin specified model
  673.     ent->s.modelindex2 = 255;        // custom gun model
  674.     ent->s.frame = 0;
  675.     VectorCopy (spawn_origin, ent->s.origin);
  676.     ent->s.origin[2] += 1;    // make sure off ground
  677.  
  678.     // set the delta angle
  679.     for (i=0 ; i<3 ; i++)
  680.         client->ps.pmove.delta_angles[i] = ANGLE2SHORT(spawn_angles[i] - client->resp.cmd_angles[i]);
  681.  
  682.     ent->s.angles[PITCH] = 0;
  683.     ent->s.angles[YAW] = spawn_angles[YAW];
  684.     ent->s.angles[ROLL] = 0;
  685.     VectorCopy (ent->s.angles, client->ps.viewangles);
  686.     VectorCopy (ent->s.angles, client->v_angle);
  687.  
  688.     if (!KillBox (ent))
  689.     {    // could't spawn in?
  690.     }
  691.  
  692.     gi.linkentity (ent);
  693.  
  694.     // force the current weapon up
  695.     client->newweapon = client->pers.weapon;
  696.     ChangeWeapon (ent);
  697. }
  698.  
  699. /*
  700. =====================
  701. ClientBeginDeathmatch
  702.  
  703. A client has just connected to the server in 
  704. deathmatch mode, so clear everything out before starting them.
  705. =====================
  706. */
  707. void ClientBeginDeathmatch (edict_t *ent)
  708. {
  709.     G_InitEdict (ent);
  710.  
  711.     InitClientResp (ent->client);
  712.  
  713.     // locate ent at a spawn point
  714.     PutClientInServer (ent);
  715.  
  716.     // send effect
  717.     gi.WriteByte (svc_muzzleflash);
  718.     gi.WriteShort (ent-g_edicts);
  719.     gi.WriteByte (MZ_LOGIN);
  720.     gi.multicast (ent->s.origin, MULTICAST_PVS);
  721.  
  722.     gi.bprintf (PRINT_HIGH, "%s entered the game\n", ent->client->pers.netname);
  723.  
  724.     // make sure all view stuff is valid
  725.     ClientEndServerFrame (ent);
  726. }
  727.  
  728.  
  729. /*
  730. ===========
  731. ClientBegin
  732.  
  733. called when a client has finished connecting, and is ready
  734. to be placed into the game.  This will happen every level load.
  735. ============
  736. */
  737. void ClientBegin (edict_t *ent, qboolean loadgame)
  738. {
  739.     int        i;
  740.  
  741.     if (deathmatch->value)
  742.     {
  743.         ClientBeginDeathmatch (ent);
  744.         return;
  745.     }
  746.  
  747.     if (loadgame && ent->classname && !strcmp(ent->classname, "player") )
  748.     {
  749.         // a loadgame will just use the entity exactly as it is
  750.         // if more clients connect than were saved, they will be
  751.         // spawned as normal
  752.         ent->inuse = true;
  753.  
  754.         // the client has cleared the client side viewangles upon
  755.         // connecting to the server, which is different than the
  756.         // state when the game is saved, so we need to compensate
  757.         // with deltaangles
  758.         for (i=0 ; i<3 ; i++)
  759.             ent->client->ps.pmove.delta_angles[i] = ANGLE2SHORT(ent->client->ps.viewangles[i]);
  760.     }
  761.     else
  762.     {
  763.         // a spawn point will completely reinitialize the entity
  764.         G_InitEdict (ent);
  765.         InitClientResp (ent->client);
  766.         PutClientInServer (ent);
  767.     }
  768.  
  769.     if (level.intermissiontime)
  770.     {
  771.         MoveClientToIntermission (ent);
  772.     }
  773.     else
  774.     {
  775.         // send effect if in a multiplayer game
  776.         if (game.maxclients > 1)
  777.         {
  778.             gi.WriteByte (svc_muzzleflash);
  779.             gi.WriteShort (ent-g_edicts);
  780.             gi.WriteByte (MZ_LOGIN);
  781.             gi.multicast (ent->s.origin, MULTICAST_PVS);
  782.  
  783.             gi.bprintf (PRINT_HIGH, "%s entered the game\n", ent->client->pers.netname);
  784.         }
  785.     }
  786.  
  787.     // make sure all view stuff is valid
  788.     ClientEndServerFrame (ent);
  789. }
  790.  
  791. /*
  792. ===========
  793. ClientUserInfoChanged
  794.  
  795. called whenever the player updates a userinfo variable.
  796.  
  797. The game can override any of the settings in place
  798. (forcing skins or names, etc) before copying it off.
  799. ============
  800. */
  801. void ClientUserinfoChanged (edict_t *ent, char *userinfo)
  802. {
  803.     char    *s;
  804.     int        playernum;
  805.  
  806.     // set name
  807.     s = Info_ValueForKey (userinfo, "name");
  808.     strncpy (ent->client->pers.netname, s, sizeof(ent->client->pers.netname)-1);
  809.  
  810.     // set skin
  811.     s = Info_ValueForKey (userinfo, "skin");
  812.  
  813.     // decide sound directory
  814.     if (s[0] == 'f' || s[0] == 'F')
  815.         strcpy (ent->client->pers.sounddir, "player/female");
  816.     else
  817.         strcpy (ent->client->pers.sounddir, "player/male");
  818.  
  819.     playernum = ent-g_edicts-1;
  820.  
  821.     // combine name and skin into a configstring
  822.     gi.configstring (CS_PLAYERSKINS+playernum, va("%s\\%s", ent->client->pers.netname, s) );
  823.  
  824.     // handedness
  825.     s = Info_ValueForKey (userinfo, "hand");
  826.     if (strlen(s))
  827.     {
  828.         ent->client->pers.hand = atoi(s);
  829.     }
  830.  
  831.     // save off the userinfo in case we want to check something later
  832.     strncpy (ent->client->pers.userinfo, userinfo, sizeof(ent->client->pers.userinfo)-1);
  833. }
  834.  
  835.  
  836. /*
  837. ===========
  838. ClientConnect
  839.  
  840. Called when a player begins connecting to the server.
  841. The game can refuse entrance to a client by returning false.
  842. If the client is allowed, the connection process will continue
  843. and eventually get to ClientBegin()
  844. Changing levels will NOT cause this to be called again.
  845. ============
  846. */
  847. qboolean ClientConnect (edict_t *ent, char *userinfo, qboolean loadgame)
  848. {
  849.     if (!loadgame)
  850.     {
  851.         // clear the respawning variables
  852.         InitClientResp (ent->client);
  853.         InitClientPersistant (ent->client);
  854.     }
  855.  
  856.     ClientUserinfoChanged (ent, userinfo);
  857.  
  858.     if (game.maxclients > 1)
  859.         gi.dprintf ("%s connected\n", ent->client->pers.netname);
  860.  
  861.     level.players++;
  862.     return true;
  863. }
  864.  
  865. /*
  866. ===========
  867. ClientDisconnect
  868.  
  869. called when a player drops from the server
  870.  
  871. ============
  872. */
  873. void ClientDisconnect (edict_t *ent)
  874. {
  875.     int        playernum;
  876.  
  877.     if (!ent->client)
  878.         return;
  879.  
  880.     gi.bprintf (PRINT_HIGH, "%s disconnected\n", ent->client->pers.netname);
  881.  
  882.     // send effect
  883.     gi.WriteByte (svc_muzzleflash);
  884.     gi.WriteShort (ent-g_edicts);
  885.     gi.WriteByte (MZ_LOGOUT);
  886.     gi.multicast (ent->s.origin, MULTICAST_PVS);
  887.  
  888.     ent->s.modelindex = 0;
  889.     ent->solid = SOLID_NOT;
  890.     gi.linkentity (ent);
  891.  
  892.     ent->inuse = false;
  893.  
  894.     level.players--;
  895.  
  896.     playernum = ent-g_edicts-1;
  897.     gi.configstring (CS_PLAYERSKINS+playernum, "");
  898. }
  899.  
  900.  
  901. //==============================================================
  902.  
  903.  
  904. void respawn (edict_t *self);
  905.  
  906. edict_t    *pm_passent;
  907.  
  908. // pmove doesn't need to know about passent and contentmask
  909. trace_t    PM_trace (vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end)
  910. {
  911.     if (pm_passent->health > 0)
  912.         return gi.trace (start, mins, maxs, end, pm_passent, MASK_PLAYERSOLID);
  913.     else
  914.         return gi.trace (start, mins, maxs, end, pm_passent, MASK_DEADSOLID);
  915. }
  916.  
  917. unsigned CheckBlock (void *b, int c)
  918. {
  919.     int    v,i;
  920.     v = 0;
  921.     for (i=0 ; i<c ; i++)
  922.         v+= ((byte *)b)[i];
  923.     return v;
  924. }
  925. void PrintPmove (pmove_t *pm)
  926. {
  927.     unsigned    c1, c2;
  928.  
  929.     c1 = CheckBlock (&pm->s, sizeof(pm->s));
  930.     c2 = CheckBlock (&pm->cmd, sizeof(pm->cmd));
  931.     Com_Printf ("sv %3i:%i %i\n", pm->cmd.impulse, c1, c2);
  932. }
  933.  
  934. /*
  935. ==============
  936. ClientThink
  937.  
  938. This will be called once for each client frame, which will
  939. usually be a couple times for each server frame.
  940. ==============
  941. */
  942. void ClientThink (edict_t *ent, usercmd_t *ucmd)
  943. {
  944.     gclient_t    *client;
  945.     edict_t    *other;
  946.     int        i, j;
  947.     pmove_t    pm;
  948.  
  949.     level.current_entity = ent;
  950.     client = ent->client;
  951.  
  952.     if (level.intermissiontime)
  953.     {
  954.         client->ps.pmove.pm_type = PM_FREEZE;
  955.         // can exit intermission after five seconds
  956.         if (level.time > level.intermissiontime + 5.0 
  957.             && (ucmd->buttons & BUTTON_ANY) )
  958.             level.exitintermission = true;
  959.         return;
  960.     }
  961.  
  962.     pm_passent = ent;
  963.  
  964.     // set up for pmove
  965.     memset (&pm, 0, sizeof(pm));
  966.  
  967.     if (ent->movetype == MOVETYPE_NOCLIP)
  968.         client->ps.pmove.pm_type = PM_SPECTATOR;
  969.     else if (ent->s.modelindex != 255)
  970.         client->ps.pmove.pm_type = PM_GIB;
  971.     else if (ent->deadflag)
  972.         client->ps.pmove.pm_type = PM_DEAD;
  973.     else
  974.         client->ps.pmove.pm_type = PM_NORMAL;
  975.  
  976.     client->ps.pmove.gravity = sv_gravity->value;
  977.     pm.s = client->ps.pmove;
  978.  
  979.     for (i=0 ; i<3 ; i++)
  980.     {
  981.         pm.s.origin[i] = ent->s.origin[i]*8;
  982.         pm.s.velocity[i] = ent->velocity[i]*8;
  983.     }
  984.  
  985.     if (memcmp(&client->old_pmove, &pm.s, sizeof(pm.s)))
  986.     {
  987.         pm.snapinitial = true;
  988. //        gi.dprintf ("pmove changed!\n");
  989.     }
  990.  
  991.     pm.cmd = *ucmd;
  992.  
  993.     pm.trace = PM_trace;    // adds default parms
  994.     pm.pointcontents = gi.pointcontents;
  995.  
  996.     // perform a pmove
  997.     gi.Pmove (&pm);
  998.  
  999.     // save results of pmove
  1000.     client->ps.pmove = pm.s;
  1001.     client->old_pmove = pm.s;
  1002.  
  1003.     for (i=0 ; i<3 ; i++)
  1004.     {
  1005.         ent->s.origin[i] = pm.s.origin[i]*0.125;
  1006.         ent->velocity[i] = pm.s.velocity[i]*0.125;
  1007.     }
  1008.  
  1009.     VectorCopy (pm.mins, ent->mins);
  1010.     VectorCopy (pm.maxs, ent->maxs);
  1011.  
  1012.     client->resp.cmd_angles[0] = SHORT2ANGLE(ucmd->angles[0]);
  1013.     client->resp.cmd_angles[1] = SHORT2ANGLE(ucmd->angles[1]);
  1014.     client->resp.cmd_angles[2] = SHORT2ANGLE(ucmd->angles[2]);
  1015.  
  1016.     if (ent->groundentity && !pm.groundentity && (pm.cmd.upmove >= 10) && (pm.waterlevel == 0))
  1017.     {
  1018.         gi.sound(ent, CHAN_VOICE, SexedSoundIndex(ent, "jump1"), 1, ATTN_NORM, 0);
  1019.         PlayerNoise(ent, ent->s.origin, PNOISE_SELF);
  1020.     }
  1021.  
  1022.     ent->viewheight = pm.viewheight;
  1023.     ent->waterlevel = pm.waterlevel;
  1024.     ent->watertype = pm.watertype;
  1025.     ent->groundentity = pm.groundentity;
  1026.     if (pm.groundentity)
  1027.         ent->groundentity_linkcount = pm.groundentity->linkcount;
  1028.  
  1029.     if (ent->deadflag)
  1030.     {
  1031.         client->ps.viewangles[ROLL] = 40;
  1032.         client->ps.viewangles[PITCH] = -15;
  1033.         client->ps.viewangles[YAW] = client->killer_yaw;
  1034.     }
  1035.     else
  1036.     {
  1037.         VectorCopy (pm.viewangles, client->v_angle);
  1038.         VectorCopy (pm.viewangles, client->ps.viewangles);
  1039.     }
  1040.  
  1041.  
  1042.     gi.linkentity (ent);
  1043.  
  1044.     if (ent->movetype != MOVETYPE_NOCLIP)
  1045.         G_TouchTriggers (ent);
  1046.  
  1047.     // touch other objects
  1048.     for (i=0 ; i<pm.numtouch ; i++)
  1049.     {
  1050.         other = pm.touchents[i];
  1051.         for (j=0 ; j<i ; j++)
  1052.             if (pm.touchents[j] == other)
  1053.                 break;
  1054.         if (j != i)
  1055.             continue;    // duplicated
  1056.         if (!other->touch)
  1057.             continue;
  1058.         other->touch (other, ent, NULL, NULL);
  1059.     }
  1060.  
  1061.  
  1062.     client->oldbuttons = client->buttons;
  1063.     client->buttons = ucmd->buttons;
  1064.     client->latched_buttons |= client->buttons & ~client->oldbuttons;
  1065.  
  1066.     // save light level the player is standing on for
  1067.     // monster sighting AI
  1068.     ent->light_level = ucmd->lightlevel;
  1069.  
  1070.     // fire weapon from final position if needed
  1071.     if (client->latched_buttons & BUTTON_ATTACK)
  1072.     {
  1073.         if (!client->weapon_thunk)
  1074.         {
  1075.             client->weapon_thunk = true;
  1076.             Think_Weapon (ent);
  1077.         }
  1078.     }
  1079.  
  1080.  
  1081. }
  1082.  
  1083.  
  1084. /*
  1085. ==============
  1086. ClientBeginServerFrame
  1087.  
  1088. This will be called once for each server frame, before running
  1089. any other entities in the world.
  1090. ==============
  1091. */
  1092. void ClientBeginServerFrame (edict_t *ent)
  1093. {
  1094.     gclient_t    *client;
  1095.  
  1096.     if (level.intermissiontime)
  1097.         return;
  1098.  
  1099.     client = ent->client;
  1100.  
  1101.     // run weapon animations if it hasn't been done by a ucmd_t
  1102.     if (!client->weapon_thunk)
  1103.         Think_Weapon (ent);
  1104.     else
  1105.         client->weapon_thunk = false;
  1106.  
  1107.     if (ent->deadflag)
  1108.     {
  1109.         // wait for any button just going down
  1110.         if ( level.time > client->respawn_time)
  1111.         {
  1112.             if (client->latched_buttons ||
  1113.                 (deathmatch->value && ((int)dmflags->value & DF_FORCE_RESPAWN) ) )
  1114.             {
  1115.                 respawn(ent);
  1116.                 client->latched_buttons = 0;
  1117.             }
  1118.         }
  1119.         return;
  1120.     }
  1121.  
  1122.     // add player trail so monsters can follow
  1123.     if (!deathmatch->value)
  1124.         if (!visible (ent, PlayerTrail_LastSpot() ) )
  1125.             PlayerTrail_Add (ent->s.old_origin);
  1126.  
  1127.     client->latched_buttons = 0;
  1128. }
  1129.