|
|
|
Editor: RED is new, YELLOW is old. This is part 2 of capture the object. In this tutorial I will show you how to make the capture point, set up the fgd, and show the player when they have the flag. The code for the capture point is real basic, and you could definatly improve it. Open up the object.h file we made in part 1 and at the bottom of the file put the following code: class CObjectCapture : public CObject { public: void Spawn( void ); void Precache( void ); void Touch( CBaseEntity *pOther ); void KeyValue( KeyValueData* ); char TeamCapture[24]; int CapturePoints; }; Those are all the functions and variables that will be in the capture point. Now create a new file called object_capture.cpp, this will contain the code for the actual capture point. Include these files at the top: #include "extdll.h" #include "util.h" #include "cbase.h" #include "weapons.h" #include "player.h" #include "soundent.h" #include "gamerules.h" #include "animation.h" #include "object.h" Those are all the header files that we will be using for the capture point. The first function will be the Spawn function. void CObjectCapture::Spawn( void ) { Precache( ); pev->movetype = MOVETYPE_TOSS; pev->solid = SOLID_TRIGGER; UTIL_SetOrigin( pev, pev->origin ); UTIL_SetSize(pev, Vector(-64, -64, 0), Vector(64, 64, 64)); SetTouch(Touch); if(CapturePoints == NULL) CapturePoints = 5; } Notice I did not give the capture point a model, if you want it to have a model just use SET_MODEL(ENT(pev), "models/< model name >.mdl"); Be sure to put that after the Precache function is called, and also dont forget to precache the model. The capture point has a movetype toss, so it will drop down to the brush right under it. Solid trigger is so that a player can walk right through it but still capture the flag. The size is bigger than the flag, that way it is easier to capture the flag since there is no model. NOTE: make sure that when mappers put the capture point in they do something to make the capture point stand out! The touch is Touch. CapturePoints is the variable we will be using to get the amount of points a mapper set, if it is NULL (just in case) than a person should get 5 points. Next will be the Precache function. This will precache whatever sounds/models/anything else you may want for the capture point. void CObjectCapture::Precache( void ) { PRECACHE_SOUND ("capture.wav"); } Just replace capture.wav with whatever sound you want, or comment it out if you dont want a sound. Now for the big part! The touch function, this will give the person that captured it their points put the flag back where it came from, and say that it was captured. void CObjectCapture::Touch( CBaseEntity *pOther ) { CBasePlayer *pPlayer = (CBasePlayer *)pOther; if (!pOther->IsPlayer()) return; if(!pPlayer->HasObject) return; if (pPlayer->HasObject) { if(!FStrEq(pPlayer->m_szTeamName, TeamCapture)) return; char text [201]; sprintf( text, "%s team captured the object!\n", TeamCapture); UTIL_ClientPrintAll( HUD_PRINTCENTER, text ); pPlayer->HasObject = FALSE; pPlayer->AddPoints(CapturePoints,FALSE); EMIT_SOUND_DYN( ENT(pev), CHAN_STATIC, "capture.wav", 1, ATTN_NONE, 0, 100 ); ReturnObject(); return; } } If it was touched by something other than a player, return. If the person that touched it does not have the object, than return so you dont execute the rest of the code. If for some reason (I have no idea how) a person did not have the object, I check to see if they have the object again. If they do have it check to see if the persons team name matches the capture point for their team (that will be later in the tutorial) if it does than print to everyone that that team captured the object. Make it so that the player no longer has the object, and give them points. Everyone will hear the sound that the object was captured, comment out this line if you do not want a sound saying that the object was captured. Return the object to where the mapper put it. Now to get two capture points, one for each team. This took some thinking to find out how without retyping the whole capture point over. class CRedCapture : public CObjectCapture { void Spawn( void ) { strcpy( TeamCapture, "Red" ); CObjectCapture::Spawn( ); } void KeyValue( KeyValueData* Data ) { if( FStrEq( Data->szKeyName, "CapturePoints" ) ) { CapturePoints = atoi( Data->szValue ); Data->fHandled = TRUE; } } } }; LINK_ENTITY_TO_CLASS( object_red_capture, CRedCapture ); class CBlueCapture : public CObjectCapture { void Spawn( void ) { strcpy( TeamCapture, "Blue" ); CObjectCapture::Spawn( ); } void KeyValue( KeyValueData* Data ) { if( FStrEq( Data->szKeyName, "CapturePoints" ) ) { CapturePoints = atoi( Data->szValue ); Data->fHandled = TRUE; } } }; LINK_ENTITY_TO_CLASS( object_blue_capture, CBlueCapture ); The first one spawns a capture point, but it copys the team Red into the team capture variable which was used in the touch function to check what team the player was on. It links the entity object_red_capture to the red capture point. The blue capture point is almost the same except that it copies Blue as the team that will capture it and links object_blue_capture to CBlueCapture. Both of those also have a KeyValue function that gets the amount of points the mapper set for a capture. Now for the fgd file. Add these lines somewhere in your mods fgd file @PointClass = object_blue_capture : "Blue Capture Point" [ CapturePoints(integer) : "Capture points" : 5 ] @PointClass = object_red_capture : "Red Capture Point" [ CapturePoints(integer) : "Capture points" : 5 ] @PointClass = object_world : "Object" [] Those are all the entities wer made, the blue and red capture points and the object. Now for the last part, having a sprite be displayed when a person has the flag. Open up you client.dll project and make a new file called object_sprite.cpp, this file will show a sprite on the persons hud when they have the object. First will be the include files: #include "hud.h" #include "clutil.h" #include < string.h > // remove spaces #include < time.h > // remove spaces #include < stdio.h > // remove spaces #include "parsemsg.h" And the declared message DECLARE_MESSAGE(m_HasObject, ObjectSprite ) If you want to know what more of this means see 2s tutorial on Wavelegnth. Next would be the init function, this is like the spawn function for the client dll. int CObjectSprite::Init(void) { HOOK_MESSAGE( ObjectSprite ); m_iFlags |= HUD_ACTIVE; gHUD.AddHudElem(this); return 1; }; That adds the hud element and and makes it so that it can be seen. Next is the vid init function. This is going to hold the name of the sprite and its size. int CObjectSprite::VidInit(void) { m_hSprite = 0; int HUD_ObjectSprite = gHUD.GetSpriteIndex( "hasobject" ); SpriteArea = &gHUD.GetSpriteRect(HUD_ObjectSprite); return 1; }; That has the size of the sprite and its index. I am not very good with sprites on the hud :(, but this all works. Now for the draw function, this could be considered the touch function for the client dll. int CObjectSprite::Draw(float fTime) { if ( gHUD.m_iHideHUDDisplay & ( HIDEHUD_ALL ) ) return 1; if(Icon == 1) { m_hSprite = LoadSprite("sprites/hasobject.spr"); SPR_Set( m_hSprite, 64, 64, 64 ); SPR_DrawAdditive( 0, ScreenWidth / 4, ScreenHeight / 4, SurvFlagArea ); } else if(Icon == 2) { m_hSprite = 0; m_iFlags |= ~HUD_ACTIVE; } return 1; } That checks to see what number the server dll sent over, if it was 1 then show it, if it was 2 then hide the sprite. Replace sprites/hasobject.spr with the sprite that you want displayed. Next function gets the values that the server dll sent over and puts it into the team variable. int CObjectSprite::MsgFunc_ObjectSprite(const char *pszName, int iSize, void *pbuf) { BEGIN_READ( pbuf, iSize ); Icon = READ_BYTE(); m_iFlags |= HUD_ACTIVE; return 1; } You can close up that file now. Open up hud.cpp in your client dll project and go down to the line that says: m_StatusIcons.Init(); Right under that put m_HasObject.Init(); Still in hud.cpp go down to the line m_StatusIcons.VidInit(); Under that put m_HasObject.VidInit(); We are done in hud.cpp but we still need to declare all the functions and variables. So open up hud.h and put these lines somewhere in it. class CObjectSprite : public CHudBase { public: int Init( void ); int VidInit( void ); int Draw(float flTime); int MsgFunc_ObjectSprite(const char *pszName, int iSize, void *pbuf); int Icon; private: wrect_t *SpriteArea; HSPRITE m_hSprite; }; Those are all the functions and variables that were used for the sprite to show up. Go down to CHudStatusIcons m_StatusIcons; And right under that put CObjectSprite m_HasObject; We are now done editing the client.dll project. That will let us show the sprite on their screen. Now to actually send the message that it should show up. Open up the mp.dll project. Go into player.cpp go down to the line int gmsgStatusValue = 0; Under that put int gmsgShowSprite = 0; Find the line in player.cpp gmsgStatusValue = REG_USER_MSG("StatusValue", 3); and under that put gmsgShowSprite = REG_USER_MSG("ObjectSprite", 1); That just says that the gmsgShowSprite is linked to the message ObjectSprite that we declared in the client dll. Go to the bottom of the PreThink function in player.cpp and put the lines if (HasObject) { MESSAGE_BEGIN( MSG_ONE, gmsgShowSprite, NULL, pev ); WRITE_BYTE( 1 ); MESSAGE_END(); } else { MESSAGE_BEGIN( MSG_ONE, gmsgShowSprite, NULL, pev ); WRITE_BYTE( 2 ); MESSAGE_END(); } If you have the object then it triggers the sprite to show on the hud by sending the message to the client. If you do not have the sprite then it hides the sprite from the hud. Now finally the long tutorial is over. You should be bale to make an object that you can pick up, pick it up and capture it for points, and have mappers put it in their maps, and lastly put a sprite on the hud showing when they have the flag! All that code was just a base for making that happen and can definatly be improved. Good luck in making that capture point work :)
Any questions or suggestions should be sent to me:
british@epix.net