Joe123
04-16-2009, 08:51 AM
Example Quest (http://zc.celestialrealm.net/scripts/10_NPCFollowerex.qst)
This script will have an ffc follow right behind Link whilst walking around.
It's based on me watching the behaviour from Terranigma, but it should work the same as when you have Marin in tow in Link's Awakening, for example.
You should arrange the NPC's combos like this:
Still Up | Still Down | Still Left | Still Right
Walking Up | Walking Down | Walking Left | Walking Right
And set the ffc's combo to the first one.
If you want it to work for more than one screen, the 'Carryover' flag is advised.
You could probably set it up to work ok-ish with the 'No FFC Carryover' screen flag, but if you wanted anything more complicated you'd need some sort of script to toggle when this one functions, but obviously that's very much dependant on your quest so I can't write it to work for everyone.
Thanks to LinkTheMaster for the 'FFCToPoint' function
const int M_NORMAL = 0;
const int M_MOVINGTOPOS = 1;
const int M_SOLIDATPOS = 2;
ffc script FollowLink{
void run(){
int orig = this->Data;
int lastDir;
int MovementState;
int CurrentScreen;
int idle;
while(true){
int x = Link->X; int y = Link->Y;
if(Link->Dir == DIR_UP||Link->Dir == DIR_DOWN) y -= Link->Dir*32-16;
else x -= (Link->Dir-2)*32-16;
if(CurrentScreen != Game->GetCurScreen()) MovementState = NormalPlacement(this,x,y);
if(MovementState == M_NORMAL){
if(lastDir != Link->Dir) MovementState = MoveToPosition(this,x,y);
else MovementState = NormalPlacement(this,x,y);
}else if(MovementState == M_MOVINGTOPOS) MovementState = WhileMoving(this,x,y,idle);
else if(MovementState == M_SOLIDATPOS) MovementState = CheckPos(this,x,y);
SetGraphics(this,orig);
CurrentScreen = Game->GetCurScreen();
idle = (idle+1)%6;
lastDir = Link->Dir;
Waitframe();
}
}
int NormalPlacement(ffc this,int x,int y){
if(Solid(this,x,y)) return M_SOLIDATPOS;
this->X = x; this->Y = y;
return M_NORMAL;
}
int MoveToPosition(ffc this,int x,int y){
if(Solid(this,x,y)) return M_SOLIDATPOS;
int speed = Distance(x,y,this->X,this->Y)/8;
if(speed < 0.5) return M_NORMAL;
else if(speed < 1.2) speed *= 2;
FFCToPoint(this,x,y,speed);
return M_MOVINGTOPOS;
}
int WhileMoving(ffc this,int x,int y,int idle){
if(Abs(this->X-x) < 3 && Abs(this->Y-y) < 3){
this->Vx = 0; this->Vy = 0;
return M_NORMAL;
}
if(idle == 0) return MoveToPosition(this,x,y);
return M_MOVINGTOPOS;
}
int CheckPos(ffc this,int x,int y){
if(Solid(this,x,y)) return M_SOLIDATPOS;
return MoveToPosition(this,x,y);
}
bool Solid(ffc this,int x,int y){
if(Screen->isSolid(x+8,y+8)){
this->Vx = 0; this->Vy = 0;
return true;
}
}
void SetGraphics(ffc this,int orig){
int moving;
if(Link->InputUp || Link->InputDown || Link->InputLeft || Link->InputRight
|| this->Vx != 0 || this->Vy != 0) moving = 4;
this->Data = orig+moving+Link->Dir;
}
int FFCToPoint(ffc f,int x,int y,int speed){
if(speed == 0) return -1;
int dx = x-f->X; int dy = y-f->Y;
int dis = Abs(dx) + Abs(dy);
int d = dis/speed;
f->Vx = dx/d; f->Vy = dy/d;
return d;
}
}
This script will have an ffc follow right behind Link whilst walking around.
It's based on me watching the behaviour from Terranigma, but it should work the same as when you have Marin in tow in Link's Awakening, for example.
You should arrange the NPC's combos like this:
Still Up | Still Down | Still Left | Still Right
Walking Up | Walking Down | Walking Left | Walking Right
And set the ffc's combo to the first one.
If you want it to work for more than one screen, the 'Carryover' flag is advised.
You could probably set it up to work ok-ish with the 'No FFC Carryover' screen flag, but if you wanted anything more complicated you'd need some sort of script to toggle when this one functions, but obviously that's very much dependant on your quest so I can't write it to work for everyone.
Thanks to LinkTheMaster for the 'FFCToPoint' function
const int M_NORMAL = 0;
const int M_MOVINGTOPOS = 1;
const int M_SOLIDATPOS = 2;
ffc script FollowLink{
void run(){
int orig = this->Data;
int lastDir;
int MovementState;
int CurrentScreen;
int idle;
while(true){
int x = Link->X; int y = Link->Y;
if(Link->Dir == DIR_UP||Link->Dir == DIR_DOWN) y -= Link->Dir*32-16;
else x -= (Link->Dir-2)*32-16;
if(CurrentScreen != Game->GetCurScreen()) MovementState = NormalPlacement(this,x,y);
if(MovementState == M_NORMAL){
if(lastDir != Link->Dir) MovementState = MoveToPosition(this,x,y);
else MovementState = NormalPlacement(this,x,y);
}else if(MovementState == M_MOVINGTOPOS) MovementState = WhileMoving(this,x,y,idle);
else if(MovementState == M_SOLIDATPOS) MovementState = CheckPos(this,x,y);
SetGraphics(this,orig);
CurrentScreen = Game->GetCurScreen();
idle = (idle+1)%6;
lastDir = Link->Dir;
Waitframe();
}
}
int NormalPlacement(ffc this,int x,int y){
if(Solid(this,x,y)) return M_SOLIDATPOS;
this->X = x; this->Y = y;
return M_NORMAL;
}
int MoveToPosition(ffc this,int x,int y){
if(Solid(this,x,y)) return M_SOLIDATPOS;
int speed = Distance(x,y,this->X,this->Y)/8;
if(speed < 0.5) return M_NORMAL;
else if(speed < 1.2) speed *= 2;
FFCToPoint(this,x,y,speed);
return M_MOVINGTOPOS;
}
int WhileMoving(ffc this,int x,int y,int idle){
if(Abs(this->X-x) < 3 && Abs(this->Y-y) < 3){
this->Vx = 0; this->Vy = 0;
return M_NORMAL;
}
if(idle == 0) return MoveToPosition(this,x,y);
return M_MOVINGTOPOS;
}
int CheckPos(ffc this,int x,int y){
if(Solid(this,x,y)) return M_SOLIDATPOS;
return MoveToPosition(this,x,y);
}
bool Solid(ffc this,int x,int y){
if(Screen->isSolid(x+8,y+8)){
this->Vx = 0; this->Vy = 0;
return true;
}
}
void SetGraphics(ffc this,int orig){
int moving;
if(Link->InputUp || Link->InputDown || Link->InputLeft || Link->InputRight
|| this->Vx != 0 || this->Vy != 0) moving = 4;
this->Data = orig+moving+Link->Dir;
}
int FFCToPoint(ffc f,int x,int y,int speed){
if(speed == 0) return -1;
int dx = x-f->X; int dy = y-f->Y;
int dis = Abs(dx) + Abs(dy);
int d = dis/speed;
f->Vx = dx/d; f->Vy = dy/d;
return d;
}
}