📄 g_ctf.c
字号:
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;
if (targ->client && attacker->client) {
if (attacker->client->resp.ghost)
if (attacker != targ)
attacker->client->resp.ghost->kills++;
if (targ->client->resp.ghost)
targ->client->resp.ghost->deaths++;
}
// 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;
gi.cprintf(attacker, PRINT_MEDIUM, "BONUS: %d points for fragging enemy flag carrier.\n",
CTF_FRAG_CARRIER_BONUS);
// 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));
if (attacker->client->resp.ghost)
attacker->client->resp.ghost->carrierdef++;
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
// 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)) &&
attacker->client->resp.ctf_team != targ->client->resp.ctf_team) {
// 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));
if (attacker->client->resp.ghost)
attacker->client->resp.ghost->basedef++;
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));
if (attacker->client->resp.ghost)
attacker->client->resp.ghost->carrierdef++;
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;
// 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 {
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;
if (other->client->resp.ghost)
other->client->resp.ghost->caps++;
// 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 (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)
gi.cprintf(ent, PRINT_HIGH, "Only lusers drop flags.\n");
else
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 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
gi.setmodel (ent, ent->item->world_model);
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;
}
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->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
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)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -