diff --git a/README.md b/README.md index 12992da..c4cb99a 100644 --- a/README.md +++ b/README.md @@ -59,7 +59,7 @@ Current milestones are separated by "Tiers", which are as follows: - Add *-at least minimal-* death messages. *-Example: "\ was killed by a \".-* **[DONE]** - Implement HUD info about the monsters, along with the "displayname" keyvalue. **[DONE]** -- Implement custom monster classification, the "classify" keyvalue. +- Implement custom monster classification, the "classify" keyvalue. **[DONE]** ### Tier 3 diff --git a/cfg/example_monster.cfg b/cfg/example_monster.cfg index 3c086ea..d1bbcb7 100755 --- a/cfg/example_monster.cfg +++ b/cfg/example_monster.cfg @@ -5,10 +5,31 @@ // To add entries to this file, just pretend it's ripent. // // "delay" means monster respawndelay. +// +// You may also be interesed in these other 2 keyvalues: +// +// "displayname" to change the monster's name, shown in HUD when you point at it. +// "classify" to change the monster's default classification, use one of these values: +// +// CLASS_NONE 0 +// CLASS_MACHINE 1 +// CLASS_PLAYER 2 +// CLASS_HUMAN_PASSIVE 3 +// CLASS_HUMAN_MILITARY 4 +// CLASS_ALIEN_MILITARY 5 +// CLASS_ALIEN_PASSIVE 6 +// CLASS_ALIEN_MONSTER 7 +// CLASS_ALIEN_PREY 8 +// CLASS_ALIEN_PREDATOR 9 +// CLASS_INSECT 10 +// CLASS_PLAYER_ALLY 11 +// CLASS_PLAYER_BIOWEAPON 12 +// CLASS_ALIEN_BIOWEAPON 13 { "origin" "90 -180 150" "delay" "30" +"displayname" "Example Custom Name" "orientation" "1" "spawnflags" "32" "classname" "monster_miniturret" @@ -16,6 +37,7 @@ { "origin" "123 456 789" "delay" "5" +"classify" "7" "angles" "0 45 0" "classname" "monster_houndeye" } diff --git a/cfg/monster_precache.cfg b/cfg/monster_precache.cfg index f0554c4..2fbe81e 100755 --- a/cfg/monster_precache.cfg +++ b/cfg/monster_precache.cfg @@ -1,6 +1,8 @@ // // MONSTERS - monsters that you always want to precache (for dynamic spawning) // +// Install this file to your mod's base directory. +// // (just remove the comment characters at the beginning of the line for the // monsters that you always want to precache.) @@ -10,12 +12,11 @@ //monster_bigmomma //monster_bullsquid //monster_gargantua -//monster_hassassin +//monster_human_assassin //monster_headcrab //monster_human_grunt //monster_houndeye //monster_alien_slave -//monster_icthyosaur //monster_alien_controller //monster_scientist //monster_snark diff --git a/cfg/monster_skill.cfg b/cfg/monster_skill.cfg index cb67e67..2c7267c 100755 --- a/cfg/monster_skill.cfg +++ b/cfg/monster_skill.cfg @@ -1,6 +1,6 @@ // MONSTERS health and damage amounts // -// (Note: Some of these aren't currently used. They're in here for future use.) +// Install this file to your mod's base directory. // Alien Grunt sk_agrunt_health 90 diff --git a/src/dlls/agrunt.cpp b/src/dlls/agrunt.cpp index e5debdf..2981c12 100644 --- a/src/dlls/agrunt.cpp +++ b/src/dlls/agrunt.cpp @@ -125,11 +125,14 @@ const char *CMAGrunt::pAlertSounds[] = //========================================================= int CMAGrunt::IRelationship ( CMBaseEntity *pTarget ) { + // ditto hgrunt.cpp + /* if ( strcmp(STRING(pTarget->pev->model), "models/hgrunt.mdl") == 0 ) { return R_NM; } - + */ + return CMBaseMonster :: IRelationship( pTarget ); } @@ -313,6 +316,11 @@ void CMAGrunt :: PainSound ( void ) //========================================================= int CMAGrunt :: Classify ( void ) { + if ( m_iClassifyOverride == -1 ) // helper + return CLASS_NONE; + else if ( m_iClassifyOverride > 0 ) + return m_iClassifyOverride; // override + return CLASS_ALIEN_MILITARY; } @@ -541,6 +549,13 @@ void CMAGrunt :: Spawn() m_flNextSpeakTime = m_flNextWordTime = gpGlobals->time + 10 + RANDOM_LONG(0, 10); MonsterInit(); + + pev->classname = MAKE_STRING( "monster_alien_grunt" ); + if ( strlen( STRING( m_szMonsterName ) ) == 0 ) + { + // default name + m_szMonsterName = MAKE_STRING( "Alien Grunt" ); + } } //========================================================= diff --git a/src/dlls/apache.cpp b/src/dlls/apache.cpp index d3fcbbb..7af6c0f 100644 --- a/src/dlls/apache.cpp +++ b/src/dlls/apache.cpp @@ -84,6 +84,13 @@ void CMApache :: Spawn( void ) m_flPrevSeen = 0.0f; m_iSoundState = 0; + + pev->classname = MAKE_STRING( "monster_apache" ); + if ( strlen( STRING( m_szMonsterName ) ) == 0 ) + { + // default name + m_szMonsterName = MAKE_STRING( "Apache" ); + } } @@ -111,7 +118,15 @@ void CMApache::Precache( void ) apache_rocket.Precache(); } - +int CMApache :: Classify ( void ) +{ + if ( m_iClassifyOverride == -1 ) // helper + return CLASS_NONE; + else if ( m_iClassifyOverride > 0 ) + return m_iClassifyOverride; // override + + return CLASS_HUMAN_MILITARY; +} void CMApache::NullThink( void ) { @@ -974,4 +989,4 @@ void CMApacheHVR :: AccelerateThink( void ) } -#endif \ No newline at end of file +#endif diff --git a/src/dlls/barney.cpp b/src/dlls/barney.cpp index c7a4650..188a488 100644 --- a/src/dlls/barney.cpp +++ b/src/dlls/barney.cpp @@ -186,6 +186,11 @@ int CMBarney :: ISoundMask ( void) //========================================================= int CMBarney :: Classify ( void ) { + if ( m_iClassifyOverride == -1 ) // helper + return CLASS_NONE; + else if ( m_iClassifyOverride > 0 ) + return m_iClassifyOverride; // override + return CLASS_PLAYER_ALLY; } @@ -357,6 +362,13 @@ void CMBarney :: Spawn() m_afCapability = bits_CAP_HEAR | bits_CAP_TURN_HEAD | bits_CAP_DOORS_GROUP; MonsterInit(); + + pev->classname = MAKE_STRING( "monster_barney" ); + if ( strlen( STRING( m_szMonsterName ) ) == 0 ) + { + // default name + m_szMonsterName = MAKE_STRING( "Barney" ); + } } //========================================================= diff --git a/src/dlls/bigmomma.cpp b/src/dlls/bigmomma.cpp index 4712cda..ec89a27 100644 --- a/src/dlls/bigmomma.cpp +++ b/src/dlls/bigmomma.cpp @@ -48,6 +48,7 @@ public: void CMInfoBM::Spawn( void ) { + pev->classname = MAKE_STRING( "info_bigmomma" ); } void CMInfoBM::KeyValue( KeyValueData* pkvd ) @@ -298,6 +299,11 @@ void CMBigMomma :: KeyValue( KeyValueData *pkvd ) //========================================================= int CMBigMomma :: Classify ( void ) { + if ( m_iClassifyOverride == -1 ) // helper + return CLASS_NONE; + else if ( m_iClassifyOverride > 0 ) + return m_iClassifyOverride; // override + return CLASS_ALIEN_MONSTER; } @@ -610,6 +616,13 @@ void CMBigMomma :: Spawn() m_MonsterState = MONSTERSTATE_NONE; MonsterInit(); + + pev->classname = MAKE_STRING( "monster_bigmomma" ); + if ( strlen( STRING( m_szMonsterName ) ) == 0 ) + { + // default name + m_szMonsterName = MAKE_STRING( "Big Momma" ); + } } //========================================================= diff --git a/src/dlls/bullsquid.cpp b/src/dlls/bullsquid.cpp index 67980d8..7af2538 100644 --- a/src/dlls/bullsquid.cpp +++ b/src/dlls/bullsquid.cpp @@ -357,6 +357,11 @@ BOOL CMBullsquid :: FValidateHintType ( short sHint ) //========================================================= int CMBullsquid :: Classify ( void ) { + if ( m_iClassifyOverride == -1 ) // helper + return CLASS_NONE; + else if ( m_iClassifyOverride > 0 ) + return m_iClassifyOverride; // override + return CLASS_ALIEN_MONSTER; } @@ -617,6 +622,13 @@ void CMBullsquid :: Spawn() m_flNextSpitTime = gpGlobals->time; MonsterInit(); + + pev->classname = MAKE_STRING( "monster_bullchicken" ); + if ( strlen( STRING( m_szMonsterName ) ) == 0 ) + { + // default name + m_szMonsterName = MAKE_STRING( "Bullsquid" ); + } } //========================================================= diff --git a/src/dlls/cmbase.h b/src/dlls/cmbase.h index be21e6a..a83ac8b 100644 --- a/src/dlls/cmbase.h +++ b/src/dlls/cmbase.h @@ -540,7 +540,6 @@ public: class CMBaseMonster; - extern int GetMonsterIndex(void); // diff --git a/src/dlls/cmbasemonster.h b/src/dlls/cmbasemonster.h index 9f9b666..2428e68 100644 --- a/src/dlls/cmbasemonster.h +++ b/src/dlls/cmbasemonster.h @@ -101,7 +101,10 @@ public: string_t m_iszTriggerTarget;// name of target that should be fired. Vector m_HackedGunPos; // HACK until we can query end of gun - + + string_t m_szMonsterName; // Monster name to display on HUD + int m_iClassifyOverride; // Overriden classification for this monster + void KeyValue( KeyValueData *pkvd ); // monster use function @@ -792,7 +795,7 @@ class CMApache : public CMBaseMonster public: void Spawn( void ); void Precache( void ); - int Classify( void ) { return CLASS_HUMAN_MILITARY; }; + int Classify( void ); int BloodColor( void ) { return DONT_BLEED; } void Killed( entvars_t *pevAttacker, int iGib ); void GibMonster( void ); diff --git a/src/dlls/combat.cpp b/src/dlls/combat.cpp index ae34eaa..44a0b3a 100644 --- a/src/dlls/combat.cpp +++ b/src/dlls/combat.cpp @@ -589,7 +589,11 @@ void CMBaseMonster :: Killed( entvars_t *pevAttacker, int iGib ) { unsigned int cCount = 0; BOOL fDone = FALSE; - + + // If a player killed this monster, add score + if ( UTIL_IsPlayer( ENT( pevAttacker ) ) ) + pevAttacker->frags += 1.0; + if ( HasMemory( bits_MEMORY_KILLED ) ) { if ( ShouldGibMonster( iGib ) ) @@ -822,7 +826,7 @@ int CMBaseMonster :: TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker { float flTake; Vector vecDir; - + if (!pev->takedamage) return 0; diff --git a/src/dlls/controller.cpp b/src/dlls/controller.cpp index 9bd0ed4..fcb8bf1 100644 --- a/src/dlls/controller.cpp +++ b/src/dlls/controller.cpp @@ -81,6 +81,11 @@ const char *CMController::pDeathSounds[] = //========================================================= int CMController :: Classify ( void ) { + if ( m_iClassifyOverride == -1 ) // helper + return CLASS_NONE; + else if ( m_iClassifyOverride > 0 ) + return m_iClassifyOverride; // override + return CLASS_ALIEN_MILITARY; } @@ -310,6 +315,13 @@ void CMController :: Spawn() m_MonsterState = MONSTERSTATE_NONE; MonsterInit(); + + pev->classname = MAKE_STRING( "monster_alien_controller" ); + if ( strlen( STRING( m_szMonsterName ) ) == 0 ) + { + // default name + m_szMonsterName = MAKE_STRING( "Alien Controller" ); + } } //========================================================= @@ -1113,6 +1125,8 @@ void CMControllerHeadBall :: Spawn( void ) m_hOwner = pev->owner; pev->dmgtime = gpGlobals->time; + + pev->classname = MAKE_STRING( "controller_head_ball" ); } @@ -1297,9 +1311,10 @@ void CMControllerZapBall :: Spawn( void ) m_hOwner = pev->owner; pev->dmgtime = gpGlobals->time; // keep track of when ball spawned pev->nextthink = gpGlobals->time + 0.1; + + pev->classname = MAKE_STRING( "controller_energy_ball" ); } - void CMControllerZapBall :: Precache( void ) { PRECACHE_MODEL("sprites/xspark4.spr"); diff --git a/src/dlls/dllapi.cpp b/src/dlls/dllapi.cpp index c810527..860d549 100644 --- a/src/dlls/dllapi.cpp +++ b/src/dlls/dllapi.cpp @@ -58,6 +58,24 @@ extern gamedll_funcs_t *gpGamedllFuncs; extern cvar_t *dllapi_log; extern cvar_t *monster_spawn; +extern cvar_t *monster_show_deaths; +extern cvar_t *monster_show_info; + +// Player TakeDamage and Killed +int g_DamageMsg; +bool g_DamageActive; +int g_DamageVictim; +edict_t *g_DamageAttacker[33]; +int g_DamageBits[33]; +bool g_PlayerKilled[33]; +float g_flWaitTillMessage[33]; + +// DeathMsg +int g_DeathMsg; +bool g_DeathActive; + +// TE_TEXTMESSAGE +float g_NextMessage[33]; cvar_t *g_psv_gravity = NULL; @@ -122,7 +140,7 @@ monster_type_t monster_types[]= "monster_bigmomma", FALSE, "monster_bullsquid", FALSE, "monster_alien_controller", FALSE, - "monster_hassassin", FALSE, + "monster_human_assassin", FALSE, "monster_headcrab", FALSE, "monster_human_grunt", FALSE, "monster_houndeye", FALSE, @@ -305,7 +323,7 @@ void check_monster_hurt(edict_t *pAttacker) } -void check_monster_dead(void) +void check_monster_dead(edict_t *pAttacker) { for (int index = 0; index < monster_ents_used; index++) { @@ -324,8 +342,9 @@ void check_monster_dead(void) pent->v.flags &= ~FL_KILLME; // clear FL_KILLME bit pent->v.deadflag = DEAD_NO; // bring back to life - - monsters[index].pMonster->Killed(VARS(pent), 0); + + monsters[index].pMonster->Killed(VARS(pAttacker), 0); + monsters[index].killed = TRUE; } } @@ -344,6 +363,195 @@ void check_monster_dead(void) } +void check_player_dead( edict_t *pPlayer ) +{ + // Death messages are disabled + if (!monster_show_deaths->value) + return; + + int iPlayerIndex = ENTINDEX( pPlayer ); + + // Player died? + if ( !UTIL_IsAlive( pPlayer ) ) + { + edict_t *pAttacker = pPlayer->v.dmg_inflictor; + char szMessage[129]; // To allow exactly 128 characters + + // Attacker is NULL or message already shown, don't care + if ( pAttacker == NULL || g_PlayerKilled[ iPlayerIndex ] ) + return; + + // Get player's name + char szPlayerName[33]; + sprintf( szPlayerName, "%s", STRING( pPlayer->v.netname ) ); + + // Killed by a monster? + if ( pAttacker->v.flags & FL_MONSTER ) + { + // Check the first character for 'aeiou'. + CMBaseMonster *pMonster = GetClassPtr((CMBaseMonster *)VARS(pAttacker)); + char szCheck[2]; + strncpy( szCheck, STRING( pMonster->m_szMonsterName ), 1 ); + + // Make the first character lowercase + szCheck[0] = tolower( szCheck[ 0 ] ); + if ( strncmp( szCheck, "a", 1 ) == 0 || strncmp( szCheck, "e", 1 ) == 0 || strncmp( szCheck, "i", 1 ) == 0 || strncmp( szCheck, "o", 1 ) == 0 || strncmp( szCheck, "u", 1 ) == 0 ) + sprintf( szMessage, "* %s was killed by an %s.\n", szPlayerName, STRING( pMonster->m_szMonsterName ) ); + else + sprintf( szMessage, "* %s was killed by a %s.\n", szPlayerName, STRING( pMonster->m_szMonsterName ) ); + } + else + { + // Any messages from here should only be shown if allowed. + // Level 0 = Disabled + // Level 1 = All messages + // Level 2 = Only monster deaths + if (monster_show_deaths->value == 1) + { + // Suicide? + if ( pAttacker == pPlayer ) + sprintf( szMessage, "* %s commited suicide.\n", szPlayerName ); + // An entity killed this player. + else if ( ENTINDEX( pAttacker ) > 0 ) + { + // Gather damage type and format death message + if ( g_DamageBits[ iPlayerIndex ] == DMG_GENERIC ) + sprintf( szMessage, "* %s died mysteriously.\n", szPlayerName ); + else if ( g_DamageBits[ iPlayerIndex ] & DMG_CRUSH ) + sprintf( szMessage, "* %s was smashed.\n", szPlayerName ); + else if ( g_DamageBits[ iPlayerIndex ] & DMG_BULLET ) + sprintf( szMessage, "* %s was shot.\n", szPlayerName ); + else if ( g_DamageBits[ iPlayerIndex ] & DMG_SLASH ) + sprintf( szMessage, "* %s lost it's jelly.\n", szPlayerName ); + else if ( g_DamageBits[ iPlayerIndex ] & DMG_BURN ) + sprintf( szMessage, "* %s burned to death.\n", szPlayerName ); + else if ( g_DamageBits[ iPlayerIndex ] & DMG_FREEZE ) + sprintf( szMessage, "* %s froze to death.\n", szPlayerName ); + else if ( g_DamageBits[ iPlayerIndex ] & DMG_FALL ) + sprintf( szMessage, "* %s broke it's bones.\n", szPlayerName ); + else if ( g_DamageBits[ iPlayerIndex ] & DMG_BLAST ) + sprintf( szMessage, "* %s blew up.\n", szPlayerName ); + else if ( g_DamageBits[ iPlayerIndex ] & DMG_CLUB ) + sprintf( szMessage, "* %s was crowbared.\n", szPlayerName ); + else if ( g_DamageBits[ iPlayerIndex ] & DMG_SHOCK ) + sprintf( szMessage, "* %s was electrocuted.\n", szPlayerName ); + else if ( g_DamageBits[ iPlayerIndex ] & DMG_SONIC ) + sprintf( szMessage, "* %s ears popped.\n", szPlayerName ); + else if ( g_DamageBits[ iPlayerIndex ] & DMG_ENERGYBEAM ) + sprintf( szMessage, "* %s saw the pretty lights.\n", szPlayerName ); + else if ( g_DamageBits[ iPlayerIndex ] == DMG_NEVERGIB ) + sprintf( szMessage, "* %s had a painful death.\n", szPlayerName ); + else if ( g_DamageBits[ iPlayerIndex ] == DMG_ALWAYSGIB ) + sprintf( szMessage, "* %s was gibbed.\n", szPlayerName ); + else if ( g_DamageBits[ iPlayerIndex ] & DMG_DROWN ) + sprintf( szMessage, "* %s became too drunk.\n", szPlayerName ); + else if ( g_DamageBits[ iPlayerIndex ] & DMG_PARALYZE ) + sprintf( szMessage, "* %s was paralyzed.\n", szPlayerName ); + else if ( g_DamageBits[ iPlayerIndex ] & DMG_NERVEGAS ) + sprintf( szMessage, "* %s lost it's brain.\n", szPlayerName ); + else if ( g_DamageBits[ iPlayerIndex ] & DMG_POISON ) + sprintf( szMessage, "* %s had a slow death.\n", szPlayerName ); + else if ( g_DamageBits[ iPlayerIndex ] & DMG_RADIATION ) + sprintf( szMessage, "* %s went nuclear.\n", szPlayerName ); + else if ( g_DamageBits[ iPlayerIndex ] & DMG_DROWNRECOVER ) + sprintf( szMessage, "* %s used too much flex tape.\n", szPlayerName ); // is this type of death even possible? + else if ( g_DamageBits[ iPlayerIndex ] & DMG_ACID ) + sprintf( szMessage, "* %s was melted.\n", szPlayerName ); + else if ( g_DamageBits[ iPlayerIndex ] & DMG_SLOWBURN ) + sprintf( szMessage, "* %s became a cake.\n", szPlayerName ); + else if ( g_DamageBits[ iPlayerIndex ] & DMG_SLOWFREEZE ) + sprintf( szMessage, "* %s died of hypothermia.\n", szPlayerName ); + else if ( g_DamageBits[ iPlayerIndex ] & DMG_MORTAR ) + sprintf( szMessage, "* %s blew his missile pet.\n", szPlayerName ); + else if ( g_DamageBits[ iPlayerIndex ] == (1 << 30) ) // (1 << 30) = 1073741824. For custom death messages + sprintf( szMessage, "* %s %s.\n", szPlayerName, STRING( pAttacker->v.noise ) ); + else // other mods could have more DMG_ variants that aren't registered here. + sprintf( szMessage, "* %s deadly died.\n", szPlayerName ); + } + // the "world" killed this player + else + sprintf( szMessage, "* %s fell or drowned or something.\n", szPlayerName ); + } + } + + // Print the message + if ( strlen( szMessage ) > 0 ) + UTIL_ClientPrintAll( HUD_PRINTTALK, szMessage ); + g_PlayerKilled[ iPlayerIndex ] = true; + } + else + g_PlayerKilled[ iPlayerIndex ] = false; +} + +void check_monster_info( edict_t *pPlayer ) +{ + // Monster Info is disabled + if (!monster_show_info->value) + return; + + // Player must be alive + if ( UTIL_IsAlive( pPlayer ) ) + { + // Don't overdo it! + if ( g_NextMessage[ ENTINDEX( pPlayer ) ] > gpGlobals->time ) + return; + + // Get player position and view angle + Vector origin = pPlayer->v.origin; + Vector view_angle = pPlayer->v.v_angle; + Vector view_offset = pPlayer->v.view_ofs; + + // Prepare Trace + TraceResult tr; + Vector v_src, v_dest; + + UTIL_MakeVectors(view_angle); + + v_src = origin + view_offset; // Player aiment + v_dest = v_src + gpGlobals->v_forward * 4096; // Should cover enough distance + + UTIL_TraceLine(v_src, v_dest, dont_ignore_monsters, pPlayer, &tr); + + // Hit an entity? + if (tr.pHit != NULL) + { + // Must be a monster + if (tr.pHit->v.flags & FL_MONSTER) + { + // Get monster info + CMBaseMonster *pMonster = GetClassPtr((CMBaseMonster *)VARS(tr.pHit)); + + char szInfo[512]; + sprintf(szInfo, "Enemy: %s\nHealth: %.0f\nFrags: %.0f\n", STRING( pMonster->m_szMonsterName ), pMonster->pev->health, pMonster->pev->frags ); + + // Create a TE_TEXTMESSAGE and show the monster information + MESSAGE_BEGIN( MSG_ONE, SVC_TEMPENTITY, NULL, pPlayer ); + WRITE_BYTE( TE_TEXTMESSAGE ); + WRITE_BYTE( 3 ); // Channel + WRITE_SHORT( 327 ); // X + WRITE_SHORT( 4771 ); // Y + WRITE_BYTE( 0 ); // Effect + WRITE_BYTE( 171 ); // R1 + WRITE_BYTE( 23 ); // G1 + WRITE_BYTE( 7 ); // B1 + WRITE_BYTE( 0 ); // A1 + WRITE_BYTE( 207 ); // R2 + WRITE_BYTE( 23 ); // G2 + WRITE_BYTE( 7 ); // B2 + WRITE_BYTE( 255 ); // A2 + WRITE_SHORT( 0 ); // Fade-in Time + WRITE_SHORT( 15 ); // Fade-out Time + WRITE_SHORT( 448 ); // Hold time + WRITE_STRING( szInfo ); // Message + MESSAGE_END(); + + // Delay till next scan + g_NextMessage[ ENTINDEX( pPlayer ) ] = gpGlobals->time + 0.875; + } + } + } +} + bool spawn_monster(int monster_type, Vector origin, Vector angles, int respawn_index, int spawnflags, pKVD *keyvalue) { int monster_index; @@ -1032,7 +1240,7 @@ void mmDispatchThink( edict_t *pent ) { monsters[index].pMonster->Think(); - check_monster_dead(); + check_monster_dead(pent); RETURN_META(MRES_SUPERCEDE); } @@ -1054,7 +1262,7 @@ void mmDispatchTouch( edict_t *pentTouched, edict_t *pentOther ) { monsters[index].pMonster->Touch(pentOther); - check_monster_dead(); + check_monster_dead(pentOther); RETURN_META(MRES_SUPERCEDE); } @@ -1174,6 +1382,13 @@ void mmStartFrame( void ) RETURN_META(MRES_IGNORED); } +void mmClientKill( edict_t *pPlayer ) +{ + // Just to let the system know the player commited suicide + pPlayer->v.dmg_inflictor = pPlayer; + RETURN_META(MRES_IGNORED); +} + static DLL_FUNCTIONS gFunctionTable = { mmGameDLLInit, //! pfnGameInit() Initialize the game (one-time call after loading of game .dll) @@ -1196,7 +1411,7 @@ static DLL_FUNCTIONS gFunctionTable = NULL, // pfnClientConnect NULL, // pfnClientDisconnect - NULL, // pfnClientKill + mmClientKill, //! pfnClientKill NULL, // pfnClientPutInServer NULL, // pfnClientCommand NULL, // pfnClientUserInfoChanged @@ -1259,18 +1474,18 @@ C_DLLEXPORT int GetEntityAPI2( DLL_FUNCTIONS *pFunctionTable, int *interfaceVers void mmDispatchThink_Post( edict_t *pent ) { check_monster_hurt(pent); - check_monster_dead(); - - + check_monster_dead(pent); + RETURN_META(MRES_IGNORED); } void mmPlayerPostThink_Post( edict_t *pEntity ) { check_monster_hurt(pEntity); - check_monster_dead(); - - + check_monster_dead(pEntity); + check_player_dead(pEntity); + check_monster_info(pEntity); + RETURN_META(MRES_IGNORED); } @@ -1353,3 +1568,534 @@ C_DLLEXPORT int GetEntityAPI2_Post( DLL_FUNCTIONS *pFunctionTable, int *interfac memcpy( pFunctionTable, &gFunctionTable_Post, sizeof( DLL_FUNCTIONS ) ); return(TRUE); } + + +// Some messages seems to be offset by 1. Linux specific? CStrike specific? +int IsCSServer( void ) +{ + char mod[16]; + sprintf( mod, "%s", GET_GAME_INFO( PLID, GINFO_NAME ) ); + + if ( strcmp( mod, "cstrike" ) == 0 || strcmp( mod, "czero" ) == 0 ) + return 1; + + return 0; +} + +int mmRegUserMsg_Post( const char *pName, int iSize ) +{ + int cs_server = IsCSServer(); + + if ( strcmp( pName, "Damage" ) == 0 ) + g_DamageMsg = META_RESULT_ORIG_RET( int ) - cs_server; + else if ( strcmp( pName, "DeathMsg" ) == 0 ) + g_DeathMsg = META_RESULT_ORIG_RET( int );// - cs_server; + + RETURN_META_VALUE( MRES_IGNORED, 0 ); +} + +void mmMessageBegin_Post( int msg_dest, int msg_type, const float *pOrigin, edict_t *ed ) +{ + if ( msg_type == g_DamageMsg ) + { + // Whatever hurting us must be a valid entity + if (ed->v.dmg_inflictor != NULL ) + { + g_DamageActive = true; + g_DamageVictim = ENTINDEX( ed ); + g_DamageAttacker[ g_DamageVictim ] = ed->v.dmg_inflictor; + } + } + else if ( msg_type == g_DeathMsg ) + { + // Prepare to update deathmsg + g_DeathActive = true; + } + + RETURN_META( MRES_IGNORED ); +} + +void mmWriteLong_Post( int iValue ) +{ + if ( g_DamageActive ) + g_DamageBits[ g_DamageVictim ] = iValue; + + RETURN_META( MRES_IGNORED ); +} + +// This cannot be done on post! +void mmWriteString( const char *szValue ) +{ + if ( g_DeathActive ) + { + // Prevent recursion + g_DeathActive = false; + + // Ensure whatever killed the player is a valid entity + if (g_DamageAttacker[ g_DamageVictim ] != NULL) + { + // Send a new WriteString with the killer's classname + WRITE_STRING( STRING( g_DamageAttacker[ g_DamageVictim ]->v.classname ) ); + + // Supercede the old message + RETURN_META( MRES_SUPERCEDE ); + } + } + + RETURN_META( MRES_IGNORED ); +} + +void mmMessageEnd_Post( void ) +{ + g_DamageActive = false; + + RETURN_META( MRES_IGNORED ); +} + +enginefuncs_t meta_engfuncs = +{ + NULL, // pfnPrecacheModel() + NULL, // pfnPrecacheSound() + NULL, // pfnSetModel() + NULL, // pfnModelIndex() + NULL, // pfnModelFrames() + + NULL, // pfnSetSize() + NULL, // pfnChangeLevel() + NULL, // pfnGetSpawnParms() + NULL, // pfnSaveSpawnParms() + + NULL, // pfnVecToYaw() + NULL, // pfnVecToAngles() + NULL, // pfnMoveToOrigin() + NULL, // pfnChangeYaw() + NULL, // pfnChangePitch() + + NULL, // pfnFindEntityByString() + NULL, // pfnGetEntityIllum() + NULL, // pfnFindEntityInSphere() + NULL, // pfnFindClientInPVS() + NULL, // pfnEntitiesInPVS() + + NULL, // pfnMakeVectors() + NULL, // pfnAngleVectors() + + NULL, // pfnCreateEntity() + NULL, // pfnRemoveEntity() + NULL, // pfnCreateNamedEntity() + + NULL, // pfnMakeStatic() + NULL, // pfnEntIsOnFloor() + NULL, // pfnDropToFloor() + + NULL, // pfnWalkMove() + NULL, // pfnSetOrigin() + + NULL, // pfnEmitSound() + NULL, // pfnEmitAmbientSound() + + NULL, // pfnTraceLine() + NULL, // pfnTraceToss() + NULL, // pfnTraceMonsterHull() + NULL, // pfnTraceHull() + NULL, // pfnTraceModel() + NULL, // pfnTraceTexture() + NULL, // pfnTraceSphere() + NULL, // pfnGetAimVector() + + NULL, // pfnServerCommand() + NULL, // pfnServerExecute() + NULL, // pfnClientCommand() + + NULL, // pfnParticleEffect() + NULL, // pfnLightStyle() + NULL, // pfnDecalIndex() + NULL, // pfnPointContents() + + NULL, // pfnMessageBegin() + NULL, // pfnMessageEnd() + + NULL, // pfnWriteByte() + NULL, // pfnWriteChar() + NULL, // pfnWriteShort() + NULL, // pfnWriteLong() + NULL, // pfnWriteAngle() + NULL, // pfnWriteCoord() + mmWriteString, //! pfnWriteString() + NULL, // pfnWriteEntity() + + NULL, // pfnCVarRegister() + NULL, // pfnCVarGetFloat() + NULL, // pfnCVarGetString() + NULL, // pfnCVarSetFloat() + NULL, // pfnCVarSetString() + + NULL, // pfnAlertMessage() + NULL, // pfnEngineFprintf() + + NULL, // pfnPvAllocEntPrivateData() + NULL, // pfnPvEntPrivateData() + NULL, // pfnFreeEntPrivateData() + + NULL, // pfnSzFromIndex() + NULL, // pfnAllocString() + + NULL, // pfnGetVarsOfEnt() + NULL, // pfnPEntityOfEntOffset() + NULL, // pfnEntOffsetOfPEntity() + NULL, // pfnIndexOfEdict() + NULL, // pfnPEntityOfEntIndex() + NULL, // pfnFindEntityByVars() + NULL, // pfnGetModelPtr() + + NULL, // pfnRegUserMsg() + + NULL, // pfnAnimationAutomove() + NULL, // pfnGetBonePosition() + + NULL, // pfnFunctionFromName() + NULL, // pfnNameForFunction() + + NULL, // pfnClientPrintf() + NULL, // pfnServerPrint() + + NULL, // pfnCmd_Args() + NULL, // pfnCmd_Argv() + NULL, // pfnCmd_Argc() + + NULL, // pfnGetAttachment() + + NULL, // pfnCRC32_Init() + NULL, // pfnCRC32_ProcessBuffer() + NULL, // pfnCRC32_ProcessByte() + NULL, // pfnCRC32_Final() + + NULL, // pfnRandomLong() + NULL, // pfnRandomFloat() + + NULL, // pfnSetView() + NULL, // pfnTime() + NULL, // pfnCrosshairAngle() + + NULL, // pfnLoadFileForMe() + NULL, // pfnFreeFile() + + NULL, // pfnEndSection() + NULL, // pfnCompareFileTime() + NULL, // pfnGetGameDir() + NULL, // pfnCvar_RegisterVariable() + NULL, // pfnFadeClientVolume() + NULL, // pfnSetClientMaxspeed() + NULL, // pfnCreateFakeClient() + NULL, // pfnRunPlayerMove() + NULL, // pfnNumberOfEntities() + + NULL, // pfnGetInfoKeyBuffer() + NULL, // pfnInfoKeyValue() + NULL, // pfnSetKeyValue() + NULL, // pfnSetClientKeyValue() + + NULL, // pfnIsMapValid() + NULL, // pfnStaticDecal() + NULL, // pfnPrecacheGeneric() + NULL, // pfnGetPlayerUserId() + NULL, // pfnBuildSoundMsg() + NULL, // pfnIsDedicatedServer() + NULL, // pfnCVarGetPointer() + NULL, // pfnGetPlayerWONId() + + NULL, // pfnInfo_RemoveKey() + NULL, // pfnGetPhysicsKeyValue() + NULL, // pfnSetPhysicsKeyValue() + NULL, // pfnGetPhysicsInfoString() + NULL, // pfnPrecacheEvent() + NULL, // pfnPlaybackEvent() + + NULL, // pfnSetFatPVS() + NULL, // pfnSetFatPAS() + + NULL, // pfnCheckVisibility() + + NULL, // pfnDeltaSetField() + NULL, // pfnDeltaUnsetField() + NULL, // pfnDeltaAddEncoder() + NULL, // pfnGetCurrentPlayer() + NULL, // pfnCanSkipPlayer() + NULL, // pfnDeltaFindField() + NULL, // pfnDeltaSetFieldByIndex() + NULL, // pfnDeltaUnsetFieldByIndex() + + NULL, // pfnSetGroupMask() + + NULL, // pfnCreateInstancedBaseline() + NULL, // pfnCvar_DirectSet() + + NULL, // pfnForceUnmodified() + + NULL, // pfnGetPlayerStats() + + NULL, // pfnAddServerCommand() + + NULL, // pfnVoice_GetClientListening() + NULL, // pfnVoice_SetClientListening() + + NULL, // pfnGetPlayerAuthId() + + NULL, // pfnSequenceGet() + NULL, // pfnSequencePickSentence() + NULL, // pfnGetFileSize() + NULL, // pfnGetApproxWavePlayLen() + NULL, // pfnIsCareerMatch() + NULL, // pfnGetLocalizedStringLength() + NULL, // pfnRegisterTutorMessageShown() + NULL, // pfnGetTimesTutorMessageShown() + NULL, // pfnProcessTutorMessageDecayBuffer() + NULL, // pfnConstructTutorMessageDecayBuffer() + NULL, // pfnResetTutorMessageDecayData() + NULL, // pfnQueryClientCvarValue() + NULL, // pfnQueryClientCvarValue2() + NULL, // pfnEngCheckParm() +}; + +C_DLLEXPORT int GetEngineFunctions(enginefuncs_t *pengfuncsFromEngine, int *interfaceVersion) +{ + if(!pengfuncsFromEngine) + { + LOG_ERROR(PLID, "GetEngineFunctions called with null pengfuncsFromEngine"); + return(FALSE); + } + else if(*interfaceVersion != ENGINE_INTERFACE_VERSION) + { + LOG_ERROR(PLID, "GetEngineFunctions version mismatch; requested=%d ours=%d", *interfaceVersion, ENGINE_INTERFACE_VERSION); + // Tell metamod what version we had, so it can figure out who is + // out of date. + *interfaceVersion = ENGINE_INTERFACE_VERSION; + return(FALSE); + } + memcpy(pengfuncsFromEngine, &meta_engfuncs, sizeof(enginefuncs_t)); + return TRUE; +} + +enginefuncs_t meta_engfuncs_post = +{ + NULL, // pfnPrecacheModel() + NULL, // pfnPrecacheSound() + NULL, // pfnSetModel() + NULL, // pfnModelIndex() + NULL, // pfnModelFrames() + + NULL, // pfnSetSize() + NULL, // pfnChangeLevel() + NULL, // pfnGetSpawnParms() + NULL, // pfnSaveSpawnParms() + + NULL, // pfnVecToYaw() + NULL, // pfnVecToAngles() + NULL, // pfnMoveToOrigin() + NULL, // pfnChangeYaw() + NULL, // pfnChangePitch() + + NULL, // pfnFindEntityByString() + NULL, // pfnGetEntityIllum() + NULL, // pfnFindEntityInSphere() + NULL, // pfnFindClientInPVS() + NULL, // pfnEntitiesInPVS() + + NULL, // pfnMakeVectors() + NULL, // pfnAngleVectors() + + NULL, // pfnCreateEntity() + NULL, // pfnRemoveEntity() + NULL, // pfnCreateNamedEntity() + + NULL, // pfnMakeStatic() + NULL, // pfnEntIsOnFloor() + NULL, // pfnDropToFloor() + + NULL, // pfnWalkMove() + NULL, // pfnSetOrigin() + + NULL, // pfnEmitSound() + NULL, // pfnEmitAmbientSound() + + NULL, // pfnTraceLine() + NULL, // pfnTraceToss() + NULL, // pfnTraceMonsterHull() + NULL, // pfnTraceHull() + NULL, // pfnTraceModel() + NULL, // pfnTraceTexture() + NULL, // pfnTraceSphere() + NULL, // pfnGetAimVector() + + NULL, // pfnServerCommand() + NULL, // pfnServerExecute() + NULL, // pfnClientCommand() + + NULL, // pfnParticleEffect() + NULL, // pfnLightStyle() + NULL, // pfnDecalIndex() + NULL, // pfnPointContents() + + mmMessageBegin_Post, //! pfnMessageBegin() + mmMessageEnd_Post, //! pfnMessageEnd() + + NULL, // pfnWriteByte() + NULL, // pfnWriteChar() + NULL, // pfnWriteShort() + mmWriteLong_Post, //! pfnWriteLong() + NULL, // pfnWriteAngle() + NULL, // pfnWriteCoord() + NULL, // pfnWriteString() + NULL, // pfnWriteEntity() + + NULL, // pfnCVarRegister() + NULL, // pfnCVarGetFloat() + NULL, // pfnCVarGetString() + NULL, // pfnCVarSetFloat() + NULL, // pfnCVarSetString() + + NULL, // pfnAlertMessage() + NULL, // pfnEngineFprintf() + + NULL, // pfnPvAllocEntPrivateData() + NULL, // pfnPvEntPrivateData() + NULL, // pfnFreeEntPrivateData() + + NULL, // pfnSzFromIndex() + NULL, // pfnAllocString() + + NULL, // pfnGetVarsOfEnt() + NULL, // pfnPEntityOfEntOffset() + NULL, // pfnEntOffsetOfPEntity() + NULL, // pfnIndexOfEdict() + NULL, // pfnPEntityOfEntIndex() + NULL, // pfnFindEntityByVars() + NULL, // pfnGetModelPtr() + + mmRegUserMsg_Post, //! pfnRegUserMsg() + + NULL, // pfnAnimationAutomove() + NULL, // pfnGetBonePosition() + + NULL, // pfnFunctionFromName() + NULL, // pfnNameForFunction() + + NULL, // pfnClientPrintf() + NULL, // pfnServerPrint() + + NULL, // pfnCmd_Args() + NULL, // pfnCmd_Argv() + NULL, // pfnCmd_Argc() + + NULL, // pfnGetAttachment() + + NULL, // pfnCRC32_Init() + NULL, // pfnCRC32_ProcessBuffer() + NULL, // pfnCRC32_ProcessByte() + NULL, // pfnCRC32_Final() + + NULL, // pfnRandomLong() + NULL, // pfnRandomFloat() + + NULL, // pfnSetView() + NULL, // pfnTime() + NULL, // pfnCrosshairAngle() + + NULL, // pfnLoadFileForMe() + NULL, // pfnFreeFile() + + NULL, // pfnEndSection() + NULL, // pfnCompareFileTime() + NULL, // pfnGetGameDir() + NULL, // pfnCvar_RegisterVariable() + NULL, // pfnFadeClientVolume() + NULL, // pfnSetClientMaxspeed() + NULL, // pfnCreateFakeClient() + NULL, // pfnRunPlayerMove() + NULL, // pfnNumberOfEntities() + + NULL, // pfnGetInfoKeyBuffer() + NULL, // pfnInfoKeyValue() + NULL, // pfnSetKeyValue() + NULL, // pfnSetClientKeyValue() + + NULL, // pfnIsMapValid() + NULL, // pfnStaticDecal() + NULL, // pfnPrecacheGeneric() + NULL, // pfnGetPlayerUserId() + NULL, // pfnBuildSoundMsg() + NULL, // pfnIsDedicatedServer() + NULL, // pfnCVarGetPointer() + NULL, // pfnGetPlayerWONId() + + NULL, // pfnInfo_RemoveKey() + NULL, // pfnGetPhysicsKeyValue() + NULL, // pfnSetPhysicsKeyValue() + NULL, // pfnGetPhysicsInfoString() + NULL, // pfnPrecacheEvent() + NULL, // pfnPlaybackEvent() + + NULL, // pfnSetFatPVS() + NULL, // pfnSetFatPAS() + + NULL, // pfnCheckVisibility() + + NULL, // pfnDeltaSetField() + NULL, // pfnDeltaUnsetField() + NULL, // pfnDeltaAddEncoder() + NULL, // pfnGetCurrentPlayer() + NULL, // pfnCanSkipPlayer() + NULL, // pfnDeltaFindField() + NULL, // pfnDeltaSetFieldByIndex() + NULL, // pfnDeltaUnsetFieldByIndex() + + NULL, // pfnSetGroupMask() + + NULL, // pfnCreateInstancedBaseline() + NULL, // pfnCvar_DirectSet() + + NULL, // pfnForceUnmodified() + + NULL, // pfnGetPlayerStats() + + NULL, // pfnAddServerCommand() + + NULL, // pfnVoice_GetClientListening() + NULL, // pfnVoice_SetClientListening() + + NULL, // pfnGetPlayerAuthId() + + NULL, // pfnSequenceGet() + NULL, // pfnSequencePickSentence() + NULL, // pfnGetFileSize() + NULL, // pfnGetApproxWavePlayLen() + NULL, // pfnIsCareerMatch() + NULL, // pfnGetLocalizedStringLength() + NULL, // pfnRegisterTutorMessageShown() + NULL, // pfnGetTimesTutorMessageShown() + NULL, // pfnProcessTutorMessageDecayBuffer() + NULL, // pfnConstructTutorMessageDecayBuffer() + NULL, // pfnResetTutorMessageDecayData() + NULL, // pfnQueryClientCvarValue() + NULL, // pfnQueryClientCvarValue2() + NULL, // pfnEngCheckParm() +}; + +C_DLLEXPORT int GetEngineFunctions_Post(enginefuncs_t *pengfuncsFromEngine, int *interfaceVersion) +{ + if(!pengfuncsFromEngine) + { + LOG_ERROR(PLID, "GetEngineFunctions_Post called with null pengfuncsFromEngine"); + return(FALSE); + } + else if(*interfaceVersion != ENGINE_INTERFACE_VERSION) + { + LOG_ERROR(PLID, "GetEngineFunctions_Post version mismatch; requested=%d ours=%d", *interfaceVersion, ENGINE_INTERFACE_VERSION); + // Tell metamod what version we had, so it can figure out who is + // out of date. + *interfaceVersion = ENGINE_INTERFACE_VERSION; + return(FALSE); + } + memcpy(pengfuncsFromEngine, &meta_engfuncs_post, sizeof(enginefuncs_t)); + return TRUE; +} diff --git a/src/dlls/gargantua.cpp b/src/dlls/gargantua.cpp index f14a59f..0602de5 100755 --- a/src/dlls/gargantua.cpp +++ b/src/dlls/gargantua.cpp @@ -624,6 +624,11 @@ void CMGargantua :: PrescheduleThink( void ) //========================================================= int CMGargantua :: Classify ( void ) { + if ( m_iClassifyOverride == -1 ) // helper + return CLASS_NONE; + else if ( m_iClassifyOverride > 0 ) + return m_iClassifyOverride; // override + return CLASS_ALIEN_MONSTER; } @@ -684,6 +689,13 @@ void CMGargantua :: Spawn() EyeOff(); m_seeTime = gpGlobals->time + 5; m_flameTime = gpGlobals->time + 2; + + pev->classname = MAKE_STRING( "monster_gargantua" ); + if ( strlen( STRING( m_szMonsterName ) ) == 0 ) + { + // default name + m_szMonsterName = MAKE_STRING( "Gargantua" ); + } } diff --git a/src/dlls/hassassin.cpp b/src/dlls/hassassin.cpp index 630d59d..91de38f 100644 --- a/src/dlls/hassassin.cpp +++ b/src/dlls/hassassin.cpp @@ -88,6 +88,11 @@ int CMHAssassin :: ISoundMask ( void) //========================================================= int CMHAssassin :: Classify ( void ) { + if ( m_iClassifyOverride == -1 ) // helper + return CLASS_NONE; + else if ( m_iClassifyOverride > 0 ) + return m_iClassifyOverride; // override + return CLASS_HUMAN_MILITARY; } @@ -228,8 +233,15 @@ void CMHAssassin :: Spawn() m_iTargetRanderamt = 20; pev->renderamt = 20; pev->rendermode = kRenderTransTexture; - + MonsterInit(); + + pev->classname = MAKE_STRING( "monster_human_assassin" ); + if ( strlen( STRING( m_szMonsterName ) ) == 0 ) + { + // default name + m_szMonsterName = MAKE_STRING( "Female Assassin" ); + } } //========================================================= @@ -906,4 +918,4 @@ Schedule_t* CMHAssassin :: GetScheduleOfType ( int Type ) return CMBaseMonster :: GetScheduleOfType( Type ); } -#endif \ No newline at end of file +#endif diff --git a/src/dlls/headcrab.cpp b/src/dlls/headcrab.cpp index 8df3507..5d283e5 100644 --- a/src/dlls/headcrab.cpp +++ b/src/dlls/headcrab.cpp @@ -119,6 +119,11 @@ const char *CMHeadCrab::pBiteSounds[] = //========================================================= int CMHeadCrab :: Classify ( void ) { + if ( m_iClassifyOverride == -1 ) // helper + return CLASS_NONE; + else if ( m_iClassifyOverride > 0 ) + return m_iClassifyOverride; // override + return CLASS_ALIEN_PREY; } @@ -256,6 +261,13 @@ void CMHeadCrab :: Spawn() m_MonsterState = MONSTERSTATE_NONE; MonsterInit(); + + pev->classname = MAKE_STRING( "monster_headcrab" ); + if ( strlen( STRING( m_szMonsterName ) ) == 0 ) + { + // default name + m_szMonsterName = MAKE_STRING( "Head Crab" ); + } } //========================================================= diff --git a/src/dlls/hgrunt.cpp b/src/dlls/hgrunt.cpp index c860d90..687d061 100644 --- a/src/dlls/hgrunt.cpp +++ b/src/dlls/hgrunt.cpp @@ -174,12 +174,15 @@ void CMHGrunt :: SpeakSentence( void ) //========================================================= int CMHGrunt::IRelationship ( CMBaseEntity *pTarget ) { - if (( strcmp(STRING(pTarget->pev->model), "models/agrunt.mdl") == 0 ) || + // on single player, forcing R_NM makes sense. + // on multiplayer, a custom classification will cause misbehaviour. + /* + if (( strcmp(STRING(pTarget->pev->model), "models/agrunt.mdl") == 0 ) || ( strcmp(STRING(pTarget->pev->model), "models/garg.mdl") == 0 )) { return R_NM; } - + */ return CMBaseMonster::IRelationship( pTarget ); } @@ -596,6 +599,11 @@ void CMHGrunt :: CheckAmmo ( void ) //========================================================= int CMHGrunt :: Classify ( void ) { + if ( m_iClassifyOverride == -1 ) // helper + return CLASS_NONE; + else if ( m_iClassifyOverride > 0 ) + return m_iClassifyOverride; // override + return CLASS_HUMAN_MILITARY; } @@ -886,6 +894,13 @@ void CMHGrunt :: Spawn() CMTalkMonster::g_talkWaitTime = 0; MonsterInit(); + + pev->classname = MAKE_STRING( "monster_human_grunt" ); + if ( strlen( STRING( m_szMonsterName ) ) == 0 ) + { + // default name + m_szMonsterName = MAKE_STRING( "Human Grunt" ); + } } //========================================================= diff --git a/src/dlls/hornet.cpp b/src/dlls/hornet.cpp index bbcc97d..960e4f5 100644 --- a/src/dlls/hornet.cpp +++ b/src/dlls/hornet.cpp @@ -49,7 +49,7 @@ void CMHornet :: Spawn( void ) pev->movetype = MOVETYPE_FLY; pev->solid = SOLID_BBOX; pev->takedamage = DAMAGE_YES; - pev->flags |= FL_MONSTER; + pev->flags |= FL_MONSTER; // I have a bad feeling about this pev->health = 1;// weak! // hornets don't live as long in multiplayer @@ -83,6 +83,8 @@ void CMHornet :: Spawn( void ) pev->nextthink = gpGlobals->time + 0.1; ResetSequenceInfo( ); + + pev->classname = MAKE_STRING( "hornet" ); } @@ -124,13 +126,23 @@ int CMHornet::IRelationship ( CMBaseEntity *pTarget ) //========================================================= int CMHornet::Classify ( void ) { - + /* if ( pev->owner && pev->owner->v.flags & FL_CLIENT) { return CLASS_PLAYER_BIOWEAPON; } return CLASS_ALIEN_BIOWEAPON; + */ + + // Ensure classify is consistent with the owner, in the event + // it's classification was overriden. + if ( pev->owner == NULL ) + return CLASS_ALIEN_BIOWEAPON; + + // Ain't this going to make the hornets code "slow"? + CMBaseMonster *pOwner = GetClassPtr((CMBaseMonster *)VARS(pev->owner)); + return pOwner->Classify(); } //========================================================= diff --git a/src/dlls/houndeye.cpp b/src/dlls/houndeye.cpp index ca27db1..5f1c4aa 100644 --- a/src/dlls/houndeye.cpp +++ b/src/dlls/houndeye.cpp @@ -78,6 +78,11 @@ enum //========================================================= int CMHoundeye :: Classify ( void ) { + if ( m_iClassifyOverride == -1 ) // helper + return CLASS_NONE; + else if ( m_iClassifyOverride > 0 ) + return m_iClassifyOverride; // override + return CLASS_ALIEN_MONSTER; } @@ -277,6 +282,13 @@ void CMHoundeye :: Spawn() m_fDontBlink = FALSE; MonsterInit(); + + pev->classname = MAKE_STRING( "monster_houndeye" ); + if ( strlen( STRING( m_szMonsterName ) ) == 0 ) + { + // default name + m_szMonsterName = MAKE_STRING( "Houndeye" ); + } } //========================================================= diff --git a/src/dlls/islave.cpp b/src/dlls/islave.cpp index 1970110..baad32b 100644 --- a/src/dlls/islave.cpp +++ b/src/dlls/islave.cpp @@ -67,6 +67,11 @@ const char *CMISlave::pDeathSounds[] = //========================================================= int CMISlave :: Classify ( void ) { + if ( m_iClassifyOverride == -1 ) // helper + return CLASS_NONE; + else if ( m_iClassifyOverride > 0 ) + return m_iClassifyOverride; // override + return CLASS_ALIEN_MILITARY; } @@ -429,10 +434,16 @@ void CMISlave :: Spawn() for (int i = 0; i < ISLAVE_MAX_BEAMS; i++) m_pBeam[i] = NULL; - m_iBravery = 0; - m_flNextAttack = 0.0f; + m_iBravery = 0; + m_flNextAttack = 0.0f; MonsterInit(); + pev->classname = MAKE_STRING( "monster_alien_slave" ); + if ( strlen( STRING( m_szMonsterName ) ) == 0 ) + { + // default name + m_szMonsterName = MAKE_STRING( "Alien Slave" ); + } } //========================================================= diff --git a/src/dlls/monster_api.cpp b/src/dlls/monster_api.cpp index 66f7514..1177bc0 100644 --- a/src/dlls/monster_api.cpp +++ b/src/dlls/monster_api.cpp @@ -40,23 +40,24 @@ #include "sdk_util.h" // UTIL_LogPrintf, etc // Must provide at least one of these.. -static META_FUNCTIONS gMetaFunctionTable = { - NULL, // pfnGetEntityAPI HL SDK; called before game DLL - NULL, // pfnGetEntityAPI_Post META; called after game DLL - GetEntityAPI2, // pfnGetEntityAPI2 HL SDK2; called before game DLL - GetEntityAPI2_Post, // pfnGetEntityAPI2_Post META; called after game DLL - NULL, // pfnGetNewDLLFunctions HL SDK2; called before game DLL - NULL, // pfnGetNewDLLFunctions_Post META; called after game DLL - NULL, // pfnGetEngineFunctions META; called before HL engine - NULL, // pfnGetEngineFunctions_Post META; called after HL engine +static META_FUNCTIONS gMetaFunctionTable = +{ + NULL, // pfnGetEntityAPI HL SDK; called before game DLL + NULL, // pfnGetEntityAPI_Post META; called after game DLL + GetEntityAPI2, // pfnGetEntityAPI2 HL SDK2; called before game DLL + GetEntityAPI2_Post, // pfnGetEntityAPI2_Post META; called after game DLL + NULL, // pfnGetNewDLLFunctions HL SDK2; called before game DLL + NULL, // pfnGetNewDLLFunctions_Post META; called after game DLL + GetEngineFunctions, // pfnGetEngineFunctions META; called before HL engine + GetEngineFunctions_Post, // pfnGetEngineFunctions_Post META; called after HL engine }; // Description of plugin plugin_info_t Plugin_info = { META_INTERFACE_VERSION, // interface version "MonsterMod", // name - "1.0", // version - "17/03/2020", // date in DD/MM/YYYY format + "2.0", // version + "03/06/2020", // date in DD/MM/YYYY format "botman, Rick90, Giegue", // original authors + recreation by... "https://github.com/JulianR0/monstermod-redo", // url "MONSTER", // logtag @@ -77,10 +78,15 @@ meta_globals_t *gpMetaGlobals; // metamod globals gamedll_funcs_t *gpGamedllFuncs; // gameDLL function tables mutil_funcs_t *gpMetaUtilFuncs; // metamod utility functions +// CVars cvar_t init_dllapi_log = {"monster_log", "0", FCVAR_EXTDLL, 0, NULL}; cvar_t *dllapi_log = NULL; cvar_t init_monster_spawn = {"monster_spawn", "1", FCVAR_EXTDLL, 0, NULL}; cvar_t *monster_spawn = NULL; +cvar_t init_monster_show_deaths = {"monster_show_deaths", "1", FCVAR_EXTDLL, 0, NULL}; +cvar_t *monster_show_deaths = NULL; +cvar_t init_monster_show_info = {"monster_show_info", "1", FCVAR_EXTDLL, 0, NULL}; +cvar_t *monster_show_info = NULL; // Metamod requesting info about this plugin: @@ -103,37 +109,44 @@ C_DLLEXPORT int Meta_Query(char *ifvers, plugin_info_t **pPlugInfo, // pFunctionTable (requested) table of function tables this plugin catches // pMGlobals (given) global vars from metamod // pGamedllFuncs (given) copy of function tables from game dll -C_DLLEXPORT int Meta_Attach(PLUG_LOADTIME now, META_FUNCTIONS *pFunctionTable, - meta_globals_t *pMGlobals, gamedll_funcs_t *pGamedllFuncs) +C_DLLEXPORT int Meta_Attach(PLUG_LOADTIME now, META_FUNCTIONS *pFunctionTable, meta_globals_t *pMGlobals, gamedll_funcs_t *pGamedllFuncs) { - if(now); // to satisfy gcc -Wunused - if(!pMGlobals) { - LOG_ERROR(PLID, "Meta_Attach called with null pMGlobals"); - return(FALSE); - } - gpMetaGlobals=pMGlobals; - if(!pFunctionTable) { - LOG_ERROR(PLID, "Meta_Attach called with null pFunctionTable"); - return(FALSE); - } - memcpy(pFunctionTable, &gMetaFunctionTable, sizeof(META_FUNCTIONS)); - gpGamedllFuncs=pGamedllFuncs; + if(now); // to satisfy gcc -Wunused + if(!pMGlobals) + { + LOG_ERROR(PLID, "Meta_Attach called with null pMGlobals"); + return(FALSE); + } + gpMetaGlobals=pMGlobals; + if(!pFunctionTable) + { + LOG_ERROR(PLID, "Meta_Attach called with null pFunctionTable"); + return(FALSE); + } + memcpy(pFunctionTable, &gMetaFunctionTable, sizeof(META_FUNCTIONS)); + gpGamedllFuncs=pGamedllFuncs; - LOG_MESSAGE(PLID, "%s %s, %s", VNAME, VVERSION, VDATE); - LOG_MESSAGE(PLID, "by %s", VAUTHOR); - LOG_MESSAGE(PLID, "%s", VURL); - LOG_MESSAGE(PLID, "compiled: %s CDT", COMPILE_TIME); + LOG_MESSAGE(PLID, "%s %s, %s", VNAME, VVERSION, VDATE); + LOG_MESSAGE(PLID, "by %s", VAUTHOR); + LOG_MESSAGE(PLID, "%s", VURL); + LOG_MESSAGE(PLID, "compiled: %s CDT", COMPILE_TIME); - LOG_CONSOLE(PLID, "[%s] %s v%s, %s", VLOGTAG, VNAME, VVERSION, VDATE); - LOG_CONSOLE(PLID, "[%s] by %s", VLOGTAG, VAUTHOR); + LOG_CONSOLE(PLID, "[%s] %s v%s, %s", VLOGTAG, VNAME, VVERSION, VDATE); + LOG_CONSOLE(PLID, "[%s] by %s", VLOGTAG, VAUTHOR); - CVAR_REGISTER(&init_dllapi_log); - dllapi_log = CVAR_GET_POINTER("monster_log"); + CVAR_REGISTER(&init_dllapi_log); + dllapi_log = CVAR_GET_POINTER("monster_log"); - CVAR_REGISTER(&init_monster_spawn); - monster_spawn = CVAR_GET_POINTER("monster_spawn"); - - return(TRUE); + CVAR_REGISTER(&init_monster_spawn); + monster_spawn = CVAR_GET_POINTER("monster_spawn"); + + CVAR_REGISTER(&init_monster_show_deaths); + monster_show_deaths = CVAR_GET_POINTER("monster_show_deaths"); + + CVAR_REGISTER(&init_monster_show_info); + monster_show_info = CVAR_GET_POINTER("monster_show_info"); + + return(TRUE); } diff --git a/src/dlls/monsters.cpp b/src/dlls/monsters.cpp index 8655a6a..84cc378 100644 --- a/src/dlls/monsters.cpp +++ b/src/dlls/monsters.cpp @@ -2504,11 +2504,21 @@ void CMBaseMonster :: KeyValue( KeyValueData *pkvd ) m_iszTriggerTarget = ALLOC_STRING( pkvd->szValue ); pkvd->fHandled = TRUE; } - else if (FStrEq(pkvd->szKeyName, "TriggerCondition") ) + else if (FStrEq(pkvd->szKeyName, "TriggerCondition")) { m_iTriggerCondition = atoi( pkvd->szValue ); pkvd->fHandled = TRUE; } + else if (FStrEq(pkvd->szKeyName, "displayname")) + { + m_szMonsterName = ALLOC_STRING( pkvd->szValue ); + pkvd->fHandled = TRUE; + } + else if (FStrEq(pkvd->szKeyName, "classify")) + { + m_iClassifyOverride = atoi( pkvd->szValue ); + pkvd->fHandled = TRUE; + } else { CMBaseToggle::KeyValue( pkvd ); diff --git a/src/dlls/nodes.cpp b/src/dlls/nodes.cpp index dd96262..88423ba 100644 --- a/src/dlls/nodes.cpp +++ b/src/dlls/nodes.cpp @@ -1485,8 +1485,6 @@ void CTestHull :: Spawn( entvars_t *pevMasterNode ) //========================================================= void CTestHull::DropDelay ( void ) { - // Do NOT uncomment or you'll get a "Tried to create a message with a bogus message type ( 0 )" crash! - // Left here only because it's on the original HLSDK, and for comedy purposes. -Giegue //UTIL_CenterPrintAll( "Node Graph out of Date. Rebuilding..." ); UTIL_SetOrigin ( VARS(pev), WorldGraph.m_pNodes[ 0 ].m_vecOrigin ); diff --git a/src/dlls/scientist.cpp b/src/dlls/scientist.cpp index c761169..a28d72f 100644 --- a/src/dlls/scientist.cpp +++ b/src/dlls/scientist.cpp @@ -517,6 +517,11 @@ void CMScientist :: RunTask( Task_t *pTask ) //========================================================= int CMScientist :: Classify ( void ) { + if ( m_iClassifyOverride == -1 ) // helper + return CLASS_NONE; + else if ( m_iClassifyOverride > 0 ) + return m_iClassifyOverride; // override + return CLASS_HUMAN_PASSIVE; } @@ -616,6 +621,13 @@ void CMScientist :: Spawn( void ) pev->skin = 1; MonsterInit(); + + pev->classname = MAKE_STRING( "monster_scientist" ); + if ( strlen( STRING( m_szMonsterName ) ) == 0 ) + { + // default name + m_szMonsterName = MAKE_STRING( "Scientist" ); + } } //========================================================= diff --git a/src/dlls/squeakgrenade.cpp b/src/dlls/squeakgrenade.cpp index 81675b9..bcc60f0 100644 --- a/src/dlls/squeakgrenade.cpp +++ b/src/dlls/squeakgrenade.cpp @@ -47,6 +47,12 @@ float CMSqueakGrenade::m_flNextBounceSoundTime = 0; int CMSqueakGrenade :: Classify ( void ) { + // E + if ( m_iClassifyOverride == -1 ) // helper + return CLASS_NONE; + else if ( m_iClassifyOverride > 0 ) + return m_iClassifyOverride; // override + return CLASS_ALIEN_MONSTER; } @@ -84,6 +90,13 @@ void CMSqueakGrenade :: Spawn( void ) ResetSequenceInfo( ); m_hEnemy = NULL; + + pev->classname = MAKE_STRING( "monster_snark" ); + if ( strlen( STRING( m_szMonsterName ) ) == 0 ) + { + // hi :3 + m_szMonsterName = MAKE_STRING( "Snark" ); + } } void CMSqueakGrenade::Precache( void ) @@ -334,4 +347,4 @@ void CMSqueakGrenade::SuperBounceTouch( edict_t *pOther ) #endif -#endif \ No newline at end of file +#endif diff --git a/src/dlls/turret.cpp b/src/dlls/turret.cpp index 730a32a..31b20ac 100755 --- a/src/dlls/turret.cpp +++ b/src/dlls/turret.cpp @@ -142,6 +142,13 @@ void CMTurret::Spawn() m_eyeBrightness = 0; pev->nextthink = gpGlobals->time + 0.3; + + pev->classname = MAKE_STRING( "monster_turret" ); + if ( strlen( STRING( m_szMonsterName ) ) == 0 ) + { + // default name + m_szMonsterName = MAKE_STRING( "Turret" ); + } } void CMTurret::Precache() @@ -166,8 +173,15 @@ void CMMiniTurret::Spawn() m_iMinPitch = -15; UTIL_SetSize(pev, Vector(-16, -16, -m_iRetractHeight), Vector(16, 16, m_iRetractHeight)); - SetThink(&CMMiniTurret::Initialize); - pev->nextthink = gpGlobals->time + 0.3; + SetThink(&CMMiniTurret::Initialize); + pev->nextthink = gpGlobals->time + 0.3; + + pev->classname = MAKE_STRING( "monster_miniturret" ); + if ( strlen( STRING( m_szMonsterName ) ) == 0 ) + { + // default name + m_szMonsterName = MAKE_STRING( "Mini-Turret" ); + } } @@ -978,7 +992,15 @@ int CMBaseTurret::MoveTurret(void) int CMBaseTurret::Classify ( void ) { if (m_iOn || m_iAutoStart) - return CLASS_MACHINE; + { + if ( m_iClassifyOverride == -1 ) // helper + return CLASS_NONE; + else if ( m_iClassifyOverride > 0 ) + return m_iClassifyOverride; // override + + return CLASS_MACHINE; + } + return CLASS_NONE; } @@ -1006,8 +1028,15 @@ void CMSentry::Spawn() UTIL_SetSize(pev, Vector(-16, -16, -m_iRetractHeight), Vector(16, 16, m_iRetractHeight)); SetTouch(&CMSentry::SentryTouch); - SetThink(&CMSentry::Initialize); - pev->nextthink = gpGlobals->time + 0.3; + SetThink(&CMSentry::Initialize); + pev->nextthink = gpGlobals->time + 0.3; + + pev->classname = MAKE_STRING( "monster_sentry" ); + if ( strlen( STRING( m_szMonsterName ) ) == 0 ) + { + // default name + m_szMonsterName = MAKE_STRING( "Sentry Turret" ); + } } void CMSentry::Shoot(Vector &vecSrc, Vector &vecDirToEnemy) diff --git a/src/dlls/util.cpp b/src/dlls/util.cpp index 08b0c64..d36c6db 100644 --- a/src/dlls/util.cpp +++ b/src/dlls/util.cpp @@ -757,7 +757,7 @@ int gmsgSayText = 0; void UTIL_ClientPrintAll( int msg_dest, const char *msg_name, const char *param1, const char *param2, const char *param3, const char *param4 ) { - if (gmsgTextMsg) + if (gmsgTextMsg == 0) gmsgTextMsg = REG_USER_MSG( "TextMsg", -1 ); MESSAGE_BEGIN( MSG_ALL, gmsgTextMsg ); @@ -778,7 +778,7 @@ void UTIL_ClientPrintAll( int msg_dest, const char *msg_name, const char *param1 void ClientPrint( entvars_t *client, int msg_dest, const char *msg_name, const char *param1, const char *param2, const char *param3, const char *param4 ) { - if (gmsgTextMsg) + if (gmsgTextMsg == 0) gmsgTextMsg = REG_USER_MSG( "TextMsg", -1 ); MESSAGE_BEGIN( MSG_ONE, gmsgTextMsg, NULL, client ); @@ -1754,11 +1754,18 @@ int UTIL_TakeDamage( edict_t *pEdict, entvars_t *pevInflictor, entvars_t *pevAtt // do the damage pEdict->v.health -= flTake; - + + // store entity that hurt this player + pEdict->v.dmg_inflictor = ENT(pevAttacker); + if ( pEdict->v.health <= 0 ) { pEdict->v.health = 1; // can't suicide if already dead! - gpGamedllFuncs->dllapi_table->pfnClientKill(pEdict); + gpGamedllFuncs->dllapi_table->pfnClientKill(pEdict); + + // Add 1 score to the monster that killed this player + if ( pevAttacker->flags & FL_MONSTER ) + pevAttacker->frags += 1.0; } // tell director about it @@ -1800,7 +1807,7 @@ int UTIL_TakeDamage( edict_t *pEdict, entvars_t *pevInflictor, entvars_t *pevAtt WRITE_COORD( pevInflictor->origin.z ); MESSAGE_END(); } - + return fTookDamage; } diff --git a/src/dlls/zombie.cpp b/src/dlls/zombie.cpp index 721171f..362747c 100644 --- a/src/dlls/zombie.cpp +++ b/src/dlls/zombie.cpp @@ -82,6 +82,11 @@ const char *CMZombie::pPainSounds[] = //========================================================= int CMZombie :: Classify ( void ) { + if ( m_iClassifyOverride == -1 ) // helper + return CLASS_NONE; + else if ( m_iClassifyOverride > 0 ) + return m_iClassifyOverride; // override + return CLASS_ALIEN_MONSTER; } @@ -254,6 +259,13 @@ void CMZombie :: Spawn() m_afCapability = bits_CAP_DOORS_GROUP; MonsterInit(); + + pev->classname = MAKE_STRING( "monster_zombie" ); + if ( strlen( STRING( m_szMonsterName ) ) == 0 ) + { + // default name + m_szMonsterName = MAKE_STRING( "Zombie" ); + } } //========================================================= @@ -313,4 +325,4 @@ int CMZombie::IgnoreConditions ( void ) return iIgnore; -} \ No newline at end of file +}