game: Add g_ctf to game

This commit is contained in:
Denis Pauk 2023-10-24 17:07:43 +03:00
parent fb5216ffcf
commit 675ce35e75
9 changed files with 264 additions and 220 deletions

View file

@ -853,6 +853,7 @@ GAME_OBJS_ = \
src/game/g_ai.o \ src/game/g_ai.o \
src/game/g_chase.o \ src/game/g_chase.o \
src/game/g_cmds.o \ src/game/g_cmds.o \
src/game/g_ctf.o \
src/game/g_combat.o \ src/game/g_combat.o \
src/game/g_func.o \ src/game/g_func.o \
src/game/g_items.o \ src/game/g_items.o \
@ -876,6 +877,7 @@ GAME_OBJS_ = \
src/game/g_weapon.o \ src/game/g_weapon.o \
src/game/dm/ball.o \ src/game/dm/ball.o \
src/game/dm/tag.o \ src/game/dm/tag.o \
src/game/menu/menu.o \
src/game/monster/berserker/berserker.o \ src/game/monster/berserker/berserker.o \
src/game/monster/boss2/boss2.o \ src/game/monster/boss2/boss2.o \
src/game/monster/boss3/boss3.o \ src/game/monster/boss3/boss3.o \
@ -1466,11 +1468,12 @@ CTF_OBJS_ = \
src/common/shared/rand.o \ src/common/shared/rand.o \
src/common/shared/shared.o \ src/common/shared/shared.o \
src/game/g_newai.o \ src/game/g_newai.o \
src/game/g_newtrig.o \
src/ctf/g_ai.o \ src/ctf/g_ai.o \
src/ctf/g_chase.o \ src/ctf/g_chase.o \
src/ctf/g_cmds.o \ src/ctf/g_cmds.o \
src/ctf/g_combat.o \ src/ctf/g_combat.o \
src/ctf/g_ctf.o \ src/game/g_ctf.o \
src/ctf/g_func.o \ src/ctf/g_func.o \
src/ctf/g_items.o \ src/ctf/g_items.o \
src/ctf/g_main.o \ src/ctf/g_main.o \
@ -1484,7 +1487,7 @@ CTF_OBJS_ = \
src/ctf/g_trigger.o \ src/ctf/g_trigger.o \
src/ctf/g_utils.o \ src/ctf/g_utils.o \
src/ctf/g_weapon.o \ src/ctf/g_weapon.o \
src/ctf/menu/menu.o \ src/game/menu/menu.o \
src/game/monster/misc/move.o \ src/game/monster/misc/move.o \
src/ctf/player/client.o \ src/ctf/player/client.o \
src/ctf/player/hud.o \ src/ctf/player/hud.o \

View file

@ -498,9 +498,9 @@ Cmd_Notarget_f(edict_t *ent)
return; return;
} }
if (deathmatch->value && !sv_cheats->value) if ((deathmatch->value || coop->value) && !sv_cheats->value)
{ {
gi.cprintf( ent, PRINT_HIGH, gi.cprintf(ent, PRINT_HIGH,
"You must run the server with '+set cheats 1' to enable this command.\n"); "You must run the server with '+set cheats 1' to enable this command.\n");
return; return;
} }
@ -527,9 +527,14 @@ Cmd_Noclip_f(edict_t *ent)
{ {
char *msg; char *msg;
if (deathmatch->value && !sv_cheats->value) if (!ent)
{ {
gi.cprintf( ent, PRINT_HIGH, return;
}
if ((deathmatch->value || coop->value) && !sv_cheats->value)
{
gi.cprintf(ent, PRINT_HIGH,
"You must run the server with '+set cheats 1' to enable this command.\n"); "You must run the server with '+set cheats 1' to enable this command.\n");
return; return;
} }
@ -558,6 +563,11 @@ Cmd_Use_f(edict_t *ent)
gitem_t *it; gitem_t *it;
char *s; char *s;
if (!ent)
{
return;
}
s = gi.args(); s = gi.args();
it = FindItem(s); it = FindItem(s);
@ -594,6 +604,11 @@ Cmd_Drop_f(edict_t *ent)
gitem_t *it; gitem_t *it;
char *s; char *s;
if (!ent)
{
return;
}
if ((Q_stricmp(gi.args(), "tech") == 0) && ((it = CTFWhat_Tech(ent)) != NULL)) if ((Q_stricmp(gi.args(), "tech") == 0) && ((it = CTFWhat_Tech(ent)) != NULL))
{ {
it->drop(ent, it); it->drop(ent, it);
@ -626,12 +641,81 @@ Cmd_Drop_f(edict_t *ent)
it->drop(ent, it); it->drop(ent, it);
} }
/*
* Display the scoreboard
*/
void
Cmd_Score_f(edict_t *ent)
{
if (!ent)
{
return;
}
ent->client->showinventory = false;
ent->client->showhelp = false;
if (ent->client->menu)
{
PMenu_Close(ent);
}
if (!deathmatch->value && !coop->value)
{
return;
}
if (ent->client->showscores)
{
ent->client->showscores = false;
ent->client->update_chase = true;
return;
}
ent->client->showscores = true;
DeathmatchScoreboardMessage(ent, ent->enemy);
gi.unicast(ent, true);
}
/*
* Display the current help message
*/
void
Cmd_Help_f(edict_t *ent)
{
/* this is for backwards compatability */
if (deathmatch->value)
{
Cmd_Score_f(ent);
return;
}
ent->client->showinventory = false;
ent->client->showscores = false;
if (ent->client->showhelp &&
(ent->client->resp.game_helpchanged == game.helpchanged))
{
ent->client->showhelp = false;
return;
}
ent->client->showhelp = true;
ent->client->resp.helpchanged = 0;
HelpComputerMessage(ent);
}
void void
Cmd_Inven_f(edict_t *ent) Cmd_Inven_f(edict_t *ent)
{ {
int i; int i;
gclient_t *cl; gclient_t *cl;
if (!ent)
{
return;
}
cl = ent->client; cl = ent->client;
cl->showscores = false; cl->showscores = false;
@ -769,6 +853,11 @@ Cmd_WeapNext_f(edict_t *ent)
gitem_t *it; gitem_t *it;
int selected_weapon; int selected_weapon;
if (!ent)
{
return;
}
cl = ent->client; cl = ent->client;
if (!cl->pers.weapon) if (!cl->pers.weapon)
@ -816,6 +905,11 @@ Cmd_WeapLast_f(edict_t *ent)
int index; int index;
gitem_t *it; gitem_t *it;
if (!ent)
{
return;
}
cl = ent->client; cl = ent->client;
if (!cl->pers.weapon || !cl->pers.lastweapon) if (!cl->pers.weapon || !cl->pers.lastweapon)
@ -850,6 +944,11 @@ Cmd_InvDrop_f(edict_t *ent)
{ {
gitem_t *it; gitem_t *it;
if (!ent)
{
return;
}
ValidateSelectedItem(ent); ValidateSelectedItem(ent);
if (ent->client->pers.selected_item == -1) if (ent->client->pers.selected_item == -1)
@ -908,6 +1007,11 @@ PlayerSort(void const *a, void const *b)
{ {
int anum, bnum; int anum, bnum;
if (!a || !b)
{
return 0;
}
anum = *(int *)a; anum = *(int *)a;
bnum = *(int *)b; bnum = *(int *)b;
@ -936,6 +1040,11 @@ Cmd_Players_f(edict_t *ent)
char large[1280]; char large[1280];
int index[256]; int index[256];
if (!ent)
{
return;
}
count = 0; count = 0;
for (i = 0; i < maxclients->value; i++) for (i = 0; i < maxclients->value; i++)
@ -977,7 +1086,12 @@ Cmd_Wave_f(edict_t *ent)
{ {
int i; int i;
i = atoi(gi.argv(1)); if (!ent)
{
return;
}
i = (int)strtol(gi.argv(1), (char **)NULL, 10);
/* can't wave when ducked */ /* can't wave when ducked */
if (ent->client->ps.pmove.pm_flags & PMF_DUCKED) if (ent->client->ps.pmove.pm_flags & PMF_DUCKED)

View file

@ -1,5 +1,8 @@
/* /*
* Copyright (C) 1997-2001 Id Software, Inc. * Copyright (C) 1997-2001 Id Software, Inc.
* Copyright (C) 2011 Knightmare
* Copyright (C) 2011 Yamagi Burmeister
* Copyright (c) ZeniMax Media Inc.
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -206,8 +209,13 @@ InitGame(void)
/* dm map list */ /* dm map list */
sv_maplist = gi.cvar("sv_maplist", "", 0); sv_maplist = gi.cvar("sv_maplist", "", 0);
/* disruptor availability */
g_disruptor = gi.cvar("g_disruptor", "0", 0);
/* others */ /* others */
aimfix = gi.cvar("aimfix", "0", CVAR_ARCHIVE); aimfix = gi.cvar("aimfix", "0", CVAR_ARCHIVE);
g_machinegun_norecoil = gi.cvar("g_machinegun_norecoil", "0", CVAR_ARCHIVE);
g_swap_speed = gi.cvar("g_swap_speed", "1", 0);
/* items */ /* items */
InitItems(); InitItems();

View file

@ -1,5 +1,6 @@
/* /*
* Copyright (C) 1997-2001 Id Software, Inc. * Copyright (C) 1997-2001 Id Software, Inc.
* Copyright (c) ZeniMax Media Inc.
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -37,6 +38,11 @@
void void
MoveClientToIntermission(edict_t *ent) MoveClientToIntermission(edict_t *ent)
{ {
if (!ent)
{
return;
}
if (deathmatch->value || coop->value) if (deathmatch->value || coop->value)
{ {
ent->client->showscores = true; ent->client->showscores = true;
@ -59,6 +65,15 @@ MoveClientToIntermission(edict_t *ent)
ent->client->enviro_framenum = 0; ent->client->enviro_framenum = 0;
ent->client->grenade_blew_up = false; ent->client->grenade_blew_up = false;
ent->client->grenade_time = 0; ent->client->grenade_time = 0;
ent->client->quadfire_framenum = 0;
ent->client->trap_blew_up = false;
ent->client->trap_time = 0;
ent->client->ir_framenum = 0;
ent->client->nuke_framenum = 0;
ent->client->double_framenum = 0;
ent->client->ps.rdflags &= ~RDF_IRGOGGLES;
ent->viewheight = 0; ent->viewheight = 0;
ent->s.modelindex = 0; ent->s.modelindex = 0;
@ -69,8 +84,9 @@ MoveClientToIntermission(edict_t *ent)
ent->s.sound = 0; ent->s.sound = 0;
ent->solid = SOLID_NOT; ent->solid = SOLID_NOT;
/* add the layout */ gi.linkentity(ent);
/* add the layout */
if (deathmatch->value || coop->value) if (deathmatch->value || coop->value)
{ {
DeathmatchScoreboardMessage(ent, NULL); DeathmatchScoreboardMessage(ent, NULL);
@ -81,8 +97,8 @@ MoveClientToIntermission(edict_t *ent)
void void
BeginIntermission(edict_t *targ) BeginIntermission(edict_t *targ)
{ {
int i, n; int i;
edict_t *ent, *client; edict_t *ent;
if (level.intermissiontime) if (level.intermissiontime)
{ {
@ -99,6 +115,8 @@ BeginIntermission(edict_t *targ)
/* respawn any dead clients */ /* respawn any dead clients */
for (i = 0; i < maxclients->value; i++) for (i = 0; i < maxclients->value; i++)
{ {
edict_t *client;
client = g_edicts + 1 + i; client = g_edicts + 1 + i;
if (!client->inuse) if (!client->inuse)
@ -121,6 +139,9 @@ BeginIntermission(edict_t *targ)
{ {
for (i = 0; i < maxclients->value; i++) for (i = 0; i < maxclients->value; i++)
{ {
int n;
edict_t *client;
client = g_edicts + 1 + i; client = g_edicts + 1 + i;
if (!client->inuse) if (!client->inuse)
@ -166,7 +187,7 @@ BeginIntermission(edict_t *targ)
else else
{ {
/* chose one of four spots */ /* chose one of four spots */
i = rand() & 3; i = randk() & 3;
while (i--) while (i--)
{ {
@ -185,6 +206,8 @@ BeginIntermission(edict_t *targ)
/* move all clients to the intermission point */ /* move all clients to the intermission point */
for (i = 0; i < maxclients->value; i++) for (i = 0; i < maxclients->value; i++)
{ {
edict_t *client;
client = g_edicts + 1 + i; client = g_edicts + 1 + i;
if (!client->inuse) if (!client->inuse)
@ -211,6 +234,12 @@ DeathmatchScoreboardMessage(edict_t *ent, edict_t *killer)
edict_t *cl_ent; edict_t *cl_ent;
char *tag; char *tag;
if (!ent) /* killer can be NULL */
{
return;
}
if (ctf->value) if (ctf->value)
{ {
CTFScoreboardMessage(ent, killer); CTFScoreboardMessage(ent, killer);
@ -299,7 +328,8 @@ DeathmatchScoreboardMessage(edict_t *ent, edict_t *killer)
} }
/* send the layout */ /* send the layout */
Com_sprintf(entry, sizeof(entry), "client %i %i %i %i %i %i ", Com_sprintf(entry, sizeof(entry),
"client %i %i %i %i %i %i ",
x, y, sorted[i], cl->resp.score, cl->ping, x, y, sorted[i], cl->resp.score, cl->ping,
(level.framenum - cl->resp.enterframe) / 600); (level.framenum - cl->resp.enterframe) / 600);
j = strlen(entry); j = strlen(entry);
@ -329,55 +359,29 @@ DeathmatchScoreboard(edict_t *ent)
gi.unicast(ent, true); gi.unicast(ent, true);
} }
/*
* Display the scoreboard
*/
void
Cmd_Score_f(edict_t *ent)
{
ent->client->showinventory = false;
ent->client->showhelp = false;
if (ent->client->menu)
{
PMenu_Close(ent);
}
if (!deathmatch->value && !coop->value)
{
return;
}
if (ent->client->showscores)
{
ent->client->showscores = false;
ent->client->update_chase = true;
return;
}
ent->client->showscores = true;
DeathmatchScoreboard(ent);
}
/* /*
* Draw help computer. * Draw help computer.
*/ */
static void void
HelpComputer(edict_t *ent) HelpComputerMessage(edict_t *ent)
{ {
char string[1024]; char string[1024];
char *sk; char *sk;
if (skill->value == 0) if (!ent)
{
return;
}
if (skill->value == SKILL_EASY)
{ {
sk = "easy"; sk = "easy";
} }
else if (skill->value == 1) else if (skill->value == SKILL_MEDIUM)
{ {
sk = "medium"; sk = "medium";
} }
else if (skill->value == 2) else if (skill->value == SKILL_HARD)
{ {
sk = "hard"; sk = "hard";
} }
@ -412,28 +416,21 @@ HelpComputer(edict_t *ent)
* Display the current help message * Display the current help message
*/ */
void void
Cmd_Help_f(edict_t *ent) InventoryMessage(edict_t *ent)
{ {
/* this is for backwards compatability */ int i;
if (deathmatch->value)
if (!ent)
{ {
Cmd_Score_f(ent);
return; return;
} }
ent->client->showinventory = false; gi.WriteByte(svc_inventory);
ent->client->showscores = false;
if (ent->client->showhelp && for (i = 0; i < MAX_ITEMS; i++)
(ent->client->resp.game_helpchanged == game.helpchanged))
{ {
ent->client->showhelp = false; gi.WriteShort(ent->client->pers.inventory[i]);
return;
} }
ent->client->showhelp = true;
ent->client->resp.helpchanged = 0;
HelpComputer(ent);
} }
/* ======================================================================= */ /* ======================================================================= */
@ -442,13 +439,17 @@ void
G_SetStats(edict_t *ent) G_SetStats(edict_t *ent)
{ {
gitem_t *item; gitem_t *item;
int index, cells; int index, cells = 0;
int power_armor_type; int power_armor_type;
if (!ent)
{
return;
}
/* health */ /* health */
ent->client->ps.stats[STAT_HEALTH_ICON] = level.pic_health; ent->client->ps.stats[STAT_HEALTH_ICON] = level.pic_health;
ent->client->ps.stats[STAT_HEALTH] = ent->health; ent->client->ps.stats[STAT_HEALTH] = (ent->health < -99) ? -99 : ent->health;
/* ammo */ /* ammo */
if (!ent->client->ammo_index) if (!ent->client->ammo_index)

View file

@ -673,6 +673,9 @@ Cmd_Drop_f(edict_t *ent)
it->drop(ent, it); it->drop(ent, it);
} }
/*
* Display the scoreboard
*/
void void
Cmd_Score_f(edict_t *ent) Cmd_Score_f(edict_t *ent)
{ {
@ -684,6 +687,11 @@ Cmd_Score_f(edict_t *ent)
ent->client->showinventory = false; ent->client->showinventory = false;
ent->client->showhelp = false; ent->client->showhelp = false;
if (ent->client->menu)
{
PMenu_Close(ent);
}
if (!deathmatch->value && !coop->value) if (!deathmatch->value && !coop->value)
{ {
return; return;
@ -808,7 +816,7 @@ Cmd_WeapPrev_f(edict_t *ent)
selected_weapon = ITEM_INDEX(cl->pers.weapon); selected_weapon = ITEM_INDEX(cl->pers.weapon);
/* scan for the next valid one */ /* scan for the next valid one */
for (i = 1; i <= MAX_ITEMS; i++) for (i = 1; i <= MAX_ITEMS; i++)
{ {
/* prevent scrolling through ALL weapons */ /* prevent scrolling through ALL weapons */
@ -1147,8 +1155,8 @@ Cmd_Wave_f(edict_t *ent)
} }
} }
static qboolean qboolean
flooded(edict_t *ent) CheckFlood(edict_t *ent)
{ {
gclient_t *cl; gclient_t *cl;
int i; int i;
@ -1233,7 +1241,7 @@ Cmd_Say_f(edict_t *ent, qboolean team, qboolean arg0)
return; return;
} }
if (flooded(ent)) if (CheckFlood(ent))
{ {
return; return;
} }

View file

@ -86,7 +86,7 @@ cvar_t *warp_list;
cvar_t *warn_unbalanced; cvar_t *warn_unbalanced;
/* Index for various CTF pics, this saves us /* Index for various CTF pics, this saves us
* from calling gi.imageindex all the time * from calling gi.imageindex all the time
* and saves a few CPU cycles since we don't * and saves a few CPU cycles since we don't
* have to do a bunch of string compares all * have to do a bunch of string compares all
* the time. * These are set in CTFPrecache() * the time. * These are set in CTFPrecache()
@ -250,7 +250,7 @@ stuffcmd(edict_t *ent, char *s)
/*--------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------*/
/* /*
* Returns entities that have * Returns entities that have
* origins within a spherical area * origins within a spherical area
*/ */
static edict_t * static edict_t *
@ -641,7 +641,7 @@ SelectCTFSpawnPoint(edict_t *ent)
/* /*
* Calculate the bonuses for flag defense, * Calculate the bonuses for flag defense,
* flag carrier defense, etc. Note that b * flag carrier defense, etc. Note that b
* onuses are not cumaltive. You get one, * onuses are not cumaltive. You get one,
* they are in importance order. * they are in importance order.
*/ */
void void
@ -706,7 +706,7 @@ CTFFragBonuses(edict_t *targ, edict_t *inflictor, edict_t *attacker)
CTF_FRAG_CARRIER_BONUS); CTF_FRAG_CARRIER_BONUS);
/* the target had the flag, clear /* the target had the flag, clear
the hurt carrier field on the the hurt carrier field on the
other team */ other team */
for (i = 1; i <= maxclients->value; i++) for (i = 1; i <= maxclients->value; i++)
{ {
@ -726,8 +726,8 @@ CTFFragBonuses(edict_t *targ, edict_t *inflictor, edict_t *attacker)
CTF_CARRIER_DANGER_PROTECT_TIMEOUT) && CTF_CARRIER_DANGER_PROTECT_TIMEOUT) &&
!attacker->client->pers.inventory[ITEM_INDEX(flag_item)]) !attacker->client->pers.inventory[ITEM_INDEX(flag_item)])
{ {
/* attacker is on the same team /* attacker is on the same team
as the flag carrier and as the flag carrier and
fragged a guy who hurt our fragged a guy who hurt our
flag carrier */ flag carrier */
attacker->client->resp.score += CTF_CARRIER_DANGER_PROTECT_BONUS; attacker->client->resp.score += CTF_CARRIER_DANGER_PROTECT_BONUS;
@ -744,8 +744,8 @@ CTFFragBonuses(edict_t *targ, edict_t *inflictor, edict_t *attacker)
return; return;
} }
/* flag and flag carrier area defense bonuses /* flag and flag carrier area defense bonuses
we have to find the flag and carrier entities we have to find the flag and carrier entities
find the flag */ find the flag */
switch (attacker->client->resp.ctf_team) switch (attacker->client->resp.ctf_team)
{ {
@ -941,7 +941,7 @@ CTFPickup_Flag(edict_t *ent, edict_t *other)
return false; return false;
} }
/* same team, if the flag at base, /* same team, if the flag at base,
check to he has the enemy flag */ check to he has the enemy flag */
if (ctf_team == CTF_TEAM1) if (ctf_team == CTF_TEAM1)
{ {
@ -1059,9 +1059,9 @@ CTFPickup_Flag(edict_t *ent, edict_t *other)
other->client->pers.inventory[ITEM_INDEX(flag_item)] = 1; other->client->pers.inventory[ITEM_INDEX(flag_item)] = 1;
other->client->resp.ctf_flagsince = level.time; other->client->resp.ctf_flagsince = level.time;
/* pick up the flag /* pick up the flag
if it's not a dropped flag, if it's not a dropped flag,
we just make is disappear we just make is disappear
if it's dropped, it will be if it's dropped, it will be
removed by the pickup caller */ removed by the pickup caller */
if (!(ent->spawnflags & DROPPED_ITEM)) if (!(ent->spawnflags & DROPPED_ITEM))
@ -1091,8 +1091,8 @@ CTFDropFlagTouch(edict_t *ent, edict_t *other,
static void static void
CTFDropFlagThink(edict_t *ent) CTFDropFlagThink(edict_t *ent)
{ {
/* auto return the flag /* auto return the flag
reset flag will remove reset flag will remove
ourselves */ ourselves */
if (strcmp(ent->classname, "item_flag_team1") == 0) if (strcmp(ent->classname, "item_flag_team1") == 0)
{ {
@ -1108,7 +1108,7 @@ CTFDropFlagThink(edict_t *ent)
} }
} }
/* /*
* Called from PlayerDie, to drop * Called from PlayerDie, to drop
* the flag from a dying player * the flag from a dying player
*/ */
@ -1242,8 +1242,8 @@ CTFEffects(edict_t *player)
} }
} }
/* /*
* Called when we enter the intermission * Called when we enter the intermission
*/ */
void void
CTFCalcScores(void) CTFCalcScores(void)
@ -1407,7 +1407,7 @@ SetCTFStats(edict_t *ent)
/* if during intermission, we must blink /* if during intermission, we must blink
the team header of the winning team */ the team header of the winning team */
if (level.intermissiontime && (level.framenum & 8)) /* blink 1/8th second */ if (level.intermissiontime && (level.framenum & 8)) /* blink 1/8th second */
{ {
/* note that ctfgame.total[12] is /* note that ctfgame.total[12] is
set when we go to intermission */ set when we go to intermission */
if (ctfgame.team1 > ctfgame.team2) if (ctfgame.team1 > ctfgame.team2)
@ -1450,9 +1450,9 @@ SetCTFStats(edict_t *ent)
} }
/* figure out what icon to display for team logos /* figure out what icon to display for team logos
three states: three states:
flag at base flag at base
flag taken flag taken
flag dropped */ flag dropped */
p1 = imageindex_i_ctf1; p1 = imageindex_i_ctf1;
e = G_Find(NULL, FOFS(classname), "item_flag_team1"); e = G_Find(NULL, FOFS(classname), "item_flag_team1");
@ -1463,7 +1463,7 @@ SetCTFStats(edict_t *ent)
{ {
int i; int i;
/* not at base /* not at base
check if on player */ check if on player */
p1 = imageindex_i_ctf1d; /* default to dropped */ p1 = imageindex_i_ctf1d; /* default to dropped */
@ -1493,7 +1493,7 @@ SetCTFStats(edict_t *ent)
{ {
int i; int i;
/* not at base /* not at base
check if on player */ check if on player */
p2 = imageindex_i_ctf2d; /* default to dropped */ p2 = imageindex_i_ctf2d; /* default to dropped */
@ -1707,8 +1707,8 @@ CTFGrappleTouch(edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf
gi.multicast(self->s.origin, MULTICAST_PVS); gi.multicast(self->s.origin, MULTICAST_PVS);
} }
/* /*
* Draw beam between grapple and self * Draw beam between grapple and self
*/ */
void void
CTFGrappleDrawCable(edict_t *self) CTFGrappleDrawCable(edict_t *self)
@ -1746,8 +1746,8 @@ CTFGrappleDrawCable(edict_t *self)
void SV_AddGravity(edict_t *ent); void SV_AddGravity(edict_t *ent);
/* /*
* pull the player toward the grapple * pull the player toward the grapple
*/ */
void void
CTFGrapplePull(edict_t *self) CTFGrapplePull(edict_t *self)
@ -1812,10 +1812,10 @@ CTFGrapplePull(edict_t *self)
if (self->owner->client->ctf_grapplestate > CTF_GRAPPLE_STATE_FLY) if (self->owner->client->ctf_grapplestate > CTF_GRAPPLE_STATE_FLY)
{ {
/* pull player toward grapple /* pull player toward grapple
this causes icky stuff with prediction, we need to extend/ this causes icky stuff with prediction, we need to extend/
the prediction layer to include two new fields in the player/ the prediction layer to include two new fields in the player/
move stuff: a point and a velocity. The client should add move stuff: a point and a velocity. The client should add
that velociy in the direction of the point */ that velociy in the direction of the point */
vec3_t forward, up; vec3_t forward, up;
@ -2041,7 +2041,7 @@ CTFTeam_f(edict_t *ent)
/* add a teleportation effect */ /* add a teleportation effect */
ent->s.event = EV_PLAYER_TELEPORT; ent->s.event = EV_PLAYER_TELEPORT;
/* hold in place briefly */ /* hold in place briefly */
ent->client->ps.pmove.pm_flags = PMF_TIME_TELEPORT; ent->client->ps.pmove.pm_flags = PMF_TIME_TELEPORT;
ent->client->ps.pmove.pm_time = 14; ent->client->ps.pmove.pm_time = 14;
@ -2128,7 +2128,7 @@ CTFScoreboardMessage(edict_t *ent, edict_t *killer)
total[team]++; total[team]++;
} }
/* print level name and exit rules /* print level name and exit rules
add the clients in sorted order */ add the clients in sorted order */
*string = 0; *string = 0;
len = 0; len = 0;
@ -2483,8 +2483,8 @@ SpawnTechs(edict_t *ent)
} }
} }
/* /*
* frees the passed edict! * frees the passed edict!
*/ */
void void
CTFRespawnTech(edict_t *ent) CTFRespawnTech(edict_t *ent)
@ -2764,10 +2764,10 @@ CTFHasRegeneration(edict_t *ent)
* ====================================================================== * ======================================================================
*/ */
/* /*
* This array is in 'importance order', * This array is in 'importance order',
* it indicates what items are more * it indicates what items are more
* important when reporting their names. * important when reporting their names.
*/ */
struct struct
{ {
@ -2876,7 +2876,7 @@ CTFSay_Team_Location(edict_t *who, char *buf)
} }
/* we now have the closest item /* we now have the closest item
see if there's more than one see if there's more than one
in the map, if so we need to in the map, if so we need to
determine what team is closest */ determine what team is closest */
what = NULL; what = NULL;
@ -2888,8 +2888,8 @@ CTFSay_Team_Location(edict_t *who, char *buf)
continue; continue;
} }
/* if we are here, there is more /* if we are here, there is more
than one, find out if hot is than one, find out if hot is
closer to red flag or blue flag */ closer to red flag or blue flag */
if (((flag1 = G_Find(NULL, FOFS(classname), "item_flag_team1")) != NULL) && if (((flag1 = G_Find(NULL, FOFS(classname), "item_flag_team1")) != NULL) &&
((flag2 = G_Find(NULL, FOFS(classname), "item_flag_team2")) != NULL)) ((flag2 = G_Find(NULL, FOFS(classname), "item_flag_team2")) != NULL))
@ -3969,7 +3969,7 @@ CTFJoinTeam(edict_t *ent, int desired_team)
/* add a teleportation effect */ /* add a teleportation effect */
ent->s.event = EV_PLAYER_TELEPORT; ent->s.event = EV_PLAYER_TELEPORT;
/* hold in place briefly */ /* hold in place briefly */
ent->client->ps.pmove.pm_flags = PMF_TIME_TELEPORT; ent->client->ps.pmove.pm_flags = PMF_TIME_TELEPORT;
ent->client->ps.pmove.pm_time = 14; ent->client->ps.pmove.pm_time = 14;
@ -4509,119 +4509,6 @@ CTFCheckRules(void)
return false; 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;
}
CTFPlayerResetGrapple(other);
/* 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);
/* 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;
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;
}
/*----------------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------------*/
/* ADMIN */ /* ADMIN */

View file

@ -27,6 +27,14 @@
#include "../header/local.h" #include "../header/local.h"
/*
* ======================================================================
*
* INTERMISSION
*
* ======================================================================
*/
void void
MoveClientToIntermission(edict_t *ent) MoveClientToIntermission(edict_t *ent)
{ {
@ -357,6 +365,18 @@ DeathmatchScoreboardMessage(edict_t *ent, edict_t *killer)
gi.WriteString(string); gi.WriteString(string);
} }
/*
* Draw instead of help message.
* Note that it isn't that hard to
* overflow the 1400 byte message limit!
*/
void
DeathmatchScoreboard(edict_t *ent)
{
DeathmatchScoreboardMessage(ent, ent->enemy);
gi.unicast(ent, true);
}
/* /*
* Draw help computer. * Draw help computer.
*/ */
@ -407,6 +427,7 @@ HelpComputerMessage(edict_t *ent)
gi.WriteByte(svc_layout); gi.WriteByte(svc_layout);
gi.WriteString(string); gi.WriteString(string);
gi.unicast(ent, true);
} }
/* /*

View file

@ -284,6 +284,8 @@ InitGame(void)
{ {
InitGameRules(); InitGameRules();
} }
CTFInit();
} }
/* ========================================================= */ /* ========================================================= */