Raised This Month: $ Target: $400
 0% 

[Tutorial] Reading/ripping hero codes


Post New Thread Reply   
 
Thread Tools Display Modes
Author Message
Jelle
[b]MOAR CANDY[/b]
Join Date: Aug 2009
Location: Denmark
Old 05-27-2011 , 04:37   [Tutorial] Reading/ripping hero codes
Reply With Quote #1

Welcome to the novice superhero tutorial

I have now started to make this tutorial as several people has been asking on how to use code from another hero to make your own.
This tutorial will show you how to read an already existing hero code and use that to make your very own, aka ripping.

Before you start with this tutorial, you should have a somewhat understanding for the pawn language and how to create a very simple hero. If you haven't already, you should read my Beginner's tutorial

I also beg you to READ THE WHOLE THING before asking questions. I have really used a lot of time to get in depth of pretty much every single thing. I know there is a lot of text, but ALL of the basics (include the almost impossible thing called searching) in covered, so please, do learn how to search for what you need BEFORE posting. I for one will ignore your post and refuse to help if your question can be found by less than 5 minutes of searching. You have come very far when you have read this so you should be able to help yourself to learn more.

Okay, so lets starts off with something simple. We want to create a hero which just simply makes us invisible, what do we do?
Well, we know that invisible woman, which is an approved superhero, makes you invisible, so why don't we just take a bit code from that one?
First this we do is to make a very basic hero which does nothing at all, but lets you choose it:

PHP Code:
#include <superheromod>

new gHeroID
new gHasInvis[SH_MAXSLOTS+1]

public 
plugin_init()
{
    
register_plugin("SUPERHERO Invis""1.0""Jelle")
    
    new 
pcvarLevel register_cvar("invis_level""0")
    
    
gHeroID sh_create_hero("Invis"pcvarLevel)
    
sh_set_hero_info(gHeroID"Go invis""Makes you invisible")
}

public 
sh_hero_init(idheroIDmode)
{
    if ( 
gHeroID != heroID ) return
    
    switch(
mode)
    {
        case 
SH_HERO_ADD:
        {
            
gHasInvis[id] = true
        
}
        
        case 
SH_HERO_DROP:
        {
            
gHasInvis[id] = false
        
}
    }

This code needs no explaining if you have read my beginner's tutorial.

So, what now?
Well, we start reading invisible woman. First up, we check out the forward plugin_init() to check which events has been used for this particular hero:

PHP Code:
public plugin_init()
{
    
// Plugin Info
    
register_plugin("SUPERHERO Invisible Woman""1.1""Glooba")

    
// DO NOT EDIT THIS FILE TO CHANGE CVARS, USE THE SHCONFIG.CFG
    
register_cvar("inviswoman_level""6")
    
register_cvar("inviswoman_alpha""0")
    
register_cvar("inviswoman_time""5")
    
register_cvar("inviswoman_cooldown""30")

    
// FIRE THE EVENT TO CREATE THIS SUPERHERO!
    
shCreateHero(gHeroName"Invisibility""Press +power key to become invisible for a short period of time"true"inviswoman_level")

    
// REGISTER EVENTS THIS HERO WILL RESPOND TO! (AND SERVER COMMANDS)
    // INIT
    
register_srvcmd("inviswoman_init""inviswoman_init")
    
shRegHeroInit(gHeroName"inviswoman_init")

    
// KEY DOWN
    
register_srvcmd("inviswoman_kd""inviswoman_kd")
    
shRegKeyDown(gHeroName"inviswoman_kd")

    
// NEW SPAWN
    
register_event("ResetHUD""newSpawn""b")

    
// DEATH
    
register_event("DeathMsg""inviswoman_death""a")

    
// LOOP
    
set_task(1.0"inviswoman_loop"0""0"b")

First up is the guy who made this wonder, Glooba, so if you are using this code, credit him if you post it, otherwise is just respectless.

We can easily see that this hero has been made by using the old 1.18 way of making heroes. This can be seen because it uses the old native shCreateHero, where the new native is called sh_create_hero. By now we know how to read this code.

The cvars are registered without using pcvars, this also tells us that this hero is old. Using pcvars is much more efficient and easier to read, which is why we will be using pcvars here. You should also know what that means.

As we have created the hero which you are able to pick, we skip to the register_event stuff which is what tells us when stuff will happen. We see an event called "ResetHUD". Now what is this? Well, if we look up register_event() on amxmodx.org: Here we see that the native is used like this:
register_event ( const event[], const function[], const flags[], [ cond=[], ... ] )
Okay, the event is the first parameter, this we see because it is explained so. But we have no idea what "ResetHUD" is, well, we look further. The next parameter says "NewSpawn". That is the function. The "NewSpawn" tells us that this is registering when a user spawns. Awesome, now we know that this hero checks when a user spawns! But wait, there is more! We also see an event called "DeathMsg". Well, using the method above we can figure out that this event registers when a user dies.

As a last this in plugin_init() we see a loop. Now what is this? Well, looking up set_task: Here we see an explanation of this: "set_task - Calls function on specified time". Okay, so now we know how what the native "set_task" actually does, but how does it work?

It works like this:
set_task ( Float:time, const function[], id = 0, parameter[]="", len = 0, flags[]="", repeat = 0 )
Okay, first param is how long it should take to call the function, next is what we want to call the function. We can set an index to the task too, but as there is no index in plugin_init() we can't do that. What is done this is just setting a "0". Every other parameters is not filled out, except the flag one. We can see that the flag "b" has been used. What does that mean?
Again checking amxmodx.org we see this:
-- "a" - Repeat task a specified number of times
-- "b" - Loop task infinitely
-- "c" - do task on time after a map timeleft
-- "d" - do task on time before a map timeleft
As flag "b" has been set, this task is run infinitely, which means it will always be called after the specified time. In invisible woman the specified time is 1 second and the function name is inviswoman_loop. This gives us no clue to what this actually is, but we know it runs each second. We might get a clue as to what this is later on.

Okay, moving on...

PHP Code:
public newSpawn(id)
{
    
gPlayerUltimateUsed[id] = false
    gInvisWomanTimer
[id] = -1
    
if ( gHasInvisWomanPower[id] ) {
        
inviswoman_endmode(id)
    }

Okay, the forward NewSpawn is this. What happens here? Well, we are assuming that this runs each time a player spawns. There is a new forward for that in the new ways of coding heroes. Lets check superheromod.inc to find it:

Code:
/**
 * Called post player spawn.
 *
 * @param id            The index of the client.
 * @param bool:newRound        True if client spawned because of a new round, else false.
 * @noreturn
 */
forward sh_client_spawn(id, bool:newRound);
Searching for "spawn" in the include file gave me this. This tells us that it is a forward, and it runs each time a user spawns. As this is in the include file, it is already registered, so there is no need to register it in plugin_init() like invisible woman does. We see two parameters. The first one being the index of the player who spawned, and the other one is a boolean which is set to true or false depending on the conditions described.

So, we know the new forward and how to use it, what now?
We see a global variable called gPlayerUltimateUsed. This is one of the few variables which is always created in your plugin, whether you like it or not, it is created, so why not use it? In the spawn even we set the variable to false to give the user a chance of using it in the new round, and he should not have to wait until his cooldown reaches 0.

Next we see that yet another new variable is used. This is called gInvisWomanTimer. The variable is set to -1 for some reason. We have no clue as to what this might be yet, but we add it just to be on the safe side.

The next line is a check to see if the user has invisible woman, and if he does, then take off invisibility. We have reset his cooldown so if he wishes to be invisible right away he can just do that.
So, lets add this to our plugin:

PHP Code:
public sh_client_spawn(id)
{
    
gPlayerUltimateUsed[id] = false
    gInvisWomanTimer
[id] = -1
    
if ( gHasInvis[id] )
    {
        
invis_endmode(id)
    }

But wait, we never created the gInvisWomanTimer variable. If you do not do this, the compiler will throw an error, since you can't use stuff which is not created. Imagine riding a bike without a bike, it can't be done.

So lets create the global variable:

PHP Code:
new gHeroID
new gHasInvis[SH_MAXSLOTS+1]
new 
gInvisTimer[SH_MAXSLOTS+1
Right, moving on to the next forward.

PHP Code:
public plugin_precache()
{
    
precache_sound(gInvisWomanSound)

You should know what this means. A sound is being precached. The sound path is specified using a variable "gInvisWomanSound". Now, just out of curiosity, we want to know where the sound is located. We see a "g" as the beginning letter. This is used to let the code readers know that it is a global variable, so lets check out the top and lets see if we can find that variable:

PHP Code:
// GLOBAL VARIABLES
new gHeroName[]="Invisible Woman"
new bool:gHasInvisWomanPower[SH_MAXSLOTS+1]
new 
gInvisWomanTimer[SH_MAXSLOTS+1]
new 
gInvisWomanMode[SH_MAXSLOTS+1]
new 
gAlpha
new gInvisWomanSound[]="player/heartbeat1.wav" 
Well, what do you know, the last global variable is gInvisWomanSound. The path is player/heartbeat1.wav. This is a sound which already exists in the cs 1.6 game, so there is no need to upload that, we can just precache it and the game will find out the rest.

Now, we want this sound too, just for the fun of it, so we do it the same way to our plugin:

PHP Code:
new gHeroID
new gHasInvis[SH_MAXSLOTS+1]
new 
gInvisTimer[SH_MAXSLOTS+1]
new 
gInvisSound[] = "player/heartbeat1.wav" 
PHP Code:
public plugin_precache()
{
    
precache_sound(gInvisSound)

Moving on:

PHP Code:
// RESPOND TO KEYDOWN
public inviswoman_kd()
{
    if ( !
hasRoundStarted() ) return

    
// First Argument is an id
    
new temp[6]
    
read_argv(1,temp,5)
    new 
id str_to_num(temp)

    if ( !
is_user_alive(id) || !gHasInvisWomanPower[id] ) return

    
// Make sure they're not in the middle of invisible woman mode
    // Let them know they already used their ultimate if they have
    
if ( gPlayerUltimateUsed[id] || gInvisWomanTimer[id] > ) {
        
playSoundDenySelect(id)
        return
    }

    
gInvisWomanTimer[id] = get_cvar_num("inviswoman_time")
    if (
get_cvar_float("inviswoman_cooldown") > 0.0 ultimateTimer(idget_cvar_float("inviswoman_cooldown"))

    
gAlpha get_cvar_num("inviswoman_alpha")
    
set_user_rendering(idkRenderFxGlowShell000kRenderTransAlphagAlpha)

    
gInvisWomanMode[id] = true

    
new message[128]
    
format(message127"You have now turned invisible")
    
set_hudmessage(5050255, -1.00.2800.01.00.00.054)
    
show_hudmessage(idmessage)

    
emit_sound(idCHAN_STATICgInvisWomanSound0.1ATTN_NORM0PITCH_NORM)

Oh, here we get a comment at the top, which lets us know that this forward is called each time a player presses the keydown for the hero. The name itself also explains it.

As this is written the old way, this code has to read the id manually, this is already done in the new 1.2 way of making heroes. How do we find out what the new native is named? Well, we open up our superheromod.inc and search for "key", the first result should be this:

Code:
/**
 * Called when a +/-power is executed.
 * See superheroconst.inc for key types.
 *
 * @param id            The index of the client.
 * @param heroID        The index of the hero.
 * @param key            The heroID power key function, key down or key up.
 * @noreturn
 */
forward sh_hero_key(id, heroID, key);
Here it is explained how to use this stuff. It says that when this forward is called, it already gives you the index of the user, the index of the hero used and the key pressed. To see key types we can look in superheroconst.inc. Now what is the key types in the new ways of doing this? Lets take a look:

Code:
// sh_hero_key(id, heroID, key) keys
#define SH_KEYUP        0    //Power Key is released
#define SH_KEYDOWN        1    //Power Key is pressed
I have searched after "key" and this is what it found first. This tells us that SH_KEYUP is defined to when the power key is not pressed anymore, and SH_KEYDOWN is when the power key is pressed.

Now, we need to register that the hero is in fact using this key stuff, this we do by using the native sh_set_hero_bind(). Now where do we use this?
First we check the include:

Code:
/**
 * Sets the hero to use a +power bind key. (Optional)
 * Use only if hero requires a bound key.
 *
 * @param heroID    The index of the hero.
 * @noreturn
 */
native sh_set_hero_bind(heroID);
The search for "key" again reviled something. This is a native which needs to know the hero index to set keydown to that specific hero.
Now where to use it? If you are looking at other keydown heroes which is made in 1.2 ways, we see that it is used in plugin_init(), so lets do that:

PHP Code:
public plugin_init()
{
    
register_plugin("SUPERHERO Invis""1.0""Jelle")
    
    new 
pcvarLevel register_cvar("invis_level""0")
    
    
gHeroID sh_create_hero("Invis"pcvarLevel)
    
sh_set_hero_info(gHeroID"Go invis""Makes you invisible")
    
    
sh_set_hero_bind(gHeroID)

Awesome, now superhero knows that it should add a bind to our hero!

Next we found out by looking in the include that the forward was sh_hero_key() and that it returned some information automatically for us. and in the hero invisible woman only the keydown is registered. Now lets actually use it:

PHP Code:
public sh_hero_key(idheroIDkey)
{
    if ( 
gHeroID != heroID ) return
    
    if ( 
key == SH_KEYDOWN && is_user_alive(id) )
    {
        
//stuff to go here
    
}

Okay, now the keydown forward has been added. First we need to check if it is the right hero index, we don't want this code to run if you press keydown for another hero. Next is a check to see if the key is pressed down, and to see if the user is alive. We do not want dead users to get invisibility.

So, what now? Now we look at the next part of the invisible woman code. We see this:

PHP Code:
    // Make sure they're not in the middle of invisible woman mode
    // Let them know they already used their ultimate if they have
    
if ( gPlayerUltimateUsed[id] || gInvisWomanTimer[id] > ) {
        
playSoundDenySelect(id)
        return
    } 
Awesome, some comments again! The author Glooba has been very helpful so far, and remember, you should also add comments to your new code if you post it, then other newbies can see what happens in it.

Now, the comments say that this is a check to see if the user has used his ultimate (ultimate being the keydown). This we should also check.
We learned earlier that gPlayerUltimateUsed is a build in variable, so that is already created. Next is the timer thing, which we still have no idea what is actually doing. That we use for the check too, just to be on the safe side, there is a reason why it is there.

PHP Code:
public sh_hero_key(idheroIDkey)
{
    if ( 
gHeroID != heroID ) return
    
    if ( 
key == SH_KEYDOWN && is_user_alive(id) )
    {
        if ( 
gPlayerUltimateUsed[id] || gInvisTimer[id] > )
        {
            
sh_sound_deny(id)
        }
    }

So, now we have this. I have changed the native PlaySoundDenySelect to sh_sound_deny. The reason is that it is the new native for 1.2 ways. How do I know that? I looked in the superheromod.inc file, you should do that same.

Next in the keydown code we see this:

PHP Code:
    gInvisWomanTimer[id] = get_cvar_num("inviswoman_time")
    if (
get_cvar_float("inviswoman_cooldown") > 0.0 ultimateTimer(idget_cvar_float("inviswoman_cooldown")) 
What happens here is that gInvisWomanTimer fetches a cvar value. This can be done this way, but as I have said in the beginning, we should be using pcvars as that is a bit faster. The p in cvar means pointer. When using pcvars we create a new variable to hold the information of what the specific cvar is set to. Before we can do anything in the keydown, we need to register that cvar.

How do we do that? Well, you should be knowing this by now, but anyway, I am going to show this really quick:

First off, a pcvar which has to be used elsewhere than where it is created should be global, then it can be used in any forward we like.

So simply add a new variable to hold the cvar value:

PHP Code:
new gHeroID
new gHasInvis[SH_MAXSLOTS+1]
new 
gInvisTimer[SH_MAXSLOTS+1]
new 
gInvisSound[] = "player/heartbeat1.wav"

new pcvarTimer 
I have made a space between gInvisSound and the pcvar, that is just to make it easier to read, nothing else.

Okay, the new global variable has been created to hold the cvar value, now lets create the cvar:

PHP Code:
public plugin_init()
{
    
register_plugin("SUPERHERO Invis""1.0""Jelle")
    
    new 
pcvarLevel register_cvar("invis_level""0")
    
pcvarTimer register_cvar("invis_time""5")
    
    
gHeroID sh_create_hero("Invis"pcvarLevel)
    
sh_set_hero_info(gHeroID"Go invis""Makes you invisible")
    
    
sh_set_hero_bind(gHeroID)

The new global variable we called pcvarTimer has now been pointed at the register_cvar native. This native creates the cvar, now we can use it.
__________________
No idea what to write here...

Last edited by Jelle; 06-07-2011 at 19:29.
Jelle is offline
Send a message via MSN to Jelle
Jelle
[b]MOAR CANDY[/b]
Join Date: Aug 2009
Location: Denmark
Old 05-27-2011 , 05:17   Re: [Tutorial] Reading/ripping hero codes
Reply With Quote #2

Okay, lets move on. We have created the pcvar variable now, and it points to the cvar, so now the value of the cvar is stored in the pcvar

But wait, there is more in this piece of code. There is a cvar more which is registered!

We register this cvar as a pcvar too, and then use it the same way as in invisible woman.

First the new global variable:

PHP Code:
new gHeroID
new gHasInvis[SH_MAXSLOTS+1]
new 
gInvisTimer[SH_MAXSLOTS+1]
new 
gInvisSound[] = "player/heartbeat1.wav"

new pcvarTimer
new pcvarCooldown 
Then we register it:

PHP Code:
public plugin_init()
{
    
register_plugin("SUPERHERO Invis""1.0""Jelle")
    
    new 
pcvarLevel register_cvar("invis_level""0")
    
pcvarTimer register_cvar("invis_time""5")
    
pcvarCooldown register_cvar("invis_cooldown""10")
    
    
gHeroID sh_create_hero("Invis"pcvarLevel)
    
sh_set_hero_info(gHeroID"Go invis""Makes you invisible")
    
    
sh_set_hero_bind(gHeroID)

and now we combine the keydown code using the new pcvars created:

PHP Code:
public sh_hero_key(idheroIDkey)
{
    if ( 
gHeroID != heroID ) return
    
    if ( 
key == SH_KEYDOWN && is_user_alive(id) )
    {
        if ( 
gPlayerUltimateUsed[id] || gInvisTimer[id] > )
        {
            
sh_sound_deny(id)
        }
        
        
gInvisTimer[id] = get_pcvar_num(pcvarTimer)
        if ( 
get_pcvar_float(pcvarCooldown) > 0.0 )
        {
            
ultimateTimer(idget_pcvar_float(pcvarCooldown))
        }
    }

Next piece of code in the keydown forward:

PHP Code:
    gAlpha get_cvar_num("inviswoman_alpha")
    
set_user_rendering(idkRenderFxGlowShell000kRenderTransAlphagAlpha
This is where the invisibility is actually set. We know that because of the word alpha, and the use of the native set_user_rendering.

We can see that a new variable has been created to hold the value of the cvar "inviswoman_alpha". First we should create that cvar, and we create it as a pcvar:

PHP Code:
new gHeroID
new gHasInvis[SH_MAXSLOTS+1]
new 
gInvisTimer[SH_MAXSLOTS+1]
new 
gInvisSound[] = "player/heartbeat1.wav"

new pcvarTimer
new pcvarCooldown
new pcvarAlpha 
PHP Code:
public plugin_init()
{
    
register_plugin("SUPERHERO Invis""1.0""Jelle")
    
    new 
pcvarLevel register_cvar("invis_level""0")
    
pcvarTimer register_cvar("invis_time""5")
    
pcvarCooldown register_cvar("invis_cooldown""10")
    
pcvarAlpha register_cvar("invis_alpha""100")
    
    
gHeroID sh_create_hero("Invis"pcvarLevel)
    
sh_set_hero_info(gHeroID"Go invis""Makes you invisible")
    
    
sh_set_hero_bind(gHeroID)

Now we have already stored the cvar value in a variable, so we actually do not need to create and use the variable called gAlpha from invisible woman. To retrieve the value of the cvar we use a native called get_pcvar_num, get_pcvar_float or get_pcvar_string as you might have seen. You should already know what a float and a string is. And in case you don't know, num is used for an integer.

So, we can actually combine these two lines into one:

PHP Code:
set_user_rendering(idkRenderFxGlowShell000kRenderTransAlphaget_pcvar_num(pcvarAlpha)) 
Inserting that into our plugin it becomes:

PHP Code:
public sh_hero_key(idheroIDkey)
{
    if ( 
gHeroID != heroID ) return
    
    if ( 
key == SH_KEYDOWN && is_user_alive(id) )
    {
        if ( 
gPlayerUltimateUsed[id] || gInvisTimer[id] > )
        {
            
sh_sound_deny(id)
        }
        
        
gInvisTimer[id] = get_pcvar_num(pcvarTimer)
        if ( 
get_pcvar_float(pcvarCooldown) > 0.0 )
        {
            
ultimateTimer(idget_pcvar_float(pcvarCooldown))
        }
        
        
set_user_rendering(idkRenderFxGlowShell000kRenderTransAlphaget_pcvar_num(pcvarAlpha))
    }

Now, what is kRenderFxGlowShell and kRenderTransAlpha? Well, lets look it up!

First we go to check amxmodx.org here

We see this:

A list of different render modes:
kRenderNormal = 0, /* src */
kRenderTransColor, /* c*a+dest*(1-a) */
kRenderTransTexture, /* src*a+dest*(1-a) */
kRenderGlow, /* src*a+dest -- No Z buffer checks */
kRenderTransAlpha, /* src*srca+dest*(1-srca) */
kRenderTransAdd, /* src*a+dest */

and this:

A list of different render effects:
kRenderFxNone = 0,
kRenderFxPulseSlow,
kRenderFxPulseFast,
kRenderFxPulseSlowWide,
kRenderFxPulseFastWide,
kRenderFxFadeSlow,
kRenderFxFadeFast,
kRenderFxSolidSlow,
kRenderFxSolidFast,
kRenderFxStrobeSlow,
kRenderFxStrobeFast,
kRenderFxStrobeFaster,
kRenderFxFlickerSlow,
kRenderFxFlickerFast,
kRenderFxNoDissipation,
kRenderFxDistort, /* Distort/scale/translate flicker */
kRenderFxHologram, /* kRenderFxDistort + distance fade */
kRenderFxDeadPlayer, /* kRenderAmt is the player index */
kRenderFxExplode, /* Scale up really big! */
kRenderFxGlowShell, /* Glowing Shell */
kRenderFxClampMinScale, /* Keep this sprite from getting very small (SPRITES only!) */

This really didn't help us much, lets dig a bit deeper, we take a look at the include file. We see on amxmodx.org that this native is in the include file called fun.inc, so we take a look at that and search for set_user_rendering, and here is what comes up:

Code:
/* Sets player rendering mode. */
native set_user_rendering(index, fx = kRenderFxNone, r = 255, g = 255, b = 255, render = kRenderNormal, amount = 16);
Oh well, this still didn't give us any clue as to what those two is used for, all we know is that it is render modes and render effects. We have seen a few comments as to what the effects and modes are, but we have not seen a complete list. Lets dig deeper. Now I know from reading the comments that these variables is fetched from the amxconst.inc include file. Lets look at that and search for render:

Code:
/* Render for set_user_rendering() */
enum {
    kRenderNormal = 0,        /* src */
    kRenderTransColor,        /* c*a+dest*(1-a) */
    kRenderTransTexture,        /* src*a+dest*(1-a) */
    kRenderGlow,            /* src*a+dest -- No Z buffer checks */
    kRenderTransAlpha,        /* src*srca+dest*(1-srca) */
    kRenderTransAdd,        /* src*a+dest */
};

/* Fx for set_user_rendering() */
enum {
    kRenderFxNone = 0,
    kRenderFxPulseSlow,
    kRenderFxPulseFast,
    kRenderFxPulseSlowWide,
    kRenderFxPulseFastWide,
    kRenderFxFadeSlow,
    kRenderFxFadeFast,
    kRenderFxSolidSlow,
    kRenderFxSolidFast,
    kRenderFxStrobeSlow,
    kRenderFxStrobeFast,
    kRenderFxStrobeFaster,
    kRenderFxFlickerSlow,
    kRenderFxFlickerFast,
    kRenderFxNoDissipation,
    kRenderFxDistort,        /* Distort/scale/translate flicker */
    kRenderFxHologram,        /* kRenderFxDistort + distance fade */
    kRenderFxDeadPlayer,        /* kRenderAmt is the player index */
    kRenderFxExplode,        /* Scale up really big! */
    kRenderFxGlowShell,        /* Glowing Shell */
    kRenderFxClampMinScale,        /* Keep this sprite from getting very small (SPRITES only!) */
};
We still don't know what some of the effects and modes are, and as seen it is quite hard to find out what it does.

Now instead of making a new topic named "What does the effects look like?", you should just test it yourself. I haven't tested it myself, so I really have no idea how it looks like, I have just been using the modes and effects from other plugins since I know how that looks like and I think that's just fine.

So, how can you test this? Well, you can install a 3rd person mode plugin. How do you find that? You DO NOT create a new topic asking for it, you SEARCH for it. Go to the amx mod x section and search in the approved plugins section. Searching for "3rd person" is enough to give me a few results. Then you just try out a few different effects and modes while 3rd person is on and you will be able to see the difference.

Now lets move on with the invisible woman code:

PHP Code:
    gInvisWomanMode[id] = true 
A new variable has been used here. As seen in the name it is a Boolean which is used to check later on if the person is using the power of not. We might use this later on, so we add it to our code.

First we create the variable:

PHP Code:
new gHeroID
new gHasInvis[SH_MAXSLOTS+1]
new 
gInvisTimer[SH_MAXSLOTS+1]
new 
gInvisSound[] = "player/heartbeat1.wav"
new bool:gInvisMode[SH_MAXSLOTS+1]

new 
pcvarTimer
new pcvarCooldown
new pcvarAlpha 
Then we add it to our code:

PHP Code:
public sh_hero_key(idheroIDkey)
{
    if ( 
gHeroID != heroID ) return
    
    if ( 
key == SH_KEYDOWN && is_user_alive(id) )
    {
        if ( 
gPlayerUltimateUsed[id] || gInvisTimer[id] > )
        {
            
sh_sound_deny(id)
        }
        
        
gInvisTimer[id] = get_pcvar_num(pcvarTimer)
        if ( 
get_pcvar_float(pcvarCooldown) > 0.0 )
        {
            
ultimateTimer(idget_pcvar_float(pcvarCooldown))
        }
        
        
set_user_rendering(idkRenderFxGlowShell000kRenderTransAlphaget_pcvar_num(pcvarAlpha))
        
        
gInvisMode[id] = true
    
}

Okay, with that done we move on with the next piece of code, still in the keydown forward.

PHP Code:
    new message[128]
    
format(message127"You have now turned invisible")
    
set_hudmessage(5050255, -1.00.2800.01.00.00.054)
    
show_hudmessage(idmessage
What is this crap now? Well, we see a new variable called message, so we assume it is a message of some sort. We also see "You have now turned invisible" and as we know this is running when keydown is pressed, so this is to let the user know that he is in fact invisible. We also see a native called show_hudmessage, so we then assume it is a hud message.

A new variable called message is created as an array with 128 blocks. Next is a native used called format. What does format do?
Yes, you guessed it, we are going to look it up!
Searching for format on amxmodx.org here

It reviles this:

Quote:
Originally Posted by amxmodx.org
format - Format a string with a given format and parameters.
Okay, maybe just a bunch of random words to you, so lets dig deeper to see what this does.

Code:
 format ( output[], len, const format[], ... )
Okay, first parameter is the output, which is this case is the variable called message, next is the blocks of the array (this native apparently needs an output variable created as an array). As you should know by now, we always minus 1 from the array size. That is because message[0] is 1, message[1] is 2 and so on, and creating a variable like "message[128]" would be 127 in len. The next parameter is what to format. What is formatted in this is "You have now turned invisible".
Basically this makes "You have now turned invisible" in each block of the message variable. This frees you from doing it like this:

PHP Code:
new message[128]
message[0] = "Y"
message[1] = "o"
message[2] = "u" 
and so on.

So, next it is setting the hud message, now what does this mean? Yes, we are going to look that up as well!
here

So what we see is that this sets the format for the HUD message.
We also see this:

Code:
set_hudmessage ( red=200, green=100, blue=0, Float:x=-1.0,  Float:y=0.35, effects=0, Float:fxtime=6.0, Float:holdtime=12.0,  Float:fadeintime=0.1, Float:fadeouttime=0.2, channel=4 )
With this we can set what color the HUD message should have, how long time, where, how and basically everything regarding the HUD message. We also see that each player has 4 channels. This means that a maximum of 4 HUD messages can be written on the screen of a client. This is also why a HUD message might disappear very quick from clients on a server with a lot of HUD messages.

next is show_hudmessage. Looking at the name, this shows the HUD message. First the index to show it to (the guy who pressed the keydown and has the hero) and then the message we wrote.

As the natives are all the same since this hero was made we are going to just use that without an edit of it:

PHP Code:
public sh_hero_key(idheroIDkey)
{
    if ( 
gHeroID != heroID ) return
    
    if ( 
key == SH_KEYDOWN && is_user_alive(id) )
    {
        if ( 
gPlayerUltimateUsed[id] || gInvisTimer[id] > )
        {
            
sh_sound_deny(id)
        }
        
        
gInvisTimer[id] = get_pcvar_num(pcvarTimer)
        if ( 
get_pcvar_float(pcvarCooldown) > 0.0 )
        {
            
ultimateTimer(idget_pcvar_float(pcvarCooldown))
        }
        
        
set_user_rendering(idkRenderFxGlowShell000kRenderTransAlphaget_pcvar_num(pcvarAlpha))
        
        
gInvisMode[id] = true
        
        
new message[128]
        
format(message127"You have now turned invisible")
        
set_hudmessage(5050255, -1.00.2800.01.00.00.054)
        
show_hudmessage(idmessage)
    }

As a last thing in this keydown forward we see a native called emit_sound:

PHP Code:
emit_sound(idCHAN_STATICgInvisWomanSound0.1ATTN_NORM0PITCH_NORM
Yes, we are going to look this up too, here

So, this site says that it, funny enough, emits a sound. The sound HAS to be precached before it can be played. Well, we precached a sound earlier on, and this is where you can use it.

Looking further at amxmodx.org we also see a list of constants used. In invisible woman CHAN_STATIC, ATTN_NORM and PITCH_NORM is used as constants. What else can be used is described on amxmodx.org.
Now, I have always been using this as it is written in invisible woman, so I have no idea how the different constants works, and I am not going to search as deep into it as I did with the render stuff, you will have to do that yourself if you really want to know what it really does.
Anyway, we add this to our code as well, because having a sound is just badass.

PHP Code:
public sh_hero_key(idheroIDkey)
{
    if ( 
gHeroID != heroID ) return
    
    if ( 
key == SH_KEYDOWN && is_user_alive(id) )
    {
        if ( 
gPlayerUltimateUsed[id] || gInvisTimer[id] > )
        {
            
sh_sound_deny(id)
        }
        
        
gInvisTimer[id] = get_pcvar_num(pcvarTimer)
        if ( 
get_pcvar_float(pcvarCooldown) > 0.0 )
        {
            
ultimateTimer(idget_pcvar_float(pcvarCooldown))
        }
        
        
set_user_rendering(idkRenderFxGlowShell000kRenderTransAlphaget_pcvar_num(pcvarAlpha))
        
        
gInvisMode[id] = true
        
        
new message[128]
        
format(message127"You have now turned invisible")
        
set_hudmessage(5050255, -1.00.2800.01.00.00.054)
        
show_hudmessage(idmessage)
        
        
emit_sound(idCHAN_STATICgInvisSound0.1ATTN_NORM0PITCH_NORM)
    }

Great, we are now done with the keydown forward. Next up is the stopSound forward. We have not yet used this forward anywhere, but surely it is used somewhere in the plugin, so we just create it now. The forward is this:

PHP Code:
public stopSound(id)
{
    
emit_sound(idCHAN_STATICgInvisWomanSound0.1ATTN_NORMSND_STOPPITCH_NORM)

So, the parameters in this forward must be stopping the sound, and the other emit_sound might be repeating the sound constantly while invisibility is on, and this is what stops it. We see SND_STOP as a constant, which is probably what stops it, but I really have no idea. Well, one thing I know is that gInvisWomanSound is not what I called the variable, but gInvisSound, so the forward would be:

PHP Code:
public stopSound(id)
{
    
emit_sound(idCHAN_STATICgInvisSound0.1ATTN_NORMSND_STOPPITCH_NORM)

Okay, so that was the stop of the sound.

Next up is the loop which we talked about in the beginning when we were looking at plugin_init.

PHP Code:
public inviswoman_loop()
{
    for ( new 
id 1id <= SH_MAXSLOTSid++ ) {
        if ( 
gHasInvisWomanPower[id] && is_user_alive(id) ) {
            if ( 
gInvisWomanTimer[id] > ) {
                new 
message[128]
                
format(message127"%d second%s left of invisibility"gInvisWomanTimer[id], gInvisWomanTimer[id] == "" "s")
                
set_hudmessage(5050255, -1.00.2800.01.00.00.054)
                
show_hudmessage(idmessage)

                
set_user_rendering(idkRenderFxGlowShell000kRenderTransAlphagAlpha)

                
gInvisWomanTimer[id]--
            }
            else if ( 
gInvisWomanTimer[id] == ) {
                    
gInvisWomanTimer[id]--
                    
inviswoman_endmode(id)
            }
        }
    }

So, what do we know about this?
We know that this runs each second infinitely, and we know that there is no player index which can be used.

We see a for. This is like if. This is called a for loop. How does this for look thing work?
Can you guess what I am about to write?
Oh yes, you did. We are going to look that up!
So, as this is a part of the scripting language itself and is used in many other scripting languages, such as PHP.
But we want to know how this works for pawn, and more importantly how it works in this context.

So, you should be familiar with the amxx wiki site:
http://wiki.amxmodx.org/index.php/Main_Page

In the intro to amxx scripting (here) there is something about a for loop. Before actually reading this tutorial you should have read that page at first, but as many people just skip such things, I will try to explain it really quick.

A for loop is a loop which starts from 1 to a specified number. In this case the specified number is SH_MAXSLOTS. As you should know this can be changed in the superheromodconst.inc file. In this you can specify how many max players is available to join your server. Standard it is set to 32 as that is maximum of a cs 1.6 server. So in this case it will run this loop 32 times. Running through all the player slots, even if the player slot is not occupied.

So lets break it down:

PHP Code:
for ( new id 1id SH_MAXSLOTSid++ ) 
First a new variable is create. This is called the initialization of the loop. We start at 1 since index 0 is the server itself, and that can't possible have this hero since that is not a player.
Next is how many times to run this loop. In this case it is how much SH_MAXSLOTS is defined to (for me it is 32). Next means to add 1 more to id. So to start with id is player slot 1, then when that whole piece of code has been run, is makes id to 2, so it will be player slot 2 and so on until it hits 32. At 32 we have set it to stop. Remember this runs 32 times each second. This is a bit heavy for the server, but making it efficiently and you wont notice having them. But of course having 200 heroes with a loop each (or even two) is very heavy for the CPU in the server.

Now that you know a bit more about a for loop (even though you should have known this to start with) we move on.

Again looking at the loop, we see that in this loop it checks if the player spot has the hero and if he is alive. If these are correct, then check to see if the timer is more than 0, which means that the user has the power running. If the power is running then let him know how long time he has left. This is done using format and a HUD message. Next it sets the rendering once again. This is because if there is another hero setting like a glow, the invisibility is removed, then this sets the invisibility again. This is actually why you might see people blinking when they have many heroes, this is because the heroes are fighter over which one to control the render of the player. At last we minus 1 from gInvisWomanTimer. -- means -1 and ++ also means +1.

So, what if the timer is not bigger than 0? Then he must have used all his time. So, we have a check to see if timer is 0, and if it is minus 1 from it to make it -1. Next up a forward is created. So if the guy has used all his time, then go to the forward called inviswoman_endmode().
So, we finally know what the loop is doing and is actually pretty clever as it tells the player how much time he has left.

This we add to our plugin, and of course writing it so it fits with the variable names I have used:

First we actually make the loop as we didn't do that yet because we didn't know what it did before now:

PHP Code:
public plugin_init()
{
    
register_plugin("SUPERHERO Invis""1.0""Jelle")
    
    new 
pcvarLevel register_cvar("invis_level""0")
    
pcvarTimer register_cvar("invis_time""5")
    
pcvarCooldown register_cvar("invis_cooldown""10")
    
pcvarAlpha register_cvar("invis_alpha""100")
    
    
gHeroID sh_create_hero("Invis"pcvarLevel)
    
sh_set_hero_info(gHeroID"Go invis""Makes you invisible")
    
    
sh_set_hero_bind(gHeroID)
    
    
set_task(1.0"inviswoman_loop"0""0"b")

Next the loop forward:

PHP Code:
public inviswoman_loop()
{
    for ( new 
id 1id <= SH_MAXSLOTSid++ )
    {
        if ( 
gHasInvis[id] && is_user_alive(id) ) 
        {
            if ( 
gInvisTimer[id] > 
            {
                new 
message[128]
                
format(message127"%d second%s left of invisibility"gInvisTimer[id], gInvisTimer[id] == "" "s")
                
set_hudmessage(5050255, -1.00.2800.01.00.00.054)
                
show_hudmessage(idmessage)

                
set_user_rendering(idkRenderFxGlowShell000kRenderTransAlphaget_pcvar_num(pcvarAlpha))

                
gInvisTimer[id]--
            }
            
            else if ( 
gInvisTimer[id] == )
            {
                    
gInvisTimer[id]--
                    
invis_endmode(id)
            }
        }
    }

Great, now for what to do in the invis_endmode forward:

PHP Code:
public inviswoman_endmode(id)
{
    if ( !
is_user_connected(id) ) return

    
gInvisWomanTimer[id] = -1
    stopSound
(id)

    if ( 
gInvisWomanMode[id]) {
        
set_user_rendering(id)
        
gInvisWomanMode[id] = false
    
}

So, first a check to see if the user is connected. Why this? Well, because the player might have disconnected during this change from the loop to this forward. If this happens and this check is not there, then you will end up with a server crash since it can't do anything with a player spot which is not occupied. Next we make sure that gInvisWomanTimer is -1. Then we stop the sound using the stopSound forward which was made earlier on.
Then last a check to see if invisible mode is on, and if it is, then turn it off by making the variable gInvisWomanMode to false.

There is nothing really new here, so we are just going to add this to our plugin:

PHP Code:
public invis_endmode(id)
{
    if ( !
is_user_connected(id) ) return

    
gInvisTimer[id] = -1
    stopSound
(id)

    if ( 
gInvisWomanMode[id] )
    {
        
set_user_rendering(id)
        
gInvisWomanMode[id] = false
    
}

Lastly we have this:

PHP Code:
public inviswoman_death()
{
    new 
id read_data(2)

    
gPlayerUltimateUsed[id] = false

    gInvisWomanTimer
[id] = -1

    
if (gHasInvisWomanPower[id]) {
        
inviswoman_endmode(id)
    }

As we found out earlier, this forward runs each time a player dies. In this old coded hero the forward needs to be registered, in these new ways of doing it, this event is already registered. Now what is it called? Yes, lets look it up!
Searching for death in the superheromod.inc file gives this result:

Code:
/**
 * Called whenever a client dies.
 * Death from sh_extra_damage will send correct info into this forward.
 *
 * @param victim        The index of the victim.
 * @param attacker        The index of the attacker.
 * @param headshot        Equals 1 if death is by a headshot else 0.
 * @param wpnDescription    Name of the weapon that killed the victim.
 * @noreturn
 */
forward sh_client_death(victim, attacker, headshot, const wpnDescription[]);
So, what we learn is that this forward returns the index of the victim and the attacker. It also returns if the victim died from a headshot or not and which weapon was used. Actually a lot of information is given. In the old days we had to get all of these informations our self, so this is just luxury that Vittu has done it like this.

So, now we know how to use this forward. What should happen when a player dies then?

At first the ultimate timer is reset (so the player can use the power right away when spawned again). Then gInvisWomanTimer is set to -1. Then a check to see if the user has the hero. If he has, then go to inviswoman_endmode which we did earlier and made it take off the power. So, we use this code in our plugin too. And as we actually only need to know the index of the guy who died, so we can just do it like this:

PHP Code:
public sh_client_death(victim)
{
    
gPlayerUltimateUsed[victim] = false

    gInvisTimer
[victim] = -1

    
if ( gHasInvis[victim] )
    {
        
invis_endmode(victim)
    }

And now that is it! You are done! Lets take a look at the final code:

PHP Code:
#include <superheromod>

new gHeroID
new gHasInvis[SH_MAXSLOTS+1]
new 
gInvisTimer[SH_MAXSLOTS+1]
new 
gInvisSound[] = "player/heartbeat1.wav"
new bool:gInvisMode[SH_MAXSLOTS+1]

new 
pcvarTimer
new pcvarCooldown
new pcvarAlpha

public plugin_init()
{
    
register_plugin("SUPERHERO Invis""1.0""Jelle")
    
    new 
pcvarLevel register_cvar("invis_level""0")
    
pcvarTimer register_cvar("invis_time""5")
    
pcvarCooldown register_cvar("invis_cooldown""10")
    
pcvarAlpha register_cvar("invis_alpha""100")
    
    
gHeroID sh_create_hero("Invis"pcvarLevel)
    
sh_set_hero_info(gHeroID"Go invis""Makes you invisible")
    
    
sh_set_hero_bind(gHeroID)
    
    
set_task(1.0"inviswoman_loop"0""0"b")
}

public 
sh_hero_init(idheroIDmode)
{
    if ( 
gHeroID != heroID ) return
    
    switch(
mode)
    {
        case 
SH_HERO_ADD:
        {
            
gHasInvis[id] = true
        
}
        
        case 
SH_HERO_DROP:
        {
            
gHasInvis[id] = false
        
}
    }
}

public 
sh_hero_key(idheroIDkey)
{
    if ( 
gHeroID != heroID ) return
    
    if ( 
key == SH_KEYDOWN && is_user_alive(id) )
    {
        if ( 
gPlayerUltimateUsed[id] || gInvisTimer[id] > )
        {
            
sh_sound_deny(id)
        }
        
        
gInvisTimer[id] = get_pcvar_num(pcvarTimer)
        if ( 
get_pcvar_float(pcvarCooldown) > 0.0 )
        {
            
ultimateTimer(idget_pcvar_float(pcvarCooldown))
        }
        
        
set_user_rendering(idkRenderFxGlowShell000kRenderTransAlphaget_pcvar_num(pcvarAlpha))
        
        
gInvisMode[id] = true
        
        
new message[128]
        
format(message127"You have now turned invisible")
        
set_hudmessage(5050255, -1.00.2800.01.00.00.054)
        
show_hudmessage(idmessage)
        
        
emit_sound(idCHAN_STATICgInvisSound0.1ATTN_NORM0PITCH_NORM)
    }
}

public 
stopSound(id)
{
    
emit_sound(idCHAN_STATICgInvisSound0.1ATTN_NORMSND_STOPPITCH_NORM)
}

public 
inviswoman_loop()
{
    for ( new 
id 1id <= SH_MAXSLOTSid++ )
    {
        if ( 
gHasInvis[id] && is_user_alive(id) ) 
        {
            if ( 
gInvisTimer[id] > 
            {
                new 
message[128]
                
format(message127"%d second%s left of invisibility"gInvisTimer[id], gInvisTimer[id] == "" "s")
                
set_hudmessage(5050255, -1.00.2800.01.00.00.054)
                
show_hudmessage(idmessage)

                
set_user_rendering(idkRenderFxGlowShell000kRenderTransAlphaget_pcvar_num(pcvarAlpha))

                
gInvisTimer[id]--
            }
            
            else if ( 
gInvisTimer[id] == )
            {
                    
gInvisTimer[id]--
                    
invis_endmode(id)
            }
        }
    }
}

public 
invis_endmode(id)
{
    if ( !
is_user_connected(id) ) return

    
gInvisTimer[id] = -1
    stopSound
(id)

    if ( 
gInvisMode[id] )
    {
        
set_user_rendering(id)
        
gInvisMode[id] = false
    
}
}

public 
sh_client_death(victim)
{
    
gPlayerUltimateUsed[victim] = false

    gInvisTimer
[victim] = -1

    
if ( gHasInvis[victim] )
    {
        
invis_endmode(victim)
    }

Congratulations, you now know what everything in this hero does and how it works. You should also have gained enough knowledge on how to read other heroes and ripping them, or just reading and understanding them. This is actually all that you need to be making your own heroes, as you now know how to search for a native and how to actually use it.

Now remember, this is just my way of doing it. My way doesn't necessarily have to be the best way. I also do it like this because I think that is the easiest way to read my code. If you make your indentation in anyway way you like, but know this: If your indentation really sucks and I am having just the slightest difficulty reading your code, I am not going to bother helping you, and I bet many users in here feel the same way. If you want help, then write your code so we can read it and don't just cluster it all together. Spaces and white places does not add to the compiled plugin file size and the compiler will skip those, so there is no reason at all to not indent your code properly.
__________________
No idea what to write here...

Last edited by Jelle; 06-07-2011 at 19:25.
Jelle is offline
Send a message via MSN to Jelle
Jelle
[b]MOAR CANDY[/b]
Join Date: Aug 2009
Location: Denmark
Old 05-27-2011 , 05:17   Re: [Tutorial] Reading/ripping hero codes
Reply With Quote #3

Now this is fine and all. But we really don't want to make this hero a keydown hero, we would rather just have a hero which just constantly gives invisibility.

So we have created the hero using the new ways, so we are going to use that as a base of the new hero we are going to create. To start off, we again make a very simple hero which does nothing but let you select it:

PHP Code:
#include <superheromod>

new gHeroID
new gHasInvis[SH_MAXSLOTS+1]

public 
plugin_init()
{
    
register_plugin("SUPERHERO Invis""1.0""Jelle")
    
    new 
pcvarLevel register_cvar("invis_level""5")
    
    
gHeroID sh_create_hero("Invis"pcvarLevel)
    
sh_set_hero_info(gHeroID"Go Invis""Makes you invisible")
}

public 
sh_hero_init(idheroIDmode)
{
    if ( 
gHeroID != heroID ) return
    
    switch(
mode)
    {
        case 
SH_HERO_ADD:
        {
            
gHasInvis[id] = true
        
}
        
        case 
SH_HERO_DROP:
        {
            
gHasInvis[id] = false
        
}
    }

Now we move on. As we don't really want to think so much about the global variables we just create them as we are going to need them, so the first thing we take a look at is plugin_ini():

PHP Code:
public plugin_init()
{
    
register_plugin("SUPERHERO Invis""1.0""Jelle")
    
    new 
pcvarLevel register_cvar("invis_level""0")
    
pcvarTimer register_cvar("invis_time""5")
    
pcvarCooldown register_cvar("invis_cooldown""10")
    
pcvarAlpha register_cvar("invis_alpha""100")
    
    
gHeroID sh_create_hero("Invis"pcvarLevel)
    
sh_set_hero_info(gHeroID"Go invis""Makes you invisible")
    
    
sh_set_hero_bind(gHeroID)
    
    
set_task(1.0"inviswoman_loop"0""0"b")

We don't need all the pcvars we created earlier. We just need the alpha stuff and the level cvar, so we just delete the cvars we don't need. Next is the sh_set_hero_bind which is pretty useless for us as we do not want to set a bind, we just want it to be an automatic hero. We need the loop as we do not want glowing heroes to take over. So plugin_init() becomes:

PHP Code:
public plugin_init()
{
    
register_plugin("SUPERHERO Invis""1.0""Jelle")
    
    new 
pcvarLevel register_cvar("invis_level""5")
    
pcvarAlpha register_cvar("invis_alpha""100")
    
    
gHeroID sh_create_hero("Invis"pcvarLevel)
    
sh_set_hero_info(gHeroID"Go Invis""Makes you invisible")
    
    
set_task(1.0"invis_loop"___"b")

Next is the hero init. We want the invisibility to be activated if the guy picks the hero while he is alive. For this we need the hero init:

PHP Code:
public sh_hero_init(idheroIDmode)
{
    if ( 
gHeroID != heroID ) return
    
    switch(
mode)
    {
        case 
SH_HERO_ADD:
        {
            
gHasInvis[id] = true
            activate_invis
(id)
        }
        
        case 
SH_HERO_DROP:
        {
            
gHasInvis[id] = false
        
}
    }

So when this hero is picked I have made a new forward which runs when that happens. I have named it activate_invis since that makes the most sense in this case. So now lets make activate_invis:

PHP Code:
activate_invis(id)
{
    if ( 
gHasInvis[id] && is_user_alive(id) && is_user_connected(id) )
    {
        
set_user_rendering(idkRenderFxGlowShell000kRenderTransAlphaget_pcvar_num(pcvarAlpha))
    }

At first we check if the user has the hero. We want to cover as much as possible, as we also want to use this forward in other conditions. I will explain that once we get to it. Next is an alive check. We do not want to set invis on a dead guy. Lastly is a connection test. If the user disconnected in the time between he added the hero and when this forward runs then you will have a server crash. But you would have to be REALLY fast to choose a hero and then disconnect right after. But again, we want to use this on other occasions as well.
The reason why I didn't add the sound in this one is because it will never stop, and I just think it is too much effort considering what you get out of it. You may add it yourself, but remember to stop it when the guy dies (using sh_client_death()) else it will keep on going when he is dead.

Next is our loop. Again because we do not want glowing heroes to take over. This can be almost taken right out of our other hero. Just that we do not have a cooldown, thus we do not need all those variables to control and check the cooldown. So the loop will be this:

PHP Code:
public invis_loop()
{
    for ( new 
id 1id <= SH_MAXSLOTSid++ )
    {
        
activate_invis(id)
    }

This is very simple. We loop through all players and run activate_invis forward for each player. We made that forward to check if the guy has the hero, if he is alive and if he is connected, if that is true, then he gets invisibility. There might be a better way of doing it, but as I am not paranoid about efficiency (*cough*Freeman*cough*) I am doing it like this. At the bottom of this tutorial I will post what I think is the most efficient way, just to make certain people happy (*cough cough*).

So, we have now set invis when the guy picks the hero (if he is alive that is) and each second we set invis on him again if he still is alive etc.
What are we missing now?
Well, what happens when the guy spawns? Nothing, yet.
All we want to do is just setting invis on the guy when he spawns as this should be activate at all times when he is alive. This is just done by doing this:

PHP Code:
public sh_client_spawn(id)
{
    
activate_invis(id)

Youp, we are just running activate_invis as we have all checks we need there.

So now we are setting invis on him on all situations I can think of (if I missed one then tell me), now we just need to take it off if he dies, this we can do with sh_client_death as that runs when a user dies:

PHP Code:
public sh_client_death(victim)
{
    if ( 
gHasInvis[victim] )
    {
        
set_user_rendering(victim)
    }

We do not want to call the native if the guy dying does not have the hero, so first a check, then we reset the invisibility.

And that should be it. Here is the whole code:

PHP Code:
#include <superheromod>

new gHeroID
new gHasInvis[SH_MAXSLOTS+1]

new 
pcvarAlpha

public plugin_init()
{
    
register_plugin("SUPERHERO Invis""1.0""Jelle")
    
    new 
pcvarLevel register_cvar("invis_level""5")
    
pcvarAlpha register_cvar("invis_alpha""100")
    
    
gHeroID sh_create_hero("Invis"pcvarLevel)
    
sh_set_hero_info(gHeroID"Go Invis""Makes you invisible")
    
    
set_task(1.0"invis_loop"___"b")
}

public 
sh_hero_init(idheroIDmode)
{
    if ( 
gHeroID != heroID ) return
    
    switch(
mode)
    {
        case 
SH_HERO_ADD:
        {
            
gHasInvis[id] = true
            activate_invis
(id)
        }
        
        case 
SH_HERO_DROP:
        {
            
gHasInvis[id] = false
        
}
    }
}

activate_invis(id)
{
    if ( 
gHasInvis[id] && is_user_alive(id) && is_user_connected(id) )
    {
        
set_user_rendering(idkRenderFxGlowShell000kRenderTransAlphaget_pcvar_num(pcvarAlpha))
    }
}

public 
invis_loop()
{
    for ( new 
id 1id <= SH_MAXSLOTSid++ )
    {
        
activate_invis(id)
    }
}

public 
sh_client_spawn(id)
{
    
activate_invis(id)
}

public 
sh_client_death(victim)
{
    if ( 
gHasInvis[victim] )
    {
        
set_user_rendering(victim)
    }

And the efficient version I was talking about:

PHP Code:
#include <superheromod>

new gHeroID
new gHasInvis[SH_MAXSLOTS+1]

new 
pcvarAlpha

public plugin_init()
{
    
register_plugin("SUPERHERO Invis""1.0""Jelle")
    
    new 
pcvarLevel register_cvar("invis_level""5")
    
pcvarAlpha register_cvar("invis_alpha""100")
    
    
gHeroID sh_create_hero("Invis"pcvarLevel)
    
sh_set_hero_info(gHeroID"Go Invis""Makes you invisible")
    
    
set_task(1.0"invis_loop"___"b")
}

public 
sh_hero_init(idheroIDmode)
{
    if ( 
gHeroID != heroID ) return
    
    switch(
mode)
    {
        case 
SH_HERO_ADD:
        {
            
gHasInvis[id] = true
            set_user_rendering
(idkRenderFxGlowShell000kRenderTransAlphaget_pcvar_num(pcvarAlpha))
        }
        
        case 
SH_HERO_DROP:
        {
            
gHasInvis[id] = false
        
}
    }
}

public 
invis_loop()
{
    for ( new 
id 1id <= SH_MAXSLOTSid++ )
    {
        if ( 
gHasInvis[id] && is_user_alive(id) )
        {
            
set_user_rendering(idkRenderFxGlowShell000kRenderTransAlphaget_pcvar_num(pcvarAlpha))
        }
    }
}

public 
sh_client_spawn(id)
{
    
set_user_rendering(idkRenderFxGlowShell000kRenderTransAlphaget_pcvar_num(pcvarAlpha))
}

public 
sh_client_death(victim)
{
    if ( 
gHasInvis[victim] )
    {
        
set_user_rendering(victim)
    }

Here I have ditched the activate_invis forward. Then it does not need to go from one forward to another. But it doesn't really matter how you do it, since in this particular situation we are NOT going to post this, as it is basically just a rip off, and you WILL be flamed to death if you post it, and especially by me if you chance the author in register_plugin.

We can also choose to make this random, so you will be randomly invisible. I have one way in my head of doing that, and that would require a few more global variables, so that will be a bit bigger. But lets try:

First up, which hero do we know is based on some random stuff? Well, Captain America comes with sh 1.2, and is already written in the 1.2 way. Batman and JTP made it but I am pretty sure Vittu re-wrote it for the 1.2 way.
Lets take a quick look at that hero:

PHP Code:
// CAPTAIN AMERICA!

/* CVARS - copy and paste to shconfig.cfg

//Captain America
captaina_level 0
captaina_pctperlev 0.02        //Percentage that factors into godmode randomness (Default 0.02)
captaina_godsecs 1.0        //# of seconds of god mode

*/

#include <superheromod>

// GLOBAL VARIABLES
new gHeroID
new const gHeroName[] = "Captain America"
new bool:gHasCaptainAmerica[SH_MAXSLOTS+1]
new 
Float:gMaxLevelFactor
new gPcvarPctPerLevgPcvarGodSecs
//----------------------------------------------------------------------------------------------
public plugin_init()
{
    
// Plugin Info
    
register_plugin("SUPERHERO Captain America"SH_VERSION_STR"{HOJ} Batman/JTP10181")

    
// DO NOT EDIT THIS FILE TO CHANGE CVARS, USE THE SHCONFIG.CFG
    
new pcvarLevel register_cvar("captaina_level""0")
    
gPcvarPctPerLev register_cvar("captaina_pctperlev""0.02")
    
gPcvarGodSecs register_cvar("captaina_godsecs""1.0")

    
// FIRE THE EVENTS TO CREATE THIS SUPERHERO!
    
gHeroID sh_create_hero(gHeroNamepcvarLevel)
    
sh_set_hero_info(gHeroID"Super Shield""Random Invincibility, better chance the higher your level")

    
// OK Random Generator
    
set_task(1.0"captaina_loop"___"b")
}
//----------------------------------------------------------------------------------------------
public plugin_cfg()
{
    
// Check here so sh_get_num_lvls has time to set itself
    
gMaxLevelFactor = (10.0 sh_get_num_lvls()) * 100.0
}
//----------------------------------------------------------------------------------------------
public sh_hero_init(idheroIDmode)
{
    if ( 
gHeroID != heroID ) return

    
gHasCaptainAmerica[id] = mode true false

    sh_debug_message
(id1"%s %s"gHeroNamemode "ADDED" "DROPPED")
}
//----------------------------------------------------------------------------------------------
public captaina_loop()
{
    if ( !
sh_is_active() ) return

    static 
Float:pctperlev
    
static Float:godsecs
    pctperlev 
get_pcvar_float(gPcvarPctPerLev)
    
godsecs get_pcvar_float(gPcvarGodSecs)
    static 
heroLevel

    
static players[32], playerCountidi
    get_players
(playersplayerCount"ah")

    for ( 
0playerCounti++ ) {
        
id players[i]

        if ( 
gHasCaptainAmerica[id] && !get_user_godmode(id) ) {

            
heroLevel floatround(sh_get_user_lvl(id) * pctperlev gMaxLevelFactor)

            if ( 
heroLevel >= random_num(0100) ) {

                
sh_set_godmode(idgodsecs)

                
//Quick Blue Screen Flash Letting You know about god mode
                
sh_screen_fade(idgodsecsgodsecs/20025550SH_FFADE_MODULATE)
            }
        }
    }
}
//----------------------------------------------------------------------------------------------
public client_connect(id)
{
    
gHasCaptainAmerica[id] = false
}
//---------------------------------------------------------------------------------------------- 
By taking a quick look at it this seems fairly easy to do. We only have to edit very few details to make it invisibility instead of god mode.

So, as I have written a few times now, we look at plugin_init first. As we do not need to use all of the code we surely wont be needing all of the global variables. Now this is just my vision of it, you can do it however you like.

PHP Code:
public plugin_init()
{
    
// Plugin Info
    
register_plugin("SUPERHERO Captain America"SH_VERSION_STR"{HOJ} Batman/JTP10181")

    
// DO NOT EDIT THIS FILE TO CHANGE CVARS, USE THE SHCONFIG.CFG
    
new pcvarLevel register_cvar("captaina_level""0")
    
gPcvarPctPerLev register_cvar("captaina_pctperlev""0.02")
    
gPcvarGodSecs register_cvar("captaina_godsecs""1.0")

    
// FIRE THE EVENTS TO CREATE THIS SUPERHERO!
    
gHeroID sh_create_hero(gHeroNamepcvarLevel)
    
sh_set_hero_info(gHeroID"Super Shield""Random Invincibility, better chance the higher your level")

    
// OK Random Generator
    
set_task(1.0"captaina_loop"___"b")

Again, I assume Vittu has made this to 1.2 ways, and he is very good at adding comments for us, this makes it much easier for us. As I have said before, you should add comments too if you are going to post your hero, that is just good scripting habits.

All we see here is just a very simple hero. At first (again) we make a very simple hero which lets us just choose it:

PHP Code:
#include <superheromod>

new gHeroID
new gHasInvis[SH_MAXSLOTS+1]

public 
plugin_init()
{
    
register_plugin("SUPERHERO Invis""1.0""Jelle")
    
    new 
pcvarLevel register_cvar("invis_level""5")
    
    
gHeroID sh_create_hero("Invis"pcvarLevel)
    
sh_set_hero_info(gHeroID"Go Invis""Makes you invisible")
}

public 
sh_hero_init(idheroIDmode)
{
    if ( 
gHeroID != heroID ) return
    
    switch(
mode)
    {
        case 
SH_HERO_ADD:
        {
            
gHasInvis[id] = true
        
}
        
        case 
SH_HERO_DROP:
        {
            
gHasInvis[id] = false
        
}
    }

Now the question is, how do we want this to work? Do we want to just give 1 second of invis each random time, or do we want to rip Captain America completely? Well, just to make this a bit different from Captain America we just do 1 second of invisibility. This means we do not need the cvar captaina_godsecs, so we just delete that. Also to be a bit different, we do not want this to depend on the level the player is in, so we delete that cvar as well. Now for the code:

PHP Code:
public plugin_init()
{
    
register_plugin("SUPERHERO Invis""1.0""Jelle")
    
    new 
pcvarLevel register_cvar("invis_level""5")
    
    
gHeroID sh_create_hero("Invis"pcvarLevel)
    
sh_set_hero_info(gHeroID"Go Invis""Makes you invisible")
    
    
set_task(1.0"invis_loop"___"b")

Yes, we make a loop and we call it invis_loop since our hero is named invis.

Next part of the code:

PHP Code:
public plugin_cfg()
{
    
// Check here so sh_get_num_lvls has time to set itself
    
gMaxLevelFactor = (10.0 sh_get_num_lvls()) * 100.0

As we do not want this hero to be level dependent, we just skip this forward.

Next is the hero init. Here we see something a bit different:

PHP Code:
public sh_hero_init(idheroIDmode)
{
    if ( 
gHeroID != heroID ) return

    
gHasCaptainAmerica[id] = mode true false

    sh_debug_message
(id1"%s %s"gHeroNamemode "ADDED" "DROPPED")

We know what the check does. But the next thing seems a bit odd. That is actually a replacement of this:

PHP Code:
    switch(mode)
    {
        case 
SH_HERO_ADD:
        {
            
gHasInvis[id] = true
        
}
        
        case 
SH_HERO_DROP:
        {
            
gHasInvis[id] = false
        
}
    } 
As it doesn't use a switch it is more efficient. But it can only be done if there is no reason to run something when a player picks or drops the hero. We do it as it is done i Captain America as we do not need to do stuff when the hero is picked or dropped. The last thing is just a debug thing. As we are just so awesome, we delete that part, so the init becomes:

PHP Code:
public sh_hero_init(idheroIDmode)
{
    if ( 
gHeroID != heroID ) return
    
    
gHasInvis[id] = mode true false

Next up is the loop:

PHP Code:
public captaina_loop()
{
    if ( !
sh_is_active() ) return

    static 
Float:pctperlev
    
static Float:godsecs
    pctperlev 
get_pcvar_float(gPcvarPctPerLev)
    
godsecs get_pcvar_float(gPcvarGodSecs)
    static 
heroLevel

    
static players[32], playerCountidi
    get_players
(playersplayerCount"ah")

    for ( 
0playerCounti++ ) {
        
id players[i]

        if ( 
gHasCaptainAmerica[id] && !get_user_godmode(id) ) {

            
heroLevel floatround(sh_get_user_lvl(id) * pctperlev gMaxLevelFactor)

            if ( 
heroLevel >= random_num(0100) ) {

                
sh_set_godmode(idgodsecs)

                
//Quick Blue Screen Flash Letting You know about god mode
                
sh_screen_fade(idgodsecsgodsecs/20025550SH_FFADE_MODULATE)
            }
        }
    }

First thing we notice is a check to see if sh is running. We should add that as well. Next thing is something called static. What is that? Well, that is almost the same as "new". It is making a new variable, and keeps it. As this is running each second this is the most efficient as it does not have to create the variables all the time, but it just re-uses them. As we decided to not use the level dependent thing and the second thing there is really no need to use these variables.

Next we see another way of making a for loop. The first native we see is get_players(), lets look it up, here
Basically this gets all alive players (using the flag a which doesn't return dead players) and skips HLTV (if it is running that is). This prevents the for loop to run more time than the player slots actually occupied (and alive), so this is more efficiently than what we have done previously. That is why we are going to use this method this time. Next is some checks you should know what is. Then we see some level dependent stuff which we skipped. Then we see the random stuff. This is done using the level of the guy. We skipped that, so we need to come up with another system.

I am really not that good with this random thing and as it is very late the only thing I can think of is one way. I will be writing that in the code later on, and explain it.
We also see the god mode native. sh mod has its own native to do that. Lastly we see a screen fade. Maybe we should use this as well to let users know they have become invisible.

Now for the code we should be using:

PHP Code:
public invis_loop()
{
    new 
players[32], playerCountidi
    get_players
(playersplayerCount"ah")
    
    for ( 
0playerCounti++ )
    {
        
id players[i]
        
        if ( 
gHasInvis[id] )
        {
            if ( 
random_num(04) == )
            {
                
set_user_rendering(idkRenderFxGlowShell000kRenderTransAlphaget_pcvar_num(pcvarAlpha))
                
                
sh_screen_fade(id1.00.50025550SH_FFADE_MODULATE)
                
                
set_task(1.0"stop_invis"id)
            }
        }
    }

Okay, lets move right on to the random stuff. First a random number is generated from 0 to 4. If the number is 2, then set invisibility. Now, what are the chances of the number being 2? Right, it is 25%! So each second you get 25% chance of getting invisible for 1 second. Next is the screen fade. It has been made as long as god mode seconds on Captain America, here it is just 1 second, so we make it 1 second. I am not going in to how it works. If you want to know then go look it up in superheromod.inc.
Lastly I have made a task. This will run the forward stop_invis after 1 second, so if the guy get invisibility then it will be taken off after a second.

Now we need to make that forward:

PHP Code:
public stop_invis(id)
{
    
set_user_rendering(id)

As you have seen in the set_task native I have passed on the index, so an index can be used here too. Then simply take the invisibility off the guy.

Now we are just left with this:

PHP Code:
public client_connect(id)
{
    
gHasCaptainAmerica[id] = false

That is just emptying the variable if the player slot has the hero or not. This is if a new player connects and gets his player slot, then the new guy will actually have this hero (or the hero powers, it wont be seen in /myheroes). By doing this, we set it to false when he connects. Then we avoid this problem. So lets do that too:

PHP Code:
public client_connect(id)
{
    
gHasInvis[id] = false

Putting this together creates:

PHP Code:
#include <superheromod>

new gHeroID
new gHasInvis[SH_MAXSLOTS+1]

new 
pcvarAlpha

public plugin_init()
{
    
register_plugin("SUPERHERO Invis""1.0""Jelle")
    
    new 
pcvarLevel register_cvar("invis_level""5")
    
pcvarAlpha register_cvar("invis_alpha""100")
    
    
gHeroID sh_create_hero("Invis"pcvarLevel)
    
sh_set_hero_info(gHeroID"Go Invis""Makes you invisible")
    
    
set_task(1.0"invis_loop"___"b")
}

public 
sh_hero_init(idheroIDmode)
{
    if ( 
gHeroID != heroID ) return
    
    
gHasInvis[id] = mode true false
}

public 
invis_loop()
{
    new 
players[32], playerCountidi
    get_players
(playersplayerCount"ah")
    
    for ( 
0playerCounti++ )
    {
        
id players[i]
        
        if ( 
gHasInvis[id] )
        {
            if ( 
random_num(04) == )
            {
                
set_user_rendering(idkRenderFxGlowShell000kRenderTransAlphaget_pcvar_num(pcvarAlpha))
                
                
sh_screen_fade(id1.00.50025550SH_FFADE_MODULATE)
                
                
set_task(1.0"stop_invis"id)
            }
        }
    }
}

public 
stop_invis(id)
{
    
set_user_rendering(id)
}

public 
client_connect(id)
{
    
gHasInvis[id] = false

As you now have seen there is various of options to do things. But remember, making a minor chance to a hero (like making invisible woman to an automatic hero) is NOT enough to post it. Please keep it to yourself as it is very easy to do and no one needs it. I also think there already is a hero which does that actually.

Now we are done. Feel free to ask questions HERE. Not by PM's. I do not like to be bombed with those and you will get quicker (and maybe) better help than I can provide.

Also feel free to give me bacon for all my hard work. This has taken me many hours to do, and you can show your appreciation by donating bacon to me.
__________________
No idea what to write here...

Last edited by Jelle; 06-07-2011 at 19:24.
Jelle is offline
Send a message via MSN to Jelle
MuzzMikkel
Member
Join Date: Aug 2010
Location: Denmark
Old 05-27-2011 , 07:39   Re: [Tutorial] Reading/ripping hero codes
Reply With Quote #4

Nice work, very helpful
MuzzMikkel is offline
Send a message via MSN to MuzzMikkel
The Art of War
Veteran Member
Join Date: Dec 2009
Location: Sweden Rock Festival
Old 05-27-2011 , 07:57   Re: [Tutorial] Reading/ripping hero codes
Reply With Quote #5

Holy shit did this take like 4 days to write lol?

Too tired to look through it all but it looks good!
__________________
The Art of War is offline
Jelle
[b]MOAR CANDY[/b]
Join Date: Aug 2009
Location: Denmark
Old 05-27-2011 , 08:41   Re: [Tutorial] Reading/ripping hero codes
Reply With Quote #6

So far it has taken me 4 hours. But I want to cover everything. There is just too many already answered questions. I figured, if they all will be answered in here, then maybe we wont have so many question.
__________________
No idea what to write here...
Jelle is offline
Send a message via MSN to Jelle
RollerBlades
Senior Member
Join Date: Feb 2011
Location: Sweden
Old 05-28-2011 , 04:49   Re: [Tutorial] Reading/ripping hero codes
Reply With Quote #7

Nice tut Jelle! and nice hero Glooba! i love it!
RollerBlades is offline
Jelle
[b]MOAR CANDY[/b]
Join Date: Aug 2009
Location: Denmark
Old 06-04-2011 , 18:07   Re: [Tutorial] Reading/ripping hero codes
Reply With Quote #8

Updated the tutorial. Check post #2 as I have continued in that post. Now the plugin is done.

Next up:
How to use this is different ways, like in a hero which doesn't use keydown. By now invisible woman has just been recreated using the new ways and a new name.
__________________
No idea what to write here...
Jelle is offline
Send a message via MSN to Jelle
Jelle
[b]MOAR CANDY[/b]
Join Date: Aug 2009
Location: Denmark
Old 06-07-2011 , 19:25   Re: [Tutorial] Reading/ripping hero codes
Reply With Quote #9

All done. If anyone finds any faults or errors please do tell me so I can change it.
__________________
No idea what to write here...
Jelle is offline
Send a message via MSN to Jelle
akdteam
Member
Join Date: Jan 2009
Old 06-08-2011 , 20:36   Re: [Tutorial] Reading/ripping hero codes
Reply With Quote #10

Excelent jelle, can you add a TE_ use?

Thanks for your time..
akdteam is offline
Reply



Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump


All times are GMT -4. The time now is 11:03.


Powered by vBulletin®
Copyright ©2000 - 2024, vBulletin Solutions, Inc.
Theme made by Freecode