mirror of
https://github.com/blendogames/thirtyflightsofloving.git
synced 2024-11-15 00:41:21 +00:00
eb97af1598
Added GetFileList() to game function imports in misison pack DLL game.h.
3229 lines
No EOL
79 KiB
C
3229 lines
No EOL
79 KiB
C
#include "g_local.h"
|
||
#include "bot.h"
|
||
|
||
typedef struct ctfgame_s
|
||
{
|
||
int team1, team2;
|
||
int total1, total2; // these are only set when going into intermission!
|
||
float last_flag_capture;
|
||
int last_capture_team;
|
||
} ctfgame_t;
|
||
//PON
|
||
qboolean bots_moveok ( edict_t *ent,float ryaw,vec3_t pos,float dist,float *bottom);
|
||
//PON
|
||
ctfgame_t ctfgame;
|
||
qboolean techspawn = false;
|
||
|
||
cvar_t *ctf;
|
||
cvar_t *ctf_forcejoin;
|
||
|
||
char *ctf_statusbar =
|
||
"yb -24 "
|
||
|
||
// health
|
||
"xv 0 "
|
||
"hnum "
|
||
"xv 50 "
|
||
"pic 0 "
|
||
|
||
// ammo
|
||
"if 2 "
|
||
" xv 100 "
|
||
" anum "
|
||
" xv 150 "
|
||
" pic 2 "
|
||
"endif "
|
||
|
||
// armor
|
||
"if 4 "
|
||
" xv 200 "
|
||
" rnum "
|
||
" xv 250 "
|
||
" pic 4 "
|
||
"endif "
|
||
|
||
// selected item
|
||
"if 6 "
|
||
" xv 296 "
|
||
" pic 6 "
|
||
"endif "
|
||
|
||
"yb -50 "
|
||
|
||
// picked up item
|
||
"if 7 "
|
||
" xv 0 "
|
||
" pic 7 "
|
||
" xv 26 "
|
||
" yb -42 "
|
||
" stat_string 8 "
|
||
" yb -50 "
|
||
"endif "
|
||
|
||
// timer
|
||
"if 9 "
|
||
"xv 246 "
|
||
"num 2 10 "
|
||
"xv 296 "
|
||
"pic 9 "
|
||
"endif "
|
||
|
||
// help / weapon icon
|
||
"if 11 "
|
||
"xv 148 "
|
||
"pic 11 "
|
||
"endif "
|
||
|
||
// frags
|
||
"xr -50 "
|
||
"yt 2 "
|
||
"num 3 14 "
|
||
|
||
//tech
|
||
"yb -129 "
|
||
"if 26 "
|
||
"xr -26 "
|
||
"pic 26 "
|
||
"endif "
|
||
|
||
// red team
|
||
"yb -102 "
|
||
"if 17 "
|
||
"xr -26 "
|
||
"pic 17 "
|
||
"endif "
|
||
"xr -62 "
|
||
"num 2 18 "
|
||
// joined overlay
|
||
"if 22 "
|
||
"yb -104 "
|
||
"xr -28 "
|
||
"pic 22 "
|
||
"endif "
|
||
|
||
// blue team
|
||
"yb -75 "
|
||
"if 19 "
|
||
"xr -26 "
|
||
"pic 19 "
|
||
"endif "
|
||
"xr -62 "
|
||
"num 2 20 "
|
||
// joined overlay
|
||
"if 23 "
|
||
"yb -77 "
|
||
"xr -28 "
|
||
"pic 23 "
|
||
"endif "
|
||
|
||
// have flag graph
|
||
"if 21 "
|
||
"yt 26 "
|
||
"xr -24 "
|
||
"pic 21 "
|
||
"endif "
|
||
|
||
// id view state
|
||
"if 27 "
|
||
"xv 0 "
|
||
"yb -58 "
|
||
"string \"Viewing\" "
|
||
"xv 64 "
|
||
"stat_string 27 "
|
||
"endif "
|
||
|
||
//sight
|
||
"if 31 "
|
||
" xv 96 "
|
||
" yv 56 "
|
||
" pic 31 "
|
||
"endif"
|
||
;
|
||
|
||
static char *tnames[] = {
|
||
"item_tech1", "item_tech2", "item_tech3", "item_tech4",
|
||
NULL
|
||
};
|
||
|
||
void stuffcmd(edict_t *ent, char *s)
|
||
{
|
||
if(ent->svflags & SVF_MONSTER) return;
|
||
|
||
gi.WriteByte (11);
|
||
gi.WriteString (s);
|
||
gi.unicast (ent, true);
|
||
}
|
||
|
||
/*--------------------------------------------------------------------------*/
|
||
|
||
/*
|
||
=================
|
||
findradius
|
||
|
||
Returns entities that have origins within a spherical area
|
||
|
||
findradius (origin, radius)
|
||
=================
|
||
*/
|
||
static edict_t *loc_findradius (edict_t *from, vec3_t org, float rad)
|
||
{
|
||
vec3_t eorg;
|
||
int j;
|
||
|
||
if (!from)
|
||
from = g_edicts;
|
||
else
|
||
from++;
|
||
for ( ; from < &g_edicts[globals.num_edicts]; from++)
|
||
{
|
||
if (!from->inuse)
|
||
continue;
|
||
#if 0
|
||
if (from->solid == SOLID_NOT)
|
||
continue;
|
||
#endif
|
||
for (j=0 ; j<3 ; j++)
|
||
eorg[j] = org[j] - (from->s.origin[j] + (from->mins[j] + from->maxs[j])*0.5);
|
||
if (VectorLength(eorg) > rad)
|
||
continue;
|
||
return from;
|
||
}
|
||
|
||
return NULL;
|
||
}
|
||
|
||
static void loc_buildboxpoints(vec3_t p[8], vec3_t org, vec3_t mins, vec3_t maxs)
|
||
{
|
||
VectorAdd(org, mins, p[0]);
|
||
VectorCopy(p[0], p[1]);
|
||
p[1][0] -= mins[0];
|
||
VectorCopy(p[0], p[2]);
|
||
p[2][1] -= mins[1];
|
||
VectorCopy(p[0], p[3]);
|
||
p[3][0] -= mins[0];
|
||
p[3][1] -= mins[1];
|
||
VectorAdd(org, maxs, p[4]);
|
||
VectorCopy(p[4], p[5]);
|
||
p[5][0] -= maxs[0];
|
||
VectorCopy(p[0], p[6]);
|
||
p[6][1] -= maxs[1];
|
||
VectorCopy(p[0], p[7]);
|
||
p[7][0] -= maxs[0];
|
||
p[7][1] -= maxs[1];
|
||
}
|
||
|
||
static qboolean loc_CanSee (edict_t *targ, edict_t *inflictor)
|
||
{
|
||
trace_t trace;
|
||
vec3_t targpoints[8];
|
||
int i;
|
||
vec3_t viewpoint;
|
||
|
||
// bmodels need special checking because their origin is 0,0,0
|
||
if (targ->movetype == MOVETYPE_PUSH)
|
||
return false; // bmodels not supported
|
||
|
||
loc_buildboxpoints(targpoints, targ->s.origin, targ->mins, targ->maxs);
|
||
|
||
VectorCopy(inflictor->s.origin, viewpoint);
|
||
viewpoint[2] += inflictor->viewheight;
|
||
|
||
for (i = 0; i < 8; i++) {
|
||
trace = gi.trace (viewpoint, vec3_origin, vec3_origin, targpoints[i], inflictor, MASK_SOLID);
|
||
if (trace.fraction == 1.0)
|
||
return true;
|
||
}
|
||
|
||
return false;
|
||
}
|
||
|
||
/*--------------------------------------------------------------------------*/
|
||
|
||
static gitem_t *flag1_item;
|
||
static gitem_t *flag2_item;
|
||
|
||
void CTFInit(void)
|
||
{
|
||
ctf = gi.cvar("ctf", "0", CVAR_SERVERINFO);
|
||
ctf_forcejoin = gi.cvar("ctf_forcejoin", "", 0);
|
||
|
||
if (!flag1_item)
|
||
flag1_item = FindItemByClassname("item_flag_team1");
|
||
if (!flag2_item)
|
||
flag2_item = FindItemByClassname("item_flag_team2");
|
||
memset(&ctfgame, 0, sizeof(ctfgame));
|
||
techspawn = false;
|
||
}
|
||
|
||
/*--------------------------------------------------------------------------*/
|
||
|
||
char *CTFTeamName(int team)
|
||
{
|
||
switch (team) {
|
||
case CTF_TEAM1:
|
||
return "RED";
|
||
case CTF_TEAM2:
|
||
return "BLUE";
|
||
}
|
||
return "UKNOWN";
|
||
}
|
||
|
||
char *CTFOtherTeamName(int team)
|
||
{
|
||
switch (team) {
|
||
case CTF_TEAM1:
|
||
return "BLUE";
|
||
case CTF_TEAM2:
|
||
return "RED";
|
||
}
|
||
return "UKNOWN";
|
||
}
|
||
|
||
int CTFOtherTeam(int team)
|
||
{
|
||
switch (team) {
|
||
case CTF_TEAM1:
|
||
return CTF_TEAM2;
|
||
case CTF_TEAM2:
|
||
return CTF_TEAM1;
|
||
}
|
||
return -1; // invalid value
|
||
}
|
||
|
||
/*--------------------------------------------------------------------------*/
|
||
|
||
edict_t *SelectRandomDeathmatchSpawnPoint (void);
|
||
edict_t *SelectFarthestDeathmatchSpawnPoint (void);
|
||
float PlayersRangeFromSpot (edict_t *spot);
|
||
|
||
void CTFAssignSkin(edict_t *ent, char *s)
|
||
{
|
||
int playernum = ent-g_edicts-1;
|
||
char *p;
|
||
char t[64];
|
||
|
||
Com_sprintf(t, sizeof(t), "%s", s);
|
||
|
||
if ((p = strrchr(t, '/')) != NULL)
|
||
p[1] = 0;
|
||
else
|
||
strcpy(t, "male/");
|
||
|
||
switch (ent->client->resp.ctf_team) {
|
||
case CTF_TEAM1:
|
||
gi.configstring (CS_PLAYERSKINS+playernum, va("%s\\%s%s",
|
||
ent->client->pers.netname, t, CTF_TEAM1_SKIN) );
|
||
break;
|
||
case CTF_TEAM2:
|
||
gi.configstring (CS_PLAYERSKINS+playernum,
|
||
va("%s\\%s%s", ent->client->pers.netname, t, CTF_TEAM2_SKIN) );
|
||
break;
|
||
default:
|
||
gi.configstring (CS_PLAYERSKINS+playernum,
|
||
va("%s\\%s", ent->client->pers.netname, s) );
|
||
break;
|
||
}
|
||
// gi.cprintf(ent, PRINT_HIGH, "You have been assigned to %s team.\n", ent->client->pers.netname);
|
||
}
|
||
|
||
void CTFAssignTeam(gclient_t *who)
|
||
{
|
||
edict_t *player;
|
||
int i;
|
||
int team1count = 0, team2count = 0;
|
||
|
||
who->resp.ctf_state = CTF_STATE_START;
|
||
|
||
if (!((int)dmflags->value & DF_CTF_FORCEJOIN)) {
|
||
who->resp.ctf_team = CTF_NOTEAM;
|
||
return;
|
||
}
|
||
|
||
for (i = 1; i <= maxclients->value; i++) {
|
||
player = &g_edicts[i];
|
||
|
||
if (!player->inuse || player->client == who)
|
||
continue;
|
||
|
||
switch (player->client->resp.ctf_team) {
|
||
case CTF_TEAM1:
|
||
team1count++;
|
||
break;
|
||
case CTF_TEAM2:
|
||
team2count++;
|
||
}
|
||
}
|
||
if (team1count < team1count)
|
||
who->resp.ctf_team = CTF_TEAM1;
|
||
else if (team2count < team1count)
|
||
who->resp.ctf_team = CTF_TEAM2;
|
||
else if (rand() & 1)
|
||
who->resp.ctf_team = CTF_TEAM1;
|
||
else
|
||
who->resp.ctf_team = CTF_TEAM2;
|
||
}
|
||
|
||
/*
|
||
================
|
||
SelectCTFSpawnPoint
|
||
|
||
go to a ctf point, but NOT the two points closest
|
||
to other players
|
||
================
|
||
*/
|
||
edict_t *SelectCTFSpawnPoint (edict_t *ent)
|
||
{
|
||
edict_t *spot, *spot1, *spot2;
|
||
int count = 0;
|
||
int selection;
|
||
float range, range1, range2;
|
||
char *cname;
|
||
|
||
if (ent->client->resp.ctf_state != CTF_STATE_START)
|
||
if ( (int)(dmflags->value) & DF_SPAWN_FARTHEST)
|
||
return SelectFarthestDeathmatchSpawnPoint ();
|
||
else
|
||
return SelectRandomDeathmatchSpawnPoint ();
|
||
|
||
ent->client->resp.ctf_state = CTF_STATE_PLAYING;
|
||
|
||
switch (ent->client->resp.ctf_team) {
|
||
case CTF_TEAM1:
|
||
cname = "info_player_team1";
|
||
break;
|
||
case CTF_TEAM2:
|
||
cname = "info_player_team2";
|
||
break;
|
||
default:
|
||
return SelectRandomDeathmatchSpawnPoint();
|
||
}
|
||
|
||
spot = NULL;
|
||
range1 = range2 = 99999;
|
||
spot1 = spot2 = NULL;
|
||
|
||
while ((spot = G_Find (spot, FOFS(classname), cname)) != NULL)
|
||
{
|
||
count++;
|
||
range = PlayersRangeFromSpot(spot);
|
||
if (range < range1)
|
||
{
|
||
range1 = range;
|
||
spot1 = spot;
|
||
}
|
||
else if (range < range2)
|
||
{
|
||
range2 = range;
|
||
spot2 = spot;
|
||
}
|
||
}
|
||
|
||
if (!count)
|
||
return SelectRandomDeathmatchSpawnPoint();
|
||
|
||
if (count <= 2)
|
||
{
|
||
spot1 = spot2 = NULL;
|
||
}
|
||
else
|
||
count -= 2;
|
||
|
||
selection = rand() % count;
|
||
|
||
spot = NULL;
|
||
do
|
||
{
|
||
spot = G_Find (spot, FOFS(classname), cname);
|
||
if (spot == spot1 || spot == spot2)
|
||
selection++;
|
||
} while(selection--);
|
||
|
||
return spot;
|
||
}
|
||
|
||
/*------------------------------------------------------------------------*/
|
||
/*
|
||
CTFFragBonuses
|
||
|
||
Calculate the bonuses for flag defense, flag carrier defense, etc.
|
||
Note that bonuses are not cumaltive. You get one, they are in importance
|
||
order.
|
||
*/
|
||
void CTFFragBonuses(edict_t *targ, edict_t *inflictor, edict_t *attacker)
|
||
{
|
||
int i;
|
||
edict_t *ent;
|
||
gitem_t *flag_item, *enemy_flag_item;
|
||
int otherteam;
|
||
edict_t *flag, *carrier;
|
||
char *c;
|
||
vec3_t v1, v2;
|
||
|
||
// no bonus for fragging yourself
|
||
if (!targ->client || !attacker->client || targ == attacker)
|
||
return;
|
||
|
||
otherteam = CTFOtherTeam(targ->client->resp.ctf_team);
|
||
if (otherteam < 0)
|
||
return; // whoever died isn't on a team
|
||
|
||
// same team, if the flag at base, check to he has the enemy flag
|
||
if (targ->client->resp.ctf_team == CTF_TEAM1) {
|
||
flag_item = flag1_item;
|
||
enemy_flag_item = flag2_item;
|
||
} else {
|
||
flag_item = flag2_item;
|
||
enemy_flag_item = flag1_item;
|
||
}
|
||
|
||
// did the attacker frag the flag carrier?
|
||
if (targ->client->pers.inventory[ITEM_INDEX(enemy_flag_item)]) {
|
||
attacker->client->resp.ctf_lastfraggedcarrier = level.time;
|
||
attacker->client->resp.score += CTF_FRAG_CARRIER_BONUS;
|
||
if(!(attacker->svflags & SVF_MONSTER))
|
||
gi.cprintf(attacker, PRINT_MEDIUM, "BONUS: %d points for fragging enemy flag carrier.\n",
|
||
CTF_FRAG_CARRIER_BONUS);
|
||
|
||
// the the target had the flag, clear the hurt carrier
|
||
// field on the other team
|
||
for (i = 1; i <= maxclients->value; i++) {
|
||
ent = g_edicts + i;
|
||
if (ent->inuse && ent->client->resp.ctf_team == otherteam)
|
||
ent->client->resp.ctf_lasthurtcarrier = 0;
|
||
}
|
||
return;
|
||
}
|
||
|
||
if (targ->client->resp.ctf_lasthurtcarrier &&
|
||
level.time - targ->client->resp.ctf_lasthurtcarrier < CTF_CARRIER_DANGER_PROTECT_TIMEOUT &&
|
||
!attacker->client->pers.inventory[ITEM_INDEX(flag_item)]) {
|
||
// attacker is on the same team as the flag carrier and
|
||
// fragged a guy who hurt our flag carrier
|
||
attacker->client->resp.score += CTF_CARRIER_DANGER_PROTECT_BONUS;
|
||
gi.bprintf(PRINT_MEDIUM, "%s defends %s's flag carrier against an agressive enemy\n",
|
||
attacker->client->pers.netname,
|
||
CTFTeamName(attacker->client->resp.ctf_team));
|
||
return;
|
||
}
|
||
|
||
// flag and flag carrier area defense bonuses
|
||
|
||
// we have to find the flag and carrier entities
|
||
|
||
// find the flag
|
||
switch (attacker->client->resp.ctf_team) {
|
||
case CTF_TEAM1:
|
||
c = "item_flag_team1";
|
||
break;
|
||
case CTF_TEAM2:
|
||
c = "item_flag_team2";
|
||
break;
|
||
default:
|
||
return;
|
||
}
|
||
|
||
flag = NULL;
|
||
while ((flag = G_Find (flag, FOFS(classname), c)) != NULL) {
|
||
if (!(flag->spawnflags & DROPPED_ITEM))
|
||
break;
|
||
}
|
||
|
||
if (!flag)
|
||
return; // can't find attacker's flag
|
||
|
||
//PONKO
|
||
if(attacker)
|
||
{
|
||
VectorSubtract(targ->s.origin,attacker->s.origin,v1);
|
||
if(VectorLength(v1) < 300
|
||
&& attacker->client && !(attacker->deadflag) && (attacker->svflags & SVF_MONSTER))
|
||
{
|
||
attacker->client->zc.second_target = flag;
|
||
}
|
||
}
|
||
//PONKO
|
||
// find attacker's team's flag carrier
|
||
for (i = 1; i <= maxclients->value; i++) {
|
||
carrier = g_edicts + i;
|
||
if (carrier->inuse &&
|
||
carrier->client->pers.inventory[ITEM_INDEX(flag_item)])
|
||
break;
|
||
carrier = NULL;
|
||
}
|
||
|
||
// ok we have the attackers flag and a pointer to the carrier
|
||
|
||
// check to see if we are defending the base's flag
|
||
VectorSubtract(targ->s.origin, flag->s.origin, v1);
|
||
VectorSubtract(attacker->s.origin, flag->s.origin, v2);
|
||
|
||
if (VectorLength(v1) < CTF_TARGET_PROTECT_RADIUS ||
|
||
VectorLength(v2) < CTF_TARGET_PROTECT_RADIUS ||
|
||
loc_CanSee(flag, targ) || loc_CanSee(flag, attacker)) {
|
||
// we defended the base flag
|
||
attacker->client->resp.score += CTF_FLAG_DEFENSE_BONUS;
|
||
if (flag->solid == SOLID_NOT)
|
||
gi.bprintf(PRINT_MEDIUM, "%s defends the %s base.\n",
|
||
attacker->client->pers.netname,
|
||
CTFTeamName(attacker->client->resp.ctf_team));
|
||
else
|
||
gi.bprintf(PRINT_MEDIUM, "%s defends the %s flag.\n",
|
||
attacker->client->pers.netname,
|
||
CTFTeamName(attacker->client->resp.ctf_team));
|
||
return;
|
||
}
|
||
|
||
if (carrier && carrier != attacker) {
|
||
VectorSubtract(targ->s.origin, carrier->s.origin, v1);
|
||
VectorSubtract(attacker->s.origin, carrier->s.origin, v1);
|
||
|
||
if (VectorLength(v1) < CTF_ATTACKER_PROTECT_RADIUS ||
|
||
VectorLength(v2) < CTF_ATTACKER_PROTECT_RADIUS ||
|
||
loc_CanSee(carrier, targ) || loc_CanSee(carrier, attacker)) {
|
||
attacker->client->resp.score += CTF_CARRIER_PROTECT_BONUS;
|
||
gi.bprintf(PRINT_MEDIUM, "%s defends the %s's flag carrier.\n",
|
||
attacker->client->pers.netname,
|
||
CTFTeamName(attacker->client->resp.ctf_team));
|
||
return;
|
||
}
|
||
}
|
||
}
|
||
|
||
void CTFCheckHurtCarrier(edict_t *targ, edict_t *attacker)
|
||
{
|
||
gitem_t *flag_item;
|
||
|
||
if (!targ->client || !attacker->client)
|
||
return;
|
||
|
||
if (targ->client->resp.ctf_team == CTF_TEAM1)
|
||
flag_item = flag2_item;
|
||
else
|
||
flag_item = flag1_item;
|
||
|
||
if (targ->client->pers.inventory[ITEM_INDEX(flag_item)] &&
|
||
targ->client->resp.ctf_team != attacker->client->resp.ctf_team)
|
||
attacker->client->resp.ctf_lasthurtcarrier = level.time;
|
||
}
|
||
|
||
|
||
/*------------------------------------------------------------------------*/
|
||
|
||
void CTFResetFlag(int ctf_team)
|
||
{
|
||
char *c;
|
||
edict_t *ent;
|
||
|
||
switch (ctf_team) {
|
||
case CTF_TEAM1:
|
||
c = "item_flag_team1";
|
||
break;
|
||
case CTF_TEAM2:
|
||
c = "item_flag_team2";
|
||
break;
|
||
default:
|
||
return;
|
||
}
|
||
|
||
ent = NULL;
|
||
while ((ent = G_Find (ent, FOFS(classname), c)) != NULL) {
|
||
if (ent->spawnflags & DROPPED_ITEM)
|
||
G_FreeEdict(ent);
|
||
else {
|
||
ent->svflags &= ~SVF_NOCLIENT;
|
||
ent->solid = SOLID_TRIGGER;
|
||
gi.linkentity(ent);
|
||
ent->s.event = EV_ITEM_RESPAWN;
|
||
}
|
||
}
|
||
}
|
||
|
||
void CTFResetFlags(void)
|
||
{
|
||
CTFResetFlag(CTF_TEAM1);
|
||
CTFResetFlag(CTF_TEAM2);
|
||
}
|
||
|
||
qboolean CTFPickup_Flag(edict_t *ent, edict_t *other)
|
||
{
|
||
int ctf_team;
|
||
int i;
|
||
edict_t *player;
|
||
gitem_t *flag_item, *enemy_flag_item;
|
||
|
||
|
||
if(chedit->value) {SetRespawn (ent, 30); return true;};
|
||
|
||
|
||
// figure out what team this flag is
|
||
if (strcmp(ent->classname, "item_flag_team1") == 0)
|
||
ctf_team = CTF_TEAM1;
|
||
else if (strcmp(ent->classname, "item_flag_team2") == 0)
|
||
ctf_team = CTF_TEAM2;
|
||
else {
|
||
if(!(ent->svflags & SVF_MONSTER))
|
||
gi.cprintf(ent, PRINT_HIGH, "Don't know what team the flag is on.\n");
|
||
return false;
|
||
}
|
||
|
||
// same team, if the flag at base, check to he has the enemy flag
|
||
if (ctf_team == CTF_TEAM1) {
|
||
flag_item = flag1_item;
|
||
enemy_flag_item = flag2_item;
|
||
} else {
|
||
flag_item = flag2_item;
|
||
enemy_flag_item = flag1_item;
|
||
}
|
||
|
||
if (ctf_team == other->client->resp.ctf_team) {
|
||
|
||
if (!(ent->spawnflags & DROPPED_ITEM)) {
|
||
// the flag is at home base. if the player has the enemy
|
||
// flag, he's just won!
|
||
|
||
if (other->client->pers.inventory[ITEM_INDEX(enemy_flag_item)]) {
|
||
gi.bprintf(PRINT_HIGH, "%s captured the %s flag!\n",
|
||
other->client->pers.netname, CTFOtherTeamName(ctf_team));
|
||
other->client->pers.inventory[ITEM_INDEX(enemy_flag_item)] = 0;
|
||
|
||
ctfgame.last_flag_capture = level.time;
|
||
ctfgame.last_capture_team = ctf_team;
|
||
if (ctf_team == CTF_TEAM1)
|
||
ctfgame.team1++;
|
||
else
|
||
ctfgame.team2++;
|
||
|
||
gi.sound (ent, CHAN_RELIABLE+CHAN_NO_PHS_ADD+CHAN_VOICE, gi.soundindex("ctf/flagcap.wav"), 1, ATTN_NONE, 0);
|
||
|
||
// other gets another 10 frag bonus
|
||
other->client->resp.score += CTF_CAPTURE_BONUS;
|
||
|
||
// Ok, let's do the player loop, hand out the bonuses
|
||
for (i = 1; i <= maxclients->value; i++) {
|
||
player = &g_edicts[i];
|
||
if (!player->inuse)
|
||
continue;
|
||
|
||
if (player->client->resp.ctf_team != other->client->resp.ctf_team)
|
||
player->client->resp.ctf_lasthurtcarrier = -5;
|
||
else if (player->client->resp.ctf_team == other->client->resp.ctf_team) {
|
||
if (player != other)
|
||
player->client->resp.score += CTF_TEAM_BONUS;
|
||
// award extra points for capture assists
|
||
if (player->client->resp.ctf_lastreturnedflag + CTF_RETURN_FLAG_ASSIST_TIMEOUT > level.time) {
|
||
gi.bprintf(PRINT_HIGH, "%s gets an assist for returning the flag!\n", player->client->pers.netname);
|
||
player->client->resp.score += CTF_RETURN_FLAG_ASSIST_BONUS;
|
||
}
|
||
if (player->client->resp.ctf_lastfraggedcarrier + CTF_FRAG_CARRIER_ASSIST_TIMEOUT > level.time) {
|
||
gi.bprintf(PRINT_HIGH, "%s gets an assist for fragging the flag carrier!\n", player->client->pers.netname);
|
||
player->client->resp.score += CTF_FRAG_CARRIER_ASSIST_BONUS;
|
||
}
|
||
}
|
||
}
|
||
|
||
CTFResetFlags();
|
||
return false;
|
||
}
|
||
return false; // its at home base already
|
||
}
|
||
// hey, its not home. return it by teleporting it back
|
||
gi.bprintf(PRINT_HIGH, "%s returned the %s flag!\n",
|
||
other->client->pers.netname, CTFTeamName(ctf_team));
|
||
other->client->resp.score += CTF_RECOVERY_BONUS;
|
||
other->client->resp.ctf_lastreturnedflag = level.time;
|
||
gi.sound (ent, CHAN_RELIABLE+CHAN_NO_PHS_ADD+CHAN_VOICE, gi.soundindex("ctf/flagret.wav"), 1, ATTN_NONE, 0);
|
||
//CTFResetFlag will remove this entity! We must return false
|
||
CTFResetFlag(ctf_team);
|
||
return false;
|
||
}
|
||
|
||
// hey, its not our flag, pick it up
|
||
gi.bprintf(PRINT_HIGH, "%s got the %s flag!\n",
|
||
other->client->pers.netname, CTFTeamName(ctf_team));
|
||
other->client->resp.score += CTF_FLAG_BONUS;
|
||
|
||
other->client->pers.inventory[ITEM_INDEX(flag_item)] = 1;
|
||
other->client->resp.ctf_flagsince = level.time;
|
||
|
||
// pick up the flag
|
||
// if it's not a dropped flag, we just make is disappear
|
||
// if it's dropped, it will be removed by the pickup caller
|
||
if (!(ent->spawnflags & DROPPED_ITEM)) {
|
||
ent->flags |= FL_RESPAWN;
|
||
ent->svflags |= SVF_NOCLIENT;
|
||
ent->solid = SOLID_NOT;
|
||
}
|
||
return true;
|
||
}
|
||
|
||
static void CTFDropFlagTouch(edict_t *ent, edict_t *other, cplane_t *plane, csurface_t *surf)
|
||
{
|
||
//owner (who dropped us) can't touch for two secs
|
||
if (other == ent->owner &&
|
||
ent->nextthink - level.time > CTF_AUTO_FLAG_RETURN_TIMEOUT-2)
|
||
return;
|
||
|
||
Touch_Item (ent, other, plane, surf);
|
||
}
|
||
|
||
static void CTFDropFlagThink(edict_t *ent)
|
||
{
|
||
// auto return the flag
|
||
// reset flag will remove ourselves
|
||
if (strcmp(ent->classname, "item_flag_team1") == 0) {
|
||
CTFResetFlag(CTF_TEAM1);
|
||
gi.bprintf(PRINT_HIGH, "The %s flag has returned!\n",
|
||
CTFTeamName(CTF_TEAM1));
|
||
} else if (strcmp(ent->classname, "item_flag_team2") == 0) {
|
||
CTFResetFlag(CTF_TEAM2);
|
||
gi.bprintf(PRINT_HIGH, "The %s flag has returned!\n",
|
||
CTFTeamName(CTF_TEAM2));
|
||
}
|
||
}
|
||
|
||
// Called from PlayerDie, to drop the flag from a dying player
|
||
void CTFDeadDropFlag(edict_t *self)
|
||
{
|
||
edict_t *dropped = NULL;
|
||
|
||
if (!flag1_item || !flag2_item)
|
||
CTFInit();
|
||
|
||
if (self->client->pers.inventory[ITEM_INDEX(flag1_item)]) {
|
||
dropped = Drop_Item(self, flag1_item);
|
||
self->client->pers.inventory[ITEM_INDEX(flag1_item)] = 0;
|
||
gi.bprintf(PRINT_HIGH, "%s lost the %s flag!\n",
|
||
self->client->pers.netname, CTFTeamName(CTF_TEAM1));
|
||
} else if (self->client->pers.inventory[ITEM_INDEX(flag2_item)]) {
|
||
dropped = Drop_Item(self, flag2_item);
|
||
self->client->pers.inventory[ITEM_INDEX(flag2_item)] = 0;
|
||
gi.bprintf(PRINT_HIGH, "%s lost the %s flag!\n",
|
||
self->client->pers.netname, CTFTeamName(CTF_TEAM2));
|
||
}
|
||
|
||
if (dropped) {
|
||
dropped->think = CTFDropFlagThink;
|
||
dropped->nextthink = level.time + CTF_AUTO_FLAG_RETURN_TIMEOUT;
|
||
dropped->touch = CTFDropFlagTouch;
|
||
}
|
||
}
|
||
|
||
qboolean CTFDrop_Flag(edict_t *ent, gitem_t *item)
|
||
{
|
||
if (rand() & 1)
|
||
{
|
||
if(!(ent->svflags & SVF_MONSTER))
|
||
gi.cprintf(ent, PRINT_HIGH, "Only lusers drop flags.\n");
|
||
}
|
||
else
|
||
{
|
||
if(!(ent->svflags & SVF_MONSTER))
|
||
gi.cprintf(ent, PRINT_HIGH, "Winners don't drop flags.\n");
|
||
}
|
||
return false;
|
||
}
|
||
|
||
static void CTFFlagThink(edict_t *ent)
|
||
{
|
||
if (ent->solid != SOLID_NOT)
|
||
ent->s.frame = 173 + (((ent->s.frame - 173) + 1) % 16);
|
||
ent->nextthink = level.time + FRAMETIME;
|
||
}
|
||
|
||
void droptofloor (edict_t *ent);
|
||
void SpawnItem3 (edict_t *ent, gitem_t *item);
|
||
//edict_t *GetBotFlag1(); //<2F>`<60>[<5B><>1<EFBFBD>̊<EFBFBD>
|
||
//edict_t *GetBotFlag2(); //<2F>`<60>[<5B><>2<EFBFBD>̊<EFBFBD>
|
||
void ChainPodThink (edict_t *ent);
|
||
qboolean ChkTFlg( void );//<2F><><EFBFBD>Z<EFBFBD>b<EFBFBD>g<EFBFBD>A<EFBFBD>b<EFBFBD>v<EFBFBD>ς݁H
|
||
void SetBotFlag1(edict_t *ent); //<2F>`<60>[<5B><>1<EFBFBD>̊<EFBFBD>
|
||
void SetBotFlag2(edict_t *ent); //<2F>`<60>[<5B><>2<EFBFBD>̊<EFBFBD>
|
||
|
||
void CTFFlagSetup (edict_t *ent)
|
||
{
|
||
trace_t tr;
|
||
vec3_t dest;
|
||
float *v;
|
||
|
||
v = tv(-15,-15,-15);
|
||
VectorCopy (v, ent->mins);
|
||
v = tv(15,15,15);
|
||
VectorCopy (v, ent->maxs);
|
||
|
||
if (ent->model)
|
||
gi.setmodel (ent, ent->model);
|
||
else if(ent->item->world_model) //PONKO
|
||
gi.setmodel (ent, ent->item->world_model);
|
||
else ent->s.modelindex = 0; //PONKO
|
||
ent->solid = SOLID_TRIGGER;
|
||
ent->movetype = MOVETYPE_TOSS;
|
||
ent->touch = Touch_Item;
|
||
|
||
v = tv(0,0,-128);
|
||
VectorAdd (ent->s.origin, v, dest);
|
||
|
||
tr = gi.trace (ent->s.origin, ent->mins, ent->maxs, dest, ent, MASK_SOLID);
|
||
if (tr.startsolid)
|
||
{
|
||
gi.dprintf ("CTFFlagSetup: %s startsolid at %s\n", ent->classname, vtos(ent->s.origin));
|
||
G_FreeEdict (ent);
|
||
return;
|
||
}
|
||
|
||
VectorCopy (tr.endpos, ent->s.origin);
|
||
|
||
gi.linkentity (ent);
|
||
|
||
ent->nextthink = level.time + FRAMETIME;
|
||
ent->think = CTFFlagThink;
|
||
|
||
////PON
|
||
// if (Q_stricmp(ent->classname, "item_flag_team1") == 0) SetBotFlag1(ent);
|
||
// else if (Q_stricmp(ent->classname, "item_flag_team2") == 0) SetBotFlag2(ent);
|
||
////PON
|
||
return;
|
||
}
|
||
|
||
void CTFEffects(edict_t *player)
|
||
{
|
||
player->s.effects &= ~(EF_FLAG1 | EF_FLAG2);
|
||
if (player->health > 0) {
|
||
if (player->client->pers.inventory[ITEM_INDEX(flag1_item)]) {
|
||
player->s.effects |= EF_FLAG1;
|
||
}
|
||
if (player->client->pers.inventory[ITEM_INDEX(flag2_item)]
|
||
|| player->client->pers.inventory[ITEM_INDEX(zflag_item)]) {
|
||
player->s.effects |= EF_FLAG2;
|
||
}
|
||
}
|
||
|
||
if (player->client->pers.inventory[ITEM_INDEX(flag1_item)])
|
||
player->s.modelindex3 = gi.modelindex("players/male/flag1.md2");
|
||
else if (player->client->pers.inventory[ITEM_INDEX(flag2_item)])
|
||
player->s.modelindex3 = gi.modelindex("players/male/flag2.md2");
|
||
else if (player->client->pers.inventory[ITEM_INDEX(zflag_item)])
|
||
{
|
||
player->s.modelindex3 = gi.modelindex("models/zflag.md2");
|
||
}
|
||
else
|
||
player->s.modelindex3 = 0;
|
||
}
|
||
|
||
// called when we enter the intermission
|
||
void CTFCalcScores(void)
|
||
{
|
||
int i;
|
||
|
||
ctfgame.total1 = ctfgame.total2 = 0;
|
||
for (i = 0; i < maxclients->value; i++) {
|
||
if (!g_edicts[i+1].inuse)
|
||
continue;
|
||
if (game.clients[i].resp.ctf_team == CTF_TEAM1)
|
||
ctfgame.total1 += game.clients[i].resp.score;
|
||
else if (game.clients[i].resp.ctf_team == CTF_TEAM2)
|
||
ctfgame.total2 += game.clients[i].resp.score;
|
||
}
|
||
}
|
||
|
||
void CTFID_f (edict_t *ent)
|
||
{
|
||
if (ent->client->resp.id_state) {
|
||
if(!(ent->svflags & SVF_MONSTER))
|
||
gi.cprintf(ent, PRINT_HIGH, "Disabling player identication display.\n");
|
||
ent->client->resp.id_state = false;
|
||
} else {
|
||
if(!(ent->svflags & SVF_MONSTER))
|
||
gi.cprintf(ent, PRINT_HIGH, "Activating player identication display.\n");
|
||
ent->client->resp.id_state = true;
|
||
}
|
||
}
|
||
|
||
static void CTFSetIDView(edict_t *ent)
|
||
{
|
||
vec3_t forward, dir;
|
||
trace_t tr;
|
||
edict_t *who, *best;
|
||
float bd = 0, d;
|
||
int i;
|
||
|
||
ent->client->ps.stats[STAT_CTF_ID_VIEW] = 0;
|
||
|
||
AngleVectors(ent->client->v_angle, forward, NULL, NULL);
|
||
VectorScale(forward, 1024, forward);
|
||
VectorAdd(ent->s.origin, forward, forward);
|
||
tr = gi.trace(ent->s.origin, NULL, NULL, forward, ent, MASK_SOLID);
|
||
if (tr.fraction < 1 && tr.ent && tr.ent->client) {
|
||
ent->client->ps.stats[STAT_CTF_ID_VIEW] =
|
||
CS_PLAYERSKINS + (ent - g_edicts - 1);
|
||
return;
|
||
}
|
||
|
||
AngleVectors(ent->client->v_angle, forward, NULL, NULL);
|
||
best = NULL;
|
||
for (i = 1; i <= maxclients->value; i++) {
|
||
who = g_edicts + i;
|
||
if (!who->inuse)
|
||
continue;
|
||
VectorSubtract(who->s.origin, ent->s.origin, dir);
|
||
VectorNormalize(dir);
|
||
d = DotProduct(forward, dir);
|
||
if (d > bd && loc_CanSee(ent, who)) {
|
||
bd = d;
|
||
best = who;
|
||
}
|
||
}
|
||
if (bd > 0.90)
|
||
ent->client->ps.stats[STAT_CTF_ID_VIEW] =
|
||
CS_PLAYERSKINS + (best - g_edicts - 1);
|
||
}
|
||
|
||
void SetCTFStats(edict_t *ent)
|
||
{
|
||
gitem_t *tech;
|
||
int i;
|
||
int p1, p2;
|
||
edict_t *e;
|
||
|
||
// logo headers for the frag display
|
||
ent->client->ps.stats[STAT_CTF_TEAM1_HEADER] = gi.imageindex ("ctfsb1");
|
||
ent->client->ps.stats[STAT_CTF_TEAM2_HEADER] = gi.imageindex ("ctfsb2");
|
||
|
||
// if during intermission, we must blink the team header of the winning team
|
||
if (level.intermissiontime && (level.framenum & 8)) { // blink 1/8th second
|
||
// note that ctfgame.total[12] is set when we go to intermission
|
||
if (ctfgame.team1 > ctfgame.team2)
|
||
ent->client->ps.stats[STAT_CTF_TEAM1_HEADER] = 0;
|
||
else if (ctfgame.team2 > ctfgame.team1)
|
||
ent->client->ps.stats[STAT_CTF_TEAM2_HEADER] = 0;
|
||
else if (ctfgame.total1 > ctfgame.total2) // frag tie breaker
|
||
ent->client->ps.stats[STAT_CTF_TEAM1_HEADER] = 0;
|
||
else if (ctfgame.total2 > ctfgame.total1)
|
||
ent->client->ps.stats[STAT_CTF_TEAM2_HEADER] = 0;
|
||
else { // tie game!
|
||
ent->client->ps.stats[STAT_CTF_TEAM1_HEADER] = 0;
|
||
ent->client->ps.stats[STAT_CTF_TEAM2_HEADER] = 0;
|
||
}
|
||
}
|
||
|
||
// tech icon
|
||
i = 0;
|
||
ent->client->ps.stats[STAT_CTF_TECH] = 0;
|
||
while (tnames[i]) {
|
||
if ((tech = FindItemByClassname(tnames[i])) != NULL &&
|
||
ent->client->pers.inventory[ITEM_INDEX(tech)]) {
|
||
ent->client->ps.stats[STAT_CTF_TECH] = gi.imageindex(tech->icon);
|
||
break;
|
||
}
|
||
i++;
|
||
}
|
||
|
||
// figure out what icon to display for team logos
|
||
// three states:
|
||
// flag at base
|
||
// flag taken
|
||
// flag dropped
|
||
p1 = gi.imageindex ("i_ctf1");
|
||
e = G_Find(NULL, FOFS(classname), "item_flag_team1");
|
||
if (e != NULL) {
|
||
if (e->solid == SOLID_NOT) {
|
||
int i;
|
||
|
||
// not at base
|
||
// check if on player
|
||
p1 = gi.imageindex ("i_ctf1d"); // default to dropped
|
||
for (i = 1; i <= maxclients->value; i++)
|
||
if (g_edicts[i].inuse &&
|
||
g_edicts[i].client->pers.inventory[ITEM_INDEX(flag1_item)]) {
|
||
// enemy has it
|
||
p1 = gi.imageindex ("i_ctf1t");
|
||
break;
|
||
}
|
||
} else if (e->spawnflags & DROPPED_ITEM)
|
||
p1 = gi.imageindex ("i_ctf1d"); // must be dropped
|
||
}
|
||
p2 = gi.imageindex ("i_ctf2");
|
||
e = G_Find(NULL, FOFS(classname), "item_flag_team2");
|
||
if (e != NULL) {
|
||
if (e->solid == SOLID_NOT) {
|
||
int i;
|
||
|
||
// not at base
|
||
// check if on player
|
||
p2 = gi.imageindex ("i_ctf2d"); // default to dropped
|
||
for (i = 1; i <= maxclients->value; i++)
|
||
if (g_edicts[i].inuse &&
|
||
g_edicts[i].client->pers.inventory[ITEM_INDEX(flag2_item)]) {
|
||
// enemy has it
|
||
p2 = gi.imageindex ("i_ctf2t");
|
||
break;
|
||
}
|
||
} else if (e->spawnflags & DROPPED_ITEM)
|
||
p2 = gi.imageindex ("i_ctf2d"); // must be dropped
|
||
}
|
||
|
||
|
||
ent->client->ps.stats[STAT_CTF_TEAM1_PIC] = p1;
|
||
ent->client->ps.stats[STAT_CTF_TEAM2_PIC] = p2;
|
||
|
||
if (ctfgame.last_flag_capture && level.time - ctfgame.last_flag_capture < 5) {
|
||
if (ctfgame.last_capture_team == CTF_TEAM1)
|
||
if (level.framenum & 8)
|
||
ent->client->ps.stats[STAT_CTF_TEAM1_PIC] = p1;
|
||
else
|
||
ent->client->ps.stats[STAT_CTF_TEAM1_PIC] = 0;
|
||
else
|
||
if (level.framenum & 8)
|
||
ent->client->ps.stats[STAT_CTF_TEAM2_PIC] = p2;
|
||
else
|
||
ent->client->ps.stats[STAT_CTF_TEAM2_PIC] = 0;
|
||
}
|
||
|
||
ent->client->ps.stats[STAT_CTF_TEAM1_CAPS] = ctfgame.team1;
|
||
ent->client->ps.stats[STAT_CTF_TEAM2_CAPS] = ctfgame.team2;
|
||
|
||
ent->client->ps.stats[STAT_CTF_FLAG_PIC] = 0;
|
||
if (ent->client->resp.ctf_team == CTF_TEAM1 &&
|
||
ent->client->pers.inventory[ITEM_INDEX(flag2_item)] &&
|
||
(level.framenum & 8))
|
||
ent->client->ps.stats[STAT_CTF_FLAG_PIC] = gi.imageindex ("i_ctf2");
|
||
|
||
else if (ent->client->resp.ctf_team == CTF_TEAM2 &&
|
||
ent->client->pers.inventory[ITEM_INDEX(flag1_item)] &&
|
||
(level.framenum & 8))
|
||
ent->client->ps.stats[STAT_CTF_FLAG_PIC] = gi.imageindex ("i_ctf1");
|
||
|
||
ent->client->ps.stats[STAT_CTF_JOINED_TEAM1_PIC] = 0;
|
||
ent->client->ps.stats[STAT_CTF_JOINED_TEAM2_PIC] = 0;
|
||
if (ent->client->resp.ctf_team == CTF_TEAM1)
|
||
ent->client->ps.stats[STAT_CTF_JOINED_TEAM1_PIC] = gi.imageindex ("i_ctfj");
|
||
else if (ent->client->resp.ctf_team == CTF_TEAM2)
|
||
ent->client->ps.stats[STAT_CTF_JOINED_TEAM2_PIC] = gi.imageindex ("i_ctfj");
|
||
|
||
ent->client->ps.stats[STAT_CTF_ID_VIEW] = 0;
|
||
if (ent->client->resp.id_state)
|
||
CTFSetIDView(ent);
|
||
}
|
||
|
||
/*------------------------------------------------------------------------*/
|
||
|
||
/*QUAKED info_player_team1 (1 0 0) (-16 -16 -24) (16 16 32)
|
||
potential team1 spawning position for ctf games
|
||
*/
|
||
void SP_info_player_team1(edict_t *self)
|
||
{
|
||
}
|
||
|
||
/*QUAKED info_player_team2 (0 0 1) (-16 -16 -24) (16 16 32)
|
||
potential team2 spawning position for ctf games
|
||
*/
|
||
void SP_info_player_team2(edict_t *self)
|
||
{
|
||
}
|
||
|
||
|
||
/*------------------------------------------------------------------------*/
|
||
/* GRAPPLE */
|
||
/*------------------------------------------------------------------------*/
|
||
|
||
// ent is player
|
||
void CTFPlayerResetGrapple(edict_t *ent)
|
||
{
|
||
int i;
|
||
edict_t *e;
|
||
vec3_t v,vv;
|
||
|
||
//PON-CTF
|
||
if(chedit->value && ent == &g_edicts[1] && ent->client->ctf_grapple)
|
||
{
|
||
e = (edict_t*)ent->client->ctf_grapple;
|
||
VectorCopy(e->s.origin,vv);
|
||
|
||
for(i = 1;(CurrentIndex - i) > 0;i++)
|
||
{
|
||
if(Route[CurrentIndex - i].state == GRS_GRAPHOOK) break;
|
||
else if(Route[CurrentIndex - i].state == GRS_GRAPSHOT) break;
|
||
}
|
||
if(Route[CurrentIndex - i].state == GRS_GRAPHOOK)
|
||
{
|
||
Route[CurrentIndex].state = GRS_GRAPRELEASE;
|
||
VectorCopy(ent->s.origin,Route[CurrentIndex].Pt);
|
||
VectorSubtract(ent->s.origin,vv,v);
|
||
Route[CurrentIndex].Tcourner[0] = VectorLength(v);
|
||
//gi.bprintf(PRINT_HIGH,"length %f\n",VectorLength(v));
|
||
}
|
||
else if(Route[CurrentIndex - i].state == GRS_GRAPSHOT)
|
||
{
|
||
CurrentIndex = CurrentIndex - i -1;
|
||
}
|
||
//gi.bprintf(PRINT_HIGH,"length %f\n",VectorLength(v));
|
||
|
||
if((CurrentIndex - i) > 0)
|
||
{
|
||
if(++CurrentIndex < MAXNODES)
|
||
{
|
||
gi.bprintf(PRINT_HIGH,"Grapple has been released.Last %i pod(s).\n",MAXNODES - CurrentIndex);
|
||
memset(&Route[CurrentIndex],0,sizeof(route_t)); //initialize
|
||
Route[CurrentIndex].index = Route[CurrentIndex - 1].index +1;
|
||
}
|
||
}
|
||
}
|
||
//PON-CTF
|
||
|
||
if (ent->client && ent->client->ctf_grapple)
|
||
CTFResetGrapple(ent->client->ctf_grapple);
|
||
ent->s.sound = 0;
|
||
}
|
||
|
||
// self is grapple, not player
|
||
void CTFResetGrapple(edict_t *self)
|
||
{
|
||
self->s.sound = 0;
|
||
|
||
if(self->owner == NULL)
|
||
{
|
||
G_FreeEdict(self);
|
||
return;
|
||
}
|
||
|
||
if (self->owner->client->ctf_grapple) {
|
||
float volume = 1.0;
|
||
gclient_t *cl;
|
||
|
||
if (self->owner->client->silencer_shots)
|
||
volume = 0.2;
|
||
|
||
gi.sound (self->owner, CHAN_RELIABLE+CHAN_WEAPON, gi.soundindex("weapons/grapple/grreset.wav"), volume, ATTN_NORM, 0);
|
||
cl = self->owner->client;
|
||
cl->ctf_grapple = NULL;
|
||
cl->ctf_grapplereleasetime = level.time;
|
||
cl->ctf_grapplestate = CTF_GRAPPLE_STATE_FLY; // we're firing, not on hook
|
||
cl->ps.pmove.pm_flags &= ~PMF_NO_PREDICTION;
|
||
G_FreeEdict(self);
|
||
}
|
||
}
|
||
|
||
void CTFGrappleTouch (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf)
|
||
{
|
||
short i;
|
||
float volume = 1.0;
|
||
|
||
if (other == self->owner)
|
||
return;
|
||
|
||
if (self->owner->client->ctf_grapplestate != CTF_GRAPPLE_STATE_FLY)
|
||
return;
|
||
|
||
if (surf && (surf->flags & SURF_SKY))
|
||
{
|
||
CTFResetGrapple(self);
|
||
return;
|
||
}
|
||
|
||
VectorCopy(vec3_origin, self->velocity);
|
||
|
||
PlayerNoise(self->owner, self->s.origin, PNOISE_IMPACT);
|
||
|
||
if (other->takedamage) {
|
||
T_Damage (other, self, self->owner, self->velocity, self->s.origin, plane->normal, self->dmg, 1, 0, MOD_GRAPPLE);
|
||
CTFResetGrapple(self);
|
||
return;
|
||
}
|
||
|
||
self->owner->client->ctf_grapplestate = CTF_GRAPPLE_STATE_PULL; // we're on hook
|
||
self->enemy = other;
|
||
|
||
//PON-CTF
|
||
if(chedit->value && self->owner == &g_edicts[1])
|
||
{
|
||
i = CurrentIndex;
|
||
while(--i > 0)
|
||
{
|
||
if(Route[i].state == GRS_GRAPSHOT)
|
||
{
|
||
VectorCopy(self->s.origin,Route[i].Tcourner);
|
||
break;
|
||
}
|
||
}
|
||
Route[CurrentIndex].state = GRS_GRAPHOOK;
|
||
VectorCopy(self->owner->s.origin,Route[CurrentIndex].Pt);
|
||
|
||
if(++CurrentIndex < MAXNODES)
|
||
{
|
||
gi.bprintf(PRINT_HIGH,"Grapple has been hook.Last %i pod(s).\n",MAXNODES - CurrentIndex);
|
||
memset(&Route[CurrentIndex],0,sizeof(route_t)); //initialize
|
||
Route[CurrentIndex].index = Route[CurrentIndex - 1].index +1;
|
||
}
|
||
}
|
||
//PON-CTF
|
||
|
||
self->solid = SOLID_NOT;
|
||
|
||
if (self->owner->client->silencer_shots)
|
||
volume = 0.2;
|
||
|
||
gi.sound (self->owner, CHAN_RELIABLE+CHAN_WEAPON, gi.soundindex("weapons/grapple/grpull.wav"), volume, ATTN_NORM, 0);
|
||
gi.sound (self, CHAN_WEAPON, gi.soundindex("weapons/grapple/grhit.wav"), volume, ATTN_NORM, 0);
|
||
|
||
gi.WriteByte (svc_temp_entity);
|
||
gi.WriteByte (TE_SPARKS);
|
||
gi.WritePosition (self->s.origin);
|
||
if (!plane)
|
||
gi.WriteDir (vec3_origin);
|
||
else
|
||
gi.WriteDir (plane->normal);
|
||
gi.multicast (self->s.origin, MULTICAST_PVS);
|
||
}
|
||
|
||
// draw beam between grapple and self
|
||
void CTFGrappleDrawCable(edict_t *self)
|
||
{
|
||
vec3_t offset, start, end, f, r;
|
||
vec3_t dir;
|
||
float distance;
|
||
float x;
|
||
|
||
if(1/*!(self->owner->svflags & SVF_MONSTER)*/)
|
||
{
|
||
AngleVectors (self->owner->client->v_angle, f, r, NULL);
|
||
VectorSet(offset, 16, 16, self->owner->viewheight-8);
|
||
P_ProjectSource (self->owner->client, self->owner->s.origin, offset, f, r, start);
|
||
}
|
||
else
|
||
{
|
||
x = self->owner->s.angles[YAW] ;
|
||
x = x * M_PI * 2 / 360;
|
||
start[0] = self->owner->s.origin[0] + cos(x) * 16;
|
||
start[1] = self->owner->s.origin[1] + sin(x) * 16;
|
||
if(self->owner->maxs[2] >=32) start[2] = self->owner->s.origin[2]+16;
|
||
else start[2] = self->owner->s.origin[2]-12;
|
||
}
|
||
|
||
VectorSubtract(start, self->owner->s.origin, offset);
|
||
|
||
VectorSubtract (start, self->s.origin, dir);
|
||
distance = VectorLength(dir);
|
||
// don't draw cable if close
|
||
if (distance < 64)
|
||
return;
|
||
|
||
#if 0
|
||
if (distance > 256)
|
||
return;
|
||
|
||
// check for min/max pitch
|
||
vectoangles (dir, angles);
|
||
if (angles[0] < -180)
|
||
angles[0] += 360;
|
||
if (fabs(angles[0]) > 45)
|
||
return;
|
||
|
||
trace_t tr; //!!
|
||
|
||
tr = gi.trace (start, NULL, NULL, self->s.origin, self, MASK_SHOT);
|
||
if (tr.ent != self) {
|
||
CTFResetGrapple(self);
|
||
return;
|
||
}
|
||
#endif
|
||
|
||
// adjust start for beam origin being in middle of a segment
|
||
// VectorMA (start, 8, f, start);
|
||
|
||
VectorCopy (self->s.origin, end);
|
||
// adjust end z for end spot since the monster is currently dead
|
||
// end[2] = self->absmin[2] + self->size[2] / 2;
|
||
|
||
gi.WriteByte (svc_temp_entity);
|
||
#if 1 //def USE_GRAPPLE_CABLE
|
||
gi.WriteByte (TE_GRAPPLE_CABLE);
|
||
gi.WriteShort (self->owner - g_edicts);
|
||
gi.WritePosition (self->owner->s.origin);
|
||
gi.WritePosition (end);
|
||
gi.WritePosition (offset);
|
||
#else
|
||
gi.WriteByte (TE_MEDIC_CABLE_ATTACK);
|
||
gi.WriteShort (self - g_edicts);
|
||
gi.WritePosition (end);
|
||
gi.WritePosition (start);
|
||
#endif
|
||
gi.multicast (self->s.origin, MULTICAST_PVS);
|
||
}
|
||
|
||
void SV_AddGravity (edict_t *ent);
|
||
|
||
// pull the player toward the grapple
|
||
void CTFGrapplePull(edict_t *self)
|
||
{
|
||
vec3_t hookdir, v;
|
||
float vlen;
|
||
|
||
if(self->owner == NULL)
|
||
{
|
||
CTFResetGrapple(self);
|
||
return;
|
||
}
|
||
|
||
/* if(!(self->owner->svflags & SVF_MONSTER))
|
||
{
|
||
if (strcmp(self->owner->client->pers.weapon->classname, "weapon_grapple") == 0 &&
|
||
!self->owner->client->newweapon &&
|
||
self->owner->client->weaponstate != WEAPON_FIRING &&
|
||
self->owner->client->weaponstate != WEAPON_ACTIVATING)
|
||
{
|
||
CTFResetGrapple(self);
|
||
return;
|
||
}
|
||
}*/
|
||
|
||
if (self->enemy) {
|
||
if (self->enemy->solid == SOLID_NOT) {
|
||
CTFResetGrapple(self);
|
||
return;
|
||
}
|
||
if (self->enemy->solid == SOLID_BBOX) {
|
||
VectorScale(self->enemy->size, 0.5, v);
|
||
VectorAdd(v, self->enemy->s.origin, v);
|
||
VectorAdd(v, self->enemy->mins, self->s.origin);
|
||
gi.linkentity (self);
|
||
} else
|
||
VectorCopy(self->enemy->velocity, self->velocity);
|
||
if (self->enemy->takedamage &&
|
||
!CheckTeamDamage (self->enemy, self->owner)) {
|
||
float volume = 1.0;
|
||
|
||
if (self->owner->client->silencer_shots)
|
||
volume = 0.2;
|
||
|
||
T_Damage (self->enemy, self, self->owner, self->velocity, self->s.origin, vec3_origin, 1, 1, 0, MOD_GRAPPLE);
|
||
gi.sound (self, CHAN_WEAPON, gi.soundindex("weapons/grapple/grhurt.wav"), volume, ATTN_NORM, 0);
|
||
}
|
||
if (self->enemy->deadflag) { // he died
|
||
CTFResetGrapple(self);
|
||
return;
|
||
}
|
||
}
|
||
|
||
CTFGrappleDrawCable(self);
|
||
|
||
if (self->owner->client->ctf_grapplestate > CTF_GRAPPLE_STATE_FLY) {
|
||
// pull player toward grapple
|
||
// this causes icky stuff with prediction, we need to extend
|
||
// the prediction layer to include two new fields in the player
|
||
// move stuff: a point and a velocity. The client should add
|
||
// that velociy in the direction of the point
|
||
vec3_t forward, up;
|
||
|
||
if(1/*!(self->owner->svflags & SVF_MONSTER)*/)
|
||
{
|
||
AngleVectors (self->owner->client->v_angle, forward, NULL, up);
|
||
VectorCopy(self->owner->s.origin, v);
|
||
v[2] += self->owner->viewheight;
|
||
VectorSubtract (self->s.origin, v, hookdir);
|
||
}
|
||
else
|
||
{
|
||
VectorCopy(self->owner->s.origin, v);
|
||
if(self->owner->maxs[2] >=32) v[2] += 16;
|
||
else v[2] -= 12;
|
||
VectorSubtract (self->s.origin, v, hookdir);
|
||
}
|
||
|
||
vlen = VectorLength(hookdir);
|
||
|
||
if (self->owner->client->ctf_grapplestate == CTF_GRAPPLE_STATE_PULL &&
|
||
vlen < 64) {
|
||
float volume = 1.0;
|
||
|
||
if (self->owner->client->silencer_shots)
|
||
volume = 0.2;
|
||
|
||
self->owner->client->ps.pmove.pm_flags |= PMF_NO_PREDICTION;
|
||
gi.sound (self->owner, CHAN_RELIABLE+CHAN_WEAPON, gi.soundindex("weapons/grapple/grhang.wav"), volume, ATTN_NORM, 0);
|
||
self->owner->client->ctf_grapplestate = CTF_GRAPPLE_STATE_HANG;
|
||
}
|
||
|
||
VectorNormalize (hookdir);
|
||
VectorScale(hookdir, CTF_GRAPPLE_PULL_SPEED, hookdir);
|
||
VectorCopy(hookdir, self->owner->velocity);
|
||
SV_AddGravity(self->owner);
|
||
}
|
||
}
|
||
|
||
void CTFFireGrapple (edict_t *self, vec3_t start, vec3_t dir, int damage, int speed, int effect)
|
||
{
|
||
edict_t *grapple;
|
||
trace_t tr;
|
||
|
||
VectorNormalize (dir);
|
||
|
||
grapple = G_Spawn();
|
||
VectorCopy (start, grapple->s.origin);
|
||
VectorCopy (start, grapple->s.old_origin);
|
||
vectoangles (dir, grapple->s.angles);
|
||
VectorScale (dir, speed, grapple->velocity);
|
||
grapple->movetype = MOVETYPE_FLYMISSILE;
|
||
grapple->clipmask = MASK_SHOT;
|
||
grapple->solid = SOLID_BBOX;
|
||
grapple->s.effects |= effect;
|
||
VectorClear (grapple->mins);
|
||
VectorClear (grapple->maxs);
|
||
grapple->s.modelindex = gi.modelindex ("models/weapons/grapple/hook/tris.md2");
|
||
// grapple->s.sound = gi.soundindex ("misc/lasfly.wav");
|
||
grapple->owner = self;
|
||
grapple->touch = CTFGrappleTouch;
|
||
// grapple->nextthink = level.time + FRAMETIME;
|
||
// grapple->think = CTFGrappleThink;
|
||
grapple->dmg = damage;
|
||
self->client->ctf_grapple = grapple;
|
||
self->client->ctf_grapplestate = CTF_GRAPPLE_STATE_FLY; // we're firing, not on hook
|
||
gi.linkentity (grapple);
|
||
|
||
tr = gi.trace (self->s.origin, NULL, NULL, grapple->s.origin, grapple, MASK_SHOT);
|
||
if (tr.fraction < 1.0)
|
||
{
|
||
VectorMA (grapple->s.origin, -10, dir, grapple->s.origin);
|
||
grapple->touch (grapple, tr.ent, NULL, NULL);
|
||
}
|
||
//PON-CTF
|
||
if(chedit->value && self == &g_edicts[1])
|
||
{
|
||
Route[CurrentIndex].state = GRS_GRAPSHOT;
|
||
VectorCopy(self->s.origin,Route[CurrentIndex].Pt);
|
||
|
||
if(++CurrentIndex < MAXNODES)
|
||
{
|
||
gi.bprintf(PRINT_HIGH,"Grapple has been shoot.Last %i pod(s).\n",MAXNODES - CurrentIndex);
|
||
memset(&Route[CurrentIndex],0,sizeof(route_t)); //initialize
|
||
Route[CurrentIndex].index = Route[CurrentIndex - 1].index +1;
|
||
}
|
||
}
|
||
//PON-CTF
|
||
|
||
}
|
||
|
||
void CTFGrappleFire (edict_t *ent, vec3_t g_offset, int damage, int effect)
|
||
{
|
||
vec3_t forward, right;
|
||
vec3_t start;
|
||
vec3_t offset;
|
||
float volume = 1.0;
|
||
|
||
if (ent->client->ctf_grapplestate > CTF_GRAPPLE_STATE_FLY)
|
||
return; // it's already out
|
||
|
||
AngleVectors (ent->client->v_angle, forward, right, NULL);
|
||
// VectorSet(offset, 24, 16, ent->viewheight-8+2);
|
||
VectorSet(offset, 24, 8, ent->viewheight-8+2);
|
||
VectorAdd (offset, g_offset, offset);
|
||
P_ProjectSource (ent->client, ent->s.origin, offset, forward, right, start);
|
||
|
||
VectorScale (forward, -2, ent->client->kick_origin);
|
||
ent->client->kick_angles[0] = -1;
|
||
|
||
if (ent->client->silencer_shots)
|
||
volume = 0.2;
|
||
|
||
gi.sound (ent, CHAN_RELIABLE+CHAN_WEAPON, gi.soundindex("weapons/grapple/grfire.wav"), volume, ATTN_NORM, 0);
|
||
CTFFireGrapple (ent, start, forward, damage, CTF_GRAPPLE_SPEED, effect);
|
||
|
||
#if 0
|
||
// send muzzle flash
|
||
gi.WriteByte (svc_muzzleflash);
|
||
gi.WriteShort (ent-g_edicts);
|
||
gi.WriteByte (MZ_BLASTER);
|
||
gi.multicast (ent->s.origin, MULTICAST_PVS);
|
||
#endif
|
||
|
||
PlayerNoise(ent, start, PNOISE_WEAPON);
|
||
}
|
||
|
||
|
||
void CTFWeapon_Grapple_Fire (edict_t *ent)
|
||
{
|
||
int damage;
|
||
|
||
damage = 10;
|
||
CTFGrappleFire (ent, vec3_origin, damage, 0);
|
||
ent->client->ps.gunframe++;
|
||
}
|
||
|
||
void CTFWeapon_Grapple (edict_t *ent)
|
||
{
|
||
static int pause_frames[] = {10, 18, 27, 0};
|
||
static int fire_frames[] = {6, 0};
|
||
int prevstate,i;
|
||
vec3_t v,vv;
|
||
edict_t *e;
|
||
|
||
// if the the attack button is still down, stay in the firing frame
|
||
if ((ent->client->buttons & BUTTON_ATTACK) &&
|
||
ent->client->weaponstate == WEAPON_FIRING &&
|
||
ent->client->ctf_grapple)
|
||
ent->client->ps.gunframe = 9;
|
||
|
||
if (!(ent->client->buttons & BUTTON_ATTACK) &&
|
||
ent->client->ctf_grapple)
|
||
{
|
||
i = ent->client->ctf_grapplestate;
|
||
e = (edict_t*)ent->client->ctf_grapple;
|
||
VectorCopy(e->s.origin,vv);
|
||
CTFResetGrapple(ent->client->ctf_grapple);
|
||
if (ent->client->weaponstate == WEAPON_FIRING)
|
||
ent->client->weaponstate = WEAPON_READY;
|
||
|
||
if(ent->svflags & SVF_MONSTER)
|
||
{
|
||
if(ent->waterlevel
|
||
|| i == CTF_GRAPPLE_STATE_HANG ) VectorClear(ent->velocity);
|
||
//fix the moving speed
|
||
if(i == CTF_GRAPPLE_STATE_PULL)
|
||
{
|
||
v[0] = ent->velocity[0];
|
||
v[1] = ent->velocity[1];
|
||
v[2] = 0;
|
||
|
||
ent->client->zc.moveyaw = Get_yaw(v);
|
||
ent->moveinfo.speed = (VectorLength(v) * FRAMETIME) / MOVE_SPD_RUN;
|
||
ent->velocity[0] = 0;
|
||
ent->velocity[1] = 0;
|
||
}
|
||
else if(i == CTF_GRAPPLE_STATE_HANG )
|
||
{
|
||
ent->moveinfo.speed = 0;
|
||
ent->velocity[0] = 0;
|
||
ent->velocity[1] = 0;
|
||
}
|
||
}
|
||
//PON-CTF
|
||
if(chedit->value && ent == &g_edicts[1])
|
||
{
|
||
for(i = 0;(CurrentIndex - i) > 0;i++)
|
||
{
|
||
if(Route[CurrentIndex - i].state == GRS_GRAPHOOK) break;
|
||
else if(Route[CurrentIndex - i].state == GRS_GRAPSHOT) break;
|
||
}
|
||
if(Route[CurrentIndex - i].state == GRS_GRAPHOOK)
|
||
{
|
||
Route[CurrentIndex].state = GRS_GRAPRELEASE;
|
||
VectorCopy(ent->s.origin,Route[CurrentIndex].Pt);
|
||
VectorSubtract(ent->s.origin,vv,v);
|
||
Route[CurrentIndex].Tcourner[0] = VectorLength(v);
|
||
//gi.bprintf(PRINT_HIGH,"length %f\n",VectorLength(v));
|
||
}
|
||
else if(Route[CurrentIndex - i].state == GRS_GRAPSHOT)
|
||
{
|
||
CurrentIndex = CurrentIndex - i -1;
|
||
}
|
||
//gi.bprintf(PRINT_HIGH,"length %f\n",VectorLength(v));
|
||
|
||
if((CurrentIndex - i) > 0)
|
||
{
|
||
if(++CurrentIndex < MAXNODES)
|
||
{
|
||
gi.bprintf(PRINT_HIGH,"Grapple has been released.Last %i pod(s).\n",MAXNODES - CurrentIndex);
|
||
memset(&Route[CurrentIndex],0,sizeof(route_t)); //initialize
|
||
Route[CurrentIndex].index = Route[CurrentIndex - 1].index +1;
|
||
}
|
||
}
|
||
}
|
||
//PON-CTF
|
||
|
||
}
|
||
|
||
|
||
if (ent->client->newweapon &&
|
||
ent->client->ctf_grapplestate > CTF_GRAPPLE_STATE_FLY &&
|
||
ent->client->weaponstate == WEAPON_FIRING) {
|
||
// he wants to change weapons while grappled
|
||
ent->client->weaponstate = WEAPON_DROPPING;
|
||
ent->client->ps.gunframe = 32;
|
||
}
|
||
|
||
prevstate = ent->client->weaponstate;
|
||
Weapon_Generic (ent, 5, 9, 31, 36, pause_frames, fire_frames,
|
||
CTFWeapon_Grapple_Fire);
|
||
|
||
|
||
if(ent->svflags & SVF_MONSTER)
|
||
{
|
||
return;
|
||
}
|
||
|
||
// if we just switched back to grapple, immediately go to fire frame
|
||
if (prevstate == WEAPON_ACTIVATING &&
|
||
ent->client->weaponstate == WEAPON_READY &&
|
||
ent->client->ctf_grapplestate > CTF_GRAPPLE_STATE_FLY) {
|
||
if (!(ent->client->buttons & BUTTON_ATTACK))
|
||
ent->client->ps.gunframe = 9;
|
||
else
|
||
ent->client->ps.gunframe = 5;
|
||
ent->client->weaponstate = WEAPON_FIRING;
|
||
}
|
||
}
|
||
|
||
void CTFTeam_f (edict_t *ent)
|
||
{
|
||
char *t, *s;
|
||
int desired_team;
|
||
|
||
t = gi.args();
|
||
if (!*t) {
|
||
if(!(ent->svflags & SVF_MONSTER))
|
||
gi.cprintf(ent, PRINT_HIGH, "You are on the %s team.\n",
|
||
CTFTeamName(ent->client->resp.ctf_team));
|
||
return;
|
||
}
|
||
if (Q_stricmp(t, "red") == 0)
|
||
desired_team = CTF_TEAM1;
|
||
else if (Q_stricmp(t, "blue") == 0)
|
||
desired_team = CTF_TEAM2;
|
||
else {
|
||
if(!(ent->svflags & SVF_MONSTER))
|
||
gi.cprintf(ent, PRINT_HIGH, "Unknown team %s.\n", t);
|
||
return;
|
||
}
|
||
|
||
if (ent->client->resp.ctf_team == desired_team) {
|
||
if(!(ent->svflags & SVF_MONSTER))
|
||
gi.cprintf(ent, PRINT_HIGH, "You are already on the %s team.\n",
|
||
CTFTeamName(ent->client->resp.ctf_team));
|
||
return;
|
||
}
|
||
|
||
////
|
||
ent->svflags = 0;
|
||
ent->flags &= ~FL_GODMODE;
|
||
ent->client->resp.ctf_team = desired_team;
|
||
ent->client->resp.ctf_state = CTF_STATE_START;
|
||
s = Info_ValueForKey (ent->client->pers.userinfo, "skin");
|
||
CTFAssignSkin(ent, s);
|
||
|
||
if (ent->solid == SOLID_NOT) { // spectator
|
||
PutClientInServer (ent);
|
||
// add a teleportation effect
|
||
ent->s.event = EV_PLAYER_TELEPORT;
|
||
// hold in place briefly
|
||
ent->client->ps.pmove.pm_flags = PMF_TIME_TELEPORT;
|
||
ent->client->ps.pmove.pm_time = 14;
|
||
gi.bprintf(PRINT_HIGH, "%s joined the %s team.\n",
|
||
ent->client->pers.netname, CTFTeamName(desired_team));
|
||
return;
|
||
}
|
||
|
||
ent->health = 0;
|
||
player_die (ent, ent, ent, 100000, vec3_origin);
|
||
// don't even bother waiting for death frames
|
||
ent->deadflag = DEAD_DEAD;
|
||
respawn (ent);
|
||
|
||
ent->client->resp.score = 0;
|
||
|
||
gi.bprintf(PRINT_HIGH, "%s changed to the %s team.\n",
|
||
ent->client->pers.netname, CTFTeamName(desired_team));
|
||
}
|
||
|
||
/*
|
||
==================
|
||
CTFScoreboardMessage
|
||
==================
|
||
*/
|
||
void CTFScoreboardMessage (edict_t *ent, edict_t *killer)
|
||
{
|
||
char entry[1024];
|
||
char string[1400];
|
||
int len;
|
||
int i, j, k, n;
|
||
int sorted[2][MAX_CLIENTS];
|
||
int sortedscores[2][MAX_CLIENTS];
|
||
int score, total[2], totalscore[2];
|
||
int last[2];
|
||
gclient_t *cl;
|
||
edict_t *cl_ent;
|
||
int team;
|
||
int maxsize = 1000;
|
||
|
||
// sort the clients by team and score
|
||
total[0] = total[1] = 0;
|
||
last[0] = last[1] = 0;
|
||
totalscore[0] = totalscore[1] = 0;
|
||
for (i=0 ; i<game.maxclients ; i++)
|
||
{
|
||
cl_ent = g_edicts + 1 + i;
|
||
if (!cl_ent->inuse)
|
||
continue;
|
||
if (game.clients[i].resp.ctf_team == CTF_TEAM1)
|
||
team = 0;
|
||
else if (game.clients[i].resp.ctf_team == CTF_TEAM2)
|
||
team = 1;
|
||
else
|
||
continue; // unknown team?
|
||
|
||
score = game.clients[i].resp.score;
|
||
for (j=0 ; j<total[team] ; j++)
|
||
{
|
||
if (score > sortedscores[team][j])
|
||
break;
|
||
}
|
||
for (k=total[team] ; k>j ; k--)
|
||
{
|
||
sorted[team][k] = sorted[team][k-1];
|
||
sortedscores[team][k] = sortedscores[team][k-1];
|
||
}
|
||
sorted[team][j] = i;
|
||
sortedscores[team][j] = score;
|
||
totalscore[team] += score;
|
||
total[team]++;
|
||
}
|
||
|
||
// print level name and exit rules
|
||
// add the clients in sorted order
|
||
*string = 0;
|
||
len = 0;
|
||
|
||
// team one
|
||
sprintf(string, "if 24 xv 8 yv 8 pic 24 endif "
|
||
"xv 40 yv 28 string \"%4d/%-3d\" "
|
||
"xv 98 yv 12 num 2 18 "
|
||
"if 25 xv 168 yv 8 pic 25 endif "
|
||
"xv 200 yv 28 string \"%4d/%-3d\" "
|
||
"xv 256 yv 12 num 2 20 ",
|
||
totalscore[0], total[0],
|
||
totalscore[1], total[1]);
|
||
len = (int)strlen(string);
|
||
|
||
for (i=0 ; i<16 ; i++)
|
||
{
|
||
if (i >= total[0] && i >= total[1])
|
||
break; // we're done
|
||
|
||
#if 0 //ndef NEW_SCORE
|
||
// set up y
|
||
sprintf(entry, "yv %d ", 42 + i * 8);
|
||
if (maxsize - len > strlen(entry)) {
|
||
strcat(string, entry);
|
||
len = strlen(string);
|
||
}
|
||
#else
|
||
*entry = 0;
|
||
#endif
|
||
|
||
// left side
|
||
if (i < total[0]) {
|
||
cl = &game.clients[sorted[0][i]];
|
||
cl_ent = g_edicts + 1 + sorted[0][i];
|
||
|
||
#if 0 //ndef NEW_SCORE
|
||
sprintf(entry+strlen(entry),
|
||
"xv 0 %s \"%3d %3d %-12.12s\" ",
|
||
(cl_ent == ent) ? "string2" : "string",
|
||
cl->resp.score,
|
||
(cl->ping > 999) ? 999 : cl->ping,
|
||
cl->pers.netname);
|
||
|
||
if (cl_ent->client->pers.inventory[ITEM_INDEX(flag2_item)])
|
||
strcat(entry, "xv 56 picn sbfctf2 ");
|
||
#else
|
||
sprintf(entry+strlen(entry),
|
||
"ctf 0 %d %d %d %d ",
|
||
42 + i * 8,
|
||
sorted[0][i],
|
||
cl->resp.score,
|
||
cl->ping > 999 ? 999 : cl->ping);
|
||
|
||
if (cl_ent->client->pers.inventory[ITEM_INDEX(flag2_item)])
|
||
sprintf(entry + strlen(entry), "xv 56 yv %d picn sbfctf2 ",
|
||
42 + i * 8);
|
||
#endif
|
||
|
||
if (maxsize - len > strlen(entry)) {
|
||
strcat(string, entry);
|
||
len = (int)strlen(string);
|
||
last[0] = i;
|
||
}
|
||
}
|
||
|
||
// right side
|
||
if (i < total[1]) {
|
||
cl = &game.clients[sorted[1][i]];
|
||
cl_ent = g_edicts + 1 + sorted[1][i];
|
||
|
||
#if 0 //ndef NEW_SCORE
|
||
sprintf(entry+strlen(entry),
|
||
"xv 160 %s \"%3d %3d %-12.12s\" ",
|
||
(cl_ent == ent) ? "string2" : "string",
|
||
cl->resp.score,
|
||
(cl->ping > 999) ? 999 : cl->ping,
|
||
cl->pers.netname);
|
||
|
||
if (cl_ent->client->pers.inventory[ITEM_INDEX(flag1_item)])
|
||
strcat(entry, "xv 216 picn sbfctf1 ");
|
||
|
||
#else
|
||
|
||
sprintf(entry+strlen(entry),
|
||
"ctf 160 %d %d %d %d ",
|
||
42 + i * 8,
|
||
sorted[1][i],
|
||
cl->resp.score,
|
||
cl->ping > 999 ? 999 : cl->ping);
|
||
|
||
if (cl_ent->client->pers.inventory[ITEM_INDEX(flag1_item)])
|
||
sprintf(entry + strlen(entry), "xv 216 yv %d picn sbfctf1 ",
|
||
42 + i * 8);
|
||
#endif
|
||
if (maxsize - len > strlen(entry)) {
|
||
strcat(string, entry);
|
||
len = (int)strlen(string);
|
||
last[1] = i;
|
||
}
|
||
}
|
||
}
|
||
|
||
// put in spectators if we have enough room
|
||
if (last[0] > last[1])
|
||
j = last[0];
|
||
else
|
||
j = last[1];
|
||
j = (j + 2) * 8 + 42;
|
||
|
||
k = n = 0;
|
||
if (maxsize - len > 50) {
|
||
for (i = 0; i < maxclients->value; i++) {
|
||
cl_ent = g_edicts + 1 + i;
|
||
cl = &game.clients[i];
|
||
if (!cl_ent->inuse ||
|
||
cl_ent->solid != SOLID_NOT ||
|
||
cl_ent->client->resp.ctf_team != CTF_NOTEAM)
|
||
continue;
|
||
|
||
if (!k) {
|
||
k = 1;
|
||
sprintf(entry, "xv 0 yv %d string2 \"Spectators\" ", j);
|
||
strcat(string, entry);
|
||
len = (int)strlen(string);
|
||
j += 8;
|
||
}
|
||
|
||
sprintf(entry+strlen(entry),
|
||
"ctf %d %d %d %d %d ",
|
||
(n & 1) ? 160 : 0, // x
|
||
j, // y
|
||
i, // playernum
|
||
cl->resp.score,
|
||
cl->ping > 999 ? 999 : cl->ping);
|
||
if (maxsize - len > strlen(entry)) {
|
||
strcat(string, entry);
|
||
len = (int)strlen(string);
|
||
}
|
||
|
||
if (n & 1)
|
||
j += 8;
|
||
n++;
|
||
}
|
||
}
|
||
|
||
if (total[0] - last[0] > 1) // couldn't fit everyone
|
||
sprintf(string + strlen(string), "xv 8 yv %d string \"..and %d more\" ",
|
||
42 + (last[0]+1)*8, total[0] - last[0] - 1);
|
||
if (total[1] - last[1] > 1) // couldn't fit everyone
|
||
sprintf(string + strlen(string), "xv 168 yv %d string \"..and %d more\" ",
|
||
42 + (last[1]+1)*8, total[1] - last[1] - 1);
|
||
|
||
gi.WriteByte (svc_layout);
|
||
gi.WriteString (string);
|
||
}
|
||
|
||
/*------------------------------------------------------------------------*/
|
||
/* TECH */
|
||
/*------------------------------------------------------------------------*/
|
||
|
||
void CTFHasTech(edict_t *who)
|
||
{
|
||
if(who->svflags & SVF_MONSTER) return ;
|
||
if (level.time - who->client->ctf_lasttechmsg > 2) {
|
||
gi.centerprintf(who, "You already have a TECH powerup.");
|
||
who->client->ctf_lasttechmsg = level.time;
|
||
}
|
||
}
|
||
|
||
gitem_t *CTFWhat_Tech(edict_t *ent)
|
||
{
|
||
gitem_t *tech;
|
||
int i;
|
||
|
||
i = 0;
|
||
while (tnames[i]) {
|
||
if ((tech = FindItemByClassname(tnames[i])) != NULL &&
|
||
ent->client->pers.inventory[ITEM_INDEX(tech)]) {
|
||
return tech;
|
||
}
|
||
i++;
|
||
}
|
||
return NULL;
|
||
}
|
||
|
||
qboolean CTFPickup_Tech (edict_t *ent, edict_t *other)
|
||
{
|
||
gitem_t *tech;
|
||
int i;
|
||
|
||
i = 0;
|
||
while (tnames[i]) {
|
||
if ((tech = FindItemByClassname(tnames[i])) != NULL &&
|
||
other->client->pers.inventory[ITEM_INDEX(tech)]) {
|
||
CTFHasTech(other);
|
||
return false; // has this one
|
||
}
|
||
i++;
|
||
}
|
||
|
||
// client only gets one tech
|
||
other->client->pers.inventory[ITEM_INDEX(ent->item)]++;
|
||
other->client->ctf_regentime = level.time;
|
||
return true;
|
||
}
|
||
|
||
static void SpawnTech(gitem_t *item, edict_t *spot);
|
||
|
||
static edict_t *FindTechSpawn(void)
|
||
{
|
||
edict_t *spot = NULL;
|
||
int i = rand() % 16;
|
||
|
||
while (i--)
|
||
spot = G_Find (spot, FOFS(classname), "info_player_deathmatch");
|
||
if (!spot)
|
||
spot = G_Find (spot, FOFS(classname), "info_player_deathmatch");
|
||
return spot;
|
||
}
|
||
|
||
static void TechThink(edict_t *tech)
|
||
{
|
||
edict_t *spot;
|
||
|
||
if ((spot = FindTechSpawn()) != NULL) {
|
||
SpawnTech(tech->item, spot);
|
||
G_FreeEdict(tech);
|
||
} else {
|
||
tech->nextthink = level.time + CTF_TECH_TIMEOUT;
|
||
tech->think = TechThink;
|
||
}
|
||
}
|
||
|
||
void CTFDrop_Tech(edict_t *ent, gitem_t *item)
|
||
{
|
||
edict_t *tech;
|
||
|
||
tech = Drop_Item(ent, item);
|
||
tech->nextthink = level.time + CTF_TECH_TIMEOUT;
|
||
tech->think = TechThink;
|
||
ent->client->pers.inventory[ITEM_INDEX(item)] = 0;
|
||
}
|
||
|
||
void CTFDeadDropTech(edict_t *ent)
|
||
{
|
||
gitem_t *tech;
|
||
edict_t *dropped;
|
||
int i;
|
||
|
||
i = 0;
|
||
while (tnames[i]) {
|
||
if ((tech = FindItemByClassname(tnames[i])) != NULL &&
|
||
ent->client->pers.inventory[ITEM_INDEX(tech)]) {
|
||
dropped = Drop_Item(ent, tech);
|
||
// hack the velocity to make it bounce random
|
||
dropped->velocity[0] = (rand() % 600) - 300;
|
||
dropped->velocity[1] = (rand() % 600) - 300;
|
||
dropped->nextthink = level.time + CTF_TECH_TIMEOUT;
|
||
dropped->think = TechThink;
|
||
dropped->owner = NULL;
|
||
ent->client->pers.inventory[ITEM_INDEX(tech)] = 0;
|
||
}
|
||
i++;
|
||
}
|
||
}
|
||
|
||
static void SpawnTech (gitem_t *item, edict_t *spot)
|
||
{
|
||
edict_t *ent;
|
||
vec3_t forward, right;
|
||
vec3_t angles;
|
||
|
||
if (!ctf->value)
|
||
return;
|
||
|
||
ent = G_Spawn();
|
||
|
||
ent->classname = item->classname;
|
||
ent->item = item;
|
||
ent->spawnflags = DROPPED_ITEM;
|
||
ent->s.effects = item->world_model_flags;
|
||
ent->s.renderfx = RF_GLOW;
|
||
VectorSet (ent->mins, -15, -15, -15);
|
||
VectorSet (ent->maxs, 15, 15, 15);
|
||
if (ent->item->world_model) //PONKO
|
||
gi.setmodel (ent, ent->item->world_model);
|
||
ent->solid = SOLID_TRIGGER;
|
||
ent->movetype = MOVETYPE_TOSS;
|
||
ent->touch = Touch_Item;
|
||
ent->owner = ent;
|
||
|
||
angles[0] = 0;
|
||
angles[1] = rand() % 360;
|
||
angles[2] = 0;
|
||
|
||
AngleVectors (angles, forward, right, NULL);
|
||
VectorCopy (spot->s.origin, ent->s.origin);
|
||
ent->s.origin[2] += 16;
|
||
VectorScale (forward, 100, ent->velocity);
|
||
ent->velocity[2] = 300;
|
||
|
||
ent->nextthink = level.time + CTF_TECH_TIMEOUT;
|
||
ent->think = TechThink;
|
||
|
||
gi.linkentity (ent);
|
||
}
|
||
|
||
static void SpawnTechs (edict_t *ent)
|
||
{
|
||
gitem_t *tech;
|
||
edict_t *spot;
|
||
int i;
|
||
|
||
i = 0;
|
||
while (tnames[i]) {
|
||
if ((tech = FindItemByClassname(tnames[i])) != NULL &&
|
||
(spot = FindTechSpawn()) != NULL)
|
||
SpawnTech(tech, spot);
|
||
i++;
|
||
}
|
||
}
|
||
|
||
// frees the passed edict!
|
||
void CTFRespawnTech (edict_t *ent)
|
||
{
|
||
edict_t *spot;
|
||
|
||
if ((spot = FindTechSpawn()) != NULL)
|
||
SpawnTech(ent->item, spot);
|
||
G_FreeEdict(ent);
|
||
}
|
||
|
||
void CTFSetupTechSpawn (void)
|
||
{
|
||
edict_t *ent;
|
||
|
||
if (techspawn || ((int)dmflags->value & DF_CTF_NO_TECH))
|
||
return;
|
||
|
||
ent = G_Spawn();
|
||
ent->nextthink = level.time + 2;
|
||
ent->think = SpawnTechs;
|
||
techspawn = true;
|
||
}
|
||
|
||
int CTFApplyResistance(edict_t *ent, int dmg)
|
||
{
|
||
static gitem_t *tech = NULL;
|
||
float volume = 1.0;
|
||
|
||
if (ent->client && ent->client->silencer_shots)
|
||
volume = 0.2;
|
||
|
||
if (!tech)
|
||
tech = FindItemByClassname("item_tech1");
|
||
if (dmg && tech && ent->client && ent->client->pers.inventory[ITEM_INDEX(tech)]) {
|
||
// make noise
|
||
gi.sound(ent, CHAN_VOICE, gi.soundindex("ctf/tech1.wav"), volume, ATTN_NORM, 0);
|
||
return dmg / 2;
|
||
}
|
||
return dmg;
|
||
}
|
||
|
||
int CTFApplyStrength(edict_t *ent, int dmg)
|
||
{
|
||
static gitem_t *tech = NULL;
|
||
|
||
if (!tech)
|
||
tech = FindItemByClassname("item_tech2");
|
||
if (dmg && tech && ent->client && ent->client->pers.inventory[ITEM_INDEX(tech)]) {
|
||
return dmg * 2;
|
||
}
|
||
return dmg;
|
||
}
|
||
|
||
qboolean CTFApplyStrengthSound(edict_t *ent)
|
||
{
|
||
static gitem_t *tech = NULL;
|
||
float volume = 1.0;
|
||
|
||
if (ent->client && ent->client->silencer_shots)
|
||
volume = 0.2;
|
||
|
||
if (!tech)
|
||
tech = FindItemByClassname("item_tech2");
|
||
if (tech && ent->client &&
|
||
ent->client->pers.inventory[ITEM_INDEX(tech)]) {
|
||
if (ent->client->ctf_techsndtime < level.time) {
|
||
ent->client->ctf_techsndtime = level.time + 1;
|
||
if (ent->client->quad_framenum > level.framenum)
|
||
gi.sound(ent, CHAN_VOICE, gi.soundindex("ctf/tech2x.wav"), volume, ATTN_NORM, 0);
|
||
else
|
||
gi.sound(ent, CHAN_VOICE, gi.soundindex("ctf/tech2.wav"), volume, ATTN_NORM, 0);
|
||
}
|
||
return true;
|
||
}
|
||
return false;
|
||
}
|
||
|
||
|
||
qboolean CTFApplyHaste(edict_t *ent)
|
||
{
|
||
static gitem_t *tech = NULL;
|
||
|
||
if (!tech)
|
||
tech = FindItemByClassname("item_tech3");
|
||
if (tech && ent->client &&
|
||
ent->client->pers.inventory[ITEM_INDEX(tech)])
|
||
return true;
|
||
return false;
|
||
}
|
||
|
||
void CTFApplyHasteSound(edict_t *ent)
|
||
{
|
||
static gitem_t *tech = NULL;
|
||
float volume = 1.0;
|
||
|
||
if (ent->client && ent->client->silencer_shots)
|
||
volume = 0.2;
|
||
|
||
if (!tech)
|
||
tech = FindItemByClassname("item_tech3");
|
||
if (tech && ent->client &&
|
||
ent->client->pers.inventory[ITEM_INDEX(tech)] &&
|
||
ent->client->ctf_techsndtime < level.time) {
|
||
ent->client->ctf_techsndtime = level.time + 1;
|
||
gi.sound(ent, CHAN_VOICE, gi.soundindex("ctf/tech3.wav"), volume, ATTN_NORM, 0);
|
||
}
|
||
}
|
||
|
||
void CTFApplyRegeneration(edict_t *ent)
|
||
{
|
||
static gitem_t *tech = NULL;
|
||
qboolean noise = false;
|
||
gclient_t *client;
|
||
int index;
|
||
float volume = 1.0;
|
||
|
||
client = ent->client;
|
||
if (!client)
|
||
return;
|
||
|
||
if (ent->client->silencer_shots)
|
||
volume = 0.2;
|
||
|
||
if (!tech)
|
||
tech = FindItemByClassname("item_tech4");
|
||
if (tech && client->pers.inventory[ITEM_INDEX(tech)]) {
|
||
if (client->ctf_regentime < level.time) {
|
||
client->ctf_regentime = level.time;
|
||
if (ent->health < 150) {
|
||
ent->health += 5;
|
||
if (ent->health > 150)
|
||
ent->health = 150;
|
||
client->ctf_regentime += 0.5;
|
||
noise = true;
|
||
}
|
||
index = ArmorIndex (ent);
|
||
if (index && client->pers.inventory[index] < 150) {
|
||
client->pers.inventory[index] += 5;
|
||
if (client->pers.inventory[index] > 150)
|
||
client->pers.inventory[index] = 150;
|
||
client->ctf_regentime += 0.5;
|
||
noise = true;
|
||
}
|
||
}
|
||
if (noise && ent->client->ctf_techsndtime < level.time) {
|
||
ent->client->ctf_techsndtime = level.time + 1;
|
||
gi.sound(ent, CHAN_VOICE, gi.soundindex("ctf/tech4.wav"), volume, ATTN_NORM, 0);
|
||
}
|
||
}
|
||
}
|
||
|
||
qboolean CTFHasRegeneration(edict_t *ent)
|
||
{
|
||
static gitem_t *tech = NULL;
|
||
|
||
if (!tech)
|
||
tech = FindItemByClassname("item_tech4");
|
||
if (tech && ent->client &&
|
||
ent->client->pers.inventory[ITEM_INDEX(tech)])
|
||
return true;
|
||
return false;
|
||
}
|
||
|
||
/*
|
||
======================================================================
|
||
|
||
SAY_TEAM
|
||
|
||
======================================================================
|
||
*/
|
||
|
||
// This array is in 'importance order', it indicates what items are
|
||
// more important when reporting their names.
|
||
struct {
|
||
char *classname;
|
||
int priority;
|
||
} loc_names[] =
|
||
{
|
||
{ "item_flag_team1", 1 },
|
||
{ "item_flag_team2", 1 },
|
||
{ "item_quad", 2 },
|
||
{ "item_invulnerability", 2 },
|
||
{ "weapon_bfg", 3 },
|
||
{ "weapon_railgun", 4 },
|
||
{ "weapon_rocketlauncher", 4 },
|
||
{ "weapon_hyperblaster", 4 },
|
||
{ "weapon_chaingun", 4 },
|
||
{ "weapon_grenadelauncher", 4 },
|
||
{ "weapon_machinegun", 4 },
|
||
{ "weapon_supershotgun", 4 },
|
||
{ "weapon_shotgun", 4 },
|
||
{ "item_power_screen", 5 },
|
||
{ "item_power_shield", 5 },
|
||
{ "item_armor_body", 6 },
|
||
{ "item_armor_combat", 6 },
|
||
{ "item_armor_jacket", 6 },
|
||
{ "item_silencer", 7 },
|
||
{ "item_breather", 7 },
|
||
{ "item_enviro", 7 },
|
||
{ "item_adrenaline", 7 },
|
||
{ "item_bandolier", 8 },
|
||
{ "item_pack", 8 },
|
||
{ NULL, 0 }
|
||
};
|
||
|
||
|
||
static void CTFSay_Team_Location(edict_t *who, char *buf)
|
||
{
|
||
edict_t *what = NULL;
|
||
edict_t *hot = NULL;
|
||
float hotdist = 999999, newdist;
|
||
vec3_t v;
|
||
int hotindex = 999;
|
||
int i;
|
||
gitem_t *item;
|
||
int nearteam = -1;
|
||
edict_t *flag1, *flag2;
|
||
qboolean hotsee = false;
|
||
qboolean cansee;
|
||
|
||
while ((what = loc_findradius(what, who->s.origin, 1024)) != NULL) {
|
||
// find what in loc_classnames
|
||
for (i = 0; loc_names[i].classname; i++)
|
||
if (strcmp(what->classname, loc_names[i].classname) == 0)
|
||
break;
|
||
if (!loc_names[i].classname)
|
||
continue;
|
||
// something we can see get priority over something we can't
|
||
cansee = loc_CanSee(what, who);
|
||
if (cansee && !hotsee) {
|
||
hotsee = true;
|
||
hotindex = loc_names[i].priority;
|
||
hot = what;
|
||
VectorSubtract(what->s.origin, who->s.origin, v);
|
||
hotdist = VectorLength(v);
|
||
continue;
|
||
}
|
||
// if we can't see this, but we have something we can see, skip it
|
||
if (hotsee && !cansee)
|
||
continue;
|
||
if (hotsee && hotindex < loc_names[i].priority)
|
||
continue;
|
||
VectorSubtract(what->s.origin, who->s.origin, v);
|
||
newdist = VectorLength(v);
|
||
if (newdist < hotdist ||
|
||
(cansee && loc_names[i].priority < hotindex)) {
|
||
hot = what;
|
||
hotdist = newdist;
|
||
hotindex = i;
|
||
hotsee = loc_CanSee(hot, who);
|
||
}
|
||
}
|
||
|
||
if (!hot) {
|
||
strcpy(buf, "nowhere");
|
||
return;
|
||
}
|
||
|
||
// we now have the closest item
|
||
// see if there's more than one in the map, if so
|
||
// we need to determine what team is closest
|
||
what = NULL;
|
||
while ((what = G_Find(what, FOFS(classname), hot->classname)) != NULL) {
|
||
if (what == hot)
|
||
continue;
|
||
// if we are here, there is more than one, find out if hot
|
||
// is closer to red flag or blue flag
|
||
if ((flag1 = G_Find(NULL, FOFS(classname), "item_flag_team1")) != NULL &&
|
||
(flag2 = G_Find(NULL, FOFS(classname), "item_flag_team2")) != NULL) {
|
||
VectorSubtract(hot->s.origin, flag1->s.origin, v);
|
||
hotdist = VectorLength(v);
|
||
VectorSubtract(hot->s.origin, flag2->s.origin, v);
|
||
newdist = VectorLength(v);
|
||
if (hotdist < newdist)
|
||
nearteam = CTF_TEAM1;
|
||
else if (hotdist > newdist)
|
||
nearteam = CTF_TEAM2;
|
||
}
|
||
break;
|
||
}
|
||
|
||
if ((item = FindItemByClassname(hot->classname)) == NULL) {
|
||
strcpy(buf, "nowhere");
|
||
return;
|
||
}
|
||
|
||
// in water?
|
||
if (who->waterlevel)
|
||
strcpy(buf, "in the water ");
|
||
else
|
||
*buf = 0;
|
||
|
||
// near or above
|
||
VectorSubtract(who->s.origin, hot->s.origin, v);
|
||
if (fabs(v[2]) > fabs(v[0]) && fabs(v[2]) > fabs(v[1]))
|
||
if (v[2] > 0)
|
||
strcat(buf, "above ");
|
||
else
|
||
strcat(buf, "below ");
|
||
else
|
||
strcat(buf, "near ");
|
||
|
||
if (nearteam == CTF_TEAM1)
|
||
strcat(buf, "the red ");
|
||
else if (nearteam == CTF_TEAM2)
|
||
strcat(buf, "the blue ");
|
||
else
|
||
strcat(buf, "the ");
|
||
|
||
strcat(buf, item->pickup_name);
|
||
}
|
||
|
||
static void CTFSay_Team_Armor(edict_t *who, char *buf)
|
||
{
|
||
gitem_t *item;
|
||
int index, cells;
|
||
int power_armor_type;
|
||
|
||
*buf = 0;
|
||
|
||
power_armor_type = PowerArmorType (who);
|
||
if (power_armor_type)
|
||
{
|
||
cells = who->client->pers.inventory[ITEM_INDEX(Fdi_CELLS/*FindItem ("cells")*/)];
|
||
if (cells)
|
||
sprintf(buf+strlen(buf), "%s with %i cells ",
|
||
(power_armor_type == POWER_ARMOR_SCREEN) ?
|
||
"Power Screen" : "Power Shield", cells);
|
||
}
|
||
|
||
index = ArmorIndex (who);
|
||
if (index)
|
||
{
|
||
item = GetItemByIndex (index);
|
||
if (item) {
|
||
if (*buf)
|
||
strcat(buf, "and ");
|
||
sprintf(buf+strlen(buf), "%i units of %s",
|
||
who->client->pers.inventory[index], item->pickup_name);
|
||
}
|
||
}
|
||
|
||
if (!*buf)
|
||
strcpy(buf, "no armor");
|
||
}
|
||
|
||
static void CTFSay_Team_Health(edict_t *who, char *buf)
|
||
{
|
||
if (who->health <= 0)
|
||
strcpy(buf, "dead");
|
||
else
|
||
sprintf(buf, "%i health", who->health);
|
||
}
|
||
|
||
static void CTFSay_Team_Tech(edict_t *who, char *buf)
|
||
{
|
||
gitem_t *tech;
|
||
int i;
|
||
|
||
// see if the player has a tech powerup
|
||
i = 0;
|
||
while (tnames[i]) {
|
||
if ((tech = FindItemByClassname(tnames[i])) != NULL &&
|
||
who->client->pers.inventory[ITEM_INDEX(tech)]) {
|
||
sprintf(buf, "the %s", tech->pickup_name);
|
||
return;
|
||
}
|
||
i++;
|
||
}
|
||
strcpy(buf, "no powerup");
|
||
}
|
||
|
||
static void CTFSay_Team_Weapon(edict_t *who, char *buf)
|
||
{
|
||
if (who->client->pers.weapon)
|
||
strcpy(buf, who->client->pers.weapon->pickup_name);
|
||
else
|
||
strcpy(buf, "none");
|
||
}
|
||
|
||
static void CTFSay_Team_Sight(edict_t *who, char *buf)
|
||
{
|
||
int i;
|
||
edict_t *targ;
|
||
int n = 0;
|
||
char s[1024];
|
||
char s2[1024];
|
||
|
||
*s = *s2 = 0;
|
||
for (i = 1; i <= maxclients->value; i++) {
|
||
targ = g_edicts + i;
|
||
if (!targ->inuse ||
|
||
targ == who ||
|
||
!loc_CanSee(targ, who))
|
||
continue;
|
||
if (*s2) {
|
||
if (strlen(s) + strlen(s2) + 3 < sizeof(s)) {
|
||
if (n)
|
||
strcat(s, ", ");
|
||
strcat(s, s2);
|
||
*s2 = 0;
|
||
}
|
||
n++;
|
||
}
|
||
strcpy(s2, targ->client->pers.netname);
|
||
}
|
||
if (*s2) {
|
||
if (strlen(s) + strlen(s2) + 6 < sizeof(s)) {
|
||
if (n)
|
||
strcat(s, " and ");
|
||
strcat(s, s2);
|
||
}
|
||
strcpy(buf, s);
|
||
} else
|
||
strcpy(buf, "no one");
|
||
}
|
||
|
||
void CTFSay_Team(edict_t *who, char *msg)
|
||
{
|
||
char outmsg[1024];
|
||
char buf[1024];
|
||
int i;
|
||
char *p;
|
||
edict_t *cl_ent;
|
||
|
||
outmsg[0] = 0;
|
||
|
||
if (*msg == '\"') {
|
||
msg[strlen(msg) - 1] = 0;
|
||
msg++;
|
||
}
|
||
|
||
for (p = outmsg; *msg && (p - outmsg) < sizeof(outmsg) - 1; msg++) {
|
||
if (*msg == '%') {
|
||
switch (*++msg) {
|
||
case 'l' :
|
||
case 'L' :
|
||
CTFSay_Team_Location(who, buf);
|
||
strcpy(p, buf);
|
||
p += strlen(buf);
|
||
break;
|
||
case 'a' :
|
||
case 'A' :
|
||
CTFSay_Team_Armor(who, buf);
|
||
strcpy(p, buf);
|
||
p += strlen(buf);
|
||
break;
|
||
case 'h' :
|
||
case 'H' :
|
||
CTFSay_Team_Health(who, buf);
|
||
strcpy(p, buf);
|
||
p += strlen(buf);
|
||
break;
|
||
case 't' :
|
||
case 'T' :
|
||
CTFSay_Team_Tech(who, buf);
|
||
strcpy(p, buf);
|
||
p += strlen(buf);
|
||
break;
|
||
case 'w' :
|
||
case 'W' :
|
||
CTFSay_Team_Weapon(who, buf);
|
||
strcpy(p, buf);
|
||
p += strlen(buf);
|
||
break;
|
||
|
||
case 'n' :
|
||
case 'N' :
|
||
CTFSay_Team_Sight(who, buf);
|
||
strcpy(p, buf);
|
||
p += strlen(buf);
|
||
break;
|
||
|
||
default :
|
||
*p++ = *msg;
|
||
}
|
||
} else
|
||
*p++ = *msg;
|
||
}
|
||
*p = 0;
|
||
|
||
for (i = 0; i < maxclients->value; i++) {
|
||
cl_ent = g_edicts + 1 + i;
|
||
if (!cl_ent->inuse)
|
||
continue;
|
||
if (cl_ent->client->resp.ctf_team == who->client->resp.ctf_team)
|
||
{
|
||
if(!(cl_ent->svflags & SVF_MONSTER))
|
||
gi.cprintf(cl_ent, PRINT_CHAT, "(%s): %s\n",
|
||
who->client->pers.netname, outmsg);
|
||
}
|
||
}
|
||
}
|
||
|
||
/*-----------------------------------------------------------------------*/
|
||
/*QUAKED misc_ctf_banner (1 .5 0) (-4 -64 0) (4 64 248) TEAM2
|
||
The origin is the bottom of the banner.
|
||
The banner is 248 tall.
|
||
*/
|
||
static void misc_ctf_banner_think (edict_t *ent)
|
||
{
|
||
ent->s.frame = (ent->s.frame + 1) % 16;
|
||
ent->nextthink = level.time + FRAMETIME;
|
||
}
|
||
|
||
void SP_misc_ctf_banner (edict_t *ent)
|
||
{
|
||
ent->movetype = MOVETYPE_NONE;
|
||
ent->solid = SOLID_NOT;
|
||
ent->s.modelindex = gi.modelindex ("models/ctf/banner/tris.md2");
|
||
if (ent->spawnflags & 1) // team2
|
||
ent->s.skinnum = 1;
|
||
|
||
ent->s.frame = rand() % 16;
|
||
gi.linkentity (ent);
|
||
|
||
ent->think = misc_ctf_banner_think;
|
||
ent->nextthink = level.time + FRAMETIME;
|
||
}
|
||
|
||
/*QUAKED misc_ctf_small_banner (1 .5 0) (-4 -32 0) (4 32 124) TEAM2
|
||
The origin is the bottom of the banner.
|
||
The banner is 124 tall.
|
||
*/
|
||
void SP_misc_ctf_small_banner (edict_t *ent)
|
||
{
|
||
ent->movetype = MOVETYPE_NONE;
|
||
ent->solid = SOLID_NOT;
|
||
ent->s.modelindex = gi.modelindex ("models/ctf/banner/small.md2");
|
||
if (ent->spawnflags & 1) // team2
|
||
ent->s.skinnum = 1;
|
||
|
||
ent->s.frame = rand() % 16;
|
||
gi.linkentity (ent);
|
||
|
||
ent->think = misc_ctf_banner_think;
|
||
ent->nextthink = level.time + FRAMETIME;
|
||
}
|
||
|
||
|
||
/*-----------------------------------------------------------------------*/
|
||
|
||
void CTFJoinTeam(edict_t *ent, int desired_team)
|
||
{
|
||
char *s;
|
||
|
||
PMenu_Close(ent);
|
||
|
||
ent->svflags &= ~SVF_NOCLIENT;
|
||
ent->client->resp.ctf_team = desired_team;
|
||
ent->client->resp.ctf_state = CTF_STATE_START;
|
||
s = Info_ValueForKey (ent->client->pers.userinfo, "skin");
|
||
CTFAssignSkin(ent, s);
|
||
|
||
/* if(!hokuto->value)
|
||
{*/
|
||
PutClientInServer (ent);
|
||
// add a teleportation effect
|
||
ent->s.event = EV_PLAYER_TELEPORT;
|
||
// hold in place briefly
|
||
ent->client->ps.pmove.pm_flags = PMF_TIME_TELEPORT;
|
||
ent->client->ps.pmove.pm_time = 14;
|
||
gi.bprintf(PRINT_HIGH, "%s joined the %s team.\n",
|
||
ent->client->pers.netname, CTFTeamName(ent->client->resp.ctf_team/*desired_team*/));
|
||
/* }
|
||
else ZigockJoinMenu(ent);*/
|
||
}
|
||
|
||
void CTFJoinTeam1(edict_t *ent, pmenu_t *p)
|
||
{
|
||
CTFJoinTeam(ent, CTF_TEAM1);
|
||
}
|
||
|
||
void CTFJoinTeam2(edict_t *ent, pmenu_t *p)
|
||
{
|
||
CTFJoinTeam(ent, CTF_TEAM2);
|
||
}
|
||
|
||
void CTFChaseCam(edict_t *ent, pmenu_t *p)
|
||
{
|
||
int i;
|
||
edict_t *e;
|
||
|
||
if (ent->client->chase_target) {
|
||
ent->client->chase_target = NULL;
|
||
PMenu_Close(ent);
|
||
return;
|
||
}
|
||
|
||
for (i = 1; i <= maxclients->value; i++) {
|
||
e = g_edicts + i;
|
||
if (e->inuse && e->solid != SOLID_NOT) {
|
||
ent->client->chase_target = e;
|
||
PMenu_Close(ent);
|
||
ent->client->update_chase = true;
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
|
||
void CTFReturnToMain(edict_t *ent, pmenu_t *p)
|
||
{
|
||
PMenu_Close(ent);
|
||
CTFOpenJoinMenu(ent);
|
||
}
|
||
|
||
void CTFCredits(edict_t *ent, pmenu_t *p);
|
||
|
||
void DeathmatchScoreboard (edict_t *ent);
|
||
|
||
void CTFShowScores(edict_t *ent, pmenu_t *p)
|
||
{
|
||
PMenu_Close(ent);
|
||
|
||
ent->client->showscores = true;
|
||
ent->client->showinventory = false;
|
||
DeathmatchScoreboard (ent);
|
||
}
|
||
|
||
pmenu_t creditsmenu[] = {
|
||
{ "*Quake II", PMENU_ALIGN_CENTER, NULL, NULL },
|
||
{ "*ThreeWave Capture the Flag", PMENU_ALIGN_CENTER, NULL, NULL },
|
||
{ NULL, PMENU_ALIGN_CENTER, NULL, NULL },
|
||
{ "*Programming", PMENU_ALIGN_CENTER, NULL, NULL },
|
||
{ "Dave 'Zoid' Kirsch", PMENU_ALIGN_CENTER, NULL, NULL },
|
||
{ "*Level Design", PMENU_ALIGN_CENTER, NULL, NULL },
|
||
{ "Christian Antkow", PMENU_ALIGN_CENTER, NULL, NULL },
|
||
{ "Tim Willits", PMENU_ALIGN_CENTER, NULL, NULL },
|
||
{ "Dave 'Zoid' Kirsch", PMENU_ALIGN_CENTER, NULL, NULL },
|
||
{ "*Art", PMENU_ALIGN_CENTER, NULL, NULL },
|
||
{ "Adrian Carmack Paul Steed", PMENU_ALIGN_CENTER, NULL, NULL },
|
||
{ "Kevin Cloud", PMENU_ALIGN_CENTER, NULL, NULL },
|
||
{ "*Sound", PMENU_ALIGN_CENTER, NULL, NULL },
|
||
{ "Tom 'Bjorn' Klok", PMENU_ALIGN_CENTER, NULL, NULL },
|
||
{ "*Original CTF Art Design", PMENU_ALIGN_CENTER, NULL, NULL },
|
||
{ "Brian 'Whaleboy' Cozzens", PMENU_ALIGN_CENTER, NULL, NULL },
|
||
{ NULL, PMENU_ALIGN_CENTER, NULL, NULL },
|
||
{ "Return to Main Menu", PMENU_ALIGN_LEFT, NULL, CTFReturnToMain }
|
||
};
|
||
|
||
|
||
pmenu_t joinmenu[] = {
|
||
{ "*Quake II", PMENU_ALIGN_CENTER, NULL, NULL },
|
||
{ "*ThreeWave Capture the Flag", PMENU_ALIGN_CENTER, NULL, NULL },
|
||
{ NULL, PMENU_ALIGN_CENTER, NULL, NULL },
|
||
{ NULL, PMENU_ALIGN_CENTER, NULL, NULL },
|
||
{ "Join Red Team", PMENU_ALIGN_LEFT, NULL, CTFJoinTeam1 },
|
||
{ NULL, PMENU_ALIGN_LEFT, NULL, NULL },
|
||
{ "Join Blue Team", PMENU_ALIGN_LEFT, NULL, CTFJoinTeam2 },
|
||
{ NULL, PMENU_ALIGN_LEFT, NULL, NULL },
|
||
{ "Chase Camera", PMENU_ALIGN_LEFT, NULL, CTFChaseCam },
|
||
{ "Credits", PMENU_ALIGN_LEFT, NULL, CTFCredits },
|
||
{ NULL, PMENU_ALIGN_LEFT, NULL, NULL },
|
||
{ "Use [ and ] to move cursor", PMENU_ALIGN_LEFT, NULL, NULL },
|
||
{ "ENTER to select", PMENU_ALIGN_LEFT, NULL, NULL },
|
||
{ "ESC to Exit Menu", PMENU_ALIGN_LEFT, NULL, NULL },
|
||
{ "(TAB to Return)", PMENU_ALIGN_LEFT, NULL, NULL },
|
||
{ NULL, PMENU_ALIGN_LEFT, NULL, NULL },
|
||
{ "v" CTF_STRING_VERSION, PMENU_ALIGN_RIGHT, NULL, NULL },
|
||
};
|
||
|
||
int CTFUpdateJoinMenu(edict_t *ent)
|
||
{
|
||
static char levelname[32];
|
||
static char team1players[32];
|
||
static char team2players[32];
|
||
int num1, num2, i;
|
||
|
||
joinmenu[4].text = "Join Red Team";
|
||
joinmenu[4].SelectFunc = CTFJoinTeam1;
|
||
joinmenu[6].text = "Join Blue Team";
|
||
joinmenu[6].SelectFunc = CTFJoinTeam2;
|
||
|
||
if (ctf_forcejoin->string && *ctf_forcejoin->string) {
|
||
if (Q_stricmp(ctf_forcejoin->string, "red") == 0) {
|
||
joinmenu[6].text = NULL;
|
||
joinmenu[6].SelectFunc = NULL;
|
||
} else if (Q_stricmp(ctf_forcejoin->string, "blue") == 0) {
|
||
joinmenu[4].text = NULL;
|
||
joinmenu[4].SelectFunc = NULL;
|
||
}
|
||
}
|
||
|
||
if (ent->client->chase_target)
|
||
joinmenu[8].text = "Leave Chase Camera";
|
||
else
|
||
joinmenu[8].text = "Chase Camera";
|
||
|
||
levelname[0] = '*';
|
||
if (g_edicts[0].message)
|
||
strncpy(levelname+1, g_edicts[0].message, sizeof(levelname) - 2);
|
||
else
|
||
strncpy(levelname+1, level.mapname, sizeof(levelname) - 2);
|
||
levelname[sizeof(levelname) - 1] = 0;
|
||
|
||
num1 = num2 = 0;
|
||
for (i = 0; i < maxclients->value; i++) {
|
||
if (!g_edicts[i+1].inuse)
|
||
continue;
|
||
if (game.clients[i].resp.ctf_team == CTF_TEAM1)
|
||
num1++;
|
||
else if (game.clients[i].resp.ctf_team == CTF_TEAM2)
|
||
num2++;
|
||
}
|
||
|
||
sprintf(team1players, " (%d players)", num1);
|
||
sprintf(team2players, " (%d players)", num2);
|
||
|
||
joinmenu[2].text = levelname;
|
||
if (joinmenu[4].text)
|
||
joinmenu[5].text = team1players;
|
||
else
|
||
joinmenu[5].text = NULL;
|
||
if (joinmenu[6].text)
|
||
joinmenu[7].text = team2players;
|
||
else
|
||
joinmenu[7].text = NULL;
|
||
|
||
if (num1 > num2)
|
||
return CTF_TEAM1;
|
||
else if (num2 > num1)
|
||
return CTF_TEAM1;
|
||
return (rand() & 1) ? CTF_TEAM1 : CTF_TEAM2;
|
||
}
|
||
|
||
void CTFOpenJoinMenu(edict_t *ent)
|
||
{
|
||
int team;
|
||
|
||
team = CTFUpdateJoinMenu(ent);
|
||
if (ent->client->chase_target)
|
||
team = 8;
|
||
else if (team == CTF_TEAM1)
|
||
team = 4;
|
||
else
|
||
team = 6;
|
||
PMenu_Open(ent, joinmenu, team, sizeof(joinmenu) / sizeof(pmenu_t));
|
||
}
|
||
|
||
void CTFCredits(edict_t *ent, pmenu_t *p)
|
||
{
|
||
PMenu_Close(ent);
|
||
PMenu_Open(ent, creditsmenu, -1, sizeof(creditsmenu) / sizeof(pmenu_t));
|
||
}
|
||
|
||
qboolean CTFStartClient(edict_t *ent)
|
||
{
|
||
if (ent->client->resp.ctf_team != CTF_NOTEAM)
|
||
return false;
|
||
|
||
if (!((int)dmflags->value & DF_CTF_FORCEJOIN)) {
|
||
// start as 'observer'
|
||
ent->movetype = MOVETYPE_NOCLIP;
|
||
ent->solid = SOLID_NOT;
|
||
ent->svflags |= SVF_NOCLIENT;
|
||
ent->client->resp.ctf_team = CTF_NOTEAM;
|
||
ent->client->ps.gunindex = 0;
|
||
gi.linkentity (ent);
|
||
|
||
CTFOpenJoinMenu(ent);
|
||
return true;
|
||
}
|
||
return false;
|
||
}
|
||
|
||
qboolean CTFCheckRules(void)
|
||
{
|
||
if (capturelimit->value &&
|
||
(ctfgame.team1 >= capturelimit->value ||
|
||
ctfgame.team2 >= capturelimit->value)) {
|
||
gi.bprintf (PRINT_HIGH, "Capturelimit hit.\n");
|
||
return true;
|
||
}
|
||
return false;
|
||
}
|
||
|
||
/*--------------------------------------------------------------------------
|
||
* just here to help old map conversions
|
||
*--------------------------------------------------------------------------*/
|
||
|
||
static void old_teleporter_touch (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf)
|
||
{
|
||
edict_t *dest;
|
||
int i;
|
||
vec3_t forward;
|
||
|
||
if (!other->client)
|
||
return;
|
||
dest = G_Find (NULL, FOFS(targetname), self->target);
|
||
if (!dest)
|
||
{
|
||
gi.dprintf ("Couldn't find destination\n");
|
||
return;
|
||
}
|
||
|
||
//ZOID
|
||
CTFPlayerResetGrapple(other);
|
||
//ZOID
|
||
|
||
// unlink to make sure it can't possibly interfere with KillBox
|
||
gi.unlinkentity (other);
|
||
|
||
VectorCopy (dest->s.origin, other->s.origin);
|
||
VectorCopy (dest->s.origin, other->s.old_origin);
|
||
// other->s.origin[2] += 10;
|
||
|
||
// clear the velocity and hold them in place briefly
|
||
VectorClear (other->velocity);
|
||
other->client->ps.pmove.pm_time = 160>>3; // hold time
|
||
other->client->ps.pmove.pm_flags |= PMF_TIME_TELEPORT;
|
||
|
||
// draw the teleport splash at source and on the player
|
||
self->enemy->s.event = EV_PLAYER_TELEPORT;
|
||
other->s.event = EV_PLAYER_TELEPORT;
|
||
|
||
// set angles
|
||
for (i=0 ; i<3 ; i++)
|
||
other->client->ps.pmove.delta_angles[i] = ANGLE2SHORT(dest->s.angles[i] - other->client->resp.cmd_angles[i]);
|
||
|
||
other->s.angles[PITCH] = 0;
|
||
other->s.angles[YAW] = dest->s.angles[YAW];
|
||
other->s.angles[ROLL] = 0;
|
||
VectorCopy (dest->s.angles, other->client->ps.viewangles);
|
||
VectorCopy (dest->s.angles, other->client->v_angle);
|
||
|
||
// give a little forward velocity
|
||
AngleVectors (other->client->v_angle, forward, NULL, NULL);
|
||
VectorScale(forward, 200, other->velocity);
|
||
|
||
// kill anything at the destination
|
||
if (!KillBox (other))
|
||
{
|
||
}
|
||
|
||
gi.linkentity (other);
|
||
}
|
||
|
||
/*QUAKED trigger_teleport (0.5 0.5 0.5) ?
|
||
Players touching this will be teleported
|
||
*/
|
||
void SP_trigger_teleport (edict_t *ent)
|
||
{
|
||
edict_t *s;
|
||
int i;
|
||
|
||
if (!ent->target)
|
||
{
|
||
gi.dprintf ("teleporter without a target.\n");
|
||
G_FreeEdict (ent);
|
||
return;
|
||
}
|
||
|
||
ent->svflags |= SVF_NOCLIENT;
|
||
ent->solid = SOLID_TRIGGER;
|
||
ent->touch = old_teleporter_touch;
|
||
if(ent->model)
|
||
gi.setmodel (ent, ent->model);
|
||
gi.linkentity (ent);
|
||
|
||
// noise maker and splash effect dude
|
||
s = G_Spawn();
|
||
ent->enemy = s;
|
||
for (i = 0; i < 3; i++)
|
||
s->s.origin[i] = ent->mins[i] + (ent->maxs[i] - ent->mins[i])/2;
|
||
s->s.sound = gi.soundindex ("world/hum1.wav");
|
||
gi.linkentity(s);
|
||
|
||
}
|
||
|
||
/*QUAKED info_teleport_destination (0.5 0.5 0.5) (-16 -16 -24) (16 16 32)
|
||
Point trigger_teleports at these.
|
||
*/
|
||
void SP_info_teleport_destination (edict_t *ent)
|
||
{
|
||
ent->s.origin[2] += 16;
|
||
}
|
||
|
||
//PON
|
||
void SpawnExtra(vec3_t position,char *classname);
|
||
void ED_CallSpawn (edict_t *ent);
|
||
|
||
//------------------------
|
||
//
|
||
// Route setup
|
||
//
|
||
// Not only for CTF but also DM
|
||
//
|
||
//------------------------
|
||
void CTFSetupNavSpawn()
|
||
{
|
||
FILE *fpout;
|
||
char name[256];
|
||
char code[8];
|
||
char SRCcode[8];
|
||
int i,j;
|
||
vec3_t v;
|
||
edict_t *other;
|
||
|
||
unsigned int size;
|
||
|
||
//PONKO
|
||
spawncycle = level.time + FRAMETIME * 100;
|
||
//PONKO
|
||
//<2F><><EFBFBD>[<5B>g<EFBFBD><67><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||
CurrentIndex = 0;
|
||
memset(Route,0,sizeof(Route));
|
||
memset(code,0,8);
|
||
|
||
if(!ctf->value) sprintf(name,".\\%s\\chdtm\\%s.chn",gamepath->string,level.mapname);
|
||
else sprintf(name,".\\%s\\chctf\\%s.chf",gamepath->string,level.mapname);
|
||
|
||
fpout = fopen(name,"rb");
|
||
if(fpout == NULL)
|
||
{
|
||
if(!ctf->value) gi.dprintf("Chaining: file %s.chn not found.\n",level.mapname);
|
||
else gi.dprintf("Chaining: file %s.chf not found.\n",level.mapname);
|
||
}
|
||
else
|
||
{
|
||
fread(code,sizeof(char),8,fpout);
|
||
|
||
if(!ctf->value) strncpy(SRCcode,"3ZBRGDTM",8);
|
||
else strncpy(SRCcode,"3ZBRGCTF",8);
|
||
|
||
if(strncmp(code,SRCcode,8))
|
||
{
|
||
CurrentIndex = 0;
|
||
gi.dprintf("Chaining: %s.chn is not a chaining file.\n",level.mapname);
|
||
fclose(fpout);
|
||
return;
|
||
}
|
||
gi.dprintf("Chaining: %s.chn founded.\n",level.mapname);
|
||
fread(&CurrentIndex,sizeof(int),1,fpout);
|
||
|
||
size = (unsigned int)CurrentIndex * sizeof(route_t);
|
||
fread(Route,size,1,fpout);
|
||
|
||
for(i = 0;i < CurrentIndex;i++)
|
||
{
|
||
if(Route[i].state == GRS_TELEPORT)
|
||
gi.dprintf("GRS_TELEPORT\n");
|
||
if((Route[i].state > GRS_TELEPORT/*GRS_ONROTATE*/ && Route[i].state <= GRS_PUSHBUTTON)
|
||
|| Route[i].state == GRS_REDFLAG || Route[i].state == GRS_BLUEFLAG)
|
||
{
|
||
other = &g_edicts[(int)maxclients->value+1];
|
||
for ( j=maxclients->value+1 ; j<globals.num_edicts ; j++, other++)
|
||
{
|
||
if (other->inuse)
|
||
{
|
||
if(Route[i].state == GRS_ONPLAT
|
||
|| Route[i].state == GRS_ONTRAIN
|
||
|| Route[i].state == GRS_PUSHBUTTON
|
||
|| Route[i].state == GRS_ONDOOR)
|
||
{
|
||
VectorAdd(other->s.origin,other->mins,v);
|
||
if(VectorCompare (Route[i].Pt,v/*other->monsterinfo.last_sighting*/))
|
||
{
|
||
//onplat
|
||
if(Route[i].state == GRS_ONPLAT
|
||
&& !Q_stricmp(other->classname, "func_plat"))
|
||
{
|
||
//gi.dprintf("assingned %s\n",other->classname);
|
||
Route[i].ent = other;
|
||
break;
|
||
}
|
||
//train
|
||
else if(Route[i].state == GRS_ONTRAIN
|
||
&& !Q_stricmp(other->classname, "func_train"))
|
||
{
|
||
//gi.dprintf("assingned %s\n",other->classname);
|
||
Route[i].ent = other;
|
||
break;
|
||
}
|
||
//button
|
||
else if(Route[i].state == GRS_PUSHBUTTON
|
||
&& !Q_stricmp(other->classname, "func_button"))
|
||
{
|
||
//gi.dprintf("assingned %s\n",other->classname);
|
||
Route[i].ent = other;
|
||
break;
|
||
}
|
||
//door
|
||
else if(Route[i].state == GRS_ONDOOR
|
||
&& !Q_stricmp(other->classname, "func_door"))
|
||
{
|
||
//gi.dprintf("assingned %s\n",other->classname);
|
||
Route[i].ent = other;
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
else if(Route[i].state == GRS_ITEMS
|
||
|| Route[i].state == GRS_REDFLAG || Route[i].state == GRS_BLUEFLAG)
|
||
{
|
||
//else gi.dprintf("CYAU!!!!!!!\n");
|
||
if(VectorCompare (Route[i].Pt,other->monsterinfo.last_sighting/*->s.origin*/))
|
||
{
|
||
//onplat
|
||
if(1/*other->classname[0] == 'w' || other->classname[0] == 'i'*/)
|
||
{
|
||
//if(Route[i].state == GRS_REDFLAG || Route[i].state == GRS_BLUEFLAG)
|
||
//gi.dprintf("HATA ATTA!!!!!!!\n");
|
||
//gi.dprintf("assingned %s\n",other->classname);
|
||
Route[i].ent = other;
|
||
break;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
//if(Route[i].state == GRS_REDFLAG || Route[i].state == GRS_BLUEFLAG)
|
||
//gi.dprintf("HATA Dame!!!!!!!\n");
|
||
}
|
||
}
|
||
}
|
||
}
|
||
if(j >= globals.num_edicts && (Route[i].state == GRS_ITEMS || Route[i].state == GRS_REDFLAG || Route[i].state == GRS_BLUEFLAG)) gi.dprintf("kicked item\n");
|
||
if(j >= globals.num_edicts) Route[i].state = GRS_NORMAL;
|
||
}
|
||
}
|
||
gi.dprintf("Chaining: Total %i chaining pod assigned.\n",CurrentIndex);
|
||
fclose(fpout);
|
||
}
|
||
return;
|
||
}
|
||
|
||
void SpawnExtra(vec3_t position,char *classname)
|
||
{
|
||
edict_t *it_ent;
|
||
|
||
it_ent = G_Spawn();
|
||
|
||
it_ent->classname = classname;
|
||
VectorCopy(position,it_ent->s.origin);
|
||
ED_CallSpawn(it_ent);
|
||
|
||
if(ctf->value && chedit->value)
|
||
{
|
||
it_ent->moveinfo.speed = -1;
|
||
it_ent->s.effects |= EF_QUAD;
|
||
}
|
||
}
|
||
|
||
void CTFJobAssign (void)
|
||
{
|
||
int i;
|
||
int defend1,defend2; //<2F>f<EFBFBD>B<EFBFBD>t<EFBFBD>F<EFBFBD><46><EFBFBD>_<EFBFBD>[<5B><><EFBFBD><EFBFBD>
|
||
int mate1,mate2; //<2F>`<60>[<5B><><EFBFBD><EFBFBD><EFBFBD>C<EFBFBD>g<EFBFBD><67><EFBFBD><EFBFBD>
|
||
gclient_t *client;
|
||
edict_t *e;
|
||
edict_t *defei1,*defei2; //<2F><><EFBFBD><EFBFBD>
|
||
edict_t *geti1,*geti2; //<2F><><EFBFBD><EFBFBD>
|
||
|
||
defend1 = 0;
|
||
defend2 = 0;
|
||
mate1 = 0;
|
||
mate2 = 0;
|
||
defei1 = NULL;
|
||
defei2 = NULL;
|
||
geti1 = NULL;
|
||
geti2 = NULL;
|
||
|
||
e = &g_edicts[(int)maxclients->value];
|
||
for ( i = maxclients->value ; i >= 1 ; i--, e--)
|
||
{
|
||
if (e->inuse)
|
||
{
|
||
client = e->client;
|
||
if(client->zc.ctfstate == CTFS_NONE) client->zc.ctfstate = CTFS_DEFENDER;
|
||
//if(client->zc.ctfstate == CTFS_CARRIER)
|
||
//gi.bprintf(PRINT_HIGH,"I am carrierY!!\n");
|
||
if(e->client->resp.ctf_team == CTF_TEAM1)
|
||
{
|
||
mate1++;
|
||
if( e->client->pers.inventory[ITEM_INDEX(FindItem("Blue Flag"))])
|
||
{
|
||
client->zc.ctfstate = CTFS_CARRIER;
|
||
}
|
||
if(1/*e->svflags & SVF_MONSTER*/)
|
||
{
|
||
|
||
if( client->zc.ctfstate == CTFS_OFFENCER && random()>0.7) defei1 = e;
|
||
else if( client->zc.ctfstate == CTFS_DEFENDER)
|
||
{
|
||
if(random()>0.7) geti1 = e;
|
||
defend1++;
|
||
}
|
||
else if( client->zc.ctfstate == CTFS_CARRIER ) defend1++;
|
||
}
|
||
}
|
||
else if(e->client->resp.ctf_team == CTF_TEAM2)
|
||
{
|
||
mate2++;
|
||
if( e->client->pers.inventory[ITEM_INDEX(FindItem("Red Flag"))])
|
||
{
|
||
client->zc.ctfstate = CTFS_CARRIER;
|
||
}
|
||
if(1/*e->svflags & SVF_MONSTER*/)
|
||
{
|
||
if( client->zc.ctfstate == CTFS_OFFENCER && random()>0.8) defei2 = e;
|
||
else if( client->zc.ctfstate == CTFS_DEFENDER)
|
||
{
|
||
if(random()>0.7) geti2 = e;
|
||
defend2++;
|
||
}
|
||
else if( client->zc.ctfstate == CTFS_CARRIER ) defend2++;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
if(defend1 < mate1 / 3 && mate1 >= 2)
|
||
{
|
||
if(defei1 != NULL) defei1->client->zc.ctfstate = CTFS_DEFENDER;
|
||
}
|
||
else if(defend1 > mate1 / 3 )
|
||
{
|
||
if(geti1 != NULL) geti1->client->zc.ctfstate = CTFS_OFFENCER;
|
||
}
|
||
if(defend2 < mate2 / 3 && mate2 >= 2)
|
||
{
|
||
if(defei2 != NULL) defei2->client->zc.ctfstate = CTFS_DEFENDER;
|
||
}
|
||
else if(defend2 > mate2 / 3 )
|
||
{
|
||
if(geti2 != NULL) geti2->client->zc.ctfstate = CTFS_OFFENCER;
|
||
}
|
||
/// gi.bprintf(PRINT_HIGH,"Called!!!!\n");
|
||
} |