import "std.zh"
import "ffcscript.zh"
const int BIG_LINK = 0;
const int CT_HOLELAVA = 128;
const int CF_PIT = 98;
const int CF_LAVA = 99;
const int WPS_LINK_FALL = 94;
const int WPS_LINK_LAVA = 95;
const int SFX_LINK_FALL = 38;
const int SFX_LINK_LAVA = 55;
const int CMB_AUTOWARP = 48;
const int HOLELAVA_DAMAGE = 8;
const int LAYER_NPC = 2; //The layer NPCs use for solid combos
const int CMB_NPC_HIDDEN = 41; //Non-solid combo used for hidden NPCs
const int CMB_NPC_SOLID = 42; //Solid combo placed under visible NPCs
const int LAYER_NPC_CANTALK = 6; //The layer used for the speech bubble
const int CMB_NPC_CANTALK = 44; //The combo used for the speech bubble
const int CS_NPC_CANTALK = 8; //The CSet used for the speech bubble
const int NPCBT_NONE = 0; //Regular NPCs
const int NPCBT_FACELINK = 1; //NPCs that turn to face Link
const int NPCBT_GUARDH = 2; //NPCs that move along a horizontal path
const int NPCBT_GUARDV = 3; //NPCs that move along a vertical path
const int DigComboStart=73;
const int DigComboEnd=226;
const int DigSpecialStart=227;
const int DigSpecialEnd=231;
const int DugComboNormal=57;
const int DugComboSpecial=57;
const int ShovelSound=64;
const int ShovelFail=57;
const int SecretSound=27;
int Falling;
bool Warping;
global script slot2_holelava
{
void run()
{
//Initialize variables used to store Link's strating position on Screen Init.
int olddmap = Game->GetCurDMap();
int oldscreen = Game->GetCurDMapScreen();
int startx = Link->X;
int starty = Link->Y;
int startdir = Link->Dir;
//Clear global variables used by Bottomless pits.
Falling = 0;
Warping = false;
//Main Loop
while(true)
{
Waitdraw();
if(Link->Action != LA_SCROLLING)
{
Update_HoleLava(startx, starty, olddmap, oldscreen, startdir);
if(Link->Z==0 && !Falling && (oldscreen != Game->GetCurDMapScreen() || olddmap != Game->GetCurDMap()))
{
olddmap = Game->GetCurDMap();
oldscreen = Game->GetCurDMapScreen();
startx = Link->X;
starty = Link->Y;
startdir = Link->Dir;
}
}
Waitframe();
}
}
}
//Handles Pit Combo Functionality.
void Update_HoleLava(int x, int y, int dmap, int scr, int dir)
{
lweapon hookshot = LoadLWeaponOf(LW_HOOKSHOT);
if(hookshot->isValid()) return;
if(Falling)
{
if(IsSideview()) Link->Jump=0;
Falling--;
if(Falling == 1)
{
int buffer[] = "Holelava";
if(CountFFCsRunning(Game->GetFFCScript(buffer)))
{
ffc f = Screen->LoadFFC(FindFFCRunning(Game->GetFFCScript(buffer)));
Warping = true;
if(f->InitD[1]==0)
{
f->InitD[6] = x;
f->InitD[7] = y;
}
}
else
{
Link->X = x;
Link->Y = y;
Link->Dir = dir;
Link->DrawXOffset -= Cond(Link->DrawXOffset < 0, -1000, 1000);
Link->HitXOffset -= Cond(Link->HitXOffset < 0, -1000, 1000);
Link->HP -= HOLELAVA_DAMAGE;
Link->Action = LA_GOTHURTLAND;
Link->HitDir = -1;
Game->PlaySound(SFX_OUCH);
if(Game->GetCurDMap()!=dmap || Game->GetCurDMapScreen()!=scr)
Link->PitWarp(dmap, scr);
}
NoAction();
Link->Action = LA_NONE;
}
}
else if(Link->Z==0 && OnPitCombo() && !Warping)
{
Link->DrawXOffset += Cond(Link->DrawXOffset < 0, -1000, 1000);
Link->HitXOffset += Cond(Link->HitXOffset < 0, -1000, 1000);
int comboflag = OnPitCombo();
SnaptoGrid();
Game->PlaySound(Cond(comboflag == CF_PIT, SFX_LINK_FALL, SFX_LINK_LAVA));
lweapon dummy = CreateLWeaponAt(LW_SCRIPT10, Link->X, Link->Y);
dummy->UseSprite(Cond(comboflag == CF_PIT, WPS_LINK_FALL, WPS_LINK_LAVA));
dummy->DeadState = dummy->NumFrames*dummy->ASpeed;
dummy->DrawXOffset = 0;
dummy->DrawYOffset = 0;
Falling = dummy->DeadState;
NoAction();
Link->Action = LA_NONE;
}
}
ffc script Holelava
{
void run(int warp, bool position, int damage)
{
while(true)
{
while(!Warping) Waitframe();
if(warp > 0)
{
this->Data = CMB_AUTOWARP+warp-1;
this->Flags[FFCF_CARRYOVER] = true;
Waitframe();
this->Data = FFCS_INVISIBLE_COMBO;
this->Flags[FFCF_CARRYOVER] = false;
Link->Z = Link->Y;
Warping = false;
Link->DrawXOffset -= Cond(Link->DrawXOffset < 0, -1000, 1000);
Link->HitXOffset -= Cond(Link->HitXOffset < 0, -1000, 1000);
Quit();
}
if(position)
{
Link->X = this->X;
Link->Y = this->Y;
}
else
{
Link->X = this->InitD[6];
Link->Y = this->InitD[7];
}
if(damage)
{
Link->HP -= damage;
Link->Action = LA_GOTHURTLAND;
Link->HitDir = -1;
Game->PlaySound(SFX_OUCH);
}
Link->DrawXOffset -= Cond(Link->DrawXOffset < 0, -1000, 1000);
Link->HitXOffset -= Cond(Link->HitXOffset < 0, -1000, 1000);
Warping = false;
Waitframe();
}
}
}
//Used to determine if Link is on a Pit or Lava combo.
int OnPitCombo()
{
int comboLoc = ComboAt(Link->X+8, Link->Y + Cond(BIG_LINK==0, 12, 8));
if(Screen->ComboT[comboLoc] != CT_HOLELAVA)
return 0;
else if(Screen->ComboI[comboLoc] == CF_PIT || Screen->ComboI[comboLoc] == CF_LAVA)
return Screen->ComboI[comboLoc];
else if(Screen->ComboF[comboLoc] == CF_PIT || Screen->ComboF[comboLoc] == CF_LAVA)
return Screen->ComboF[comboLoc];
else
return 0;
}
//Snaps Link to the combo so he appears completely over pit and lava combos.
void SnaptoGrid()
{
int x = Link->X;
int y = Link->Y + Cond(BIG_LINK==0, 8, 0);
int comboLoc = ComboAt(x, y);
//X Axis
if(Screen->ComboT[comboLoc] == CT_HOLELAVA && Cond(x % 16 == 0, true, Screen->ComboT[comboLoc+1] != CT_HOLELAVA))
Link->X = ComboX(comboLoc);
else if(Screen->ComboT[comboLoc+1] == CT_HOLELAVA && Cond(x % 16 == 0, true, Screen->ComboT[comboLoc] != CT_HOLELAVA))
Link->X = ComboX(comboLoc+1);
if(Cond(y % 16 == 0, false, Screen->ComboT[comboLoc+16] == CT_HOLELAVA) && Cond(x % 16 == 0, true, Screen->ComboT[comboLoc+17] != CT_HOLELAVA))
Link->X = ComboX(comboLoc+16);
else if(Cond(y % 16 == 0, false, Screen->ComboT[comboLoc+17] == CT_HOLELAVA) && Cond(x % 16 == 0, true, Screen->ComboT[comboLoc+16] != CT_HOLELAVA))
Link->X = ComboX(comboLoc+17);
//Y Axis
if(Screen->ComboT[comboLoc] == CT_HOLELAVA && Cond(y % 16 == 0, true, Screen->ComboT[comboLoc+16] != CT_HOLELAVA))
Link->Y = ComboY(comboLoc);
else if(Screen->ComboT[comboLoc+16] == CT_HOLELAVA && Cond(y % 16 == 0, true, Screen->ComboT[comboLoc] != CT_HOLELAVA))
Link->Y = ComboY(comboLoc+16);
if(Cond(x % 16 == 0, false, Screen->ComboT[comboLoc+1] == CT_HOLELAVA) && Cond(y % 16 == 0, true, Screen->ComboT[comboLoc+17] != CT_HOLELAVA))
Link->Y = ComboY(comboLoc+1);
else if(Cond(x % 16 == 0, false, Screen->ComboT[comboLoc+17] == CT_HOLELAVA) && Cond(y % 16 == 0, true, Screen->ComboT[comboLoc+1] != CT_HOLELAVA))
Link->Y = ComboY(comboLoc+17);
}
ffc script NPCScript{
void run(int String, int ItemCheck, int Type, int Arg1, int Arg2, int NoSolid, int Script, int ItemToGive){
//Stores the NPC's combo, hides it
int Combo = this->Data;
this->Data = CMB_NPC_HIDDEN;
//Waits until the NPC should appear and shows it
if(ItemCheck<0){
while(!Link->Item[Abs(ItemCheck)]){
Waitframe();
}
this->Data = Combo;
if(Type==NPCBT_FACELINK){
this->Data = Combo + Arg1;
}
}
else if(ItemCheck>0){
if(!Link->Item[Abs(ItemCheck)]){
this->Data = Combo;
if(Type==NPCBT_FACELINK){
this->Data = Combo + Arg1;
}
}
}
else if(ItemCheck==0){
this->Data = Combo;
if(Type==NPCBT_FACELINK){
this->Data = Combo + Arg1;
}
}
//Saves the width and height of the FFC for collision checks
int Width = 16;
int Height = 16;
if(this->EffectWidth!=16)
Width = this->EffectWidth;
else if(this->TileWidth>1)
Width = this->TileWidth*16;
if(this->EffectHeight!=16)
Height = this->EffectHeight;
else if(this->TileHeight>1)
Height = this->TileHeight*16;
//Wait until the screen is done scrolling to avoid a weird ZC crashing bug
Waitframe();
while(Link->Action==LA_SCROLLING){
Waitframe();
}
//Sets the space below the NPC or the space a guard NPC occupies to be solid
if(LAYER_NPC>-1&&NoSolid==0){
if(Type==NPCBT_GUARDH){
for(int x=Arg1; x<=Arg2+this->TileWidth-1; x++){
for(int y=Floor(this->Y/16); y<=Floor(this->Y/16)+this->TileHeight-1; y++){
SetLayerComboD(LAYER_NPC, y*16+x, CMB_NPC_SOLID);
}
}
}
else if(Type==NPCBT_GUARDV){
for(int x=Floor(this->X/16); x<=Floor(this->X/16)+this->TileWidth-1; x++){
for(int y=Arg1; y<=Arg2+this->TileHeight-1; y++){
SetLayerComboD(LAYER_NPC, y*16+x, CMB_NPC_SOLID);
}
}
}
else{
for(int x=Floor(this->X/16); x<=Floor(this->X/16)+this->TileWidth-1; x++){
for(int y=Floor(this->Y/16); y<=Floor(this->Y/16)+this->TileHeight-1; y++){
SetLayerComboD(LAYER_NPC, y*16+x, CMB_NPC_SOLID);
}
}
}
}
while(true){
//Removes NPCs if Link has the required item
if(ItemCheck>0){
if(Link->Item[ItemCheck]){
this->Data = CMB_NPC_HIDDEN;
if(LAYER_NPC>-1&&NoSolid==0){
if(Type==NPCBT_GUARDH){
for(int x=Arg1; x<=Arg2+this->TileWidth-1; x++){
for(int y=Floor(this->Y/16); y<=Floor(this->Y/16)+this->TileHeight-1; y++){
SetLayerComboD(LAYER_NPC, y*16+x, CMB_NPC_HIDDEN);
}
}
}
else if(Type==NPCBT_GUARDV){
for(int x=Floor(this->X/16); x<=Floor(this->X/16)+this->TileWidth-1; x++){
for(int y=Arg1; y<=Arg2+this->TileHeight-1; y++){
SetLayerComboD(LAYER_NPC, y*16+x, CMB_NPC_HIDDEN);
}
}
}
else{
for(int x=Floor(this->X/16); x<=Floor(this->X/16)+this->TileWidth-1; x++){
for(int y=Floor(this->Y/16); y<=Floor(this->Y/16)+this->TileHeight-1; y++){
SetLayerComboD(LAYER_NPC, y*16+x, CMB_NPC_HIDDEN);
}
}
}
}
Quit();
}
}
//Handles animation for turning NPCs
if(Type==NPCBT_FACELINK&&(Link->X>0&&Link->X<240&&Link->Y>0&&Link->Y<160)){
if(Distance(CenterLinkX(), CenterLinkY(), CenterX(this), CenterY(this))<Arg2)
this->Data = Combo + AngleDir4(Angle(CenterX(this), CenterY(this), CenterLinkX(), CenterLinkY()));
else
this->Data = Combo + Arg1;
}
//Handles movement for guard NPCs
else if(Type==NPCBT_GUARDH){
if(Link->X>16*Arg1-32&&Link->X<16*Arg2+32&&Link->Y>this->Y-32&&Link->Y<this->Y+32){
this->X = Clamp(this->X+(-this->X + Link->X)/4, 16*Arg1, 16*Arg2);
}
}
else if(Type==NPCBT_GUARDV){
if(Link->X>this->X-32&&Link->X<this->X+32&&Link->Y>16*Arg1-32&&Link->Y<16*Arg2+32){
this->Y = Clamp(this->Y+(-this->Y + Link->Y)/4, 16*Arg1, 16*Arg2);
}
}
//Facing Up
if(Link->Dir==DIR_UP&&Link->Y>=this->Y&&Link->Y<=this->Y+Height-8&&Link->X>=this->X-8&&Link->X<=this->X+Width-8){
if(CMB_NPC_CANTALK>0)
Screen->FastCombo(LAYER_NPC_CANTALK, Link->X, Link->Y-16, CMB_NPC_CANTALK, CS_NPC_CANTALK, 128);
if(Link->PressA){
Link->InputA = false;
Link->PressA = false;
Screen->Message(String);
Link->Item[ItemToGive] = true;
if(Script>0){
RunFFCScript(Script, 0);
}
}
}
//Facing Down
else if(Link->Dir==DIR_DOWN&&Link->Y>=this->Y-16&&Link->Y<=this->Y+Height-16&&Link->X>=this->X-8&&Link->X<=this->X+Width-8){
if(CMB_NPC_CANTALK>0)
Screen->FastCombo(LAYER_NPC_CANTALK, Link->X, Link->Y-16, CMB_NPC_CANTALK, CS_NPC_CANTALK, 128);
if(Link->PressA){
Link->InputA = false;
Link->PressA = false;
Screen->Message(String);
if(Script>0){
RunFFCScript(Script, 0);
}
}
}
//Facing Left
else if(Link->Dir==DIR_LEFT&&Link->Y>=this->Y-8&&Link->Y<=this->Y+Height-8&&Link->X>=this->X&&Link->X<=this->X+Width){
if(CMB_NPC_CANTALK>0)
Screen->FastCombo(LAYER_NPC_CANTALK, Link->X, Link->Y-16, CMB_NPC_CANTALK, CS_NPC_CANTALK, 128);
if(Link->PressA){
Link->InputA = false;
Link->PressA = false;
Screen->Message(String);
if(Script>0){
RunFFCScript(Script, 0);
}
}
}
//Facing Right
else if(Link->Dir==DIR_RIGHT&&Link->Y>=this->Y-8&&Link->Y<=this->Y+Height-8&&Link->X>=this->X-16&&Link->X<=this->X+Width-16){
if(CMB_NPC_CANTALK>0)
Screen->FastCombo(LAYER_NPC_CANTALK, Link->X, Link->Y-16, CMB_NPC_CANTALK, CS_NPC_CANTALK, 128);
if(Link->PressA){
Link->InputA = false;
Link->PressA = false;
Screen->Message(String);
if(Script>0){
RunFFCScript(Script, 0);
}
}
}
Waitframe();
}
}
}
ffc script sign {
void run(int m, int ItemToGive) {
bool close;
while(true){
if ( Link->X >= this->X - 8 && Link->X <= this->X + 24 && Link->Y >= this->Y && Link->Y <= this->Y + 24 && Link->Dir == DIR_UP ){
close = true;
}
if ( Link->X < this->X - 8 || Link->X > this->X + 24 || Link->Y < this->Y || Link->Y > this->Y + 24 || Link->Dir != DIR_UP ) {
close = false;
}
if ( Link->PressA && close ) {
Screen->Message(m);
if ( !Link->Item[ItemToGive] == false)
{
item GiveItem= Screen->CreateItem(ItemToGive);
GiveItem->X = Link->X;
GiveItem->Y = Link->Y;
GiveItem->Z = Link->Z;
}
}
//Screen->Message(0); //Why do we have a hardcoded message here?
Waitframe();
}
}
}
ffc script GiveItems{
void run(int life, int rupees, int bombs, int arrows, int magic, int keys, int superbombs, int thing){
Game->Counter[CR_LIFE] += (life);
Game->Counter[CR_RUPEES] += (rupees);
Game->Counter[CR_BOMBS] += (bombs);
Game->Counter[CR_ARROWS] += (arrows);
Game->Counter[CR_MAGIC] += (magic);
Game->Counter[CR_KEYS] += (keys);
Game->Counter[CR_SBOMBS] += (superbombs);
Link->Item[thing] = true;
Waitframe();
}
}
ffc script Key{
void run(){
Game->Counter[CR_KEYS] += 1;
Link->HeldItem = 9;
Link->Action = LA_HOLD2LAND;
Game->PlaySound(20);
Link->Item[Screen->RoomData] = true;
Waitframe();
}
}
ffc script messageonlyone{
void run(int m){
if(Screen->D[0] != 1){
Screen->Message(m);
Screen->D[0] = 1;
}
}
}
item script Shovel{
void run(){
int chance;
int itemdrop;
int itemlocx;
int itemlocy;
Link->Action=LA_ATTACKING;
if((Link->Dir==0&&(Screen->ComboD[ComboAt(Link->X+8,Link->Y-8)]<DigComboStart||Screen->ComboD[ComboAt(Link->X+8,Link->Y-8)]>DigSpecialEnd))
||(Link->Dir==1&&(Screen->ComboD[ComboAt(Link->X+8,Link->Y+24)]<DigComboStart||Screen->ComboD[ComboAt(Link->X+8,Link->Y+24)]>DigSpecialEnd))
||(Link->Dir==2&&(Screen->ComboD[ComboAt(Link->X-8,Link->Y+8)]<DigComboStart||Screen->ComboD[ComboAt(Link->X-8,Link->Y+8)]>DigSpecialEnd))
||(Link->Dir==3&&(Screen->ComboD[ComboAt(Link->X+24,Link->Y+8)]<DigComboStart||Screen->ComboD[ComboAt(Link->X+24,Link->Y+8)]>DigSpecialEnd))){
Game->PlaySound(ShovelFail);
}
else{
Game->PlaySound(ShovelSound);
chance=Rand(100)+1;
if(Link->Dir==0){
if(Screen->ComboD[ComboAt(Link->X+8,Link->Y-8)]<DigSpecialStart){
Screen->ComboD[ComboAt(Link->X+8,Link->Y-8)]=DugComboNormal;
}
else{
Game->PlaySound(SecretSound);
Screen->ComboD[ComboAt(Link->X+8,Link->Y-8)]=DugComboSpecial;
chance=101;
}
}
if(Link->Dir==1){
if(Screen->ComboD[ComboAt(Link->X+8,Link->Y+24)]<DigSpecialStart){
Screen->ComboD[ComboAt(Link->X+8,Link->Y+24)]=DugComboNormal;
}
else{
Game->PlaySound(SecretSound);
Screen->ComboD[ComboAt(Link->X+8,Link->Y+24)]=DugComboSpecial;
chance=101;
}
}
if(Link->Dir==2){
if(Screen->ComboD[ComboAt(Link->X-8,Link->Y+8)]<DigSpecialStart){
Screen->ComboD[ComboAt(Link->X-8,Link->Y+8)]=DugComboNormal;
}
else{
Game->PlaySound(SecretSound);
Screen->ComboD[ComboAt(Link->X-8,Link->Y+8)]=DugComboSpecial;
chance=101;
}
}
if(Link->Dir==3){
if(Screen->ComboD[ComboAt(Link->X+24,Link->Y+8)]<DigSpecialStart){
Screen->ComboD[ComboAt(Link->X+24,Link->Y+8)]=DugComboNormal;
}
else{
Game->PlaySound(SecretSound);
Screen->ComboD[ComboAt(Link->X+24,Link->Y+8)]=DugComboSpecial;
chance=101;
}
}
// The item drops are currently set to be the same as the default tall grass combo drops.
// The variable "chance" is a randomly generated number between 1 and 100.
// It determines whether you will get an item, and if so, which one.
// Here, you have a 20% chance to spawn 1 rupee, and a 15% chance to spawn a heart.
// If you want, edit this or add more lines to spawn more drops.
// You can use this line as a template: if(chance>=21&&chance<=35)itemdrop=2;
// The "chance" variable determines the chance you have of obtaining the item, as we've
// seen before, and the "itemdrop" variable is the number of the item in ZQuest.
if(chance<=20)itemdrop=0;
if(chance>=21&&chance<=35)itemdrop=2;
// NB: If you dug a special combo, the "chance" variable is automatically set to 101 so
// the script won't spawn drops on top of special combos like stairs.
if(Link->Dir==0){
itemlocx=Link->X;
itemlocy=Link->Y-16;
}
if(Link->Dir==1){
itemlocx=Link->X;
itemlocy=Link->Y+16;
}
if(Link->Dir==2){
itemlocx=Link->X-16;
itemlocy=Link->Y;
}
if(Link->Dir==3){
itemlocx=Link->X+16;
itemlocy=Link->Y;
}
// This is the part of the code that spawns the item.
// If you have edited the default item drops, change "35" and set it according to your drops.
if(chance<=35){
item i=Screen->CreateItem(itemdrop);
i->X=itemlocx;
i->Y=itemlocy;
i->Z=10;
i->Pickup=IP_TIMEOUT;
}
}
}
}
item script ItemMessage{
void run(int m){
Screen->Message(m);
}
}
item script ItemWarp{
void run (int DMap, int Screen){
Link->Warp(DMap, Screen);
}
}