46 spot =
G_Find(spot,
FOFS(classname),
"info_player_start");
49 if (!spot->targetname)
51 VectorSubtract(self->s.origin, spot->s.origin, d);
52 if (VectorLength(d) < 384) {
53 if ((!self->targetname) || Q_stricmp(self->targetname, spot->targetname) != 0) {
55 self->targetname = spot->targetname;
72 spot->classname =
"info_player_coop";
73 spot->s.origin[0] = 188 - 64;
74 spot->s.origin[1] = -164;
75 spot->s.origin[2] = 80;
76 spot->targetname =
"jail3";
77 spot->s.angles[1] = 90;
80 spot->classname =
"info_player_coop";
81 spot->s.origin[0] = 188 + 64;
82 spot->s.origin[1] = -164;
83 spot->s.origin[2] = 80;
84 spot->targetname =
"jail3";
85 spot->s.angles[1] = 90;
88 spot->classname =
"info_player_coop";
89 spot->s.origin[0] = 188 + 128;
90 spot->s.origin[1] = -164;
91 spot->s.origin[2] = 80;
92 spot->targetname =
"jail3";
93 spot->s.angles[1] = 90;
184 if (info[0] ==
'f' || info[0] ==
'F')
197 if (info[0] !=
'f' && info[0] !=
'F' && info[0] !=
'm' && info[0] !=
'M')
209 if (
coop->value && attacker->client)
220 message =
"suicides";
223 message =
"cratered";
226 message =
"was squished";
229 message =
"sank like a rock";
235 message =
"does a back flip into the lava";
242 message =
"found a way out";
245 message =
"saw the light";
248 message =
"got blasted";
253 message =
"was in the wrong place";
256 if (attacker ==
self) {
259 message =
"tried to put the pin back in";
264 message =
"tripped on its own grenade";
266 message =
"tripped on her own grenade";
268 message =
"tripped on his own grenade";
272 message =
"blew itself up";
274 message =
"blew herself up";
276 message =
"blew himself up";
279 message =
"should have used a smaller gun";
283 message =
"killed itself";
285 message =
"killed herself";
287 message =
"killed himself";
292 gi.bprintf(PRINT_MEDIUM,
"%s %s.\n", self->client->pers.netname, message);
294 self->client->resp.score--;
299 self->enemy = attacker;
300 if (attacker && attacker->client) {
303 message =
"was blasted by";
306 message =
"was gunned down by";
309 message =
"was blown away by";
310 message2 =
"'s super shotgun";
313 message =
"was machinegunned by";
316 message =
"was cut in half by";
317 message2 =
"'s chaingun";
320 message =
"was popped by";
321 message2 =
"'s grenade";
324 message =
"was shredded by";
325 message2 =
"'s shrapnel";
329 message2 =
"'s rocket";
332 message =
"almost dodged";
333 message2 =
"'s rocket";
336 message =
"was melted by";
337 message2 =
"'s hyperblaster";
340 message =
"was railed by";
343 message =
"saw the pretty lights from";
347 message =
"was disintegrated by";
348 message2 =
"'s BFG blast";
351 message =
"couldn't hide from";
356 message2 =
"'s handgrenade";
359 message =
"didn't see";
360 message2 =
"'s handgrenade";
364 message2 =
"'s pain";
367 message =
"tried to invade";
368 message2 =
"'s personal space";
372 gi.bprintf(PRINT_MEDIUM,
"%s %s %s%s\n", self->client->pers.netname, message, attacker->client->pers.netname, message2);
375 attacker->client->resp.score--;
377 attacker->client->resp.score++;
384 gi.bprintf(PRINT_MEDIUM,
"%s died.\n", self->client->pers.netname);
386 self->client->resp.score--;
390 void Touch_Item(edict_t *ent, edict_t *
other, cplane_t *plane, csurface_t *surf);
402 item =
self->client->pers.weapon;
403 if (! self->client->pers.inventory[self->client->ammo_index])
405 if (item && (strcmp(item->
pickup_name,
"Blaster") == 0))
408 if (!((
int)(
dmflags->value) & DF_QUAD_DROP))
411 quad = (
self->client->quad_framenum > (
level.
framenum + 10));
419 self->client->v_angle[YAW] -= spread;
421 self->client->v_angle[YAW] += spread;
426 self->client->v_angle[YAW] += spread;
428 self->client->v_angle[YAW] -= spread;
443 void LookAtKiller(edict_t *
self, edict_t *inflictor, edict_t *attacker)
447 if (attacker && attacker !=
world && attacker !=
self) {
448 VectorSubtract(attacker->s.origin, self->s.origin, dir);
449 }
else if (inflictor && inflictor !=
world && inflictor !=
self) {
450 VectorSubtract(inflictor->s.origin, self->s.origin, dir);
452 self->client->killer_yaw =
self->s.angles[YAW];
457 self->client->killer_yaw = 180 / M_PI * atan2(dir[1], dir[0]);
459 self->client->killer_yaw = 0;
461 self->client->killer_yaw = 90;
463 self->client->killer_yaw = -90;
465 if (self->client->killer_yaw < 0)
466 self->client->killer_yaw += 360;
476 void player_die(edict_t *
self, edict_t *inflictor, edict_t *attacker,
int damage, vec3_t point)
480 VectorClear(self->avelocity);
485 self->s.modelindex2 = 0;
487 self->s.angles[0] = 0;
488 self->s.angles[2] = 0;
491 self->client->weapon_sound = 0;
496 self->svflags |= SVF_DEADMONSTER;
498 if (!self->deadflag) {
499 self->client->respawn_time =
level.
time + 1.0;
501 self->client->ps.pmove.pm_type = PM_DEAD;
511 self->client->resp.coop_respawn.inventory[n] =
self->client->pers.inventory[n];
512 self->client->pers.inventory[n] = 0;
517 self->client->quad_framenum = 0;
518 self->client->invincible_framenum = 0;
519 self->client->breather_framenum = 0;
520 self->client->enviro_framenum = 0;
523 if (self->health < -40) {
525 gi.sound(
self, CHAN_BODY,
gi.soundindex(
"misc/udeath.wav"), 1, ATTN_NORM, 0);
526 for (n = 0; n < 4; n++)
533 if (!self->deadflag) {
539 if (self->client->ps.pmove.pm_flags & PMF_DUCKED) {
556 gi.sound(
self, CHAN_VOICE,
gi.soundindex(
va(
"*death%i.wav", (rand() % 4) + 1)), 1, ATTN_NORM, 0);
579 memset(&client->pers, 0,
sizeof(client->pers));
582 client->pers.selected_item =
ITEM_INDEX(item);
583 client->pers.inventory[client->pers.selected_item] = 1;
585 client->pers.weapon = item;
594 client->pers.inventory[
ITEM_INDEX(item_flareg)] = 1;
599 client->pers.inventory[
ITEM_INDEX(item_grenades)] = 5;
604 client->pers.health = 100;
605 client->pers.max_health = 100;
607 client->pers.max_bullets = 200;
608 client->pers.max_shells = 100;
609 client->pers.max_rockets = 50;
610 client->pers.max_grenades = 50;
611 client->pers.max_cells = 200;
612 client->pers.max_slugs = 50;
614 client->pers.connected = qtrue;
620 memset(&client->resp, 0,
sizeof(client->resp));
622 client->resp.coop_respawn = client->pers;
648 game.
clients[i].pers.score = ent->client->resp.score;
654 ent->health = ent->client->pers.health;
655 ent->max_health = ent->client->pers.max_health;
656 ent->flags |= ent->client->pers.savedFlags;
658 ent->client->resp.score = ent->client->pers.score;
681 float bestplayerdistance;
684 float playerdistance;
687 bestplayerdistance = 9999999;
695 if (player->health <= 0)
698 VectorSubtract(spot->s.origin, player->s.origin, v);
699 playerdistance = VectorLength(v);
701 if (playerdistance < bestplayerdistance)
702 bestplayerdistance = playerdistance;
705 return bestplayerdistance;
718 edict_t *spot, *spot1, *spot2;
721 float range, range1, range2;
724 range1 = range2 = 99999;
725 spot1 = spot2 = NULL;
727 while ((spot =
G_Find(spot,
FOFS(classname),
"info_player_deathmatch")) != NULL) {
730 if (
range < range1) {
733 }
else if (
range < range2) {
743 spot1 = spot2 = NULL;
747 selection = rand() % count;
751 spot =
G_Find(spot,
FOFS(classname),
"info_player_deathmatch");
752 if (spot == spot1 || spot == spot2)
754 }
while (selection--);
768 float bestdistance, bestplayerdistance;
775 while ((spot =
G_Find(spot,
FOFS(classname),
"info_player_deathmatch")) != NULL) {
778 if (bestplayerdistance > bestdistance) {
780 bestdistance = bestplayerdistance;
790 spot =
G_Find(NULL,
FOFS(classname),
"info_player_deathmatch");
797 if ((
int)(
dmflags->value) & DF_SPAWN_FARTHEST)
807 edict_t *spot = NULL;
820 spot =
G_Find(spot,
FOFS(classname),
"info_player_coop");
824 target = spot->targetname;
849 edict_t *spot = NULL;
853 else if (
coop->value)
858 while ((spot =
G_Find(spot,
FOFS(classname),
"info_player_start")) != NULL) {
872 spot =
G_Find(spot,
FOFS(classname),
"info_player_start");
879 VectorCopy(spot->s.origin,
origin);
881 VectorCopy(spot->s.angles, angles);
895 ent->classname =
"bodyque";
899 void body_die(edict_t *
self, edict_t *inflictor, edict_t *attacker,
int damage, vec3_t point)
903 if (self->health < -40) {
904 gi.sound(
self, CHAN_BODY,
gi.soundindex(
"misc/udeath.wav"), 1, ATTN_NORM, 0);
905 for (n = 0; n < 4; n++)
907 self->s.origin[2] -= 48;
917 gi.unlinkentity(ent);
924 if (body->s.modelindex) {
926 gi.WriteByte(TE_BLOOD);
927 gi.WritePosition(body->s.origin);
929 gi.multicast(body->s.origin, MULTICAST_PVS);
932 gi.unlinkentity(body);
935 body->s.event = EV_OTHER_TELEPORT;
937 body->svflags = ent->svflags;
938 VectorCopy(ent->mins, body->mins);
939 VectorCopy(ent->maxs, body->maxs);
940 VectorCopy(ent->absmin, body->absmin);
941 VectorCopy(ent->absmax, body->absmax);
942 VectorCopy(ent->size, body->size);
943 VectorCopy(ent->velocity, body->velocity);
944 VectorCopy(ent->avelocity, body->avelocity);
945 body->solid = ent->solid;
946 body->clipmask = ent->clipmask;
947 body->owner = ent->owner;
948 body->movetype = ent->movetype;
949 body->groundentity = ent->groundentity;
963 self->svflags &= ~SVF_NOCLIENT;
967 self->s.event = EV_PLAYER_TELEPORT;
970 self->client->ps.pmove.pm_flags = PMF_TIME_TELEPORT;
971 self->client->ps.pmove.pm_time = 14;
979 gi.AddCommandString(
"pushmenu loadgame\n");
993 if (ent->client->pers.spectator) {
998 gi.cprintf(ent, PRINT_HIGH,
"Spectator password incorrect.\n");
999 ent->client->pers.spectator = qfalse;
1001 gi.WriteString(
"spectator 0\n");
1002 gi.unicast(ent, qtrue);
1007 for (i = 1, numspec = 0; i <=
maxclients->value; i++)
1012 gi.cprintf(ent, PRINT_HIGH,
"Server spectator limit is full.");
1013 ent->client->pers.spectator = qfalse;
1016 gi.WriteString(
"spectator 0\n");
1017 gi.unicast(ent, qtrue);
1026 gi.cprintf(ent, PRINT_HIGH,
"Password incorrect.\n");
1027 ent->client->pers.spectator = qtrue;
1029 gi.WriteString(
"spectator 1\n");
1030 gi.unicast(ent, qtrue);
1036 ent->client->resp.score = ent->client->pers.score = 0;
1038 ent->svflags &= ~SVF_NOCLIENT;
1042 if (!ent->client->pers.spectator) {
1046 gi.WriteByte(MZ_LOGIN);
1047 gi.multicast(ent->s.origin, MULTICAST_PVS);
1050 ent->client->ps.pmove.pm_flags = PMF_TIME_TELEPORT;
1051 ent->client->ps.pmove.pm_time = 14;
1056 if (ent->client->pers.spectator)
1057 gi.bprintf(PRINT_HIGH,
"%s has moved to the sidelines\n", ent->client->pers.netname);
1059 gi.bprintf(PRINT_HIGH,
"%s joined the game\n", ent->client->pers.netname);
1075 vec3_t mins = { -16, -16, -24};
1076 vec3_t maxs = {16, 16, 32};
1078 vec3_t spawn_origin, spawn_angles;
1090 client = ent->client;
1094 char userinfo[MAX_INFO_STRING];
1096 resp = client->resp;
1097 memcpy(userinfo, client->pers.userinfo,
sizeof(userinfo));
1102 char userinfo[MAX_INFO_STRING];
1104 resp = client->resp;
1105 memcpy(userinfo, client->pers.userinfo,
sizeof(userinfo));
1116 if (resp.
score > client->pers.score)
1117 client->pers.score = resp.
score;
1121 saved = client->pers;
1122 memset(client, 0,
sizeof(*client));
1123 client->pers =
saved;
1124 if (client->pers.health <= 0)
1126 client->resp = resp;
1132 ent->groundentity = NULL;
1136 ent->viewheight = 22;
1138 ent->classname =
"player";
1140 ent->solid = SOLID_BBOX;
1143 ent->clipmask = MASK_PLAYERSOLID;
1144 ent->model =
"players/male/tris.md2";
1147 ent->waterlevel = 0;
1150 ent->svflags &= ~SVF_DEADMONSTER;
1152 VectorCopy(mins, ent->mins);
1153 VectorCopy(maxs, ent->maxs);
1154 VectorClear(ent->velocity);
1157 memset(&ent->client->ps, 0,
sizeof(client->ps));
1159 client->ps.pmove.origin[0] = spawn_origin[0] * 8;
1160 client->ps.pmove.origin[1] = spawn_origin[1] * 8;
1161 client->ps.pmove.origin[2] = spawn_origin[2] * 8;
1164 client->ps.fov = 90;
1167 if (client->ps.fov < 1)
1168 client->ps.fov = 90;
1169 else if (client->ps.fov > 160)
1170 client->ps.fov = 160;
1173 client->ps.gunindex =
gi.modelindex(client->pers.weapon->view_model);
1177 ent->s.modelindex = 255;
1178 ent->s.modelindex2 = 255;
1181 ent->s.skinnum = ent -
g_edicts - 1;
1184 VectorCopy(spawn_origin, ent->s.origin);
1185 ent->s.origin[2] += 1;
1186 VectorCopy(ent->s.origin, ent->s.old_origin);
1189 for (i = 0 ; i < 3 ; i++) {
1190 client->ps.pmove.delta_angles[i] = ANGLE2SHORT(spawn_angles[i] - client->resp.cmd_angles[i]);
1193 ent->s.angles[PITCH] = 0;
1194 ent->s.angles[YAW] = spawn_angles[YAW];
1195 ent->s.angles[ROLL] = 0;
1196 VectorCopy(ent->s.angles, client->ps.viewangles);
1197 VectorCopy(ent->s.angles, client->v_angle);
1200 if (client->pers.spectator) {
1201 client->chase_target = NULL;
1203 client->resp.spectator = qtrue;
1206 ent->solid = SOLID_NOT;
1207 ent->svflags |= SVF_NOCLIENT;
1208 ent->client->ps.gunindex = 0;
1212 client->resp.spectator = qfalse;
1221 client->newweapon = client->pers.weapon;
1248 gi.WriteByte(MZ_LOGIN);
1249 gi.multicast(ent->s.origin, MULTICAST_PVS);
1252 gi.bprintf(PRINT_HIGH,
"%s entered the game\n", ent->client->pers.netname);
1280 if (ent->inuse == qtrue) {
1285 for (i = 0 ; i < 3 ; i++)
1286 ent->client->ps.pmove.delta_angles[i] = ANGLE2SHORT(ent->client->ps.viewangles[i]);
1292 ent->classname =
"player";
1304 gi.WriteByte(MZ_LOGIN);
1305 gi.multicast(ent->s.origin, MULTICAST_PVS);
1307 gi.bprintf(PRINT_HIGH,
"%s entered the game\n", ent->client->pers.netname);
1332 strcpy(userinfo,
"\\name\\badinfo\\skin\\male/grunt");
1337 strncpy(ent->client->pers.netname, s,
sizeof(ent->client->pers.netname) - 1);
1342 if (
deathmatch->value && *s && strcmp(s,
"0"))
1343 ent->client->pers.spectator = qtrue;
1345 ent->client->pers.spectator = qfalse;
1353 gi.configstring(CS_PLAYERSKINS + playernum,
va(
"%s\\%s", ent->client->pers.netname, s));
1357 ent->client->ps.fov = 90;
1360 if (ent->client->ps.fov < 1)
1361 ent->client->ps.fov = 90;
1362 else if (ent->client->ps.fov > 160)
1363 ent->client->ps.fov = 160;
1369 ent->client->pers.hand = atoi(s);
1373 strncpy(ent->client->pers.userinfo, userinfo,
sizeof(ent->client->pers.userinfo) - 1);
1402 if (
deathmatch->value && *value && strcmp(value,
"0")) {
1413 for (i = numspec = 0; i <
maxclients->value; i++)
1437 if (ent->inuse == qfalse) {
1447 gi.dprintf(
"%s connected\n", ent->client->pers.netname);
1450 ent->client->pers.connected = qtrue;
1469 gi.bprintf(PRINT_HIGH,
"%s disconnected\n", ent->client->pers.netname);
1475 gi.WriteByte(MZ_LOGOUT);
1476 gi.multicast(ent->s.origin, MULTICAST_PVS);
1479 gi.unlinkentity(ent);
1480 ent->s.modelindex = 0;
1484 ent->solid = SOLID_NOT;
1485 ent->inuse = qfalse;
1486 ent->classname =
"disconnected";
1487 ent->client->pers.connected = qfalse;
1501 trace_t q_gameabi
PM_trace(vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end)
1504 return gi.trace(start, mins, maxs, end,
pm_passent, MASK_PLAYERSOLID);
1506 return gi.trace(start, mins, maxs, end,
pm_passent, MASK_DEADSOLID);
1513 for (i = 0 ; i <
c ; i++)
1514 v += ((
byte *)b)[i];
1523 Com_Printf(
"sv %3i:%i %i\n",
pm->cmd.impulse, c1, c2);
1542 client = ent->client;
1545 client->ps.pmove.pm_type = PM_FREEZE;
1548 && (ucmd->buttons & BUTTON_ANY))
1555 if (ent->client->chase_target) {
1557 client->resp.cmd_angles[0] = SHORT2ANGLE(ucmd->angles[0]);
1558 client->resp.cmd_angles[1] = SHORT2ANGLE(ucmd->angles[1]);
1559 client->resp.cmd_angles[2] = SHORT2ANGLE(ucmd->angles[2]);
1564 memset(&
pm, 0,
sizeof(
pm));
1567 client->ps.pmove.pm_type = PM_SPECTATOR;
1568 else if (ent->s.modelindex != 255)
1569 client->ps.pmove.pm_type = PM_GIB;
1570 else if (ent->deadflag)
1571 client->ps.pmove.pm_type = PM_DEAD;
1573 client->ps.pmove.pm_type = PM_NORMAL;
1575 client->ps.pmove.gravity =
sv_gravity->value;
1576 pm.s = client->ps.pmove;
1578 for (i = 0 ; i < 3 ; i++) {
1579 pm.s.origin[i] = ent->s.origin[i] * 8;
1580 pm.s.velocity[i] = ent->velocity[i] * 8;
1583 if (memcmp(&client->old_pmove, &
pm.s,
sizeof(
pm.s))) {
1584 pm.snapinitial = qtrue;
1591 pm.pointcontents =
gi.pointcontents;
1597 client->ps.pmove =
pm.s;
1598 client->old_pmove =
pm.s;
1600 for (i = 0 ; i < 3 ; i++) {
1601 ent->s.origin[i] =
pm.s.origin[i] * 0.125;
1602 ent->velocity[i] =
pm.s.velocity[i] * 0.125;
1605 VectorCopy(
pm.mins, ent->mins);
1606 VectorCopy(
pm.maxs, ent->maxs);
1608 client->resp.cmd_angles[0] = SHORT2ANGLE(ucmd->angles[0]);
1609 client->resp.cmd_angles[1] = SHORT2ANGLE(ucmd->angles[1]);
1610 client->resp.cmd_angles[2] = SHORT2ANGLE(ucmd->angles[2]);
1612 if (ent->groundentity && !
pm.groundentity && (
pm.cmd.upmove >= 10) && (
pm.waterlevel == 0)) {
1613 gi.sound(ent, CHAN_VOICE,
gi.soundindex(
"*jump1.wav"), 1, ATTN_NORM, 0);
1617 ent->viewheight =
pm.viewheight;
1618 ent->waterlevel =
pm.waterlevel;
1619 ent->watertype =
pm.watertype;
1620 ent->groundentity =
pm.groundentity;
1621 if (
pm.groundentity)
1622 ent->groundentity_linkcount =
pm.groundentity->linkcount;
1624 if (ent->deadflag) {
1625 client->ps.viewangles[ROLL] = 40;
1626 client->ps.viewangles[PITCH] = -15;
1627 client->ps.viewangles[YAW] = client->killer_yaw;
1629 VectorCopy(
pm.viewangles, client->v_angle);
1630 VectorCopy(
pm.viewangles, client->ps.viewangles);
1639 for (i = 0 ; i <
pm.numtouch ; i++) {
1641 for (j = 0 ; j < i ; j++)
1653 client->oldbuttons = client->buttons;
1654 client->buttons = ucmd->buttons;
1655 client->latched_buttons |= client->buttons & ~client->oldbuttons;
1659 ent->light_level = ucmd->lightlevel;
1662 if (client->latched_buttons & BUTTON_ATTACK) {
1663 if (client->resp.spectator) {
1665 client->latched_buttons = 0;
1667 if (client->chase_target) {
1668 client->chase_target = NULL;
1669 client->ps.pmove.pm_flags &= ~PMF_NO_PREDICTION;
1673 }
else if (!client->weapon_thunk) {
1674 client->weapon_thunk = qtrue;
1679 if (client->resp.spectator) {
1680 if (ucmd->upmove >= 10) {
1681 if (!(client->ps.pmove.pm_flags & PMF_JUMP_HELD)) {
1682 client->ps.pmove.pm_flags |= PMF_JUMP_HELD;
1683 if (client->chase_target)
1689 client->ps.pmove.pm_flags &= ~PMF_JUMP_HELD;
1695 if (
other->inuse &&
other->client->chase_target == ent)
1717 client = ent->client;
1720 client->pers.spectator != client->resp.spectator &&
1721 (
level.
time - client->respawn_time) >= 5) {
1727 if (!client->weapon_thunk && !client->resp.spectator)
1730 client->weapon_thunk = qfalse;
1732 if (ent->deadflag) {
1734 if (
level.
time > client->respawn_time) {
1737 buttonMask = BUTTON_ATTACK;
1741 if ((client->latched_buttons & buttonMask) ||
1744 client->latched_buttons = 0;
1755 client->latched_buttons = 0;