It's very basic, but here it is...
[pascal]
unit particle;

interface

type
// a single particle
TParticle = record
state : integer; // state of the particle
typ : integer; // type of particle effect
x,y : integer; // world position of particle
xv,yv : real; // velocity of particle
curr_color_r : integer; // the current rendering color of particle
curr_color_g : integer; // the current rendering color of particle
curr_color_b : integer; // the current rendering color of particle
start_color_r : integer; // the start color or range effect
start_color_g : integer; // the start color or range effect
start_color_b : integer; // the start color or range effect
end_color_r : integer; // the ending color of range effect
end_color_g : integer; // the ending color of range effect
end_color_b : integer; // the ending color of range effect
counter : integer; // general state transition timer
max_count : integer; // max value for counter
end;

const
// defines for particle system
PARTICLE_STATE_DEAD = 0;
PARTICLE_STATE_ALIVE = 1;

// types of particles
PARTICLE_TYPE_FLICKER = 0;
PARTICLE_TYPE_FADE = 1;

// color of particle
PARTICLE_COLOR_RED = 0;
PARTICLE_COLOR_GREEN = 1;
PARTICLE_COLOR_BLUE = 2;
PARTICLE_COLOR_WHITE = 3;

MAX_PARTICLES = 20;

// color ranges
COLOR_RED_START = 32;
COLOR_RED_END = 47;

COLOR_GREEN_START = 96;
COLOR_GREEN_END = 111;

COLOR_BLUE_START = 144;
COLOR_BLUE_END = 159;

COLOR_WHITE_START = 16;
COLOR_WHITE_END = 31;

var
particles : array[0..MAX_PARTICLES] of TParticle;
particle_wind : integer;
particle_gravity : real;

procedure ResetExplosionParticles;

procedure Draw;

procedure Move;

procedure Explode( aX, aY : integer );

implementation

uses
common;

procedure ResetExplosionParticles;
var
index, angle, velocity : integer;
begin
Randomize;

// loop thru and reset all the particles to dead
for index := 0 to MAX_PARTICLES do
begin
// compute random trajectory angle
angle := random( 360 );
// compute random trajectory velocity
velocity := random( 4 ) + 2;
particles[ index ].state := PARTICLE_STATE_ALIVE;
particles[ index ].typ := PARTICLE_TYPE_FADE;
particles[ index ].x := 0;
particles[ index ].y := 0;
particles[ index ].xv := Trunc( cos(angle) * velocity );
particles[ index ].yv := Trunc( sin(angle) * velocity );
particles[ index ].start_color_r := COLOR_RED_START;
particles[ index ].end_color_r := COLOR_RED_END;
particles[ index ].curr_color_r := particles[ index ].start_color_r;
particles[ index ].counter := 0;
particles[ index ].max_count := random( 3 ) + 3;
end;
end;

procedure Move;
var
index : integer;
begin
for index := 0 to MAX_PARTICLES do
begin
// test if this particle is alive
if (particles[index].state = PARTICLE_STATE_ALIVE) then
begin
// translate particle
particles[index].x := Trunc(particles[index].x + particles[index].xv);
particles[index].y := Trunc(particles[index].y + particles[index].yv);

// update velocity based on gravity and wind
particles[index].xv := particles[index].xv + particle_wind;
particles[index].yv := particles[index].yv + particle_gravity;

// now based on type of particle perform proper animation
if (particles[index].typ = PARTICLE_TYPE_FLICKER ) then
begin
// simply choose a color in the color range and assign it to the current color
particles[index].curr_color_r := Random( particles[index].start_color_r ) + particles[index].end_color_r;
particles[index].curr_color_g := Random( particles[index].start_color_g ) + particles[index].end_color_g;
particles[index].curr_color_b := Random( particles[index].start_color_b ) + particles[index].end_color_b;

// now update counter
particles[index].counter := particles[index].counter + 1;
if (particles[index].counter >= particles[index].max_count) then
begin
// kill the particle
particles[index].state := PARTICLE_STATE_DEAD;
end; // end if
end // end if
else
begin
// must be a fade, be careful!
// test if it's time to update color
particles[index].counter := particles[index].counter + 1;
if (particles[index].counter >= particles[index].max_count) then
begin
// reset counter
particles[index].counter := 0;

// update color
particles[index].curr_color_r := particles[index].curr_color_r + 1;
if ( particles[ index ].curr_color_r > particles[index].end_color_r ) then
begin
// transition is complete, terminate particle
particles[index].state := PARTICLE_STATE_DEAD;

end; // end if

end; // end if

end; // end else

end; // end if

end; // end for index
end;

procedure Draw;
var
index, x, y : integer;
begin
for index := 0 to MAX_PARTICLES do
begin
// test if particle is alive
if (particles[index].state = PARTICLE_STATE_ALIVE) then
begin
// render the particle, perform world to screen transform
x := particles[ index ].x;
y := particles[ index ].y;

// test for clip
if ( x >= screenWidth )
or ( x < 0 )
or ( y >= screenHeight )
or ( y < 0 ) then
break;

// draw the pixel
SetColor(particles[index].curr_color_r, particles[index].curr_color_g, particles[index].curr_color_b);
Plot(x, y);
end; // end if

end; // end for index
end;

procedure Explode( aX, aY : integer );
var
index : integer;
begin
// loop thru and set start position of to dead
for index := 0 to MAX_PARTICLES do
begin
particles[ index ].x := aX + random( 2 );
particles[ index ].y := aY + random( 3 );
end;
end;

initialization
particle_wind := 0;
particle_gravity := 0.2;

end.
[/pascal]

The only problem I noticed is that the colours don't seem to change, so I will need to sort that out. All the particles seem to appear as black at the moment.

I also want to change the sin/cos function calls to look-up tables which I will store in my "common" unit. Not sure if it will speed things up, as it seems fine at the moment, but I suppose it couldn't hurt.