Beaucoup de newbies se demande comment faire réaparaitre les objets au début d'un nouveau round, et il emploie le plus souvent des techniques rendant le code très lourd... (en tout cas c'est comme ça que j'ai fait au début). Je vais donc vous filez le code de mon mod Over Ground (<= De la PUB ça fait jamais de mal) qui sert à Respawner les entités, chez moi il fonctionne, devrais pas y avoir de problèmes chez vous.
Pour commencer on va définir deux trois trucs dans la classe CBaseEntity, ouvrez cbase.h et à la fin de la déclaration de classe, juste avant le " };", ajoutez :/**** * * Over Ground (2002-2003) - Mod pour Half-Life - SDK * * Code source de Tigerknee (tigerknee@voila.fr) * Plus d'infos sur le site internet du mod : * http://og.portailmods.com * * ****/virtual void EntSave ( void); virtual void EntRestore ( void);
entvars_t pev_old; KeyValueSave *pkvd_old; bool firstround;
Maintenant on va s'en sevir, pour commencer, ouvrez cbase.cpp et tout à la fin ajoutez:/**** * * Over Ground (2002-2003) - Mod pour Half-Life - SDK * * Code source de Tigerknee (tigerknee@voila.fr) * Plus d'infos sur le site internet du mod : * http://og.portailmods.com * * ****/void CBaseEntity::EntSave( void ) { // On sauvegarde les données pev_old = *pev; firstround = true; }
void CBaseEntity::EntRestore( void ) { *pev = pev_old;
// Les KeyValues KeyValueData kvd; KeyValueSave *ValueKey; ValueKey = pkvd_old;
while ( ValueKey ) { kvd.fHandled = false;
kvd.szClassName = ValueKey->Classname; kvd.szKeyName = ValueKey->Keyname; kvd.szValue = ValueKey->Value;
KeyValue( &kvd ); ValueKey = ValueKey->next; }
// On reset le think... SetThink( NULL ); SetUse( NULL ); SetTouch( NULL ); SetBlocked( NULL );
pev->nextthink = -1; firstround = false; }
Toujours dans cbase.cpp, cherchez la fonction DispatchSpawn(), on va y ajouter un bout de code, juste avant l'appel de la fonction Spawn(), ajoutez le code suivant:/**** * * Over Ground (2002-2003) - Mod pour Half-Life - SDK * * Code source de Tigerknee (tigerknee@voila.fr) * Plus d'infos sur le site internet du mod : * http://og.portailmods.com * * ****/int DispatchSpawn( edict_t *pent ) { CBaseEntity *pEntity = (CBaseEntity *)GET_PRIVATE(pent);
if (pEntity) { // Initialize these or entities who don't link to the world won't have anything in here pEntity->pev->absmin = pEntity->pev->origin - Vector(1,1,1); pEntity->pev->absmax = pEntity->pev->origin + Vector(1,1,1);
// On sauvegarde les données concernant l'entité pEntity->EntSave(); pEntity->Spawn();
// Try to get the pointer again, in case the spawn function deleted the entity. // UNDONE: Spawn() should really return a code to ask that the entity be deleted, but // that would touch too much code for me to do that right now. pEntity = (CBaseEntity *)GET_PRIVATE(pent);
if ( pEntity ) { if ( g_pGameRules && !g_pGameRules->IsAllowedToSpawn( pEntity ) ) return -1; // return that this entity should be deleted if ( pEntity->pev->flags & FL_KILLME ) return -1; } }
return 0; }
Bien, maintenant cherchez la fonction DispatchKeyValue(), et ajoutez y le code suivant:/**** * * Over Ground (2002-2003) - Mod pour Half-Life - SDK * * Code source de Tigerknee (tigerknee@voila.fr) * Plus d'infos sur le site internet du mod : * http://og.portailmods.com * * ****/void DispatchKeyValue( edict_t *pentKeyvalue, KeyValueData *pkvd ) { KeyValueSave *KValue;
if ( !pkvd || !pentKeyvalue ) return;
EntvarsKeyvalue( VARS(pentKeyvalue), pkvd );
// If the key was an entity variable, or there's no class set yet, don't look for the object, it may // not exist yet. if ( pkvd->fHandled || pkvd->szClassName == NULL ) return;
// Get the actualy entity object CBaseEntity *pEntity = (CBaseEntity *)GET_PRIVATE(pentKeyvalue);
if ( !pEntity ) return;
KValue = new KeyValueSave;
strncpy( KValue->Classname, pkvd->szClassName, 255 ); strncpy( KValue->Keyname, pkvd->szKeyName, 255 ); strncpy( KValue->Value, pkvd->szValue, 255 );
KValue->next = pEntity->pkvd_old; pEntity->pkvd_old = KValue;
pEntity->KeyValue( pkvd ); }
On a déja fait pas mal de trucs mais c'est loin d'être fini (enfin j'exagère c'est bientot fini quand même), maintenant on va faire un tour de client.cpp, au début du fichier, après les #includes, ajoutez les lignes de code suivantes:/**** * * Over Ground (2002-2003) - Mod pour Half-Life - SDK * * Code source de Tigerknee (tigerknee@voila.fr) * Plus d'infos sur le site internet du mod : * http://og.portailmods.com * * ****/edict_t *pEdictList_save; int edictCount_save; int clientMax_save;
Hum, mais à quoi ça va bien pouvoir nous servir tout ça, direction la fonction ServerActivate(), remplacez la fonction par celle-ci:/**** * * Over Ground (2002-2003) - Mod pour Half-Life - SDK * * Code source de Tigerknee (tigerknee@voila.fr) * Plus d'infos sur le site internet du mod : * http://og.portailmods.com * * ****/void ServerActivate( edict_t *pEdictList, int edictCount, int clientMax ) { int i; CBaseEntity *pClass;
// Every call to ServerActivate should be matched by a call to ServerDeactivate g_serveractive = 1;
// On commence par sauvegarder les valeurs pour les réutiliser // lors du chargement d'un nouveau round pEdictList_save = pEdictList; edictCount_save = edictCount; clientMax_save = clientMax;
// Clients have not been initialized yet for ( i = 0; i < edictCount; i++ ) { if ( pEdictList[i].free ) continue;
// Clients aren't necessarily initialized until ClientPutInServer() if ( i < clientMax || !pEdictList[i].pvPrivateData ) continue;
pClass = CBaseEntity::Instance( &pEdictList[i] ); // Activate this entity if it's got a class & isn't dormant
if ( pClass && !(pClass->pev->flags & FL_DORMANT) ) pClass->Activate(); else ALERT( at_console, "Can't instance %sn", STRING(pEdictList[i].v.classname) ); }
// Link user messages here to make sure first client can get them... LinkUserMessages(); }
Bien maintenant juste en dessous on va ajoutez deux nouvelles fonctions:/**** * * Over Ground (2002-2003) - Mod pour Half-Life - SDK * * Code source de Tigerknee (tigerknee@voila.fr) * Plus d'infos sur le site internet du mod : * http://og.portailmods.com * * ****/bool IsMapEntity( CBaseEntity *Entity ) { CBaseEntity *pClass;
for ( int i = 0; i < edictCount_save; i++ ) { if ( pEdictList_save[i].free ) continue;
if ( i < clientMax_save || !pEdictList_save[i].pvPrivateData ) continue;
pClass = CBaseEntity::Instance( &pEdictList_save[i] );
if ( pClass && pClass == Entity ) return true; }
return false; }
void ServerRestore( void ) { CBaseEntity *pEntity;
// On supprime tout ou on restaure si l'entité fait parties // de celles placées volontairements par le mappeur for ( int i = 1; i < gpGlobals->maxEntities; i++ ) { // on récupère l'entité pEntity = UTIL_EntityByIndex( i );
if ( !pEntity ) continue;
// On ne fait rien si c'est un joueur, un monstre ou si l'entité est désactivée if ( pEntity->pev->flags & ( FL_DORMANT | FL_CLIENT | FL_MONSTER ) ) continue;
// Sinon on la supprime ou on la restaure si elle existait en début de partie if ( IsMapEntity( pEntity ) ) { pEntity->EntRestore(); pEntity->Spawn(); pEntity->Activate(); } else { // on arrêtte les sons des objets susceptibles d'en jouer un if ( FClassnameIs( pEntity->pev, "rpg_rocket" ) ) STOP_SOUND( pEntity->edict(), CHAN_VOICE, "weapons/rpg_rocket.wav" );
UTIL_Remove( pEntity ); } } }
J'utilise une nouvelle fonction, on va la définir, dans util.cpp, juste en dessous de la définition de UTIL_PlayerByindex, définissez cette fonction:/**** * * Over Ground (2002-2003) - Mod pour Half-Life - SDK * * Code source de Tigerknee (tigerknee@voila.fr) * Plus d'infos sur le site internet du mod : * http://og.portailmods.com * * ****/CBaseEntity *UTIL_EntityByIndex( int Index ) { CBaseEntity *pEnt = NULL;
if ( Index > 0 && Index <= gpGlobals->maxEntities ) { edict_t *pEdict = INDEXENT( Index );
if ( UTIL_IsValidEntity( pEdict ) ) pEnt = (CBaseEntity *)GET_PRIVATE( pEdict ); }
return pEnt; }
Puis dans util.h, ajoutez:/**** * * Over Ground (2002-2003) - Mod pour Half-Life - SDK * * Code source de Tigerknee (tigerknee@voila.fr) * Plus d'infos sur le site internet du mod : * http://og.portailmods.com * * ****/extern CBaseEntity *UTIL_EntityByIndex( int Index );
Maintenant allez faire un tour dans eiface.h, et juste en dessous de la définition de la structure KeyValueData, ajoutez ceci:/**** * * Over Ground (2002-2003) - Mod pour Half-Life - SDK * * Code source de Tigerknee (tigerknee@voila.fr) * Plus d'infos sur le site internet du mod : * http://og.portailmods.com * * ****/// Pour sauvegarder les KeyValues typedef struct KeyValueSave_s {
char Classname[255]; char Keyname[255]; char Value[255];
KeyValueSave_s *next;
} KeyValueSave;
Ouah, la plus grosse partie est faites, maintenant il faut s'occuper de deux trois cas particuliers, vous aurez sans doute remarquez au passage puisque vous ne faites pas un simple copier-coller que je stoppe le son de la roquette, en effet, celle-ci joue un son alors si on arrête pas le son, bah vous aurez plus de roquettes mais un son en boucle, c'est assez cool. Enfin vous devez ajouter à cet endroit le code nécessaire pour stopper les sons des diverses entités spécifiques à votre mod susceptibles d'en jouer un. Bon, on va s'occupper de quelques entités maintenant, pour commencer le ambient_generic, allez dans le fichier sound.cpp et cherchez la fonction Spawn() de l'ambient_generic, bon je vous dit tout de suite je sais plus si y'avait une fonction Precache() ou non puisque je l'ai bougé, alros faites de même et remplacer la fonction Spawn() par:/**** * * Over Ground (2002-2003) - Mod pour Half-Life - SDK * * Code source de Tigerknee (tigerknee@voila.fr) * Plus d'infos sur le site internet du mod : * http://og.portailmods.com * * ****/void CAmbientGeneric :: Spawn( void ) { /* -1 : "Default" 0 : "Everywhere" 200 : "Small Radius" 125 : "Medium Radius" 80 : "Large Radius" */ m_fLooping = false;
char* szSoundFile = (char*) STRING(pev->message);
if ( FStringNull( pev->message ) || strlen( szSoundFile ) < 1 ) { ALERT( at_error, "EMPTY AMBIENT AT: %f, %f, %fn", pev->origin.x, pev->origin.y, pev->origin.z ); pev->nextthink = gpGlobals->time + 0.1; SetThink( SUB_Remove ); return; }
if ( !FStringNull( pev->message ) && strlen( szSoundFile ) > 1 ) { if (*szSoundFile != '!') PRECACHE_SOUND(szSoundFile); }
// On arrête le son UTIL_EmitAmbientSound ( ENT(pev), pev->origin, szSoundFile, 0, 0, SND_STOP, 0);
if ( FBitSet ( pev->spawnflags, AMBIENT_SOUND_EVERYWHERE) ) { m_flAttenuation = ATTN_NONE; } else if ( FBitSet ( pev->spawnflags, AMBIENT_SOUND_SMALLRADIUS) ) { m_flAttenuation = ATTN_IDLE; } else if ( FBitSet ( pev->spawnflags, AMBIENT_SOUND_MEDIUMRADIUS) ) { m_flAttenuation = ATTN_STATIC; } else if ( FBitSet ( pev->spawnflags, AMBIENT_SOUND_LARGERADIUS) ) { m_flAttenuation = ATTN_NORM; } else {// if the designer didn't set a sound attenuation, default to one. m_flAttenuation = ATTN_STATIC; }
pev->solid = SOLID_NOT; pev->movetype = MOVETYPE_NONE;
// Set up think function for dynamic modification // of ambient sound's pitch or volume. Don't // start thinking yet.
SetThink(RampThink); pev->nextthink = -1;
// allow on/off switching via 'use' function.
SetUse ( ToggleUse );
m_fActive = FALSE;
if ( FBitSet ( pev->spawnflags, AMBIENT_SOUND_NOT_LOOPING ) ) m_fLooping = FALSE; else m_fLooping = TRUE;
// init all dynamic modulation parms InitModulationParms();
if ( !FBitSet (pev->spawnflags, AMBIENT_SOUND_START_SILENT ) ) { // start the sound ASAP if (m_fLooping) m_fActive = TRUE; }
if ( m_fActive ) { UTIL_EmitAmbientSound ( ENT(pev), pev->origin, szSoundFile, (m_dpv.vol * 0.01), m_flAttenuation, firstround ? SND_SPAWNING : 0, m_dpv.pitch);
pev->nextthink = gpGlobals->time + 0.1; } }
J'ai juste fait deux trois modifs mais rien de bien méchant, vous pourrez vous attarder dessus si ça vous interesse, maintenant le func_rotating, direction le fichier bmodels.cpp et cherchez l'endroit où se trouve le func_rotating, vu que j'ai un peu touché à tout et que je sais plus comment sont les fontions d'origines, contentez vous de remplacez les fonctions Spawn() et Precache() par celles-ci:/**** * * Over Ground (2002-2003) - Mod pour Half-Life - SDK * * Code source de Tigerknee (tigerknee@voila.fr) * Plus d'infos sur le site internet du mod : * http://og.portailmods.com * * ****/void CFuncRotating :: Spawn( ) { // set final pitch. Must not be PITCH_NORM, since we // plan on pitch shifting later.
m_pitch = PITCH_NORM - 1;
Precache( );
// maintain compatibility with previous maps if (m_flVolume == 0.0) m_flVolume = 1.0;
// if the designer didn't set a sound attenuation, default to one. m_flAttenuation = ATTN_NORM;
if ( FBitSet ( pev->spawnflags, SF_BRUSH_ROTATE_SMALLRADIUS) ) { m_flAttenuation = ATTN_IDLE; } else if ( FBitSet ( pev->spawnflags, SF_BRUSH_ROTATE_MEDIUMRADIUS) ) { m_flAttenuation = ATTN_STATIC; } else if ( FBitSet ( pev->spawnflags, SF_BRUSH_ROTATE_LARGERADIUS) ) { m_flAttenuation = ATTN_NORM; }
// prevent divide by zero if level designer forgets friction! if ( m_flFanFriction <= 0 ) { m_flFanFriction = 1; }
if ( FBitSet(pev->spawnflags, SF_BRUSH_ROTATE_Z_AXIS) ) pev->movedir = Vector(0,0,1); else if ( FBitSet(pev->spawnflags, SF_BRUSH_ROTATE_X_AXIS) ) pev->movedir = Vector(1,0,0); else pev->movedir = Vector(0,1,0); // y-axis
// check for reverse rotation if ( FBitSet(pev->spawnflags, SF_BRUSH_ROTATE_BACKWARDS) ) pev->movedir = pev->movedir * -1;
// some rotating objects like fake volumetric lights will not be solid. if ( FBitSet(pev->spawnflags, SF_ROTATING_NOT_SOLID) ) { pev->solid = SOLID_NOT; pev->skin = CONTENTS_EMPTY; pev->movetype = MOVETYPE_PUSH; } else { pev->solid = SOLID_BSP; pev->movetype = MOVETYPE_PUSH; }
UTIL_SetOrigin(pev, pev->origin); SET_MODEL( ENT(pev), STRING(pev->model) );
SetUse( RotatingUse ); // did level designer forget to assign speed? if (pev->speed <= 0) pev->speed = 0;
// instant-use brush? if ( FBitSet( pev->spawnflags, SF_BRUSH_ROTATE_INSTANT) ) { SetThink( SUB_CallUseToggle ); pev->nextthink = pev->ltime + 1.5; // leave a magic delay for client to start up } // can this brush inflict pain? if ( FBitSet (pev->spawnflags, SF_BRUSH_HURT) ) { SetTouch( HurtTouch ); } }
void CFuncRotating :: Precache( void ) { char* szSoundFile = (char*) STRING(pev->message);
// set up fan sounds
if (!FStringNull( pev->message ) && strlen( szSoundFile ) > 0) { // if a path is set for a wave, use it PRECACHE_SOUND(szSoundFile); pev->noiseRunning = ALLOC_STRING(szSoundFile); } else { // otherwise use preset sound switch (m_sounds) { case 1: PRECACHE_SOUND ("fans/fan1.wav"); pev->noiseRunning = ALLOC_STRING("fans/fan1.wav"); break; case 2: PRECACHE_SOUND ("fans/fan2.wav"); pev->noiseRunning = ALLOC_STRING("fans/fan2.wav"); break; case 3: PRECACHE_SOUND ("fans/fan3.wav"); pev->noiseRunning = ALLOC_STRING("fans/fan3.wav"); break; case 4: PRECACHE_SOUND ("fans/fan4.wav"); pev->noiseRunning = ALLOC_STRING("fans/fan4.wav"); break; case 5: PRECACHE_SOUND ("fans/fan5.wav"); pev->noiseRunning = ALLOC_STRING("fans/fan5.wav"); break;
case 0: default: if (!FStringNull( pev->message ) && strlen( szSoundFile ) > 0) { PRECACHE_SOUND(szSoundFile);
pev->noiseRunning = ALLOC_STRING(szSoundFile); break; }else { pev->noiseRunning = ALLOC_STRING("common/null.wav"); break; } } }
EMIT_SOUND_DYN(ENT(pev), CHAN_STATIC, (char *)STRING(pev->noiseRunning /* Stop */), 0, 0, SND_STOP, m_pitch); }
Stop, ce n'est pas tout, vous aurez aussi un problème avec le multi_manager, => triggers.cpp, ajoutez à la classe CMultiManager la fonction suivante:/**** * * Over Ground (2002-2003) - Mod pour Half-Life - SDK * * Code source de Tigerknee (tigerknee@voila.fr) * Plus d'infos sur le site internet du mod : * http://og.portailmods.com * * ****/void CMultiManager :: EntRestore( void ) { // Normalement pas de chances pour que ce soit un clone puisqu'il n'était // pas présent en début de partie, mais bon if ( IsClone() ) { UTIL_Remove( this ); return; }
m_cTargets = 0;
for ( int i = 0; i < MAX_MULTI_TARGETS; i++ ) { m_iTargetName [ i ] = NULL; m_flTargetDelay [ i ] = NULL; }
CBaseEntity::EntRestore(); }
Je vous laisse l'ajouté dans votre définition de classe c'est pas bien dur. Voila maintenant dans votre fonction qui vous sert à relancer un nouveau round, ajoutez le bout de code suivant:/**** * * Over Ground (2002-2003) - Mod pour Half-Life - SDK * * Code source de Tigerknee (tigerknee@voila.fr) * Plus d'infos sur le site internet du mod : * http://og.portailmods.com * * ****/ServerRestore();
Sans oublier de mettre cette ligne au début du fichier dans lequel se trouve votre fonction après les #includes sinon le compilateur va vous dire qu'il ne connait pas la fonction:/**** * * Over Ground (2002-2003) - Mod pour Half-Life - SDK * * Code source de Tigerknee (tigerknee@voila.fr) * Plus d'infos sur le site internet du mod : * http://og.portailmods.com * * ****/void ServerRestore( void );
Voila, c'est tout pour ce tutorial, j'éspère que j'ai rien oublié au code, mais ça devrait fonctionner, faites quand même attention à bien vérifier si les entités de votre mod n'ont pas besoin d'avoir une fonction EntRestore() particulière ou un son à stopper, mais bon je vous laisse faire.
Date de création : 10/12/2005 @ 15:28
Dernière modification : 13/05/2006 @ 18:25
Catégorie : 3- Le precache
Page lue 2052 fois
Prévisualiser la page
Imprimer la page
|