454 lines
11 KiB
C
454 lines
11 KiB
C
/*==============================================================================
|
|
The Weapons Factory -
|
|
Team Fortress Style Flag Capture Functions
|
|
Original code by Gregg Reno
|
|
==============================================================================*/
|
|
#include "g_local.h"
|
|
#include "stdlog.h" // StdLog - Mark Davies
|
|
|
|
extern gitem_t *flag1_item;
|
|
extern gitem_t *flag2_item;
|
|
extern ctfgame_t ctfgame;
|
|
|
|
void CTFResetFlags(void);
|
|
void CTFResetFlag(int ctf_team);
|
|
void WFRemoveDisguise(edict_t *ent);
|
|
int PlayerChangeScore(edict_t *self, int points);
|
|
|
|
qboolean WFUnbalanced_Teams(edict_t *flag, edict_t *player)
|
|
{
|
|
int team_limit;
|
|
int flagteamcount = 0, playerteamcount = 0;
|
|
int i;
|
|
int diff;
|
|
edict_t *target;
|
|
int flagteam;
|
|
|
|
team_limit = wf_game.unbalanced_limit;
|
|
|
|
// figure out what team this flag is
|
|
if (strcmp(flag->classname, "item_flag_team1") == 0)
|
|
flagteam = CTF_TEAM1;
|
|
else if (strcmp(flag->classname, "item_flag_team2") == 0)
|
|
flagteam = CTF_TEAM2;
|
|
else
|
|
flagteam = 0;
|
|
|
|
|
|
//Is any limit set?
|
|
if (team_limit <= 0)
|
|
{
|
|
//gi.dprintf("No Limit Set\n");
|
|
return false;
|
|
}
|
|
|
|
//Teams must be set
|
|
if ((flagteam == 0) || (player->wf_team == 0))
|
|
{
|
|
//gi.dprintf("Someone doesn't have their wf_team flag set: %d, %d\n",
|
|
// flagteam, player->wf_team );
|
|
return false;
|
|
}
|
|
|
|
//Must be on different teams
|
|
if (flagteam == player->wf_team == 0)
|
|
|
|
//Count players on each team
|
|
for (i = 1; i <= maxclients->value; i++)
|
|
{
|
|
target = &g_edicts[i];
|
|
|
|
if (!target->inuse)
|
|
continue;
|
|
|
|
if (target->wf_team == flagteam )
|
|
flagteamcount++;
|
|
|
|
if (target->wf_team == player->wf_team)
|
|
playerteamcount++;
|
|
}
|
|
|
|
diff = playerteamcount - flagteamcount;
|
|
//gi.dprintf("Diff=%d, playercount = %d, flagcount = %d, team limit = %d\n",
|
|
// diff, playerteamcount,flagteamcount,team_limit);
|
|
|
|
if (diff >= team_limit)
|
|
{
|
|
safe_cprintf(player, PRINT_HIGH, "Sorry, you can't pick up flag. Teams are not balanced.\n");
|
|
return true;
|
|
}
|
|
else
|
|
return false;
|
|
}
|
|
|
|
qboolean WFPickup_Flag(edict_t *ent, edict_t *other)
|
|
{
|
|
int ctf_team;
|
|
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
|
|
{
|
|
safe_cprintf(other, 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;
|
|
}
|
|
|
|
//Cant create decoy in observer/spectator mode
|
|
if (other->solid == SOLID_NOT)
|
|
{
|
|
safe_cprintf(other, PRINT_HIGH, "Nice try, but observers can't pick up the flag!.\n");
|
|
return false;
|
|
}
|
|
|
|
|
|
if (other->client->resp.ctf_team != CTF_TEAM1 &&
|
|
other->client->resp.ctf_team != CTF_TEAM2)
|
|
{
|
|
safe_cprintf(other, PRINT_HIGH, "I don't know how you did it, but you don't have a team!.\n");
|
|
return false;
|
|
}
|
|
|
|
//Note - you can't pick up your own flag - just the enemy's
|
|
if (ctf_team != other->client->resp.ctf_team)
|
|
{
|
|
|
|
// hey, its not our flag, pick it up
|
|
if (PlayerChangeScore(other,CTF_FLAG_BONUS))
|
|
{
|
|
gi.bprintf(PRINT_HIGH, "%s got the %s flag!\n",
|
|
other->client->pers.netname, CTFTeamName(ctf_team));
|
|
|
|
// Log Flag Pickup - MarkDavies
|
|
sl_LogScore( &gi,
|
|
other->client->pers.netname,
|
|
NULL,
|
|
"F Pickup",
|
|
-1,
|
|
CTF_FLAG_BONUS);
|
|
}
|
|
|
|
if (ctf_team == CTF_TEAM1)
|
|
flag1dropped = 0; //clear the dropped flag flag
|
|
else if (ctf_team == CTF_TEAM2)
|
|
flag2dropped = 0;
|
|
|
|
other->client->pers.inventory[ITEM_INDEX(flag_item)] = 1;
|
|
other->client->resp.ctf_flagsince = level.time;
|
|
|
|
//Remove player disguise
|
|
if (other->disguised) WFRemoveDisguise(other);
|
|
|
|
// 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;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
//Something touched home base
|
|
void Home_Touch (edict_t *ent, edict_t *other, cplane_t *plane, csurface_t *surf)
|
|
{
|
|
int i;
|
|
edict_t *player;
|
|
gitem_t *flag_item, *enemy_flag_item;
|
|
|
|
//Did someone try to put something on top of the base? If so, blow it up!
|
|
if (!strcmp(other->classname, "SentryGun") )
|
|
{
|
|
turret_remove(other->creator);
|
|
}
|
|
if (!strcmp(other->classname, "SentryStand") )
|
|
{
|
|
turret_remove(other->standowner);
|
|
}
|
|
if (!strcmp(other->classname, "depot") )
|
|
{
|
|
if (other->owner) other->owner->supply = NULL;
|
|
//G_FreeEdict(other);
|
|
BecomeExplosion1 (other);
|
|
}
|
|
if (!strcmp(other->classname, "healingdepot") )
|
|
{
|
|
if (other->owner) other->owner->supply = NULL;
|
|
//G_FreeEdict(other);
|
|
BecomeExplosion1 (other);
|
|
}
|
|
|
|
//Did a player touch?
|
|
if (!other->client)
|
|
return;
|
|
|
|
//Home base and player must be on same team
|
|
if (ent->wf_team != other->wf_team)
|
|
return;
|
|
|
|
// same team, if the flag at base, check to see if he has the enemy flag
|
|
if (other->wf_team == CTF_TEAM1)
|
|
{
|
|
flag_item = flag1_item;
|
|
enemy_flag_item = flag2_item;
|
|
}
|
|
else
|
|
{
|
|
flag_item = flag2_item;
|
|
enemy_flag_item = flag1_item;
|
|
}
|
|
|
|
//Does the player have the enemy flag?
|
|
if (other->client->pers.inventory[ITEM_INDEX(enemy_flag_item)])
|
|
{
|
|
//Yes - TOUCHDOWN!
|
|
other->client->pers.inventory[ITEM_INDEX(enemy_flag_item)] = 0;
|
|
|
|
ctfgame.last_flag_capture = level.time;
|
|
ctfgame.last_capture_team = other->wf_team;
|
|
if (other->wf_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
|
|
if (PlayerChangeScore(other,CTF_CAPTURE_BONUS))
|
|
{
|
|
gi.bprintf(PRINT_HIGH, "%s captured the %s flag!\n",
|
|
other->client->pers.netname, CTFOtherTeamName(other->wf_team));
|
|
|
|
// Log Flag Capture - MarkDavies
|
|
sl_LogScore( &gi,
|
|
other->client->pers.netname,
|
|
NULL,
|
|
"F Capture",
|
|
-1,
|
|
CTF_CAPTURE_BONUS);
|
|
}
|
|
//execute the trigger if it exists
|
|
if (ent->orig_map_entity)
|
|
{
|
|
G_UseTargets (ent->orig_map_entity, other);
|
|
//if (wfdebug) gi.dprintf("Using Target %s\n", ent->orig_map_entity->target);
|
|
}
|
|
else
|
|
{
|
|
//if (wfdebug) gi.dprintf("No Target\n");
|
|
}
|
|
|
|
// 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)
|
|
continue;
|
|
if (!other->client)
|
|
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)
|
|
{
|
|
if (PlayerChangeScore(player,CTF_TEAM_BONUS))
|
|
{
|
|
// Log Flag Capture Team Score - MarkDavies
|
|
sl_LogScore( &gi,
|
|
player->client->pers.netname,
|
|
NULL,
|
|
"Team Score",
|
|
-1,
|
|
CTF_TEAM_BONUS);
|
|
}
|
|
}
|
|
// award extra points for capture assists
|
|
if (player->client->resp.ctf_lastreturnedflag + CTF_RETURN_FLAG_ASSIST_TIMEOUT > level.time)
|
|
{
|
|
if (PlayerChangeScore(player,CTF_RETURN_FLAG_ASSIST_BONUS))
|
|
{
|
|
gi.bprintf(PRINT_HIGH, "%s gets an assist for returning the flag!\n", player->client->pers.netname);
|
|
|
|
// Log Flag Capture Team Score - MarkDavies
|
|
sl_LogScore( &gi,
|
|
player->client->pers.netname,
|
|
NULL,
|
|
"F Return Assist",
|
|
-1,
|
|
CTF_RETURN_FLAG_ASSIST_BONUS);
|
|
}
|
|
|
|
}
|
|
if (player->client->resp.ctf_lastfraggedcarrier + CTF_FRAG_CARRIER_ASSIST_TIMEOUT > level.time)
|
|
{
|
|
if (PlayerChangeScore(player,CTF_FRAG_CARRIER_ASSIST_BONUS))
|
|
{
|
|
|
|
gi.bprintf(PRINT_HIGH, "%s gets an assist for fragging the flag carrier!\n", player->client->pers.netname);
|
|
// Log Flag Capture Frag Assist Score - MarkDavies
|
|
sl_LogScore( &gi,
|
|
player->client->pers.netname,
|
|
NULL,
|
|
"FC Frag Assist",
|
|
-1,
|
|
CTF_FRAG_CARRIER_ASSIST_BONUS);
|
|
}
|
|
|
|
}
|
|
}
|
|
}
|
|
if (ent->wf_team == CTF_TEAM1)
|
|
CTFResetFlag(CTF_TEAM2);
|
|
else
|
|
CTFResetFlag(CTF_TEAM1);
|
|
}
|
|
}
|
|
|
|
void Home_Think (edict_t *ent)
|
|
{
|
|
//For some reason, entity needs a think function
|
|
ent->nextthink = level.time + 5.0;
|
|
}
|
|
|
|
|
|
void Create_Home_Base(edict_t *flag, int team)
|
|
{
|
|
edict_t *home;
|
|
|
|
home = G_Spawn ();
|
|
|
|
home->wf_team = team;
|
|
|
|
//gi.dprintf("--Create Home: %s. Target = %s, ent = %d\n", flag->classname, flag->target, flag);
|
|
|
|
//Save a pointer to the flag/home base entity so the
|
|
//triggers will work
|
|
if ((flag->target) && (flag->target[0] != 0))
|
|
home->orig_map_entity = flag;
|
|
|
|
VectorCopy(flag->s.origin, home->s.origin);
|
|
home->s.origin[2] += 40;
|
|
//home->classname="depot";
|
|
home->takedamage=DAMAGE_NO;
|
|
home->movetype= MOVETYPE_TOSS;
|
|
home->mass = 200;
|
|
home->solid = SOLID_BBOX;
|
|
home->clipmask=MASK_ALL;
|
|
home->deadflag =DEAD_NO;
|
|
home->clipmask = MASK_SHOT;
|
|
home->model = flag->model;
|
|
home->s.modelindex = gi.modelindex ("models/objects/flagbase/tris.md2");
|
|
|
|
if (team == CTF_TEAM1)
|
|
{
|
|
home->classname="home_team1";
|
|
home->s.skinnum = 0;
|
|
}
|
|
else
|
|
{
|
|
home->classname="home_team2";
|
|
home->s.skinnum = 1;
|
|
}
|
|
|
|
home->solid = SOLID_BBOX;
|
|
|
|
VectorSet (home->mins, -20, -20, -15);
|
|
VectorSet (home->maxs, 20, 20, -13);
|
|
home->s.frame =0;
|
|
home->waterlevel = 0;
|
|
home->watertype=0;
|
|
home->health= 100;
|
|
home->max_health =100;
|
|
home->gib_health = -80;
|
|
// home->die = supplydepot_die;
|
|
home->owner = flag;
|
|
home->dmg = 100;
|
|
home->dmg_radius = 100;
|
|
// home->touch = SupplyTouch;
|
|
// home->think =SupplyThink;
|
|
home->touch = Home_Touch;
|
|
home->think = Home_Think;
|
|
home->nextthink = level.time + 1.0;
|
|
VectorClear (home->velocity);
|
|
gi.linkentity (home);
|
|
|
|
// gi.dprintf("FLAG CREATED.\n");
|
|
}
|
|
|
|
|
|
void Create_All_Home_Bases (void)
|
|
{
|
|
edict_t *spot;
|
|
|
|
spot = NULL;
|
|
|
|
//Team 1 home base
|
|
|
|
//First try home base (flag return) position
|
|
spot = G_Find (spot, FOFS(classname), "item_flagreturn_team1");
|
|
|
|
//Next try flag spot
|
|
if (!spot) spot = G_Find (spot, FOFS(classname), "item_flag_team1");
|
|
|
|
if (!spot)
|
|
{
|
|
gi.dprintf("WARNING - Could not place flag return entity for team 1!\n");
|
|
}
|
|
else
|
|
{
|
|
Create_Home_Base(spot, CTF_TEAM1);
|
|
}
|
|
|
|
|
|
//Team 2 home base
|
|
|
|
//First try home base (flag return) position
|
|
spot = NULL;
|
|
spot = G_Find (spot, FOFS(classname), "item_flagreturn_team2");
|
|
|
|
//Next try flag spot
|
|
if (!spot) spot = G_Find (spot, FOFS(classname), "item_flag_team2");
|
|
|
|
if (!spot)
|
|
{
|
|
gi.dprintf("WARNING - Could not place flag return entity for team 2!\n");
|
|
}
|
|
else
|
|
{
|
|
if (strcmp(spot->classname, "item_flagreturn_team2") == 0)//4/99
|
|
spot->s.skinnum = 1;//3/99 small fix for g_items.c/bot
|
|
|
|
Create_Home_Base(spot, CTF_TEAM2);
|
|
}
|
|
|
|
|
|
}
|