sof-sdk/Source/Game/gamecpp/dm_arsenal.cpp

519 lines
10 KiB
C++
Raw Permalink Normal View History

2000-06-15 00:00:00 +00:00
// *****************************************************************************
// dm_arsenal.cpp
// *****************************************************************************
#include "g_local.h"
#include "dm_private.h"
#include "w_weapons.h"
#include "../strings/dm_arsenal.h"
const int DF_ARSENAL_NO_HEALTH = (1<<0);
const int DF_ARSENAL_NO_ITEMS = (1<<1);
const int DF_ARSENAL_NO_FALLING = (1<<3);
const int DF_ARSENAL_REALISTIC_DAMAGE = (1<<4);
const int DF_ARSENAL_SAME_LEVEL = (1<<5);
const int DF_ARSENAL_FORCE_RESPAWN = (1<<9);
const int DF_ARSENAL_NO_ARMOR = (1<<10);
void sendRestartPrediction(edict_t *ent);
/*
=================
getPlayerDMInfo
=================
*/
static player_dmarsenalInfo_c *getPlayerDMInfo(const edict_t *ent)
{
return((player_dmarsenalInfo_c *)ent->client->dmInfo);
}
/*
==================
SendStatusInfo
==================
*/
static void SendStatusInfo(edict_t *ent)
{
if(level.intermissiontime)
return;
if(ent->client->pers.spectator)
return;
gi.SP_Print(ent,DM_ARSENAL_LAYOUT_STATUS,ent->client->inv->countWeapons());
}
/*
==================
SendStatusInfo2
==================
*/
static void SendStatusInfo2(edict_t *ent)
{
if(level.intermissiontime)
return;
if(ent->client->pers.spectator)
return;
ent->client->showinventory=false;
ent->client->showscores=false;
ent->client->showhelp_time=level.time+5.0;
SendStatusInfo(ent);
gi.unicast(ent,true);
}
/*
==================
dmarsenal_c::checkEvents
==================
*/
void dmarsenal_c::checkEvents(void)
{
if(resetGame==-1)
{
resetGame=0;
int i;
edict_t *e2;
// Reset the weapons for everyone as a new round is about to start.
setWeapons();
for (i = 1; i <= game.maxclients; i++)
{
e2 = &g_edicts[i];
if (!e2->inuse)
continue;
if (!e2->client)
continue;
assert(e2->client->inv);
sharedEdict_t sh;
sh.inv = (inven_c *)e2->client->inv;
sh.edict = e2;
sh.inv->setOwner(&sh);
e2->client->inv->deactivateCurrentWeapon();
e2->client->inv->deactivateInventory();
giveClientWeapons(*e2,true);
SendStatusInfo2(e2);
}
}
}
/*
==================
dmarsenal_c::setWeapons
==================
*/
void dmarsenal_c::setWeapons(void)
{
int count,
bit,
tot,
max;
count=0;
tot=0;
max=SFW_NUM_WEAPONS-3;
while(1)
{
if((bit=gi.flrand(1,max+1))>max)
bit=max;
tot|=1<<(bit-1);
count=0;
for(int i=1;i<=max;i++)
{
if(tot&(1<<(i-1)))
{
weaponForSlot[count]=i;
count++;
}
}
if(count>=ARSENAL_MAXWEAPONS)
break;
}
firstToOneHit=0;
resetGame=0;
}
/*
==================
dmarsenal_c::giveClientWeapons
==================
*/
void dmarsenal_c::giveClientWeapons(edict_t &ent,qboolean newInv)
{
if(newInv)
{
W_InitInv(ent);
sendRestartPrediction(&ent);
}
sharedEdict_t sh;
sh.inv = (inven_c *)ent.client->inv;
sh.edict = &ent;
sh.inv->setOwner(&sh);
sh.inv->clearInv(true);
sh.inv->rulesSetWeaponsUseAmmo(0);
sh.inv->rulesSetDropWeapons(0);
sh.inv->rulesSetWeaponsReload(0);
sh.inv->rulesSetBestWeaponMode("unsafe");
sh.inv->rulesSetFreelySelectWeapon(0);
if(newInv)
{
for(int i = 0; i < ARSENAL_MAXWEAPONS; i++)
sh.inv->addWeaponType(weaponForSlot[i],0);
// Save off weapons and inventory counts.
sh.inv->buildInvString(getPlayerDMInfo((const edict_t *)&ent)->invString(),true,false,false,false);
}
else
{
// Reconstitute saved inventory.
int weaponsAvailable;
sh.inv->extractInvFromString(&weaponsAvailable,getPlayerDMInfo((const edict_t *)&ent)->invString());
}
sh.inv->addWeaponType(SFW_THROWHAND);
sh.inv->selectBestWeapon();
}
/*
==================
dmarsenal_c::levelInit
==================
*/
void dmarsenal_c::levelInit(void)
{
gi.SP_Register("dm_arsenal");
// Precache sounds.
gi.soundindex("dm/arsenal/bigwinner.wav");
gi.soundindex("dm/arsenal/lastweapon.wav");
// Make certain all the weapons needed during the game are precached,
// because it's possible for all the weapon types to be used during
// a game.
for(int i=SFW_KNIFE;i<=SFW_THROWHAND;i++)
{
// View weapons.
AddWeaponTypeForPrecache(i);
// Bolt-ons / pickups. Eugh... but necessary to precache.
if(Pickup *p=thePickupList.GetPickupFromType(PU_WEAPON,i))
{
edict_t *ent=G_Spawn();
I_Spawn(ent,p);
G_FreeEdict(ent);
}
}
// Determine the available weapons at the start of the game.
setWeapons();
}
/*
==================
dmarsenal_c::checkItemSpawn
==================
*/
int dmarsenal_c::checkItemSpawn(edict_t *ent,Pickup **pickup)
{
if ((*pickup)->GetPickupListIndex() == OBJ_CTF_FLAG)
{
G_FreeEdict (ent);
return(0);
}
if(dmRule_NO_HEALTH())
{
if ((*pickup)->GetType() == PU_HEALTH)
{
G_FreeEdict (ent);
return(0);
}
}
if(dmRule_NO_ITEMS())
{
if ((*pickup)->GetType() == PU_INV)
{
G_FreeEdict (ent);
return(0);
}
}
if(dmRule_NO_ARMOR())
{
if ((*pickup)->GetType() == PU_ARMOR)
{
G_FreeEdict (ent);
return(0);
}
}
if ((*pickup)->GetType() == PU_AMMO)
{
G_FreeEdict (ent);
return(0);
}
if ((*pickup)->GetType() == PU_WEAPON)
{
G_FreeEdict (ent);
return(0);
}
return(-1);
}
/*
==================
dmarsenal_c::dmRule_xxx
==================
*/
int dmarsenal_c::dmRule_NO_HEALTH(void)
{
return((int)dmflags->value&DF_ARSENAL_NO_HEALTH);
}
int dmarsenal_c::dmRule_NO_ITEMS(void)
{
return((int)dmflags->value&DF_ARSENAL_NO_ITEMS);
}
int dmarsenal_c::dmRule_NO_FALLING(void)
{
return((int)dmflags->value&DF_ARSENAL_NO_FALLING);
}
int dmarsenal_c::dmRule_REALISTIC_DAMAGE(void)
{
return((int)dmflags->value&DF_ARSENAL_REALISTIC_DAMAGE);
}
int dmarsenal_c::dmRule_SAME_LEVEL(void)
{
return((int)dmflags->value&DF_ARSENAL_SAME_LEVEL);
}
int dmarsenal_c::dmRule_FORCE_RESPAWN(void)
{
return((int)dmflags->value&DF_ARSENAL_FORCE_RESPAWN);
}
int dmarsenal_c::dmRule_NO_ARMOR(void)
{
return((int)dmflags->value&DF_ARSENAL_NO_ARMOR);
}
/*
==================
dmarsenal_c::initPlayerDMInfo
==================
*/
void dmarsenal_c::initPlayerDMInfo(edict_t &ent)
{
if(!ent.client->dmInfo)
ent.client->dmInfo = new player_dmarsenalInfo_c;
}
/*
==================
dmarsenal_c::clientConnect
==================
*/
void dmarsenal_c::clientConnect(edict_t &ent)
{
gamerules_c::clientConnect(ent);
giveClientWeapons(ent,true);
}
/*
==================
dmarsenal_c::clientDie
==================
*/
void dmarsenal_c::clientDie(edict_t &ent, edict_t &inflictor, edict_t &killer)
{
if(ent.client->pers.spectator)
return;
// Save off weapons and inventory counts.
sharedEdict_t sh;
sh.inv = (inven_c *)ent.client->inv;
sh.edict = &ent;
sh.inv->setOwner(&sh);
sh.inv->buildInvString(getPlayerDMInfo((const edict_t *)&ent)->invString(),true,false,false,false);
// Lose a frag?
if((!killer.client)||(&killer==&ent))
{
// I was killed by non player or killed myself.
if (&killer==&ent)
{
// the killer is me
ent.client->resp.score -= sv_suicidepenalty->value;
}
else
{
ent.client->resp.score--;
}
return;
}
else
{
// I was killed by another player.
int weaponsCount;
// Award my killer a frag.
killer.client->resp.score+=1;
// Telefragging, hand grenades and c4 don't count towards the big winner bonus.
if((meansOfDeath!=MOD_TELEFRAG)&&(meansOfDeath!=MOD_GRENADE)&&(meansOfDeath!=MOD_C4))
{
// My killer used their current weapon to kill me, so they should drop
// it and take out the next one.
killer.client->inv->removeCurrentWeapon();
// When counting the number of weapons, we need to subtract -1 because
// the inventory system takes a while to actually drop the weapon. In
// other words, we can't just set the current weapon slot to empty in
// removeCurrentWeapon()... and then count the weapons - that screws
// the whole weapon changing thing up. So I guess this is not the worst
// or the best hack, but re-writing the weapons code to avoid the above
// scenario just isn't worth it at this late stage.
weaponsCount=killer.client->inv->countWeapons()-1;
// Check to see how many weapons my killer has left...
if(weaponsCount==0)
{
// My killer used all his weapons up so award them a frag plus the big winner bonus.
killer.client->resp.score+=10;
gi.positioned_sound(vec3_origin,g_edicts,CHAN_BODY,gi.soundindex("dm/arsenal/bigwinner.wav"),0.6,ATTN_NONE,0);
gi.SP_Print(0,DM_ARSENAL_TEXT_BIG_WINNER,killer.s.number);
// Time to reset game!
resetGame=-1;
}
else if((!firstToOneHit)&&(weaponsCount==1))
{
// Somehas become the first player to have just one weapon left to
// use, so annouce this to everyone.
firstToOneHit=1;
gi.positioned_sound(vec3_origin,g_edicts,CHAN_BODY,gi.soundindex("dm/arsenal/lastweapon.wav"),0.6,ATTN_NONE,0);
gi.SP_Print(0,DM_ARSENAL_TEXT_LAST_WEAPON,killer.s.number);
}
}
}
}
/*
==================
dmarsenal_c::clientDieWeaponHandler
==================
*/
void dmarsenal_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(0);
sh.inv->handlePlayerDeath();
if(IGhoulInst *gun=ent->client->ps.gun)
gun->SetAllPartsOnOff(false);
}
/*
==================
dmarsenal_c::clientHelpMessage
==================
*/
void dmarsenal_c::clientHelpMessage(edict_t *ent)
{
// Display my status info.
SendStatusInfo2(ent);
}
/*
==================
dmarsenal_c::clientRespawn
==================
*/
void dmarsenal_c::clientRespawn(edict_t &ent)
{
giveClientWeapons(ent,ent.client->pers.spectator);
// Send status update.
SendStatusInfo2(&ent);
}
/*
==================
dmarsenal_c::clientScoreboardMessage
==================
*/
void dmarsenal_c::clientScoreboardMessage (edict_t *ent, edict_t *killer, qboolean log_file)
{
gamerules_c::clientScoreboardMessage(ent,killer,log_file);
}