as released 1998-11-29
This commit is contained in:
commit
e3ace8e28d
95 changed files with 72059 additions and 0 deletions
298
Makefile
Normal file
298
Makefile
Normal file
|
@ -0,0 +1,298 @@
|
|||
|
||||
BUILD_DEBUG_DIR=debug
|
||||
BUILD_RELEASE_DIR=release
|
||||
|
||||
CC=gcc
|
||||
BASE_CFLAGS=-Dstricmp=strcasecmp
|
||||
RELEASE_CFLAGS=$(BASE_CFLAGS) -ffast-math -funroll-loops \
|
||||
-fomit-frame-pointer -fexpensive-optimizations
|
||||
DEBUG_CFLAGS=$(BASE_CFLAGS) -g
|
||||
LDFLAGS=-ldl -lm
|
||||
|
||||
SHLIBEXT=so
|
||||
|
||||
SHLIBCFLAGS=-fPIC
|
||||
SHLIBLDFLAGS=-shared
|
||||
|
||||
DO_CC=$(CC) $(CFLAGS) -o $@ -c $<
|
||||
DO_SHLIB_CC=$(CC) $(CFLAGS) $(SHLIBCFLAGS) -o $@ -c $<
|
||||
|
||||
TARGETS=$(BUILDDIR)/game$(ARCH).$(SHLIBEXT) \
|
||||
|
||||
build_debug:
|
||||
@-mkdir $(BUILD_DEBUG_DIR)
|
||||
$(MAKE) targets BUILDDIR=$(BUILD_DEBUG_DIR) CFLAGS="$(DEBUG_CFLAGS)"
|
||||
|
||||
build_release:
|
||||
@-mkdir $(BUILD_RELEASE_DIR)
|
||||
$(MAKE) targets BUILDDIR=$(BUILD_RELEASE_DIR) CFLAGS="$(RELEASE_CFLAGS)"
|
||||
|
||||
all: build_debug build_release
|
||||
|
||||
targets: $(TARGETS)
|
||||
|
||||
ROGUE_OBJS = \
|
||||
$(BUILDDIR)/dm_ball.o \
|
||||
$(BUILDDIR)/dm_tag.o \
|
||||
$(BUILDDIR)/g_ai.o \
|
||||
$(BUILDDIR)/g_chase.o \
|
||||
$(BUILDDIR)/g_cmds.o \
|
||||
$(BUILDDIR)/g_combat.o \
|
||||
$(BUILDDIR)/g_func.o \
|
||||
$(BUILDDIR)/g_items.o \
|
||||
$(BUILDDIR)/g_main.o \
|
||||
$(BUILDDIR)/g_misc.o \
|
||||
$(BUILDDIR)/g_monster.o \
|
||||
$(BUILDDIR)/g_newai.o \
|
||||
$(BUILDDIR)/g_newdm.o \
|
||||
$(BUILDDIR)/g_newfnc.o \
|
||||
$(BUILDDIR)/g_newtarg.o \
|
||||
$(BUILDDIR)/g_newtrig.o \
|
||||
$(BUILDDIR)/g_newweap.o \
|
||||
$(BUILDDIR)/g_phys.o \
|
||||
$(BUILDDIR)/g_save.o \
|
||||
$(BUILDDIR)/g_spawn.o \
|
||||
$(BUILDDIR)/g_sphere.o \
|
||||
$(BUILDDIR)/g_svcmds.o \
|
||||
$(BUILDDIR)/g_target.o \
|
||||
$(BUILDDIR)/g_trigger.o \
|
||||
$(BUILDDIR)/g_turret.o \
|
||||
$(BUILDDIR)/g_utils.o \
|
||||
$(BUILDDIR)/g_weapon.o \
|
||||
$(BUILDDIR)/m_actor.o \
|
||||
$(BUILDDIR)/m_berserk.o \
|
||||
$(BUILDDIR)/m_boss2.o \
|
||||
$(BUILDDIR)/m_boss3.o \
|
||||
$(BUILDDIR)/m_boss31.o \
|
||||
$(BUILDDIR)/m_boss32.o \
|
||||
$(BUILDDIR)/m_brain.o \
|
||||
$(BUILDDIR)/m_carrier.o \
|
||||
$(BUILDDIR)/m_chick.o \
|
||||
$(BUILDDIR)/m_flash.o \
|
||||
$(BUILDDIR)/m_flipper.o \
|
||||
$(BUILDDIR)/m_float.o \
|
||||
$(BUILDDIR)/m_flyer.o \
|
||||
$(BUILDDIR)/m_gladiator.o \
|
||||
$(BUILDDIR)/m_gunner.o \
|
||||
$(BUILDDIR)/m_hover.o \
|
||||
$(BUILDDIR)/m_infantry.o \
|
||||
$(BUILDDIR)/m_insane.o \
|
||||
$(BUILDDIR)/m_medic.o \
|
||||
$(BUILDDIR)/m_move.o \
|
||||
$(BUILDDIR)/m_mutant.o \
|
||||
$(BUILDDIR)/m_parasite.o \
|
||||
$(BUILDDIR)/m_soldier.o \
|
||||
$(BUILDDIR)/m_stalker.o \
|
||||
$(BUILDDIR)/m_supertank.o \
|
||||
$(BUILDDIR)/m_tank.o \
|
||||
$(BUILDDIR)/m_turret.o \
|
||||
$(BUILDDIR)/m_widow.o \
|
||||
$(BUILDDIR)/m_widow2.o \
|
||||
$(BUILDDIR)/p_client.o \
|
||||
$(BUILDDIR)/p_hud.o \
|
||||
$(BUILDDIR)/p_trail.o \
|
||||
$(BUILDDIR)/p_view.o \
|
||||
$(BUILDDIR)/p_weapon.o \
|
||||
$(BUILDDIR)/q_shared.o
|
||||
|
||||
$(BUILDDIR)/game$(ARCH).$(SHLIBEXT) : $(ROGUE_OBJS)
|
||||
$(CC) $(CFLAGS) $(SHLIBLDFLAGS) -o $@ $(ROGUE_OBJS)
|
||||
|
||||
$(BUILDDIR)/dm_ball.o : dm_ball.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/dm_tag.o : dm_tag.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/g_ai.o : g_ai.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/g_chase.o : g_chase.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/g_cmds.o : g_cmds.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/g_combat.o : g_combat.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/g_func.o : g_func.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/g_items.o : g_items.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/g_main.o : g_main.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/g_misc.o : g_misc.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/g_monster.o : g_monster.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/g_newai.o : g_newai.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/g_newdm.o : g_newdm.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/g_newfnc.o : g_newfnc.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/g_newtarg.o : g_newtarg.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/g_newtrig.o : g_newtrig.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/g_newweap.o : g_newweap.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/g_phys.o : g_phys.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/g_save.o : g_save.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/g_spawn.o : g_spawn.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/g_sphere.o : g_sphere.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/g_svcmds.o : g_svcmds.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/g_target.o : g_target.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/g_trigger.o : g_trigger.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/g_turret.o : g_turret.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/g_utils.o : g_utils.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/g_weapon.o : g_weapon.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/m_actor.o : m_actor.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/m_berserk.o : m_berserk.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/m_boss2.o : m_boss2.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/m_boss3.o : m_boss3.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/m_boss31.o : m_boss31.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/m_boss32.o : m_boss32.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/m_brain.o : m_brain.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/m_carrier.o : m_carrier.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/m_chick.o : m_chick.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/m_flash.o : m_flash.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/m_flipper.o : m_flipper.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/m_float.o : m_float.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/m_flyer.o : m_flyer.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/m_gladiator.o : m_gladiator.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/m_gunner.o : m_gunner.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/m_hover.o : m_hover.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/m_infantry.o : m_infantry.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/m_insane.o : m_insane.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/m_medic.o : m_medic.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/m_move.o : m_move.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/m_mutant.o : m_mutant.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/m_parasite.o : m_parasite.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/m_soldier.o : m_soldier.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/m_stalker.o : m_stalker.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/m_supertank.o : m_supertank.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/m_tank.o : m_tank.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/m_turret.o : m_turret.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/m_widow.o : m_widow.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/m_widow2.o : m_widow2.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/p_client.o : p_client.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/p_hud.o : p_hud.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/p_trail.o : p_trail.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/p_view.o : p_view.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/p_weapon.o : p_weapon.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/q_shared.o : q_shared.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
######################
|
||||
|
||||
clean: clean-debug clean-release
|
||||
|
||||
clean-debug:
|
||||
$(MAKE) clean2 BUILDDIR=$(BUILD_DEBUG_DIR) CFLAGS="$(DEBUG_CFLAGS)"
|
||||
|
||||
clean-release:
|
||||
$(MAKE) clean2 BUILDDIR=$(BUILD_RELEASE_DIR) CFLAGS="$(DEBUG_CFLAGS)"
|
||||
|
||||
clean2:
|
||||
-rm -f $(ROGUE_OBJS)
|
678
dm_ball.c
Normal file
678
dm_ball.c
Normal file
|
@ -0,0 +1,678 @@
|
|||
// dm_ball.c
|
||||
// pmack
|
||||
// june 98
|
||||
|
||||
#include "g_local.h"
|
||||
|
||||
// defines
|
||||
|
||||
#define DBALL_GOAL_TEAM1 0x0001
|
||||
#define DBALL_GOAL_TEAM2 0x0002
|
||||
|
||||
// globals
|
||||
|
||||
edict_t *dball_ball_entity = NULL;
|
||||
int dball_ball_startpt_count;
|
||||
int dball_team1_goalscore;
|
||||
int dball_team2_goalscore;
|
||||
|
||||
cvar_t *dball_team1_skin;
|
||||
cvar_t *dball_team2_skin;
|
||||
cvar_t *goallimit;
|
||||
|
||||
// prototypes
|
||||
|
||||
extern void EndDMLevel (void);
|
||||
extern void ClientUserinfoChanged (edict_t *ent, char *userinfo);
|
||||
extern void SelectSpawnPoint (edict_t *ent, vec3_t origin, vec3_t angles);
|
||||
extern float PlayersRangeFromSpot (edict_t *spot);
|
||||
|
||||
void DBall_BallDie (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point);
|
||||
void DBall_BallRespawn (edict_t *self);
|
||||
|
||||
// **************************
|
||||
// Game rules
|
||||
// **************************
|
||||
|
||||
int DBall_CheckDMRules (void)
|
||||
{
|
||||
if(goallimit && goallimit->value)
|
||||
{
|
||||
if(dball_team1_goalscore >= goallimit->value)
|
||||
gi.bprintf (PRINT_HIGH, "Team 1 Wins.\n");
|
||||
else if(dball_team2_goalscore >= goallimit->value)
|
||||
gi.bprintf (PRINT_HIGH, "Team 2 Wins.\n");
|
||||
else
|
||||
return 0;
|
||||
|
||||
EndDMLevel ();
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
//==================
|
||||
//==================
|
||||
void DBall_ClientBegin (edict_t *ent)
|
||||
{
|
||||
int team1, team2, unassigned;
|
||||
edict_t *other;
|
||||
char *p;
|
||||
static char value[512];
|
||||
int j;
|
||||
|
||||
team1 = 0;
|
||||
team2 = 0;
|
||||
unassigned = 0;
|
||||
|
||||
for (j = 1; j <= game.maxclients; j++)
|
||||
{
|
||||
other = &g_edicts[j];
|
||||
if (!other->inuse)
|
||||
continue;
|
||||
if (!other->client)
|
||||
continue;
|
||||
if (other == ent) // don't count the new player
|
||||
continue;
|
||||
|
||||
strcpy(value, Info_ValueForKey (other->client->pers.userinfo, "skin"));
|
||||
p = strchr(value, '/');
|
||||
if (p)
|
||||
{
|
||||
if(!strcmp(dball_team1_skin->string, value))
|
||||
team1++;
|
||||
else if(!strcmp(dball_team2_skin->string, value))
|
||||
team2++;
|
||||
else
|
||||
unassigned++;
|
||||
}
|
||||
else
|
||||
unassigned++;
|
||||
}
|
||||
|
||||
if(team1 > team2)
|
||||
{
|
||||
gi.dprintf("assigned to team 2\n");
|
||||
Info_SetValueForKey(ent->client->pers.userinfo, "skin", dball_team2_skin->string);
|
||||
}
|
||||
else
|
||||
{
|
||||
gi.dprintf("assigned to team 1\n");
|
||||
Info_SetValueForKey(ent->client->pers.userinfo, "skin", dball_team1_skin->string);
|
||||
}
|
||||
|
||||
ClientUserinfoChanged(ent, ent->client->pers.userinfo);
|
||||
|
||||
if(unassigned)
|
||||
gi.dprintf("%d unassigned players present!\n", unassigned);
|
||||
}
|
||||
|
||||
//==================
|
||||
//==================
|
||||
void DBall_SelectSpawnPoint (edict_t *ent, vec3_t origin, vec3_t angles)
|
||||
{
|
||||
edict_t *bestspot;
|
||||
float bestdistance, bestplayerdistance;
|
||||
edict_t *spot;
|
||||
char *spottype;
|
||||
char skin[512];
|
||||
|
||||
strcpy(skin, Info_ValueForKey (ent->client->pers.userinfo, "skin"));
|
||||
if(!strcmp(dball_team1_skin->string, skin))
|
||||
spottype = "dm_dball_team1_start";
|
||||
else if(!strcmp(dball_team2_skin->string, skin))
|
||||
spottype = "dm_dball_team2_start";
|
||||
else
|
||||
spottype = "info_player_deathmatch";
|
||||
|
||||
spot = NULL;
|
||||
bestspot = NULL;
|
||||
bestdistance = 0;
|
||||
while ((spot = G_Find (spot, FOFS(classname), spottype)) != NULL)
|
||||
{
|
||||
bestplayerdistance = PlayersRangeFromSpot (spot);
|
||||
|
||||
if (bestplayerdistance > bestdistance)
|
||||
{
|
||||
bestspot = spot;
|
||||
bestdistance = bestplayerdistance;
|
||||
}
|
||||
}
|
||||
|
||||
if (bestspot)
|
||||
{
|
||||
VectorCopy (bestspot->s.origin, origin);
|
||||
origin[2] += 9;
|
||||
VectorCopy (bestspot->s.angles, angles);
|
||||
return;
|
||||
}
|
||||
|
||||
// if we didn't find an appropriate spawnpoint, just
|
||||
// call the standard one.
|
||||
SelectSpawnPoint(ent, origin, angles);
|
||||
}
|
||||
|
||||
//==================
|
||||
//==================
|
||||
void DBall_GameInit (void)
|
||||
{
|
||||
// we don't want a minimum speed for friction to take effect.
|
||||
// this will allow any knockback to move stuff.
|
||||
sv_stopspeed->value = 0;
|
||||
dball_team1_goalscore = 0;
|
||||
dball_team2_goalscore = 0;
|
||||
|
||||
dmflags->value = (int)dmflags->value | DF_NO_MINES | DF_NO_NUKES | DF_NO_STACK_DOUBLE |
|
||||
DF_NO_FRIENDLY_FIRE | DF_SKINTEAMS;
|
||||
|
||||
dball_team1_skin = gi.cvar ("dball_team1_skin", "male/ctf_r", 0);
|
||||
dball_team2_skin = gi.cvar ("dball_team2_skin", "male/ctf_b", 0);
|
||||
goallimit = gi.cvar ("goallimit", "0", 0);
|
||||
}
|
||||
|
||||
//==================
|
||||
//==================
|
||||
void DBall_PostInitSetup (void)
|
||||
{
|
||||
edict_t *e;
|
||||
|
||||
e=NULL;
|
||||
// turn teleporter destinations nonsolid.
|
||||
while(e = G_Find (e, FOFS(classname), "misc_teleporter_dest"))
|
||||
{
|
||||
e->solid = SOLID_NOT;
|
||||
gi.linkentity (e);
|
||||
}
|
||||
|
||||
// count the ball start points
|
||||
dball_ball_startpt_count = 0;
|
||||
e=NULL;
|
||||
while(e = G_Find (e, FOFS(classname), "dm_dball_ball_start"))
|
||||
{
|
||||
dball_ball_startpt_count++;
|
||||
}
|
||||
|
||||
if(dball_ball_startpt_count == 0)
|
||||
gi.dprintf("No Deathball start points!\n");
|
||||
}
|
||||
|
||||
//==================
|
||||
// DBall_ChangeDamage - half damage between players. full if it involves
|
||||
// the ball entity
|
||||
//==================
|
||||
int DBall_ChangeDamage (edict_t *targ, edict_t *attacker, int damage, int mod)
|
||||
{
|
||||
// cut player -> ball damage to 1
|
||||
if (targ == dball_ball_entity)
|
||||
return 1;
|
||||
|
||||
// damage player -> player is halved
|
||||
if (attacker != dball_ball_entity)
|
||||
return damage / 2;
|
||||
|
||||
return damage;
|
||||
}
|
||||
|
||||
//==================
|
||||
//==================
|
||||
int DBall_ChangeKnockback (edict_t *targ, edict_t *attacker, int knockback, int mod)
|
||||
{
|
||||
if(targ != dball_ball_entity)
|
||||
return knockback;
|
||||
|
||||
if(knockback < 1)
|
||||
{
|
||||
// FIXME - these don't account for quad/double
|
||||
if(mod == MOD_ROCKET) // rocket
|
||||
knockback = 70;
|
||||
else if(mod == MOD_BFG_EFFECT) // bfg
|
||||
knockback = 90;
|
||||
else
|
||||
gi.dprintf ("zero knockback, mod %d\n", mod);
|
||||
}
|
||||
else
|
||||
{
|
||||
// FIXME - change this to an array?
|
||||
switch(mod)
|
||||
{
|
||||
case MOD_BLASTER:
|
||||
knockback *= 3;
|
||||
break;
|
||||
case MOD_SHOTGUN:
|
||||
knockback = (knockback * 3) / 8;
|
||||
break;
|
||||
case MOD_SSHOTGUN:
|
||||
knockback = knockback / 3;
|
||||
break;
|
||||
case MOD_MACHINEGUN:
|
||||
knockback = (knockback * 3) / 2;
|
||||
break;
|
||||
case MOD_HYPERBLASTER:
|
||||
knockback *= 4;
|
||||
break;
|
||||
case MOD_GRENADE:
|
||||
case MOD_HANDGRENADE:
|
||||
case MOD_PROX:
|
||||
case MOD_G_SPLASH:
|
||||
case MOD_HG_SPLASH:
|
||||
case MOD_HELD_GRENADE:
|
||||
case MOD_TRACKER:
|
||||
case MOD_DISINTEGRATOR:
|
||||
knockback /= 2;
|
||||
break;
|
||||
case MOD_R_SPLASH:
|
||||
knockback = (knockback * 3) / 2;
|
||||
break;
|
||||
case MOD_RAILGUN:
|
||||
case MOD_HEATBEAM:
|
||||
knockback /= 3;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// gi.dprintf("mod: %d knockback: %d\n", mod, knockback);
|
||||
return knockback;
|
||||
}
|
||||
|
||||
// **************************
|
||||
// Goals
|
||||
// **************************
|
||||
|
||||
void DBall_GoalTouch (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf)
|
||||
{
|
||||
int team_score;
|
||||
int scorechange;
|
||||
int j;
|
||||
char value[512];
|
||||
char *p;
|
||||
edict_t *ent;
|
||||
|
||||
if(other != dball_ball_entity)
|
||||
return;
|
||||
|
||||
self->health = self->max_health;
|
||||
|
||||
// determine which team scored, and bump the team score
|
||||
if(self->spawnflags & DBALL_GOAL_TEAM1)
|
||||
{
|
||||
dball_team1_goalscore += self->wait;
|
||||
team_score = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
dball_team2_goalscore += self->wait;
|
||||
team_score = 2;
|
||||
}
|
||||
|
||||
// bump the score for everyone on the correct team.
|
||||
for (j = 1; j <= game.maxclients; j++)
|
||||
{
|
||||
ent = &g_edicts[j];
|
||||
if (!ent->inuse)
|
||||
continue;
|
||||
if (!ent->client)
|
||||
continue;
|
||||
|
||||
if (ent == other->enemy)
|
||||
scorechange = self->wait + 5;
|
||||
else
|
||||
scorechange = self->wait;
|
||||
|
||||
strcpy(value, Info_ValueForKey (ent->client->pers.userinfo, "skin"));
|
||||
p = strchr(value, '/');
|
||||
if (p)
|
||||
{
|
||||
if(!strcmp(dball_team1_skin->string, value))
|
||||
{
|
||||
if(team_score == 1)
|
||||
ent->client->resp.score += scorechange;
|
||||
else if(other->enemy == ent)
|
||||
ent->client->resp.score -= scorechange;
|
||||
}
|
||||
else if(!strcmp(dball_team2_skin->string, value))
|
||||
{
|
||||
if(team_score == 2)
|
||||
ent->client->resp.score += scorechange;
|
||||
else if(other->enemy == ent)
|
||||
ent->client->resp.score -= scorechange;
|
||||
}
|
||||
else
|
||||
gi.dprintf("unassigned player!!!!\n");
|
||||
}
|
||||
}
|
||||
|
||||
if(other->enemy)
|
||||
gi.dprintf("score for team %d by %s\n", team_score, other->enemy->client->pers.netname);
|
||||
else
|
||||
gi.dprintf("score for team %d by someone\n", team_score);
|
||||
|
||||
DBall_BallDie (other, other->enemy, other->enemy, 0, vec3_origin);
|
||||
|
||||
G_UseTargets (self, other);
|
||||
}
|
||||
|
||||
// **************************
|
||||
// Ball
|
||||
// **************************
|
||||
|
||||
edict_t *PickBallStart (edict_t *ent)
|
||||
{
|
||||
int which, current;
|
||||
edict_t *e;
|
||||
|
||||
which = ceil(random() * dball_ball_startpt_count);
|
||||
e = NULL;
|
||||
current = 0;
|
||||
|
||||
while(e = G_Find (e, FOFS(classname), "dm_dball_ball_start"))
|
||||
{
|
||||
current++;
|
||||
if(current == which)
|
||||
return e;
|
||||
}
|
||||
|
||||
if(current == 0)
|
||||
gi.dprintf("No ball start points found!\n");
|
||||
|
||||
return G_Find(NULL, FOFS(classname), "dm_dball_ball_start");
|
||||
}
|
||||
|
||||
//==================
|
||||
// DBall_BallTouch - if the ball hit another player, hurt them
|
||||
//==================
|
||||
void DBall_BallTouch (edict_t *ent, edict_t *other, cplane_t *plane, csurface_t *surf)
|
||||
{
|
||||
vec3_t dir;
|
||||
float dot;
|
||||
float speed;
|
||||
|
||||
if(other->takedamage == DAMAGE_NO)
|
||||
return;
|
||||
|
||||
// hit a player
|
||||
if(other->client)
|
||||
{
|
||||
if(ent->velocity[0] || ent->velocity[1] || ent->velocity[2])
|
||||
{
|
||||
speed = VectorLength(ent->velocity);
|
||||
|
||||
VectorSubtract(ent->s.origin, other->s.origin, dir);
|
||||
dot = DotProduct(dir, ent->velocity);
|
||||
|
||||
if(dot > 0.7)
|
||||
{
|
||||
T_Damage (other, ent, ent, vec3_origin, ent->s.origin, vec3_origin,
|
||||
speed/10, speed/10, 0, MOD_DBALL_CRUSH);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//==================
|
||||
// DBall_BallPain
|
||||
//==================
|
||||
void DBall_BallPain (edict_t *self, edict_t *other, float kick, int damage)
|
||||
{
|
||||
self->enemy = other;
|
||||
self->health = self->max_health;
|
||||
// if(other->classname)
|
||||
// gi.dprintf("hurt by %s -- %d\n", other->classname, self->health);
|
||||
}
|
||||
|
||||
void DBall_BallDie (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point)
|
||||
{
|
||||
// do the splash effect
|
||||
gi.WriteByte (svc_temp_entity);
|
||||
gi.WriteByte (TE_DBALL_GOAL);
|
||||
gi.WritePosition (self->s.origin);
|
||||
gi.multicast (self->s.origin, MULTICAST_PVS);
|
||||
|
||||
VectorClear(self->s.angles);
|
||||
VectorClear(self->velocity);
|
||||
VectorClear(self->avelocity);
|
||||
|
||||
// make it invisible and desolid until respawn time
|
||||
self->solid = SOLID_NOT;
|
||||
// self->s.modelindex = 0;
|
||||
self->think = DBall_BallRespawn;
|
||||
self->nextthink = level.time + 2;
|
||||
gi.linkentity(self);
|
||||
|
||||
}
|
||||
|
||||
void DBall_BallRespawn (edict_t *self)
|
||||
{
|
||||
edict_t *start;
|
||||
|
||||
// do the splash effect
|
||||
gi.WriteByte (svc_temp_entity);
|
||||
gi.WriteByte (TE_DBALL_GOAL);
|
||||
gi.WritePosition (self->s.origin);
|
||||
gi.multicast (self->s.origin, MULTICAST_PVS);
|
||||
|
||||
// move the ball and stop it
|
||||
start = PickBallStart(self);
|
||||
if(start)
|
||||
{
|
||||
VectorCopy(start->s.origin, self->s.origin);
|
||||
VectorCopy(start->s.origin, self->s.old_origin);
|
||||
}
|
||||
|
||||
VectorClear(self->s.angles);
|
||||
VectorClear(self->velocity);
|
||||
VectorClear(self->avelocity);
|
||||
|
||||
self->solid = SOLID_BBOX;
|
||||
self->s.modelindex = gi.modelindex ("models/objects/dball/tris.md2");
|
||||
self->s.event = EV_PLAYER_TELEPORT;
|
||||
self->groundentity = NULL;
|
||||
|
||||
// kill anything at the destination
|
||||
KillBox (self);
|
||||
|
||||
gi.linkentity (self);
|
||||
}
|
||||
|
||||
// ************************
|
||||
// SPEED CHANGES
|
||||
// ************************
|
||||
|
||||
#define DBALL_SPEED_ONEWAY 1
|
||||
|
||||
void DBall_SpeedTouch (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf)
|
||||
{
|
||||
float dot;
|
||||
vec3_t vel;
|
||||
|
||||
if(other != dball_ball_entity)
|
||||
return;
|
||||
|
||||
if(self->timestamp >= level.time)
|
||||
return;
|
||||
|
||||
if(VectorLength(other->velocity) < 1)
|
||||
return;
|
||||
|
||||
if(self->spawnflags & DBALL_SPEED_ONEWAY)
|
||||
{
|
||||
VectorCopy (other->velocity, vel);
|
||||
VectorNormalize (vel);
|
||||
dot = DotProduct (vel, self->movedir);
|
||||
if(dot < 0.8)
|
||||
return;
|
||||
}
|
||||
|
||||
self->timestamp = level.time + self->delay;
|
||||
VectorScale (other->velocity, self->speed, other->velocity);
|
||||
}
|
||||
|
||||
// ************************
|
||||
// SPAWN FUNCTIONS
|
||||
// ************************
|
||||
|
||||
/*QUAKED dm_dball_ball (1 .5 .5) (-48 -48 -48) (48 48 48)
|
||||
Deathball Ball
|
||||
*/
|
||||
void SP_dm_dball_ball (edict_t *self)
|
||||
{
|
||||
if(!(deathmatch->value))
|
||||
{
|
||||
G_FreeEdict(self);
|
||||
return;
|
||||
}
|
||||
|
||||
if(gamerules && (gamerules->value != RDM_DEATHBALL))
|
||||
{
|
||||
G_FreeEdict(self);
|
||||
return;
|
||||
}
|
||||
|
||||
dball_ball_entity = self;
|
||||
// VectorCopy (self->s.origin, dball_ball_startpt);
|
||||
|
||||
self->s.modelindex = gi.modelindex ("models/objects/dball/tris.md2");
|
||||
VectorSet (self->mins, -32, -32, -32);
|
||||
VectorSet (self->maxs, 32, 32, 32);
|
||||
self->solid = SOLID_BBOX;
|
||||
self->movetype = MOVETYPE_NEWTOSS;
|
||||
self->clipmask = MASK_MONSTERSOLID;
|
||||
|
||||
self->takedamage = DAMAGE_YES;
|
||||
self->mass = 50;
|
||||
self->health = 50000;
|
||||
self->max_health = 50000;
|
||||
self->pain = DBall_BallPain;
|
||||
self->die = DBall_BallDie;
|
||||
self->touch = DBall_BallTouch;
|
||||
|
||||
gi.linkentity (self);
|
||||
}
|
||||
|
||||
/*QUAKED dm_dball_team1_start (1 .5 .5) (-16 -16 -24) (16 16 32)
|
||||
Deathball team 1 start point
|
||||
*/
|
||||
void SP_dm_dball_team1_start (edict_t *self)
|
||||
{
|
||||
if (!deathmatch->value)
|
||||
{
|
||||
G_FreeEdict (self);
|
||||
return;
|
||||
}
|
||||
if(gamerules && (gamerules->value != RDM_DEATHBALL))
|
||||
{
|
||||
G_FreeEdict(self);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/*QUAKED dm_dball_team2_start (1 .5 .5) (-16 -16 -24) (16 16 32)
|
||||
Deathball team 2 start point
|
||||
*/
|
||||
void SP_dm_dball_team2_start (edict_t *self)
|
||||
{
|
||||
if (!deathmatch->value)
|
||||
{
|
||||
G_FreeEdict (self);
|
||||
return;
|
||||
}
|
||||
if(gamerules && (gamerules->value != RDM_DEATHBALL))
|
||||
{
|
||||
G_FreeEdict(self);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/*QUAKED dm_dball_ball_start (1 .5 .5) (-48 -48 -48) (48 48 48)
|
||||
Deathball ball start point
|
||||
*/
|
||||
void SP_dm_dball_ball_start (edict_t *self)
|
||||
{
|
||||
if (!deathmatch->value)
|
||||
{
|
||||
G_FreeEdict (self);
|
||||
return;
|
||||
}
|
||||
if(gamerules && (gamerules->value != RDM_DEATHBALL))
|
||||
{
|
||||
G_FreeEdict(self);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/*QUAKED dm_dball_speed_change (1 .5 .5) ? ONEWAY
|
||||
Deathball ball speed changing field.
|
||||
|
||||
speed: multiplier for speed (.5 = half, 2 = double, etc) (default = double)
|
||||
angle: used with ONEWAY so speed change is only one way.
|
||||
delay: time between speed changes (default: 0.2 sec)
|
||||
*/
|
||||
void SP_dm_dball_speed_change (edict_t *self)
|
||||
{
|
||||
if (!deathmatch->value)
|
||||
{
|
||||
G_FreeEdict (self);
|
||||
return;
|
||||
}
|
||||
if(gamerules && (gamerules->value != RDM_DEATHBALL))
|
||||
{
|
||||
G_FreeEdict(self);
|
||||
return;
|
||||
}
|
||||
|
||||
if(!self->speed)
|
||||
self->speed = 2;
|
||||
|
||||
if(!self->delay)
|
||||
self->delay = 0.2;
|
||||
|
||||
self->touch = DBall_SpeedTouch;
|
||||
self->solid = SOLID_TRIGGER;
|
||||
self->movetype = MOVETYPE_NONE;
|
||||
self->svflags |= SVF_NOCLIENT;
|
||||
|
||||
if (!VectorCompare(self->s.angles, vec3_origin))
|
||||
G_SetMovedir (self->s.angles, self->movedir);
|
||||
else
|
||||
VectorSet (self->movedir, 1, 0, 0);
|
||||
|
||||
gi.setmodel (self, self->model);
|
||||
gi.linkentity (self);
|
||||
}
|
||||
|
||||
/*QUAKED dm_dball_goal (1 .5 .5) ? TEAM1 TEAM2
|
||||
Deathball goal
|
||||
|
||||
Team1/Team2 - beneficiary of this goal. when the ball enters this goal, the beneficiary team will score.
|
||||
|
||||
"wait": score to be given for this goal (default 10) player gets score+5.
|
||||
*/
|
||||
void SP_dm_dball_goal (edict_t *self)
|
||||
{
|
||||
if(!(deathmatch->value))
|
||||
{
|
||||
G_FreeEdict(self);
|
||||
return;
|
||||
}
|
||||
|
||||
if(gamerules && (gamerules->value != RDM_DEATHBALL))
|
||||
{
|
||||
G_FreeEdict(self);
|
||||
return;
|
||||
}
|
||||
|
||||
if(!self->wait)
|
||||
self->wait = 10;
|
||||
|
||||
self->touch = DBall_GoalTouch;
|
||||
self->solid = SOLID_TRIGGER;
|
||||
self->movetype = MOVETYPE_NONE;
|
||||
self->svflags |= SVF_NOCLIENT;
|
||||
|
||||
if (!VectorCompare(self->s.angles, vec3_origin))
|
||||
G_SetMovedir (self->s.angles, self->movedir);
|
||||
|
||||
gi.setmodel (self, self->model);
|
||||
gi.linkentity (self);
|
||||
|
||||
}
|
333
dm_tag.c
Normal file
333
dm_tag.c
Normal file
|
@ -0,0 +1,333 @@
|
|||
// dm_tag
|
||||
// pmack
|
||||
// june 1998
|
||||
|
||||
#include "g_local.h"
|
||||
|
||||
extern edict_t *SelectFarthestDeathmatchSpawnPoint (void);
|
||||
extern void SelectSpawnPoint (edict_t *ent, vec3_t origin, vec3_t angles);
|
||||
|
||||
void SP_dm_tag_token (edict_t *self);
|
||||
|
||||
// ***********************
|
||||
// Tag Specific Stuff
|
||||
// ***********************
|
||||
|
||||
edict_t *tag_token;
|
||||
edict_t *tag_owner;
|
||||
int tag_count;
|
||||
|
||||
//=================
|
||||
//=================
|
||||
void Tag_PlayerDeath(edict_t *targ, edict_t *inflictor, edict_t *attacker)
|
||||
{
|
||||
// gi.dprintf("%s killed %s\n", attacker->classname, targ->classname);
|
||||
// gi.dprintf("%x killed %x\n", attacker, targ);
|
||||
|
||||
if(tag_token && targ && (targ == tag_owner))
|
||||
{
|
||||
// gi.dprintf("owner died/suicided. dropping\n");
|
||||
Tag_DropToken(targ, FindItem( "Tag Token" ));
|
||||
tag_owner = NULL;
|
||||
tag_count = 0;
|
||||
}
|
||||
// else
|
||||
// gi.dprintf("unrelated slaying\n");
|
||||
}
|
||||
|
||||
//=================
|
||||
//=================
|
||||
void Tag_KillItBonus (edict_t *self)
|
||||
{
|
||||
edict_t *armor;
|
||||
|
||||
// if the player is hurt, boost them up to max.
|
||||
if(self->health < self->max_health)
|
||||
{
|
||||
self->health += 200;
|
||||
if(self->health > self->max_health)
|
||||
self->health = self->max_health;
|
||||
}
|
||||
|
||||
// give the player a body armor
|
||||
armor = G_Spawn();
|
||||
armor->spawnflags |= DROPPED_ITEM;
|
||||
armor->item = FindItem("Body Armor");
|
||||
Touch_Item(armor, self, NULL, NULL);
|
||||
if(armor->inuse)
|
||||
G_FreeEdict(armor);
|
||||
}
|
||||
|
||||
//=================
|
||||
//=================
|
||||
void Tag_PlayerDisconnect (edict_t *self)
|
||||
{
|
||||
if(tag_token && self && (self == tag_owner))
|
||||
{
|
||||
// gi.dprintf("owner died/suicided. dropping\n");
|
||||
Tag_DropToken(self, FindItem( "Tag Token" ));
|
||||
tag_owner = NULL;
|
||||
tag_count = 0;
|
||||
}
|
||||
}
|
||||
|
||||
//=================
|
||||
//=================
|
||||
void Tag_Score (edict_t *attacker, edict_t *victim, int scoreChange)
|
||||
{
|
||||
gitem_t *quad;
|
||||
int mod;
|
||||
|
||||
mod = meansOfDeath & ~MOD_FRIENDLY_FIRE;
|
||||
|
||||
// gi.dprintf("%s killed %s\n", attacker->classname, victim->classname);
|
||||
// gi.dprintf("%x killed %x\n", attacker, victim);
|
||||
if(tag_token && tag_owner)
|
||||
{
|
||||
// owner killed somone else
|
||||
if((scoreChange > 0) && tag_owner == attacker)
|
||||
{
|
||||
scoreChange = 3;
|
||||
tag_count++;
|
||||
// gi.dprintf("tag total: %d\n", tag_count);
|
||||
if(tag_count == 5)
|
||||
{
|
||||
// gi.dprintf("going to quad\n");
|
||||
quad = FindItem ("Quad Damage");
|
||||
attacker->client->pers.inventory[ITEM_INDEX(quad)]++;
|
||||
quad->use (attacker, quad);
|
||||
tag_count = 0;
|
||||
}
|
||||
}
|
||||
// owner got killed. 5 points and switch owners
|
||||
else if(tag_owner == victim && tag_owner != attacker)
|
||||
{
|
||||
// gi.dprintf("owner killed by another player.\n");
|
||||
scoreChange = 5;
|
||||
if ((mod == MOD_HUNTER_SPHERE) || (mod == MOD_DOPPLE_EXPLODE) ||
|
||||
(mod == MOD_DOPPLE_VENGEANCE) || (mod == MOD_DOPPLE_HUNTER) ||
|
||||
(attacker->health <= 0))
|
||||
{
|
||||
Tag_DropToken(tag_owner, FindItem( "Tag Token" ));
|
||||
tag_owner = NULL;
|
||||
tag_count = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
Tag_KillItBonus(attacker);
|
||||
tag_owner = attacker;
|
||||
tag_count = 0;
|
||||
}
|
||||
}
|
||||
// else
|
||||
// gi.dprintf("unaffected slaying\n");
|
||||
}
|
||||
// else
|
||||
// gi.dprintf("no tag token?\n");
|
||||
|
||||
attacker->client->resp.score += scoreChange;
|
||||
}
|
||||
|
||||
//=================
|
||||
//=================
|
||||
qboolean Tag_PickupToken (edict_t *ent, edict_t *other)
|
||||
{
|
||||
if(gamerules && (gamerules->value != 2))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// gi.dprintf("tag token picked up by %x\n", other);
|
||||
// sanity checking is good.
|
||||
if(tag_token != ent)
|
||||
tag_token = ent;
|
||||
|
||||
other->client->pers.inventory[ITEM_INDEX(ent->item)]++;
|
||||
|
||||
tag_owner = other;
|
||||
tag_count = 0;
|
||||
|
||||
Tag_KillItBonus (other);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//=================
|
||||
//=================
|
||||
void Tag_Respawn (edict_t *ent)
|
||||
{
|
||||
edict_t *spot;
|
||||
|
||||
spot = SelectFarthestDeathmatchSpawnPoint();
|
||||
if(spot == NULL)
|
||||
{
|
||||
// gi.dprintf("No open spawn point, waiting...\n");
|
||||
ent->nextthink = level.time + 1;
|
||||
return;
|
||||
}
|
||||
|
||||
// gi.dprintf("Relocating\n");
|
||||
|
||||
VectorCopy(spot->s.origin, ent->s.origin);
|
||||
gi.linkentity(ent);
|
||||
}
|
||||
|
||||
//=================
|
||||
//=================
|
||||
void Tag_MakeTouchable (edict_t *ent)
|
||||
{
|
||||
ent->touch = Touch_Item;
|
||||
|
||||
tag_token->think = Tag_Respawn;
|
||||
|
||||
// check here to see if it's in lava or slime. if so, do a respawn sooner
|
||||
if(gi.pointcontents(ent->s.origin) & (CONTENTS_LAVA|CONTENTS_SLIME))
|
||||
{
|
||||
// gi.dprintf("spawned in slime or lava. quick relocate\n");
|
||||
tag_token->nextthink = level.time + 3;
|
||||
}
|
||||
else
|
||||
{
|
||||
// gi.dprintf("spawned in the clear. regular relocate\n");
|
||||
tag_token->nextthink = level.time + 30;
|
||||
}
|
||||
}
|
||||
|
||||
//=================
|
||||
//=================
|
||||
void Tag_DropToken (edict_t *ent, gitem_t *item)
|
||||
{
|
||||
trace_t trace;
|
||||
vec3_t forward, right;
|
||||
vec3_t offset;
|
||||
|
||||
// if(ent->client)
|
||||
// gi.dprintf("%s dropped the tag token\n", ent->client->pers.netname);
|
||||
// else
|
||||
// gi.dprintf("non-client dropped the tag token (%s)\n", ent->classname);
|
||||
|
||||
// reset the score count for next player
|
||||
tag_count = 0;
|
||||
tag_owner = NULL;
|
||||
|
||||
tag_token = G_Spawn();
|
||||
|
||||
tag_token->classname = item->classname;
|
||||
tag_token->item = item;
|
||||
tag_token->spawnflags = DROPPED_ITEM;
|
||||
tag_token->s.effects = EF_ROTATE | EF_TAGTRAIL;
|
||||
tag_token->s.renderfx = RF_GLOW;
|
||||
VectorSet (tag_token->mins, -15, -15, -15);
|
||||
VectorSet (tag_token->maxs, 15, 15, 15);
|
||||
gi.setmodel (tag_token, tag_token->item->world_model);
|
||||
tag_token->solid = SOLID_TRIGGER;
|
||||
tag_token->movetype = MOVETYPE_TOSS;
|
||||
tag_token->touch = NULL;
|
||||
tag_token->owner = ent;
|
||||
|
||||
AngleVectors (ent->client->v_angle, forward, right, NULL);
|
||||
VectorSet(offset, 24, 0, -16);
|
||||
G_ProjectSource (ent->s.origin, offset, forward, right, tag_token->s.origin);
|
||||
trace = gi.trace (ent->s.origin, tag_token->mins, tag_token->maxs,
|
||||
tag_token->s.origin, ent, CONTENTS_SOLID);
|
||||
VectorCopy (trace.endpos, tag_token->s.origin);
|
||||
|
||||
VectorScale (forward, 100, tag_token->velocity);
|
||||
tag_token->velocity[2] = 300;
|
||||
|
||||
tag_token->think = Tag_MakeTouchable;
|
||||
tag_token->nextthink = level.time + 1;
|
||||
|
||||
gi.linkentity (tag_token);
|
||||
|
||||
// tag_token = Drop_Item (ent, item);
|
||||
ent->client->pers.inventory[ITEM_INDEX(item)]--;
|
||||
ValidateSelectedItem (ent);
|
||||
}
|
||||
|
||||
//=================
|
||||
//=================
|
||||
void Tag_PlayerEffects (edict_t *ent)
|
||||
{
|
||||
if(ent == tag_owner)
|
||||
ent->s.effects |= EF_TAGTRAIL;
|
||||
}
|
||||
|
||||
//=================
|
||||
//=================
|
||||
void Tag_DogTag (edict_t *ent, edict_t *killer, char **pic)
|
||||
{
|
||||
if(ent == tag_owner)
|
||||
(*pic)="tag3";
|
||||
}
|
||||
|
||||
//=================
|
||||
// Tag_ChangeDamage - damage done that does not involve the tag owner
|
||||
// is at 75% original to encourage folks to go after the tag owner.
|
||||
//=================
|
||||
int Tag_ChangeDamage (edict_t *targ, edict_t *attacker, int damage, int mod)
|
||||
{
|
||||
if((targ != tag_owner) && (attacker != tag_owner))
|
||||
return (damage * 3 / 4);
|
||||
|
||||
return damage;
|
||||
}
|
||||
|
||||
//=================
|
||||
//=================
|
||||
void Tag_GameInit (void)
|
||||
{
|
||||
tag_token = NULL;
|
||||
tag_owner = NULL;
|
||||
tag_count = 0;
|
||||
}
|
||||
|
||||
//=================
|
||||
//=================
|
||||
void Tag_PostInitSetup (void)
|
||||
{
|
||||
edict_t *e;
|
||||
vec3_t origin, angles;
|
||||
|
||||
// automatic spawning of tag token if one is not present on map.
|
||||
e = G_Find (NULL, FOFS(classname), "dm_tag_token");
|
||||
if(e == NULL)
|
||||
{
|
||||
e = G_Spawn();
|
||||
e->classname = "dm_tag_token";
|
||||
|
||||
SelectSpawnPoint (e, origin, angles);
|
||||
VectorCopy(origin, e->s.origin);
|
||||
VectorCopy(origin, e->s.old_origin);
|
||||
VectorCopy(angles, e->s.angles);
|
||||
SP_dm_tag_token (e);
|
||||
}
|
||||
}
|
||||
|
||||
/*QUAKED dm_tag_token (.3 .3 1) (-16 -16 -16) (16 16 16)
|
||||
The tag token for deathmatch tag games.
|
||||
*/
|
||||
void SP_dm_tag_token (edict_t *self)
|
||||
{
|
||||
if(!(deathmatch->value))
|
||||
{
|
||||
G_FreeEdict(self);
|
||||
return;
|
||||
}
|
||||
|
||||
if(gamerules && (gamerules->value != 2))
|
||||
{
|
||||
G_FreeEdict(self);
|
||||
return;
|
||||
}
|
||||
|
||||
// store the tag token edict pointer for later use.
|
||||
tag_token = self;
|
||||
tag_count = 0;
|
||||
|
||||
self->classname = "dm_tag_token";
|
||||
self->model = "models/items/tagtoken/tris.md2";
|
||||
self->count = 1;
|
||||
SpawnItem (self, FindItem ("Tag Token"));
|
||||
}
|
||||
|
156
g_chase.c
Normal file
156
g_chase.c
Normal file
|
@ -0,0 +1,156 @@
|
|||
#include "g_local.h"
|
||||
|
||||
void UpdateChaseCam(edict_t *ent)
|
||||
{
|
||||
vec3_t o, ownerv, goal;
|
||||
edict_t *targ;
|
||||
vec3_t forward, right;
|
||||
trace_t trace;
|
||||
int i;
|
||||
vec3_t oldgoal;
|
||||
vec3_t angles;
|
||||
|
||||
// is our chase target gone?
|
||||
if (!ent->client->chase_target->inuse
|
||||
|| ent->client->chase_target->client->resp.spectator) {
|
||||
edict_t *old = ent->client->chase_target;
|
||||
ChaseNext(ent);
|
||||
if (ent->client->chase_target == old) {
|
||||
ent->client->chase_target = NULL;
|
||||
ent->client->ps.pmove.pm_flags &= ~PMF_NO_PREDICTION;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
targ = ent->client->chase_target;
|
||||
|
||||
VectorCopy(targ->s.origin, ownerv);
|
||||
VectorCopy(ent->s.origin, oldgoal);
|
||||
|
||||
ownerv[2] += targ->viewheight;
|
||||
|
||||
VectorCopy(targ->client->v_angle, angles);
|
||||
if (angles[PITCH] > 56)
|
||||
angles[PITCH] = 56;
|
||||
AngleVectors (angles, forward, right, NULL);
|
||||
VectorNormalize(forward);
|
||||
VectorMA(ownerv, -30, forward, o);
|
||||
|
||||
if (o[2] < targ->s.origin[2] + 20)
|
||||
o[2] = targ->s.origin[2] + 20;
|
||||
|
||||
// jump animation lifts
|
||||
if (!targ->groundentity)
|
||||
o[2] += 16;
|
||||
|
||||
trace = gi.trace(ownerv, vec3_origin, vec3_origin, o, targ, MASK_SOLID);
|
||||
|
||||
VectorCopy(trace.endpos, goal);
|
||||
|
||||
VectorMA(goal, 2, forward, goal);
|
||||
|
||||
// pad for floors and ceilings
|
||||
VectorCopy(goal, o);
|
||||
o[2] += 6;
|
||||
trace = gi.trace(goal, vec3_origin, vec3_origin, o, targ, MASK_SOLID);
|
||||
if (trace.fraction < 1) {
|
||||
VectorCopy(trace.endpos, goal);
|
||||
goal[2] -= 6;
|
||||
}
|
||||
|
||||
VectorCopy(goal, o);
|
||||
o[2] -= 6;
|
||||
trace = gi.trace(goal, vec3_origin, vec3_origin, o, targ, MASK_SOLID);
|
||||
if (trace.fraction < 1) {
|
||||
VectorCopy(trace.endpos, goal);
|
||||
goal[2] += 6;
|
||||
}
|
||||
|
||||
if (targ->deadflag)
|
||||
ent->client->ps.pmove.pm_type = PM_DEAD;
|
||||
else
|
||||
ent->client->ps.pmove.pm_type = PM_FREEZE;
|
||||
|
||||
VectorCopy(goal, ent->s.origin);
|
||||
for (i=0 ; i<3 ; i++)
|
||||
ent->client->ps.pmove.delta_angles[i] = ANGLE2SHORT(targ->client->v_angle[i] - ent->client->resp.cmd_angles[i]);
|
||||
|
||||
if (targ->deadflag) {
|
||||
ent->client->ps.viewangles[ROLL] = 40;
|
||||
ent->client->ps.viewangles[PITCH] = -15;
|
||||
ent->client->ps.viewangles[YAW] = targ->client->killer_yaw;
|
||||
} else {
|
||||
VectorCopy(targ->client->v_angle, ent->client->ps.viewangles);
|
||||
VectorCopy(targ->client->v_angle, ent->client->v_angle);
|
||||
}
|
||||
|
||||
ent->viewheight = 0;
|
||||
ent->client->ps.pmove.pm_flags |= PMF_NO_PREDICTION;
|
||||
gi.linkentity(ent);
|
||||
}
|
||||
|
||||
void ChaseNext(edict_t *ent)
|
||||
{
|
||||
int i;
|
||||
edict_t *e;
|
||||
|
||||
if (!ent->client->chase_target)
|
||||
return;
|
||||
|
||||
i = ent->client->chase_target - g_edicts;
|
||||
do {
|
||||
i++;
|
||||
if (i > maxclients->value)
|
||||
i = 1;
|
||||
e = g_edicts + i;
|
||||
if (!e->inuse)
|
||||
continue;
|
||||
if (!e->client->resp.spectator)
|
||||
break;
|
||||
} while (e != ent->client->chase_target);
|
||||
|
||||
ent->client->chase_target = e;
|
||||
ent->client->update_chase = true;
|
||||
}
|
||||
|
||||
void ChasePrev(edict_t *ent)
|
||||
{
|
||||
int i;
|
||||
edict_t *e;
|
||||
|
||||
if (!ent->client->chase_target)
|
||||
return;
|
||||
|
||||
i = ent->client->chase_target - g_edicts;
|
||||
do {
|
||||
i--;
|
||||
if (i < 1)
|
||||
i = maxclients->value;
|
||||
e = g_edicts + i;
|
||||
if (!e->inuse)
|
||||
continue;
|
||||
if (!e->client->resp.spectator)
|
||||
break;
|
||||
} while (e != ent->client->chase_target);
|
||||
|
||||
ent->client->chase_target = e;
|
||||
ent->client->update_chase = true;
|
||||
}
|
||||
|
||||
void GetChaseTarget(edict_t *ent)
|
||||
{
|
||||
int i;
|
||||
edict_t *other;
|
||||
|
||||
for (i = 1; i <= maxclients->value; i++) {
|
||||
other = g_edicts + i;
|
||||
if (other->inuse && !other->client->resp.spectator) {
|
||||
ent->client->chase_target = other;
|
||||
ent->client->update_chase = true;
|
||||
UpdateChaseCam(ent);
|
||||
return;
|
||||
}
|
||||
}
|
||||
gi.centerprintf(ent, "No other players to chase.");
|
||||
}
|
||||
|
947
g_combat.c
Normal file
947
g_combat.c
Normal file
|
@ -0,0 +1,947 @@
|
|||
// g_combat.c
|
||||
|
||||
#include "g_local.h"
|
||||
|
||||
void M_SetEffects (edict_t *self);
|
||||
|
||||
/*
|
||||
ROGUE
|
||||
clean up heal targets for medic
|
||||
*/
|
||||
void cleanupHealTarget (edict_t *ent)
|
||||
{
|
||||
ent->monsterinfo.healer = NULL;
|
||||
ent->takedamage = DAMAGE_YES;
|
||||
ent->monsterinfo.aiflags &= ~AI_RESURRECTING;
|
||||
M_SetEffects (ent);
|
||||
}
|
||||
/*
|
||||
============
|
||||
CanDamage
|
||||
|
||||
Returns true if the inflictor can directly damage the target. Used for
|
||||
explosions and melee attacks.
|
||||
============
|
||||
*/
|
||||
qboolean CanDamage (edict_t *targ, edict_t *inflictor)
|
||||
{
|
||||
vec3_t dest;
|
||||
trace_t trace;
|
||||
|
||||
// bmodels need special checking because their origin is 0,0,0
|
||||
if (targ->movetype == MOVETYPE_PUSH)
|
||||
{
|
||||
VectorAdd (targ->absmin, targ->absmax, dest);
|
||||
VectorScale (dest, 0.5, dest);
|
||||
trace = gi.trace (inflictor->s.origin, vec3_origin, vec3_origin, dest, inflictor, MASK_SOLID);
|
||||
if (trace.fraction == 1.0)
|
||||
return true;
|
||||
if (trace.ent == targ)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
trace = gi.trace (inflictor->s.origin, vec3_origin, vec3_origin, targ->s.origin, inflictor, MASK_SOLID);
|
||||
if (trace.fraction == 1.0)
|
||||
return true;
|
||||
|
||||
VectorCopy (targ->s.origin, dest);
|
||||
dest[0] += 15.0;
|
||||
dest[1] += 15.0;
|
||||
trace = gi.trace (inflictor->s.origin, vec3_origin, vec3_origin, dest, inflictor, MASK_SOLID);
|
||||
if (trace.fraction == 1.0)
|
||||
return true;
|
||||
|
||||
VectorCopy (targ->s.origin, dest);
|
||||
dest[0] += 15.0;
|
||||
dest[1] -= 15.0;
|
||||
trace = gi.trace (inflictor->s.origin, vec3_origin, vec3_origin, dest, inflictor, MASK_SOLID);
|
||||
if (trace.fraction == 1.0)
|
||||
return true;
|
||||
|
||||
VectorCopy (targ->s.origin, dest);
|
||||
dest[0] -= 15.0;
|
||||
dest[1] += 15.0;
|
||||
trace = gi.trace (inflictor->s.origin, vec3_origin, vec3_origin, dest, inflictor, MASK_SOLID);
|
||||
if (trace.fraction == 1.0)
|
||||
return true;
|
||||
|
||||
VectorCopy (targ->s.origin, dest);
|
||||
dest[0] -= 15.0;
|
||||
dest[1] -= 15.0;
|
||||
trace = gi.trace (inflictor->s.origin, vec3_origin, vec3_origin, dest, inflictor, MASK_SOLID);
|
||||
if (trace.fraction == 1.0)
|
||||
return true;
|
||||
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
============
|
||||
Killed
|
||||
============
|
||||
*/
|
||||
void Killed (edict_t *targ, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point)
|
||||