These are all most CV1 enemies, but coded in the CV3 style (for compatibility with my long-overdue project). They should still run the same for the most part, as the only real changes between CV1 and CV3 codes were some complexities of state machines (CV1 wasn't very efficient) and how things like invincibility were handled.
(Yes, I'm aware I named all the duplicate enemy states XXXX2 even though these were the original CV enemies. I didn't start with CV1's code and didn't feel like renaming everything.)
CV1 Bat
timeline_index = st_flybat2
It's a pretty simple one, even for a CV3 conversion.
switch timeline_position
{
case 0:
status |= MOVING;
sprite_index = spr_Bat;
image_speed = 1/8;
y = Belmont.y + 1;
ystart += 8;
en_xscale_set();
vspd = 0;
hspd = 9/8 * image_xscale;
timeline_position += 1;
case 1:
move_sinewave(3);
break;
}
CV1 Sleeping Bat
timeline_index = st_zzzbat2
Much simpler than the CV3 sleeping bat, as it just flies straight.
switch timeline_position
{
case 0:
sprite_index = spr_SleepBat;
image_index = 0;
image_speed = 0;
status |= STILL;
timeline_position += 1;
break;
case 1: //83FF
if abs(Belmont.y-y) < $38
if abs(Belmont.x-x) < $60
{
timeline_position += 1;
en_xscale_set();
hspd = 3/2 * image_xscale;
vspd = 3/2;
image_index += 1;
status &= ~STILL;
status |= MOVING;
}
break;
case 2:
vspd -= 1/32;
if vspd<0
timeline_position += 1;
break;
case 3:
vspd = 0;
break;
}
CV1 Medusa Head
timeline_index = st_medhead2
Nearly the same as the bat, but with a larger wave amplitude.
switch timeline_position
{
case 0:
sprite_index = spr_MedHead;
image_speed = 1/8;
status |= MOVING;
en_xscale_set();
vspd = 2;
hspd = 5/4 * image_xscale;
timeline_position += 1;
break;
case 1:
move_sinewave(0);
break;
}
CV1 Panther
timeline_index = st_panther
This was the first CV1 enemy I studied and translated into CV3 code.
switch timeline_position
{
case 0:
sprite_index = spr_Panther;
image_index = 0;
image_speed = 0;
status |= STILL;
status &= ~MOVING;
timeline_position += 1;
break;
case 1:
if abs(x-Belmont.x) < $40
{
en_xscale_set();
image_index = 1;
image_speed = 1/7;
status |= MOVING;
hspd = 2 * image_xscale;
timeline_position += 1;
}
break;
case 2:
if !tile_map_read($2E) //check if no collision below
{
image_index = 1;
status |= STILL;
vspd = -3/2;
hspd = 2 * image_xscale;
timeline_position += 1;
}
break;
case 3:
vspd += 1/8;
if vspd > 0
if tile_map_read($2E) //check if collision below
{
y &= ~7;
vspd = 0;
en_xscale_set();
hspd = 2 * image_xscale;
status &= ~STILL;
image_index = 1;
timeline_position = 2;
}
break;
}
CV1 Ghoul
timeline_index = st_ghoul
As you'd expect from the Goomba of Castlevania, the code is simple.
switch timeline_position
{
case 0:
sprite_index = spr_Ghoul;
status |= MOVING;
image_index = 0;
image_speed = 1/8;
en_xscale_set();
hspd = 7/8 * image_xscale);
timeline_position += 1;
break;
case 1:
if !tile_map_read($D,0) //check for no collision below
{
hspd = 0;
vspd = 1;
timeline_position += 1;
}
else
if tile_map_read($7,0)
move_horz_rev(1);
break;
case 2:
if tile_map_read($D,0) //check for collision below
{
move_stop();
hspd = 7/8 * image_xscale;
timeline_position = 1;
}
break;
}
CV1 Merman
timeline_index = st_merman2
switch timeline_position
{
case 0:
case 6:
play_sound(snd_0E) /*splash sound*/);
for({var i; i=0;} i<4; i+=1;)
{
with spawn_watersplash(0,0)
switch i
{
case 0:
move_horz_set($30/$100,1);
move_vert_set($280/$100,1);
break;
case 1:
move_horz_set($60/$100,1);
move_vert_set($140/$100,1);
break;
case 2:
move_horz_set($60/$100,1);
move_horz_set($140/$100,1);
break;
case 3:
move_horz_set($30/$100,0);
move_horz_set($280/$100,1);
break;
}
}
if timeline_position == 6
{
instance_destroy();
break;
}
sprite_replace(myIndex,"MermanJump.gif",0,0,0,8,16);
image_speed = 0;
en_xscale_set();
status |= STILL | MOVING;
alarm[3] = 0;
timeline_position = 1;
break;
case 1:
vspd += 1/8;
if vspd < 0 break;
if y - view_yview > $C0
timeline_position = 6;
else
if tile_map_read(0,0) //check for collision below
{
if !alarm[3]
{
alarm[3] = 1;
play_sound(snd_0D) /*thud sound*/);
}
y &= ~$F;
en_xscale_set();
status &= ~STILL;
image_speed = 1/8;
alarm[2] = 8;
timeline_position = 2;
}
break;
case 2:
alarm[2] -= 1;
if !alarm[2]
{
hspd = 3/4 * image_xscale;
status |= MOVING;
switch irandom(3)
{
case 0: alarm[2] = $4F; break;
case 1: alarm[2] = $79; break;
case 2: alarm[2] = $5D; break;
case 3: alarm[2] = $90; break;
}
timeline_position = 3;
}
break;
case 3:
alarm[2] -= 1;
if alarm[2]
{
if !tile_map_read(0,0) //check for no collision below
{
timeline_position = 1;
hspd = 0;
image_index = 0;
}
}
else
{
image_index = 2;
alarm[2] = $10;
timeline_position = 4;
}
break;
case 4:
alarm[2] -= 1;
if !alarm[2]
{
with spawn_fireball(0,-8) //remember to set fireball's image_xscale upon creation
hspd = 7/4 * image_xscale;
alarm[2] = $10;
timeline_position = 5;
}
break;
case 5:
alarm[2] -= 1;
if !alarm[2]
{
en_xscale_set();
image_index = 0;
switch irandom(3)
{
case 0: alarm[2] = $4F; break;
case 1: alarm[2] = $79; break;
case 2: alarm[2] = $5D; break;
case 3: alarm[2] = $90; break;
}
timeline_position = 3;
}
}
CV1 Ghost
timeline_index = st_ghost2
Very little was edited in this, hence the odd format. Remember sc_cvbat1 is found in the Giant Bat's code in the previous post.
alarm[2] -= 1;
switch timeline_position
{
case 0:
sprite_index = spr_Ghost;
image_speed = 1/8;
timeline_position += 1;
status |= MOVING;
case 1:
if !alarm[2]
{
alarm[2] = $20;
var temp;
temp[1] = sc_cvbat1(0,0);
temp[0] = temp[1] & 1;
temp[1] = temp[1] >> 1;
temp[1] -= temp[1] >> 2;
temp[1] /= $100;
if temp[0]
{
hspd = temp[1] * image_xscale);
if alarm[5] vspd = -3/4;
else vspd = 3/4;
}
else
{
if alarm[5] vspd = -temp[1];
else vspd = temp[1];
hspd = 3/4 * image_xscale;
}
}
}
CV1 Fleaman
timeline_index = st_fleaman2
Both the lurking Fleaman and the one dropped by Harpies use the same code.
switch timeline_position
{
case 0:
if !alarm[2]
alarm[2] = $3C;
alarm[2] -= 1;
if !alarm[2]
{
sprite_index = spr_Fleaman;
image_speed = 0;
status |= STILL | MOVING;
timeline_position = 1;
}
break;
case 1:
vspd += 1/8;
if tile_map_read(0,0) //(0,8) //check for collision below
{
vspd = 0;
y &= ~7;
image_index = 0;
alarm[2] = 8;
timeline_position += 1;
}
break;
case 2:
alarm[2] -= 1;
if alarm[2] break;
if Belmont.hitTimer //If Belmont is invincible
en_xscale_set();
image_index = 1;
timeline_position = 1;
if abs(x - Belmont.x) < $40
&& image_xscale != Belmont.image_xscale
{
vspd = -7/2;
hspd = image_xscale;
}
else
{
vspd = -1;
hspd = 9/4 * image_xscale;
}
break;
//States 3 and 4 are identical to 1 and 2 respectively.
//State 5 is only used when an Eagle carries a Fleaman.
case 5:
var temp; temp = global.instance[myIndex+5];
if temp //Did a harpy drop it?
if temp.timeline_index == st_harpy2
if irandom(7)
{
x = temp.x + $10;
break;
}
else
if abs(x - Belmont.x) > $3F
{
x = temp.x + $10;
break;
}
timeline_position = 1;
vspd = 0;
hspd = 0;
status |= MOVING | STILL;
image_index = 1;
break;
}
CV1 Bone Skeleton
timeline_index = st_boneskel2
In clocktower stages, facing direction depends on which side of the cog he is standing. It's also apparent in how this enemy is coded that I've been making incompatible changes to my codes as I post.
if !(status & OFFSCREEN)
{
en_xscale_set();
if block == 13 || block == 17
{
if x - view_xview > $80
image_xscale = -1; //face left if on the right side
else
image_xscale = 1; //face right if on the left side
}
}
switch timeline_position
{
case 0:
switch irandom(3)
{
case 0: alarm[3] = 4;
case 1: alarm[3] = 2;
case 2: alarm[3] = 3;
case 3: alarm[3] = 1;
}
sprite_index = spr_BoneSkel2;
hspd = 3/2 * image_xscale;
status |= MOVING;
timeline_position = 1;
alarm[2] = 4;
break;
case 1:
alarm[2] -= 1;
if alarm[2] break;
alarm[3] -= 1;
if alarm[3]
{
if status & OFFSCREEN
hspd = abs(hspd) * image_xscale;
else
if abs(x - Belmont.x) < $48
hspd = abs(hspd) * -image_xscale;
else
hspd = abs(hspd) * image_xscale;
alarm[2] = $10;
timeline_position = 2;
}
else
{
alarm[2] = 4;
timeline_position = 3;
}
break;
case 2:
alarm[2] -= 1;
if alarm[2]
{
if tile_map_read(0,0) //($C,0) //check if collision in front
hspd *= -1;
else
if !tile_map_read(0,0) //(0,$10) //check if no collision below
{
hspd = 5/4 * image_xscale;
vspd = -5/2;
timeline_position = 5;
//no change in status - still animated during jump
}
}
else
{
alarm[2] = 4;
timeline_position = 1;
}
break;
case 3:
alarm[2] -= 1;
if alarm[2] break;
if !(status & OFFSCREEN)
{
with spawn_bone2(0,0)
{
hspd = 3/4 * other.image_xscale;
vspd = -(3.5 + irandom(1));
}
}
timeline_position = 4;
alarm[2] = 8;
break;
case 4:
alarm[2] -= 1;
if alarm[2] break;
case 6:
timeline_position = 0;
break;
case 5:
vspd += 1/8;
if tile_map_read(0,0) //(0,$10) //Check for collision below
{
y &= ~$F;
vspd = 0;
timeline_position = 6;
}
break;
}
CV1 Armor
timeline_index = st_armor2
The code may look like it's just the same thing for states 1 and 2, but it's actually different.
switch timeline_position
{
case 0:
sprite_index = spr_Knight;
status |= MOVING;
image_speed = 1/$10;
en_xscale_set();
hspd = 1/2 * image_xscale;
alarm[2] = 0;
timeline_position += 1;
break;
case 1:
if abs(Belmont.y-y) < $4
{
en_xscale_set();
hspd = 1/2 * image_xscale;
timeline_position += 1;
alarm[2] = $C0;
}
else
{
alarm[2] -= 1;
if !alarm[2]
{
hspd *= -1;
image_xscale *= -1;
alarm[2] = $C0;
}
if !tile_map_read($D,0) //check for collision below
timeline_position += 2;
else
if tile_map_read($6,image_xscale) //check for collisions in front
or tile_map_read($20,image_xscale)
{
hspd *= -1;
image_xscale *= -1;
}
}
break;
case 2:
if abs(Belmont.y - y) < $4
{
alarm[2] -= 1;
if !alarm[2]
{
en_xscale_set();
hspd = 1/2 * image_xscale;
alarm[2] = $C0;
}
if !tile_map_read($D,0) //check for collision below
timeline_position += 1;
else
if tile_map_read($6,image_xscale) //check for collisions in front
or tile_map_read($20,image_xscale)
{
hspd *= -1;
image_xscale *= -1;
}
}
else
{
timeline_position = 0;
alarm[2] = $C0;
}
break;
case 3:
vspd += 1/8;
if tile_map_read($D,0) //Check for collision below
{
y &= ~$F;
vspd = 0;
timeline_position = 1;
}
break;
}
CV1 Blood Skeleton
timeline_index = st_bloodskel2
There are two codes. The first is run independent of all others and handles state 4 when the Stopwatch is active.
//Continue state 4 if stopwatch counting down
if global.pause | 4
{
if timeline_position == 4
{
alarm[2] -= 1;
if !alarm[2]
{
alarm[2] = $54;
timeline_position = 0;
status |= PASSTHRU;
sprite_index = spr_BonePile;
}
}
}
switch timeline_position
{
case 0:
if !alarm[2]
{
alarm[2] = $3C;
status |= PASSTHRU | STILL;
sprite_index = spr_BonePile;
}
image_index = 0;
alarm[2] -= 1;
if !alarm[2]
{
timeline_position = 1;
image_speed = 1/$18;
status &= ~STILL;
alarm[3] = 1;
}
break;
case 1:
if image_index < 2 break;
sprite_index = spr_BloodSkel;
case 3:
alarm[2] -= 1;
if !alarm[2]
{
alarm[3] -= 1;
if !alarm[3]
{
en_xscale_set();
switch irandom(3) //uses secondary randomizer
{
case 0: alarm[3] = 4; break;
case 1: alarm[3] = 3; break;
case 2: alarm[3] = 5; break;
case 3: alarm[3] = 4; break;
}
}
image_index = 0;
image_speed = 1/16;
hspd = 5/8 * image_xscale;
status |= MOVING;
status &= ~(PASSTHRU | STILL);
alarm[2] = $30;
timeline_position = 2;
}
break;
case 2:
alarm[2] -= 1;
if alarm[2]
{
if tile_map_read(0,0) //($C,0) //check if collision ahead
{
hspd *= -1;
image_xscale *= -1;
}
else
if !(status & OFFSCREEN)
if !tile_map_read(0,0) //(0,$10) //check for no collision below
{
timeline_position = 5;
vspd = 0;
}
}
else
{
status |= STILL;
status &= ~MOVING;
alarm[2] = $10;
timeline_position = 3;
}
break;
//When hit by an attack, set state to 4
case 4:
if !alarm[2]
{
alarm[2] = $20;
status |= PASSTHRU;
sprite_index = spr_BonePile;
image_index 1;
image_speed = -1/$18;
}
alarm[2] -= 1;
if !alarm[2]
{
alarm[2] = $54;
status |= PASSTHRU | STILL;
timeline_position = 0;
}
break;
//The following state is only accessible when falling
case 5:
vspd += 1/8;
if tile_map_read(0,0) //(0,$10) //check for collision below
{
y &= ~7;
vspd = 0;
timeline_position = 2;
}
break;
}
CV1 Crow
timeline_index = st_crow2
This was a fun one to crack. As a couple of you may recall, I actually found a bug in the original code, which upon remedying is made the Crow's movement much smoother and more natural. It's commented, so you can choose which version you want. By default Crows are perched; setting alarm[5] when spawning them aggros them immediately.
en_xscale_set();
switch timeline_position
{
case 0:
if !alarm[5] //aggro flag
{
alarm[5] = 1;
alarm[2] = $3C;
sprite_index = spr_CrowPerch;
image_index = 0;
status |= STILL;
}
if !alarm[2]
{
sprite_index = spr_CrowFly;
alarm[4] = sign(y-Belmont.y);
switch irandom(3) //uses secondary randomizer
{
case 0: vspd = 7/4 * alarm[4]; break;
case 1: vspd = 5/2 * alarm[4]; break;
case 2: vspd = 5/4 * alarm[4]; break;
case 3: vspd = 2 * alarm[4]; break;
}
alarm[3] = image_xscale;
hspd = 3/4 * image_xscale;
status |= MOVING;
timeline_position += 1;
}
else
alarm[2] -= 1;
//Original code handled offscreen status and weapon collisions
break;
case 1:
var temp; temp = sign(vspd);
vspd += 1/32 * -alarm[4];
hspd += 1/32 * -alarm[3];
if sign(vspd) != temp
{
switch irandom(3) //uses secondary randomizer
{
case 0: alarm[2] = $18; break;
case 1: alarm[2] = $3F; break;
case 2: alarm[2] = $25; break;
case 3: alarm[2] = $79; break;
}
timeline_position = 2;
}
break;
case 2:
alarm[2] -= 1;
if alarm[2] break;
alarm[3] = image_xscale;
if abs(x - Belmont.x) < $20
{
hspd = 1/4 * alarm[3];
vspd = 0;
alarm[2] = $3D; //was random, but values are the same
timeline_position = 3;
}
else
{
alarm[4] = sign(y - Belmont.y);
switch irandom(3) //uses secondary randomizer
{
case 0: vspd = 7/4 * alarm[4]; break;
case 1: vspd = 5/2 * alarm[4]; break;
case 2: vspd = 5/4 * alarm[4]; break;
case 3: vspd = 2 * alarm[4]; break;
}
hspd = 3/4 * alarm[3];
timeline_position = 1;
}
break;
case 3:
alarm[2] -= 1;
if alarm[2]
{
if alarm[3] > 0
{
if Belmont.x - 8 < x break;
else
if x < Belmont.x + 8 break;
hspd += 1/32;
}
else hspd -= 1/32;
alarm[4] = sign(y - global.instance[0].y);
hspd = 1/2 * alarm[3];
/*
The original game code ran this line
but the correct line should have been
vspd = 1/2 * alarm[4];
*/
alarm[2] = $79;
timeline_position = 4;
}
else
{
image_index = 0;
alarm[4] = sign(y - Belmont.y);
switch irandom(3) //uses secondary randomizer
{
case 0: vspd = 7/4 * alarm[4]; break;
case 1: vspd = 5/2 * alarm[4]; break;
case 2: vspd = 5/4 * alarm[4]; break;
case 3: vspd = 2 * alarm[4]; break;
}
hspd = 3/4 * alarm[3];
timeline_position = 1;
}
break;
case 4:
alarm[2] -= 1;
if !alarm[2]
timeline_position = 0;
break;
}
CV1 Eagle
timeline_index = st_harpy2
Essentially the same as a Harpy from CV3, except a Harpy drops a Fleaman whereas the Fleaman ejects itself from the Eagle. This was either a reference to The Hobbit, or the Fleamen are prey of Eagles.
switch timeline_position
{
case 0:
en_xscale_set();
status |= MOVING;
sprite_index = spr_Eagle;
image_speed = 1/16;
global.instance[myIndex - 5] = instance_create(x+$10,y,obj_fleaman);
with global.instance[myIndex - 5]
{
timeline_position = 5;
sprite_index = spr_Fleaman;
image_speed = 1/8;
}
hspd = 7/4 * image_xscale;
alarm[2] = $30;
timeline_position = 1;
break;
case 1:
alarm[2] -= 1;
if !alarm[2]
{
alarm[2] = $10;
timeline_position = 2;
}
break;
case 2:
alarm[2] -= 1;
if !alarm[2]
{
alarm[2] = $30;
timeline_position = 1;
}
break;
}
CV1 Axe Knight
timeline_index = st_axeknight2
en_xscale_set();
switch timeline_position
{
case 0:
switch irandom(3)
{
case 0: alarm[3] = 9; break;
case 1: alarm[3] = 11; break;
case 2: alarm[3] = 10; break;
case 3: alarm[3] = 12; break;
}
if abs(x - Belmont.x) < $50
alarm[4] = -image_xscale;
else
alarm[4] = image_xscale;
hspd = 5/8 * alarm[4];
sprite_index = spr_AxeKnight;
alarm[2] = $10;
timeline_position = 1;
break;
case 1:
if status & OFFSCREEN
{
alarm[2] = 4;
timeline_position = 2;
}
else
{
alarm[2] -= 1;
if alarm[2]
{
if tile_map_read(0,0) //($C,0) //check for collision ahead
or !tile_map_read(0,0) //($04,$10) //check for pits ahead
hspd *= -1;
}
else
{
alarm[3] -= 1;
if alarm[3]
{
alarm[2] = 4;
timeline_position = 2;
status &= ~MOVING;
}
else
{
alarm[2] = $10;
timeline_position = 3;
}
}
}
break;
case 2:
alarm[2] -= 1;
if !alarm[2]
{
if abs(x - Belmont.x) < $50
alarm[4] = -image_xscale;
else
alarm[4] = image_xscale;
hspd = 5/8 * alarm[4];
alarm[2] = $10;
timeline_position = 1;
}
break;
case 3:
alarm[2] -= 1;
if !alarm[2]
{
with spawn_axe(0,0)
{
if irandom(1)
y = other.y - 12;
else
y = other.y + 8;
hspd = 5/4 * other.image_xscale;
alarm[2] = $58;
}
timeline_position = 0;
}
break;
}