Last active
December 20, 2015 10:39
-
-
Save gwx/6116836 to your computer and use it in GitHub Desktop.
Sideview stairs in ZC.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import "std.zh" | |
//////////////////////////////////////////////////////////////// | |
//// Engine Constants. | |
// Combo Flag for soft platforms. | |
const int CF_SOFT = 98; | |
//// Block Types. | |
// An empty block. | |
const int BLOCK_EMPTY = 0; | |
// A fallthrough block. | |
const int BLOCK_SOFT = 1; | |
// A standard block. | |
const int BLOCK_HARD = 2; | |
//// Stair combo types. | |
const int CT_NEG = 142; | |
const int CT_CROSS = 143; | |
const int CT_POS = 144; | |
//// Custom Engine Constants. | |
// Link's walk speed. | |
const float LINK_WALK = 1.5; | |
// Link's gravitic acceleration. | |
const float LINK_GRAV = 0.16; | |
// Link's terminal velocity. | |
const float LINK_TERM = 3.2; | |
//////////////////////////////////////////////////////////////// | |
//// Global Variables | |
//////////////// | |
//// Link's State | |
//// How to handle Link's movement. | |
// We're letting the ZC engine handle movement. | |
const int LINK_MODE_ENGINE = 0; | |
// We're dealing with Link's movement ourselves. | |
const int LINK_MODE_CUSTOM = 1; | |
// We're moving link accourding to the stair system. | |
const int LINK_MODE_STAIR = 2; | |
// Link's current movement mode. | |
int LinkMode = LINK_MODE_ENGINE; | |
// Link's Location. This is so we can have fractional movement. | |
float LinkX = 0; | |
float LinkY = 0; | |
// Link's Vertical Velocity. | |
float LinkVy = 0; | |
// What Link is standing on. | |
int LinkBlock = BLOCK_HARD; | |
// Link's jump speed. | |
float LinkJump = -4; | |
// Link's hop speed. | |
float LinkHop = -1; | |
//// Fake input since we're cancelling it. | |
bool InputJump = false; | |
bool PressJump = false; | |
//// Various parts of Link's state from last frame. | |
// Link's Position. | |
float OldLinkX = 0; | |
float OldLinkY = 0; | |
int OldLinkAction = LA_NONE; | |
//// Stair State. | |
// On a down-left up-right stair. | |
const int STAIR_NEG = -1; | |
// Not on any stairs. | |
const int STAIR_NONE = 0; | |
// On an up-left down-right stair. | |
const int STAIR_POS = 1; | |
//// Stair Positioning - where we are on a stair. | |
// We're in the middle of the stair. | |
const int STAIR_MIDDLE = 0; | |
// We're anchored to the side of a stair. | |
const int STAIR_BOTTOM = 1; | |
// We're anchored to a stair diagonally. | |
const int STAIR_TOP = 2; | |
// The current kind of stair that Link is standing on. | |
int StairMode = STAIR_NONE; | |
// If the stairs were mounted this frame. | |
bool StairMount = false; | |
// The combo position fo the stair that Link is anchored to. | |
int StairLoc = -1; | |
// Where we are on the stair. | |
int StairPos = STAIR_MIDDLE; | |
// The x position of the edge of the stairs. | |
int StairEdgeX = -1; | |
// The left edge of the stairs that Link is on. | |
int StairLeft = 0; | |
// The right edge of the stairs that Link is on. | |
int StairRight = 0; | |
// If the anchored stair has another above it. | |
bool StairAbove = false; | |
// If the anchored stair has another below it. | |
bool StairBelow = false; | |
// The y offset of the current stair. | |
int StairY = 0; | |
//////////////// | |
//// Screen Change | |
//// Screen State on the previous frame. | |
// DMap from last frame. | |
int OldDMap = -1; | |
// DMap Screen from last frame. | |
int OldDScreen = -1; | |
// If the dmap has changed from the last frame. | |
bool DMapChanged = false; | |
// If the screen has changed from the last frame. | |
bool ScreenChanged = false; | |
// Used so that ScreenChanged is only set on the first frame | |
// of a scrolling screen change. | |
bool _ScreenChanged_ScrollFlag = false; | |
// The ScreenChange FFC sets this so that maze screens can be used. | |
bool _ScreenChanged_ForceFlag = false; | |
// If the screen change has been handled by custom code. | |
bool ScreenChangeHandled = true; | |
// We're pretty sure that the screen change was caused by a warp of | |
// some sort. | |
const int SCREEN_CHANGE_WARP = -1; | |
// Best guess for which direction we changed screens in | |
// based on Link's current position. | |
int ScreenChangeDir = SCREEN_CHANGE_WARP; | |
global script Active { | |
void run() { | |
LinkX = Link->X; | |
LinkY = Link->Y; | |
while (true) { | |
OldLink_Update1(); | |
ScreenChange_Update1(); | |
Stair_Update1(); | |
Input_Update1(); | |
//Input_Update2(); | |
// Performs Game Logic. | |
Waitdraw(); | |
ScreenChange_Update2(); | |
DetermineLinkMode(); | |
// If we're not using custom movement, update Link's positioning | |
// variables to match whatever the engine says. | |
if (LinkMode == LINK_MODE_ENGINE) { | |
LinkX = Link->X; | |
LinkY = Link->Y;} | |
// Perform custom movement. | |
if (LinkMode == LINK_MODE_CUSTOM) { | |
StairMode = STAIR_NONE; | |
LinkCustomOnScreenChange(); | |
LinkCustomUpdatePosition(); | |
LinkCustomJump(); | |
LinkCustomMountStair();} | |
// We could possibly switch to stair movement at this point. | |
if (LinkMode == LINK_MODE_STAIR) { | |
Link->Jump = 0; | |
LinkStairOnScreenChange(); | |
LinkStairFindStair(); | |
LinkStairFallOff();} | |
// And away from it at this point. | |
if (LinkMode == LINK_MODE_STAIR) { | |
LinkStairUpdatePosition(); | |
LinkStairJump();} | |
LinkAdjust(); | |
// Wait for the screen to draw. | |
// (You wouldn't think it from the name, right?) | |
Waitframe();}}} | |
// If the combo location (in units of tiles) is valid, it is returned. | |
// otherwise, -1 is returned. | |
int FindLoc(int tx, int ty) { | |
if (tx < 0 || tx > 15 || ty < 0 || ty > 10) { | |
return -1;} | |
return tx + (ty << 4);} | |
// Determine whether we'll be relying on the ZC engine for movement | |
// or on this custom code. | |
// Place after Waitdraw, and before anything that needs to know Link's mode. | |
void DetermineLinkMode() { | |
// Check for various situations in which we want to fallback on | |
// the built-in ZC engine. | |
if (// If we're not a sideview screen, we definitely want | |
// to use the ZC engine. | |
!IsSideview() || | |
// If Link is Frozen, he's probably using the hookshot. | |
Link->Action == LA_FROZEN || | |
// If the screen is scrolling, we can't do anything anyway. | |
Link->Action == LA_SCROLLING || | |
// If he's hurt, we want to rely on the built-in knockback. | |
Link->Action == LA_GOTHURTLAND || | |
Link->Action == LA_GOTHURTWATER) { | |
// Rely on the engine. | |
LinkMode = LINK_MODE_ENGINE;} | |
// There's on reason not to, so use our custom engine or stairs.. | |
else if (StairMode != STAIR_NONE) { | |
LinkMode = LINK_MODE_STAIR;} | |
else { | |
LinkMode = LINK_MODE_CUSTOM;}} | |
// Return true if the combo at the given position is a stair. | |
bool IsStair(int x, int y) { | |
if (x < 0 || x >= 256 || y < 0 || y >= 176) {return false;} | |
else {return IsStair((y & 240) + (x >> 4));}} | |
bool IsStair(int loc) { | |
if (loc == -1) {return false;} | |
int ct = Screen->ComboT[loc]; | |
return CT_NEG <= ct && ct <= CT_POS;} | |
bool IsValidStair(int loc) { | |
if (StairMode == STAIR_NEG) {return IsNegStair(loc);} | |
else if (StairMode == STAIR_POS) {return IsPosStair(loc);}} | |
bool IsValidStair(int x, int y) { | |
if (StairMode == STAIR_NEG) {return IsNegStair(x, y);} | |
else if (StairMode == STAIR_POS) {return IsPosStair(x, y);}} | |
bool IsPosStair(int x, int y) { | |
if (x < 0 || x > 255 || y < 0 || y > 175) {return false;} | |
else {return IsPosStair((y & 240) + (x >> 4));}} | |
bool IsPosStair(int loc) { | |
if (loc == -1) {return false;} | |
int ct = Screen->ComboT[loc]; | |
return ct == CT_CROSS || ct == CT_POS;} | |
bool IsNegStair(int x, int y) { | |
if (x < 0 || x > 255 || y < 0 || y > 175) {return false;} | |
else {return IsNegStair((y & 240) + (x >> 4));}} | |
bool IsNegStair(int loc) { | |
if (loc == -1) {return false;} | |
int ct = Screen->ComboT[loc]; | |
return ct == CT_CROSS || ct == CT_NEG;} | |
// Gets the block type at the given position on screen. | |
int GetBlockType(int x, int y) { | |
// Outside the screen is always considered open. | |
if (x < 0 || x >= 256 || y < 0 || y >= 176) {return BLOCK_EMPTY;} | |
// Non-solid blocks are always empty. | |
else if (!Screen->isSolid(x, y)) {return BLOCK_EMPTY;} | |
// Otherwise, if has the soft flag or is a stair, | |
// it is a soft block. | |
else if (ComboFI(x, y, CF_SOFT) || IsStair(x, y)) {return BLOCK_SOFT;} | |
// Otherwise it is hard. | |
else {return BLOCK_HARD;}} | |
// Updates Old Link position when the screen changes. | |
void LinkUpdateOldOnScreenChange() { | |
// Set old link position to the edge of the screen we came in from. | |
if (ScreenChangeDir == DIR_UP) { | |
OldLinkY = 160;} | |
else if (ScreenChangeDir == DIR_DOWN) { | |
OldLinkY = 0;} | |
else if (ScreenChangeDir == DIR_LEFT) { | |
OldLinkX = 240;} | |
else if (ScreenChangeDir == DIR_RIGHT) { | |
OldLinkX = 0;}} | |
// Various actions to perform if the screen changed on us. | |
void LinkCustomOnScreenChange() { | |
if (ScreenChangeHandled) {return;} | |
// Respect any warps or such. | |
LinkX = Link->X; | |
LinkY = Link->Y; | |
LinkUpdateOldOnScreenChange(); | |
// Mark as being handled. | |
ScreenChangeHandled = true;} | |
// Perform the actual movement of Link. | |
void LinkCustomUpdatePosition() { | |
// First, move according to player input. | |
if (// We can only move if we're standing still or walking. | |
Link->Action == LA_NONE || Link->Action == LA_WALKING || | |
// Or we're in the air and attacking. | |
(Link->Action == LA_ATTACKING && LinkBlock == BLOCK_EMPTY)) { | |
// Then move left or right, but not both. | |
if (Link->InputLeft) {LinkX -= LINK_WALK;} | |
else if (Link->InputRight) {LinkX += LINK_WALK;}} | |
// Check against running into a wall to the left. | |
if (// First check that we moved left. | |
LinkX < OldLinkX && | |
(// Then check for hard blocks at Link's top, middle, and bottom. | |
GetBlockType(LinkX, LinkY) == BLOCK_HARD || | |
GetBlockType(LinkX, LinkY + 8) == BLOCK_HARD || | |
GetBlockType(LinkX, LinkY + 15) == BLOCK_HARD)) { | |
// If he hit, move Link right to the next multiple of 8. | |
LinkX += 8 - (LinkX % 8);} | |
// Check against running into a wall to the right. | |
if (// First check that we moved right. | |
LinkX > OldLinkX && | |
(// Then check for hard blocks at Link's top, middle, and bottom. | |
GetBlockType(LinkX + 15, LinkY) == BLOCK_HARD || | |
GetBlockType(LinkX + 15, LinkY + 8) == BLOCK_HARD || | |
GetBlockType(LinkX + 15, LinkY + 15) == BLOCK_HARD)) { | |
// If he hit, move Link left to the previous multiple of 8. | |
LinkX &= 0x1FFF8;} | |
// Then move Link according to his vertical velocity. | |
LinkY += LinkVy; | |
// Check against running into a hard block above. | |
if (// First check that we're moving up. | |
LinkY < OldLinkY && | |
(// Then check against Link's middle-left and middle-right. | |
GetBlockType(LinkX + 5, LinkY) == BLOCK_HARD || | |
GetBlockType(LinkX + 11, LinkY) == BLOCK_HARD)) { | |
// If he hit, move Link down to the next multiple of 8. | |
LinkY += 8 - (LinkY % 8); | |
// and get rid of his vertical velocity. | |
LinkVy = 0;} | |
// Check against running into a block below, and assign the block type | |
// below Link to LinkBlock for this round. | |
// First check to make sure we're moving down. | |
if (LinkY > OldLinkY) { | |
// Get the hardest type of platform below Link. | |
// Check against his middle-left and middle-right. | |
LinkBlock = Max(GetBlockType(LinkX + 5, LinkY + 16), | |
GetBlockType(LinkX + 11, LinkY + 16)); | |
// See if we ran into a block. | |
if (// A hard block always counts. | |
LinkBlock == BLOCK_HARD || | |
// A soft block counts as long as we're not holding the jump | |
// button down, or we started out past it. | |
(LinkBlock == BLOCK_SOFT && | |
!InputJump && | |
!(OldLinkY > (LinkY & 0x1FFF8)))) { | |
// If he hit, move Link up to the previous multiple of 8. | |
LinkY &= 0x1FFF8; | |
// and get rid of his vertical velocity. | |
LinkVy = 0;}} | |
// Otherwise, we're in the air. | |
else { | |
LinkBlock = BLOCK_EMPTY;} | |
Link->Jump = 0; | |
Link->Z = 0; | |
// Gravity. | |
LinkVy = Min(LinkVy + LINK_GRAV, LINK_TERM);} | |
// Perform a sideview jump. | |
void SideviewJump() { | |
Game->PlaySound(SFX_JUMP); | |
// We're holding down, so only hop. | |
if (Link->InputDown) {LinkVy = LinkHop;} | |
// Otherwise do the full jump. | |
else {LinkVy = LinkJump;}} | |
// Jump according to custom mode rules. | |
void LinkCustomJump() { | |
if (// The Jump button is pressed. | |
PressJump && | |
// Can't jump in the air. | |
LinkBlock != BLOCK_EMPTY && | |
// Must have positive y velocity. | |
LinkVy >= 0 && | |
// Can't be doing anything but walking. | |
(Link->Action == LA_NONE || Link->Action == LA_WALKING)) { | |
// Jump! | |
SideviewJump();}} | |
// Check if we need to get onto stairs from custom mode. | |
void LinkCustomMountStair() { | |
// We never get on a stair unless we're standing on something. | |
if (LinkBlock == BLOCK_EMPTY) {return;} | |
// We must have a positive or 0 y velocity. | |
if (LinkVy < 0) {return;} | |
// We're moving up-left, so check an up-left going stair on the same | |
// tile as Link. | |
if (Link->InputLeft && Link->InputUp && IsPosStair(LinkX, LinkY + 15)) { | |
MountStair(LinkX, LinkY + 15, STAIR_POS); | |
StairPos = STAIR_BOTTOM;} | |
// We're moving up-right, so check an up-right going stair on the same | |
// tile as Link. | |
else if (Link->InputRight && Link->InputUp && | |
IsNegStair(LinkX + 15, LinkY + 15)) { | |
MountStair(LinkX + 15, LinkY + 15, STAIR_NEG); | |
StairPos = STAIR_BOTTOM;} | |
// We're moving down-left, so check a down-left going stair on the | |
// tile below Link. | |
if (Link->InputLeft && Link->InputDown && IsNegStair(LinkX + 2, LinkY + 18)) { | |
MountStair(LinkX + 2, LinkY + 18, STAIR_NEG); | |
StairPos = STAIR_TOP;} | |
// We're moving down-right, so check a down-right going stair on the | |
// tile below Link. | |
if (Link->InputRight && Link->InputDown && | |
IsPosStair(LinkX + 13, LinkY + 18)) { | |
MountStair(LinkX + 13, LinkY + 18, STAIR_POS); | |
StairPos = STAIR_TOP;}} | |
// Causes Link to mount the stair at the given position. | |
// Returns true if the stair was mounted. | |
bool MountStair(int x, int y, int mode) { | |
// First, make sure there's actually a stair there. | |
int start = (y & 240) + (x >> 4); | |
if (x < 0 || x >= 256 || y < 0 || y >= 176 || !IsStair(start)) { | |
LinkMode = LINK_MODE_CUSTOM; | |
StairMode = STAIR_NONE; | |
return false;} | |
// Change to stair movement mode. | |
LinkMode = LINK_MODE_STAIR; | |
StairMode = mode; | |
StairLoc = ComboAt(x, y); | |
// Mark the stairs being mounted this frame. | |
StairMount = true; | |
// Set the Y offset. | |
x = ComboX(start); | |
y = ComboY(start); | |
StairY = | |
// Start with the y position of the stair combo. | |
y | |
// Move to 1 cell above it. | |
- 16 | |
// Adjust for the x position of the stair combo in the stair direction. | |
- x * StairMode; | |
return true;} | |
void Stair_Update1() { | |
StairMount = false;} | |
// Adjust Link's position if the screen changed. | |
void LinkStairOnScreenChange() { | |
if (ScreenChangeHandled) {return;} | |
int stairTX = StairLoc % 16; | |
int stairTY = StairLoc >> 4; | |
LinkUpdateOldOnScreenChange(); | |
// If we walked off the top of the screen. | |
if (ScreenChangeDir == DIR_UP) { | |
int adjust = (StairLoc >> 4) + 1; | |
stairTX -= adjust * StairMode; | |
stairTY = 10; | |
StairLoc = FindLoc(stairTX, stairTY); | |
LinkX = (stairTX + StairMode) * 16; | |
LinkY = 160;} | |
// We walked off the bottom of the screen. | |
else if (ScreenChangeDir == DIR_DOWN) { | |
int adjust = 11 - stairTY; | |
// First check if there is actually a stair on the top of the new screen. | |
int loc = FindLoc(stairTX + StairMode * adjust, 0); | |
if (!IsValidStair(loc)) { | |
// If there isn't then just set Link's X to where that stair would be. | |
LinkX = ComboX(loc); | |
StairLoc = -1;} | |
// If there is, proceed as normal. | |
else { | |
stairTX += 2 * StairMode; | |
stairTY = 1; | |
StairLoc = FindLoc(stairTX, stairTY); | |
LinkX = stairTX * 16;} | |
LinkY = 0;} | |
// We walked off the left edge of the screen. Make sure that the | |
// stairs actually reached all the way to the left as well. | |
else if (ScreenChangeDir == DIR_LEFT && | |
(// If we were on the edge stair, then we know it existed. | |
stairTX == 0 || | |
// Check above or below based on stair direction | |
Cond(StairMode == STAIR_POS, StairAbove, StairBelow))) { | |
stairTX = 15; | |
// How far away the stair we're anchored to is from the wall. | |
int adjust = (StairLoc % 16) + 1; | |
stairTY -= adjust * StairMode; | |
StairLoc = FindLoc(stairTX, stairTY); | |
LinkX = 240; | |
LinkY = (stairTY - 1) * 16; | |
// If there isn't a valid stair there, and we were moving up, then | |
// move Link down a tile, because he never climbed it while the | |
// screen was scrolling. | |
if (StairMode == STAIR_POS && !IsValidStair(StairLoc)) { | |
LinkY += 16;}} | |
// We walked off the right edge of the screen. Make sure that the | |
// stairs actually reached all the way to the right as well. | |
else if (ScreenChangeDir == DIR_RIGHT && | |
(// If we were on the edge stair, then we know it existed. | |
stairTX == 15 || | |
// Check above or below based on stair direction | |
Cond(StairMode == STAIR_POS, StairBelow, StairAbove))) { | |
stairTX = 0; | |
// How far away the stair we're anchored to is from the wall. | |
int adjust = 16 - (StairLoc % 16); | |
stairTY += adjust * StairMode; | |
StairLoc = FindLoc(stairTX, stairTY); | |
LinkX = 0; | |
LinkY = (stairTY - 1) * 16; | |
// If there isn't a valid stair there, and we were moving up, then | |
// move Link down a tile, because he never climbed it while the | |
// screen was scrolling. | |
if (StairMode == STAIR_NEG && !IsValidStair(StairLoc)) { | |
LinkY += 16;}} | |
// Otherwise, cancel stairs. | |
else { | |
LinkX = Link->X; | |
LinkY = Link->Y; | |
StairMode = STAIR_NONE; | |
LinkMode = LINK_MODE_CUSTOM;} | |
if (StairMode != STAIR_NONE) { | |
MountStair(stairTX << 4, stairTY << 4, StairMode);} | |
ScreenChangeHandled = true;} | |
// Update Link's position based on the stair he's on. | |
void LinkStairUpdatePosition() { | |
// First, move according to player input. | |
if (// We can only move if we're standing still or walking. | |
Link->Action == LA_NONE || Link->Action == LA_WALKING) { | |
// Then move left or right, but not both. | |
if (Link->InputLeft) {LinkX -= LINK_WALK;} | |
else if (Link->InputRight) {LinkX += LINK_WALK;}} | |
// If we're at the top or bottom of the stair, check against running | |
// into walls. | |
if (StairPos != STAIR_MIDDLE) { | |
// Check against running into a wall to the left. | |
if (// First check that we moved left. | |
LinkX < OldLinkX && | |
// Then check that we're not at the top of a negative stair. | |
(StairPos != STAIR_TOP || StairMode != STAIR_NEG) && | |
(// Then check for hard blocks at Link's top, middle, and bottom. | |
GetBlockType(LinkX, LinkY) == BLOCK_HARD || | |
GetBlockType(LinkX, LinkY + 8) == BLOCK_HARD || | |
GetBlockType(LinkX, LinkY + 15) == BLOCK_HARD)) { | |
// If he hit, move Link right to the next multiple of 8. | |
LinkX += 8 - (LinkX % 8);} | |
// Check against running into a wall to the right. | |
if (// First check that we moved right. | |
LinkX > OldLinkX && | |
// Then check that we're not at the top of a positive stair. | |
(StairPos != STAIR_TOP || StairMode != STAIR_POS) && | |
(// Then check for hard blocks at Link's top, middle, and bottom. | |
GetBlockType(LinkX + 15, LinkY) == BLOCK_HARD || | |
GetBlockType(LinkX + 15, LinkY + 8) == BLOCK_HARD || | |
GetBlockType(LinkX + 15, LinkY + 15) == BLOCK_HARD)) { | |
// If he hit, move Link left to the previous multiple of 8. | |
LinkX &= 0x1FFF8;}} | |
//// Then adjust y positioning. | |
// If we're at the middle of the stair, use the standard formula. | |
LinkY = LinkX * StairMode + StairY; | |
// If we're at the bottom, align Link with the anchored stair. | |
if (StairPos == STAIR_BOTTOM && | |
((StairMode == STAIR_NEG && LinkX <= ComboX(StairLoc) - 16) || | |
(StairMode == STAIR_POS && LinkX >= ComboX(StairLoc) + 16))) { | |
LinkY = ComboY(StairLoc);} | |
// If we're at the top, align Link with the cell above the anchored stair. | |
else if (StairPos == STAIR_TOP && | |
((StairMode == STAIR_NEG && LinkX >= ComboX(StairLoc) - 1) || | |
(StairMode == STAIR_POS && LinkX <= ComboX(StairLoc) + 1))) { | |
LinkY = ComboY(StairLoc) - 16;}} | |
// Find the stair that Link is currently standing on. | |
void LinkStairFindStair() { | |
if (StairLoc == -1) {return;} | |
//// First, check if we've moved off of the stair we're currently anchored to. | |
// Get the edge closest to the stair. | |
int x = LinkX + Cond(StairMode == STAIR_POS, 0, 15); | |
int stairX = ComboX(StairLoc); | |
int stairTX = StairLoc % 16; | |
int stairTY = StairLoc >> 4; | |
// Direction we've shifted. | |
int shiftDir = 0; | |
// We've moved off the left side of the stair, so move the StairLoc | |
// 1 to the left, plus up or down as appropriate. | |
if (x < stairX) { | |
stairTX--; | |
stairTY -= StairMode; | |
shiftDir = -1;} | |
// We've moved off the right side of the stair, so move the StairLoc | |
// 1 to the right, plus up or down as appropriate. | |
else if (x >= stairX + 16) { | |
stairTX++; | |
stairTY += StairMode; | |
shiftDir = 1;} | |
StairLoc = FindLoc(stairTX, stairTY); | |
StairPos = STAIR_MIDDLE; | |
// If we found the stairs, but we're on the top edge of a stair (and | |
// not on the edge of a screen), set to the top edge anyway. | |
if (IsValidStair(StairLoc) && | |
((StairMode == STAIR_POS && stairTX != 0) || | |
(StairMode == STAIR_NEG && stairTX != 15))) { | |
int aboveLoc = FindLoc(stairTX - StairMode, stairTY - 1); | |
if (!IsValidStair(aboveLoc)) { | |
StairPos = STAIR_TOP;}} | |
// Check for a stair to the side. | |
if (// First, make sure that we didn't already find a stair. | |
!IsValidStair(StairLoc) && | |
// And then also make sure that we didn't shift up the stair, | |
// because we're shifting up again and a double shift doesn't | |
// make sense. | |
shiftDir * StairMode != -1) { | |
StairLoc = FindLoc(stairTX - StairMode, stairTY - 1); | |
// If we're on the bottom of the screen, assume there's more | |
// stairs on the next screen. | |
if (stairTY - 1 < 10) { | |
StairPos = STAIR_BOTTOM;}} | |
// Then check for a stair diagonally downward. | |
if (!IsValidStair(StairLoc)) { | |
StairLoc = FindLoc(stairTX + StairMode, stairTY + 1); | |
StairPos = STAIR_TOP;} | |
// Check if we failed. | |
if (!IsValidStair(StairLoc)) { | |
StairLoc = -1; | |
return;} | |
// Set StairLeft and StairRight to the proper values for Link's position. | |
if (StairPos == STAIR_MIDDLE) { | |
StairLeft = 0; | |
StairRight = 255;} | |
else { | |
stairTX = StairLoc % 16; | |
StairLeft = (stairTX - 1) * 16 - 2; | |
StairRight = (stairTX + 1) * 16 + 2;} | |
// Find if there's a stair above and below. | |
StairAbove = IsValidStair(FindLoc(stairTX - StairMode, stairTY - 1)); | |
StairBelow = IsValidStair(FindLoc(stairTX + StairMode, stairTY + 1));} | |
// See if Link is leaving the stairs. | |
void LinkStairFallOff() { | |
if (// Getting hurt knocks you off of stairs. | |
Link->Action == LA_GOTHURTLAND || Link->Action == LA_GOTHURTWATER || | |
// If we couldn't locate a stair earlier, that means we fall off, too. | |
StairLoc == -1 || | |
// Or if we've moved too far off of the top or bottom of a stair. | |
LinkX < StairLeft || LinkX > StairRight) { | |
StairMode = STAIR_NONE; | |
LinkMode = LINK_MODE_CUSTOM;}} | |
// Jump according to stair mode rules. | |
void LinkStairJump() { | |
if (// The Jump button is pressed. | |
PressJump && | |
// Can't be doing anything but walking. | |
(Link->Action == LA_NONE || Link->Action == LA_WALKING)) { | |
StairMode = STAIR_NONE; | |
LinkMode = LINK_MODE_CUSTOM; | |
// Jump! | |
SideviewJump();}} | |
// Assigns all the OldLink variables for the upcoming frame. | |
// Place before Waitdraw(). | |
void OldLink_Update1() { | |
OldLinkX = Link->X; | |
OldLinkY = Link->Y; | |
OldLinkAction = Link->Action;} | |
// Record the current dmap and dscreen right before they are changed. | |
// Place before Waitdraw(). | |
void ScreenChange_Update1() { | |
OldDMap = Game->GetCurDMap(); | |
OldDScreen = Game->GetCurDMapScreen();} | |
// Updates information dealing with changing screens. | |
// Place after Waitdraw(), when the screen changes happen. | |
void ScreenChange_Update2() { | |
// Grab current values. | |
int dMap = Game->GetCurDMap(); | |
int dScreen = Game->GetCurDMapScreen(); | |
// Compare with old values. | |
DMapChanged = dMap != OldDMap; | |
ScreenChanged = DMapChanged || dScreen != OldDScreen; | |
// Check for scrolling change to the same screen. | |
if (Link->Action == LA_SCROLLING) { | |
if (!ScreenChanged && !_ScreenChanged_ScrollFlag) { | |
ScreenChanged = true; | |
_ScreenChanged_ScrollFlag = true;}} | |
// We're no longer scrolling, so reset scroll flag. | |
else { | |
_ScreenChanged_ScrollFlag = false;} | |
// Check for a forced screen change flag. | |
if (_ScreenChanged_ForceFlag) { | |
ScreenChanged = true; | |
_ScreenChanged_ForceFlag = false;} | |
// Find the screen change direction. | |
if (ScreenChanged) { | |
// Mark the screen change as needing to be handled. | |
ScreenChangeHandled = false; | |
// Try to guess the direction. | |
if (Link->Y >= 160) {ScreenChangeDir = DIR_UP;} | |
else if (Link->Y <= 0) {ScreenChangeDir = DIR_DOWN;} | |
else if (Link->X >= 240) {ScreenChangeDir = DIR_LEFT;} | |
else if (Link->X <= 0) {ScreenChangeDir = DIR_RIGHT;} | |
else {ScreenChangeDir = SCREEN_CHANGE_WARP;}}} | |
// Adjust some of Link's variables after all the mechanical | |
// manipulation is done. | |
void LinkAdjust() { | |
// Don't do anything in engine mode. | |
if (LinkMode == LINK_MODE_ENGINE) {return;} | |
// Update Link's actual position. | |
Link->X = Round(LinkX); | |
Link->Y = Round(LinkY); | |
// Force the walking animation if we moved and have no other action. | |
if (Link->Action == LA_NONE && (LinkX != OldLinkX || LinkY != OldLinkY)) { | |
Link->Action = LA_WALKING;} | |
// Set the direction according to input. | |
if (Link->InputUp) {Link->Dir = DIR_UP;} | |
else if (Link->InputDown) {Link->Dir = DIR_DOWN;} | |
else if (Link->InputLeft) {Link->Dir = DIR_LEFT;} | |
else if (Link->InputRight) {Link->Dir = DIR_RIGHT;}} | |
// Don't scroll through items on sideview screens with L. | |
void Input_Update1() { | |
// Ignore L if this is a sideview screen. | |
if (IsSideview()) { | |
InputJump = Link->InputL; | |
PressJump = Link->PressL; | |
Link->InputL = false; | |
Link->PressL = false;}} | |
// Change the inputs so the engine doesn't set Link facing a weird | |
// direction or something else we don't want. | |
void Input_Update2() { | |
// If we're not in engine mode, up and down take preference for | |
// direction. | |
if (LinkMode != LINK_MODE_ENGINE && | |
(Link->InputUp || Link->InputDown)) { | |
Link->InputLeft = false; | |
Link->InputRight = false; | |
Link->PressLeft = false; | |
Link->PressRight = false;}} | |
ffc script ScreenChange { | |
void run() { | |
_ScreenChanged_ForceFlag = true;}} | |
// Don't carry over velocity or stair state. | |
global script OnContinue { | |
void run() { | |
StairMode = STAIR_NONE; | |
LinkVy = 0;}} | |
// Set first argument to Link's full jump speed. | |
// Set second argument to Link's jump speed while holding down. | |
item script AdjustLinkJump { | |
void run (int jumpSpeed, int hopSpeed) { | |
LinkJump = jumpSpeed; | |
LinkHop = hopSpeed;}} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment