void CBasePlayerWeapon::ItemPostFrame()
{
if ((m_fInReload) && (m_pPlayer->m_flNextAttack <= UTIL_WeaponTimeBase()))
{
// complete the reload.
int j = V_min(iMaxClip() - m_iClip, m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType]);
// Add them to the clip
m_iClip += j;
m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] -= j;
To better understand how this code works.
int j
= we are looking for how many bullets we need in our current clip to get a full clip (or the maximum ammo amounts available)V_min(a,b)
= "j" will be either the necessary amount to make a full clip OR the remaining ammo amount left. (You can't get a full Glock clip if you only have 3 bullets in your inventory)m_iClip += j;
)if
and else
statements.void CBasePlayerWeapon::ItemPostFrame()
{
if ((m_fInReload) && (m_pPlayer->m_flNextAttack <= UTIL_WeaponTimeBase()))
{
// get j count
int j = V_min(iMaxClip() - m_iClip, m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType]);
// Add a full clip and permanently remove the previous one if a full clip is available
// m_iClip = MaxClip(); could work as well.
if (m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] >= iMaxClip())
{
m_iClip += j;
m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] -= iMaxClip();
}
// Add the only remaining clip (full or not) and permanently remove the previous one.
else
{
m_iClip = m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType];
m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] = 0;
}
Now, the only thing to do is to ensure that none of your guns share the same type of ammo.GameMenu.res
."3"
{
"label" "#GameUI_CampaignSelect"
"command" "engine disconnect; maxplayers 1; map hlu_campaignselect"
}
Think()
callback for it with a sufficient delay set for nextthink
. Now I'm wondering if this is the elegant way of delaying actions in a plugin or is there a more straightforward way.// clip brushes don't stay in the drawing hull
if (contents == CONTENTS_CLIP)
{
b->hulls[0].faces = NULL;
b->contents = CONTENTS_SOLID;
}
This makes clip brushes invisible but also removes them from the point hull, used for things like hitscan ray traces which is why you can shoot through them.CGameRules
and the code around it.InstallGameRules
(assuming they'd be implemented as gamerules) instead of mangling with different DLLs. The latter could be pretty messy.ClientPutInServer
which runs when the player enters the game, but unfortunately it is too early to send messages from here.
void ClientPutInServer( edict_t *pEntity ) {
const char* playername = STRING(pEntity->v.netname);
char* modelname = g_engfuncs.pfnInfoKeyValue( g_engfuncs.pfnGetInfoKeyBuffer( pEntity ), "model" );
char modelfile[256];
snprintf(modelfile, sizeof(modelfile), "models/player/%s/%s.mdl", modelname, modelname);
LOG_MESSAGE(PLID, "Player %s is using model %s", playername, modelname);
if (fileExists( modelfile )) {
LOG_MESSAGE(PLID, "Model %s is present on server", modelname);
SAY(pEntity, "Your model is present on the server, it will be precached for the next round!");
if (addPrecacheEntry( playername, modelname ))
LOG_MESSAGE(PLID, "Added model %s to precache list", modelname);
else
LOG_MESSAGE(PLID, "Model %s will not be precached - reduntant or precache list is full", modelname);
}
else {
LOG_MESSAGE(PLID, "Unable to precache due to FILE MISSING: %s!", modelfile);
SAY(pEntity, "Your model is not present on the server, can't distribute for other players!");
}
RETURN_META(MRES_IGNORED);
}
If I send a message to other players who are already in game, or all players, they receive the message, so it's not that SAY()
doesn't work. I think somehow I should add some timing, so the message would be sent several seconds later when they are already playing. (Just an irrelevant sidenote: the log message "Model %s will not be precached - reduntant or precache list is full
" is confusing, because if the model is already added to the list, it WILL be precached for the next round, but won't if the list is full.)SAY()
is a macro I defined to send raw messages – I remember there are other methods I tried, but all of them effectively do this at their core.
#define SAY(pEntity, text) {\
MESSAGE_BEGIN( MSG_ONE, GET_USER_MSG_ID(PLID, "SayText", NULL), NULL, pEntity );\
WRITE_BYTE( ENTINDEX(pEntity) );\
WRITE_STRING( text );\
MESSAGE_END();\
}
And fileExists()
here is just a wrapper for calling access()
(this is the other thing I have problem with):
bool fileExists(const char* path) {
char fullpath[256];
snprintf(fullpath, sizeof(fullpath), "%s/%s", &gGamedir[0], path);
return access(fullpath, R_OK) == 0;
}
I highly doubt that LoadFileForMe()
would mmap()
the file – it would be somewhat better because it's faster and the kernel could at least unload it if it's not used, but it would still be better to not load files in the middle of a game when they are not needed in memory.IFileSystem
in public/FileSystem.h
is interesting, I think it would do what I need but I have no idea what it links to.+door1
and train -> newpos
instead of having to manually create a trigger_relay or trigger_changetarget. Advanced users can even make their own template entities and behaviors, and share them with others via .zip files.{_tb_group}
to entity names and targetnames inside linked groups to produce unique names per group.
Download links:
Unknown command from unsafe location. Ignoring.