User:Dutchmega/code: Difference between revisions

From Valve Developer Community
Jump to navigation Jump to search
No edit summary
(→‎Is player AFK?: Updated code)
 
(6 intermediate revisions by 2 users not shown)
Line 1: Line 1:
I've got more of this stuff. Where should I put them all? Just here or... somewhere else... <sup>(Ha! you didn't expect the last 2 words, did you?)</sup>
== Making the antlion burn! ==
== Making the antlion burn! ==
Add the following under <code>protected</code> in npc_antlion.h
Add the following under <code>protected</code> in npc_antlion.h
Line 15: Line 18:
}
}
</pre>
</pre>
== UTIL_LoadTexture ==
== UTIL_LoadTexture ==
Here's a very handy function from the [[Plan_of_Attack|Plan Of Attack]] source.
Here's a very handy function from the [[Plan_of_Attack|Plan Of Attack]] source.


<pre>
<pre>
#ifdef CLIENT_DLL
int UTIL_LoadTexture(const char *szFile)
int UTIL_LoadTexture(const char *szFile)
{
{
#ifdef CLIENT_DLL
char szStr[256];
char szStr[256];


Line 45: Line 47:


return iID;
return iID;
#else
}
return -1;
#endif
#endif
}
</pre>
</pre>


Line 85: Line 85:


Just don't forget to change the define everytime you release a new version
Just don't forget to change the define everytime you release a new version
{{Note|add #include "version.h" to cdll_client_int.cpp and gameinterface.cpp.}}


== Improved lagcompensation code ==
== Improved lagcompensation code ==
Line 103: Line 104:
Also take a look at the code from [[SDK_Known_Issues_List#Sticky_Player_Collisions|Sticky Player Collisions]]
Also take a look at the code from [[SDK_Known_Issues_List#Sticky_Player_Collisions|Sticky Player Collisions]]


== Bugs found while making a HL2 co-op mod ==
== PHP's substr ==
* NPCs don't work with the HL2MP weapons
By [[User:Vaber|Vaber]]:
* You don't see blood
<pre>char * substr( char * dst, const char * src, signed int from, signed int to)
* You hear the warning-sound when you spawn without any weapons & ammo.
{
* Fallen items/weapons from NPCs respawn.
if( (int)strlen( src ) < from )
* APC doesn't aim good
{
* Metropolice with stunstick doesn't work
strcpy( dst, src );
* Citizens with RPG don't work
return dst;
* You don't hear footsteps of NPCs.
}
* Crash or 'players not dropping objects' when hit hard and have something picked with the gravity gun.
 
* Sceneentity doesn't find <code>!player</code>.
int ifrom = (from >= 0) ? from : ((int)strlen(src) + from);
* <code>effects/strider_muzzle</code> not precached when you spawn an combine with the AR2.
int ito = (to >= 0) ? to : ((int)strlen(src) + to) - ifrom;
* Deaths are not counted at the scoreboard when killed by an NPC.
 
* <code>filter_damage_type</code>-entity doesn't work
int i = ifrom;
* Commanding citizens doesn't work.
int j = 0;
* Hoppers don't work
for( ; i < ito + ifrom; i++, j++)
* You don't see tracers & muzzleflash when a NPC shoots
{
* Flashlight isn't aimed in the right direction if the model has a stunstick/crowbar/grenade.
dst[ j ] = src[ i ];
* You don't hear tracer-sounds
}
* Items/weapons with the SF_NORESPAWN flag move to their original position.
dst[ j ] = 0;
* You hear the metropolice deathsound (radio) when you kill it with the combine ball.
 
* Scanner doesn't find any players when it's only allowed to inspect players.
return dst;
* When you die in the water, the underwater-ambientsound never stopts.
}
* Combine soldiers don't do hand signals
 
* When you kill a combine with the combine ball, the (dropped) items/weapons aren't dissolved.
char * substr( char * dst, const char * src, signed int pos )
* APCs laserdot isn't hidden
{
* Grenades float in the air when dropped by an NPC or when destroying an ammobox.
return substr( dst, src, pos, (int)strlen( src ) );
* You hear the ammo-warningsound & deathsound when you spawn without any weapons
}</pre>
* NPCs aren't frozen at an intermission.
 
* env_message doesn't work in MP
 
* It's possible to turn on the flashlight without the suit.
== UTIL_ModelToName ==
* You don't see the muzzleflash/tracer of a func_tank gun.
<pre>const char* UTIL_ModelToName(const char * modelName) {
* You don't see underwater bubbles
if ( Q_stristr(modelName, "combine_soldier") ) {
* When the player is on fire and dies, the fire doesn't disappear when he respawns
return "Combine Soldier";
* Using shield-scanner in maps is not possible unless the mapname begins with <code>d3</code>
}
* Scriptsound NPC_CeilingTurret.ShotSounds doesn't exist
else if ( Q_stristr(modelName, "combine_super_soldier") ) {
* Not all sk_ variables in the <code>game_shared</code> have the flag FCVAR_REPLICATED
return "Combine Elite";
* The sk_ damage variables for the crowbar and stunstick are removed in HL2DM
}
* Stunstick-sparks (random effect) are shown while the stunstick isn't the active weapon
else if ( Q_stristr(modelName, "strider") ) {
* Ammo in the HUD doesn't reposition good after an resolution-change
return "Strider";
* Many sounds of the physcannon are disabled in HL2DM
}
* Physcannon isn't predicted good, which results in weird results while picking up objects
else if ( Q_stristr(modelName, "antlion_guard") ) {
* You don't see swing-animations of stunstick & crowbar of other players
return "Antlionguard";
* You don't hear fastzombie's alertsound
}
* Metrocops won't walk around
else if ( Q_stristr(modelName, "antlion") ) {
* Metrocop's stunstick isn't blue, like in SP
return "Antlion";
* CPASAttenuationFilter doesn't work in MP, which results in not hearing sounds
}
* Deathnotice won't always show when killed by an NPC
else if ( Q_stristr(modelName, "headcrabblack") ) {
<br>
return "Poison Headcrab";
All fixed, so if you ask nice, I'll give you the fix.<br>
}
Of course, there's a bigger list of missing features. For example: 'Get points when you kill an NPC' or a deathnotice with the name of the NPC that killed you.
else if ( Q_stristr(modelName, "headcrabclassic") ) {
return "Headcrab";
}
else if ( Q_stristr(modelName, "headcrab") ) {
return "Fast Headcrab";
}
else if ( Q_stristr(modelName, "zombie/poison") ) {
return "Poison Zombie";
}
else if ( Q_stristr(modelName, "zombie/fast") ) {
return "Fast Zombie";
}
else if ( Q_stristr(modelName, "zombie_soldier") ) {
return "Zombine";
}
else if ( Q_stristr(modelName, "zombie") ) {
return "Zombie";
}
else if ( Q_stristr(modelName, "Group01") ) {
if( Q_stristr(modelName, "female") )
return "Citizen Female";
else if( Q_stristr(modelName, "male") )
return "Citizen Male";
return "Citizen";
}
else if ( Q_stristr(modelName, "Group02") ) {
if( Q_stristr(modelName, "female") )
return "Refugee Female";
else if( Q_stristr(modelName, "male") )
return "Refugee Male";
return "Refugee";
}
else if ( Q_stristr(modelName, "Group03m") ) {
if( Q_stristr(modelName, "female") )
return "Rebel Female (Medic)";
else if( Q_stristr(modelName, "male") )
return "Rebel Male (Medic)";
return "Rebel (Medic)";
}
else if ( Q_stristr(modelName, "Group03") ) {
if( Q_stristr(modelName, "female") )
return "Rebel Female";
else if( Q_stristr(modelName, "male") )
return "Rebel Male";
return "Rebel";
}
else if ( Q_stristr(modelName, "barnacle") ) {
return "Barnacle";
}
else if ( Q_stristr(modelName, "icthyosaur") ) {
return "Icthyosaur";
}
else if ( Q_stristr(modelName, "manhack") ) {
return "Combine Manhack";
}
else if ( Q_stristr(modelName, "roller") ) {
return "Combine Rollermine";
}
else if ( Q_stristr(modelName, "police") ) {
return "Combine Metrocop";
}
else if ( Q_stristr(modelName, "turret") ) {
return "Combine Turret";
}
else if ( Q_stristr(modelName, "vortigaunt") ) {
return "Vortigaunt";
}
else if ( Q_stristr(modelName, "scanner") ) {
return "Combine Scanner";
}
else if ( Q_stristr(modelName, "dropship")  && !Q_stristr(modelName, "destroyed") ) {
return "Combine Dropship";
}
else if ( Q_stristr(modelName, "gunship")  && !Q_stristr(modelName, "destroyed") ) {
return "Combine Gunship";
}
else if ( Q_stristr(modelName, "helicopter")  && !Q_stristr(modelName, "destroyed") ) {
return "Combine Helicopter";
}
else if ( Q_stristr(modelName, "combine_mine01") ) {
return "Combine Hopper";
}
else if ( Q_stristr(modelName, "helicopter") ) {
return "Combine Helicopter";
}
else if( Q_stristr(modelName, "alyx") && !Q_stristr(modelName, "gun") )
{
return "Alyx";
}
else if( Q_stristr(modelName, "breen.mdl") && !Q_stristr(modelName, "monitor") )
{
return "Breen";
}
else if( Q_stristr(modelName, "barney") && !Q_stristr(modelName, "helmet") )
{
return "Barney";
}
else if( Q_stristr(modelName, "kleiner") )
{
return "Kleiner";
}
else if( Q_stristr(modelName, "gman") )
{
return "G-Man";
}
else if( Q_stristr(modelName, "eli") && !Q_stristr(modelName, "_") ) // well, must be after hELIcopter :D
{
return "Eli";
}
else if ( Q_stristr(modelName, "dog.mdl") ) {
return "Dog";
}
// APC as last, because it's only 3 letters
else if ( Q_stristr(modelName, "apc") && !Q_stristr(modelName, "destroyed") ) {
return "Combine APC";
}
return NULL;
}</pre>
 
 
== Is player AFK? ==
With this little code you can see which players are AFK. Nice for in the scoreboard.
 
Add to <code>multiplay_gamerules.cpp</code>:
<pre>ConVar mp_afktime( "mp_afktime",
  "20",
  FCVAR_NOTIFY|FCVAR_REPLICATED,
  "delay before setting unactive player as AFK" );</pre>
 
Open <code>player.cpp</code> and add after the includes:
<pre>extern ConVar mp_afktime;</pre>
 
Add to <code>CBasePlayer::CBasePlayer</code>:
<pre>m_fLastActive = 0.0f;
m_bAFK = false;</pre>
 
And add to the top of the function <code>CBasePlayer::PostThink</code>:
<pre>
if( m_nButtons == 0 )
{
int diff1 = gpGlobals->curtime - m_fLastActive;
int diff2 = gpGlobals->curtime - m_fLastPlayerTalkTime;
 
if( diff1 > mp_afktime.GetInt() && diff2 > mp_afktime.GetInt() )
m_bAFK = true;
}
else
{
m_fLastActive = gpGlobals->curtime;
m_bAFK = false;
}
</pre>
 
Also add to <code>player.h</code>:
<pre>
float m_fLastActive;
bool m_bAFK;
bool IsAFK() { return m_bAFK; }</pre>

Latest revision as of 05:50, 7 October 2006

I've got more of this stuff. Where should I put them all? Just here or... somewhere else... (Ha! you didn't expect the last 2 words, did you?)


Making the antlion burn!

Add the following under protected in npc_antlion.h

virtual	bool		AllowedToIgnite( void ) { return true; }

Well, now the damh thing burns but it doesn't visually respond to it. You can use the drown-animation: Add the following piece of code to the top of the function GatherConditions():

if( IsOnFire() )
{
	SetCondition( COND_ANTLION_IN_WATER );
}

UTIL_LoadTexture

Here's a very handy function from the Plan Of Attack source.

#ifdef CLIENT_DLL
int UTIL_LoadTexture(const char *szFile)
{
	char szStr[256];

	// try to pull it
	int iID = vgui::surface()->DrawGetTextureId(szFile);

	// did we get it?
	if(iID >= 0)
		return iID;

	// does the file exist?
	Q_snprintf(szStr, sizeof(szStr), "materials/%s.vmt", szFile);
	if(!vgui::filesystem()->FileExists(szStr))
	{
		DevMsg("UTIL_LoadTexture: texture %s does not exist!\n", szFile);
		return -1;
	}

	// create the new texture
	iID = vgui::surface()->CreateNewTextureID();
	vgui::surface()->DrawSetTextureFile(iID, szFile, true, false);

	return iID;
}
#endif

Disallow players connecting to a server with a different version

Add the file version.h to your game_shared and add it to both projects. Content:

#define VERSION "0.01"

Then add to cdll_client_int.cpp:

void cl_versionCallback_f( ConVar *var, char const *pOldString )
{
	if( Q_stricmp( var->GetString(), var->GetDefault() ) ) var->Revert();
}
static ConVar	cl_version	( "cl_version", VERSION, FCVAR_USERINFO|FCVAR_CLIENTDLL, "The version of this mod",
				cl_versionCallback_f );

Then open GameInterface.cpp and find the function ClientConnect() Replace the contents of that function with this:

	// DM: Get the version of the client and compare it with the server's version
	const char* version = engine->GetClientConVarValue( engine->IndexOfEdict( pEdict ), "cl_version" );

	if (stricmp(VERSION, version) == 0)
	{
		return g_pGameRules->ClientConnected( pEdict, pszName, pszAddress, reject, maxrejectlen );
		// Aka true
	}
	else
	{
		char string [256];
		Q_snprintf( string, sizeof(string), "The server runs a different version (%s)", VERSION);
		Q_strcpy( reject, string ); 
		maxrejectlen = strlen(string);
		return false;
	}

Just don't forget to change the define everytime you release a new version

Note.pngNote:add #include "version.h" to cdll_client_int.cpp and gameinterface.cpp.

Improved lagcompensation code

Open dlls/player_lagcompensation.cpp and replace, around line 369

// lost track, too much difference 
return;

with

// DM: Some small improvements for lagcompensation 
// From Plan of Attack-source 
// did we found a context smaller then target time ? 
if ( record->m_flSimulationTime <= flTargetTime ) 
 break; // hurra, stop  
// store this position for the next time through the loop 
prevOrg = record->m_vecOrigin; 
// go one step back 
curr = track->Next( curr ); 

Also take a look at the code from Sticky Player Collisions

PHP's substr

By Vaber:

char * substr( char * dst, const char * src, signed int from, signed int to)
{
	if( (int)strlen( src ) < from )
	{
		strcpy( dst, src );
		return dst;
	}

	int ifrom = (from >= 0) ? from : ((int)strlen(src) + from);
	int ito = (to >= 0) ? to : ((int)strlen(src) + to) - ifrom;

	int i = ifrom;
	int j = 0;
	for( ; i < ito + ifrom; i++, j++)
	{
		dst[ j ] = src[ i ];
	}
	dst[ j ] = 0;

	return dst;
}

char * substr( char * dst, const char * src, signed int pos )
{
	return substr( dst, src, pos, (int)strlen( src ) );
}


UTIL_ModelToName

const char* UTIL_ModelToName(const char * modelName) {
	if ( Q_stristr(modelName, "combine_soldier") ) {
		return "Combine Soldier";
	}
	else if ( Q_stristr(modelName, "combine_super_soldier") ) {
		return "Combine Elite";
	}
	else if ( Q_stristr(modelName, "strider") ) {
		return "Strider";
	}
	else if ( Q_stristr(modelName, "antlion_guard") ) {
		return "Antlionguard";
	}
	else if ( Q_stristr(modelName, "antlion") ) {
		return "Antlion";
	}
	else if ( Q_stristr(modelName, "headcrabblack") ) {
		return "Poison Headcrab";
	}
	else if ( Q_stristr(modelName, "headcrabclassic") ) {
		return "Headcrab";
	}
	else if ( Q_stristr(modelName, "headcrab") ) {
		return "Fast Headcrab";
	}
	else if ( Q_stristr(modelName, "zombie/poison") ) {
		return "Poison Zombie";
	}
	else if ( Q_stristr(modelName, "zombie/fast") ) {
		return "Fast Zombie";
	}
	else if ( Q_stristr(modelName, "zombie_soldier") ) {
		return "Zombine";
	}
	else if ( Q_stristr(modelName, "zombie") ) {
		return "Zombie";
	}
	else if ( Q_stristr(modelName, "Group01") ) {
		if( Q_stristr(modelName, "female") )
			return "Citizen Female";
		else if( Q_stristr(modelName, "male") )
			return "Citizen Male";
		
		return "Citizen";
	}
	else if ( Q_stristr(modelName, "Group02") ) {
		if( Q_stristr(modelName, "female") )
			return "Refugee Female";
		else if( Q_stristr(modelName, "male") )
			return "Refugee Male";
		
		return "Refugee";
	}
	else if ( Q_stristr(modelName, "Group03m") ) {
		if( Q_stristr(modelName, "female") )
			return "Rebel Female (Medic)";
		else if( Q_stristr(modelName, "male") )
			return "Rebel Male (Medic)";
		
		return "Rebel (Medic)";
	}
	else if ( Q_stristr(modelName, "Group03") ) {
		if( Q_stristr(modelName, "female") )
			return "Rebel Female";
		else if( Q_stristr(modelName, "male") )
			return "Rebel Male";
		
		return "Rebel";
	}
	else if ( Q_stristr(modelName, "barnacle") ) {
		return "Barnacle";
	}
	else if ( Q_stristr(modelName, "icthyosaur") ) {
		return "Icthyosaur";
	}
	else if ( Q_stristr(modelName, "manhack") ) {
		return "Combine Manhack";
	}
	else if ( Q_stristr(modelName, "roller") ) {
		return "Combine Rollermine";
	}
	else if ( Q_stristr(modelName, "police") ) {
		return "Combine Metrocop";
	}
	else if ( Q_stristr(modelName, "turret") ) {
		return "Combine Turret";
	}
	else if ( Q_stristr(modelName, "vortigaunt") ) {
		return "Vortigaunt";
	}
	else if ( Q_stristr(modelName, "scanner") ) {
		return "Combine Scanner";
	}
	else if ( Q_stristr(modelName, "dropship")  && !Q_stristr(modelName, "destroyed") ) {
		return "Combine Dropship";
	}
	else if ( Q_stristr(modelName, "gunship")  && !Q_stristr(modelName, "destroyed") ) {
		return "Combine Gunship";
	}
	else if ( Q_stristr(modelName, "helicopter")  && !Q_stristr(modelName, "destroyed") ) {
		return "Combine Helicopter";
	}
	else if ( Q_stristr(modelName, "combine_mine01") ) {
		return "Combine Hopper";
	}
	else if ( Q_stristr(modelName, "helicopter") ) {
		return "Combine Helicopter";
	}
	else if( Q_stristr(modelName, "alyx") && !Q_stristr(modelName, "gun") )
	{
		return "Alyx";
	}
	else if( Q_stristr(modelName, "breen.mdl") && !Q_stristr(modelName, "monitor") )
	{
		return "Breen";
	}
	else if( Q_stristr(modelName, "barney") && !Q_stristr(modelName, "helmet") )
	{
		return "Barney";
	}
	else if( Q_stristr(modelName, "kleiner") )
	{
		return "Kleiner";
	}
	else if( Q_stristr(modelName, "gman") )
	{
		return "G-Man";
	}
	else if( Q_stristr(modelName, "eli") && !Q_stristr(modelName, "_") ) // well, must be after hELIcopter :D
	{
		return "Eli";
	}
	else if ( Q_stristr(modelName, "dog.mdl") ) {
		return "Dog";
	}
	// APC as last, because it's only 3 letters
	else if ( Q_stristr(modelName, "apc") && !Q_stristr(modelName, "destroyed") ) {
		return "Combine APC";
	}
	
	return NULL;
}


Is player AFK?

With this little code you can see which players are AFK. Nice for in the scoreboard.

Add to multiplay_gamerules.cpp:

ConVar	mp_afktime( "mp_afktime",
					  "20",
					  FCVAR_NOTIFY|FCVAR_REPLICATED,
					  "delay before setting unactive player as AFK" );

Open player.cpp and add after the includes:

extern ConVar mp_afktime;

Add to CBasePlayer::CBasePlayer:

m_fLastActive = 0.0f;
m_bAFK = false;

And add to the top of the function CBasePlayer::PostThink:

if( m_nButtons == 0 )
{
	int diff1 = gpGlobals->curtime - m_fLastActive;
	int diff2 = gpGlobals->curtime - m_fLastPlayerTalkTime;

	if( diff1 > mp_afktime.GetInt() && diff2 > mp_afktime.GetInt() )
		m_bAFK = true;
}
else 
{ 
	m_fLastActive = gpGlobals->curtime; 
	m_bAFK = false;
}

Also add to player.h:

float m_fLastActive;
bool m_bAFK;
bool IsAFK() { return m_bAFK; }