// After regaining control of Link upon entering a new screen, the number of frames to wait before opening shutters.
const int SHUTTER_DELAY_TIME = 15;
// The screen and map number of the previous frame.
int prevScreen;
int prevDMap;
// Holds shutter combo locations
int shutterPos[176];
// True if there are enemies still on the screen
bool enemiesLeft = true;
// True if enemy, secret, perm secret, and flag shutters are closed, respectively.
bool shuttersEnemyClosed = true;
bool shuttersSecretClosed = true;
bool shuttersPermSecretClosed = true;
bool shuttersFlagClosed = true;
// If set to true by another script, flag shutters will open.
bool shutterFlag = false;
// True while Link is automatically moving out of the way for a shutter to close.
bool shutterRunning = false;
// Records combos on screen 81 for safe keeping so that other combos can be placed and tested there.
int shutterTempCombo[4];
// Array used to count the number of shutters to close after Link steps off of them.
int shutterCheck[2];
// Counter for closing shutters after Link regains control.
int shutterDelay = SHUTTER_DELAY_TIME;
void shutterControl() {
if(changeScreen()) {
// The screen has been changed in the last frame. Time to initialize new shutters!
// Reset the script flag for flag shutters
shutterFlag = false;
// Start by saying all shutters are open so that we can close only the ones necessary.
// This means we'll only have to spend time checking shutter conditions for shutter types that actually exist.
shuttersEnemyClosed = false;
shuttersSecretClosed = false;
shuttersPermSecretClosed = false;
shuttersFlagClosed = false;
// The number of shutter combos on the screen.
int numDoors = 0;
// The following loop determines the number of shutter combos on the screen. Suppose there are k.
// It then sets the first k values of ShutterPos[] to the combo locations of those doors, and sets value k+1 to -1.
// It also determines which types of shutters are in use.
for(int i=0; i<176; i++) {
// Looping through all combos on the screen...
shutterPos[numDoors] = -1;
if(Screen->ComboT[i] == CT_SCRIPT1 && Screen->ComboF[i] != 100 &&
(Screen->ComboI[i] != 100 || Screen->ComboF[i] == 98 || Screen->ComboF[i] == 99 || Screen->ComboF[i] == 101)) {
// The combo is a shutter type AND the combo flag is not a one-way shutter AND
// either the inherent flag is not a one-way shutter or the combo flag is one one of the other types of shutters.
shutterPos[numDoors] = i;
numDoors++;
if(Screen->ComboF[i] == 98) {
shuttersSecretClosed = true;
}
else if(Screen->ComboF[i] == 99) {
shuttersPermSecretClosed = true;
}
else if(Screen->ComboF[i] == 101) {
shuttersFlagClosed = true;
}
else if(Screen->ComboI[i] == 98) {
shuttersSecretClosed = true;
}
else if(Screen->ComboI[i] == 99) {
shuttersPermSecretClosed = true;
}
else if(Screen->ComboI[i] == 101) {
shuttersFlagClosed = true;
}
else {
shuttersEnemyClosed = true;
}
}
}
// Screen has changed, so reset the shutter delay counter.
shutterDelay = SHUTTER_DELAY_TIME;
if(Screen->ComboT[ComboAt(Link->X, Link->Y)] == CT_SCRIPT1 ||
Screen->ComboT[ComboAt(Link->X+15, Link->Y)] == CT_SCRIPT1 ||
Screen->ComboT[ComboAt(Link->X, Link->Y+15)] == CT_SCRIPT1 ||
Screen->ComboT[ComboAt(Link->X+15, Link->Y+15)] == CT_SCRIPT1) {
// If Link is standing on a shutter combo...
// Link is on a shutter on the first frame of a new screen, so the automatic walking begins...
shutterRunning = true;
// Determine which edge Link is on, and make him face the direction he's about to walk.
// So if he's on the left side of the screen, for instance, make him face right.
int dir = -1;
if(Link->Y >= 175) {
dir = DIR_UP;
}
else if(Link->Y <= -1) {
dir = DIR_DOWN;
}
else if(Link->X >= 255) {
dir = DIR_LEFT;
}
else if(Link->X <= -1) {
dir = DIR_RIGHT;
}
Link->Dir = dir;
// Link will be taking up at most two rows of combos (if moving horizontally) or two columns of combos (if moving vertically).
// shutterCheck[0] and shutterCheck[1] will count the number of shutter combos his top and bottom (or left and right) halves
// will touch as he automatically walks away from the shutter combos. Here we initialize the values to 0.
shutterCheck[0] = 0;
shutterCheck[1] = 0;
// Now we actually find those values:
if(dir == DIR_UP) {
int y=10;
while(Screen->ComboT[ComboAt(Link->X, 16*y)] == CT_SCRIPT1) {
Screen->ComboD[ComboAt(Link->X, 16*y)]++;
y--;
shutterCheck[0]++;
}
if(Link->X % 16 != 0) {
y=10;
while(Screen->ComboT[ComboAt(Link->X+15, 16*y)] == CT_SCRIPT1) {
Screen->ComboD[ComboAt(Link->X+15, 16*y)]++;
y--;
shutterCheck[1]++;
}
}
}
else if(dir == DIR_DOWN) {
int y=0;
while(Screen->ComboT[ComboAt(Link->X, 16*y)] == CT_SCRIPT1) {
Screen->ComboD[ComboAt(Link->X, 16*y)]++;
y++;
shutterCheck[0]++;
}
if(Link->X % 16 != 0) {
y=0;
while(Screen->ComboT[ComboAt(Link->X+15, 16*y)] == CT_SCRIPT1) {
Screen->ComboD[ComboAt(Link->X+15, 16*y)]++;
y++;
shutterCheck[1]++;
}
}
}
else if(dir == DIR_LEFT) {
int x=15;
while(Screen->ComboT[ComboAt(16*x, Link->Y)] == CT_SCRIPT1) {
Screen->ComboD[ComboAt(16*x, Link->Y)]++;
x--;
shutterCheck[0]++;
}
if(Link->Y % 16 != 0) {
x=15;
while(Screen->ComboT[ComboAt(16*x, Link->Y+15)] == CT_SCRIPT1) {
Screen->ComboD[ComboAt(16*x, Link->Y+15)]++;
x--;
shutterCheck[1]++;
}
}
}
else if(dir == DIR_RIGHT) {
int x=0;
while(Screen->ComboT[ComboAt(16*x, Link->Y)] == CT_SCRIPT1) {
Screen->ComboD[ComboAt(16*x, Link->Y)]++;
x++;
shutterCheck[0]++;
}
if(Link->Y % 16 != 0) {
x=0;
while(Screen->ComboT[ComboAt(16*x, Link->Y+15)] == CT_SCRIPT1) {
Screen->ComboD[ComboAt(16*x, Link->Y+15)]++;
x++;
shutterCheck[1]++;
}
}
}
// If the four corners of Link are standing on combos with combo data a, b, c, and d, then we'll use screen 81 on map 1
// to place combos a-1, b-1, c-1, and d-1. Then, we can check if those combos are shutter type. These variables hold
// the original data for the combos on this screen so we can replace them when we're done.
shutterTempCombo[0] = Game->GetComboData(1, 0x81, 0);
shutterTempCombo[1] = Game->GetComboData(1, 0x81, 1);
shutterTempCombo[2] = Game->GetComboData(1, 0x81, 2);
shutterTempCombo[3] = Game->GetComboData(1, 0x81, 3);
}
}
// End change Screen!
else if(shutterRunning == true) {
// We're in the animation mode. Link is auto-walking.
// If the four corners of Link are standing on combos with combo data a, b, c, and d, then we'll use screen 81 on map 1
// to place combos a-1, b-1, c-1, and d-1.
Game->SetComboData(1, 0x81, 0, Screen->ComboD[ComboAt(Link->X, Link->Y)]-1);
Game->SetComboData(1, 0x81, 1, Screen->ComboD[ComboAt(Link->X+15, Link->Y)]-1);
Game->SetComboData(1, 0x81, 2, Screen->ComboD[ComboAt(Link->X, Link->Y+15)]-1);
Game->SetComboData(1, 0x81, 3, Screen->ComboD[ComboAt(Link->X+15, Link->Y+15)]-1);
// Now we record the types of the combos we just placed.
int shutterComboType[4];
shutterComboType[0] = Game->GetComboType(1, 0x81, 0);
shutterComboType[1] = Game->GetComboType(1, 0x81, 1);
shutterComboType[2] = Game->GetComboType(1, 0x81, 2);
shutterComboType[3] = Game->GetComboType(1, 0x81, 3);
// Get Link's direction which, due to the actions on the change screen frame, should be the direction he's auto-walking.
int dir = Link->Dir;
if((shutterComboType[0] == CT_SCRIPT1) || (shutterComboType[1] == CT_SCRIPT1) ||
(shutterComboType[2] == CT_SCRIPT1) || (shutterComboType[3] == CT_SCRIPT1)) {
// If the combo Link is walking on WAS a shutter type...
// Disable movement and A+B buttons...
noMoveAction();
// ...and auto-walk in the correct direction
if(dir == DIR_UP) {
Link->InputUp = true;
}
else if(dir == DIR_DOWN) {
Link->InputDown = true;
}
else if(dir == DIR_LEFT) {
Link->InputLeft = true;
}
else if(dir == DIR_RIGHT) {
Link->InputRight = true;
}
}
else {
// Link is off the shutter combos and can stop auto-walking! Hooray!
// Animation is complete, so turn off the shutterRunning flag so we don't enter this if statement again.
shutterRunning = false;
// We screwed up screen 81 on map 1 earlier, so let's restore the combos we changed.
Game->SetComboData(1, 0x81, 0, shutterTempCombo[0]);
Game->SetComboData(1, 0x81, 1, shutterTempCombo[1]);
Game->SetComboData(1, 0x81, 2, shutterTempCombo[2]);
Game->SetComboData(1, 0x81, 3, shutterTempCombo[3]);
// Now we loop through the combos Link walked over during his journey and subtract one from the combo data
// So that the shutters are closed. First left half, then right half (or top then bottom)
for(int i=0; i<shutterCheck[0]; i++) {
if(dir == DIR_UP) {
Screen->ComboD[ComboAt(Link->X, 16*(10-i))]--;
}
else if(dir == DIR_DOWN) {
Screen->ComboD[ComboAt(Link->X, 16*i)]--;
}
else if(dir == DIR_LEFT) {
Screen->ComboD[ComboAt(16*(15-i), Link->Y)]--;
}
else if(dir == DIR_RIGHT) {
Screen->ComboD[ComboAt(16*i, Link->Y)]--;
}
}
for(int i=0; i<shutterCheck[1]; i++) {
if(dir == DIR_UP) {
Screen->ComboD[ComboAt(Link->X+15, 16*(10-i))]--;
}
else if(dir == DIR_DOWN) {
Screen->ComboD[ComboAt(Link->X+15, 16*i)]--;
}
else if(dir == DIR_LEFT) {
Screen->ComboD[ComboAt(16*(15-i), Link->Y+15)]--;
}
else if(dir == DIR_RIGHT) {
Screen->ComboD[ComboAt(16*i, Link->Y+15)]--;
}
}
// Shutters have closed. Let's make it official by playing the shutter sfx!
Game->PlaySound(SFX_SHUTTER);
}
}
// End shutter running. Link's auto-walk animation is over!
// If Link auto-walked, he'll enter this if statement on the frame after completing it. Otherwise, he'll enter this
// if statement as soon as the screen finishes scrolling. Either way, this is a countdown to when we can start opening shutters.
else if(shutterDelay > 0 && Link->Action != LA_SCROLLING) {
shutterDelay--;
}
else if(Link->Action != LA_SCROLLING) {
// We didn't just change screens, we're not in an auto-walk animation, and the shutter-opening countdown timer has finished!
// Time to check if we can actually open the shutters!
// If there are "enemy shutters" on the screen that are closed, check if we can open them.
if(shuttersEnemyClosed) {
openShuttersEnemyCheck();
}
// If there are "secret shutters" on the screen that are closed, check if we can open them.
if(shuttersSecretClosed) {
openShuttersSecretCheck();
}
// If there are "permanent secret shutters" on the screen that are closed, check if we can open them.
if(shuttersPermSecretClosed) {
openShuttersPermSecretCheck();
}
// If there are "script flag shutters" on the screen that are closed, check if we can open them.
if(shuttersFlagClosed) {
openShuttersFlagCheck();
}
}
}
// End the shutter control script!
// This function returns true if the current screen is different from the screen in the previous frame.
bool changeScreen() {
if((Game->GetCurScreen() != prevScreen) || (Game->GetCurDMap() != prevDMap)) {
return true;
}
else {
return false;
}
}
// This function checks if all the enemies on the screen are dead, and if so, opens "enemy shutters."
void openShuttersEnemyCheck() {
npc en;
bool enemiesLeft = false;
// Loop through all NPCs on screen. If any of them have ID >=20, they are real enemies, so set enemiesLeft to true and break the loop.
for(int i=1; i<=Screen->NumNPCs(); i++) {
en = Screen->LoadNPC(i);
if(!GetNPCMiscFlag(en,8) && en->ID != NPC_ITEMFAIRY) {
enemiesLeft = true;
break;
}
}
if(enemiesLeft == false) {
// If you got through the loop without seeing any enemies...
// Open the "enemy shutters."
openShuttersEnemy();
// Set this to false so that we don't bother checking this condition anymore.
shuttersEnemyClosed = false;
}
}
// This function opens all "enemy shutters."
void openShuttersEnemy() {
int i=0;
// Loop through all (non one-way) shutter combos on the screen...
while(shutterPos[i] >= 0) {
// If there are no shutter flags on the combo, it's an "enemy shutter," so open it by incrementing the combo data.
if(Screen->ComboF[shutterPos[i]] != 98 && Screen->ComboI[shutterPos[i]] != 98 &&
Screen->ComboF[shutterPos[i]] != 99 && Screen->ComboI[shutterPos[i]] != 99 &&
Screen->ComboF[shutterPos[i]] != 101 && Screen->ComboI[shutterPos[i]] != 101) {
Screen->ComboD[shutterPos[i]] = Screen->ComboD[shutterPos[i]]+1;
}
i++;
}
// If there was at least one "enemy shutter," then we closed it, so let's make it official with an SFX!
if(i > 0) {
Game->PlaySound(SFX_SHUTTER);
}
}
// This function checks if temporary secrets have been activated, and if so, opens "secret shutters."
void openShuttersSecretCheck() {
if(GetLayerComboF(1,0) < 16 || GetLayerComboF(1,0) > 31) {
// If the combo in the top-left corner of layer 1 either doesn't have a flag or has a non-secret flag (not flags 16-31)...
// Open the "secret shutters."
openShuttersSecret();
// Set this to false so that we don't bother checking this condition anymore.
shuttersSecretClosed = false;
}
}
// This function opens all "secret shutters."
void openShuttersSecret() {
int i=0;
// Loop through all (non one-way) shutter combos on the screen...
while(shutterPos[i] >= 0) {
// If either:
// The combo flag on the shutter is a "secret shutter" flag OR
// The inherent flag is a "secret shutter" flag and the combo flag on the shutter is not another type of shutter flag...
// It's a "secret shutter," so open it by incrementing the combo data.
if(Screen->ComboF[shutterPos[i]] == 98 ||
(Screen->ComboI[shutterPos[i]] == 98 && Screen->ComboF[shutterPos[i]] != 99 && Screen->ComboF[shutterPos[i]] != 101)) {
Screen->ComboD[shutterPos[i]] = Screen->ComboD[shutterPos[i]]+1;
}
i++;
}
// If there was at least one "secret shutter," then we closed it, so let's make it official with an SFX!
if(i > 0) {
Game->PlaySound(SFX_SHUTTER);
}
}
// This function checks if the screen secrets flag has been activated, and if so, opens "permanent secret shutters."
void openShuttersPermSecretCheck() {
if(Screen->State[ST_SECRET] == true) {
// If the secret state has been set to true...
// Open the "permanent secret shutters."
openShuttersPermSecret();
// Set this to false so that we don't bother checking this condition anymore.
shuttersPermSecretClosed = false;
}
}
// This function opens all "permanent secret shutters."
void openShuttersPermSecret() {
int i=0;
// Loop through all (non one-way) shutter combos on the screen...
while(shutterPos[i] >= 0) {
// If either:
// The combo flag on the shutter is a "permanent secret shutter" flag OR
// The inherent flag is a "permanent secret shutter" flag and the combo flag on the shutter is not another type of shutter flag...
// It's a "permanent secret shutter," so open it by incrementing the combo data.
if(Screen->ComboF[shutterPos[i]] == 99 ||
(Screen->ComboI[shutterPos[i]] == 99 && Screen->ComboF[shutterPos[i]] != 98 && Screen->ComboF[shutterPos[i]] != 101)) {
Screen->ComboD[shutterPos[i]] = Screen->ComboD[shutterPos[i]]+1;
}
i++;
}
// If there was at least one "permanent secret shutter," then we closed it, so let's make it official with an SFX!
if(i > 0) {
Game->PlaySound(SFX_SHUTTER);
}
}
// This function checks if the script flag has been activated by another script, and if so, opens "flag shutters."
void openShuttersFlagCheck() {
if(shutterFlag) {
// If the shutter flag has been set to true by another script...
// Open the "flag shutters."
openShuttersFlag();
// Set this to false so that we don't bother checking this condition anymore.
shuttersFlagClosed = false;
}
}
// This function opens all "flag shutters."
void openShuttersFlag() {
int i=0;
// Loop through all (non one-way) shutter combos on the screen...
while(shutterPos[i] >= 0) {
// If either:
// The combo flag on the shutter is a "flag shutter" flag OR
// The inherent flag is a "flag shutter" flag and the combo flag on the shutter is not another type of shutter flag...
// It's a "flag shutter," so open it by incrementing the combo data.
if(Screen->ComboF[shutterPos[i]] == 101 ||
(Screen->ComboI[shutterPos[i]] == 101 && Screen->ComboF[shutterPos[i]] != 98 && Screen->ComboF[shutterPos[i]] != 99)) {
Screen->ComboD[shutterPos[i]] = Screen->ComboD[shutterPos[i]]+1;
}
i++;
}
// If there was at least one "flag shutter," then we closed it, so let's make it official with an SFX!
if(i > 0) {
Game->PlaySound(SFX_SHUTTER);
}
}
// This function updates the prevScreen and prevDMap to reflect the current screen and dmap.
void updatePrev() {
prevScreen = Game->GetCurScreen();
prevDMap = Game->GetCurDMap();
}
// This function kills movement inputs plus A+B inputs.
void noMoveAction() {
Link->InputUp = false;
Link->InputDown = false;
Link->InputLeft = false;
Link->InputRight = false;
Link->InputA = false;
Link->InputB = false;
Link->PressUp = false;
Link->PressDown = false;
Link->PressLeft = false;
Link->PressRight = false;
Link->PressA = false;
Link->PressB = false;
}