sof-sdk/Source/Game/gamecpp/dm.cpp
2000-06-15 00:00:00 +00:00

1301 lines
No EOL
27 KiB
C++

// *****************************************************************************
// dm.cpp
// *****************************************************************************
#include "g_local.h"
#include "dm_private.h"
#include "w_weapons.h"
#include "../strings/dm_generic.h"
#include "ai_private.h" // so we know what a bodyhuman_c is
#include "..\qcommon\configstring.h"
gamemode_ic *dm = NULL;
dmnone_c nodm;
dmstandard_c standard;
dmassassin_c assassin;
dmarsenal_c arsenal;
dmctf_c ctf;
dmreal_c real;
gamerules_c *gamerules[] =
{
&nodm,
&standard,
&assassin,
&arsenal,
&ctf,
&real
};
extern void W_InitInv(edict_t &ent);
extern void sendRestartPrediction(edict_t *ent);
/*
=================
countPlayers
Returns the number of players in the current game.
=================
*/
int countPlayers(void)
{
int i;
edict_t *e2;
int num = 0;
for(i = 1; i <= game.maxclients; i++)
{
e2 = &g_edicts[i];
if (!e2->inuse)
continue;
if (!e2->client)
continue;
if (e2->client->pers.spectator)
continue;
num++;
}
return(num);
}
/*
=================
IsFemale
=================
*/
qboolean IsFemale(edict_t *ent)
{
if(!ent->client || !ent->client->body)
return false;
if (ent->client->body->GetClassCode()==BODY_FEMALE)
{
return (true);
}
return(false);
}
/*
==============
setPlayernameColor
==============
*/
void setPlayernameColor(edict_t &ent,edict_t &other,byte color)
{
if(!ent.client)
return;
if(other.inuse)
ent.client->playernameColors[other.s.number-1]=color;
}
/*
=================
InitDeathmatchSystem
=================
*/
void InitDeathmatchSystem(void)
{
if(!dm)
{
dm = new gamemode_c;
}
#ifndef _DEMO_
dm->setDMMode(((deathmatch->value>=DM_NONE)&&(deathmatch->value<=DM_REAL))?deathmatch->value:0);
#else
dm->setDMMode(((deathmatch->value>=DM_NONE)&&(deathmatch->value<=DM_STANDARD))?deathmatch->value:0);
#endif
gi.SP_Register("dm_generic");
// Generic DM specific precaching and stuff.
if(dm->isDM())
{
// Precache generic DM effects.
// gi.effectindex("environ/invuln");
gi.effectindex("environ/irespawn");
gi.effectindex("environ/prespawn");
// Precache generic DM sounds.
gi.soundindex("dm/armorpu.wav");
gi.soundindex("dm/irespawn.wav");
gi.soundindex("dm/frag.wav");
gi.soundindex("dm/selffrag.wav");
gi.soundindex("dm/healthpu.wav");
gi.soundindex("dm/prespawn.wav");
}
// Clear the CTF team color config strings, used to tell clients what blue
// and red team names are.
gi.configstring(CS_CTF_BLUE_TEAM, "");
gi.configstring(CS_CTF_RED_TEAM, "");
dm->preLevelInit();
}
/*
=================
DeleteDeathmatchSystem
=================
*/
void DeleteDeathmatchSystem(void)
{
if(dm)
{
delete dm;
dm=0;
}
}
/*
==================
respawnUntouchedItem
==================
This item was dropped at some point and hasn't been touched in a while. Move it
to its designer-specified spawn point.
*/
void respawnUntouchedItem(edict_t* ent)
{
dm->respawnUntouchedItem(ent);
}
/*
===============
ClearEffects
===============
*/
void ClearEffects (edict_t *ent)
{
// This also makes the item solid.
fxRunner.clearContinualEffects(ent);
}
/*
===============
DoRespawn
===============
*/
void DoRespawn (edict_t *ent)
{
ent->flags &= ~FL_RESPAWN;
ent->svflags &= ~SVF_NOCLIENT;
ent->solid = SOLID_NOT;
ent->touch_debounce_time = 0.0;
gi.linkentity(ent);
// Send a respawning effect.
fxRunner.exec("environ/irespawn", ent->s.origin);
// 1/4/00 kef -- play a "fade in" anim. at the end of that anim, switch back to non-fade anim.
PickupInst *pickupInst = thePickupList.GetPickupInstFromEdict(ent);
if (pickupInst)
{
pickupInst->FadeIn();
}
// Respawn sound. FIXME: Make part of FX? Not sure about PHS issues here tho'?
gi.sound(ent, CHAN_ITEM, gi.soundindex("dm/irespawn.wav"), .6, ATTN_NORM, 0);
ent->think = ClearEffects;
ent->nextthink = level.time + ITEM_RESPAWN_FADEIN;
}
/*
================
itemDropToFloor
Adjust the Z component of an ent's origin of so that it lies on the floor.
================
*/
void itemDropToFloor (edict_t *ent)
{
trace_t tr;
vec3_t vec,dest;
VectorSet(vec,0.0,0.0,-128.0);
VectorAdd (ent->s.origin, vec, dest);
gi.trace (ent->s.origin, ent->mins, ent->maxs, dest, ent, MASK_SOLID, &tr);
if (tr.startsolid)
{
gi.dprintf ("itemDropToFloor: %s startsolid at %s\n", ent->classname, vtos(ent->s.origin));
G_FreeEdict (ent);
return;
}
VectorCopy (tr.endpos, ent->s.origin);
ent->nextthink = level.time + FRAMETIME;
ent->think = DoRespawn;
}
/*
===============
gamerules_c::setRespawn
===============
*/
void gamerules_c::setRespawn (edict_t *ent, float delay)
{
float adjusted_delay;
int clients;
ent->flags |= FL_RESPAWN;
ent->svflags |= SVF_NOCLIENT;
ent->solid = SOLID_NOT;
if (deathmatch->value)
{
clients=(float)level.num_clients;
if (clients<2.0)
clients=2.0;
adjusted_delay = delay * sqrt(2.0/clients); // Spawn more frequently when more players.
// Lemme see here: sqrt(2/2) = sqrt(1) = 1
// sqrt(2/8) = sqrt(1/4) = 1/2
// sqrt(2/32) = sqrt(1/16) = 1/4
}
else
{
adjusted_delay = delay;
}
ent->nextthink = level.time + adjusted_delay;
ent->think = DoRespawn;
gi.linkentity (ent);
}
/*
==================
gamerules_c::openLogFile
==================
*/
void gamerules_c::openLogFile(void)
{
if(log_file_name->string[0])
{
char name[MAX_QPATH];
// Try to open the log-file.
// do we need a counter value?
Com_sprintf (name, sizeof(name), "%s", log_file_name->string);
if (log_file_counter->value)
{
char exten[10];
// copy the extension somewhere
strcpy(exten, COM_FileExtension(name));
// remove the extension from the file name
COM_StripExtension(name, name);
// add in number
Com_sprintf (name, sizeof(name), "%s%d.", name, (int)log_file_counter->value);
gi.cvar_setvalue("log_file_counter", log_file_counter->value +1.0);
// re-add extension
strcat(name, exten);
}
Com_Printf ("Dumping end game log to %s\n", name);
gi.FS_CreatePath (name);
// decide what we need to do, append or overwrite
if (!stricmp(log_file_mode->string, "o"))
{
filePtr = fopen (name, "w");
}
else
{
filePtr = fopen (name, "a");
}
// If we managed to open the log-file, write out the game details, else
// print an error message.
if(filePtr)
{
int hours,secs,mins;
cvar_t *host_name;
secs = level.time;
hours = secs / (60*60);
secs -= hours * (60*60);
mins = secs / 60;
secs -= mins * 60;
host_name = gi.cvar("hostname", "", 0);
fprintf (filePtr, "%s\n", log_file_header->string);
fprintf (filePtr, "%sMap Name : %s\n", log_file_line_header->string, level.mapname);
fprintf (filePtr, "%sHost Name : %s\n", log_file_line_header->string, host_name->string);
fprintf (filePtr, "%sGame type : %s\n", log_file_line_header->string, getGameName());
fprintf (filePtr, "%sGame Duration : %02i:%02i:%02i\n%s\n", log_file_line_header->string, hours, mins, secs, log_file_line_header->string);
}
else
{
Com_Printf("ERROR: couldn't open game log-file.\n");
}
}
}
/*
==================
gamerules_c::closeLogFile
==================
*/
void gamerules_c::closeLogFile(void)
{
if(filePtr)
{
fprintf(filePtr,"%s\n",log_file_footer->string);
fclose(filePtr);
}
}
/*
==================
gamerules_c::clientConnect
==================
*/
void gamerules_c::clientConnect(edict_t &ent)
{
// I see my own playername in TC_BLACK.
setPlayernameColor(ent,ent,0);
// I see all other players' playernames in TC_BLACK.
edict_t *other;
int i;
for(i=1;i<=game.maxclients;i++)
{
other=&g_edicts[i];
if(!other->inuse)
continue;
if(!other->client)
continue;
if(other!=&ent)
setPlayernameColor(ent,(edict_t &)*other,0);
}
// All other players see my playername in TC_BLACK.
for(i=1;i<=game.maxclients;i++)
{
other=&g_edicts[i];
if(!other->inuse)
continue;
if(!other->client)
continue;
if(other!=&ent)
setPlayernameColor((edict_t &)*other,ent,0);
}
}
/*
==================
gamerules_c::clientSetDroppedItemThink
==================
*/
static void droppedItemThink(edict_t *ent)
{
// fxRunner.exec("environ/teleport7", ent->s.origin);
G_FreeEdict(ent);
return;
}
void gamerules_c::clientSetDroppedItemThink(edict_t *ent)
{
ent->think=droppedItemThink;
ent->nextthink=level.time+20.0F;
}
/*
==================
gamerules_c::clientDropItem
==================
*/
void gamerules_c::clientDropItem(edict_t *ent,int type,int ammoCount)
{
if (!ent->ghoulInst)
{
return;
}
Pickup *pickup = NULL;
if (pickup = thePickupList.GetPickupFromType(PU_INV, type))
{
edict_t *dropped;
Matrix4 ZoneMatrix;
Vect3 zonePos;
vec3_t handPos,
dir;
// Whatever weapon player is holding, throw one off.
dropped=G_Spawn();
dropped->spawnflags|=DROPPED_ITEM;
I_Spawn(dropped,pickup);
dropped->enemy=ent;
dropped->touch_debounce_time=level.time+2.0;
ent->ghoulInst->
GetBoltMatrix(level.time,
ZoneMatrix,
ent->ghoulInst->GetGhoulObject()->FindPart("wbolt_hand_l"),
IGhoulInst::MatrixType::Entity);
ZoneMatrix.GetRow(3,zonePos);
handPos[0]=zonePos[0];
handPos[1]=zonePos[1];
handPos[2]=zonePos[2];
VectorAdd(ent->s.origin,handPos,dropped->s.origin);
AngleVectors(ent->client->ps.viewangles,dir,NULL, NULL);
dir[2] = 0;
VectorNormalize(dir);
VectorMA(dropped->s.origin, 20.0, dir, dropped->s.origin);
VectorScale(dir,250.0,dropped->velocity);
dropped->velocity[2]+=150.0;
dropped->health = ammoCount;
clientSetDroppedItemThink(dropped);
}
}
/*
==================
gamerules_c::clientSetDroppedWeaponThink
==================
*/
static void droppedWeaponThink(edict_t *ent)
{
// fxRunner.exec("environ/teleport7", ent->s.origin);
G_FreeEdict(ent);
return;
}
void gamerules_c::clientSetDroppedWeaponThink(edict_t *ent)
{
ent->think=droppedWeaponThink;
ent->nextthink=level.time+20.0F;
}
/*
==================
gamerules_c::clientDieWeaponHandler
==================
*/
void gamerules_c::clientDieWeaponHandler(edict_t *ent)
{
sharedEdict_t sh;
sh.inv=(inven_c *)ent->client->inv;
sh.edict=ent;
sh.inv->setOwner(&sh);
sh.inv->rulesSetDropWeapons(-1);
sh.inv->handlePlayerDeath();
if(IGhoulInst *gun=ent->client->ps.gun)
gun->SetAllPartsOnOff(false);
}
/*
==================
gamerules_c::clientDropWeapon
==================
*/
void gamerules_c::clientDropWeapon(edict_t *ent,int type, int clipSize)
{
if (!ent->ghoulInst)
{
return;
}
Pickup *pickup = NULL;
if (pickup = thePickupList.GetPickupFromType(PU_WEAPON, type))
{
edict_t *dropped;
Matrix4 ZoneMatrix;
Vect3 zonePos;
vec3_t handPos,
dir;
// Whatever weapon player is holding, throw one off.
dropped=G_Spawn();
dropped->spawnflags|=DROPPED_ITEM;
I_Spawn(dropped,pickup);
dropped->enemy=ent;
dropped->touch_debounce_time=level.time+2.0;
ent->ghoulInst->
GetBoltMatrix(level.time,
ZoneMatrix,
ent->ghoulInst->GetGhoulObject()->FindPart("wbolt_hand_r"),
IGhoulInst::MatrixType::Entity);
ZoneMatrix.GetRow(3,zonePos);
handPos[0]=zonePos[0];
handPos[1]=zonePos[1];
handPos[2]=zonePos[2];
VectorAdd(ent->s.origin,handPos,dropped->s.origin);
AngleVectors(ent->client->ps.viewangles,dir,NULL, NULL);
dir[2] = 0;
VectorNormalize(dir);
// 2/3/00 dk -- We need to see if we can spawn the weapon at a point in front of the player.
// If we can't, just spawn it as close as we can. Without this test, a player with his face against the wall may end
// up dropping it on the other side of that wall.
vec3_t spawnPoint;
trace_t trace;
VectorMA(dropped->s.origin, 20.0, dir, spawnPoint);
dropped->owner = ent; // don't want player to interfere with trace
gi.trace(dropped->s.origin, dropped->mins, dropped->maxs, spawnPoint, dropped, MASK_SOLID, &trace);
if (trace.fraction < 1)
{
if (trace.startsolid) // ugh, we're probably in a corner trying to drop a weapon that won't fit.
// well, try behind us a bit
{
vec3_t backPoint;
VectorMA(dropped->s.origin, -10, dir, backPoint);
gi.trace(backPoint, dropped->mins, dropped->maxs, dropped->s.origin, dropped, MASK_SOLID, &trace);
VectorMA(backPoint, 10.0 * trace.fraction, dir, dropped->s.origin);
}
else
{
VectorMA(dropped->s.origin, 20.0 * trace.fraction, dir, dropped->s.origin);
}
}
else
{
VectorCopy(spawnPoint, dropped->s.origin);
}
dropped->owner = NULL;
VectorScale(dir,250.0,dropped->velocity);
dropped->velocity[2]+=150.0;
dropped->health = clipSize;
clientSetDroppedWeaponThink(dropped);
if(ent->health>0)
{
const char *weapon = gi.SP_GetStringText(pickup->GetDroppedStringIndex());
gi.SP_Print(ent,DM_GENERIC_TEXT_DROPPED_WEAPON,weapon);
}
}
}
/*
==================
gamerules_c::clientHandlePredn
==================
*/
void gamerules_c::clientHandlePredn(edict_t &ent)
{
// Start with a zero init'd inventory and issue a (reliable) instruction to
// restart the player's client-side inventory system.
W_InitInv(ent);
sendRestartPrediction(&ent);
}
/*
==================
gamerules_c::clientObituary
==================
*/
void gamerules_c::clientObituary(edict_t *self, edict_t *inflictor, edict_t *attacker)
{
int mod,
message;
mod = meansOfDeath & ~MOD_FRIENDLY_FIRE;
message = -1;
switch (mod)
{
case MOD_WATER:
message = DM_GENERIC_TEXT_OBT_MOD_WATER;
break;
case MOD_SLIME:
message = DM_GENERIC_TEXT_OBT_MOD_SLIME;
break;
case MOD_CRUSH:
message = DM_GENERIC_TEXT_OBT_MOD_CRUSH;
break;
case MOD_FALLING:
message = DM_GENERIC_TEXT_OBT_MOD_FALLING;
break;
case MOD_SUICIDE:
message = DM_GENERIC_TEXT_OBT_MOD_SUICIDE;
break;
case MOD_EXPLOSIVE:
message = DM_GENERIC_TEXT_OBT_MOD_EXPLOSIVE;
break;
case MOD_FIRE:
message = DM_GENERIC_TEXT_OBT_MOD_FIRE;
break;
case MOD_LAVA:
message = DM_GENERIC_TEXT_OBT_MOD_LAVA;
break;
case MOD_EXIT:
message = DM_GENERIC_TEXT_OBT_MOD_EXIT;
break;
case MOD_BARBWIRE:
message = DM_GENERIC_TEXT_OBT_MOD_BARBWIRE;
break;
case MOD_DOGBITE:
message = DM_GENERIC_TEXT_OBT_MOD_DOGBITE;
break;
}
if(attacker == self)
{
switch (mod)
{
case MOD_PHOS_GRENADE:
message = DM_GENERIC_TEXT_OBT_MOD_PHOS_GRENADE;
break;
case MOD_ROCKET_SPLASH:
if (IsFemale(self))
message = DM_GENERIC_TEXT_OBT_MOD_ROCKET_SPLASH_F;
else
message = DM_GENERIC_TEXT_OBT_MOD_ROCKET_SPLASH_M;
break;
case MOD_C4:
if (IsFemale(self))
message = DM_GENERIC_TEXT_OBT_MOD_C4_F;
else
message = DM_GENERIC_TEXT_OBT_MOD_C4_M;
break;
case MOD_CLAYMORE:
message = DM_GENERIC_TEXT_OBT_MOD_CLAYMORE;
break;
case MOD_NEURAL_GRENADE:
if (IsFemale(self))
message = DM_GENERIC_TEXT_OBT_MOD_NEURAL_GRENADE_F;
else
message = DM_GENERIC_TEXT_OBT_MOD_NEURAL_GRENADE_M;
break;
case MOD_GRENADE:
if (IsFemale(self))
message = DM_GENERIC_TEXT_OBT_MOD_GRENADE_F;
else
message = DM_GENERIC_TEXT_OBT_MOD_GRENADE_M;
break;
default:
if (IsFemale(self))
message = DM_GENERIC_TEXT_OBT_F;
else
message = DM_GENERIC_TEXT_OBT_M;
break;
}
}
if(message>-1)
{
gi.SP_Print_Obit(0,message,self->s.number);
if (dedicated->value)
{
char consoleMsg[MAX_OSPATH];
gi.SP_SPrint(consoleMsg, MAX_OSPATH, message, self->s.number);
gi.Sys_ConsoleOutput (consoleMsg);
}
self->enemy = NULL;
return;
}
self->enemy = attacker;
if(attacker && attacker->client)
{
switch (mod)
{
case MOD_KNIFE_SLASH:
message = DM_GENERIC_TEXT_OBT_MOD_KNIFE_SLASH;
break;
case MOD_KNIFE_THROWN:
message = DM_GENERIC_TEXT_OBT_MOD_KNIFE_THROWN;
break;
case MOD_PISTOL1:
message = DM_GENERIC_TEXT_OBT_MOD_PISTOL1;
break;
case MOD_PISTOL2:
message = DM_GENERIC_TEXT_OBT_MOD_PISTOL2;
break;
case MOD_MPISTOL:
message = DM_GENERIC_TEXT_OBT_MOD_MPISTOL;
break;
case MOD_ASSAULTRIFLE:
message = DM_GENERIC_TEXT_OBT_MOD_ASSAULTRIFLE;
break;
case MOD_SNIPERRIFLE:
message = DM_GENERIC_TEXT_OBT_MOD_SNIPERRIFLE;
break;
case MOD_AUTOSHOTGUN:
message = DM_GENERIC_TEXT_OBT_MOD_AUTOSHOTGUN;
break;
case MOD_SHOTGUN:
message = DM_GENERIC_TEXT_OBT_MOD_SHOTGUN;
break;
case MOD_MACHINEGUN:
message = DM_GENERIC_TEXT_OBT_MOD_MACHINEGUN;
break;
case MOD_PHOS_GRENADE:
message = DM_GENERIC_TEXT_OBT_MOD_PHOS_GRENADE_2;
break;
case MOD_ROCKET:
message = DM_GENERIC_TEXT_OBT_MOD_ROCKET;
break;
case MOD_ROCKET_SPLASH:
message = DM_GENERIC_TEXT_OBT_MOD_ROCKET_SPLASH;
break;
case MOD_MPG:
message = DM_GENERIC_TEXT_OBT_MOD_MPG;
break;
case MOD_FLAMEGUN:
message = DM_GENERIC_TEXT_OBT_MOD_FLAMEGUN;
break;
case MOD_FLAMEGUN_NAPALM:
message = DM_GENERIC_TEXT_OBT_MOD_FLAMEGUN_NAPALM;
break;
case MOD_C4:
message = DM_GENERIC_TEXT_OBT_MOD_C4;
break;
case MOD_CLAYMORE:
message = DM_GENERIC_TEXT_OBT_MOD_CLAYMORE_2;
break;
case MOD_NEURAL_GRENADE:
message = DM_GENERIC_TEXT_OBT_MOD_NEURAL_GRENADE;
break;
case MOD_TELEFRAG:
message = DM_GENERIC_TEXT_OBT_MOD_TELEFRAG;
break;
case MOD_GRENADE:
message = DM_GENERIC_TEXT_OBT_MOD_GRENADE_2;
break;
case MOD_CONC_GRENADE:
message = DM_GENERIC_TEXT_OBT_MOD_CONC_GRENADE;
break;
}
if(message>-1)
{
gi.SP_Print_Obit(0,message,self->s.number,attacker->s.number);
if (dedicated->value)
{
char consoleMsg[MAX_OSPATH];
gi.SP_SPrint(consoleMsg, MAX_OSPATH, message, self->s.number, attacker->s.number);
gi.Sys_ConsoleOutput (consoleMsg);
}
return;
}
}
gi.SP_Print_Obit(0,DM_GENERIC_TEXT_OBT_DIED,self->s.number);
if (dedicated->value)
{
char consoleMsg[MAX_OSPATH];
if (message>-1)
{
gi.SP_SPrint(consoleMsg, MAX_OSPATH, message, self->s.number);
gi.Sys_ConsoleOutput (consoleMsg);
}
else
{
gi.SP_SPrint(consoleMsg, MAX_OSPATH, DM_GENERIC_TEXT_OBT_DIED, self->s.number);
gi.Sys_ConsoleOutput (consoleMsg);
}
}
}
/*
==================
gamerules_c::clientScoreboardMessage
==================
*/
int TeamCompare(void const *a, void const *b)
{
struct TeamInfo_s *A, *B;
A = (struct TeamInfo_s *)a;
B = (struct TeamInfo_s *)b;
return (A->score < B->score);
}
void gamerules_c::clientScoreboardMessage (edict_t *ent, edict_t *killer, qboolean log_file)
{
int i,j,k;
int sorted[MAX_CLIENTS];
int sortedscores[MAX_CLIENTS];
struct TeamInfo_s teams[MAX_CLIENTS];
int score,total,total_teams, real_total;
int x,y,top;
gclient_t *cl;
edict_t *cl_ent;
total=total_teams = 0;
// Is logging to a log-file enabled?
if(log_file)
openLogFile();
// Sort all the clients by score from highest to lowest.
for(i=0;i<game.maxclients;i++)
{
cl_ent=g_edicts+1+i;
if(!cl_ent->inuse)
continue;
// Spectators get added separately if there's any room left.
if(cl_ent->client->resp.spectator)
continue;
score=game.clients[i].resp.score;
for(j=0;j<total;j++)
{
if(score>sortedscores[j])
{
break;
}
}
for(k=total;k>j;k--)
{
sorted[k]=sorted[k-1];
sortedscores[k]=sortedscores[k-1];
}
sorted[j]=i;
sortedscores[j]=score;
total++;
if(!dm->dmRule_TEAMPLAY())
continue;
if(!strcmp(Info_ValueForKey(cl_ent->client->pers.userinfo, "skin"),Info_ValueForKey (cl_ent->client->pers.userinfo, "teamname")))
{
// Ensure those clients with no team affiliation (i.e. skin == teamname)
// don't produce a team aggregate score.
continue;
}
for(j=0;j<total_teams;j++)
{
if (OnSameTeam(g_edicts + 1 + teams[j].rep, cl_ent))
{
teams[j].score += score;
break;
}
}
if (j == total_teams)
{
teams[total_teams].rep = i;
teams[total_teams].score = score;
teams[total_teams].teamname = Info_ValueForKey (cl_ent->client->pers.userinfo, "teamname");
total_teams++;
}
}
qsort((void *)teams, total_teams, sizeof(TeamInfo_s), TeamCompare);
real_total=total;
if(total>12)
{
total=12;
}
if (total_teams > 6)
{
total_teams = 6;
}
// Clear the client's layout.
top=32;
gi.SP_Print(ent,DM_GENERIC_LAYOUT_RESET);
// Handle team aggregate scores if teamplay is on.
if (dm->dmRule_TEAMPLAY())
{
top = -64;
y = top;
for(i=0;i<total_teams;i++)
{
x=(i>=3)?160:0;
if(i==3)
{
y = top;
}
gi.SP_Print(ent,DM_GENERIC_LAYOUT_SCOREBOARD_TEAM,
(short)x,(short)y,
teams[i].rep,
(short)teams[i].score);
// Write the scores to the open log-file if we have one.
if(filePtr)
{
fprintf(filePtr,"%sTeam %s\n",log_file_line_header->string,teams[i].teamname);
fprintf(filePtr,"%sScore %i\n",log_file_line_header->string,teams[i].score);
}
y+=32;
}
if(filePtr)
{
fprintf(filePtr,"\n");
}
if (total_teams >= 3)
{
top=64;
}
else
{
top = 32;
}
}
y = top;
// Send the scores for all active players to the client's layout.
for(i=0;i<total;i++)
{
cl=&game.clients[sorted[i]];
cl_ent=g_edicts+1+sorted[i];
x=(i>=6)?160:0;
if(i==6)
y=top;
gi.SP_Print(ent,DM_GENERIC_LAYOUT_SCOREBAORD_CLIENT,
(short)x,(short)y,
sorted[i],
(short)cl->resp.score,
(unsigned short)cl->ping,
(unsigned short)((level.framenum-cl->resp.enterframe)/600));
y+=32;
}
// Send the scores for all spectators to the client's layout - if there's
// any room left on the scoreboard.
j=0;
while((j<game.maxclients)&&(i<12))
{
cl=&game.clients[j];
cl_ent=g_edicts+1+j;
if((!cl_ent->inuse)||(!cl_ent->client->resp.spectator))
{
j++;
continue;
}
x=(i>=6)?160:0;
if(i==6)
y=top;
gi.SP_Print(ent,DM_GENERIC_LAYOUT_SCOREBAORD_SPECTATOR,
(short)x,(short)y,
j,
(unsigned short)cl->ping,
(unsigned short)((level.framenum-cl->resp.enterframe)/600));
y+=32;
i++;
j++;
}
// Write the scores to the open log-file if we have one.
if(filePtr)
{
// Active players.
for(i=0;i<real_total;i++)
{
cl=&game.clients[sorted[i]];
cl_ent=g_edicts+1+sorted[i];
fprintf(filePtr,"%sClient %s\n",log_file_line_header->string,cl_ent->client->pers.netname);
fprintf(filePtr,"%sScore %i\n",log_file_line_header->string,cl->resp.score);
fprintf(filePtr,"%sPing %i\n",log_file_line_header->string,cl->ping);
fprintf(filePtr,"%sTime %i\n%s\n",log_file_line_header->string,(level.framenum-cl->resp.enterframe)/600,log_file_line_header->string);
}
// Spectators.
for(i=0;i<game.maxclients;i++)
{
cl=&game.clients[i];
cl_ent=g_edicts+1+i;
if((!cl_ent->inuse)||(!cl_ent->client->resp.spectator))
continue;
fprintf(filePtr,"%sClient %s\n",log_file_line_header->string,cl_ent->client->pers.netname);
fprintf(filePtr,"%s %s\n",log_file_line_header->string,"spectator");
fprintf(filePtr,"%sPing %i\n",log_file_line_header->string,cl->ping);
fprintf(filePtr,"%sTime %i\n%s\n",log_file_line_header->string,(level.framenum-cl->resp.enterframe)/600,log_file_line_header->string);
}
}
// Close the open log file if we have one.
closeLogFile();
}
/*
==================
gamerules_c::clientCalculateWaver
==================
*/
float gamerules_c::clientCalculateWaver(edict_t &ent, int atkID)
{
bodyhuman_c *body = NULL;
float waverAmount = 0, speed = 0;
// check for arm damage.
if (body = (bodyhuman_c*)ent.client->body)
{ // IsAimImpeded returns -1 if left arm, 1 if right arm. for now, though, I think
//all we care about is the fact that we took an arm hit
if (body->IsAimImpeded())
{
waverAmount += 3; // totally guessing here. additionally, shouldn't be hardcoded.
}
}
// check speed
speed = DotProduct(ent.velocity, ent.velocity);
speed *= 3.0 / 80000.0;//max possible miss fire is 30 degrees
waverAmount += speed;
// check for Sniper rifle, add waver based on zoom
if((atkID == ATK_SNIPER)/* || (atkID == ATK_SNIPER_ALT)*/)
{
// This waver based on a desired maximum waver of 4.5 when not zoomed (fov == 95),
// then a linearly decreasing slope from 2 at minimum zoom (fov == 60),
// to no waver when maximally zoomed (fov == 6). Thus:
// (CurrentFOV - FOV@MaxZoom) * MaxWaver (CurrentFOV - 6) * 2
// waver = --------------------------------------- = --------------------------
// (FOV@MinZoom - FOV@MaxZoom) (60 - 6)
if(ent.client->ps.fov > 60)
{
waverAmount = 4.5;
}
else
{
waverAmount = 0;//((ent.client->ps.fov - 6) * .037);
}
}
return waverAmount;
}
/*
====================
gamerules_c::clientGetMovescale
====================
*/
float gamerules_c::clientGetMovescale(edict_t *ent)
{
return(g_movescale->value-(g_movescale->value*ent->client->moveScale));
}
/*
====================
gamerules_c::IsUnprotectedGoreZone
====================
*/
bool gamerules_c::IsUnprotectedGoreZone(gz_code zone)
{
if ((zone == GZ_SHLDR_RIGHT_FRONT) || (zone == GZ_SHLDR_RIGHT_BACK) || (zone == GZ_SHLDR_LEFT_FRONT) ||
(zone == GZ_SHLDR_LEFT_BACK) || (zone == GZ_CHEST_FRONT) || (zone == GZ_CHEST_BACK) ||
(zone == GZ_GUT_FRONT_EXTRA) || (zone == GZ_GUT_BACK_EXTRA))
{
return false;
}
return true;
}
/*
====================
gamerules_c::IsLimbZone
====================
*/
bool gamerules_c::IsLimbZone(gz_code zone)
{
if ((zone == GZ_ARM_UPPER_RIGHT) || (zone == GZ_ARM_UPPER_LEFT) || (zone == GZ_ARM_LOWER_RIGHT) ||
(zone == GZ_ARM_LOWER_LEFT) || (zone == GZ_LEG_UPPER_RIGHT_FRONT) || (zone == GZ_LEG_UPPER_RIGHT_BACK) ||
(zone == GZ_LEG_UPPER_LEFT_FRONT) || (zone == GZ_LEG_UPPER_LEFT_BACK) || (zone == GZ_LEG_LOWER_RIGHT) ||
(zone == GZ_LEG_LOWER_LEFT) || (zone == GZ_FOOT_RIGHT) || (zone == GZ_FOOT_LEFT))
{
return true;
}
return false;
}
/*
====================
gamerules_c::IsShootableWeapon
====================
*/
bool gamerules_c::IsShootableWeapon(char *weaponname)
{
if(!strcmp(weaponname, "w_pistol1") || !strcmp(weaponname, "w_knife"))
{
return false;
}
return true;
}
/*
==================
gamemode_c::setDMMode
==================
*/
void gamemode_c::setDMMode(int newtype)
{
gametype = newtype;
rules = gamerules[newtype];
gi.configstring(CS_SHOWNAMES,rules->arePlayerNamesOn()?"1":"0");
gi.configstring(CS_SHOWTEAMS,rules->arePlayerTeamsOn()?"1":"0");
rules->registerPlayerIcons();
}