Skip to content

Instantly share code, notes, and snippets.

@gwx
Created August 20, 2013 13:49
Show Gist options
  • Save gwx/6281707 to your computer and use it in GitHub Desktop.
Save gwx/6281707 to your computer and use it in GitHub Desktop.
// There is no custom link action - fall back on Link->Action.
const int CLA_NONE = 0;
// Link is pounding with a hammer.
const int CLA_POUND = 1;
// Link is stabbing.
const int CLA_STAB = 2;
// Link is throwing.
const int CLA_THROW = 3;
// Link is slashing.
const int CLA_SLASH = 4;
// Link is recovering.
const int CLA_RECOVER = 5;
//// Pound Constants
// Start of 8 tiles for link pounding. The animation is 2 tiles long.
const int CLA_POUND_TILE = 38442;
// Pound total duration.
const int CLA_POUND_DURATION = 16;
// Tick on which link switches to the next frame.
const int CLA_POUND_LINK_ADV1 = 6;
// Tick on which item switches to the next frame.
const int CLA_POUND_ITEM_ADV1 = 6;
const int CLA_POUND_ITEM_ADV2 = 7;
// Tick on which the strike hits.
const int CLA_POUND_HIT = 7;
//// Stab Constants
// Start of 4 tiles for link stabbing.
const int CLA_STAB_TILE = 38452;
// Stab total duration.
const int CLA_STAB_DURATION = 12;
//// Throw Constants
// Start of 4 tiles for Link throwing.
const int CLA_THROW_TILE = 38452;
// Throw total duration.
const int CLA_THROW_DURATION = 6;
//// Slash Constants
// Start of 12 tiles for link slashing.
const int CLA_SLASH_TILE = 38462;
// Tick on which link switches to the next frame.
const int CLA_SLASH_ADV1 = 4;
const int CLA_SLASH_ADV2 = 8;
// Slash total duration.
const int CLA_SLASH_DURATION = 12;
// The current custom link action.
int CLA_Action = CLA_NONE;
// The current animation id for link.
int CLA_LinkAnimationId = LWEAPON_ID_NULL;
// The number of frames the current action has been happening.
int CLA_Frames = 0;
// Timer for custom durations.
int CLA_Timer = 0;
//// Info for the item being used to read.
// The current item location.
int CLA_ItemX = 0;
int CLA_ItemY = 0;
// The current item frame offset.
int CLA_ItemFrame = 0;
// If the weapon is striking during this frame.
bool CLA_Strike = false;
// Test for standard actions that we can override.
bool CLA_CanAct() {
return CLA_Action == CLA_NONE &&
(Link->Action == LA_NONE ||
Link->Action == LA_WALKING ||
Link->Action == LA_GOTHURTLAND);}
// Make the animation base.
lweapon CLA_CreateAnimationBase() {
lweapon base = Screen->CreateLWeapon(LW_ANIMATION2);
base->DeadState = -2;
base->CollDetection = false;
base->Behind = true;
base->Frame = 0;
base->NumFrames = 9999;
base->ASpeed = 3600;
return base;}
// Update running custom link action. Just calls the respective update
// method for each action.
void CLA_Update() {
if (CLA_Action == CLA_POUND) {CLA_UpdatePound();}
else if (CLA_Action == CLA_STAB) {CLA_UpdateStab();}
else if (CLA_Action == CLA_SLASH) {CLA_UpdateSlash();}
else if (CLA_Action == CLA_THROW) {CLA_UpdateThrow();}
else if (CLA_Action == CLA_RECOVER) {CLA_UpdateRecover();}}
// Pound with an item.
void CLA_Pound() {
// Only works if we're not doing anything else.
if (!CLA_CanAct()) {return;}
CLA_Action = CLA_POUND;
BlockInput(KEY_DIR, CLA_POUND_DURATION);
// Setup Link's animation.
Link->Invisible = true;
lweapon animation = CLA_CreateAnimationBase();
animation->OriginalTile = CLA_POUND_TILE;
animation->CSet = 6;
CLA_LinkAnimationId = GetId(animation);
CLA_Frames = -1;
CLA_UpdatePound();}
// Stab with an item.
void CLA_Stab() {
// Only works if we're not doing anything else.
if (!CLA_CanAct()) {return;}
CLA_Action = CLA_STAB;
BlockInput(KEY_DIR, CLA_STAB_DURATION);
// Steup Link's animation.
Link->Invisible = true;
lweapon animation = CLA_CreateAnimationBase();
animation->OriginalTile = CLA_STAB_TILE;
animation->CSet = 6;
CLA_LinkAnimationId = GetId(animation);
CLA_Frames = -1;
CLA_UpdateStab();}
// Slash with an item.
void CLA_Slash() {
// Only works if we're not doing anything else.
if (!CLA_CanAct()) {return;}
CLA_Action = CLA_SLASH;
BlockInput(KEY_DIR, CLA_SLASH_DURATION);
// Steup Link's animation.
Link->Invisible = true;
lweapon animation = CLA_CreateAnimationBase();
animation->OriginalTile = CLA_SLASH_TILE;
animation->CSet = 6;
CLA_LinkAnimationId = GetId(animation);
CLA_Frames = -1;
CLA_UpdateSlash();}
void CLA_Throw() {
// Only works if we're not doing anything else.
if (!CLA_CanAct()) {return;}
CLA_Action = CLA_THROW;
BlockInput(KEY_DIR, CLA_THROW_DURATION);
// Steup Link's animation.
Link->Invisible = true;
lweapon animation = CLA_CreateAnimationBase();
animation->OriginalTile = CLA_THROW_TILE;
animation->CSet = 6;
CLA_LinkAnimationId = GetId(animation);
CLA_Frames = -1;
CLA_UpdateThrow();}
void CLA_Recover(int duration) {
// Only works if we're not doing anything else.
if (!CLA_CanAct()) {return;}
CLA_Action = CLA_RECOVER;
BlockInput(KEY_DIR, duration);
CLA_Frames = -1;
CLA_Timer = duration + 1;
CLA_UpdateRecover();}
void CLA_UpdatePound() {
Link->Action = LA_ATTACKING;
CLA_Frames++;
// Update link animation.
lweapon animation = FindLWeapon(CLA_LinkAnimationId);
animation->DrawXOffset = Link->X;
animation->DrawYOffset = Link->Y;
animation->Frame = Link->Dir * 2 +
Cond(CLA_Frames >= CLA_POUND_LINK_ADV1, 1, 0);
animation->Tile = animation->OriginalTile + animation->Frame;
// Update item info.
if (CLA_Frames >= CLA_POUND_ITEM_ADV2) {
CLA_ItemX = DirX(Link->Dir) * 16 + Link->X;
CLA_ItemY = DirY(Link->Dir) * 16 + Link->Y;
CLA_ItemFrame = 2;}
else if (CLA_Frames >= CLA_POUND_ITEM_ADV1) {
if (Link->Dir >= DIR_LEFT) {
CLA_ItemX = DirX(Link->Dir) * 12 + Link->X;
CLA_ItemY = Link->Y - 4;}
else {
CLA_ItemX = Link->X;
CLA_ItemY = 16 * (Link->Dir - 1) + Link->Y;}
CLA_ItemFrame = 1;}
else {
CLA_ItemX = Link->X;
CLA_ItemY = Link->Y - 14;
CLA_ItemFrame = 0;}
CLA_Strike = CLA_Frames == CLA_POUND_HIT;
// Exit out if we need to.
if (CLA_Frames >= CLA_POUND_DURATION) {
Remove(animation);
Link->Action = LA_NONE;
CLA_Action = CLA_NONE;
Link->Invisible = false;}}
void CLA_UpdateStab() {
Link->Action = LA_ATTACKING;
CLA_Frames++;
lweapon animation = FindLWeapon(CLA_LinkAnimationId);
animation->DrawXOffset = Link->X;
animation->DrawYOffset = Link->Y;
animation->Frame = Link->Dir;
animation->Tile = animation->OriginalTile + animation->Frame;
// Item Info.
int offset = 14;
if (CLA_Frames < 2) {offset = 10 + CLA_Frames * 2;}
else if (CLA_Frames > CLA_STAB_DURATION - 2) {
offset = 10 + (CLA_STAB_DURATION - CLA_Frames) * 2;}
CLA_ItemX = offset * DirX(Link->Dir) + Link->X;
CLA_ItemY = offset * DirY(Link->Dir) + Link->Y;
// Exit if needed.
if (CLA_Frames >= CLA_STAB_DURATION) {
Remove(animation);
Link->Action = LA_NONE;
CLA_Action = CLA_NONE;
Link->Invisible = false;}}
void CLA_UpdateThrow() {
Link->Action = LA_ATTACKING;
CLA_Frames++;
lweapon animation = FindLWeapon(CLA_LinkAnimationId);
animation->DrawXOffset = Link->X;
animation->DrawYOffset = Link->Y;
animation->Frame = Link->Dir;
animation->Tile = animation->OriginalTile + animation->Frame;
// Item Info.
int offset = 8;
CLA_ItemX = offset * DirX(Link->Dir) + Link->X;
CLA_ItemY = offset * DirY(Link->Dir) + Link->Y;
// Exit if needed.
if (CLA_Frames >= CLA_THROW_DURATION) {
Remove(animation);
Link->Action = LA_NONE;
CLA_Action = CLA_NONE;
Link->Invisible = false;}}
void CLA_UpdateSlash() {
Link->Action = LA_ATTACKING;
CLA_Frames++;
// Update link animation.
lweapon animation = FindLWeapon(CLA_LinkAnimationId);
animation->DrawXOffset = Link->X;
animation->DrawYOffset = Link->Y;
animation->Frame = Link->Dir * 3 +
Cond(CLA_Frames >= CLA_SLASH_ADV1, 1, 0) +
Cond(CLA_Frames >= CLA_SLASH_ADV2, 1, 0);
animation->Tile = animation->OriginalTile + animation->Frame;
// Update item info.
if (CLA_Frames >= CLA_SLASH_ADV2) {
CLA_ItemFrame = 2;
if (Link->Dir == DIR_UP) {
CLA_ItemX = Link->X - 8;
CLA_ItemY = Link->Y - 8;}
else if (Link->Dir == DIR_DOWN) {
CLA_ItemX = Link->X + 8;
CLA_ItemY = Link->Y + 8;}
else if (Link->Dir == DIR_LEFT) {
CLA_ItemX = Link->X - 8;
CLA_ItemY = Link->Y + 8;}
else if (Link->Dir == DIR_RIGHT) {
CLA_ItemX = Link->X + 8;
CLA_ItemY = Link->Y + 8;}}
else if (CLA_Frames >= CLA_SLASH_ADV1) {
CLA_ItemX = DirX(Link->Dir) * 14 + Link->X;
CLA_ItemY = DirY(Link->Dir) * 14 + Link->Y;
CLA_ItemFrame = 1;}
else {
CLA_ItemFrame = 0;
if (Link->Dir == DIR_UP) {
CLA_ItemX = Link->X + 8;
CLA_ItemY = Link->Y - 8;}
else if (Link->Dir == DIR_DOWN) {
CLA_ItemX = Link->X - 8;
CLA_ItemY = Link->Y + 8;}
else if (Link->Dir == DIR_LEFT) {
CLA_ItemX = Link->X - 8;
CLA_ItemY = Link->Y - 8;}
else if (Link->Dir == DIR_RIGHT) {
CLA_ItemX = Link->X + 8;
CLA_ItemY = Link->Y - 8;}}
CLA_Strike = true;
// Exit out if we need to.
if (CLA_Frames >= CLA_SLASH_DURATION) {
Remove(animation);
Link->Action = LA_NONE;
CLA_Action = CLA_NONE;
Link->Invisible = false;}}
void CLA_UpdateRecover() {
CLA_Timer--;
if (CLA_Timer <= 0) {
CLA_Action = CLA_NONE;}}
// Make sure we don't get permanently stuck somehow.
void CLA_Continue() {
CLA_Action = CLA_NONE;}
// tile - starting tile for spear.
// damage - damage done.
// length - length of the spear in pixels.
item script IU_Spear {
void run(int _, int tile, int damage, int length) {
if (CLA_CanAct()) {
CreateFFC(SCR_FFC_SPEAR, tile, damage, length);}}}
ffc script Spear {
void run(int tile, int damage, int length) {
this->Flags[FFCF_ETHEREAL] = true;
Game->PlaySound(SFX_SWORD);
int offset = length - 16;
// Number of tiles the spear takes up.
int size = (length + 15) >> 4;
// Calculate offsets from standard.
int strikeDX = DirX(Link->Dir) * offset;
int strikeDY = DirY(Link->Dir) * offset;
int drawDX = Min(strikeDX, 0);
int drawDY = Min(strikeDY, 0);
lweapon animation = Screen->CreateLWeapon(LW_ANIMATION2);
int animationId = GetId(animation);
animation->DeadState = -2;
animation->OriginalTile = tile + Link->Dir * size;
animation->Behind = true;
animation->CSet = 5;
animation->CollDetection = false;
animation->Frame = 0;
animation->NumFrames = 40;
animation->ASpeed = 3600;
animation->Extend = EXT_NORMAL;
animation->TileWidth = size;
animation->TileHeight = size;
// Put after animation so that link is on top of spear.
CLA_Stab();
int strikeId = LWEAPON_ID_NULL;
lweapon strike;
while (CLA_Action == CLA_STAB) {
animation = FindLWeapon(animationId);
animation->DrawXOffset = CLA_ItemX + drawDX;
animation->DrawYOffset = CLA_ItemY + drawDY;
animation->Tile = animation->OriginalTile;
// (Re)create strike if needed.
if (strikeId == LWEAPON_ID_NULL || !strike->isValid()) {
strike = Spear_CreateStrike(damage);
strikeId = GetId(strike);}
// Update strike position.
strike->X = Clamp(CLA_ItemX + strikeDX, 0, 240);
strike->Y = Clamp(CLA_ItemY + strikeDY, 0, 160);
Slash_SlashSolid(strike);
Waitframe();
strike = FindLWeapon(strikeId);}
if (strikeId != LWEAPON_ID_NULL) {
Remove(FindLWeapon(strikeId));}
Remove(FindLWeapon(animationId));}}
lweapon Spear_CreateStrike(int damage) {
lweapon strike = CLWeaponCreate();
strike->DrawXOffset = 500;
strike->Damage = damage;
strike->Dir = Link->Dir;
return strike;}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment