const int CF_CURSOR_CHANGEABLE=98; //Combo Flag to define combos that Evil Cursoe can change
//Evil Cursor
//An enemy that looks like Windows mouse cursor. Once upon time it "selects" (via drag) a portion of the screen. And every combo in selection will either fire eweapon at Link, or change to given one(if allowed), or both.
//Hunger and Homing fastor used. Step Speed defines number of frames (speed value/10) used to draw selection.
ffc script EvilCursor{
void run(int enemyID){
npc ghost = Ghost_InitAutoGhost(this, enemyID);
int HF = ghost->Homing;
int HR = ghost->Haltrate;
int RR = ghost->Rate;
int HNG = ghost->Hunger;
int SPD = ghost->Step;
int WPND = ghost->WeaponDamage;
int cursorx = Ghost_GetAttribute(ghost,0, 2);//Selection X size
int cursory = Ghost_GetAttribute(ghost,1, 2);//Selection Y size
int delay = Ghost_GetAttribute(ghost,2, 90);//Wait time between moving, in frames
int WPNS = Ghost_GetAttribute(ghost,3, -1);//Eweapon sprite
int combochange = Ghost_GetAttribute(ghost,4, 0);//ID of combo used to replace changeable combos. <0 - Use next combo in table.
int enID = Ghost_GetAttribute(ghost,5, 0);//ID of enemy to spawn on each selected space.
int continiouscombochange = Ghost_GetAttribute(ghost,6, 0);//>0 - Enemy can change the same combo on screen multiple times.
ghost->Extend=3;
Ghost_SetFlag(GHF_NORMAL);
Ghost_SetFlag(GHF_NO_FALL);
Ghost_SetFlag(GHF_IGNORE_ALL_TERRAIN);
Ghost_SetFlag(GHF_IGNORE_NO_ENEMY);
Ghost_UnsetFlag(GHF_KNOCKBACK);
int OrigTile = ghost->OriginalTile;
int State = 0;
int statecounter = delay;
int haltcounter = -1;
int origx = Ghost_X;
int origy = Ghost_Y;
int targpos=0;
int targx = 0;
int targy = 0;
int cmb = ComboAt(Ghost_X +1, Ghost_Y+1);
int temp=0;
int list[8];
for (int i=0;i<8;i++){
list[i]=0;
}
int combl=0;
int defs[18];
Ghost_StoreDefenses(ghost,defs);
while(true){
if (State==0){
statecounter--;
if (statecounter<=0){
for (int i=0;i<176;i++){
if (Screen->ComboS[i]>0)continue;
if (ComboFI(i, CF_NOENEMY))continue;
if (!CursorLeaperMoveAdjacent(i, cmb, cursorx, cursory)) continue;
list[combl]=i;
combl++;
}
if (Rand(4)<HNG && NumLWeaponsOf(LW_BAIT)){
for (int i=1;i<=Screen->NumLWeapons();i++){
lweapon l =Screen->LoadLWeapon(i);
if (l->ID!=LW_BAIT)continue;
int p = ComboAt(CenterX(l),CenterY(l));
targpos = Cursor_ClosestToPos(list, p);
}
}
else if (Rand(256)<HF){
int p = ComboAt(CenterLinkX(),CenterLinkY());
targpos = Cursor_ClosestToPos(list, p);
}
else {
targpos = Rand(combl);
targpos = list[targpos];
}
targx = ComboX(targpos);
targy = ComboY(targpos);
statecounter = SPD/10;
combl=0;
State=1;
}
}
if (State==1){
statecounter--;
Ghost_X = Lerp(targx, origx, statecounter*10/SPD);
Ghost_Y = Lerp(targy, origy, statecounter*10/SPD);
Screen->Rectangle(2, Ghost_X, Ghost_Y, origx, origy,1, 1, 0, 0, 0,false, OP_OPAQUE);
if (statecounter<=0){
if (targx<origx){
temp=targx;
targx=origx;
origx=temp;
}if (targy<origy){
temp=targy;
targy=origy;
origy=temp;
}
// Screen->Rectangle(2, Ghost_X, Ghost_Y, origx, origy,1, 1, 0, 0, 0,false, OP_OPAQUE);
for (int i=0;i<176;i++){
if (Screen->ComboS[i]>0)continue;
if (ComboFI(i, CF_NOENEMY))continue;
if (!RectCollision(origx, origy,targx, targy, ComboX(i)+1, ComboY(i)+1, ComboX(i)+15, ComboY(i)+15)) continue;
if (combochange>0 && ComboFI(i,CF_CURSOR_CHANGEABLE)){
Screen->ComboD[i]=combochange;
if (continiouscombochange==0)Screen->ComboF[i]=0;
}
if (combochange<0 && ComboFI(i,CF_CURSOR_CHANGEABLE)){
Screen->ComboD[i]++;
if (continiouscombochange==0)Screen->ComboF[i]=0;
}
if (WPND>0){
eweapon e = FireAimedEWeapon(ghost->Weapon, ComboX(i), ComboY(i), 0, Cond(ghost->Weapon==EW_BOMBBLAST||ghost->Weapon==EW_SBOMBBLAST, 0, 200), WPND, WPNS, -1, EWF_ROTATE);
}
if (enID>0){
npc n = CreateNPCAt(enID, ComboX(i), ComboY(i));
lweapon e = CreateLWeaponAt(LW_SPARKLE, ComboX(i), ComboY(i));
e->UseSprite(22);//Use Misc Spawn for spawn effect.
e->CollDetection=false;
}
}
cmb = ComboAt(Ghost_X +1, Ghost_Y+1);
origx = ComboX(cmb);
origy = ComboY(cmb);
Ghost_X = origx;
Ghost_Y = origy;
// for (int i=0;i<8;i++){
// list[i]=0;
// }
statecounter=delay;
State=0;
}
}
Ghost_Waitframe(this, ghost);
}
}
}
int Cursor_ClosestToPos(int list, int pos){
int dist = 9999;
int ret = 0;
int pos2 = 0;
int dist2 = 0;
for (int i = 0; i<SizeOfArray(list);i++){
if (list[i]==0)continue;
pos2 = list[i];
dist2 = Distance(ComboX(pos2), ComboY(pos2), ComboX(pos), ComboY(pos));
if (dist2<dist)dist=dist2;
else continue;
ret=pos2;
}
return ret;
}
// Returns TRUE, if two given combos are within move of leaping chess piece.
bool CursorLeaperMoveAdjacent(int cmb1, int cmb2, int l1, int l2){
int r1 = ComboY (cmb1);
int r2 = ComboY (cmb2);
int f1 = ComboX (cmb1);
int f2 = ComboX (cmb2);
if ((Abs(r1-r2)/16)==l1){
if ((Abs(f1-f2)/16)==l2) return true;
}
if ((Abs(r1-r2)/16)==l2){
if ((Abs(f1-f2)/16)==l1) return true;
}
return false;
}