Dynamic Weapon Spawns: Difference between revisions
m (adding to programming category) |
(Typo) |
||
Line 1: | Line 1: | ||
== Introduction == | == Introduction == | ||
A feature that has been in many console FPS games for years is dynamic weapon spawns. The best example was Perfect Dark. You could choose 6 different weapons at the begining of the round, and then the game would place those weapons at whatever point the weapon was assigned to. Pistols might go in all slot 1 spawns, cloak generators at another. | |||
This sort of thing can add longevity to some maps, as each game you could use a different set of weapons. So, how would one go about adding this to a PC game such as Half-Life 2? | This sort of thing can add longevity to some maps, as each game you could use a different set of weapons. So, how would one go about adding this to a PC game such as Half-Life 2? |
Revision as of 23:59, 9 October 2005
Introduction
A feature that has been in many console FPS games for years is dynamic weapon spawns. The best example was Perfect Dark. You could choose 6 different weapons at the begining of the round, and then the game would place those weapons at whatever point the weapon was assigned to. Pistols might go in all slot 1 spawns, cloak generators at another.
This sort of thing can add longevity to some maps, as each game you could use a different set of weapons. So, how would one go about adding this to a PC game such as Half-Life 2?
Setting it up
To do this I used a model entity, CWeaponSpawn. Create a new cpp file, call it weaponspawns.cpp or something and place it in the game_shared folder, this goes on both the client and server. Add the file to both projects. Let's make the entity, here's an empty shell of an model ent...
#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 } 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);
When it comes to letting server admins set an option, nothing beats a CVAR(or ConVar if you prefer). We will use 6 different weapon slots in our set. Let's declare them, these go at the top 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 we can let the server admin set an integer value to those CVARs to set weapons. Another way to do it is to set them to strings, like
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.
Something that annoyed me when I did this for HL1 was how I checked what weapon to spawn, I would check constants, this would mean if I had to remove or add an weapon in the list I had to change most of the values. So we will 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 that we have everything set up we can get this to work. The magic happens in our entities Think Function. We need to check what slot in the set this ent caters for, and what weapon is assigned to that slot. To do that we have this.
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; }
We now know what we are supposed to create. To create an entity we call this.
CBaseEntity::Create( "weapon_falcon2", GetLocalOrigin(), GetLocalAngles() );
So we check BoundWeapon and spawn 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 like I am, you will notice that weapon's dont respawn if 'dropped' this seems to include createing an entity like this, if so call this afterwards.
pEntity->RemoveSpawnFlags( SF_NORESPAWN );
Getting it in-game
Ok, so we now have our shiny new entities, how do we get them to work?
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 our 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)" ]
(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
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.scr file in a text editor(it's not a windows screensaver) and add 6 of these to it.
"mp_pdweapon1" { "Weapon 1" { LIST "Disable Spawner" "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 if they don't read the manual you are going to write or I'll kill you ;)
//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
Well, copy-pasting my ent might leave you with a bit of a tangle, heres my complete file
If you have any problems you can PM me here User_talk:Draco Or you can contact me at #ausbg on GameSurge IRC.