|
|
|
This tutorial will show you how to make an entity that someone is supposed to get and take to a capture point. First create a header file called object.h in it put the following: // // object.h // class CObject : public CBaseEntity { public: virtual void Spawn( void ); virtual void Precache( void ); virtual void ReturnObject( void ); virtual void Materialize( void ); virtual void Touch( CBaseEntity *pOther ); virtual BOOL MyTouch( CBasePlayer *pPlayer ); virtual void Think( void ); BOOL HasObject; BOOL FallenObject; }; Those are all the functions that the object will have. Now create the file object.cpp, this is going to be the actually object that you can pick up and put on the capture point. First put: #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" extern int gmsgItemPickup; enum Object_Animations { IDLE = 1 }; at the top of the file. There are the header files at the top, including the the new object.h header file we just made. Extern int gmsgItemPickUp is for when you touch the flag and pick it up. Object_Animations is the enum that will hold the object animations. Next will be the spawn. void CObject::Spawn ( void ) { Precache( ); SET_MODEL(ENT(pev), "models/can.mdl"); pev->movetype = MOVETYPE_TOSS; pev->solid = SOLID_TRIGGER; UTIL_SetOrigin( pev, pev->origin ); UTIL_SetSize(pev, Vector(-16, -16, 0), Vector(16, 16, 16)); SetThink( Think ); SetTouch( Touch ); pev->sequence = IDLE; pev->framerate = 1.0; pev->nextthink = gpGlobals->time + 0.1; } It calls the Precache() function to precache all the models and anything else you need before you spawn it. The model is just a can, change that to whatever you want to capture like a flag. It has a movetype toss so it will fall to a brush below it. SOLID_TRIGGER is so you can trigger it by walking through it. It sets the think to Think and the touch to Touch, those functions will be created later in this tutorial. The sequence right now is IDLE. Next is the Precache function. void CObject::Precache( ) { PRECACHE_MODEL( "models/can.mdl" ); } that should be self explanatory. Materialize is the function that will make it visible and operable again after we change some of the things around in it. void CObject::Materialize( void ) { if ( pev->effects & EF_NODRAW ) { pev->effects &= ~EF_NODRAW; pev->effects |= EF_MUZZLEFLASH; } SetTouch( Touch ); SetThink( Think ); } It makes it visible and sets the think and touch back again. Now for the touch function, this does not handle all the picking up information though. void CObject::Touch( CBaseEntity *pOther ) { if ( !pOther->IsPlayer() ) return; CBasePlayer *pPlayer = (CBasePlayer *)pOther; if (MyTouch( pPlayer )) { SUB_UseTargets( pOther, USE_TOGGLE, 0 ); SetTouch( NULL ); SetThink( NULL ); pev->effects |= EF_NODRAW; } } It calls the MyTouch function to see if we actually did pick up the object. If it was picked up this sets the think and touch to NULL and makes it invisible. Now for the big one! MyTouch handles the picking up of the object. *BigGuy: Sorry guys, I goofed on this one the first time. BOOL CObject::MyTouch( CBasePlayer *pPlayer ) { char text[256]; CBaseEntity *pEnt; if ( ( pPlayer->pev->weapons & (1<< WEAPON_SUIT) ) ) { if(pPlayer->HasObject) return FALSE; pPlayer->HasObject = TRUE; CBaseEntity *pEnt = CBaseEntity::Create( "object_follow", pev->origin, pev->angles, pPlayer->edict() ); CObjectFollow *pFollow = (CObjectFollow *)pEnt; pFollow->Owner = pPlayer; if(FStrEq(pPlayer->m_szTeamName, "Red")) { sprintf( text, "Red team has the object!\n"); UTIL_ClientPrintAll( HUD_PRINTCENTER, text ); } else if(FStrEq(pPlayer->m_szTeamName, "Blue")) { sprintf( text, "Blue team has the object!\n"); UTIL_ClientPrintAll( HUD_PRINTCENTER, text ); } MESSAGE_BEGIN( MSG_ONE, gmsgItemPickup, NULL, pPlayer->pev ); WRITE_STRING( STRING(pev->classname) ); MESSAGE_END(); if(FallenObject) UTIL_Remove( this ); return TRUE; } return FALSE; } This is the big thing for the flag, it lets you pick it up. First it checks to see if you have the suit. If you already has the object then you cannot pick it up again. If you dont have the object it gives you the object. It creates the entity that actually follows you, that will be later in this tutorial. It sets who the object is supposed to follow, the player that picked it up. Next it checks to see what team you are on, just replace Red and Blue with whatever your team names are. It then says what team picked up the object, either red or blue. It then picks up the object and says it did by sending a message to the client. If it was fallen from a person that died or other, then it removes it so there wont be more than one object in the world at a time. Return TRUE just says that yes, you did pick up the object. The think function is just for animating. void CObject::Think( void ) { pev->sequence = IDLE; pev->nextthink = gpGlobals->time + 0.1; } That just sets the sequence to play to IDLE. The last function is the one that after you capture the flag it will make it be visible and you can pick it up again, where the mapper put it. void CObject::ReturnObject( ) { edict_t *pFind; CBaseEntity *pEnt; pFind = FIND_ENTITY_BY_CLASSNAME( NULL, "object_world" ); while ( !FNullEnt( pFind ) ) { CBaseEntity *pEnt = CBaseEntity::Instance( pFind ); CObject *pObject = (CObject *)pEnt; pObject->Materialize( ); pFind = FIND_ENTITY_BY_CLASSNAME( pFind, "object_world" ); } } It does a search for the object entity then materializes it there, and does that for every object that the mapper put in the map. The next thing will be to link the actual entity to the class. LINK_ENTITY_TO_CLASS( object_world, CObject ); That says that object_world (the entity that the mappers will put in the map) comes from the CObject class. The object that you pick up is almost done. Open up player.h and right above: int m_iPlayerSound; Put BOOL HasObject; Now it should compile with no errors. But it will crash in game when you try to pick up the flag because the object_follow will not be found. Now onto making the entity that will follow the person Go into object.h and underneath the CObject stuff, we are going to put the CObjectFollow stuff. class CObjectFollow : public CObject { public: virtual void Spawn( void ); virtual void Precache( void ); virtual void Think( void ); CBasePlayer *Owner; }; The following object is alot simpler than the actual one in the world, because all it is a model that animates and follows the owner. So in object.cpp under everything we just did put: void CObjectFollow::Spawn( ) { Precache( ); UTIL_SetOrigin( pev, pev->origin ); pev->movetype = MOVETYPE_NONE; pev->solid = SOLID_NOT; pev->effects |= EF_NODRAW; pev->sequence = IDLE; pev->framerate = 1.0; SET_MODEL(ENT(pev), "models/can.mdl"); SetThink( Think ); pev->nextthink = gpGlobals->time + 0.1; } That will spawn it, pretty self explanatory. There is another precache function. void CObjectFollow::Precache( ) { PRECACHE_MODEL ("models/can.mdl"); } That precaches the can model, you could call the one in CObject, but I wanted to make a new one to give more freedom to my code. The last function here is the Think. void CObjectFollow::Think( ) { pev->effects &= ~EF_NODRAW; pev->aiment = ENT(Owner->pev); pev->movetype = MOVETYPE_FOLLOW; if (!Owner->IsAlive()) UTIL_Remove( this ); if ( !Owner->HasObject) UTIL_Remove( this ); else { pev->sequence = IDLE; pev->nextthink = gpGlobals->time + 0.1; } } If the owner is not alive or no longer has the flag then it is removed from them. If it should still be on them then just animate it. Lastly link the entity to the class. LINK_ENTITY_TO_CLASS( object_follow, CObjectFollow ); Now compile and it should work. Except that when the person that has the flag dies then there is no more flag, that would definatly ruin the gameplay! So go into player.cpp and include the object.h file. Go down to PackDeadPlayerItems(), near the end of the function but before RemoveAllItems( TRUE ); put the lines: if(HasObject) { char szText [201]; CBaseEntity *pEnt; if(FStrEq(m_szTeamName, "Red")) sprintf(szText, "Red lost the object!"); else if(FStrEq(m_szTeamName, "Blue")) sprintf(szText, "Blue lost the object!"); UTIL_ClientPrintAll( HUD_PRINTCENTER, szText ); pEnt = CBaseEntity::Create( "object_world", pev->origin,pev->angles, edict() ); pEnt->pev->velocity = pev->velocity * 1.2; pEnt->pev->angles.x = 0; CObject *pObject = (CObject *)pEnt; pObject->FallenObject = TRUE; HasObject = FALSE; } That makes it so if you die there is a flag in the world the people can pick up. It also says that it is fallen so that there will not be multiple flags in the world. That just says what team dropped the object, creates on in the world, and says that it is fallen. The next part will include the capture point, so for now just run around seeing who can get the flag :)
Any questions or suggestions should be sent to me:
british@epix.net