Jump to content

Droideka and Vehicle NPCs


Go to solution Solved by Serenity937,

Recommended Posts

Posted

Hi guys, time for another question. 

 

I've recently been playing around with NPCs to see if I can add some new enemies to the game for my Singleplayer maps and I thought it would be nice to make some experiments with the Droideka vehicle.

 

 First thing I did was create a new NPC with the CLASS_MARK1 because the vehicle weapons seems to now work in Singleplayer (Does anybody know why and if there's anyway to fix it?) and a simple script so that the deka wouldn't roll, just walk without the shield. It did work, but for some reason it shoots from its head instead of its hands. Pic related: . 

 

 

10miykx.jpg

 

 

Since I'm a man of science, I tried to see how did the Vehicle NPC shoot in Singleplayer, and I noticed that it did shoot from its arms with the "droideka_laser" weapon found in the vehicles/weapons folder of the pk3 but it shoots backwards. Pic related again:

 

e9x1dz.jpg

 

 

So question time:

 

- Does anybody know if I can make an NPC have a modded vehicle's weapon like the droideka's? How? 

- Is there any way to make it shoot not-backwards?

- Why does the CLASS_MARK1 NPC (also tried with stormtrooper, ATST and many other classes) shoot from its head instead of the hands? Is there any way I can fix it? How? 

 

Lancelot likes this
Posted

Tags. Looks like they need to be adjusted/added. Take a look at the mark1 model - what's the name of its muzzle tag? You need to change the Droideka model, adding the missing tag.

Noodle likes this
Posted

Tags. Looks like they need to be adjusted/added. Take a look at the mark1 model - what's the name of its muzzle tag? You need to change the Droideka model, adding the missing tag.

 

Sounds like a good idea, though I'm new at the whole moding thing. What software do I need to do that? The droideka has 4 muzzle tags named Muzzle1, muzzle2,muzzle3, and muzzle4. The mark1 has no muzzle tag, but a bunch of tags named 'flash' that are at both arms. 

 

Still, when I changed the NPC class to stormtrooper, or to ATST, it had the same problem. Even with a blaster rifle it kept shooting from the face. If the problem is still indeed a tag, how can I add them?

Posted (edited)

I think I fixed it in my prequel conversion mod, but I can't remember if I did or how I did it. :P

 

 

I am impressed! How did I never hear of this mod before? The Droideka worked quite well, only thing that seemed buggy was that sometimes this happened: 

 

5pleg4.jpg

 

Edit: I think the solution you had was to give the Deka an emplaced gun and change the effects so it looked like the vehicle's custom weapon. The only downside is that now the emplaced gun fires the droideka lasers. 

Edited by Noodle
Circa likes this
Posted

I am impressed! How did I never hear of this mod before? The Droideka worked quite well, only thing that seemed buggy was that sometimes this happened: 

 

 

 

Edit: I think the solution you had was to give the Deka an emplaced gun and change the effects so it looked like the vehicle's custom weapon. The only downside is that now the emplaced gun fires the droideka lasers. 

Yeah, the only real way of fixing it completely is to add a new weapon for it to use, via code. 

Noodle and Serenity937 like this
Posted

Yeah, the only real way of fixing it completely is to add a new weapon for it to use, via code. 

 

Thanks for the help! I'll stick to your solution since I have no coding knowledge.

  • Solution
Posted

Add a New NPC class with individual behaviour ,code in the animations, .dat file additions in code and file x2 different ways (MP Differes from SP),effects code.

 

Its was quite a fair bit of work.

switch( team )
		{// not sure if TEAM_ENEMY is appropriate here, I think I should be using NPC_class to check for behavior - dmv
		case TEAM_ENEMY:
			// special cases for enemy droids
			switch( NPC->client->NPC_class)
			{
			case CLASS_ATST:
				NPC_BehaviorSet_ATST( bState );
				return;
			case CLASS_PROBE:
				NPC_BehaviorSet_ImperialProbe(bState);
				return;
			case CLASS_DROIDEKA:
				NPC_BehaviorSet_DROIDEKA(bState);
				return;
			case CLASS_REMOTE:
				NPC_BehaviorSet_Remote( bState );
				return;

The behaviour state set up



/*
-------------------------
NPC_BehaviorSet_DROIDEKA
-------------------------
*/
void NPC_BehaviorSet_DROIDEKA( int bState )
{
	switch( bState )
	{
	case BS_STAND_GUARD:
	case BS_DEFAULT:
	case BS_PATROL:
	case BS_STAND_AND_SHOOT:
	case BS_HUNT_AND_KILL:
		NPC_BSDROIDEKA_Default();
		break;
	default:
		NPC_BehaviorSet_Default( bState );
		break;
	}
}

and the i made a whole new NPC AI set up for this bad boy



void G_DROIDEKACheckPain( gentity_t *self, gentity_t *other, const vec3_t point, int damage, int mod,int hitLoc )
{	
	if ( rand() & 1 )
	{
		G_SoundOnEnt( self, CHAN_LESS_ATTEN, "sound/chars/droideka/pain25" );
	}
	else
	{
		G_SoundOnEnt( self, CHAN_LESS_ATTEN, "sound/chars/droideka/pain100" );
	}
}
/*
-------------------------
NPC_DROIDEKA_Pain
-------------------------
*/
void NPC_DROIDEKA_Pain( gentity_t *self, gentity_t *inflictor, gentity_t *other, const vec3_t point, int damage, int mod,int hitLoc ) 
{
	G_DROIDEKACheckPain( self, other, point, damage, mod, hitLoc );
	NPC_Pain( self, inflictor, other, point, damage, mod );
}

/*
-------------------------
DROIDEKA_Hunt
-------------------------`
*/
void DROIDEKA_Hunt( qboolean visible, qboolean advance )
{

	//If we're not supposed to stand still, pursue the player
	if ( NPCInfo->standTime < level.time )
	{
		//Move towards our goal
		NPCInfo->goalEntity = NPC->enemy;
		NPCInfo->goalRadius = 12;
		NPC_MoveToGoal( qtrue );
	}

	if ( NPCInfo->goalEntity == NULL )
	{//hunt
		NPCInfo->goalEntity = NPC->enemy;
	}
	NPCInfo->combatMove = qtrue;
	NPC_MoveToGoal( qtrue );
	NPC_FaceEnemy();
	//Update our angles regardless
	NPC_UpdateAngles( qtrue, qtrue );

}

/*
-------------------------
DROIDEKA_Ranged
-------------------------
*/
void DROIDEKA_Ranged( qboolean visible, qboolean advance, qboolean altAttack )
{

	if ( TIMER_Done( NPC, "atkDelay" ) && visible )	// Attack?
	{
		TIMER_Set( NPC, "atkDelay", Q_irand( 500, 1000 ) );
		ucmd.buttons |= BUTTON_ATTACK;
	}

	if ( NPCInfo->scriptFlags & SCF_CHASE_ENEMIES )
	{
		DROIDEKA_Hunt( visible, advance );
	}
}

/*
-------------------------
DROIDEKA_Attack
-------------------------
*/
void DROIDEKA_Attack( void )
{
	qboolean	altAttack=qfalse;

	// Rate our distance to the target, and our visibilty
	float		distance	= (int) DistanceHorizontalSquared( NPC->currentOrigin, NPC->enemy->currentOrigin );	
	distance_e	distRate	= ( distance > MIN_MELEE_RANGE_SQR ) ? DIST_LONG : DIST_MELEE;
	qboolean	visible		= NPC_ClearLOS( NPC->enemy );
	qboolean	advance		= (qboolean)(distance > MIN_DISTANCE_SQR);
	

	if ( NPC_CheckEnemyExt() == qfalse )
	{
		NPC->enemy = NULL;
		DROIDEKA_Hunt( visible, advance );
		return;
	}

	NPC_FaceEnemy( qtrue );

	// If we cannot see our target, move to see it
	if ( visible == qfalse )
	{
		if ( NPCInfo->scriptFlags & SCF_CHASE_ENEMIES )
		{
			DROIDEKA_Hunt( visible, advance );
			return;
		}
	}

	// Decide what type of attack to do

	//If we're too far away, then keep walking forward
	if ( distRate != DIST_MELEE )
	{
		DROIDEKA_Hunt( visible, advance );
		return;
	}

	NPC_FaceEnemy( qtrue );

	DROIDEKA_Ranged( visible, advance,altAttack );
}

/*
-------------------------
DROIDEKA_Patrol
-------------------------
*/
void DROIDEKA_Patrol( void )
{
	if ( NPC_CheckPlayerTeamStealth() )
	{
		NPC_UpdateAngles( qtrue, qtrue );
		return;
	}

	//If we have somewhere to go, then do that
	if (!NPC->enemy)
	{
		if ( UpdateGoal() )
		{
			ucmd.buttons |= BUTTON_WALKING;
			NPC_MoveToGoal( qtrue );
			NPC_UpdateAngles( qtrue, qtrue );
		}
	}

}

/*
-------------------------
DROIDEKA_Idle
-------------------------
*/
void DROIDEKA_Idle( void )
{
	BubbleShield_Update();
}

/*
-------------------------
NPC_BSDROIDEKA_Default
-------------------------
*/
void NPC_BSDROIDEKA_Default( void )
{
	if ( NPC->enemy )
	{
		if( (NPCInfo->scriptFlags & SCF_CHASE_ENEMIES) )
		{
			NPCInfo->goalEntity = NPC->enemy;
		}
		DROIDEKA_Attack();
	}
	else if ( NPCInfo->scriptFlags & SCF_LOOK_FOR_ENEMIES )
	{
		DROIDEKA_Patrol();
	} 
	else
	{
		DROIDEKA_Idle();
	}
}

as a result ,you can script the decca easily.

 

Did the same with SBD also.

 

you can download examples of the code and build your own version

 

http://www.moddb.com/mods/serenitysabersystems/addons/serenityjedienginesdk

NumberWan and Noodle like this
Posted

Add a New NPC class with individual behaviour ,code in the animations, .dat file additions in code and file x2 different ways (MP Differes from SP),effects code.

 

Its was quite a fair bit of work.

switch( team )
		{// not sure if TEAM_ENEMY is appropriate here, I think I should be using NPC_class to check for behavior - dmv
		case TEAM_ENEMY:
			// special cases for enemy droids
			switch( NPC->client->NPC_class)
			{
			case CLASS_ATST:
				NPC_BehaviorSet_ATST( bState );
				return;
			case CLASS_PROBE:
				NPC_BehaviorSet_ImperialProbe(bState);
				return;
			case CLASS_DROIDEKA:
				NPC_BehaviorSet_DROIDEKA(bState);
				return;
			case CLASS_REMOTE:
				NPC_BehaviorSet_Remote( bState );
				return;

The behaviour state set up



/*
-------------------------
NPC_BehaviorSet_DROIDEKA
-------------------------
*/
void NPC_BehaviorSet_DROIDEKA( int bState )
{
	switch( bState )
	{
	case BS_STAND_GUARD:
	case BS_DEFAULT:
	case BS_PATROL:
	case BS_STAND_AND_SHOOT:
	case BS_HUNT_AND_KILL:
		NPC_BSDROIDEKA_Default();
		break;
	default:
		NPC_BehaviorSet_Default( bState );
		break;
	}
}

and the i made a whole new NPC AI set up for this bad boy



void G_DROIDEKACheckPain( gentity_t *self, gentity_t *other, const vec3_t point, int damage, int mod,int hitLoc )
{	
	if ( rand() & 1 )
	{
		G_SoundOnEnt( self, CHAN_LESS_ATTEN, "sound/chars/droideka/pain25" );
	}
	else
	{
		G_SoundOnEnt( self, CHAN_LESS_ATTEN, "sound/chars/droideka/pain100" );
	}
}
/*
-------------------------
NPC_DROIDEKA_Pain
-------------------------
*/
void NPC_DROIDEKA_Pain( gentity_t *self, gentity_t *inflictor, gentity_t *other, const vec3_t point, int damage, int mod,int hitLoc ) 
{
	G_DROIDEKACheckPain( self, other, point, damage, mod, hitLoc );
	NPC_Pain( self, inflictor, other, point, damage, mod );
}

/*
-------------------------
DROIDEKA_Hunt
-------------------------`
*/
void DROIDEKA_Hunt( qboolean visible, qboolean advance )
{

	//If we're not supposed to stand still, pursue the player
	if ( NPCInfo->standTime < level.time )
	{
		//Move towards our goal
		NPCInfo->goalEntity = NPC->enemy;
		NPCInfo->goalRadius = 12;
		NPC_MoveToGoal( qtrue );
	}

	if ( NPCInfo->goalEntity == NULL )
	{//hunt
		NPCInfo->goalEntity = NPC->enemy;
	}
	NPCInfo->combatMove = qtrue;
	NPC_MoveToGoal( qtrue );
	NPC_FaceEnemy();
	//Update our angles regardless
	NPC_UpdateAngles( qtrue, qtrue );

}

/*
-------------------------
DROIDEKA_Ranged
-------------------------
*/
void DROIDEKA_Ranged( qboolean visible, qboolean advance, qboolean altAttack )
{

	if ( TIMER_Done( NPC, "atkDelay" ) && visible )	// Attack?
	{
		TIMER_Set( NPC, "atkDelay", Q_irand( 500, 1000 ) );
		ucmd.buttons |= BUTTON_ATTACK;
	}

	if ( NPCInfo->scriptFlags & SCF_CHASE_ENEMIES )
	{
		DROIDEKA_Hunt( visible, advance );
	}
}

/*
-------------------------
DROIDEKA_Attack
-------------------------
*/
void DROIDEKA_Attack( void )
{
	qboolean	altAttack=qfalse;

	// Rate our distance to the target, and our visibilty
	float		distance	= (int) DistanceHorizontalSquared( NPC->currentOrigin, NPC->enemy->currentOrigin );	
	distance_e	distRate	= ( distance > MIN_MELEE_RANGE_SQR ) ? DIST_LONG : DIST_MELEE;
	qboolean	visible		= NPC_ClearLOS( NPC->enemy );
	qboolean	advance		= (qboolean)(distance > MIN_DISTANCE_SQR);
	

	if ( NPC_CheckEnemyExt() == qfalse )
	{
		NPC->enemy = NULL;
		DROIDEKA_Hunt( visible, advance );
		return;
	}

	NPC_FaceEnemy( qtrue );

	// If we cannot see our target, move to see it
	if ( visible == qfalse )
	{
		if ( NPCInfo->scriptFlags & SCF_CHASE_ENEMIES )
		{
			DROIDEKA_Hunt( visible, advance );
			return;
		}
	}

	// Decide what type of attack to do

	//If we're too far away, then keep walking forward
	if ( distRate != DIST_MELEE )
	{
		DROIDEKA_Hunt( visible, advance );
		return;
	}

	NPC_FaceEnemy( qtrue );

	DROIDEKA_Ranged( visible, advance,altAttack );
}

/*
-------------------------
DROIDEKA_Patrol
-------------------------
*/
void DROIDEKA_Patrol( void )
{
	if ( NPC_CheckPlayerTeamStealth() )
	{
		NPC_UpdateAngles( qtrue, qtrue );
		return;
	}

	//If we have somewhere to go, then do that
	if (!NPC->enemy)
	{
		if ( UpdateGoal() )
		{
			ucmd.buttons |= BUTTON_WALKING;
			NPC_MoveToGoal( qtrue );
			NPC_UpdateAngles( qtrue, qtrue );
		}
	}

}

/*
-------------------------
DROIDEKA_Idle
-------------------------
*/
void DROIDEKA_Idle( void )
{
	BubbleShield_Update();
}

/*
-------------------------
NPC_BSDROIDEKA_Default
-------------------------
*/
void NPC_BSDROIDEKA_Default( void )
{
	if ( NPC->enemy )
	{
		if( (NPCInfo->scriptFlags & SCF_CHASE_ENEMIES) )
		{
			NPCInfo->goalEntity = NPC->enemy;
		}
		DROIDEKA_Attack();
	}
	else if ( NPCInfo->scriptFlags & SCF_LOOK_FOR_ENEMIES )
	{
		DROIDEKA_Patrol();
	} 
	else
	{
		DROIDEKA_Idle();
	}
}

as a result ,you can script the decca easily.

 

Did the same with SBD also.

 

you can download examples of the code and build your own version

 

http://www.moddb.com/mods/serenitysabersystems/addons/serenityjedienginesdk

 

I'm impressed! I guess now its a good time to learn a bit of coding. 

Posted

Honestly mate! Its worth trying your hand at coding. Think small and start small,Set yourself a realistic goal,something small and you wont get overwhelmed at the start.

Stay on one topic ,Animations is where i started. swapping them about.

 

For your purpose i would select Class system.

 

Get the openjk code (Its the best,stable and nice and clean).

 

Then learn everything by searching through the code for 1 class type i suggest  CLASS_R2D2. its a simple set up not too different to how you might want a decca to act.

 

Unless your a genius i suggest doing a simple search for tutorials and also other released SDK ,s to learn from.  :winkthumb:

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...