Dynamic Weapon Spawns: Difference between revisions
(Typo) |
No edit summary |
||
(26 intermediate revisions by 8 users not shown) | |||
Line 1: | Line 1: | ||
{{Abstract Coding}} | |||
This | For years, many console FPS games have been using a great feature called dynamic weapon spawn. The best example to illustrate that feature is the Perfect Dark game. Indeed, you can choose up to six different weapons at the beginning of the game, then the game will put those weapons at whatever point the weapon was assigned to. Pistols should go in all slot 1 spawns, cloak generators at another, and so on. | ||
This kind of feature might add some longevity to your map because each game would let you select different sets of weapons. This article describes how one would go about adding this to a PC game such as [[Half-Life 2]]. | |||
== Setting it up == | == Setting it up == | ||
Creating a model entity called CWeaponSpawn seems to work. | |||
Thus, create a new file called '''weaponspawns.cpp''' or something and place it in the '''\game_shared''' folder so the file will be shared by both the client and the server dlls. Then, add the file to both projects in the Visual C++ editor. | |||
OK, now let's create the entity in the code, here's an empty shell of a model entity: | |||
#include "cbase.h" | #include "cbase.h" | ||
Line 36: | Line 41: | ||
void Precache( void ) | void Precache( void ) | ||
{ | { | ||
PrecacheModel ("models/w_rcp120.mdl"); / set a different model, something you have | PrecacheModel ("models/w_rcp120.mdl"); // set a different model, something you have | ||
//Precache all entities spawned at these, to prevent late caching(ingame stutters suck) | |||
UTIL_PrecacheOther("weapon_falcon2"); | |||
UTIL_PrecacheOther("weapon_magsec4"); | |||
UTIL_PrecacheOther("weapon_dy357"); | |||
UTIL_PrecacheOther("weapon_dy357lx"); | |||
UTIL_PrecacheOther("weapon_cmp"); | |||
UTIL_PrecacheOther("weapon_cyclone"); | |||
UTIL_PrecacheOther("weapon_laptopgun"); | |||
UTIL_PrecacheOther("weapon_rcp120"); | |||
UTIL_PrecacheOther("weapon_proximitymine"); | |||
UTIL_PrecacheOther("weapon_remotemine"); | |||
UTIL_PrecacheOther("weapon_timedmine"); | |||
} | |||
void Think( void ) | void Think( void ) | ||
Line 58: | Line 75: | ||
PRECACHE_REGISTER(pd_weaponspawner); | PRECACHE_REGISTER(pd_weaponspawner); | ||
Whenever a server host / adminstrator has to set up options for their server, the best idea is to use Console Variables ( CVARs ). For that tutorial, we will use six different CVARs to implement our dynamic weapons system. | |||
To make it tight, copy that piece of code at the very bottom of the file. | |||
ConVar mp_pdweapon1( "mp_pdweapon1", "1", FCVAR_NOTIFY|FCVAR_REPLICATED, "Weapon to create at weapon 1 areas" ); | ConVar mp_pdweapon1( "mp_pdweapon1", "1", FCVAR_NOTIFY|FCVAR_REPLICATED, "Weapon to create at weapon 1 areas" ); | ||
Line 67: | Line 85: | ||
ConVar mp_pdweapon6( "mp_pdweapon6", "1", FCVAR_NOTIFY|FCVAR_REPLICATED, "Weapon to create at weapon 6 areas" ); | ConVar mp_pdweapon6( "mp_pdweapon6", "1", FCVAR_NOTIFY|FCVAR_REPLICATED, "Weapon to create at weapon 6 areas" ); | ||
Now | Now this is possible to let the server host set an integer value to those CVARs to set weapons. Another way to do it is to set them to strings. Thus the CVar would look like this: | ||
ConVar mp_pdweapon1( "mp_pdweapon1", "magsec4", FCVAR_NOTIFY|FCVAR_REPLICATED, "Weapon to create at weapon 1 areas" ); | ConVar mp_pdweapon1( "mp_pdweapon1", "magsec4", FCVAR_NOTIFY|FCVAR_REPLICATED, "Weapon to create at weapon 1 areas" ); | ||
Line 73: | Line 91: | ||
Using that you could check for what weapon goes with magsec4 and spawn it. | Using that you could check for what weapon goes with magsec4 and spawn it. | ||
This seemed to be an annoyance when it was done for HL1, and how to check what weapon to spawn, a way to do this would check constants, though this would mean if you had to remove or add an weapon in the list you would have to change most of the values. So it's best to avoid this with an enum. | |||
typedef enum | typedef enum | ||
Line 89: | Line 107: | ||
== Getting it to work == | == Getting it to work == | ||
Now | Now everything is set up, it is possible to get it to work. The key resides in the entity Think() function. It's necessary to check what slot in the set this ent caters for, and what weapon is assigned to that slot. To do that this can be done. | ||
int m_iWeaponSlot; | int m_iWeaponSlot; | ||
Line 122: | Line 140: | ||
} | } | ||
Now it comes clear what is supposed to be created. To create an entity this is called. | |||
CBaseEntity::Create( "weapon_falcon2", GetLocalOrigin(), GetLocalAngles() ); | CBaseEntity::Create( "weapon_falcon2", GetLocalOrigin(), GetLocalAngles() ); | ||
So | So BoundWeapon is checked and spawns the appropriate item. | ||
CBaseEntity * pEntity = NULL; | CBaseEntity * pEntity = NULL; | ||
Line 151: | Line 169: | ||
} | } | ||
Also, if you are using the blank MP | Also, if you are using the blank MP SDK, you will notice that weapons don't respawn if 'dropped' this seems to include creating an entity like this, if so call this afterwards. | ||
pEntity->RemoveSpawnFlags( SF_NORESPAWN ); | pEntity->RemoveSpawnFlags( SF_NORESPAWN ); | ||
Line 157: | Line 175: | ||
== Getting it in-game == | == Getting it in-game == | ||
Ok, so | Ok, so this shiney new entity has been created, how is it going to work in game? | ||
If you don't have your own mod FGD yet it might be time to make one. Create an ordinary text file with the .fgd extension and add this line to it. | If you don't have your own mod FGD yet it might be time to make one. Create an ordinary text file with the .fgd extension and add this line to it. | ||
Line 163: | Line 181: | ||
@include "hl2mp.fgd" | @include "hl2mp.fgd" | ||
If you don't use the hl2mp FGD, replace that with whatever fgd you use in your mod. Time to declare the new model ent. | |||
@PointClass base(Angles) studio("models/w_rcp120.mdl") = pd_weaponspawner : "An Perfect Dark weapon spawn point" | @PointClass base(Angles) studio("models/w_rcp120.mdl") = pd_weaponspawner : "An Perfect Dark weapon spawn point" | ||
Line 170: | Line 188: | ||
] | ] | ||
{{note|Set a different model or icon, something you have}} | |||
Now you can place one in hammer. Set the forweapon value to something between 1 and 6 and compile the map. Place one for each slot so you can see it all working. | |||
== Further == | == Further == | ||
This is all well and good, but what if your admin doesn't know about this? What if he or she is a bumbling fool? You should keep in mind the old 1:10 ratio, assume anyone who uses or edits your program is 10x more stupid than you are. To help listen server users work this out you can add it to the server options menu when you create game. Open the | This is all well and good, but what if your admin doesn't know about this? What if he or she is a bumbling fool? You should keep in mind the old 1:10 ratio, assume anyone who uses or edits your program is 10x more stupid than you are. To help listen server users work this out you can add it to the server options menu when you create game. Open the settings_default.scr file in a text editor (it's not a windows screensaver) and add the following. | ||
"mp_pdweapon1" | "mp_pdweapon1" | ||
Line 181: | Line 201: | ||
{ | { | ||
LIST | LIST | ||
" | "Disabled" "0" | ||
"Falcon 2" "1" | "Falcon 2" "1" | ||
"DY357" "2" | "DY357" "2" | ||
"Shotgun" "3" | "Shotgun" "3" | ||
"AR34" "4" | "AR34" "4" | ||
"Callisto NTG" "5" | "Callisto NTG" "5" | ||
"RCP-120" "6" | "RCP-120" "6" | ||
} | } | ||
{ "6" } | { "6" } | ||
} | } | ||
Then you should be a sport and add them to the server.cfg file when you distribute the mod, so any admin who goes to edit them might guess what they mean | Then you should be a sport and add them to the server.cfg file when you distribute the mod, so any admin who goes to edit them might guess what they mean. | ||
//Weapon Spawn settings: | //Weapon Spawn settings: | ||
Line 204: | Line 224: | ||
== Reference == | == Reference == | ||
Since copy-pasting this whole entity might leave you with a bit of a tangle, [http://draco.dajoob.com/files/pdspawners.cpp here is the whole file]. | |||
If you have any problems you can | If you have any problems you can leave a message in the [[User:Draco|original author's talk page]] or you can attempt to contact him on IRC at <code>#ausbg</code> on GameSurge. | ||
== See also == | |||
*[[Dynamic Weapon Spawns (Advanced)]] | |||
[[Category:Tutorials]] [[Category:Programming]] | [[Category:Tutorials]] [[Category:Programming]] |
Latest revision as of 03:09, 2 August 2013
Abstract Coding series Discuss your thoughts - Help us develop the articles or ideas you want |
---|
Levels & XP | Optimization | Procedural Textures | Sights & Sniperrifles | Special effects | Vehicles | Threads | Save Game Files | Night Vision | Non-offensive Weapons | Dynamic Weapon Spawns | Dynamic Weapon Spawns (Advanced) |
For years, many console FPS games have been using a great feature called dynamic weapon spawn. The best example to illustrate that feature is the Perfect Dark game. Indeed, you can choose up to six different weapons at the beginning of the game, then the game will put those weapons at whatever point the weapon was assigned to. Pistols should go in all slot 1 spawns, cloak generators at another, and so on.
This kind of feature might add some longevity to your map because each game would let you select different sets of weapons. This article describes how one would go about adding this to a PC game such as Half-Life 2.
Setting it up
Creating a model entity called CWeaponSpawn seems to work.
Thus, create a new file called weaponspawns.cpp or something and place it in the \game_shared folder so the file will be shared by both the client and the server dlls. Then, add the file to both projects in the Visual C++ editor.
OK, now let's create the entity in the code, here's an empty shell of a model entity:
#include "cbase.h" #ifdef CLIENT_DLL #define CWeaponSpawner C_WeaponSpawner #endif class CWeaponSpawner : public CBaseAnimating { DECLARE_CLASS( CWeaponSpawner, CBaseAnimating ); DECLARE_NETWORKCLASS(); DECLARE_PREDICTABLE(); DECLARE_DATADESC(); int m_iWeaponSlot; public: void Spawn( void ) { Precache( ); BaseClass::Spawn( ); AddEffects( EF_NODRAW ); SetMoveType( MOVETYPE_NONE ); SetSolid( SOLID_NONE ); SetThink( &CWeaponSpawner::Think ); SetNextThink( gpGlobals->curtime + 3 ); } void Precache( void ) { PrecacheModel ("models/w_rcp120.mdl"); // set a different model, something you have //Precache all entities spawned at these, to prevent late caching(ingame stutters suck) UTIL_PrecacheOther("weapon_falcon2"); UTIL_PrecacheOther("weapon_magsec4"); UTIL_PrecacheOther("weapon_dy357"); UTIL_PrecacheOther("weapon_dy357lx"); UTIL_PrecacheOther("weapon_cmp"); UTIL_PrecacheOther("weapon_cyclone"); UTIL_PrecacheOther("weapon_laptopgun"); UTIL_PrecacheOther("weapon_rcp120"); UTIL_PrecacheOther("weapon_proximitymine"); UTIL_PrecacheOther("weapon_remotemine"); UTIL_PrecacheOther("weapon_timedmine"); } void Think( void ) { } }; IMPLEMENT_NETWORKCLASS_ALIASED( WeaponSpawner, DT_WeaponSpawner ) BEGIN_NETWORK_TABLE( CWeaponSpawner, DT_WeaponSpawner ) END_NETWORK_TABLE() BEGIN_PREDICTION_DATA( CWeaponSpawner ) END_PREDICTION_DATA() BEGIN_DATADESC( CWeaponSpawner ) DEFINE_KEYFIELD( m_iWeaponSlot, FIELD_INTEGER, "ForWeapon" ), #ifndef CLIENT_DLL DEFINE_THINKFUNC( Think ), #endif END_DATADESC() LINK_ENTITY_TO_CLASS(pd_weaponspawner, CWeaponSpawner); PRECACHE_REGISTER(pd_weaponspawner);
Whenever a server host / adminstrator has to set up options for their server, the best idea is to use Console Variables ( CVARs ). For that tutorial, we will use six different CVARs to implement our dynamic weapons system. To make it tight, copy that piece of code at the very bottom of the file.
ConVar mp_pdweapon1( "mp_pdweapon1", "1", FCVAR_NOTIFY|FCVAR_REPLICATED, "Weapon to create at weapon 1 areas" ); ConVar mp_pdweapon2( "mp_pdweapon2", "1", FCVAR_NOTIFY|FCVAR_REPLICATED, "Weapon to create at weapon 2 areas" ); ConVar mp_pdweapon3( "mp_pdweapon3", "1", FCVAR_NOTIFY|FCVAR_REPLICATED, "Weapon to create at weapon 3 areas" ); ConVar mp_pdweapon4( "mp_pdweapon4", "1", FCVAR_NOTIFY|FCVAR_REPLICATED, "Weapon to create at weapon 4 areas" ); ConVar mp_pdweapon5( "mp_pdweapon5", "1", FCVAR_NOTIFY|FCVAR_REPLICATED, "Weapon to create at weapon 5 areas" ); ConVar mp_pdweapon6( "mp_pdweapon6", "1", FCVAR_NOTIFY|FCVAR_REPLICATED, "Weapon to create at weapon 6 areas" );
Now this is possible to let the server host set an integer value to those CVARs to set weapons. Another way to do it is to set them to strings. Thus the CVar would look like this:
ConVar mp_pdweapon1( "mp_pdweapon1", "magsec4", FCVAR_NOTIFY|FCVAR_REPLICATED, "Weapon to create at weapon 1 areas" );
Using that you could check for what weapon goes with magsec4 and spawn it.
This seemed to be an annoyance when it was done for HL1, and how to check what weapon to spawn, a way to do this would check constants, though this would mean if you had to remove or add an weapon in the list you would have to change most of the values. So it's best to avoid this with an enum.
typedef enum { SPAWN_OFF = 0, SPAWN_FALCON2, SPAWN_DY357, SPAWN_SHOTGUN, SPAWN_AR34, SPAWN_CALLISTO, SPAWN_RCP120, } WeaponsToSpawn;
Getting it to work
Now everything is set up, it is possible to get it to work. The key resides in the entity Think() function. It's necessary to check what slot in the set this ent caters for, and what weapon is assigned to that slot. To do that this can be done.
int m_iWeaponSlot;
and
DEFINE_KEYFIELD( m_iWeaponSlot, FIELD_INTEGER, "ForWeapon" ),
It is an key value for a level designer to set, more on that later. We can now check for the weapon like so.
int BoundWeapon = 0; switch (m_iWeaponSlot) { case 1: BoundWeapon = mp_pdweapon1.GetInt(); break; case 2: BoundWeapon = mp_pdweapon2.GetInt(); break; case 3: BoundWeapon = mp_pdweapon3.GetInt(); break; case 4: BoundWeapon = mp_pdweapon4.GetInt(); break; case 5: BoundWeapon = mp_pdweapon5.GetInt(); break; case 6: BoundWeapon = mp_pdweapon6.GetInt(); break; }
Now it comes clear what is supposed to be created. To create an entity this is called.
CBaseEntity::Create( "weapon_falcon2", GetLocalOrigin(), GetLocalAngles() );
So BoundWeapon is checked and spawns the appropriate item.
CBaseEntity * pEntity = NULL; switch (BoundWeapon) { case SPAWN_FALCON2: pEntity = CBaseEntity::Create( "weapon_falcon2", GetLocalOrigin(), GetLocalAngles() ); break; case SPAWN_DY357: pEntity = CBaseEntity::Create( "weapon_dy357", GetLocalOrigin(), GetLocalAngles() ); break; case SPAWN_SHOTGUN: pEntity = CBaseEntity::Create( "weapon_shotgun", GetLocalOrigin(), GetLocalAngles() ); break; case SPAWN_AR34: pEntity = CBaseEntity::Create( "weapon_ar34", GetLocalOrigin(), GetLocalAngles() ); break; case SPAWN_CALLISTO: pEntity = CBaseEntity::Create( "weapon_callisto", GetLocalOrigin(), GetLocalAngles() ); break; case SPAWN_RCP120: pEntity = CBaseEntity::Create( "weapon_rcp120", GetLocalOrigin(), GetLocalAngles() ); break; }
Also, if you are using the blank MP SDK, you will notice that weapons don't respawn if 'dropped' this seems to include creating an entity like this, if so call this afterwards.
pEntity->RemoveSpawnFlags( SF_NORESPAWN );
Getting it in-game
Ok, so this shiney new entity has been created, how is it going to work in game?
If you don't have your own mod FGD yet it might be time to make one. Create an ordinary text file with the .fgd extension and add this line to it.
@include "hl2mp.fgd"
If you don't use the hl2mp FGD, replace that with whatever fgd you use in your mod. Time to declare the new model ent.
@PointClass base(Angles) studio("models/w_rcp120.mdl") = pd_weaponspawner : "An Perfect Dark weapon spawn point" [ ForWeapon(integer) : "For what weapon slot?" : 1 : "What weapon slot can use this point?(1-6)" ]

Now you can place one in hammer. Set the forweapon value to something between 1 and 6 and compile the map. Place one for each slot so you can see it all working.
Further
This is all well and good, but what if your admin doesn't know about this? What if he or she is a bumbling fool? You should keep in mind the old 1:10 ratio, assume anyone who uses or edits your program is 10x more stupid than you are. To help listen server users work this out you can add it to the server options menu when you create game. Open the settings_default.scr file in a text editor (it's not a windows screensaver) and add the following.
"mp_pdweapon1" { "Weapon 1" { LIST "Disabled" "0" "Falcon 2" "1" "DY357" "2" "Shotgun" "3" "AR34" "4" "Callisto NTG" "5" "RCP-120" "6" } { "6" } }
Then you should be a sport and add them to the server.cfg file when you distribute the mod, so any admin who goes to edit them might guess what they mean.
//Weapon Spawn settings: mp_pdweapon1 1 //falcon 2 mp_pdweapon2 2 //magnum mp_pdweapon3 3 //shotteh mp_pdweapon4 4 //assault rifle mp_pdweapon5 5 //alien wafflebat gun mp_pdweapon6 0 //disabled
Reference
Since copy-pasting this whole entity might leave you with a bit of a tangle, here is the whole file.
If you have any problems you can leave a message in the original author's talk page or you can attempt to contact him on IRC at #ausbg
on GameSurge.