Start making monstermod aware of normal HL monsters.
This is still heavily experimental and its use is not yet recommended.
This commit is contained in:
@@ -134,6 +134,8 @@ public:
|
||||
virtual void MonsterThink( void );
|
||||
void EXPORT CallMonsterThink( void ) { this->MonsterThink(); }
|
||||
virtual int IRelationship ( CMBaseEntity *pTarget );
|
||||
virtual int IRelationship ( int iTargetClass );
|
||||
int IRelationshipByClass ( int iClass );
|
||||
virtual void MonsterInit ( void );
|
||||
virtual void MonsterInitDead( void ); // Call after animation/pose is set up
|
||||
virtual void BecomeDead( void );
|
||||
@@ -1655,8 +1657,17 @@ public:
|
||||
void HandleAnimEvent(MonsterEvent_t *pEvent);
|
||||
void SetActivity(Activity NewActivity);
|
||||
|
||||
Schedule_t *GetSchedule( void );
|
||||
Schedule_t *GetScheduleOfType ( int Type );
|
||||
|
||||
BOOL CheckRangeAttack1( float flDot, float flDist );
|
||||
BOOL CheckMeleeAttack1( float flDot, float flDist );
|
||||
BOOL CheckRangeAttack2( float flDot, float flDist );
|
||||
|
||||
void Minigun(void);
|
||||
|
||||
CUSTOM_SCHEDULES
|
||||
|
||||
float m_flMinigunSpinTime;
|
||||
};
|
||||
|
||||
@@ -1695,4 +1706,8 @@ public:
|
||||
int m_iBodyGibs;
|
||||
};
|
||||
|
||||
//=========================================================
|
||||
// Looking for Stukabat? It's located in cmflyingmonster.h
|
||||
//=========================================================
|
||||
|
||||
#endif // BASEMONSTER_H
|
||||
|
||||
@@ -1154,6 +1154,59 @@ void RadiusDamage( Vector vecSrc, entvars_t *pevInflictor, entvars_t *pevAttacke
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (!UTIL_IsPlayer(pEntity))
|
||||
{
|
||||
// I'm doing really bad copypastes instead of making the code clean!
|
||||
// Remind me to refactor this, this is not how this is supposed to be written!
|
||||
// -Giegue
|
||||
edict_t *pMonster = pEntity;
|
||||
|
||||
if ( iClassIgnore != CLASS_NONE && pMonster->v.iuser4 == iClassIgnore )
|
||||
{// houndeyes don't hurt other houndeyes with their attack
|
||||
continue;
|
||||
}
|
||||
|
||||
// blast's don't tavel into or out of water
|
||||
if (bInWater && pEntity->v.waterlevel == 0)
|
||||
continue;
|
||||
if (!bInWater && pEntity->v.waterlevel == 3)
|
||||
continue;
|
||||
|
||||
vecSpot = UTIL_BodyTarget( pMonster, vecSrc );
|
||||
|
||||
UTIL_TraceLine ( vecSrc, vecSpot, dont_ignore_monsters, ENT(pevInflictor), &tr );
|
||||
|
||||
if ( tr.flFraction == 1.0 || tr.pHit == pEntity )
|
||||
{// the explosion can 'see' this entity, so hurt them!
|
||||
if (tr.fStartSolid)
|
||||
{
|
||||
// if we're stuck inside them, fixup the position and distance
|
||||
tr.vecEndPos = vecSrc;
|
||||
tr.flFraction = 0.0;
|
||||
}
|
||||
|
||||
// decrease damage for an ent that's farther from the bomb.
|
||||
flAdjustedDamage = ( vecSrc - tr.vecEndPos ).Length() * falloff;
|
||||
flAdjustedDamage = flDamage - flAdjustedDamage;
|
||||
|
||||
if ( flAdjustedDamage < 0 )
|
||||
{
|
||||
flAdjustedDamage = 0;
|
||||
}
|
||||
|
||||
// ALERT( at_console, "hit %s\n", STRING( pEntity->pev->classname ) );
|
||||
if (tr.flFraction != 1.0)
|
||||
{
|
||||
ClearMultiDamage( );
|
||||
UTIL_TraceAttack( pMonster, pevInflictor, flAdjustedDamage, (tr.vecEndPos - vecSrc).Normalize( ), &tr, bitsDamageType );
|
||||
ApplyMultiDamage( pevInflictor, pevAttacker );
|
||||
}
|
||||
else
|
||||
{
|
||||
UTIL_TakeDamageExternal( pMonster, pevInflictor, pevAttacker, flAdjustedDamage, bitsDamageType );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1207,6 +1260,8 @@ edict_t* CMBaseMonster :: CheckTraceHullAttack( float flDist, int iDamage, int i
|
||||
CMBaseMonster *pMonster = GetClassPtr((CMBaseMonster *)VARS(pEntity));
|
||||
pMonster->TakeDamage( pev, pev, iDamage, iDmgType );
|
||||
}
|
||||
else if (!UTIL_IsPlayer(pEntity))
|
||||
UTIL_TakeDamageExternal( pEntity, pev, pev, iDamage, iDmgType );
|
||||
}
|
||||
|
||||
return pEntity;
|
||||
@@ -1396,7 +1451,9 @@ void CMBaseEntity::FireBullets(ULONG cShots, Vector vecSrc, Vector vecDirShootin
|
||||
TEXTURETYPE_PlaySound(&tr, vecSrc, vecEnd, iBulletType);
|
||||
DecalGunshot( &tr, iBulletType );
|
||||
}
|
||||
else switch(iBulletType)
|
||||
else
|
||||
{
|
||||
switch(iBulletType)
|
||||
{
|
||||
default:
|
||||
case BULLET_MONSTER_9MM:
|
||||
@@ -1448,7 +1505,8 @@ void CMBaseEntity::FireBullets(ULONG cShots, Vector vecSrc, Vector vecDirShootin
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (tr.pHit->v.euser4 != NULL)
|
||||
}
|
||||
else if (tr.pHit->v.euser4 != NULL) // monstermod monster
|
||||
{
|
||||
CMBaseEntity *pMonster = GetClassPtr((CMBaseMonster *)VARS(tr.pHit));
|
||||
|
||||
@@ -1458,7 +1516,9 @@ void CMBaseEntity::FireBullets(ULONG cShots, Vector vecSrc, Vector vecDirShootin
|
||||
TEXTURETYPE_PlaySound(&tr, vecSrc, vecEnd, iBulletType);
|
||||
DecalGunshot( &tr, iBulletType );
|
||||
}
|
||||
else switch(iBulletType)
|
||||
else
|
||||
{
|
||||
switch(iBulletType)
|
||||
{
|
||||
default:
|
||||
case BULLET_MONSTER_9MM:
|
||||
@@ -1511,6 +1571,72 @@ void CMBaseEntity::FireBullets(ULONG cShots, Vector vecSrc, Vector vecDirShootin
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (!UTIL_IsPlayer(tr.pHit)) // normal game monster
|
||||
{
|
||||
edict_t *pMonster = tr.pHit;
|
||||
|
||||
if ( iDamage )
|
||||
{
|
||||
UTIL_TraceAttack(pMonster, pevAttacker, iDamage, vecDir, &tr, DMG_BULLET | ((iDamage > 16) ? DMG_ALWAYSGIB : DMG_NEVERGIB) );
|
||||
TEXTURETYPE_PlaySound(&tr, vecSrc, vecEnd, iBulletType);
|
||||
DecalGunshot( &tr, iBulletType );
|
||||
}
|
||||
else
|
||||
{
|
||||
switch(iBulletType)
|
||||
{
|
||||
default:
|
||||
case BULLET_MONSTER_9MM:
|
||||
UTIL_TraceAttack(pMonster, pevAttacker, gSkillData.monDmg9MM, vecDir, &tr, DMG_BULLET);
|
||||
TEXTURETYPE_PlaySound(&tr, vecSrc, vecEnd, iBulletType);
|
||||
DecalGunshot( &tr, iBulletType );
|
||||
|
||||
break;
|
||||
|
||||
case BULLET_MONSTER_MP5:
|
||||
UTIL_TraceAttack(pMonster, pevAttacker, gSkillData.monDmgMP5, vecDir, &tr, DMG_BULLET);
|
||||
TEXTURETYPE_PlaySound(&tr, vecSrc, vecEnd, iBulletType);
|
||||
DecalGunshot( &tr, iBulletType );
|
||||
|
||||
break;
|
||||
|
||||
case BULLET_MONSTER_12MM:
|
||||
UTIL_TraceAttack(pMonster, pevAttacker, gSkillData.monDmg12MM, vecDir, &tr, DMG_BULLET);
|
||||
if ( !tracer )
|
||||
{
|
||||
TEXTURETYPE_PlaySound(&tr, vecSrc, vecEnd, iBulletType);
|
||||
DecalGunshot( &tr, iBulletType );
|
||||
}
|
||||
break;
|
||||
|
||||
case BULLET_MONSTER_762:
|
||||
UTIL_TraceAttack(pMonster, pevAttacker, gSkillData.monDmg762, vecDir, &tr, DMG_BULLET);
|
||||
TEXTURETYPE_PlaySound(&tr, vecSrc, vecEnd, iBulletType);
|
||||
DecalGunshot( &tr, iBulletType );
|
||||
|
||||
break;
|
||||
|
||||
case BULLET_MONSTER_357:
|
||||
UTIL_TraceAttack(pMonster, pevAttacker, gSkillData.monDmg357, vecDir, &tr, DMG_BULLET);
|
||||
TEXTURETYPE_PlaySound(&tr, vecSrc, vecEnd, iBulletType);
|
||||
DecalGunshot( &tr, iBulletType );
|
||||
|
||||
break;
|
||||
|
||||
case BULLET_NONE: // FIX
|
||||
UTIL_TraceAttack(pMonster, pevAttacker, 50, vecDir, &tr, DMG_CLUB);
|
||||
TEXTURETYPE_PlaySound(&tr, vecSrc, vecEnd, iBulletType);
|
||||
// only decal glass
|
||||
if ( !FNullEnt(tr.pHit) && VARS(tr.pHit)->rendermode != 0)
|
||||
{
|
||||
UTIL_DecalTrace( &tr, DECAL_GLASSBREAK1 + RANDOM_LONG(0,2) );
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// make bullet trails
|
||||
UTIL_BubbleTrail( vecSrc, tr.vecEndPos, (flDistance * tr.flFraction) / 64.0 );
|
||||
}
|
||||
|
||||
@@ -137,17 +137,14 @@ void CMBaseMonster :: Look ( int iDistance )
|
||||
{
|
||||
pSightEnt = pList[i];
|
||||
// !!!temporarily only considering other monsters and clients, don't see prisoners
|
||||
if ( pSightEnt != this->edict() &&
|
||||
!FBitSet( pSightEnt->v.spawnflags, SF_MONSTER_PRISONER ) &&
|
||||
pSightEnt->v.health > 0 )
|
||||
if ( pSightEnt != this->edict() && !FBitSet( pSightEnt->v.spawnflags, SF_MONSTER_PRISONER ) && pSightEnt->v.health > 0 )
|
||||
{
|
||||
// is this a player AND are they alive?
|
||||
if (UTIL_IsPlayer(pSightEnt) && UTIL_IsAlive(pSightEnt))
|
||||
{
|
||||
// the looker will want to consider this entity
|
||||
// don't check anything else about an entity that can't be seen.
|
||||
if ( UTIL_FInViewCone( pSightEnt, ENT(pev), m_flFieldOfView ) &&
|
||||
!FBitSet( pSightEnt->v.flags, FL_NOTARGET ) && UTIL_FVisible( pSightEnt, ENT(pev) ) )
|
||||
if ( UTIL_FInViewCone( pSightEnt, ENT(pev), m_flFieldOfView ) && !FBitSet( pSightEnt->v.flags, FL_NOTARGET ) && UTIL_FVisible( pSightEnt, ENT(pev) ) )
|
||||
{
|
||||
m_edictList[m_edictList_count] = pSightEnt;
|
||||
m_edictList_count++;
|
||||
@@ -170,12 +167,12 @@ void CMBaseMonster :: Look ( int iDistance )
|
||||
}
|
||||
else if (pSightEnt->v.euser4 != NULL)
|
||||
{
|
||||
/* MonsterMod monster looking at another MonsterMod monster */
|
||||
CMBaseMonster *pMonster = GetClassPtr((CMBaseMonster *)VARS(pSightEnt));
|
||||
|
||||
// the looker will want to consider this entity
|
||||
// don't check anything else about an entity that can't be seen, or an entity that you don't care about.
|
||||
if ( IRelationship( pMonster ) != R_NO && UTIL_FInViewCone( pSightEnt, ENT(pev), m_flFieldOfView ) &&
|
||||
!FBitSet( pSightEnt->v.flags, FL_NOTARGET ) && UTIL_FVisible( pSightEnt, ENT(pev) ) )
|
||||
if ( IRelationship( pMonster ) != R_NO && UTIL_FInViewCone( pSightEnt, ENT(pev), m_flFieldOfView ) && !FBitSet( pSightEnt->v.flags, FL_NOTARGET ) && UTIL_FVisible( pSightEnt, ENT(pev) ) )
|
||||
{
|
||||
m_edictList[m_edictList_count] = pSightEnt;
|
||||
m_edictList_count++;
|
||||
@@ -210,6 +207,47 @@ void CMBaseMonster :: Look ( int iDistance )
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (!UTIL_IsPlayer(pSightEnt))
|
||||
{
|
||||
/* MonsterMod monster looking at a NON-MonsterMod monster */
|
||||
|
||||
// the looker will want to consider this entity
|
||||
// don't check anything else about an entity that can't be seen, or an entity that you don't care about.
|
||||
if ( IRelationship( pSightEnt->v.iuser4 ) != R_NO && UTIL_FInViewCone( pSightEnt, ENT(pev), m_flFieldOfView ) && !FBitSet( pSightEnt->v.flags, FL_NOTARGET ) && UTIL_FVisible( pSightEnt, ENT(pev) ) )
|
||||
{
|
||||
m_edictList[m_edictList_count] = pSightEnt;
|
||||
m_edictList_count++;
|
||||
|
||||
if ( pSightEnt == m_hEnemy )
|
||||
{
|
||||
// we know this ent is visible, so if it also happens to be our enemy, store that now.
|
||||
iSighted |= bits_COND_SEE_ENEMY;
|
||||
}
|
||||
|
||||
// don't add the Enemy's relationship to the conditions. We only want to worry about conditions when
|
||||
// we see monsters other than the Enemy.
|
||||
switch ( IRelationship ( pSightEnt->v.iuser4 ) )
|
||||
{
|
||||
case R_NM:
|
||||
iSighted |= bits_COND_SEE_NEMESIS;
|
||||
break;
|
||||
case R_HT:
|
||||
iSighted |= bits_COND_SEE_HATE;
|
||||
break;
|
||||
case R_DL:
|
||||
iSighted |= bits_COND_SEE_DISLIKE;
|
||||
break;
|
||||
case R_FR:
|
||||
iSighted |= bits_COND_SEE_FEAR;
|
||||
break;
|
||||
case R_AL:
|
||||
break;
|
||||
default:
|
||||
ALERT ( at_aiconsole, "%s can't assess %s\n", STRING(pev->classname), STRING(pSightEnt->v.classname ) );
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1743,6 +1781,9 @@ void CMBaseMonster :: StartMonster ( void )
|
||||
SetActivity( ACT_IDLE );
|
||||
ChangeSchedule( GetScheduleOfType( SCHED_WAIT_TRIGGER ) );
|
||||
}
|
||||
|
||||
// Notify normal game engine of monster classify
|
||||
pev->iuser4 = Classify();
|
||||
}
|
||||
|
||||
|
||||
@@ -1784,6 +1825,14 @@ int CMBaseMonster::TaskIsRunning( void )
|
||||
// relationship between two types of monster.
|
||||
//=========================================================
|
||||
int CMBaseMonster::IRelationship ( CMBaseEntity *pTarget )
|
||||
{
|
||||
return IRelationshipByClass( pTarget->Classify() );
|
||||
}
|
||||
int CMBaseMonster::IRelationship ( int iTargetClass )
|
||||
{
|
||||
return IRelationshipByClass( iTargetClass );
|
||||
}
|
||||
int CMBaseMonster::IRelationshipByClass ( int iClass )
|
||||
{
|
||||
static int iEnemy[16][16] =
|
||||
{ // NONE MACH PLYR HPASS HMIL AMIL APASS AMONST APREY APRED INSECT PLRALY PBWPN ABWPN RXPIT RXSHK
|
||||
@@ -1805,7 +1854,7 @@ int CMBaseMonster::IRelationship ( CMBaseEntity *pTarget )
|
||||
/*RXSHOCKTRP*/ { R_NO ,R_DL ,R_HT ,R_DL ,R_HT ,R_HT ,R_DL ,R_NO ,R_NO ,R_DL ,R_NO ,R_DL, R_NO, R_NO, R_AL, R_AL }
|
||||
};
|
||||
|
||||
return iEnemy[ Classify() ][ pTarget->Classify() ];
|
||||
return iEnemy[ Classify() ][ iClass ];
|
||||
}
|
||||
|
||||
//=========================================================
|
||||
@@ -2041,16 +2090,17 @@ edict_t *CMBaseMonster :: BestVisibleEnemy ( void )
|
||||
if ( iDist <= iNearest )
|
||||
{
|
||||
iNearest = iDist;
|
||||
iBestRelationship = R_NM; // player is always nemsis
|
||||
iBestRelationship = R_NM; // player is always nemesis
|
||||
pReturn = pEnt;
|
||||
}
|
||||
}
|
||||
else if (pEnt->v.euser4 != NULL)
|
||||
{
|
||||
// it's a monstermod monster...
|
||||
CMBaseMonster *pNextEnt = GetClassPtr((CMBaseMonster *)VARS(pEnt));
|
||||
if ( pNextEnt->IsAlive() )
|
||||
{
|
||||
if ( IRelationship( pNextEnt) > iBestRelationship )
|
||||
if ( IRelationship( pNextEnt ) > iBestRelationship )
|
||||
{
|
||||
// this entity is disliked MORE than the entity that we
|
||||
// currently think is the best visible enemy. No need to do
|
||||
@@ -2059,7 +2109,7 @@ edict_t *CMBaseMonster :: BestVisibleEnemy ( void )
|
||||
iNearest = ( pNextEnt->pev->origin - pev->origin ).Length();
|
||||
pReturn = pEnt;
|
||||
}
|
||||
else if ( IRelationship( pNextEnt) == iBestRelationship )
|
||||
else if ( IRelationship( pNextEnt ) == iBestRelationship )
|
||||
{
|
||||
// this entity is disliked just as much as the entity that
|
||||
// we currently think is the best visible enemy, so we only
|
||||
@@ -2075,6 +2125,31 @@ edict_t *CMBaseMonster :: BestVisibleEnemy ( void )
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (!UTIL_IsPlayer(pEnt))
|
||||
{
|
||||
// it's a game default monster...
|
||||
if ( UTIL_IsAlive(pEnt) )
|
||||
{
|
||||
//repeat2
|
||||
if ( IRelationship( pEnt->v.iuser4 ) > iBestRelationship )
|
||||
{
|
||||
iBestRelationship = IRelationship( pEnt->v.iuser4 );
|
||||
iNearest = ( pEnt->v.origin - pev->origin ).Length();
|
||||
pReturn = pEnt;
|
||||
}
|
||||
else if ( IRelationship( pEnt->v.iuser4 ) == iBestRelationship )
|
||||
{
|
||||
iDist = ( pEnt->v.origin - pev->origin ).Length();
|
||||
|
||||
if ( iDist <= iNearest )
|
||||
{
|
||||
iNearest = iDist;
|
||||
iBestRelationship = IRelationship( pEnt->v.iuser4 );
|
||||
pReturn = pEnt;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
edictList_index++;
|
||||
}
|
||||
|
||||
@@ -1968,3 +1968,11 @@ bool UTIL_IsBSPModel( edict_t *pent )
|
||||
{
|
||||
return (pent->v.solid == SOLID_BSP || pent->v.movetype == MOVETYPE_PUSHSTEP);
|
||||
}
|
||||
|
||||
void UTIL_TakeDamageExternal( edict_t *pEdict, entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType )
|
||||
{
|
||||
// Tell AMXX to call TakeDamage for us.
|
||||
char extCmd[64];
|
||||
sprintf( extCmd, "monster_hurt_entity %i %i %i %f %i\n", ENTINDEX( pEdict ), ENTINDEX( ENT( pevInflictor ) ), ENTINDEX( ENT( pevAttacker ) ), flDamage, bitsDamageType );
|
||||
SERVER_COMMAND( extCmd );
|
||||
}
|
||||
|
||||
@@ -538,3 +538,4 @@ Vector UTIL_Center(edict_t *pEdict);
|
||||
edict_t *UTIL_GetNextTarget( edict_t *pEntity );
|
||||
edict_t *UTIL_FindNearestPlayer(edict_t *pEdict, float m_flFieldOfView);
|
||||
bool UTIL_IsBSPModel( edict_t *pent );
|
||||
void UTIL_TakeDamageExternal( edict_t *pEdict, entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType );
|
||||
|
||||
@@ -79,6 +79,8 @@ void ApplyMultiDamage(entvars_t *pevInflictor, entvars_t *pevAttacker )
|
||||
CMBaseMonster *pMonster = GetClassPtr((CMBaseMonster *)VARS(gMultiDamage.pEntity));
|
||||
pMonster->TakeDamage(pevInflictor, pevAttacker, gMultiDamage.amount, gMultiDamage.type );
|
||||
}
|
||||
else if (!UTIL_IsPlayer(gMultiDamage.pEntity))
|
||||
UTIL_TakeDamageExternal(gMultiDamage.pEntity, pevInflictor, pevAttacker, gMultiDamage.amount, gMultiDamage.type );
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user