NS Metamod Coding FAQ

  1. How do I get/set a player's resources?
  2. How can I find out a player's class?
  3. How can I give a marine an order/waypoint?
  4. How can I find out if the server is running an ns_ or co_ map?
  5. How can I get a list of area location names?
  6. Where are the particle effects defined?
  7. How can I play a HUD sound?
  8. How can I display a build notification?
  9. How can I detect map load/round reset?
  10. How can I find out how long the round has been playing for?
  11. What's the deal with those scripting entities?
  12. What do the iuser3 values mean?
  13. What do the iuser4 values mean?
  14. How can I find out where the commander is pointing/clicking?
  15. What are the available impulses, and what do they mean?
  16. How can I find out if a building is fully built?
  17. How can I get/set an alien player's energy?
  18. What are the available events, and what do they do?
  19. How can I change a marine's reserve ammo?
  20. How can I get/set a player's jetpack fuel?
  21. Where can I get a list of all the NS messages and their formats?
  22. How do I get/set a player's experience (combat)?
  23. How do I get/set a player's levels (combat)?

1. How do I get/set a player's resources?

This code:
float UTIL_GetPlayerResources( edict_t *player )
{
    return player->v.vuser4.z;
}

will return a player's resources for an alien player and the team's resources for a marine player.  This value is reset every frame by the NS DLL.  To alter a player's resources, this code (thanks to mahnsawce for the updated offset):
#define RESOURCE_OFFSET 398
void UTIL_SetPlayerResources( edict_t *player, float resources )
{
    (float*)((char*)(player->pvPrivateData) + 398) = resources;
}

Note that this will only work for alien players; the marine resources are stored elsewhere.  Also, the offset value is only valid for NS2.01 final.  It will likely change in future versions of NS.  For Linux plugins, add five to the offset value.
01/02/2004: Voogru has found the resource offset for NS3.0 (public beta 2) - 400.  Linux offset currently unknown, but believed to be similar.

2. How can I find out a player's class?

This is different depending on the version of NS.  Fo version 2.01 and lower, there are two methods: either check the value in the player's iuser3 variable, or use this code to get the player's model:
edict_t *player;   // Assumes this is set to the player's edict.
char *infobuffer;
char model[32];
infobuffer = (*g_engfuncs.pfnGetInfoKeyBuffer)(player);
strcpy(model, (g_engfuncs.pfnInfoKeyValue(infobuffer, "model")));

The value in model with be one of: "soldier", "heavy", "commander", "alien1", "alien2", "alien3", "alien4", "alien5", "gestate".  To find out if a marine has a jetpack, check if their model is "soldier" and their pev->body is equal to one.

For version 3.0 (public beta 1) and above, there are two methods: either check the value in the player's iuser3 variable, or use this code to get the player's model:
edict_t *player;   // Assumes this is set to the player's edict.
const char *model;
model = STRING(player->v.model);

The value in model with be of the form "models/player/x/x.mdl" where 'x' is one of: "soldier", "heavy", "commander", "alien1", "alien2", "alien3", "alien4", "alien5", "gestate".  To find out if a marine has a jetpack, check if their model is "models/players/soldier/soldier.mdl" and their pev->body is equal to one.  Thanks to mahnsawce for pointing out the new model settings.

3. How can I give a marine an order/waypoint?

Send that player a SetOrder message.

4. How can I find out if the server is running an ns_ or co_ map?

There should be several ways: offical ns_maps have exactly three team_hive entities, while co_maps should only have one.  You could also hook the SetupMap message which sends the map name during map load.

5. How can I get a list of area location names?

The x/y bounds of the info_location entities are sent in the SetupMap message, along with the text they should display.  Note that the text value may be of the form "#name" in which case it must be looked up in titles.txt.

6. Where are the particle effects defined?

The properties for the various particle systems are sent during the first thirty seconds of each round in a series of Particles messages.  There is one message for each type of particle system (e.g. lerk spores, phase effect, etc.) followed by one for each env_custom_particles entity in the map.

7. How can I play a HUD sound?

8. How can I display a build notification?

These are both handled by the PlayHUDNot message.

9. How can I detect map load/round reset?

10. How can I find out how long the round has been playing for?

Hook the GameStatus message and look for the round reset/round end/map load/timer messages.

11. What's the deal with those scripting entities?

The trigger_script entity appears to be used for triggering server-side scripts.  The only info I could find on map-related scripting in NS is from this article (from before NS was released):
GH: What significant changes or events have happened since the last build of natural Selection? How many more do you think will occur before natural Selection is ready?

Flayra: Let’s see...the biggest change there is our new scripting system.  We haven’t announced this yet, but here is as good a place as any.  As we are “shipping” more and more often (every Friday for playtesters), I was spending more and more time testing, and the penalty for bugs gets larger.  I needed a way to automate testing.  I’ve struggled with this problem for a long time, because the tests are complex.  It’s not a simple thing to test if welding is working, for example.  You need to automatically point the welder in the right direction, hold down the button, then watch the screen to make sure the progress is going at the right rate, and finally that the weld finishes.  The system I’ve finally settled on is a scripting solution with LUA.  The nice thing about this, is that I can now write a quick script that performs these actions, then checks the world state and compares it with a saved good state, and tells me if the states are the same.  If so, the test passes and next test runs, if not, the test fails and the tests stop.

The great thing about this scripting system is that I can open it up to mappers for their own custom special behavior and effects.  We’ll be announcing more details about this soon.

12. What do the iuser3 values mean?

The iuser3 value is used to tell the client the type of the entity.  Each entity should have one value from the list placed in it's iuser3 variable.

13. What do the iuser4 values mean?

The iuser 4 variable is a bitmask, so each value corresponds to one bit.  The meanings of most of the values should be obvious from the names and comments in the NS SDK. A few notes on some, though:

14. How can I find out where the commander is pointing/clicking?

All the selecting of buildings/players is handled client-side, so the only way to find out what is selected is when an impulse is fired (e.g. the recycle impulse).  Impulse 82 is sent every tenth of a second and contains the current mouse position.  Info from Flayra:
the position of the "ghost" building should be contained in upmove, sidemove and forwardmove.
The problem is those coordinates are normalized in screen space, so that might not be that helpful. Upmove is the normalized screen x * 1000, sidemove is the normalized screen y * 1000, and forwardmove is z. I'm not sure how much that helps, but that's all the info I can easily give you.

15. What are the available impulses, and what do they mean?

The list of available impulses is in AvHMessage.h in the NS SDK.  The comments should describe them fairly well.

16. How can I find out if a building is fully built?

Fully built buildings will have the MASK_BUILDABLE flag in iuser4 unset.  Hives are the lone exception to this rule: they are fully built if their fuser1 variable is at least 1000.  The following code taken from Voogru's plugins checks these:
bool UTIL_IsBuilt(edict_t *pent)
{
    if( ! (pent->v.iuser4 & (1<<2)) )
    {
        return true;
    }
    else if(FStrEq(STRING(pent->v.classname),"team_hive") && pent->v.fuser1 >= 1000)//Hives are just wierd.
    {
        pent->v.iuser4 &= ~(1<<2);
        return true;
    }
    return false;
}

17. How can I get/set a player's energy?

Thanks to mahnsawce for finding this out.  To get the player's energy, simply use this code:
float UTIL_GetPlayerEnergy( edict_t *player )
{
    return player->v.fuser1 / 10.0;   // This returns the percentage (0%-100%)
}

This value is reset by the NS DLL every frame.  Currently, the offset to set the player's energy is unknown.

18. What are the available events, and what do they do?

Events should be played using PLAYBACK_EVENT_FULL.  Some events may require the v/f/iuser parameters to be set.  Events only produce visual/audio effects; they do not do damage.
Event ID
Effect
1
Weapon Animation
2
Knife swipe
3
LMG round with brass
4
Pistol round with brass
5
Shotgun round with shell
6
HMG round with shell
7
GL round
8
Gorge spit projectile
9
Onos gore
10
Fade swipe?
11
Spore projectile.  No spore cloud.
12
Lerk spike.  Impact only.
13
Skulk bite
14
Health spray
15
Gorge web projectile
16
Primal scream
17
Parasite
18
Metabolise
19
Umbra projectile.  No cloud.
20
Blink success
21
Xenocide effect
22
Bilebomb projectile and splash
23
Acid rocket projectile and splash
24
Stomp shockwave
25
Devour
26
Leap
27
Charge
28
OC spike
29
Welder
30
WelderConst
31
WelderStart
32
WelderEnd
33
Jetpack effect
34
Regeneration noise
35
Start cloak
36
End cloak
37
Spore cloud
38
Umbra cloud
39
StopScream???
40
IP spawn effect
41
Commander item drop effect
42
Siege impact
43
SiegeViewHit???
44
CommandPoints??? Don't know.  Appears to be a green light ???
45
Alien flashlight on noise
46
Alien flashlight off noise
47
Marine empty-ammo noise
48
NumericalInfo - those lines of text that say "x resources recieved" or "ammo recieved".
origin - the origin of the text
fparam1 - for "resources" event, the number of resources recieved
iparam1 - the type of the event (0=resources, 1=health, 2=resources donated, 3=ammo)
iparam2 - for "resources" event, the team that gets the resources (1=marines, 2=aliens)
49
InvalidAction
50
Particle
51
Distress beacon light/siren
52
MetabolizeSuccess

19. How can I change a marine's reserve ammo?

Thanks to mahnsawce, the offsets for the marine's reserve ammo have been found.  Note that these have only been tested on NS2.01 final.  Given a pointer to an edict_t called "player", we can use this expression to return a pointer to the player's reserve ammo:
(int*)((char*)(player)+OFFSET)
The value of OFFSET depends on the type of reserve ammo you want.  Known values are: LMG = 0xE6, Pistol = 0xE7, Shotgun = 0xE8, HMG = 0xE9, GL = 0xEA.  Under Linux, the offsets should be increased by 5.

20. How can I get/set a player's jetpack fuel?

The player's jetpack fuel is stored in pev->fuser3.  The following code can be used to get/set it.  Thanks to mahnsawce for figuring this out.
float UTIL_GetJetpackFuel( edict_t *player )
{
    return (player->v.fuser3 / 10.0);   // Returns JP fuels as a percentage (0-100)
}

// newFuel should be a percentage (0-100)
void UTIL_SetJetpackFuel( edict_t *player, float newFuel )
{
    player->v.fuser3 = newFuel / 10.0
}

21. Where can I get a list of all the NS messages and their formats?

Right here.

22. How can I get/set a player's experience (combat)?

This code:
float UTIL_GetPlayerExperience( edict_t *player )
{
    return player->v.vuser4.z;
}

will return a player's experience (assuming this is a combat map).  This value is reset every frame by the NS DLL.  Thanks to clamatius for this info.
01/02/2004: Voogru has found the offsets for player experience (NS3.0 public beta 2).  It is stored as a float; the offsets are: win32 - 1579; linux - 1554.

23. How can I get/set a player's levels (combat)?

Voogru has found the offsets for player levels for win32 servers:
#define PLAYER_POINTS_OFFSET 1581
(int*)((char*)(player)+PLAYER_POINTS_OFFSET)
Voogru's notes: "numbers are 0-9, these are points SPENT not points available, so if I have a total of 9 points and 5 points left, this number would be 4."


Home