Version 2, last updated by Luke S at 17 Jan 01:37 UTC

Just some idea to simplify enemy entity coding. If you got any feedback please

#define DEATHLENGTH 480
#include <enemy> 

/* Public Function */
// None

/* Local variable */
new HitCount;
new RandomDelay = 2000;

new LeapCount = 2000;
/* Display Object */
new body[EntityGraphic] = { NULLOBJECT, 0, 24, 0 };	// Display Object, Offset x, Offset y, Offset z
new head[EntityGraphic] = { NULLOBJECT, 0, 0, 1 };		// Display Object, Offset x, Offset y, Offset z
new object:shadow = NULLOBJECT;

/* Collisions Settings */
new hitzone[3][RECT] = { 
	{ 4, 28, 24, 24 }, // Body 
	{ -16, 16, 64, 56 }, // Attack Alert
	{ 4, 28, 24, 16 }, // jumping body
};

START_SETUP
	_speed_ = 50;
	_damage_ = 50;
	_health_ = _maxhealth_ = 100;

	dw = dh =  32;

	SetStateGraphic( STANDING, "enemy_bones01.png", "front_0", "side_0", "back_0", "side_0" );
	SetStateGraphic( MOVING, "enemy_bones01.png", "front", "side", "back", "side" );
	SetStateGraphic( LEAPING, "enemy_bones01.png", "stomp", "stomp", "stomp", "stomp" );
END_SETUP

/* Function */
public Init(...)
{
	EnemyInit();

	/* Retrive Display Objects */
	body[egOBJ] = object:EntityGetNumber("object-id");
	head[egOBJ] = ObjectCreate( "enemy_bones01.png:head_front", SPRITE, dx, dy, 4, 0, 0, WHITE );
	shadow = ObjectCreate( "", CIRCLE, dx, dy+32, 2, 16, 8, 0x000000DD );


	ShowObjects( head[egOBJ], body[egOBJ], shadow );

}

main()
{
	if ( _state_ == GONE || GameState() != 1 )
		return;

	if ( StateChanged() )
	{
		ResetObjects( head[egOBJ], body[egOBJ] );
	}


	new q = (_state_ == LEAPING ? 2 : 0);
	CollisionSet(SELF, 0, TYPE_ENEMY, dx + hitzone[q][rX], dy + hitzone[q][rY], hitzone[q][rW], hitzone[q][rH] );
	CollisionSet(SELF, 1, TYPE_ENEMY, dx + hitzone[1][rX], dy + hitzone[1][rY], hitzone[1][rW], hitzone[1][rH] );

	switch( _state_ )
	{
		case STANDING:
			Stand();
		case MOVING:
			Move();
		case LEAPING:
			Leap();
		case HIT:
			Hurt();
		case DYING:
			HandleDying();
		case SPECIALSTATE:
			Special();
		case DEAD:
		{
			HideObjects( head[egOBJ], body[egOBJ], shadow );
			CollisionSet(SELF, -1, 0);
			SetState(GONE);
			return;
		}
	}

	UpdateEntityGraphics( head );
	UpdateEntityGraphics( body );
	ObjectPosition( shadow, dx+4, dy+48, 2, 24, 8);
}

public Close()
{
	CollisionSet(SELF, -1, 0);
	ObjectDelete(shadow);
	ObjectDelete(head[egOBJ]);
}

/* Local Function */
SetHeadDir(head_direction)
{
	head_direction %= 8;
	switch ( head_direction ) 
	{
		case 1:
			ReplaceEntityGraphics( head, "enemy_bones01.png:head_side", false );
		case 2:
			ReplaceEntityGraphics( head, "enemy_bones01.png:head_front", false );
		case 3:
			ReplaceEntityGraphics( head, "enemy_bones01.png:head_side", true );
		default:
			ReplaceEntityGraphics( head, "enemy_bones01.png:head_front", false );
	}
}

/* States */
STATEFUNCTION Move()
{
	ReplaceEntityGraphics( body, STATE_GRAPHIC, STATE_FLIP );
	SetHeadDir(_dir_);
	
	if ( !random(30) ) // Change Direction
	{
		RandomizeMovement();
		SetState(STANDING);
	}
	else
	{
		EntityMove( MASK_ENEMYSOLID2 );
	}
}


STATEFUNCTION Leap()
{
	ReplaceEntityGraphics( body, STATE_GRAPHIC, STATE_FLIP );
	EntityMove( MASK_ENEMYSOLID2 );

	if ( Countdown(LeapCount) ) // Check the hit counter
	{
		SetState(STANDING);
		RandomizeMovement();
		CheckHealth();
	}
	
}

STATEFUNCTION Stand()
{
	ReplaceEntityGraphics( body, STATE_GRAPHIC, STATE_FLIP );
	
	if ( !random(8) ) // 1 in 8 change to look around
	{
		new head_direction = _dir_;
		if ( random(2) )
			head_direction+=2;
		else
			head_direction-=2;
		SetHeadDir(head_direction);
	}

	if ( !random(60) ) // Start Moving Again
	{
		_angle_ = Dir2Angle(random(8));
		SetState(MOVING);
	}
}



STATEFUNCTION Hurt()
{
	CollisionSet(SELF, -1, 0);
	EntityMove(MASK_ENEMYSOLID2);

	new q = (HitCount % 100) / 20;
	ColourEntityGraphics(body, hit_colours[q]);
	ColourEntityGraphics(head, hit_colours[q]);

	EntityMove( MASK_ENEMYSOLID2 );

	if ( Countdown(HitCount) ) // Check the hit counter
	{
		SetState(MOVING);
		RandomizeMovement();
		CheckHealth();
	}
}

STATEFUNCTION Special()
{

	switch ( current_effect )
	{
		case STUNNED:
		{
			StunnedEffect( effect_count );
			ReplaceEntityGraphics( body, "enemy_bones01.png:front_0", false );
		}
		case FROZEN:
		{
			ReplaceEntityGraphics( body, "enemy_bones01.png:front_0", false );
			ColourEntityGraphics( body, 0x0000FFFF);
		}
		case SHOCKED:
		{
		}
		case BURNING:
		{
		}
		default:
		{
			SetState(STANDING);
			return;
		}
	}

	if ( Countdown(effect_count) ) //Reset State
	{
		SetState(STANDING);
	}

}



/* Public Functions */
PUBLICFUNCTIONHIT
{
	if ( _state_ == HIT || _state_ == DYING || _state_ == GONE )
		return;

	strcopy( _attacker_, attacker );

	if ( attack&APLAYER == APLAYER )
	{
		EntityPublicFunction( _attacker_, "Hurt", "nnn", ASWORD, _damage_, angle );
	}
	else if ( _state_ != HIT)
	{
		if ( rect == 1 )
		{
			_angle_ = fatan2(fixed:(x-dx), fixed:(y-dy), degrees);
			SetState(LEAPING);
			LeapCount = 2000;
		}
		else
		{
			
			AudioPlaySound( "enemy_hurt.wav", dx, dy );
			_state_ = HIT;
			_health_ -= damage;
			HitCount = 1000;
			
			//_angle_ = fatan2(fixed:(dx-x), fixed:(dy-y), degrees);
			Hurt();
		}
	}
	CheckHealth();
}