Portable Half-Life SDK. GoldSource and Xash3D. Crossplatform.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

669 lines
16 KiB

// ---------------------------------------------------------------
// BubbleMod
//
// AUTHOR
// Tyler Lund <halflife@bubblemod.org>
//
// LICENSE
//
// Permission is granted to anyone to use this software for
// any purpose on any computer system, and to redistribute it
// in any way, subject to the following restrictions:
//
// 1. The author is not responsible for the consequences of
// use of this software, no matter how awful, even if they
// arise from defects in it.
// 2. The origin of this software must not be misrepresented,
// either by explicit claim or by omission.
// 3. Altered versions must be plainly marked as such, and
// must not be misrepresented (by explicit claim or
// omission) as being the original software.
// 3a. It would be nice if I got a copy of your improved
// version sent to halflife@bubblemod.org.
// 4. This notice must not be removed or altered.
//
// ---------------------------------------------------------------
#include "extdll.h"
#include "util.h"
#include "cbase.h"
#include "player.h"
#include "weapons.h"
#include "gamerules.h"
#include "game.h"
#include "BMOD_constants.h"
#define MAX_RULE_BUFFER 1024
extern DLL_GLOBAL int g_VoteStatus;
extern DLL_GLOBAL float g_VoteTimer;
typedef struct mapcycle_item_s
{
struct mapcycle_item_s *next;
char mapname[ 32 ];
int minplayers, maxplayers;
char rulebuffer[ MAX_RULE_BUFFER ];
} mapcycle_item_t;
typedef struct mapcycle_s
{
struct mapcycle_item_s *items;
struct mapcycle_item_s *next_item;
} mapcycle_t;
extern DLL_GLOBAL BOOL g_fGameOver;
extern int gmsgSpectator;
extern edict_t *EntSelectSpawnPoint( CBaseEntity *pPlayer );
extern int CountPlayers( void );
extern void DestroyMapCycle( mapcycle_t *cycle );
extern int ReloadMapCycleFile( char *filename, mapcycle_t *cycle );
extern void ExtractCommandString( char *s, char *szCommand );
extern cvar_t bm_guns;
extern cvar_t bm_ammo;
extern cvar_t bm_g;
extern cvar_t bm_cbar_mod;
extern cvar_t bm_mp5_mod;
extern cvar_t bm_shotty_mod;
extern cvar_t bm_xbow_mod;
extern cvar_t bm_rpg_mod;
extern cvar_t bm_tau_mod;
extern cvar_t bm_gluon_mod;
extern cvar_t bm_hornet_mod;
extern cvar_t bm_trip_mod;
extern cvar_t bm_snarks_mod;
extern cvar_t bm_spawneffects;
/*
extern cvar_t bm_score_crowbar;
extern cvar_t bm_score_throwncbar;
extern cvar_t bm_score_9mm;
extern cvar_t bm_score_357;
extern cvar_t bm_score_mp5;
extern cvar_t bm_score_shotgun;
extern cvar_t bm_score_squidspit;
extern cvar_t bm_score_zapgun;
extern cvar_t bm_score_mp5grenade;
extern cvar_t bm_score_gluon;
extern cvar_t bm_score_tau;
extern cvar_t bm_score_bolt;
extern cvar_t bm_score_crossbow;
extern cvar_t bm_score_satchel;
extern cvar_t bm_score_handgrenade;
extern cvar_t bm_score_rpg;
extern cvar_t bm_score_snarks;
extern cvar_t bm_score_tripmine;
int CGameRules :: BMOD_IPointsForKill( CBasePlayer *pAttacker, CBasePlayer *pKilled, entvars_t *pInflictor)
{
if (g_pGameRules->IsTeamplay())
{
if ( !pKilled )
return 0;
if ( !pAttacker )
return 1;
if ( pAttacker != pKilled && PlayerRelationship( pAttacker, pKilled ) == GR_TEAMMATE )
return -1;
}
if (!strcmp(STRING(pInflictor->classname), "weapon_crowbar"))
return bm_score_crowbar.value;
else if (!strcmp(STRING(pInflictor->classname), "flying_crowbar"))
return bm_score_throwncbar.value;
else if (!strcmp(STRING(pInflictor->classname), "weapon_9mmhandgun"))
return bm_score_9mm.value;
else if (!strcmp(STRING(pInflictor->classname), "weapon_357"))
return bm_score_357.value;
else if (!strcmp(STRING(pInflictor->classname), "weapon_9mmAR"))
return bm_score_mp5.value;
else if (!strcmp(STRING(pInflictor->classname), "weapon_shotgun"))
return bm_score_shotgun.value;
else if (!strcmp(STRING(pInflictor->classname), "squidspit"))
return bm_score_squidspit.value;
else if (!strcmp(STRING(pInflictor->classname), "weapon_hornetgun"))
return bm_score_zapgun.value;
else if (!strcmp(STRING(pInflictor->classname), "weapon_egon"))
return bm_score_gluon.value;
else if (!strcmp(STRING(pInflictor->classname), "weapon_gauss"))
return bm_score_tau.value;
else if (!strcmp(STRING(pInflictor->classname), "bolt"))
return bm_score_bolt.value;
else if (!strcmp(STRING(pInflictor->classname), "weapon_crossbow"))
return bm_score_crossbow.value;
else if (!strcmp(STRING(pInflictor->classname), "monster_satchel"))
return bm_score_satchel.value;
else if (!strcmp(STRING(pInflictor->classname), "hand_grenade"))
return bm_score_handgrenade.value;
else if (!strcmp(STRING(pInflictor->classname), "rpg_rocket"))
return bm_score_rpg.value;
else if (!strcmp(STRING(pInflictor->classname), "monster_snark"))
return bm_score_snarks.value;
else
return 1;
}
*/
void CHalfLifeMultiplay :: BMOD_ClientDisconnected(edict_t *pClient, CBasePlayer *pPlayer)
{
// Disconnecting observers
//MESSAGE_BEGIN( MSG_ALL, gmsgSpectator );
// WRITE_BYTE( ENTINDEX(pClient) );
// WRITE_BYTE( 0 );
//MESSAGE_END();
CBasePlayer *client = NULL;
while ( ((client = (CBasePlayer*)UTIL_FindEntityByClassname( client, "player" )) != NULL) && (!FNullEnt(client->edict())) )
{
if ( !client->pev )
continue;
if ( client == pPlayer )
continue;
// If a spectator was chasing this player, move him/her onto the next player
if ( client->m_hObserverTarget == pPlayer )
{
int iMode = client->pev->iuser1;
client->pev->iuser1 = 0;
client->m_hObserverTarget = NULL;
client->Observer_SetMode( iMode );
}
}
// Destroy all satchels, trips, and snark mines owned by this player.
DeactivateSatchels( pPlayer );
DeactivateTrips( pPlayer );
DeactivateSnarkTrips( pPlayer );
pPlayer->m_bIsConnected = FALSE;
UTIL_SaveRestorePlayer(pPlayer, 1, 0);
}
void CHalfLifeMultiplay :: BMOD_PlayerSpawn( CBasePlayer *pPlayer )
{
// Send new players into observer mode.
if (!pPlayer->m_iFirstSpawn)
{
pPlayer->m_iFirstSpawn = TRUE;
edict_t *pentSpawnSpot = EntSelectSpawnPoint( pPlayer );
pPlayer->StartObserver( VARS(pentSpawnSpot)->origin, VARS(pentSpawnSpot)->angles);
pPlayer->m_iSpawnKills = 0;
pPlayer->m_iTypeKills = 0;
pPlayer->m_bBanMe = FALSE;
UTIL_SaveRestorePlayer(pPlayer, 0, 0);
}
// Else stuff for a new player.
else if (bm_spawneffects.value) {
MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY );
WRITE_BYTE( TE_TELEPORT ); //This denotes which temporary intity we want to use
WRITE_COORD(pPlayer->pev->origin.x);// Location-X
WRITE_COORD(pPlayer->pev->origin.y);// Location-Y
WRITE_COORD(pPlayer->pev->origin.z);// Location-Z
MESSAGE_END();
EMIT_SOUND(ENT(pPlayer->pev), CHAN_BODY, "debris/beamstart8.wav", 1.0, ATTN_NORM);
}
}
void CHalfLifeMultiplay :: BMOD_InitHUD( CBasePlayer *pl )
{
pl->m_bIsConnected = TRUE;
pl->m_iKillsThisFrame = 0;
pl->m_iSpamSay = 0;
pl->m_LocateMode = FALSE;
pl->m_LeetSpeak = FALSE;
// pl->m_iHLHack = 0;
}
void CGameRules :: BMOD_PreChangeLevel( void )
{
return;
}
void CHalfLifeMultiplay :: BMOD_PreChangeLevel( void )
{
static char szPreviousMapCycleFile[ 256 ];
static mapcycle_t mapcycle;
char szNextMap[32];
char szFirstMapInList[32];
char szCommands[ 1500 ];
char szRules[ 1500 ];
int minplayers = 0, maxplayers = 0;
strcpy( szFirstMapInList, "hldm1" ); // the absolute default level is hldm1
int curplayers;
BOOL do_cycle = TRUE;
// find the map to change to
char *mapcfile = (char*)CVAR_GET_STRING( "mapcyclefile" );
ASSERT( mapcfile != NULL );
szCommands[ 0 ] = '\0';
szRules[ 0 ] = '\0';
curplayers = CountPlayers();
// Has the map cycle filename changed?
if ( stricmp( mapcfile, szPreviousMapCycleFile ) )
{
strcpy( szPreviousMapCycleFile, mapcfile );
DestroyMapCycle( &mapcycle );
if ( !ReloadMapCycleFile( mapcfile, &mapcycle ) || ( !mapcycle.items ) )
{
ALERT( at_console, "Unable to load map cycle file %s\n", mapcfile );
do_cycle = FALSE;
}
}
if ( do_cycle && mapcycle.items )
{
BOOL keeplooking = FALSE;
BOOL found = FALSE;
mapcycle_item_s *item;
// Assume current map
strcpy( szNextMap, STRING(gpGlobals->mapname) );
strcpy( szFirstMapInList, STRING(gpGlobals->mapname) );
// Traverse list
for ( item = mapcycle.next_item; item->next != mapcycle.next_item; item = item->next )
{
keeplooking = FALSE;
ASSERT( item != NULL );
if ( item->minplayers != 0 )
{
if ( curplayers >= item->minplayers )
{
found = TRUE;
minplayers = item->minplayers;
}
else
{
keeplooking = TRUE;
}
}
if ( item->maxplayers != 0 )
{
if ( curplayers <= item->maxplayers )
{
found = TRUE;
maxplayers = item->maxplayers;
}
else
{
keeplooking = TRUE;
}
}
if ( keeplooking )
continue;
found = TRUE;
break;
}
if ( !found )
{
item = mapcycle.next_item;
}
// Increment next item pointer
mapcycle.next_item = item->next;
// Perform logic on current item
strcpy( szNextMap, item->mapname );
ExtractCommandString( item->rulebuffer, szCommands );
strcpy( szRules, item->rulebuffer );
}
if ( !IS_MAP_VALID(szNextMap) )
{
strcpy( szNextMap, szFirstMapInList );
}
CVAR_SET_STRING("bm_map", STRING(gpGlobals->mapname) );
CVAR_SET_STRING("bm_nextmap", szNextMap );
}
// Bmod version of Changelevel
void CHalfLifeMultiplay :: ChangeLevel( void )
{
char szNextMap[32];
// Confirm what map we need.
// BMOD_PreChangeLevel();
strcpy( szNextMap, (char*)CVAR_GET_STRING( "bm_nextmap" ) );
g_fGameOver = TRUE;
ALERT( at_console, "CHANGE LEVEL: %s\n", szNextMap );
CHANGE_LEVEL( szNextMap, NULL );
}
void CHalfLifeMultiplay :: BMOD_Think ( void )
{
static float setVarsTime = 0;
if (setVarsTime < gpGlobals->time )
{
g_engfuncs.pfnCvar_DirectSet( &bm_ver, UTIL_VarArgs( "%s", BMOD_VERSION ) );
g_engfuncs.pfnCvar_DirectSet( &bm_bname, UTIL_VarArgs( "%s", BMOD_BRANCH_NAME ) );
g_engfuncs.pfnCvar_DirectSet( &bm_bver, UTIL_VarArgs( "%s", BMOD_BRANCH_VERSION ) );
g_engfuncs.pfnCvar_DirectSet( &bm_burl, UTIL_VarArgs( "%s", BMOD_BRANCH_URL ) );
BMOD_UpdateGuns();
BMOD_UpdateMods();
//UTIL_ClientPrintAll( HUD_PRINTTALK, UTIL_VarArgs( "<SERVER> updated at %f", gpGlobals->time));
setVarsTime = gpGlobals->time + 1;
}
// BMod voting
if ((g_VoteStatus == 1) && (g_VoteTimer < gpGlobals->time))
{
int players = CountPlayers();
int votesNeeded = (players * 3 / 4) + ((players < 3) ? 1 : 0);
char winner[81];
strcpy(winner, UTIL_CountVotes());
int winvotes = winner[0];
char map[81];
strcpy(map, &winner[1]);
UTIL_SpeakAll("dadeda");
if (winvotes >= votesNeeded) {
UTIL_ClientPrintAll( HUD_PRINTTALK, "<SERVER> *** We have a winner! ***\n");
}
else {
UTIL_ClientPrintAll( HUD_PRINTTALK, "<SERVER> *** Voting is closed! ***\n");
}
/*if (winvotes)
UTIL_ClientPrintAll( HUD_PRINTTALK, UTIL_VarArgs( "<SERVER> \"%s\" got %i vote(s). (needed %i to win with %i players)\n",
&(winner[1]),
winvotes,
votesNeeded,
players ) );*/
if (winvotes == 0)
UTIL_ClientPrintAll( HUD_PRINTTALK, "<SERVER> No votes were cast!\n");
if (winvotes >= votesNeeded)
{
if (!strcmp(map, "extend")) {
UTIL_ClientPrintAll( HUD_PRINTTALK, "<SERVER> Extend won the vote! This map will be extended 30 mins & 25 kills.\n");
int newTime = CVAR_GET_FLOAT("mp_timelimit") + 30;
int newFrags = CVAR_GET_FLOAT("mp_fraglimit") + 25;
CVAR_SET_FLOAT( "mp_timelimit", (newTime > bm_maxtime.value) ? bm_maxtime.value : newTime);
CVAR_SET_FLOAT( "mp_fraglimit", (newFrags > bm_maxfrags.value) ? bm_maxfrags.value : newFrags);
g_VoteStatus = 0;
}
else {
UTIL_ClientPrintAll( HUD_PRINTTALK, UTIL_VarArgs( "<SERVER> \"%s\" Won the vote! Changing map... please wait.\n",
&(winner[1])
));
CVAR_SET_STRING("bm_nextmap", &(winner[1]));
g_VoteStatus = 2;
g_VoteTimer = gpGlobals->time + 10;
}
UTIL_LogPrintf( "// Map \"%s\" won the map vote.\n", map);
}
else
{
if (winvotes)
UTIL_ClientPrintAll( HUD_PRINTTALK, UTIL_VarArgs( "<SERVER> \"%s\" got %i vote(s). (needed %i to win with %i players)\n",
&(winner[1]),
winvotes,
votesNeeded,
players ) );
UTIL_LogPrintf( "// Map vote ended.\n", map);
g_VoteStatus = 0;
}
}
if ((g_VoteStatus == 2) && (g_VoteTimer < gpGlobals->time))
{
g_VoteStatus = 0;
CVAR_SET_FLOAT( "mp_timelimit", 1);
}
// BMod
}
void CHalfLifeMultiplay :: BMOD_GiveGunsAndAmmo ( CBasePlayer *pPlayer )
{
char *pName;
char itemlist[1025];
char szTemp[80];
int iszItem;
// Give ammo
// make a copy because strtok is destructive
strncpy( itemlist, bm_ammo.string, 1024 );
pName = itemlist;
pName = strtok( pName, ";" );
while ( pName != NULL && *pName )
{
strcpy( szTemp, "ammo_" );
strcat( szTemp, pName );
iszItem = ALLOC_STRING( szTemp );
pPlayer->GiveNamedItem( STRING(iszItem) );
pName = strtok( NULL, ";" );
}
// Give guns
// make a copy because strtok is destructive
strncpy( itemlist, bm_guns.string, 1024 );
pName = itemlist;
pName = strtok( pName, ";" );
int guns = 0;
while ( pName != NULL && *pName )
{
strcpy( szTemp, "weapon_" );
strcat( szTemp, pName );
if (!strcmp(szTemp, "weapon_glock"))
{
strcpy( szTemp, "weapon_9mmhandgun" );
}
else if (!strcmp(szTemp, "weapon_mp5"))
{
strcpy( szTemp, "weapon_9mmAR" );
}
else if (!strcmp(szTemp, "weapon_python"))
{
strcpy( szTemp, "weapon_357" );
}
iszItem = ALLOC_STRING( szTemp );
pPlayer->GiveNamedItem( STRING(iszItem) );
pPlayer->SelectItem( STRING(iszItem) );
pName = strtok( NULL, ";" );
}
}
void CHalfLifeMultiplay :: BMOD_UpdateGuns ( void )
{
char *pName;
char itemlist[1024];
int guns = 0;
// guns
// make a copy because strtok is destructive
strncpy( itemlist, bm_guns.string, 1024 );
pName = itemlist;
pName = strtok( pName, ";" );
while ( pName != NULL && *pName )
{
if (!strcmp(pName, "crowbar"))
{
guns = guns | (1 << 0);
}
else if (!strcmp(pName, "9mmhandgun") || !strcmp(pName, "glock"))
{
guns = guns | (1 << 1);
}
else if (!strcmp(pName, "357") || !strcmp(pName, "python"))
{
guns = guns | (1 << 2);
}
else if (!strcmp(pName, "9mmAR") || !strcmp(pName, "mp5"))
{
guns = guns | (1 << 3);
}
else if (!strcmp(pName, "shotgun"))
{
guns = guns | (1 << 4);
}
else if (!strcmp(pName, "egon"))
{
guns = guns | (1 << 5);
}
else if (!strcmp(pName, "gauss"))
{
guns = guns | (1 << 6);
}
else if (!strcmp(pName, "rpg"))
{
guns = guns | (1 << 7);
}
else if (!strcmp(pName, "hornetgun"))
{
guns = guns | (1 << 8);
}
else if (!strcmp(pName, "tripmine"))
{
guns = guns | (1 << 9);
}
else if (!strcmp(pName, "satchel"))
{
guns = guns | (1 << 10);
}
else if (!strcmp(pName, "handgrenade"))
{
guns = guns | (1 << 11);
}
else if (!strcmp(pName, "snark"))
{
guns = guns | (1 << 12);
}
else if (!strcmp(pName, "crossbow"))
{
guns = guns | (1 << 13);
}
pName = strtok( NULL, ";" );
}
g_engfuncs.pfnCvar_DirectSet( &bm_g, UTIL_VarArgs( "%d", guns ) );
}
void CHalfLifeMultiplay :: BMOD_UpdateMods ( void )
{
int mods = 0;
// mods
// bm_cbar_mod
// bm_mp5_mod
// bm_shotty_mod
// bm_xbow_mod
// bm_rpg_mod
// bm_tau_mod
// bm_gluon_mod
// bm_hornet_mod
// bm_trip_mod
// bm_snarks_mod
if (bm_cbar_mod.value)
{
mods = mods | (1 << 0);
}
/*
if (!strcmp(pName, "9mmhandgun") || !strcmp(pName, "glock"))
{
mods = mods | (1 << 1);
}
*/
/*
if (!strcmp(pName, "357") || !strcmp(pName, "python"))
{
mods = mods | (1 << 2);
}
*/
if (bm_mp5_mod.value)
{
mods = mods | (1 << 3);
}
if (bm_shotty_mod.value)
{
mods = mods | (1 << 4);
}
if (bm_gluon_mod.value)
{
mods = mods | (1 << 5);
}
if (bm_tau_mod.value)
{
mods = mods | (1 << 6);
}
if (bm_rpg_mod.value)
{
mods = mods | (1 << 7);
}
if (bm_hornet_mod.value)
{
mods = mods | (1 << 8);
}
if (bm_trip_mod.value)
{
mods = mods | (1 << 9);
}
/*
if (!strcmp(pName, "satchel"))
{
mods = mods | (1 << 10);
}
*/
/*
if (!strcmp(pName, "handgrenade"))
{
mods = mods | (1 << 11);
}
*/
if (bm_snarks_mod.value)
{
mods = mods | (1 << 12);
}
if (bm_xbow_mod.value)
{
mods = mods | (1 << 13);
}
g_engfuncs.pfnCvar_DirectSet( &bm_mods, UTIL_VarArgs( "%d", mods ) );
}