I really wanted to have some custom Moldorm in my quest, and I was becoming quite annoyed by the fact that built-in Moldorms don't respect walkability. So I decided to try to script it with ghost.zh. I looked in this forum and only found an old topic about it, but still it was quite useful for me to have hint on where to start with it. So, apparently I managed to do something. I tested it with some Mini Moldorm like in LA and it seems to work fine. Is till have some glitches from time to time I don't fully understand, and I have to test it with different number of segments, step and other attributes.
Here's the script so far:
Spoiler
// Moldorm
const int MAXprevious = 500;
const int MAXsegments = 100;
const int TAIL_NPC = 152; // set it to Other, no itemset, no animation, no movement
// Attributes
// uses step (75), homing factor (10), random rate (1)
// set fisrt argument to the number of segments (at least 1)
ffc script Moldorm{
void run(int enemyID){
npc ghost;
// Initialization
ghost = Ghost_InitAutoGhost(this, enemyID, GHF_NORMAL);
Ghost_UnsetFlag(GHF_KNOCKBACK);
Ghost_SetFlag(GHF_8WAY);
int originalHP = ghost->HP;
int totalHP = originalHP;
int takenDamage = 0;
int segments = ghost->Attributes[0];
int step = ghost->Step;
int homing = ghost->Homing;
int rate = ghost->Rate;
int hunger = ghost->Hunger;
int originalTile = ghost->OriginalTile;
int segOffset = 16*50/ghost->Step; // how may frames behind draw each tail segment
int tailTileOffset1 = 40;
int tailTileOffset2 = 80;
// initialize counter
int counter = -1;
int counter1 = 0;
npc tailSegment[100]; // MAXsegments
for(int i=1;i<segments;i++){
tailSegment[i] = Screen->CreateNPC(TAIL_NPC);
tailSegment[i]->HP = originalHP;
tailSegment[i]->X = Ghost_X;
tailSegment[i]->Y = Ghost_Y;
tailSegment[i]->Damage = ghost->WeaponDamage;
tailSegment[i]->CSet = ghost->CSet;
if(i<segments-1) tailSegment[i]->OriginalTile = ghost->OriginalTile + tailTileOffset1;
else tailSegment[i]->OriginalTile = ghost->OriginalTile + tailTileOffset2;
totalHP += tailSegment[i]->HP;
}
int previousX[500]; // MAXprevious
int previousY[500]; // MAXprevious
int previousZ[500]; // MAXprevious
for(int i=0;i<MAXprevious;i++){
previousX[i] = Ghost_X;
previousY[i] = Ghost_Y;
previousZ[i] = 0;
}
while(true){
// ...
if(ghost->Stun == 0){
// Movement
Ghost_ConstantWalk8(counter, step, rate, homing, hunger);
// graphics
if(Ghost_Dir > DIR_RIGHT) ghost->OriginalTile = originalTile - (ghost->Tile-ghost->OriginalTile) + (Ghost_Dir-DIR_RIGHT-1)*4+20;
else ghost->OriginalTile = originalTile;
// Tail
for(int i=1;i<segments;i++){
tailSegment[i]->X = previousX[i*segOffset];
tailSegment[i]->Y = previousY[i*segOffset];
tailSegment[i]->Z = previousZ[i*segOffset];
if(i<segments-1) tailSegment[i]->OriginalTile = ghost->Tile + tailTileOffset1;
else tailSegment[i]->OriginalTile = ghost->Tile + tailTileOffset2;
}
// update previous position
previousX[0] = Ghost_X;
previousY[0] = Ghost_Y;
previousZ[0] = Ghost_Z;
for(int i=MAXprevious-1;i>0;i--){
previousX[i] = previousX[i-1];
previousY[i] = previousY[i-1];
previousZ[i] = previousZ[i-1];
}
}
// Waitframe
if(ghost->Stun == 0) Ghost_Waitframe(this, ghost, false, false);
else Ghost_Waitframe2(this, ghost, false, false);
// assign damage
takenDamage = originalHP-ghost->HP;
for(int i=1;i<segments;i++){
if(originalHP-tailSegment[i]->HP > takenDamage){
takenDamage = originalHP-tailSegment[i]->HP;
}
}
if(takenDamage>0) ghost->Stun = 20; // stun the enemy if damaged
totalHP = segments*originalHP - takenDamage;
Trace(totalHP);
//
// if it's dead
if(totalHP<=0){
ghost->HP = 0;
for(int i=0;i<segments;i++){
tailSegment[i]->HP = 0;
}
segments = 0;
break;
}
// otherwise
else if(totalHP>originalHP){
Ghost_HP = originalHP;
totalHP -= originalHP;
// go on with the other segments
for(int i=1;i<segments;i++){
if(totalHP>originalHP){
tailSegment[i]->HP = originalHP;
totalHP -= originalHP;
}
else{
tailSegment[i]->HP = totalHP;
for(int j=i+1;j<segments;j++){
tailSegment[j]->HP = 0;
}
segments = i+1;
break;
}
}
}
else{
Ghost_HP = totalHP;
for(int i=1;i<segments;i++){
tailSegment[i]->HP = 0;
}
segments = 1;
}
}
this->Data = 0;
Quit();
}
}
If anybody wants to give it a try and let me know if he finds something wrong or to improve, I would be happy!