Merge generic parts of ctf/ with baseq2/. This should have any impact on

the baseq2/ source path.
This commit is contained in:
Yamagi Burmeister 2011-10-05 15:30:11 +00:00
parent 0bd9096f7f
commit 56b41dd705
14 changed files with 881 additions and 6 deletions

View File

@ -103,11 +103,24 @@ SelectNextItem(edict_t *ent, int itflags)
cl = ent->client;
#ifdef CTF
if (cl->menu)
{
PMenu_Next(ent);
return;
}
else if (cl->chase_target)
{
ChaseNext(ent);
return;
}
#else
if (cl->chase_target)
{
ChaseNext(ent);
return;
}
#endif
/* scan for the next valid one */
for (i = 1; i <= MAX_ITEMS; i++)
@ -152,11 +165,24 @@ SelectPrevItem(edict_t *ent, int itflags)
cl = ent->client;
#ifdef CTF
if (cl->menu)
{
PMenu_Prev(ent);
return;
}
else if (cl->chase_target)
{
ChasePrev(ent);
return;
}
#else
if (cl->chase_target)
{
ChasePrev(ent);
return;
}
#endif
/* scan for the next valid one */
for (i = 1; i <= MAX_ITEMS; i++)
@ -578,6 +604,16 @@ Cmd_Drop_f(edict_t *ent)
return;
}
#ifdef CTF
/* Special case for the
tech powerup */
if (Q_stricmp(gi.args(), "tech") == 0 && (it = CTFWhat_Tech(ent)) != NULL)
{
it->drop (ent, it);
return;
}
#endif
s = gi.args();
it = FindItem(s);
@ -620,12 +656,28 @@ Cmd_Inven_f(edict_t *ent)
cl->showscores = false;
cl->showhelp = false;
#ifdef CTF
if (ent->client->menu)
{
PMenu_Close(ent);
ent->client->update_chase = true;
return;
}
#endif
if (cl->showinventory)
{
cl->showinventory = false;
return;
}
#ifdef CTF
if (ctf->value && cl->resp.ctf_team == CTF_NOTEAM)
{
CTFOpenJoinMenu(ent);
return;
}
#endif
cl->showinventory = true;
gi.WriteByte(svc_inventory);
@ -648,6 +700,14 @@ Cmd_InvUse_f(edict_t *ent)
return;
}
#ifdef CTF
if (ent->client->menu)
{
PMenu_Select(ent);
return;
}
#endif
ValidateSelectedItem(ent);
if (ent->client->pers.selected_item == -1)
@ -667,6 +727,30 @@ Cmd_InvUse_f(edict_t *ent)
it->use(ent, it);
}
#ifdef CTF
void
Cmd_LastWeap_f (edict_t *ent)
{
gclient_t *cl;
if (!ent)
{
return;
}
cl = ent->client;
if (!cl->pers.weapon || !cl->pers.lastweapon)
{
return;
}
cl->pers.lastweapon->use (ent, cl->pers.lastweapon);
}
#endif
void
Cmd_WeapPrev_f(edict_t *ent)
{
@ -851,6 +935,13 @@ Cmd_Kill_f(edict_t *ent)
return;
}
#ifdef CTF
if (ent->solid == SOLID_NOT)
{
return;
}
#endif
if (((level.time - ent->client->respawn_time) < 5) ||
(ent->client->resp.spectator))
{
@ -874,6 +965,15 @@ Cmd_PutAway_f(edict_t *ent)
ent->client->showscores = false;
ent->client->showhelp = false;
ent->client->showinventory = false;
#ifdef CTF
if (ent->client->menu)
{
PMenu_Close(ent);
}
ent->client->update_chase = true;
#endif
}
int
@ -1319,6 +1419,60 @@ ClientCommand(edict_t *ent)
{
Cmd_PlayerList_f(ent);
}
#ifdef CTF
else if (Q_stricmp (cmd, "team") == 0)
{
CTFTeam_f (ent);
}
else if (Q_stricmp(cmd, "id") == 0)
{
CTFID_f (ent);
}
else if (Q_stricmp(cmd, "yes") == 0)
{
CTFVoteYes(ent);
}
else if (Q_stricmp(cmd, "no") == 0)
{
CTFVoteNo(ent);
}
else if (Q_stricmp(cmd, "ready") == 0)
{
CTFReady(ent);
}
else if (Q_stricmp(cmd, "notready") == 0)
{
CTFNotReady(ent);
}
else if (Q_stricmp(cmd, "ghost") == 0)
{
CTFGhost(ent);
}
else if (Q_stricmp(cmd, "admin") == 0)
{
CTFAdmin(ent);
}
else if (Q_stricmp(cmd, "stats") == 0)
{
CTFStats(ent);
}
else if (Q_stricmp(cmd, "warp") == 0)
{
CTFWarp(ent);
}
else if (Q_stricmp(cmd, "boot") == 0)
{
CTFBoot(ent);
}
else if (Q_stricmp(cmd, "playerlist") == 0)
{
CTFPlayerList(ent);
}
else if (Q_stricmp(cmd, "observer") == 0)
{
CTFObserver(ent);
}
#endif
else /* anything that doesn't match a command will be a chat */
{
Cmd_Say_f(ent, false, true);

View File

@ -506,6 +506,29 @@ M_ReactToDamage(edict_t *targ, edict_t *attacker)
}
}
qboolean
CheckTeamDamage (edict_t *targ, edict_t *attacker)
{
if (!targ || !attacker)
{
return false;
}
#ifdef CTF
if (ctf->value && targ->client && attacker->client)
{
if (targ->client->resp.ctf_team ==
attacker->client->resp.ctf_team && targ != attacker)
{
return true;
}
#endif
return false;
}
void
T_Damage(edict_t *targ, edict_t *inflictor, edict_t *attacker,
vec3_t dir, vec3_t point, vec3_t normal, int damage,
@ -581,6 +604,11 @@ T_Damage(edict_t *targ, edict_t *inflictor, edict_t *attacker,
damage *= 2;
}
#ifdef CTF
/* strength tech */
damage = CTFApplyStrength(attacker, damage);
#endif
if (targ->flags & FL_NO_KNOCKBACK)
{
knockback = 0;
@ -646,21 +674,48 @@ T_Damage(edict_t *targ, edict_t *inflictor, edict_t *attacker,
save = damage;
}
#ifdef CTF
/* team armor protect */
if (ctf->value && targ->client && attacker->client &&
targ->client->resp.ctf_team == attacker->client->resp.ctf_team &&
targ != attacker && ((int)dmflags->value & DF_ARMOR_PROTECT))
{
psave = asave = 0;
}
else
{
psave = CheckPowerArmor (targ, point, normal, take, dflags);
take -= psave;
asave = CheckArmor (targ, point, normal, take, te_sparks, dflags);
take -= asave;
}
#else
psave = CheckPowerArmor(targ, point, normal, take, dflags);
take -= psave;
asave = CheckArmor(targ, point, normal, take, te_sparks, dflags);
take -= asave;
#endif
/* treat cheat/powerup savings the same as armor */
asave += save;
#ifdef CTF
/* Resistance tech */
take = CTFApplyResistance(targ, take);
#endif
/* team damage avoidance */
if ((dflags & DAMAGE_NO_PROTECTION))
if (!(dflags & DAMAGE_NO_PROTECTION) && CheckTeamDamage (targ, attacker))
{
return;
}
#ifdef CTF
CTFCheckHurtCarrier(targ, attacker);
#endif
/* do the damage */
if (take)
{

View File

@ -147,6 +147,27 @@ DoRespawn(edict_t *ent)
master = ent->teammaster;
#ifdef CTF
/* in ctf, when we are weapons stay, only the
master of a team of weapons is spawned */
if (ctf->value && ((int)dmflags->value & DF_WEAPONS_STAY) &&
master->item && (master->item->flags & IT_WEAPON))
{
ent = master;
}
else
{
for (count = 0, ent = master; ent; ent = ent->chain, count++)
{
}
choice = rand() % count;
for (count = 0, ent = master; count < choice; ent = ent->chain, count++)
{
}
}
#else
for (count = 0, ent = master; ent; ent = ent->chain, count++)
{
}
@ -156,6 +177,7 @@ DoRespawn(edict_t *ent)
for (count = 0, ent = master; count < choice; ent = ent->chain, count++)
{
}
#endif
}
ent->svflags &= ~SVF_NOCLIENT;
@ -824,7 +846,11 @@ MegaHealth_think(edict_t *self)
return;
}
if (self->owner->health > self->owner->max_health)
if (self->owner->health > self->owner->max_health
#ifdef CTF
&& !CTFHasRegeneration(self->owner)
#endif
)
{
self->nextthink = level.time + 1;
self->owner->health -= 1;
@ -857,8 +883,22 @@ Pickup_Health(edict_t *ent, edict_t *other)
}
}
#ifdef CTF
if (other->health >= 250 && ent->count > 25)
{
return false;
}
#endif
other->health += ent->count;
#ifdef CTF
if (other->health > 250 && ent->count > 25)
{
other->health = 250;
}
#endif
if (!(ent->style & HEALTH_IGNORE_MAX))
{
if (other->health > other->max_health)
@ -867,7 +907,11 @@ Pickup_Health(edict_t *ent, edict_t *other)
}
}
if (ent->style & HEALTH_TIMED)
if ((ent->style & HEALTH_TIMED)
#ifdef CTF
&& !CTFHasRegeneration(other)
#endif
)
{
ent->think = MegaHealth_think;
ent->nextthink = level.time + 5;
@ -1641,6 +1685,16 @@ SpawnItem(edict_t *ent, gitem_t *item)
item->drop = NULL;
}
#ifdef CTF
/* Don't spawn the flags unless enabled */
if (!ctf->value && (strcmp(ent->classname, "item_flag_team1") == 0 ||
strcmp(ent->classname, "item_flag_team2") == 0))
{
G_FreeEdict(ent);
return;
}
#endif
ent->item = item;
ent->nextthink = level.time + 2 * FRAMETIME; /* items start after other solids */
ent->think = droptofloor;
@ -1651,6 +1705,15 @@ SpawnItem(edict_t *ent, gitem_t *item)
{
gi.modelindex(ent->model);
}
#ifdef CTF
/* flags are server animated */
if (strcmp(ent->classname, "item_flag_team1") == 0 ||
strcmp(ent->classname, "item_flag_team2") == 0)
{
ent->think = CTFFlagSetup;
}
#endif
}
/* ====================================================================== */
@ -2572,6 +2635,140 @@ gitem_t itemlist[] = {
"items/s_health.wav items/n_health.wav items/l_health.wav items/m_health.wav"
},
#ifdef CTF
/* QUAKED item_flag_team1 (1 0.2 0) (-16 -16 -24) (16 16 32) */
{
"item_flag_team1",
CTFPickup_Flag,
NULL,
CTFDrop_Flag,
NULL,
"ctf/flagtk.wav",
"players/male/flag1.md2", EF_FLAG1,
NULL,
"i_ctf1",
"Red Flag",
2,
0,
NULL,
0,
0,
NULL,
0,
"ctf/flagcap.wav"
},
/* QUAKED item_flag_team2 (1 0.2 0) (-16 -16 -24) (16 16 32) */
{
"item_flag_team2",
CTFPickup_Flag,
NULL,
CTFDrop_Flag,
NULL,
"ctf/flagtk.wav",
"players/male/flag2.md2", EF_FLAG2,
NULL,
"i_ctf2",
"Blue Flag",
2,
0,
NULL,
0,
0,
NULL,
0,
"ctf/flagcap.wav"
},
/* Resistance Tech */
{
"item_tech1",
CTFPickup_Tech,
NULL,
CTFDrop_Tech,
NULL,
"items/pkup.wav",
"models/ctf/resistance/tris.md2", EF_ROTATE,
NULL,
"tech1",
"Disruptor Shield",
2,
0,
NULL,
IT_TECH,
0,
NULL,
0,
"ctf/tech1.wav"
},
/* Strength Tech */
{
"item_tech2",
CTFPickup_Tech,
NULL,
CTFDrop_Tech,
NULL,
"items/pkup.wav",
"models/ctf/strength/tris.md2", EF_ROTATE,
NULL,
"tech2",
"Power Amplifier",
2,
0,
NULL,
IT_TECH,
0,
NULL,
0,
"ctf/tech2.wav ctf/tech2x.wav"
},
/* Haste Tech */
{
"item_tech3",
CTFPickup_Tech,
NULL,
CTFDrop_Tech,
NULL,
"items/pkup.wav",
"models/ctf/haste/tris.md2", EF_ROTATE,
NULL,
"tech3",
"Time Accel",
2,
0,
NULL,
IT_TECH,
0,
NULL,
0,
"ctf/tech3.wav"
},
/* Regeneration Tech */
{
"item_tech4",
CTFPickup_Tech,
NULL,
CTFDrop_Tech,
NULL,
"items/pkup.wav",
"models/ctf/regeneration/tris.md2", EF_ROTATE,
NULL,
"tech4",
"AutoDoc",
2,
0,
NULL,
IT_TECH,
0,
NULL,
0,
"ctf/tech4.wav"
},
#endif
/* end of list marker */
{NULL}
};

View File

@ -32,8 +32,16 @@
#define GAME_INCLUDE
#include "game.h"
#ifdef CTF
#include "p_menu.h"
#endif
/* the "gameversion" client command will print this plus compile date */
#define GAMEVERSION "baseq2"
#ifdef CTF
#define GAMEVERSION "ctf"
#else
#define GAMEVERSION "baseq2"
#endif
/* protocol bytes that can be directly added to messages */
#define svc_muzzleflash 1
@ -208,6 +216,9 @@ typedef struct
#define IT_STAY_COOP 8
#define IT_KEY 16
#define IT_POWERUP 32
#ifdef CTF
#define IT_TECH 64
#endif
/* gitem_t->weapmodel for weapons indicates model index */
#define WEAP_BLASTER 1
@ -221,6 +232,9 @@ typedef struct
#define WEAP_HYPERBLASTER 9
#define WEAP_RAILGUN 10
#define WEAP_BFG 11
#ifdef CTF
#define WEAP_GRAPPLE 12
#endif
typedef struct gitem_s
{
@ -494,6 +508,12 @@ extern cvar_t *dmflags;
extern cvar_t *skill;
extern cvar_t *fraglimit;
extern cvar_t *timelimit;
#ifdef CTF
extern cvar_t *capturelimit;
extern cvar_t *instantweap;
#endif
extern cvar_t *password;
extern cvar_t *spectator_password;
extern cvar_t *needpass;
@ -828,6 +848,22 @@ typedef struct
client_persistant_t coop_respawn; /* what to set client->pers to on a respawn */
int enterframe; /* level.framenum the client entered the game */
int score; /* frags, etc */
#ifdef CTF
int ctf_team; /*CTF team */
int ctf_state;
float ctf_lasthurtcarrier;
float ctf_lastreturnedflag;
float ctf_flagsince;
float ctf_lastfraggedcarrier;
qboolean id_state;
float lastidtime;
qboolean voted; /* for elections */
qboolean ready;
qboolean admin;
struct ghost_s *ghost;
#endif
vec3_t cmd_angles; /* angles sent over in the last command */
qboolean spectator; /* client is a spectator */
@ -847,6 +883,11 @@ struct gclient_s
pmove_state_t old_pmove; /* for detecting out-of-pmove changes */
qboolean showscores; /* set layout stat */
#ifdef CTF
qboolean inmenu; /* in menu */
pmenuhnd_t *menu; /* current menu */
#endif
qboolean showinventory; /* set layout stat */
qboolean showhelp;
qboolean showhelpicon;
@ -915,6 +956,19 @@ struct gclient_s
float respawn_time; /* can respawn when time > this */
#ifdef CTF
void *ctf_grapple; /* entity of grapple */
int ctf_grapplestate; /* true if pulling */
float ctf_grapplereleasetime; /* time of grapple release */
float ctf_regentime; /* regen tech */
float ctf_techsndtime;
float ctf_lasttechmsg;
edict_t *chase_target;
qboolean update_chase;
float menutime; /* time to update menu */
qboolean menudirty;
#endif
edict_t *chase_target; /* player we are chasing */
qboolean update_chase; /* need to update chase info? */
};
@ -1066,3 +1120,7 @@ struct edict_s
monsterinfo_t monsterinfo;
};
#ifdef CTF
#include "g_ctf.h"
#endif

View File

@ -44,6 +44,12 @@ cvar_t *dmflags;
cvar_t *skill;
cvar_t *fraglimit;
cvar_t *timelimit;
#ifdef CTF
cvar_t *capturelimit;
cvar_t *instantweap;
#endif
cvar_t *password;
cvar_t *spectator_password;
cvar_t *needpass;
@ -336,6 +342,19 @@ CheckDMRules(void)
return;
}
#ifdef CTF
if (ctf->value && CTFCheckRules())
{
EndDMLevel ();
return;
}
if (CTFInMatch())
{
return;
}
#endif
if (timelimit->value)
{
if (level.time >= timelimit->value * 60)

View File

@ -421,6 +421,32 @@ BecomeExplosion1(edict_t *self)
return;
}
#ifdef CTF
/* Flags are important! */
if (strcmp(self->classname, "item_flag_team1") == 0)
{
CTFResetFlag(CTF_TEAM1);
gi.bprintf(PRINT_HIGH, "The %s flag has returned!\n",
CTFTeamName(CTF_TEAM1));
return;
}
if (strcmp(self->classname, "item_flag_team2") == 0)
{
CTFResetFlag(CTF_TEAM2);
gi.bprintf(PRINT_HIGH, "The %s flag has returned!\n",
CTFTeamName(CTF_TEAM1));
return;
}
/* techs are important too */
if (self->item && (self->item->flags & IT_TECH))
{
CTFRespawnTech(self);
return;
}
#endif
gi.WriteByte(svc_temp_entity);
gi.WriteByte(TE_EXPLOSION1);
gi.WritePosition(self->s.origin);
@ -2584,6 +2610,10 @@ teleporter_touch(edict_t *self, edict_t *other, cplane_t *plane /* unused */,
return;
}
#ifdef CTF
CTFPlayerResetGrapple(other);
#endif
/* unlink to make sure it can't possibly interfere with KillBox */
gi.unlinkentity(other);

View File

@ -160,6 +160,11 @@ spawn_t spawns[] = {
{"info_player_coop", SP_info_player_coop},
{"info_player_intermission", SP_info_player_intermission},
#ifdef CTF
{"info_player_team1", SP_info_player_team1},
{"info_player_team2", SP_info_player_team2},
#endif
{"func_plat", SP_func_plat},
{"func_button", SP_func_button},
{"func_door", SP_func_door},
@ -222,6 +227,10 @@ spawn_t spawns[] = {
{"misc_explobox", SP_misc_explobox},
{"misc_banner", SP_misc_banner},
#ifdef CTF
{"misc_ctf_banner", SP_misc_ctf_banner},
{"misc_ctf_small_banner", SP_misc_ctf_small_banner},
#endif
{"misc_satellite_dish", SP_misc_satellite_dish},
{"misc_actor", SP_misc_actor},
{"misc_gib_arm", SP_misc_gib_arm},
@ -235,11 +244,16 @@ spawn_t spawns[] = {
{"misc_strogg_ship", SP_misc_strogg_ship},
{"misc_teleporter", SP_misc_teleporter},
{"misc_teleporter_dest", SP_misc_teleporter_dest},
#ifdef CTF
{"trigger_teleport", SP_trigger_teleport},
{"info_teleport_destination", SP_info_teleport_destination},
#endif
{"misc_blackhole", SP_misc_blackhole},
{"misc_eastertank", SP_misc_eastertank},
{"misc_easterchick", SP_misc_easterchick},
{"misc_easterchick2", SP_misc_easterchick2},
#ifndef CTF
{"monster_berserk", SP_monster_berserk},
{"monster_gladiator", SP_monster_gladiator},
{"monster_gunner", SP_monster_gunner},
@ -268,6 +282,7 @@ spawn_t spawns[] = {
{"turret_breach", SP_turret_breach},
{"turret_base", SP_turret_base},
{"turret_driver", SP_turret_driver},
#endif
{NULL, NULL}
};
@ -707,6 +722,10 @@ SpawnEntities(const char *mapname, char *entities, const char *spawnpoint)
G_FindTeams();
PlayerTrail_Init();
#ifdef CTF
CTFSpawn();
#endif
}
/* =================================================================== */
@ -917,7 +936,19 @@ SP_worldspawn(edict_t *ent)
/* status bar program */
if (deathmatch->value)
{
#ifdef CTF
if (ctf->value)
{
gi.configstring (CS_STATUSBAR, ctf_statusbar);
CTFPrecache();
}
else
{
gi.configstring (CS_STATUSBAR, dm_statusbar);
}
#else
gi.configstring(CS_STATUSBAR, dm_statusbar);
#endif
}
else
{

View File

@ -1103,6 +1103,16 @@ bfg_think(edict_t *self)
continue;
}
#ifdef CTF
/* Don't target players in CTF */
if (ctf->value && ent->client &&
self->owner->client &&
ent->client->resp.ctf_team == self->owner->client->resp.ctf_team)
{
continue;
}
#endif
VectorMA(ent->absmin, 0.5, ent->size, point);
VectorSubtract(point, self->s.origin, dir);

View File

@ -40,6 +40,10 @@
#define SVF_DEADMONSTER 0x00000002 /* treat as CONTENTS_DEADMONSTER for collision */
#define SVF_MONSTER 0x00000004 /* treat as CONTENTS_MONSTER for collision */
#ifdef CTF
#define SVF_PROJECTILE 0x00000008
#endif
#define MAX_ENT_CLUSTERS 16
typedef enum

View File

@ -520,6 +520,12 @@ ClientObituary(edict_t *self, edict_t *inflictor /* unused */,
message = "tried to invade";
message2 = "'s personal space";
break;
#ifdef CTF
case MOD_GRAPPLE:
message = "was caught by";
message2 = "'s grapple";
break;
#endif
}
if (message)
@ -691,6 +697,10 @@ player_die(edict_t *self, edict_t *inflictor, edict_t *attacker,
self->s.modelindex2 = 0; /* remove linked weapon model */
#ifdef CTF
self->s.modelindex3 = 0;
#endif
self->s.angles[0] = 0;
self->s.angles[2] = 0;
@ -707,8 +717,28 @@ player_die(edict_t *self, edict_t *inflictor, edict_t *attacker,
LookAtKiller(self, inflictor, attacker);
self->client->ps.pmove.pm_type = PM_DEAD;
ClientObituary(self, inflictor, attacker);
#ifdef CTF
/* if at start and same team, clear */
if (ctf->value && meansOfDeath == MOD_TELEFRAG &&
self->client->resp.ctf_state < 2 &&
self->client->resp.ctf_team == attacker->client->resp.ctf_team)
{
attacker->client->resp.score--;
self->client->resp.ctf_state = 0;
}
CTFFragBonuses(self, inflictor, attacker);
#endif
TossClientWeapon(self);
#ifdef CTF
CTFPlayerResetGrapple(self);
CTFDeadDropFlag(self);
CTFDeadDropTech(self);
#endif
if (deathmatch->value)
{
Cmd_Help_f(self); /* show scores */
@ -749,6 +779,11 @@ player_die(edict_t *self, edict_t *inflictor, edict_t *attacker,
ThrowClientHead(self, damage);
#ifdef CTF
self->client->anim_priority = ANIM_DEATH;
self->client->anim_end = 0;
#endif
self->takedamage = DAMAGE_NO;
}
else
@ -822,6 +857,13 @@ InitClientPersistant(gclient_t *client)
client->pers.weapon = item;
#ifdef CTF
client->pers.lastweapon = item;
item = FindItem("Grapple");
client->pers.inventory[ITEM_INDEX(item)] = 1;
#endif
client->pers.health = 100;
client->pers.max_health = 100;
@ -843,9 +885,27 @@ InitClientResp(gclient_t *client)
return;
}
#ifdef CTF
int ctf_team = client->resp.ctf_team;
qboolean id_state = client->resp.id_state;
#endif
memset(&client->resp, 0, sizeof(client->resp));
#ifdef CTF
client->resp.ctf_team = ctf_team;
client->resp.id_state = id_state;
#endif
client->resp.enterframe = level.framenum;
client->resp.coop_respawn = client->pers;
#ifdef CTF
if (ctf->value && client->resp.ctf_team < CTF_TEAM1)
{
CTFAssignTeam(client);
}
#endif
}
/*
@ -1139,7 +1199,18 @@ SelectSpawnPoint(edict_t *ent, vec3_t origin, vec3_t angles)
if (deathmatch->value)
{
#ifdef CTF
if (ctf->value)
{
spot = SelectCTFSpawnPoint(ent);
}
else
{
spot = SelectDeathmatchSpawnPoint ();
}
#else
spot = SelectDeathmatchSpawnPoint();
#endif
}
else if (coop->value)
{
@ -1523,6 +1594,10 @@ PutClientInServer(edict_t *ent)
client->ps.pmove.origin[1] = spawn_origin[1] * 8;
client->ps.pmove.origin[2] = spawn_origin[2] * 8;
#ifdef CTF
client->ps.pmove.pm_flags &= ~PMF_NO_PREDICTION;
#endif
if (deathmatch->value && ((int)dmflags->value & DF_FIXED_FOV))
{
client->ps.fov = 90;
@ -1589,6 +1664,13 @@ PutClientInServer(edict_t *ent)
client->resp.spectator = false;
}
#ifdef CTF
if (CTFStartClient(ent))
{
return;
}
#endif
if (!KillBox(ent))
{
/* could't spawn in? */
@ -1755,8 +1837,23 @@ ClientUserinfoChanged(edict_t *ent, char *userinfo)
playernum = ent - g_edicts - 1;
/* combine name and skin into a configstring */
#ifdef CTF
if (ctf->value)
{
CTFAssignSkin(ent, s);
}
else
{
gi.configstring (CS_PLAYERSKINS+playernum,
va("%s\\%s", ent->client->pers.netname, s) );
}
/* set player name field (used in id_state view) */
gi.configstring (CS_GENERAL+playernum, ent->client->pers.netname);
#else
gi.configstring(CS_PLAYERSKINS + playernum,
va("%s\\%s", ent->client->pers.netname, s));
#endif
/* fov */
if (deathmatch->value && ((int)dmflags->value & DF_FIXED_FOV))
@ -1870,6 +1967,12 @@ ClientConnect(edict_t *ent, char *userinfo)
if (ent->inuse == false)
{
/* clear the respawning variables */
#ifdef CTF
/* Force team join */
ent->client->resp.ctf_team = -1;
ent->client->resp.id_state = true;
#endif
InitClientResp(ent->client);
if (!game.autosaved || !ent->client->pers.weapon)
@ -1911,6 +2014,11 @@ ClientDisconnect(edict_t *ent)
gi.bprintf(PRINT_HIGH, "%s disconnected\n", ent->client->pers.netname);
#ifdef CTF
CTFDeadDropFlag(ent);
CTFDeadDropTech(ent);
#endif
/* send effect */
gi.WriteByte(svc_muzzleflash);
gi.WriteShort(ent - g_edicts);
@ -2117,6 +2225,13 @@ ClientThink(edict_t *ent, usercmd_t *ucmd)
VectorCopy(pm.viewangles, client->ps.viewangles);
}
#ifdef CTF
if (client->ctf_grapple)
{
CTFGrapplePull(client->ctf_grapple);
}
#endif
gi.linkentity(ent);
if (ent->movetype != MOVETYPE_NOCLIP)
@ -2160,7 +2275,11 @@ ClientThink(edict_t *ent, usercmd_t *ucmd)
ent->light_level = ucmd->lightlevel;
/* fire weapon from final position if needed */
if (client->latched_buttons & BUTTON_ATTACK)
if (client->latched_buttons & BUTTON_ATTACK
#ifdef CTF
&& ent->movetype != MOVETYPE_NOCLIP
#endif
)
{
if (client->resp.spectator)
{
@ -2183,6 +2302,29 @@ ClientThink(edict_t *ent, usercmd_t *ucmd)
}
}
#ifdef CTF
/* Regen tech */
CTFApplyRegeneration(ent);
for (i = 1; i <= maxclients->value; i++)
{
other = g_edicts + i;
if (other->inuse && other->client->chase_target == ent)
{
UpdateChaseCam(other);
}
}
if (client->menudirty && client->menutime <= level.time)
{
PMenu_Do_Update(ent);
gi.unicast (ent, true);
client->menutime = level.time;
client->menudirty = false;
}
#endif
if (client->resp.spectator)
{
if (ucmd->upmove >= 10)
@ -2251,7 +2393,11 @@ ClientBeginServerFrame(edict_t *ent)
}
/* run weapon animations if it hasn't been done by a ucmd_t */
if (!client->weapon_thunk && !client->resp.spectator)
if (!client->weapon_thunk && !client->resp.spectator
#ifdef CTF
&& ent->movetype != MOVETYPE_NOCLIP
#endif
)
{
Think_Weapon(ent);
}

View File

@ -90,6 +90,13 @@ BeginIntermission(edict_t *targ)
return; /* already activated */
}
#ifdef CTF
if (deathmatch->value && ctf->value)
{
CTFCalcScores();
}
#endif
game.autosaved = false;
/* respawn any dead clients */
@ -213,6 +220,14 @@ DeathmatchScoreboardMessage(edict_t *ent, edict_t *killer)
return;
}
#ifdef CTF
if (ctf->value)
{
CTFScoreboardMessage (ent, killer);
return;
}
#endif
/* sort the clients by score */
total = 0;
@ -346,6 +361,13 @@ Cmd_Score_f(edict_t *ent)
ent->client->showinventory = false;
ent->client->showhelp = false;
#ifdef CTF
if (ent->client->menu)
{
PMenu_Close(ent);
}
#endif
if (!deathmatch->value && !coop->value)
{
return;
@ -698,5 +720,9 @@ G_SetSpectatorStats(edict_t *ent)
{
cl->ps.stats[STAT_CHASE] = 0;
}
#ifdef CTF
SetCTFStats(ent);
#endif
}

View File

@ -670,6 +670,16 @@ P_FallingDamage(edict_t *ent)
delta = delta * delta * 0.0001;
#ifdef CTF
/* never take damage if just release grapple or on grapple */
if (level.time - ent->client->ctf_grapplereleasetime <= FRAMETIME * 2 ||
(ent->client->ctf_grapple &&
ent->client->ctf_grapplestate > CTF_GRAPPLE_STATE_FLY))
{
return;
}
#endif
/* never take falling damage if completely underwater */
if (ent->waterlevel == 3)
{
@ -985,6 +995,10 @@ G_SetClientEffects(edict_t *ent)
}
}
#ifdef CTF
CTFEffects(ent);
#endif
if (ent->client->quad_framenum > level.framenum)
{
remaining = ent->client->quad_framenum - level.framenum;
@ -1185,6 +1199,23 @@ newanim:
if (!ent->groundentity)
{
#ifdef CTF
if (client->ctf_grapple)
{
ent->s.frame = FRAME_stand01;
client->anim_end = FRAME_stand40;
}
else
{
client->anim_priority = ANIM_JUMP;
if (ent->s.frame != FRAME_jump2)
{
ent->s.frame = FRAME_jump1;
}
client->anim_end = FRAME_jump2;
}
#else
client->anim_priority = ANIM_JUMP;
if (ent->s.frame != FRAME_jump2)
@ -1193,6 +1224,7 @@ newanim:
}
client->anim_end = FRAME_jump2;
#endif
}
else if (run)
{
@ -1338,6 +1370,28 @@ ClientEndServerFrame(edict_t *ent)
can be accurately determined */
SV_CalcBlend(ent);
#ifdef CTF
if (!ent->client->chase_target)
{
G_SetStats (ent);
}
/* update chasecam follower stats */
for (i = 1; i <= maxclients->value; i++)
{
edict_t *e = g_edicts + i;
if (!e->inuse || e->client->chase_target != ent)
{
continue;
}
memcpy(e->client->ps.stats, ent->client->ps.stats,
sizeof(ent->client->ps.stats));
e->client->ps.stats[STAT_LAYOUTS] = 1;
break;
}
#else
/* chase cam stuff */
if (ent->client->resp.spectator)
{
@ -1350,6 +1404,8 @@ ClientEndServerFrame(edict_t *ent)
G_CheckChaseStats(ent);
#endif
G_SetClientEvent(ent);
G_SetClientEffects(ent);
@ -1368,7 +1424,20 @@ ClientEndServerFrame(edict_t *ent)
/* if the scoreboard is up, update it */
if (ent->client->showscores && !(level.framenum & 31))
{
#ifdef CTF
if (ent->client->menu)
{
PMenu_Do_Update(ent);
ent->client->menudirty = false;
ent->client->menutime = level.time;
}
else
{
DeathmatchScoreboardMessage (ent, ent->enemy);
}
#else
DeathmatchScoreboardMessage(ent, ent->enemy);
#endif
gi.unicast(ent, false);
}
}

View File

@ -451,10 +451,17 @@ Drop_Weapon(edict_t *ent, gitem_t *item)
* A generic function to handle
* the basics of weapon thinking
*/
#ifdef CTF
void
Weapon_Generic2(edict_t *ent, int FRAME_ACTIVATE_LAST, int FRAME_FIRE_LAST,
int FRAME_IDLE_LAST, int FRAME_DEACTIVATE_LAST, int *pause_frames,
int *fire_frames, void (*fire)(edict_t *ent))
#else
void
Weapon_Generic(edict_t *ent, int FRAME_ACTIVATE_LAST, int FRAME_FIRE_LAST,
int FRAME_IDLE_LAST, int FRAME_DEACTIVATE_LAST, int *pause_frames,
int *fire_frames, void (*fire)(edict_t *ent))
#endif
{
int n;
@ -605,11 +612,23 @@ Weapon_Generic(edict_t *ent, int FRAME_ACTIVATE_LAST, int FRAME_FIRE_LAST,
{
if (ent->client->ps.gunframe == fire_frames[n])
{
#ifdef CTF
if (!CTFApplyStrengthSound(ent))
{
if (ent->client->quad_framenum > level.framenum)
{
gi.sound(ent, CHAN_ITEM, gi.soundindex("items/damage3.wav"), 1, ATTN_NORM, 0);
}
}
CTFApplyHasteSound(ent);
#else
if (ent->client->quad_framenum > level.framenum)
{
gi.sound(ent, CHAN_ITEM, gi.soundindex(
"items/damage3.wav"), 1, ATTN_NORM, 0);
}
#endif
fire(ent);
break;
@ -628,6 +647,39 @@ Weapon_Generic(edict_t *ent, int FRAME_ACTIVATE_LAST, int FRAME_FIRE_LAST,
}
}
#ifdef CTF
void Weapon_Generic (edict_t *ent, int FRAME_ACTIVATE_LAST, int FRAME_FIRE_LAST,
int FRAME_IDLE_LAST, int FRAME_DEACTIVATE_LAST, int *pause_frames,
int *fire_frames, void (*fire)(edict_t *ent))
{
int oldstate = ent->client->weaponstate;
if (!ent || !fire_frames || !fire)
{
return;
}
Weapon_Generic2 (ent, FRAME_ACTIVATE_LAST, FRAME_FIRE_LAST,
FRAME_IDLE_LAST, FRAME_DEACTIVATE_LAST, pause_frames,
fire_frames, fire);
/* run the weapon frame again if hasted */
if (Q_stricmp(ent->client->pers.weapon->pickup_name, "Grapple") == 0 &&
ent->client->weaponstate == WEAPON_FIRING)
return;
if ((CTFApplyHaste(ent) ||
(Q_stricmp(ent->client->pers.weapon->pickup_name, "Grapple") == 0 &&
ent->client->weaponstate != WEAPON_FIRING))
&& oldstate == ent->client->weaponstate)
{
Weapon_Generic2 (ent, FRAME_ACTIVATE_LAST, FRAME_FIRE_LAST,
FRAME_IDLE_LAST, FRAME_DEACTIVATE_LAST, pause_frames,
fire_frames, fire);
}
}
#endif
/* ====================================================================== */
/* GRENADE */

View File

@ -215,10 +215,30 @@ InitGame(void)
skill = gi.cvar("skill", "1", CVAR_LATCH);
maxentities = gi.cvar("maxentities", "1024", CVAR_LATCH);
#ifdef CTF
/* This game.so only supports deathmatch */
if (!deathmatch->value)
{
gi.dprintf("Forcing deathmatch.\n");
gi.cvar_set("deathmatch", "1");
}
if (coop->value)
{
gi.cvar_set("coop", "0");
}
#endif
/* change anytime vars */
dmflags = gi.cvar("dmflags", "0", CVAR_SERVERINFO);
fraglimit = gi.cvar("fraglimit", "0", CVAR_SERVERINFO);
timelimit = gi.cvar("timelimit", "0", CVAR_SERVERINFO);
#ifdef CTF
capturelimit = gi.cvar ("capturelimit", "0", CVAR_SERVERINFO);
instantweap = gi.cvar ("instantweap", "0", CVAR_SERVERINFO);
#endif
password = gi.cvar("password", "", CVAR_USERINFO);
spectator_password = gi.cvar("spectator_password", "", CVAR_USERINFO);
needpass = gi.cvar("needpass", "0", CVAR_SERVERINFO);
@ -254,6 +274,10 @@ InitGame(void)
game.maxclients = maxclients->value;
game.clients = gi.TagMalloc(game.maxclients * sizeof(game.clients[0]), TAG_GAME);
globals.num_edicts = game.maxclients + 1;
#ifdef CTF
CTFInit();
#endif
}
/* ========================================================= */