Help me, Lords of coding!! Created 3 years ago2021-04-04 22:41:22 UTC by Alexis_of_Steel Alexis_of_Steel

Created 3 years ago2021-04-04 22:41:22 UTC by Alexis_of_Steel Alexis_of_Steel

Posted 3 years ago2021-04-04 22:41:22 UTC Post #345507
Hello there. I'm back with a new issue.
I want to create an item that doubles all the damage done by the player, but I don't know how to achieve that.
As far as I know, there is nothing in the Half-Life source code that looks like the item I want to create, so that's why I'm asking for your help.

The concept is simple but at the same time complicated: Once you pick up the item, for 15 seconds all the damage you do with your weapons will be double. After 15 seconds, the item will be removed from your inventory, and the effect will end. Now you can pick up another item of these.

Oh, Lords of Coding, I invoke you!

I have only written the basic structure of my item, at the bottom of items.cpp:
// An item that doubles all the damage done.
class CDamageDoubler : public CItem
{
    void CDamageDoubler :: Spawn( void )
    {
        Precache();
        SET_MODEL(ENT(pev), "models/w_rad.mdl");
        CItem::Spawn();
    }

    void CDamageDoubler :: Precache( void )
    {
        PRECACHE_MODEL("models/w_rad.mdl");
        PRECACHE_SOUND("scientist/sci_pain3.wav"); // stahp sound
    }

    BOOL CDamageDoubler :: MyTouch( CBasePlayer *pPlayer )
    {
        if ( pPlayer->m_fDamageDoubler ) // If the player owns this item, then he cannot take another.
        {
            return FALSE;
        }

        if ( ( pPlayer->pev->weapons & (1<<WEAPON_SUIT) ) ) // The player can take this item only if he is wearing the HEV suit
        {
            ALERT( at_console, "You have picked up the damage doubler\n" ); // Display a message on the console.
            EMIT_SOUND(ENT(pPlayer->pev), CHAN_ITEM, "scientist/sci_pain3.wav", 1, ATTN_NORM); // play the stahp sound
            pPlayer->m_fDamageDoubler = TRUE;
            return TRUE;
        }
        return FALSE;
    }
};

LINK_ENTITY_TO_CLASS( item_damage_doubler, CDamageDoubler );
m_fDamageDoubler is declared somewhere in player.h:
BOOL m_fDamageDoubler; // For my item that doubles the damage done
Thanks in advance!!!
Posted 3 years ago2021-04-05 15:01:42 UTC Post #345509
Well, it's probably a bit tricky since the Half-Life SDK code isn't the most well-structured. You would have to find every place where damage is done by the player and make it take into account whether or not the player has the double damage effect and scale the damage accordingly. For bullet weapons it should be fairly simple, since they all call the FireBulletsPlayer function, which you can modify to scale damage, but for other weapons it might take a bit more work.
Dr. Orange Dr. OrangeSource good.
Posted 3 years ago2021-04-05 18:18:43 UTC Post #345510
Hello Dr. Orange! What you say sounds logical. But how would I make that effect last only 15 seconds? That question surpasses my rudimentary knowledge of programming in Half-Life :(
Posted 3 years ago2021-04-05 18:31:37 UTC Post #345511
look at the code that starts dealing damage to players when they spend too much time underwater
Posted 3 years ago2021-04-05 20:06:07 UTC Post #345514
Well, you'd have to also store the time when the player got the powerup, and then remove the powerup state adter 15 seconds has passed. I'm not sure exactly what's the best way to do that, but as Bruce said, look at some damage over time stuff. Maybe there's a think function for the player you could use.
Dr. Orange Dr. OrangeSource good.
Posted 3 years ago2021-04-06 11:56:56 UTC Post #345515
The way you have programmed your item is fine if the player keeps the item in his inventory forever which is not what you want because you want the power up to be "time based".

First, remove your BOOL m_fDamageDoubler because it's going to be more confusing than helping.

In CBasePlayer (player.h) class declaration, add this:
float m_flDoubleDamageBonusTime;

bool HasDoubleDamageBonus()
{
    return gpGlobals->time < m_flDoubleDamageTime;
}
If you are not familiar with HL SDK programming: gpGlobals->time is the current game time.

m_flDoubleDamageBonusTime basically tells when the power up should be "off" and it gives you the state of the power up (game time higher than double damage time? It's off then. Double damage time higher than game time? It's on then) so you basically have 2 information in a single variable. That's why the handy bool HasDoubleDamageBonus() is made and you should use it whenever you want to check if the player has the double damage bonus (it replaces your obsolete if ( m_fDoubleDamageBonus )).

In CBasePlayer::Spawn in player.cpp, add m_flDoubleDamageBonusTime = -1.0f; to the end to properly initialize the variable (because nobody likes problems).

If you are making a singleplayer mod, add m_flDoubleDamageBonusTime to the save/restore table of CBasePlayer as a FIELD_TIME to prevent issues when saving/loading games (again because nobody likes problems).

Want to give 15 seconds of power up to the player? Just do m_flDoubleDamageBonusTime = gpGlobals->time + 15.0f;.

Like Dr. Orange mentioned, the FireBulletsPlayer method is responsible for firearms damage (crowbar, grenades and such are handled separately). That's where you do if ( pPlayer->HasDoubleDamageBonus() ) flDamage *= 2.0f; to actually apply the damage bonus.
Posted 3 years ago2021-04-07 00:41:40 UTC Post #345516
Merci, Shepard62700FR! And of course, thanks to Dr. Orange and Bruce for their contributions too.
I think I did well what Shepard62700FR told me.
I mean, first I have removed BOOL m_fDamageDoubler from CBasePlayer class declaration (player.h). Right there I have written:
float m_flDoubleDamageBonusTime;

bool HasDoubleDamageBonus()
{
    return gpGlobals->time < m_flDoubleDamageBonusTime;
}
In CBasePlayer::Spawn (player.cpp) I have added:
m_flDoubleDamageBonusTime = gpGlobals->time + 15.0f;
And in TYPEDESCRIPTION (player.cpp) I have added too:
DEFINE_FIELD( CBasePlayer, m_flDoubleDamageBonusTime, FIELD_TIME ),
And finally the code of my item was like this (items.cpp):
class CDamageDoubler : public CItem
{
    void CDamageDoubler :: Spawn( void )
    {
        Precache();
        SET_MODEL(ENT(pev), "models/w_rad.mdl");
        CItem::Spawn();
    }

    void CDamageDoubler :: Precache( void )
    {
        PRECACHE_MODEL("models/w_rad.mdl");
        PRECACHE_SOUND("scientist/sci_pain3.wav"); // stahp sound
    }

    BOOL CDamageDoubler :: MyTouch( CBasePlayer *pPlayer )
    {
        if ( ( pPlayer->pev->weapons & (1<<WEAPON_SUIT) ) ) // The player can take this item only if he is wearing the HEV suit
        {
            ALERT( at_console, "You have picked up the damage doubler\n" ); // Display a message on the console.
            EMIT_SOUND(ENT(pPlayer->pev), CHAN_ITEM, "scientist/sci_pain3.wav", 1, ATTN_NORM); // play the stahp sound
            pPlayer->HasDoubleDamageBonus(); // New line
            return TRUE;
        }
        return FALSE;
    }
};

LINK_ENTITY_TO_CLASS( item_damage_doubler, CDamageDoubler );
But I do not know exactly how to double the damage of both weapons that use FireBulletsPlayer and those that do not use this function. If you can give me a concrete example, it would be very helpful. :)
Posted 3 years ago2021-04-07 14:48:07 UTC Post #345517
You may want to read Shephard62700FR's post more carefully, because there are two problems with your code:
  • it's immediately giving players a 15-seconds double-damage bonus when they spawn, instead of initializing the bonus-expiry time to -1.0f.
  • it's not giving a double-damage bonus when the damage-doubler item is touched, it's only checking whether the player currently has a double-damage bonus.
It's also not preventing the player from picking up another damage-bonus item if they already have an active damage bonus.

As for applying the damage bonus, FireBulletsPlayer is a CBaseEntity member function, so it doesn't know about CBasePlayer fields like m_flDoubleDamageBonusTime (it can be called on any entity, after all). One way to work around that is by creating a virtual float GetDamageBonus() function in CBaseEntity that returns 1.0f, but which you override in CBasePlayer to return 2.0f if HasDoubleDamageBonus() is true (you can look at the CBaseEntity::IsPlayer and CBasePlayer::IsPlayer functions for an example of how a virtual function can be overridden in a child class). You can then use that function inside FireBulletsPlayer as following:
pEntity->TraceAttack(pevAttacker, gSkillData.plrDmg9MM * GetDamageBonus(), vecDir, &tr, DMG_BULLET);

Some of the other weapons call TraceAttack directly, and since weapons contain a pointer to the player (CBasePlayer* m_pPlayer), you should be able to obtain the damage factor for them with m_pPlayer->GetDamageBonus(). For explosives I think you'll need to look at the RadiusDamage function, probably using CBaseEntity::Instance(ENT(pevInflictor))->GetDamageBonus() to get the damage bonus, if I understand how that works correctly.
Posted 3 years ago2021-04-08 01:14:57 UTC Post #345518
Thanks, Captain P. I see that it's more complicated than what I thought :confused:
You must be logged in to post a response.