Limit npc attack to only enemy in front Created 6 years ago2018-01-29 23:04:36 UTC by abbadon abbadon

Created 6 years ago2018-01-29 23:04:36 UTC by abbadon abbadon

Posted 6 years ago2018-01-29 23:04:36 UTC Post #338729
Hi again!!, I am wondering how to avoid the attack of a given npc only affect the enemy in front of it and not every npc surrounding it. The code for the attack function of my npc is this:

[quote]int CTrolley :: GiveAmmo( int iCount, char *szName, int iMax )
{

CBaseEntity *pPlayer;

pPlayer = UTIL_FindEntityByClassname( NULL, "player" );

if (pPlayer->ammo_9mm <= 100)//limite de munición para que te recargue

{
pPlayer->GiveAmmo(600,"9mm",600); 
return TRUE;
}


return FALSE;
}[/quote]

The npc, when "attacks" the player and give him ammo, it result in giving ammo to every player around him. How can I fix this?
Posted 6 years ago2018-01-30 10:41:33 UTC Post #338730
You need to show the code that calls GiveAmmo, also this should only ever give ammo to the player with the lowest entity index, regardless of distance.
Posted 6 years ago2018-01-30 15:16:03 UTC Post #338731
Here you are:

Declaration of the function...
int CTrolley :: GiveAmmo( int iCount, char *szName, int iMax );// ZWC ARM 8-7-2015
Where it is used...
[quote]
//=========================================================
// HandleAnimEvent - catches the monster-specific messages
// that occur when tagged animation frames are played.
//=========================================================
void CTrolley :: HandleAnimEvent( MonsterEvent_t *pEvent )
{
switch( pEvent->event )
{
	case TROLL_AE_ATTACK_RIGHT:
	{
//ALERT( at_console, "RELOAD!!\n" );
	CBaseEntity *pHurt = CheckTraceHullAttack( 0, -25, DMG_SLASH );//Gives some health... (if -25 was +25 it will hurt you)
		if ( pHurt )
		{

			EMIT_SOUND_DYN ( ENT(pev), CHAN_WEAPON, pAttackHitSounds[ RANDOM_LONG(0,ARRAYSIZE(pAttackHitSounds)-1) ], 1.0, ATTN_NORM, 0, 100 + RANDOM_LONG(-5,5) );

		    GiveAmmo(600, "9mm",600);// Give ammo
			//GiveAmmo(1, "uranium", 1);// Commented. Not more URANIUM
		}
		else // Play a random attack miss sound
			EMIT_SOUND_DYN ( ENT(pev), CHAN_WEAPON, pAttackMissSounds[ RANDOM_LONG(0,ARRAYSIZE(pAttackMissSounds)-1) ], 1.0, ATTN_NORM, 0, 100 + RANDOM_LONG(-5,5) );
	//	if (RANDOM_LONG(0,1))
	//		AttackSounds();

		pev->nextthink = gpGlobals->time + 5;//Time for recharge is limited
	}
	break;
	default:
		CBaseMonster::HandleAnimEvent( pEvent );
		break;
}
}
[/quote]
Posted 6 years ago2018-01-30 16:09:58 UTC Post #338732
CTrolley is a monster, and i'm assuming TROLL_AE_ATTACK_RIGHT is an event in an animation triggered as a melee attack on a player.

This means that m_hEnemy (https://github.com/ValveSoftware/halflife/blob/master/dlls/basemonster.h#L40) is the player. Use that member variable to give ammo to the correct player, in other words GiveAmmo should look like this:
int CTrolley :: GiveAmmo( CBasePlayer* pPlayer, int iCount, char *szName, int iMax )
{
if (pPlayer->ammo_9mm <= 100)//limite de munición para que te recargue

{
pPlayer->GiveAmmo(600,"9mm",600);
return TRUE;

}

return FALSE;
}
And HandleAnimEvent should do this:
if( m_hEnemy && m_hEnemy->IsPlayer() )
{
CBasePlayer* pPlayer = static_cast<CBasePlayer*>( static_cast<CBaseEntity*>( m_hEnemy ) );
GiveAmmo( pPlayer, 600,"9mm",600 );
}
I should note that GiveAmmo ignores the values you're giving it and is always giving those amounts, so make sure you update it to use the input values if you want that to work correctly.
Posted 6 years ago2018-01-30 20:24:04 UTC Post #338734
Mmmm, tried to compile it, and...

[quote]
Compiling...
trolley.cpp
C:\DevZWC20\Elementos\Single-Player Source\dlls\trolley.cpp(361) : error C2593: 'operator &&' is ambiguous
C:\DevZWC20\Elementos\Single-Player Source\dlls\trolley.cpp(363) : error C2061: syntax error : identifier 'CBasePlayer'
C:\DevZWC20\Elementos\Single-Player Source\dlls\trolley.cpp(492) : error C2027: use of undefined type 'CBasePlayer'
C:\DevZWC20\Elementos\Single-Player Source\dlls\util.h(300) : see declaration of 'CBasePlayer'
C:\DevZWC20\Elementos\Single-Player Source\dlls\trolley.cpp(492) : error C2227: left of '->ammo_9mm' must point to class/struct/union
C:\DevZWC20\Elementos\Single-Player Source\dlls\trolley.cpp(495) : error C2027: use of undefined type 'CBasePlayer'
C:\DevZWC20\Elementos\Single-Player Source\dlls\util.h(300) : see declaration of 'CBasePlayer'
C:\DevZWC20\Elementos\Single-Player Source\dlls\trolley.cpp(495) : error C2227: left of '->GiveAmmo' must point to class/struct/union
Error executing cl.exe.
[/quote]

Of course I have modified the declaration of the GiveAmmo function...
int CTrolley :: GiveAmmo( CBasePlayer* pPlayer, int iCount, char *szName, int iMax );
Posted 6 years ago2018-01-30 20:51:48 UTC Post #338735
Replace CBasePlayer with CBaseEntity, it'll work.
Try using m_hEnemy != NULL instead of just m_hEnemy, so:
if( m_hEnemy != NULL && m_hEnemy->IsPlayer() )
Posted 6 years ago2018-01-30 23:27:02 UTC Post #338736
Done!,Compiles fine, but they still add ammo to me even if I am not "attacked". :/ Sure my fault!, almost 8 months without touching code sure is the cause, ha ha ha!! XD. I will take a look for a bad placed part. Thanks Solokiller, I will post the results!

Edit: tried another solution, still with no luck...

[quote]
int CTrolley::IRelationship( CBaseEntity *pTarget )
{
if ( pTarget->ammo_9mm < 100 && FClassnameIs ( pTarget->pev, "player" ) )
{
  	return R_NM;
}

if ( pTarget->ammo_9mm > 100 )
{
	return R_AL;
}
if (FBitSet(pTarget->pev->flags, FL_FAKECLIENT))
{
	return R_AL;
}
return CBaseMonster::IRelationship( pTarget );
}
[/quote]

I know that the two last "if" could be joined togheter, but I have added the FL_FAKECLIENT part just to give it a try. ;)
Posted 6 years ago2018-01-30 23:34:56 UTC Post #338737
Which animation has the event, and when is it used, as in which act is it associated with? ACT_MELEE_ATTACK1/2 or something else? It might be triggering for all players at all times, so the act itself may need changing.
Posted 6 years ago2018-01-31 10:54:05 UTC Post #338739
void CTrolley :: HandleAnimEvent( MonsterEvent_t *pEvent )
{
switch( pEvent->event )
{
case TROLL_AE_ATTACK_RIGHT:
{
...
Right there, I should post the qc file for the event, right? (50..whatever I think it is). :)
Posted 6 years ago2018-01-31 13:13:00 UTC Post #338741
Yeah, the QC file should tell us what's up. Make sure to list which animations are used.
Posted 6 years ago2018-01-31 19:40:30 UTC Post #338748
I can't be much help with this as I have absolutely no idea how things work in goldsource, but what I would suggest is finding a way to output the return of all the variables in your function on screen.

I find it's a lot easier to find out exactly what is going on in the code visually rather than trial-and-error, maybe your function is running multiple times, or there's an issue within the function running one time, or it's elsewhere.
If you can output the functions in some visual form, at least you'll have some idea of what's going on.
Crollo CrolloTrollo
Posted 6 years ago2018-02-01 09:32:57 UTC Post #338750
Hi!, even if it´s about something quite different, I found this...

http://twhl.info/articulator.php?art=163&form=old

...and something is telling me that things will not be as simple as I thought (remember that I am very bad at coding), maybe I should take a closer look to trolley.cpp and the monster_trolley.qc files, and post them (they´re not so long files). ;)

trolley.cpp is based on the original HL´s zombie monster, with some hacks to make it "attack" (reload) you if you have certain amount of ammo ( more or less than 100 ).

Of course I will add "ALERT (at_console..." wherever I think it will be useful, thanks Crollo ;) .
Posted 6 years ago2018-02-01 15:59:51 UTC Post #338754
Here´s the qc file:

[quote]
/*
QC script generated by Half-Life MDL Decompiler 1.2
2003, Kratisto. Based on code from Valve's HL SDK.

monster_trolley.mdl

Original internal name:
"C:\DevZWC20\Elementos\Modelos v2.0\Elementos Reloader\monster_trtè "
*/

$modelname "monster_trolley.mdl"
$cd ".\"
$cdtexture ".\"
$scale 1.0
$cliptotextures

$bbox 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000
$cbox 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000
$eyeposition 0.000000 0.000000 0.000000

//reference mesh(es)
$body "body" "reference"

$texrendermode "trolley.bmp" "masked"
$texrendermode "carreta.bmp" "masked"

// 37 hit box(es)
$hbox 0 "Bip01 Pelvis" -11.515389 -9.690666 -1.395845 2.593500 2.622000 12.946850
$hbox 0 "Bip01 L Thigh" -1.463000 -1.330000 0.000000 1.130500 3.030500 6.451018
$hbox 0 "Bip01 L Calf" -1.102000 -1.035500 0.000000 1.453500 1.520000 5.381332
$hbox 0 "Bip01 L Foot" -2.118500 -1.387000 -0.646000 0.456000 0.589000 2.405057
$hbox 0 "Bip01 R Thigh" -1.320500 -1.168500 0.000000 1.377500 1.472500 6.453395
$hbox 0 "Bip01 R Calf" -1.092500 -1.083000 0.000000 1.472500 1.463000 5.352680
$hbox 0 "Bip01 R Foot" -2.137500 -1.406000 -0.627000 0.437000 0.608000 2.413388
$hbox 0 "Bip01 Spine" -2.004500 -2.033000 -2.148197 2.679000 2.622000 0.370500
$hbox 0 "Bip01 Spine1" -2.603000 -2.517500 -0.323000 2.517500 2.593500 4.674000
$hbox 0 "Bip01 Neck" -0.921500 -0.970822 -0.489736 0.998358 0.950000 1.634000
$hbox 0 "Bip01 L UpperArm" -0.817000 -0.969000 0.000000 0.921500 1.130500 3.098885
$hbox 0 "Bip01 L Forearm" -0.598500 -0.798000 -0.038000 0.684000 0.655500 4.953762
$hbox 0 "Bip01 R UpperArm" -0.864500 -1.007000 -0.161500 0.902500 1.035500 2.877933
$hbox 0 "Bip01 R Forearm" -0.589000 -0.655500 -0.047500 0.731500 0.750500 4.959755
$hbox 0 "Bip01 Head" -1.681500 -1.197000 -0.608000 1.225500 1.729000 2.565000
$hbox 0 "Bip01 L Foot1" -0.940500 -1.159000 -0.123500 0.589000 0.579500 1.140000
$hbox 0 "Bip01 R Foot1" -1.054500 -0.997500 -0.114000 0.560500 0.636500 1.159000
$hbox 0 "Bip01 Bolsa" -2.166000 -2.071000 -1.225500 2.156500 2.365500 1.814500
$hbox 0 "Bip01 Carro" -11.970000 -11.922500 -30.731306 10.867999 10.944000 2.631500
$hbox 0 "Bip01 Soporte_Izq_2" -2.365500 -0.446500 -1.415500 1.035500 1.054500 1.653000
$hbox 0 "Bip01 Soporte_D_2" -2.346500 -0.427500 -1.434500 1.045000 1.149500 1.624500
$hbox 0 "Bip01 Rueda" -2.669500 -2.660000 -2.840500 2.859500 2.802500 2.840500
$hbox 0 "Bip01 Fuelle A 1 " -2.983000 -4.389000 -0.475000 2.726500 4.655000 15.028999
$hbox 0 "Bip01 Fuelle A 2" -2.365500 -5.177500 -0.418000 2.565000 5.320000 15.095500
$hbox 0 "Bip01 Fuelle A 3" -1.596000 -4.959000 -0.228000 1.757500 4.826000 15.285500
$hbox 0 "Bip01 Fuelle A 4" -1.358500 -5.405500 -0.304000 1.406000 5.491000 15.219000
$hbox 0 "Bip01 Fuelle A 5" -0.940500 -5.149000 -0.237500 1.102000 4.968500 15.276000
$hbox 0 "Bip01 Bandeja" -8.749500 -8.702000 -4.560000 8.284000 8.170000 1.843000
$hbox 0 "Bip 01 BandejaRecarga D" -5.899500 -5.396000 -2.080500 4.598000 1.415500 4.607500
$hbox 0 "Bip01 AmmoBox D" -5.291500 -4.265500 -4.778500 5.453000 4.218000 4.655000
$hbox 0 "Bip 01 BandejaRecarga I" -5.709500 0.000000 -2.213500 5.842500 3.714500 4.664500
$hbox 0 "Bip01 Ammobox I" -5.377000 -3.315500 -4.826000 5.500500 3.363000 4.617000
$hbox 0 "Bip01 Fuelle P1" -1.605500 -5.434000 -0.465500 1.567500 5.405500 15.057500
$hbox 0 "Bip01 Fuelle P2" -1.045000 -5.092000 -0.313500 1.254000 4.997000 15.190499
$hbox 0 "Bip01 Fuelle P3" -0.912000 -5.453000 -0.304000 1.045000 5.481500 15.219000
$hbox 0 "Bip01 Fuelle P4" -0.684000 -5.054000 -0.247000 0.855000 5.016000 15.256999
$hbox 0 "Bip01 Fuelle P5" -0.617500 -5.453000 -0.294500 0.722000 5.481500 15.228500

// 14 animation sequence(s)
$sequence "idle1" "idle1" fps 5 loop ACT_IDLE 4
$sequence "turnleft" "turnleft" fps 20 ACT_TURN_LEFT 1
$sequence "turnright" "turnright" fps 20 ACT_TURN_RIGHT 1
$sequence "flinchsmall" "flinchsmall" fps 12 ACT_SMALL_FLINCH 5
$sequence "flinch" "flinch" fps 12 ACT_SMALL_FLINCH 1
$sequence "bigflinch" "bigflinch" fps 12 ACT_BIG_FLINCH 1
$sequence "attack1" "attack1" fps 8 ACT_MELEE_ATTACK1 5 { event 1 25 }
$sequence "run" "run" LX fps 50 loop ACT_WALK 1 {
{ event 1004 2 "common/npc_step1.wav" }
{ event 1004 12 "common/npc_step3.wav" }
{ event 1004 22 "common/npc_step2.wav" }
{ event 1004 29 "common/npc_step4.wav" }
{ event 1004 29 "common/npc_step1.wav" }
{ event 1004 29 "common/npc_step3.wav" }
}
$sequence "laflinch" "laflinch" fps 12 ACT_FLINCH_LEFTARM 1
$sequence "raflinch" "raflinch" fps 12 ACT_FLINCH_RIGHTARM 1
$sequence "llflinch" "llflinch" fps 12 ACT_FLINCH_LEFTLEG 1
$sequence "rlflinch" "rlflinch" fps 12 ACT_FLINCH_RIGHTLEG 1
$sequence "diesimple" "diesimple" X fps 20 ACT_DIESIMPLE 1 { event 2001 13 }
$sequence "deadidle" "deadidle" fps 1 loop

// End of QC script.
[/quote]

And the cpp file:

[quote]
/***
*
* Copyright (c) 1996-2002, Valve LLC. All rights reserved.
*
* This product contains software technology licensed from Id
* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc.
* All Rights Reserved.
*
  • This source code contains proprietary and confidential information of
  • Valve LLC and its suppliers. Access to this code is restricted to
  • persons who have executed a written SDK license with Valve. Any access,
  • use or distribution of this code by or to any unlicensed person is illegal.
*
****/

//=========================================================
// TROLLEY-RELOADER : Los tíos de la carretilla
// Based on the zombie character from HL
// 6-Julio-2015
//=========================================================

#include "extdll.h"
#include "util.h"
#include "cbase.h"
#include "monsters.h"
#include "squadmonster.h"
#include "weapons.h"
#include "effects.h"
#include "game.h"

//=========================================================
// Monster's Anim Events Go Here
//=========================================================
#define TROLL_AE_ATTACK_RIGHT 0x01
#define TROLL_FLINCH_DELAY 0 // at most one flinch every n secs
//======================================================
// Monster BASIC stuff
//======================================================

class CTrolley : public CBaseMonster
{

public:
void Spawn( void );
void Precache( void );
void SetYawSpeed ( void );
// void AttackSounds( void );
void PainSound( void );
// void DeathSounds( void );
// void IdleSound( void );
// void AlertSound( void );
void HandleAnimEvent( MonsterEvent_t *pEvent );
Vector Center( void );
Vector BodyTarget( const Vector &posSrc );
int IRelationship( CBaseEntity *pTarget );
int Classify ( void );
int	IgnoreConditions( void );
int CTrolley :: GiveAmmo(  int iCount, char *szName, int iMax );// ZWC ARM 8-7-2015
int TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType );
BOOL CheckMeleeAttack1( float flDot, float flDist ); 

virtual float GetDamageAmount( void ) { return 0;}   //return gSkillData.headcrabDmgBite; }
virtual int GetVoicePitch( void ) { return 100; }
virtual float GetSoundVolue( void ) { return 1.0; }
// static const char *pAttackSounds[];
// static const char *pIdleSounds[];
// static const char *pAlertSounds[];
static const char *pPainSounds[];
static const char *pAttackHitSounds[];
static const char *pAttackMissSounds[];
// static const char *pDeathSounds[];
// static const char *pBiteSounds[];
//==============================================================================================================
// ARM: Declaración de la Función TraceAttack, el tiempo de ejecución de las animaciones "flinch", la función
// de ignorar condiciones, la descripcion de datos ESTATICOS ( m_SaveData ) y la función que disuelve los 
// cuerpos al morir.
//==============================================================================================================
void    TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType );
float m_flNextFlinch;
static	TYPEDESCRIPTION m_SaveData[];

void BecomeDead( void );
};

const char *CTrolley::pAttackHitSounds[] =
{
"kid/reloadok1.wav",
"kid/reloadok2.wav",
"kid/reloadok3.wav",
};

const char *CTrolley::pAttackMissSounds[] =
{
"kid/reloadfail1.wav",
"kid/reloadfail2.wav",
};

/*
const char *CTrolley::pAttackSounds[] =
{
"kid/enroute1.wav",
"kid/enroute2.wav",
};

const char *CTrolley::pIdleSounds[] =
{
"kid/idle1.wav",
"kid/idle2.wav",
"kid/idle3.wav",
"kid/idle4.wav",
};

const char *CTrolley::pAlertSounds[] =
{
"kid/alert10.wav",
"kid/alert20.wav",
"kid/alert30.wav",
};
*/
const char *CTrolley::pPainSounds[] =
{
"kid/pain1.wav",
"kid/pain2.wav",
};
/*
const char *CTrolley::pBiteSounds[] =
{
"kid/clash.wav",
};

const char *CTrolley::pDeathSounds[] =
{
"kid/die1.wav",
"kid/die2.wav",
};
*/
LINK_ENTITY_TO_CLASS( monster_trolley, CTrolley );

//=========================================================
// CheckMeleeAttack1 osea Recargar a las APU
//=========================================================
BOOL CTrolley::CheckMeleeAttack1( float flDot, float flDist )
{
// ALERT(at_aiconsole, "CheckMelee(%f, %f)\n", flDot, flDist);
if (flDot >= 0.7)
{
	if (flDist <= 50)
		return TRUE;
}
return FALSE;
}

//=========================================================

//==========================================================
// Relationship
//==========================================================
int CTrolley::IRelationship( CBaseEntity *pTarget )
{
if ( pTarget->ammo_9mm < 100 && FClassnameIs ( pTarget->pev, "player" ) )
{
  	return R_NM;
}

if ( pTarget->ammo_9mm > 100 )
{
	return R_AL;
}
if (FBitSet(pTarget->pev->flags, FL_FAKECLIENT))
{
	return R_AL;
}
return CBaseMonster::IRelationship( pTarget );
}
//===========================================================

//=========================================================
// Classify - indicates this monster's place in the
// relationship table.
//=========================================================
int CTrolley :: Classify ( void )
{
return	CLASS_PLAYER_ALLY;
}

//=========================================================
// Center - returns the real center of the trolley guy.The
// bounding box is much larger than the actual creature so
// this is needed for targeting
//=========================================================
Vector CTrolley :: Center ( void )
{
return Vector( pev->origin.x, pev->origin.y, pev->origin.z + 6 );
}

Vector CTrolley :: BodyTarget( const Vector &posSrc )
{
return Center( );
}

//=========================================================
// SetYawSpeed - allows each sequence to have a different
// turn rate associated with it.
//=========================================================
void CTrolley :: SetYawSpeed ( void )

{
int ys;
switch ( m_Activity )
{
case ACT_IDLE:
	ys = 60;
	break;
//case ACT_RUN:
case ACT_WALK:
	ys = 90;
	break;
case ACT_TURN_LEFT:
case ACT_TURN_RIGHT:
	ys = 180;
	break;
default:
	ys = 45;
	break;
}
pev->yaw_speed = ys;
}

int CTrolley :: TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType )
{
// Drone take 15% damage from normal attacks
if ( bitsDamageType == DMG_BULLET || DMG_BLAST || DMG_SHOCK )
{
//	Vector vecDir = pev->origin - (pevInflictor->absmin + pevInflictor->absmax) * 0.5;
//	vecDir = vecDir.Normalize();
//	float flForce = DamageForce( flDamage );
//	pev->velocity = pev->velocity + vecDir * flForce;
	flDamage *= 0;
}
	if ( bitsDamageType == DMG_SLASH )
{
//	Vector vecDir = pev->origin - (pevInflictor->absmin + pevInflictor->absmax) * 0.5;
//	vecDir = vecDir.Normalize();
//	float flForce = DamageForce( flDamage );
//	pev->velocity = pev->velocity + vecDir * flForce;
	flDamage *= 0.1;
}
// Old code has this "HACK" warning.
if ( IsAlive() )
	PainSound();
return CBaseMonster::TakeDamage( pevInflictor, pevAttacker, flDamage, bitsDamageType );
}

void CTrolley :: PainSound( void )
{
int pitch = 95 + RANDOM_LONG(0,9);
if (RANDOM_LONG(0,5) < 2)
	EMIT_SOUND_DYN ( ENT(pev), CHAN_VOICE, pPainSounds[ RANDOM_LONG(0,ARRAYSIZE(pPainSounds)-1) ], 1.0, ATTN_NORM, 0, pitch );
}
/*
void CTrolley :: AlertSound( void )
{
int pitch = 95 + RANDOM_LONG(0,9);
EMIT_SOUND_DYN ( ENT(pev), CHAN_VOICE, pAlertSounds[ RANDOM_LONG(0,ARRAYSIZE(pAlertSounds)-1) ], 1.0, ATTN_NORM, 0, pitch );
}

void CTrolley :: IdleSound( void )
{
int pitch = 95 + RANDOM_LONG(0,9);
// Play a random idle sound
EMIT_SOUND_DYN ( ENT(pev), CHAN_VOICE, pIdleSounds[ RANDOM_LONG(0,ARRAYSIZE(pIdleSounds)-1) ], 1.0, ATTN_NORM, 0, 100 + RANDOM_LONG(-5,5) );
}

void CTrolley :: AttackSounds( void )
{
// Play a random attack sound
EMIT_SOUND_DYN ( ENT(pev), CHAN_VOICE, pAttackSounds[ RANDOM_LONG(0,ARRAYSIZE(pAttackSounds)-1) ], 1.0, ATTN_NORM, 0, 100 + RANDOM_LONG(-5,5) );
}
*/
//========================================================
// Zion's Corpses' Fade Function
//========================================================
void CTrolley::BecomeDead( void )
{

//if ( ShouldFadeOnDeath() )
//			{
				// this monster was created by a monstermaker... fade the corpse out.
				SUB_StartFadeOut();
//			}
//==================================================
//Intento de que no pete el sistema ARM: 26-1-2016
//==================================================
CBaseEntity *pOwner = CBaseEntity::Instance(pev->owner);
if ( pOwner )
{
	pOwner->DeathNotice( pev );
}
UTIL_Remove( this );
UpdateOnRemove();//NUevo. Sacado de GitHub 19-10-2016 (c)Solokiller
//======================================================
}

//=========================================================
// HandleAnimEvent - catches the monster-specific messages
// that occur when tagged animation frames are played.
//=========================================================
void CTrolley :: HandleAnimEvent( MonsterEvent_t *pEvent )
{
switch( pEvent->event )
{
	case TROLL_AE_ATTACK_RIGHT:
	{

//ALERT( at_console, "RELOAD!!\n" );
		CBaseEntity *pHurt = CheckTraceHullAttack( 0, -25, DMG_SLASH );// Si el segndo numero es negativo TE DA ESO DE SALUD
		if ( pHurt )
		{

			EMIT_SOUND_DYN ( ENT(pev), CHAN_WEAPON, pAttackHitSounds[ RANDOM_LONG(0,ARRAYSIZE(pAttackHitSounds)-1) ], 1.0, ATTN_NORM, 0, 100 + RANDOM_LONG(-5,5) );

		    GiveAmmo(600, "9mm",600);//
		}

		else // Play a random attack miss sound
			EMIT_SOUND_DYN ( ENT(pev), CHAN_WEAPON, pAttackMissSounds[ RANDOM_LONG(0,ARRAYSIZE(pAttackMissSounds)-1) ], 1.0, ATTN_NORM, 0, 100 + RANDOM_LONG(-5,5) );
	//	if (RANDOM_LONG(0,1))
	//		AttackSounds();

		pev->nextthink = gpGlobals->time + 5;//7-7-2015
	}
	break;
	default:
		CBaseMonster::HandleAnimEvent( pEvent );
		break;
}
}

//=========================================================
// Spawn
//=========================================================
void CTrolley :: Spawn()
{
Precache( );
SET_MODEL(ENT(pev), "models/monster_trolley.mdl");

UTIL_SetSize( pev, Vector( -32, -32, 0 ), Vector( 32, 32, 64 ) );//Será del tamaño del houndeye o del bullsquid ás o menos,,,
pev->solid			= SOLID_BBOX;//SOLID_SLIDEBOX;
pev->movetype		= MOVETYPE_STEP;
m_bloodColor		= DONT_BLEED;
pev->health			= 50;
pev->view_ofs		= VEC_VIEW;// position of the eyes relative to monster's origin.
m_flFieldOfView		= VIEW_FIELD_FULL;// indicates the width of this monster's forward view cone ( as a dotproduct result )
m_MonsterState		= MONSTERSTATE_HUNT;//MONSTERSTATE_NONE;
m_afCapability		= bits_CAP_DOORS_GROUP;
MonsterInit();
SetModelCollisionBox ();
}

//=========================================================
// Precache - precaches all resources this monster needs
//=========================================================
void CTrolley :: Precache()
{
int i;
PRECACHE_MODEL("models/monster_trolley.mdl");
for ( i = 0; i < ARRAYSIZE( pAttackHitSounds ); i++ )
	PRECACHE_SOUND((char *)pAttackHitSounds[i]);
for ( i = 0; i < ARRAYSIZE( pAttackMissSounds ); i++ )
	PRECACHE_SOUND((char *)pAttackMissSounds[i]);
for ( i = 0; i < ARRAYSIZE( pPainSounds ); i++ )
	PRECACHE_SOUND((char *)pPainSounds[i]);
}

void CTrolley::TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType )
{
bitsDamageType &= DMG_GENERIC;
if ( bitsDamageType == 0)
{
	if ( pev->dmgtime != gpGlobals->time || (RANDOM_LONG(0,100) < 20) )
	{
	Vector vecBlood = (ptr->vecEndPos - pev->origin).Normalize( );
	}
	flDamage *= 1.5;
}
CBaseMonster::TraceAttack( pevAttacker, flDamage, vecDir, ptr, bitsDamageType );
}

//===============================================================
// 6 Julio 2015
//===============================================================

int CTrolley :: GiveAmmo( int iCount, char *szName, int iMax )
{

CBaseEntity *pPlayer;

pPlayer = UTIL_FindEntityByClassname( NULL, "player" );

if (pPlayer->ammo_9mm <= 100)//limite de munición para que te recargue

{
pPlayer->GiveAmmo(600,"9mm",600); 
return TRUE;
}


return FALSE;
}

//=========================================================================
// Trolley AI specific Schedules ¿comentar para que SIEMPRE recargue?
//=========================================================================

int CTrolley::IgnoreConditions ( void )
{
int iIgnore = CBaseMonster::IgnoreConditions();
if ((m_Activity == ACT_MELEE_ATTACK1) || (m_Activity == ACT_MELEE_ATTACK1))
{
#if 0
	if (pev->health < 20)
		iIgnore |= (bits_COND_LIGHT_DAMAGE|bits_COND_HEAVY_DAMAGE);
	else
#endif
	if (m_flNextFlinch >= gpGlobals->time)
		iIgnore |= (bits_COND_LIGHT_DAMAGE|bits_COND_HEAVY_DAMAGE);
}
if ((m_Activity == ACT_SMALL_FLINCH) || (m_Activity == ACT_BIG_FLINCH))
{
	if (m_flNextFlinch < gpGlobals->time)
		m_flNextFlinch = gpGlobals->time + TROLL_FLINCH_DELAY;
}
return iIgnore;
}

//=================================================================================
// Fin del Trolley
//=================================================================================
Posted 6 years ago2018-02-01 19:41:59 UTC Post #338756
BOOL CTrolley::CheckMeleeAttack1( float flDot, float flDist )
{
// ALERT(at_aiconsole, "CheckMelee(%f, %f)\n", flDot, flDist);

if (flDot >= 0.7)
{
if (flDist <= 50)
return TRUE;
}
return FALSE;
}
Anything within 50 units and in front of the trolley gets ammo every time it attacks. The conditions for attacks is based on how much ammo they've got, however you return R_AL in IRelationship if they have enough ammo, which can cause the AI to still consider it. Return R_NO instead, see if that changes anything.

Also, your conditions aren't correct, if the player has exactly 100 ammo it relies on default relationship settings. Change the
if ( pTarget->ammo_9mm > 100 )
to
if ( pTarget->ammo_9mm >= 100 )
I'm assuming your code correctly updates ammo_9mm, which is SDK behavior. If it does not, you should correct that.
Posted 6 years ago2018-02-04 10:29:11 UTC Post #338772
It´s working!!, I have add some little changes and now it works like a charm!!, when I call the reload guy, he reloads who has less ammo than 100, if the player or bot has more than that, he passes away and search its new objective. More important: if it reloads a bot or another player, it DOES NOT reload you too; in the previous version the trolley guy reloads you and all the surrounding players.

This is the final cpp:

[quote][green]
/***
*
* Copyright (c) 1996-2002, Valve LLC. All rights reserved.
*
* This product contains software technology licensed from Id
* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc.
* All Rights Reserved.
*
  • This source code contains proprietary and confidential information of
  • Valve LLC and its suppliers. Access to this code is restricted to
  • persons who have executed a written SDK license with Valve. Any access,
  • use or distribution of this code by or to any unlicensed person is illegal.
*
****/[/green]

//=================================
// TROLLEY-RELOADER : Los tíos de la carretilla
// Modifications to the original zombie.cpp code
// (c) A.R 6-Julio-2015
// Final FIX (c) Solokiller 2-Feb-2018
//=================================

#include "extdll.h"
#include "util.h"
#include "cbase.h"
#include "monsters.h"
#include "squadmonster.h"
#include "weapons.h"
#include "effects.h"
#include "game.h"
//=========================
// Monster's Anim Events Go Here
//=========================

#define TROLL_AE_ATTACK_RIGHT 0x01
#define TROLL_FLINCH_DELAY 0
//==========================
// Monster BASIC stuff
//==========================

class CTrolley : public CBaseMonster
{
[blue]public:
[blue]void[/blue] Spawn( [blue]void[/blue] );
[blue]void[/blue] Precache( [blue]void[/blue] );
[blue]void[/blue] SetYawSpeed ( [blue]void[/blue] );
[blue]void[/blue] PainSound( [blue]void[/blue] );
[blue]void[/blue] HandleAnimEvent( MonsterEvent_t *pEvent );
Vector Center( [blue]void[/blue] );
Vector BodyTarget( const Vector &posSrc );
[blue]int[/blue] IRelationship( CBaseEntity *pTarget );
[blue]int[/blue] Classify ( [blue]void[/blue] );
[blue]int[/blue]	IgnoreConditions( [blue]void[/blue] );
/int CTrolley :: GiveAmmo( int iCount, char *szName, int iMax );/ ZWC
ARM 8-7-2015

//===================================// (c) Solokiller 2-Feb-2018//===================================
int CTrolley :: GiveAmmo( CBaseEntity* pPlayer, int iCount, char *szName, int iMax ); //===================================
int TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType );
BOOL CheckMeleeAttack1( float flDot, float flDist );
[blue]virtual float[/blue] GetDamageAmount( [blue]void[/blue] ) { [blue]return[/blue] 0;} 
[blue]virtual int[/blue] GetVoicePitch( [blue]void[/blue] ) { [blue]return[/blue] 100; }
[blue]virtual float[/blue] GetSoundVolue( [blue]void[/blue] ) { [blue]return[/blue] 1.0; }
[blue]static const char[/blue] *pPainSounds[];
[blue]static const char[/blue] *pAttackHitSounds[];
[blue]static const char[/blue] *pAttackMissSounds[];
//==================================
// ARM: Declaración de la Función TraceAttack,
// el tiempo de ejecución de
// las animaciones "flinch", la función de
// ignorar condiciones, la descripcion de
// datos ESTATICOS ( m_SaveData ) y la función que
// disuelve los cuerpos al morir.
//==================================

void TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType );
float m_flNextFlinch;
[blue]static[/blue]	TYPEDESCRIPTION m_SaveData[];

[blue]void[/blue] BecomeDead( [blue]void[/blue] );
};

const char *CTrolley::pAttackHitSounds[] =
{
"kid/reloadok1.wav",
"kid/reloadok2.wav",
"kid/reloadok3.wav",
};

const char *CTrolley::pAttackMissSounds[] =
{
"kid/reloadfail1.wav",
"kid/reloadfail2.wav",
};

const char *CTrolley::pPainSounds[] =
{
"kid/pain1.wav",
"kid/pain2.wav",
};

LINK_ENTITY_TO_CLASS( monster_trolley, CTrolley );

//==============================
// CheckMeleeAttack1 osea Recargar a las APU / RELOAD APUs
//==============================

BOOL CTrolley::CheckMeleeAttack1( float flDot, float flDist )
{
[blue]if[/blue] (flDot >= 0.7)
{
	[blue]if[/blue] (flDist <= 50)
	[blue]return[/blue] TRUE;
}
[blue]return[/blue] FALSE;
}

//==========================
//==========================
// Relationship
//==========================

int CTrolley::IRelationship( CBaseEntity *pTarget )
{
if (pTarget->ammo_9mm <= 100 && FClassnameIs( pTarget->pev, "player" ))
{
  [blue]return[/blue] R_NM;
}
[blue]if[/blue] ( pTarget->ammo_9mm >= 100 )
{
  [blue]return[/blue] R_FR;
}
[blue]if[/blue] (FBitSet(pTarget->pev->flags, FL_FAKECLIENT))
{
[blue]return[/blue] R_FR;
}
return CBaseMonster::IRelationship( pTarget );
}
//====================================

//=====================================
// Classify - indicates this monster's place in the
// relationship table.
//=====================================

int CTrolley :: Classify (void )
{
[blue]return[/blue]	CLASS_PLAYER_ALLY;
CBaseEntity *pTarget;[green]//New, just to try...[/green]
[blue]if[/blue] ( pTarget->ammo_9mm >= 100 )
{
	[blue]return[/blue] CLASS_NONE;
}
}
//=====================================
// Center - returns the real center of the trolley guy.The
// bounding box is much larger than the actual creature so
// this is needed for targeting
//=====================================

Vector CTrolley :: Center (void )
{
[blue]return[/blue] Vector( pev->origin.x, pev->origin.y, pev->origin.z + 6 );
}

Vector CTrolley :: BodyTarget( const Vector &posSrc )
{
[blue]return[/blue] Center( );
}

//=======================================
// SetYawSpeed - allows each sequence to have a different
// turn rate associated with it.
//=======================================

void CTrolley :: SetYawSpeed ( void )
{
[blue]int[/blue] ys;
[blue]switch[/blue] ( m_Activity )
{
[blue]case[/blue] ACT_IDLE: ys = 60;[blue]break;[/blue]
[blue]case[/blue] ACT_WALK: ys = 90;[blue]break[/blue];
[blue]case[/blue] ACT_TURN_LEFT:
[blue]case[/blue] ACT_TURN_RIGHT:ys = 180;[blue]break;[/blue]
[blue]default:[/blue]ys = 45;
[blue]break;[/blue]
}
pev->yaw_speed = ys;
}

int CTrolley :: TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType )
{
[blue]if[/blue] ( bitsDamageType == DMG_BULLET || DMG_BLAST || DMG_SHOCK )
{
		flDamage *= 0;
}
	[blue]if[/blue] ( bitsDamageType == DMG_SLASH )
{
	flDamage *= 1.1;
}
[blue]if[/blue] ( IsAlive() )
PainSound();
[blue]return[/blue] CBaseMonster::TakeDamage( pevInflictor, pevAttacker, flDamage, bitsDamageType );
}

void CTrolley :: PainSound( void )
{
[blue]int[/blue] pitch = 95 + RANDOM_LONG(0,9);
[blue]if[/blue] (RANDOM_LONG(0,5) < 2)
EMIT_SOUND_DYN ( ENT(pev), CHAN_VOICE, pPainSounds[ RANDOM_LONG(0,ARRAYSIZE(pPainSounds)-1) ], 1.0, ATTN_NORM, 0, pitch );
}
//================================
// Zion's Corpses' Fade Function
//================================

void CTrolley::BecomeDead( void )
{
[green]// monster created by a monstermaker... fade the corpse out.[/green]
SUB_StartFadeOut();
[green]
//=================================
//With this the game wont crash ARM: 26-1-2016
//=================================
[/green]
CBaseEntity *pOwner = CBaseEntity::Instance(pev->owner);
[blue]if [/blue]( pOwner )
{
	pOwner->DeathNotice( pev );
}
UTIL_Remove( [blue]this[/blue] );
UpdateOnRemove();[green]//NEW. from GitHub 19-10-2016 [b](c)Solokiller[/b]
//=====================================
[/green]
}//=====================================
// HandleAnimEvent - catches the monster-specific messages
// that occur when tagged animation frames are played.
//=====================================

void CTrolley :: HandleAnimEvent( MonsterEvent_t *pEvent )
{
[blue]switch[/blue]( pEvent->event )
{
[blue]case[/blue] TROLL_AE_ATTACK_RIGHT:
[green]/*
//===================================
// My version
//===================================
	{
		CBaseEntity *pHurt = CheckTraceHullAttack( 0, -25, DMG_SLASH );// Si el segndo numero es negativo TE DA ESO DE SALUD
		if ( pHurt )
		{
			EMIT_SOUND_DYN ( ENT(pev), CHAN_WEAPON, pAttackHitSounds[ RANDOM_LONG(0,ARRAYSIZE(pAttackHitSounds)-1) ], 1.0, ATTN_NORM, 0, 100 + RANDOM_LONG(-5,5) );
		    GiveAmmo(600, "9mm",600);
		}
		else // Play a random attack miss sound
		EMIT_SOUND_DYN ( ENT(pev), CHAN_WEAPON, pAttackMissSounds[ RANDOM_LONG(0,ARRAYSIZE(pAttackMissSounds)-1) ], 1.0, ATTN_NORM, 0, 100 + RANDOM_LONG(-5,5) );
		pev->nextthink = gpGlobals->time + 10;
	}
//=============================
*/
//=============================
// (c) Solokiller 2-Feb-2018
//=============================
[/green]
	[blue]if[/blue]( m_hEnemy != NULL && m_hEnemy->IsPlayer() ) 
	{
		CBaseEntity* pPlayer = [blue]static_cast[/blue]<CBaseEntity*>( [blue]static_cast[/blue]<CBaseEntity*>( m_hEnemy ) );
		GiveAmmo( pPlayer, 600,"9mm",600 );
pev->nextthink = gpGlobals->time + 10;
	} 
//=================================== break;
	[blue]default[/blue]:
	CBaseMonster::HandleAnimEvent( pEvent );
	[blue]break[/blue];
}
}

//==================================
// Spawn
//==================================

void CTrolley :: Spawn()
{
Precache( );
SET_MODEL(ENT(pev), "models/monster_trolley.mdl");
UTIL_SetSize( pev, Vector( -32, -32, 0 ), Vector( 32, 32, 64 ) );
pev->solid		= SOLID_BBOX;
pev->movetype		= MOVETYPE_STEP;
m_bloodColor		= DONT_BLEED;
pev->health		= 50;
pev->view_ofs		= VEC_VIEW;
m_flFieldOfView		= VIEW_FIELD_FULL;
m_MonsterState		= MONSTERSTATE_HUNT;
m_afCapability		= bits_CAP_DOORS_GROUP;
MonsterInit();
SetModelCollisionBox ();
}

//=====================================
// Precache - precaches all resources this monster needs
//=====================================

void CTrolley :: Precache()
{
[blue]int[/blue] i;
PRECACHE_MODEL("models/monster_trolley.mdl");
[blue]for[/blue] ( i = 0; i < ARRAYSIZE( pAttackHitSounds ); i++ )
	PRECACHE_SOUND(([blue]char[/blue] *)pAttackHitSounds[i]);
[blue]for[/blue] ( i = 0; i < ARRAYSIZE( pAttackMissSounds ); i++ )
	PRECACHE_SOUND(([blue]char[/blue] *)pAttackMissSounds[i]);
[blue]for[/blue] ( i = 0; i < ARRAYSIZE( pPainSounds ); i++ )
	PRECACHE_SOUND(([blue]char[/blue] *)pPainSounds[i]);
}

void CTrolley::TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType )
{
bitsDamageType &= DMG_GENERIC;
[blue]if[/blue] ( bitsDamageType == 0)
{
if ( pev->dmgtime != gpGlobals->time || (RANDOM_LONG(0,100) < 20) )
{
Vector vecBlood = (ptr->vecEndPos - pev->origin).Normalize( );
}
[blue]flDamage[/blue] *= 1.5;
}
CBaseMonster::TraceAttack( pevAttacker, flDamage, vecDir, ptr, bitsDamageType );
}

[green]
//=======================================
// 6 Julio 2015
//=======================================
/*
int CTrolley :: GiveAmmo( int iCount, char *szName, int iMax )
{
CBaseEntity *pPlayer;
pPlayer = UTIL_FindEntityByClassname( NULL, "player" );
if (pPlayer->ammo_9mm <= 100)//limite de munición para que te recargue
{
	pPlayer->GiveAmmo(600,"9mm",600);
	return TRUE;
}
 return FALSE;
}
*/

//============================
// Solokiller 2-Feb-2018
//============================
[/green]

int CTrolley :: GiveAmmo( CBaseEntity* pPlayer, int iCount, char *szName,int iMax )
{
if (pPlayer->ammo_9mm <= 100)//limite de munición para que te recargue
{ 
	pPlayer->GiveAmmo(600,"9mm",600);
	[blue]return[/blue] TRUE;
}
[blue]return[/blue] FALSE;
}
//====================================
// Trolley AI specific Schedules
//====================================

int CTrolley::IgnoreConditions (void )
{
int iIgnore = CBaseMonster::IgnoreConditions();
if ((m_Activity == ACT_MELEE_ATTACK1) || (m_Activity == ACT_MELEE_ATTACK1))
{
#if 0
	[blue]if[/blue] (pev->health < 20)
iIgnore |= (bits_COND_LIGHT_DAMAGE|bits_COND_HEAVY_DAMAGE);
else
#endif

if (m_flNextFlinch >= gpGlobals->time)
iIgnore |= (bits_COND_LIGHT_DAMAGE|bits_COND_HEAVY_DAMAGE);
}
if ((m_Activity == ACT_SMALL_FLINCH) || (m_Activity == ACT_BIG_FLINCH))
{
[blue]if[/blue] (m_flNextFlinch < gpGlobals->time)
m_flNextFlinch = gpGlobals->time + TROLL_FLINCH_DELAY;
}
[blue]return[/blue] iIgnore;
}

//================================
// Fin del Trolley
//================================

[/quote]

I´m so tired tonight. Tomorrow I will continue to edit the code... :zonked:
You must be logged in to post a response.