Magnetic Gloves
The Oracle sub-series introduced a number of cool new items to the Zelda series which used Link's top-down perspective in fun and new ways. One of these items was the Magnetic Gloves, which allowed Link to push/pull himself away from/towards poles. The gloves changed alignment with each use, meaning that you had to be careful while using them, lest you shoot off in the wrong direction. They also allowed Link to manipulate large iron balls to solve puzzles, such as hitting switches remotely. The magnetic force travelled through blocks.
This script implements an item that functions in the same way. Currently, it just allows for Link to fly across pits. Later, I will add the iron balls portion.
Script
This script uses the Global OnStart Script. Please refer to that page for more details on how to use this.
These are the global variables:
bool magna_gloves_active = false;
bool magna_gloves_positive = false;
const int magna_flag = 99;
const int magna_positive = 144;
This section is the script body:
//Courtesy of Saffith/beefster09
bool isSolid(int x, int y) {
if(x<0 || x>255 || y<0 || y>175) return false;
int mask=1111b;
if(x % 16 < 8)
mask &= 0011b;
else
mask &= 1100b;
if(y % 16 < 8)
mask &= 0101b;
else
mask &= 1010b;
int ret = Screen->ComboS[ComboAt(x, y)] & mask;
return (ret!=0);
}
//functions go here
void MagnaGlovesWork() {
if(Link->InputB) {
//Link->Action = LA_FROZEN;
int lc = 0;
bool yes = false;
if(Link->Dir == DIR_LEFT) {
for(int i = Floor(Link->X / 16) - 1; i >= 0; i--) {
lc = ComboAt(i * 16, Link->Y + 8);
if(Screen->ComboF[lc] == magna_flag || Screen->ComboI[lc] == magna_flag) {
yes = true;
break;
}
}
if(yes) {
Link->Z = 5;
Link->Jump = 0;
Link->Y = Floor((Link->Y + 8) / 16) * 16;
KillLinkInput();
if(magna_gloves_positive) {
if(!isSolid(Link->X + 16, Link->Y)) {
Link->X += 1;
}
if(!isSolid(Link->X + 16, Link->Y)) {
Link->X += 1;
}
} else {
if(!isSolid(Link->X - 1, Link->Y)) {
Link->X -= 1;
}
if(!isSolid(Link->X - 1, Link->Y)) {
Link->X -= 1;
}
}
}
} else if(Link->Dir == DIR_RIGHT) {
for(int i = Floor(Link->X / 16) + 1; i <= 16; i++) {
lc = ComboAt(i * 16, Link->Y + 8);
if(Screen->ComboF[lc] == magna_flag || Screen->ComboI[lc] == magna_flag) {
yes = true;
break;
}
}
if(yes) {
Link->Z = 5;
Link->Jump = 0;
Link->Y = Floor((Link->Y + 8) / 16) * 16;
KillLinkInput();
if(magna_gloves_positive) {
if(!isSolid(Link->X - 1, Link->Y)) {
Link->X -= 1;
}
if(!isSolid(Link->X - 1, Link->Y)) {
Link->X -= 1;
}
} else {
if(!isSolid(Link->X + 16, Link->Y)) {
Link->X += 1;
}
if(!isSolid(Link->X + 16, Link->Y)) {
Link->X += 1;
}
}
}
} else if(Link->Dir == DIR_UP) {
for(int i = Floor((Link->Y + 9) / 16) - 1; i >= 0; i--) {
lc = ComboAt(Link->X + 8, i * 16);
if(Screen->ComboF[lc] == magna_flag || Screen->ComboI[lc] == magna_flag) {
yes = true;
break;
}
}
if(yes) {
Link->Z = 5;
Link->Jump = 0;
Link->X = Floor((Link->X + 8) / 16) * 16;
KillLinkInput();
if(!magna_gloves_positive) {
if(!isSolid(Link->X, Link->Y - 1)) {
Link->Y -= 1;
}
if(!isSolid(Link->X, Link->Y - 1)) {
Link->Y -= 1;
}
} else {
if(!isSolid(Link->X, Link->Y + 16)) {
Link->Y += 1;
}
if(!isSolid(Link->X, Link->Y + 16)) {
Link->Y += 1;
}
}
}
} else if(Link->Dir == DIR_DOWN) {
for(int i = Floor(Link->Y / 16) + 1; i <= 16; i++) {
lc = ComboAt(Link->X + 8, i * 16);
if(Screen->ComboF[lc] == magna_flag || Screen->ComboI[lc] == magna_flag) {
yes = true;
break;
}
}
if(yes) {
Link->Z = 5;
Link->Jump = 0;
Link->X = Floor((Link->X + 8) / 16) * 16;
KillLinkInput();
if(!magna_gloves_positive) {
if(!isSolid(Link->X, Link->Y + 16)) {
Link->Y += 1;
}
if(!isSolid(Link->X, Link->Y + 16)) {
Link->Y += 1;
}
} else {
if(!isSolid(Link->X, Link->Y - 1)) {
Link->Y -= 1;
}
if(!isSolid(Link->X, Link->Y - 1)) {
Link->Y -= 1;
}
}
}
}
if(!yes) {
int d = Link->Dir;
//well, we're not attached to anything.
//so, let's move around
if(Link->InputUp) {
Link->InputUp = false;
if(!isSolid(Link->X, Link->Y - 1)) Link->Y -= 1;
}
if(Link->InputDown) {
Link->InputDown = false;
if(!isSolid(Link->X, Link->Y + 16)) Link->Y += 1;
}
if(Link->InputLeft) {
Link->InputLeft = false;
if(!isSolid(Link->X - 1, Link->Y)) Link->X -= 1;
}
if(Link->InputRight) {
Link->InputRight = false;
if(!isSolid(Link->X + 16, Link->Y)) Link->X += 1;
}
//Link->Dir = d;
}
} else {
magna_gloves_active = false;
magna_gloves_positive = !magna_gloves_positive;
//Link->Action = LA_NONE;
Link->Item[magna_positive] = !Link->Item[magna_positive];
}
}
void KillLinkInput() {
Link->InputUp = false;
Link->InputDown = false;
Link->InputLeft = false;
Link->InputRight = false;
}
This section is the function call:
if(magna_gloves_active) MagnaGlovesWork();
It also comes with a couple of FFC scripts, that go outside the global script:
//balls are negative
//they are also inert
ffc script IronBall {
void run() {
lweapon lw;
while(true) {
//we only need to care if the gloves are active
if(magna_gloves_active) {
//first, is link aligned with us?
if((Link->X + 8 > this->X && Link->X + 8 < this->X + 16) || (Link->Y + 8 > this->Y && Link->Y + 8 < this->Y + 16)) {
//yes he is!
//is he facing us?
int d = link_direction(this);
if(d == DIR_LEFT && Link->Dir == DIR_RIGHT ||
d == DIR_RIGHT && Link->Dir == DIR_LEFT ||
d == DIR_UP && Link->Dir == DIR_DOWN ||
d == DIR_DOWN && Link->Dir == DIR_UP) {
//he is! But, we're not done yet...
//is there a pole in the way?
bool ok = true;
if(d == DIR_LEFT) {
for(int i = Floor(this->X / 16) - 1; i > Floor(Link->X / 16); i--) {
if(Screen->ComboF[ComboAt(i * 16, this->Y)] == magna_flag || Screen->ComboI[ComboAt(i * 16, this->Y)] == magna_flag) {
ok = false;
}
}
} else if(d == DIR_RIGHT) {
for(int i = Floor(this->X / 16) + 1; i < Floor(Link->X / 16); i++) {
if(Screen->ComboF[ComboAt(i * 16, this->Y)] == magna_flag || Screen->ComboI[ComboAt(i * 16, this->Y)] == magna_flag) {
ok = false;
}
}
} else if(d == DIR_UP) {
for(int i = Floor(this->Y / 16) - 1; i > Floor(Link->Y / 16); i--) {
if(Screen->ComboF[ComboAt(this->X, i * 16)] == magna_flag || Screen->ComboI[ComboAt(this->X, i * 16)] == magna_flag) {
ok = false;
}
}
} else if(d == DIR_DOWN) {
for(int i = Floor(this->Y / 16) + 1; i < Floor(Link->Y / 16); i++) {
if(Screen->ComboF[ComboAt(this->X, i * 16)] == magna_flag || Screen->ComboI[ComboAt(this->X, i * 16)] == magna_flag) {
ok = false;
}
}
}
if(ok) {
//yes! we get to do something!
if(d == DIR_UP) {
//we need to align ourselves to Link
moveH(Link->X - this->X, this);
//... and either move towards him...
if(magna_gloves_positive) {
if(this->Y > Link->Y + 17) moveV(-2,this);
} else {
// or away from him
moveV(2, this);
}
} else if(d == DIR_DOWN) {
moveH(Link->X - this->X, this);
if(magna_gloves_positive) {
if(this->Y < Link->Y - 2) moveV(2, this);
} else {
moveV(-2, this);
}
} else if(d == DIR_LEFT) {
moveV(Link->Y - this->Y, this);
if(magna_gloves_positive) {
if(this->X > Link->X + 17) moveH(-2, this);
} else {
moveH(2, this);
}
} else if(d == DIR_RIGHT) {
moveV(Link->Y - this->Y, this);
if(magna_gloves_positive) {
if(this->X < Link->X - 2) moveH(2, this);
} else {
moveH(-2, this);
}
}
//also, we need to damage enemies. so, we'll spawn little lweapons that are invisible
if(lw->isValid()) lw->DeadState = WDS_DEAD;
lw = Screen->CreateLWeapon(LW_SCRIPT1);
lw->X = this->X;
lw->Y = this->Y;
lw->Damage = 1;
lw->OriginalTile = 41;
lw->Tile = 41;
} else {
//well, that was a wasted effort.
}
}
}
}
Waitframe();
}
}
void moveV(int amt, ffc this) {
if(amt == 0) return;
if(amt < 0) {
for(int i = 1; i <= Abs(amt); i++) {
if(isSolid(this->X + 8, this->Y - 1) || isSolid(this->X + 12, this->Y - 1)) break;
this->Y--;
}
} else {
for(int i = 1; i <= amt; i++) {
if(isSolid(this->X + 4, this->Y + 1 + 15) || isSolid(this->X + 12, this->Y + 1 + 15)) break;
this->Y++;
}
}
}
void moveH(int amt, ffc this) {
if(amt == 0) return;
if(amt < 0) {
for(int i = 1; i <= Abs(amt); i++) {
if(isSolid(this->X - 1, this->Y + 4) || isSolid(this->X - 1, this->Y + 12)) break;
this->X--;
}
} else {
for(int i = 1; i <= amt; i++) {
if(isSolid(this->X + 1 + 15, this->Y + 4) || isSolid(this->X + 1 + 15, this->Y + 12)) break;
this->X++;
}
}
}
int link_direction(ffc this) {
int d_x = this->X - Link->X;
int d_y = this->Y - Link->Y;
int a_x = Abs(d_x);
int a_y = Abs(d_y);
if(a_x <= a_y) {
if(d_y >= 0) {
return DIR_UP;
} else {
return DIR_DOWN;
}
} else {
if(d_x >= 0) {
return DIR_LEFT;
} else {
return DIR_RIGHT;
}
}
}
}
ffc script RotatingPole {
void run() {
while(true) {
Waitframes(39);
//now we rotate!
if(Link->X >= this->X + 16 && Link->X < this->X + 18 && Link->Y >= this->Y - 4 && Link->Y <= this->Y + 8 && Link->Dir == DIR_LEFT) {
//link is to the right
Link->X = this->X;
Link->Y = this->Y + 16;
Link->Dir = DIR_UP;
} else if(Link->X >= this->X - 18 && Link->X <= this->X - 16 && Link->Y >= this->Y - 4 && Link->Y <= this->Y + 8 && Link->Dir == DIR_RIGHT) {
//link is to the left
Link->X = this->X;
Link->Y = this->Y - 16;
Link->Dir = DIR_DOWN;
} else if(Link->X >= this->X - 2 && Link->X <= this->X + 8 && Link->Y >= this->Y - 18 && Link->Y <= this->Y - 16 && Link->Dir == DIR_DOWN) {
//link is to the top
Link->Y = this->Y;
Link->X = this->X + 16;
Link->Dir = DIR_LEFT;
} else if(Link->X >= this->X - 2 && Link->X <= this->X + 8 && Link->Y >= this->Y + 16 && Link->Y <= this->Y + 18 && Link->Dir == DIR_UP) {
//link is to the bottom
Link->Y = this->Y;
Link->X = this->X - 16;
Link->Dir = DIR_RIGHT;
}
Waitframes(9);
}
}
}
Function Call Arguments
There are no arguments
Updates
- August 12, 2008 - Added the Iron Ball FFC script and the Rotating Pole FFC script. Fixed several bugs, and made the code 85% more robust.
Notes
Screen shots



