mirror of
https://github.com/id-Software/quake2-rerelease-dll.git
synced 2026-03-20 00:49:33 +01:00
Initial commit
This commit is contained in:
687
rerelease/rogue/rogue_dm_ball.cpp
Normal file
687
rerelease/rogue/rogue_dm_ball.cpp
Normal file
@@ -0,0 +1,687 @@
|
||||
// Copyright (c) ZeniMax Media Inc.
|
||||
// Licensed under the GNU General Public License 2.0.
|
||||
// dm_ball.c
|
||||
// pmack
|
||||
// june 98
|
||||
|
||||
#include "../g_local.h"
|
||||
|
||||
// defines
|
||||
|
||||
constexpr spawnflags_t SPAWNFLAG_DBALL_GOAL_TEAM1 = 0x0001_spawnflag;
|
||||
// unused; assumed by not being team1
|
||||
// constexpr uint32_t SPAWNFLAG_DBALL_GOAL_TEAM2 = 0x0002;
|
||||
|
||||
// globals
|
||||
|
||||
edict_t *dball_ball_entity = nullptr;
|
||||
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
|
||||
|
||||
void EndDMLevel();
|
||||
float PlayersRangeFromSpot(edict_t *spot);
|
||||
|
||||
void DBall_BallDie(edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, const vec3_t &point, const mod_t &mod);
|
||||
void DBall_BallRespawn(edict_t *self);
|
||||
|
||||
// **************************
|
||||
// Game rules
|
||||
// **************************
|
||||
|
||||
int DBall_CheckDMRules()
|
||||
{
|
||||
if (goallimit->integer)
|
||||
{
|
||||
if (dball_team1_goalscore >= goallimit->integer)
|
||||
gi.LocBroadcast_Print(PRINT_HIGH, "Team 1 Wins.\n");
|
||||
else if (dball_team2_goalscore >= goallimit->integer)
|
||||
gi.LocBroadcast_Print(PRINT_HIGH, "Team 2 Wins.\n");
|
||||
else
|
||||
return 0;
|
||||
|
||||
EndDMLevel();
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
//==================
|
||||
//==================
|
||||
void DBall_ClientBegin(edict_t *ent)
|
||||
{
|
||||
#if 0
|
||||
uint32_t team1, team2, unassigned;
|
||||
edict_t *other;
|
||||
char *p;
|
||||
static char value[512];
|
||||
|
||||
team1 = 0;
|
||||
team2 = 0;
|
||||
unassigned = 0;
|
||||
|
||||
for (uint32_t 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;
|
||||
|
||||
Q_strlcpy(value, Info_ValueForKey(other->client->pers.userinfo, "skin"), sizeof(value));
|
||||
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.Com_Print("assigned to team 2\n");
|
||||
Info_SetValueForKey(ent->client->pers.userinfo, "skin", dball_team2_skin->string);
|
||||
}
|
||||
else
|
||||
{
|
||||
gi.Com_Print("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.Com_PrintFmt("{} unassigned players present!\n", unassigned);
|
||||
#endif
|
||||
}
|
||||
|
||||
//==================
|
||||
//==================
|
||||
bool DBall_SelectSpawnPoint(edict_t *ent, vec3_t &origin, vec3_t &angles, bool force_spawn)
|
||||
{
|
||||
#if 0
|
||||
edict_t *bestspot;
|
||||
float bestdistance, bestplayerdistance;
|
||||
edict_t *spot;
|
||||
const char *spottype;
|
||||
static char skin[512];
|
||||
|
||||
Q_strlcpy(skin, Info_ValueForKey(ent->client->pers.userinfo, "skin"), sizeof(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 = nullptr;
|
||||
bestspot = nullptr;
|
||||
bestdistance = 0;
|
||||
while ((spot = G_FindByString<&edict_t::classname>(spot, spottype)) != nullptr)
|
||||
{
|
||||
bestplayerdistance = PlayersRangeFromSpot(spot);
|
||||
|
||||
if (bestplayerdistance > bestdistance)
|
||||
{
|
||||
bestspot = spot;
|
||||
bestdistance = bestplayerdistance;
|
||||
}
|
||||
}
|
||||
|
||||
if (bestspot)
|
||||
{
|
||||
origin = bestspot->s.origin;
|
||||
origin[2] += 9;
|
||||
angles = bestspot->s.angles;
|
||||
return true;
|
||||
}
|
||||
|
||||
// if we didn't find an appropriate spawnpoint, just
|
||||
// call the standard one.
|
||||
#endif
|
||||
bool lm = false;
|
||||
return SelectSpawnPoint(ent, origin, angles, force_spawn, lm);
|
||||
}
|
||||
|
||||
//==================
|
||||
//==================
|
||||
void DBall_GameInit()
|
||||
{
|
||||
// we don't want a minimum speed for friction to take effect.
|
||||
// this will allow any knockback to move stuff.
|
||||
gi.cvar_forceset("sv_stopspeed", "0");
|
||||
dball_team1_goalscore = 0;
|
||||
dball_team2_goalscore = 0;
|
||||
|
||||
gi.cvar_forceset(g_no_mines->name, "1");
|
||||
gi.cvar_forceset(g_no_nukes->name, "1");
|
||||
gi.cvar_forceset(g_dm_no_stack_double->name, "1");
|
||||
gi.cvar_forceset(g_friendly_fire->name, "0");
|
||||
//gi.cvar_forceset(g_no_mines->name, "1"); note: skin teams gone...
|
||||
|
||||
dball_team1_skin = gi.cvar("dball_team1_skin", "male/ctf_r", CVAR_NOFLAGS);
|
||||
dball_team2_skin = gi.cvar("dball_team2_skin", "male/ctf_b", CVAR_NOFLAGS);
|
||||
goallimit = gi.cvar("goallimit", "0", CVAR_NOFLAGS);
|
||||
}
|
||||
|
||||
//==================
|
||||
//==================
|
||||
void DBall_PostInitSetup()
|
||||
{
|
||||
edict_t *e;
|
||||
|
||||
e = nullptr;
|
||||
// turn teleporter destinations nonsolid.
|
||||
while ((e = G_FindByString<&edict_t::classname>(e, "misc_teleporter_dest")))
|
||||
{
|
||||
e->solid = SOLID_NOT;
|
||||
gi.linkentity(e);
|
||||
}
|
||||
|
||||
// count the ball start points
|
||||
dball_ball_startpt_count = 0;
|
||||
e = nullptr;
|
||||
while ((e = G_FindByString<&edict_t::classname>(e, "dm_dball_ball_start")))
|
||||
{
|
||||
dball_ball_startpt_count++;
|
||||
}
|
||||
|
||||
if (dball_ball_startpt_count == 0)
|
||||
gi.Com_Print("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, mod_t 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, mod_t mod)
|
||||
{
|
||||
if (targ != dball_ball_entity)
|
||||
return knockback;
|
||||
|
||||
if (knockback < 1)
|
||||
{
|
||||
// FIXME - these don't account for quad/double
|
||||
if (mod.id == MOD_ROCKET) // rocket
|
||||
knockback = 70;
|
||||
else if (mod.id == MOD_BFG_EFFECT) // bfg
|
||||
knockback = 90;
|
||||
else
|
||||
gi.Com_PrintFmt("zero knockback, mod {}\n", (int32_t) mod.id);
|
||||
}
|
||||
else
|
||||
{
|
||||
// FIXME - change this to an array?
|
||||
switch (mod.id)
|
||||
{
|
||||
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;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// gi.dprintf("mod: %d knockback: %d\n", mod, knockback);
|
||||
return knockback;
|
||||
}
|
||||
|
||||
// **************************
|
||||
// Goals
|
||||
// **************************
|
||||
|
||||
TOUCH(DBall_GoalTouch) (edict_t *self, edict_t *other, const trace_t &tr, bool other_touching_self) -> void
|
||||
{
|
||||
#if 0
|
||||
static char value[512];
|
||||
int team_score;
|
||||
int scorechange;
|
||||
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.has(SPAWNFLAG_DBALL_GOAL_TEAM1))
|
||||
{
|
||||
dball_team1_goalscore += (int) self->wait;
|
||||
team_score = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
dball_team2_goalscore += (int) self->wait;
|
||||
team_score = 2;
|
||||
}
|
||||
|
||||
// bump the score for everyone on the correct team.
|
||||
for (uint32_t j = 1; j <= game.maxclients; j++)
|
||||
{
|
||||
ent = &g_edicts[j];
|
||||
if (!ent->inuse)
|
||||
continue;
|
||||
if (!ent->client)
|
||||
continue;
|
||||
|
||||
if (ent == other->enemy)
|
||||
scorechange = (int) self->wait + 5;
|
||||
else
|
||||
scorechange = (int) self->wait;
|
||||
|
||||
Q_strlcpy(value, Info_ValueForKey(ent->client->pers.userinfo, "skin"), sizeof(value));
|
||||
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.Com_Print("unassigned player!!!!\n");
|
||||
}
|
||||
}
|
||||
|
||||
if (other->enemy)
|
||||
gi.Com_PrintFmt("score for team {} by {}\n", team_score, other->enemy->client->pers.netname);
|
||||
else
|
||||
gi.Com_PrintFmt("score for team {} by someone\n", team_score);
|
||||
|
||||
DBall_BallDie(other, other->enemy, other->enemy, 0, vec3_origin, MOD_SUICIDE);
|
||||
|
||||
G_UseTargets(self, other);
|
||||
#endif
|
||||
}
|
||||
|
||||
// **************************
|
||||
// Ball
|
||||
// **************************
|
||||
|
||||
edict_t *PickBallStart(edict_t *ent)
|
||||
{
|
||||
int which, current;
|
||||
edict_t *e;
|
||||
|
||||
which = irandom(dball_ball_startpt_count);
|
||||
e = nullptr;
|
||||
current = 0;
|
||||
|
||||
while ((e = G_FindByString<&edict_t::classname>(e, "dm_dball_ball_start")))
|
||||
{
|
||||
current++;
|
||||
if (current == which)
|
||||
return e;
|
||||
}
|
||||
|
||||
if (current == 0)
|
||||
gi.Com_Print("No ball start points found!\n");
|
||||
|
||||
return G_FindByString<&edict_t::classname>(nullptr, "dm_dball_ball_start");
|
||||
}
|
||||
|
||||
//==================
|
||||
// DBall_BallTouch - if the ball hit another player, hurt them
|
||||
//==================
|
||||
TOUCH(DBall_BallTouch) (edict_t *ent, edict_t *other, const trace_t &tr, bool other_touching_self) -> void
|
||||
{
|
||||
vec3_t dir;
|
||||
float dot;
|
||||
float speed;
|
||||
|
||||
if (other->takedamage == false)
|
||||
return;
|
||||
|
||||
// hit a player
|
||||
if (other->client)
|
||||
{
|
||||
if (ent->velocity[0] || ent->velocity[1] || ent->velocity[2])
|
||||
{
|
||||
speed = ent->velocity.length();
|
||||
|
||||
dir = ent->s.origin - other->s.origin;
|
||||
dot = dir.dot(ent->velocity);
|
||||
|
||||
if (dot > 0.7f)
|
||||
{
|
||||
T_Damage(other, ent, ent, vec3_origin, ent->s.origin, vec3_origin,
|
||||
(int) (speed / 10), (int) (speed / 10), DAMAGE_NONE, MOD_DBALL_CRUSH);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//==================
|
||||
// DBall_BallPain
|
||||
//==================
|
||||
PAIN(DBall_BallPain) (edict_t *self, edict_t *other, float kick, int damage, const mod_t &mod) -> void
|
||||
{
|
||||
self->enemy = other;
|
||||
self->health = self->max_health;
|
||||
// if(other->classname)
|
||||
// gi.Com_PrintFmt("hurt by {} -- {}\n", other->classname, self->health);
|
||||
}
|
||||
|
||||
DIE(DBall_BallDie) (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, const vec3_t &point, const mod_t &mod) -> void
|
||||
{
|
||||
// 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, false);
|
||||
|
||||
self->s.angles = {};
|
||||
self->velocity = {};
|
||||
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_sec;
|
||||
gi.linkentity(self);
|
||||
}
|
||||
|
||||
THINK(DBall_BallRespawn) (edict_t *self) -> void
|
||||
{
|
||||
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, false);
|
||||
|
||||
// move the ball and stop it
|
||||
start = PickBallStart(self);
|
||||
if (start)
|
||||
{
|
||||
self->s.origin = start->s.origin;
|
||||
self->s.old_origin = start->s.origin;
|
||||
}
|
||||
|
||||
self->s.angles = {};
|
||||
self->velocity = {};
|
||||
self->avelocity = {};
|
||||
|
||||
self->solid = SOLID_BBOX;
|
||||
self->s.modelindex = gi.modelindex("models/objects/dball/tris.md2");
|
||||
self->s.event = EV_PLAYER_TELEPORT;
|
||||
self->groundentity = nullptr;
|
||||
|
||||
gi.linkentity(self);
|
||||
|
||||
// kill anything at the destination
|
||||
KillBox(self, false);
|
||||
}
|
||||
|
||||
// ************************
|
||||
// SPEED CHANGES
|
||||
// ************************
|
||||
|
||||
constexpr spawnflags_t SPAWNFLAG_DBALL_SPEED_ONEWAY = 1_spawnflag;
|
||||
|
||||
TOUCH(DBall_SpeedTouch) (edict_t *self, edict_t *other, const trace_t &tr, bool other_touching_self) -> void
|
||||
{
|
||||
float dot;
|
||||
vec3_t vel;
|
||||
|
||||
if (other != dball_ball_entity)
|
||||
return;
|
||||
|
||||
if (self->timestamp >= level.time)
|
||||
return;
|
||||
|
||||
if (other->velocity.length() < 1)
|
||||
return;
|
||||
|
||||
if (self->spawnflags.has(SPAWNFLAG_DBALL_SPEED_ONEWAY))
|
||||
{
|
||||
vel = other->velocity;
|
||||
vel.normalize();
|
||||
dot = vel.dot(self->movedir);
|
||||
if (dot < 0.8f)
|
||||
return;
|
||||
}
|
||||
|
||||
self->timestamp = level.time + gtime_t::from_sec(self->delay);
|
||||
other->velocity *= self->speed;
|
||||
}
|
||||
|
||||
// ************************
|
||||
// SPAWN FUNCTIONS
|
||||
// ************************
|
||||
|
||||
/*QUAKED dm_dball_ball (1 .5 .5) (-48 -48 -48) (48 48 48) ONEWAY
|
||||
Deathball Ball
|
||||
*/
|
||||
void SP_dm_dball_ball(edict_t *self)
|
||||
{
|
||||
if (!deathmatch->integer)
|
||||
{
|
||||
G_FreeEdict(self);
|
||||
return;
|
||||
}
|
||||
|
||||
if (gamerules->integer != RDM_DEATHBALL)
|
||||
{
|
||||
G_FreeEdict(self);
|
||||
return;
|
||||
}
|
||||
|
||||
dball_ball_entity = self;
|
||||
// dball_ball_startpt = self->s.origin;
|
||||
|
||||
self->s.modelindex = gi.modelindex("models/objects/dball/tris.md2");
|
||||
self->mins = { -32, -32, -32 };
|
||||
self->maxs = { 32, 32, 32 };
|
||||
self->solid = SOLID_BBOX;
|
||||
self->movetype = MOVETYPE_NEWTOSS;
|
||||
self->clipmask = MASK_MONSTERSOLID;
|
||||
|
||||
self->takedamage = true;
|
||||
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->integer)
|
||||
{
|
||||
G_FreeEdict(self);
|
||||
return;
|
||||
}
|
||||
if (gamerules->integer != 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->integer)
|
||||
{
|
||||
G_FreeEdict(self);
|
||||
return;
|
||||
}
|
||||
if (gamerules->integer != 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->integer)
|
||||
{
|
||||
G_FreeEdict(self);
|
||||
return;
|
||||
}
|
||||
if (gamerules->integer != 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->integer)
|
||||
{
|
||||
G_FreeEdict(self);
|
||||
return;
|
||||
}
|
||||
if (gamerules->integer != RDM_DEATHBALL)
|
||||
{
|
||||
G_FreeEdict(self);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!self->speed)
|
||||
self->speed = 2;
|
||||
|
||||
if (!self->delay)
|
||||
self->delay = 0.2f;
|
||||
|
||||
self->touch = DBall_SpeedTouch;
|
||||
self->solid = SOLID_TRIGGER;
|
||||
self->movetype = MOVETYPE_NONE;
|
||||
self->svflags |= SVF_NOCLIENT;
|
||||
|
||||
if (self->s.angles)
|
||||
G_SetMovedir(self->s.angles, self->movedir);
|
||||
else
|
||||
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->integer)
|
||||
{
|
||||
G_FreeEdict(self);
|
||||
return;
|
||||
}
|
||||
|
||||
if (gamerules->integer != 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 (self->s.angles)
|
||||
G_SetMovedir(self->s.angles, self->movedir);
|
||||
|
||||
gi.setmodel(self, self->model);
|
||||
gi.linkentity(self);
|
||||
}
|
||||
Reference in New Issue
Block a user