Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #option BINARY_32BIT off
- //Would break a number of things if set on
- #option SHORT_CIRCUIT on
- //Should work for everything in std_zh, and just speed it up
- import "std.zh"
- //Main Files
- #include "std_zh/std_constants.zh"
- #include "std_zh/std_functions.zh"
- #include "std_zh/std_vars.zh" //Basic array, and some generic handlers. Useful in preventing quest fixing/expansion issues.
- //ZScript string handling functions, akin to those found in C
- //#include "string.zh"
- #include "std_zh/string_constants.zh" //Now #includeed from here. This prevents conflicts for those people
- #include "std_zh/string_functions.zh" //who would #include string.zh from a secondary source, as that file is now
- //empty, and the string.ch components load from here.
- //New Functions, for 2.53.0 and above
- #include "std_zh/std_extension.zh"
- //Keyboard handling for 2.54 and above
- #include "std_zh/std_keyboard.zh"
- //Locale
- #include "std_zh/locale/std_EnglishIntl.zh" //International English Localisation
- //Settings
- #include "std_zh/std.cfg"
- // ffcscript.zh
- // Version 1.1.1
- // Combo to be used for generic script vehicle FFCs. This should be
- // an invisible combo with no type or flag. It cannot be combo 0.
- const int FFCS_INVISIBLE_COMBO = 1;
- // Range of FFCs to use. Numbers must be between 1 and 32.
- const int FFCS_MIN_FFC = 1;
- const int FFCS_MAX_FFC = 32;
- int RunFFCScript(int scriptNum, float args)
- {
- // Invalid script
- if(scriptNum<0 || scriptNum>511)
- return 0;
- ffc theFFC;
- // Find an FFC not already in use
- for(int i=FFCS_MIN_FFC; i<=FFCS_MAX_FFC; i++)
- {
- theFFC=Screen->LoadFFC(i);
- if(theFFC->Script!=0 ||
- (theFFC->Data!=0 && theFFC->Data!=FFCS_INVISIBLE_COMBO) ||
- theFFC->Flags[FFCF_CHANGER])
- continue;
- // Found an unused one; set it up
- theFFC->Data=FFCS_INVISIBLE_COMBO;
- theFFC->Script=scriptNum;
- if(args!=NULL)
- {
- for(int j=Min(SizeOfArray(args), 8)-1; j>=0; j--)
- theFFC->InitD[j]=args[j];
- }
- return i;
- }
- // No FFCs available
- return 0;
- }
- ffc RunFFCScriptOrQuit(int scriptNum, float args)
- {
- // Invalid script
- if(scriptNum<0 || scriptNum>511)
- Quit();
- int ffcID=RunFFCScript(scriptNum, args);
- if(ffcID==0)
- Quit();
- return Screen->LoadFFC(ffcID);
- }
- int FindFFCRunning(int scriptNum)
- {
- // Invalid script
- if(scriptNum<0 || scriptNum>511)
- return 0;
- ffc f;
- for(int i=1; i<=32; i++)
- {
- f=Screen->LoadFFC(i);
- if(f->Script==scriptNum)
- return i;
- }
- // No FFCs running it
- return 0;
- }
- int FindNthFFCRunning(int scriptNum, int n)
- {
- // Invalid script
- if(scriptNum<0 || scriptNum>511)
- return 0;
- ffc f;
- for(int i=1; i<=32; i++)
- {
- f=Screen->LoadFFC(i);
- if(f->Script==scriptNum)
- {
- n--;
- if(n==0)
- return i;
- }
- }
- // Not that many FFCs running it
- return 0;
- }
- int CountFFCsRunning(int scriptNum)
- {
- // Invalid script
- if(scriptNum<0 || scriptNum>511)
- return 0;
- ffc f;
- int numFFCs=0;
- for(int i=1; i<=32; i++)
- {
- f=Screen->LoadFFC(i);
- if(f->Script==scriptNum)
- numFFCs++;
- }
- return numFFCs;
- }
- //=============================================================================
- // stdExtra.zh version 3.5
- // Latest update:
- // * Added SCREEN_COMBOS
- // * Removed equipItemA/B()
- // * Removed SelectPressInput() and SetInput
- // * Added RadianVectorX/Y by Mero
- // * Removed cw() and ccw() and added rotateDir() by Mero
- //=============================================================================
- //Pre-requisites
- //#include "std.zh"
- //#include "ffcscript.zh"
- //#include "string.zh"
- //==== * Quest-Specific Settings * ============================================
- //Text colors
- const int COLOR_WHITE = 0x01;
- const int COLOR_BLACK = 0x0F;
- //Combos
- const int CMB_BLANK = 0; //Leave this be - combo 0 should always be invisible and no properties
- const int CMB_FREEZEALL = 892; //Combo with "Freeze all (Except FFCs)" type
- const int CMB_FREEZEFFC = 893; //Combo with "Freeze all (FFCs only)" type
- //FFC Slots
- const int FFC_FREEZEALL = 31;
- const int FFC_FREEZEFFC = 32;
- //Other Settings
- const int MAX_ITEMS = 255; //Set to the highest item ID you use to make GetCurrentItem() more efficient
- //=============================================================================
- //Screen Dimensions
- const int SCREEN_WIDTH = 256;
- const int SCREEN_HEIGHT = 176;
- const int SCREEN_VISIBLEHEIGHT = 168; //The height of the screen you can see (bottom 8 pixels cut off)
- const int SCREEN_SSTOP = -64; //The top of the subscreen
- const int SCREEN_COMBOS = 176; // Number of combos on screen
- //Sprite Flips and rotations
- const int FLIP_NO = 0; //Not flipped
- const int FLIP_H = 1; //Horizontal
- const int FLIP_V = 2; //Vertical
- const int FLIP_B = 3; //Vertical & Horizontal
- const int ROTATE_CW = 4; //Clockwise
- const int ROTATE_CCW = 7; //Counter-clockwise
- const int ROTATE_CW_FLIP = 5;
- const int ROTATE_CCW_FLIP = 6;
- //NPC Misc Flags
- const int NPCMF_DAMAGE = 0x0001; //"Damaged by Power 0 weapons"
- const int NPCMF_INVISIBLE = 0x0002; //"Is invisible"
- const int NPCMF_NOTRETURN = 0x0004; //"Never returns after death"
- const int NPCMF_NOTENEMY = 0x0008; //"Doesn't count as beatable enemy"
- //const int NPCMF_SPAWNFLICKER = 0x0010; //Spawn animation = flicker (???)
- const int NPCMF_LENSONLY = 0x0020; //"Can only be seen with Lens of Truth"
- //const int NPCMF_FLASHING = 0x0040;
- //const int NPCMF_FLICKERING = 0x0080;
- //const int NPCMF_TRANSLUCENT = 0x0100;
- const int NPCMF_SHIELDFRONT = 0x0200;
- const int NPCMF_SHIELDLEFT = 0x0400;
- const int NPCMF_SHIELDRIGHT = 0x0800;
- const int NPCMF_SHIELDBACK = 0x1000;
- const int NPCMF_HAMMERBREAK = 0x2000; //"Hammer can break shield"
- //===============================================================================
- //Reusable scripts
- //===============================================================================
- //Run an FFC script
- //D0-D6: Arguments for the FFC Script
- //D7: The script number to run
- item script ffcItem{
- void run(int d0, int d1, int d2, int d3, int d4, int d5, int d6, int ffc_id){
- int d[7] = {d0,d1,d2,d3,d4,d5,d6};
- if(FindFFCRunning(ffc_id)<=0){
- RunFFCScriptOrQuit(ffc_id, d);
- }
- }
- }
- //===============================================================================
- //Position and movement
- //===============================================================================
- //Prevents moving in any direction
- void NoMovement(){
- Link->InputUp = false; Link->PressUp = false;
- Link->InputDown = false; Link->PressDown = false;
- Link->InputLeft = false; Link->PressLeft = false;
- Link->InputRight = false; Link->PressRight = false;
- }
- //Converts velocity into a direction.
- int VelocityToDir(float x, float y){
- if(x == 0 && y == 0) return -1;
- return RadianAngleDir8(RadianAngle(0, x, 0, y));
- }
- int VelocityToDir4(float x, float y){
- if(x == 0 && y == 0) return -1;
- return RadianAngleDir4(RadianAngle(0, x, 0, y));
- }
- //Converts the x component of a velocity into a direction.
- int XSpeedToDir(float x){
- return VelocityToDir(x, 0);
- }
- //Converts the y component of a velocity into a direction.
- int YSpeedToDir(float y){
- return VelocityToDir(0, y);
- }
- //Takes a direction of movement and gets the xspeed.
- float DirToXSpeed(int dir){
- if(dir<4)
- return Cond((dir*2)-5 < -1, 0, (dir*2)-5);
- else
- return Cond(dir<6, -1.5, 1.5);
- }
- //Takes a direction of movement and gets the yspeed.
- float DirToYSpeed(int dir){
- if(dir > 7) dir = toggleBlock(dir);
- if(dir < 2) return 0;
- float ret = 1;
- if(dir >= 4) ret += .5;
- return Cond(IsEven(dir), -ret, ret);
- }
- //Returns the angle in radians of a direction; used for weapon angles
- float dirToRad(int dir){
- if ( dir == DIR_UP )
- return 1.5 * PI;
- if ( dir == DIR_DOWN )
- return .5 * PI;
- if ( dir == DIR_LEFT )
- return PI;
- if ( dir == DIR_RIGHT )
- return 0;
- }
- int dirToDeg(int dir){
- if ( dir == DIR_UP )
- return 90;
- if ( dir == DIR_DOWN )
- return 270;
- if ( dir == DIR_LEFT )
- return 180;
- if ( dir == DIR_RIGHT )
- return 0;
- }
- // Returns value from 0 to 360 rather than -180 to 180
- float AnglePos(int x1, int y1, int x2, int y2){
- float angle = ArcTan(x2-x1, y2-y1)*57.2958;
- if(angle < 0)
- angle += 360;
- return angle;
- }
- // Returns the X component of a radian angle.
- float RadianVectorX(float len, float angle)
- {
- return len * RadianCos(angle);
- }
- // Returns the Y component of a radian angle.
- float RadianVectorY(float len, float angle)
- {
- return len * RadianSin(angle);
- }
- //Returns the distance between the given Coordinate and Link's Center.
- float DistanceLink(float x, float y)
- {
- return Distance(CenterLinkX(), CenterLinkY(), x, y);
- }
- //Returns the distance between Link's center and an object's center.
- float DistanceLink(ffc f)
- {
- return Distance(CenterLinkX(), CenterLinkY(), CenterX(f), CenterY(f));
- }
- float DistanceLink(npc n)
- {
- return Distance(CenterLinkX(), CenterLinkY(), CenterX(n), CenterY(n));
- }
- float DistanceLink(lweapon l)
- {
- return Distance(CenterLinkX(), CenterLinkY(), CenterX(l), CenterY(l));
- }
- float DistanceLink(eweapon e)
- {
- return Distance(CenterLinkX(), CenterLinkY(), CenterX(e), CenterY(e));
- }
- //Converts 8-way direction to 4-way
- int dir8ToDir4(int dir)
- {
- if(dir != Clamp(dir, 0, 15)) return -1;
- dir &= 7;
- if((dir & 4) == 0)
- return dir;
- else
- return Cond(IsEven(dir), DIR_UP, DIR_DOWN);
- }
- //Returns the reverse of the given direction.
- int reverseDir(int dir)
- {
- if(dir != Clamp(dir, 0, 15)) return -1; //Invalid direction
- return Cond(dir<8, OppositeDir(dir), ((dir+4)%8)+8);
- }
- // Rotates a given direction
- int rotateDir(int dir, bool ccw, bool eightway)
- {
- if(dir==DIR_UP) dir = 0;
- else if(dir==DIR_RIGHTUP) dir = 1;
- else if(dir==DIR_RIGHT) dir = 2;
- else if(dir==DIR_RIGHTDOWN) dir = 3;
- else if(dir==DIR_DOWN) dir = 4;
- else if(dir==DIR_LEFTDOWN) dir = 5;
- else if(dir==DIR_LEFT) dir = 6;
- else if(dir==DIR_LEFTUP) dir = 7;
- else return -1; //Invalid Direction;
- if(eightway)
- dir=(dir+Cond(ccw, 7,1))%8;
- else
- dir=(dir+Cond(ccw,6,2))%8; //Will never be odd. And needs to wrap by 8 regardless.
- if(dir==0) return DIR_UP;
- else if(dir==1) return DIR_RIGHTUP;
- else if(dir==2) return DIR_RIGHT;
- else if(dir==3) return DIR_RIGHTDOWN;
- else if(dir==4) return DIR_DOWN;
- else if(dir==5) return DIR_LEFTDOWN;
- else if(dir==6) return DIR_LEFT;
- else if(dir==7) return DIR_LEFTUP;
- }
- //Move the specified object a set distance in a set direction
- //Walkable: Don't move onto a solid space
- //PreventOffScreen: Don't move off screen
- bool moveLink ( int dir, int dist, bool walkable, bool preventOffScreen )
- {
- //Can't move
- if ( walkable && !CanWalk(Link->X, Link->Y, dir, dist, false) )
- return false;
- //Otherwise, check direction
- if ( dir == DIR_UP && (!preventOffScreen || Link->Y - dist > 0) )
- Link->Y -= dist;
- else if ( dir == DIR_DOWN && (!preventOffScreen || Link->Y + dist < SCREEN_HEIGHT) )
- Link->Y += dist;
- else if ( dir == DIR_LEFT && (!preventOffScreen || Link->X - dist > 0))
- Link->X -= dist;
- else if ( dir == DIR_RIGHT && (!preventOffScreen || Link->X + dist < SCREEN_WIDTH) )
- Link->X += dist;
- else
- return false;
- return true;
- }
- bool move ( ffc this, int dir, int dist, bool walkable, bool preventOffScreen )
- {
- //Can't move
- if ( walkable && !CanWalk(this->X, this->Y, dir, dist, false) )
- return false;
- //Otherwise, check direction
- if ( dir == DIR_UP && (!preventOffScreen || this->Y - dist > 0) )
- this->Y -= dist;
- else if ( dir == DIR_DOWN && (!preventOffScreen || this->Y + dist < SCREEN_HEIGHT) )
- this->Y += dist;
- else if ( dir == DIR_LEFT && (!preventOffScreen || this->X - dist > 0))
- this->X -= dist;
- else if ( dir == DIR_RIGHT && (!preventOffScreen || this->X + dist < SCREEN_WIDTH) )
- this->X += dist;
- else
- return false;
- return true;
- }
- bool move ( npc enem, int dir, int dist, bool walkable, bool preventOffScreen )
- {
- //Can't move
- if ( walkable && !CanWalk(enem->X, enem->Y, dir, dist, false) )
- return false;
- //Otherwise, check direction
- if ( dir == DIR_UP && (!preventOffScreen || enem->Y - dist > 0) )
- enem->Y -= dist;
- else if ( dir == DIR_DOWN && (!preventOffScreen || enem->Y + dist < SCREEN_HEIGHT) )
- enem->Y += dist;
- else if ( dir == DIR_LEFT && (!preventOffScreen || enem->X - dist > 0))
- enem->X -= dist;
- else if ( dir == DIR_RIGHT && (!preventOffScreen || enem->X + dist < SCREEN_WIDTH) )
- enem->X += dist;
- else
- return false;
- return true;
- }
- bool move ( lweapon weap, int dir, int dist, bool walkable, bool preventOffScreen )
- {
- //Can't move
- if ( walkable && !CanWalk(weap->X, weap->Y, dir, dist, false) )
- return false;
- //Otherwise, check direction
- if ( dir == DIR_UP && (!preventOffScreen || weap->Y - dist > 0) )
- weap->Y -= dist;
- else if ( dir == DIR_DOWN && (!preventOffScreen || weap->Y + dist < SCREEN_HEIGHT) )
- weap->Y += dist;
- else if ( dir == DIR_LEFT && (!preventOffScreen || weap->X - dist > 0))
- weap->X -= dist;
- else if ( dir == DIR_RIGHT && (!preventOffScreen || weap->X + dist < SCREEN_WIDTH) )
- weap->X += dist;
- else
- return false;
- return true;
- }
- bool move ( eweapon weap, int dir, int dist, bool walkable, bool preventOffScreen )
- {
- //Can't move
- if ( walkable && !CanWalk(weap->X, weap->Y, dir, dist, false) )
- return false;
- //Otherwise, check direction
- if ( dir == DIR_UP && (!preventOffScreen || weap->Y - dist > 0) )
- weap->Y -= dist;
- else if ( dir == DIR_DOWN && (!preventOffScreen || weap->Y + dist < SCREEN_HEIGHT) )
- weap->Y += dist;
- else if ( dir == DIR_LEFT && (!preventOffScreen || weap->X - dist > 0))
- weap->X -= dist;
- else if ( dir == DIR_RIGHT && (!preventOffScreen || weap->X + dist < SCREEN_WIDTH) )
- weap->X += dist;
- else
- return false;
- return true;
- }
- bool move ( item theItem, int dir, int dist, bool walkable, bool preventOffScreen )
- {
- //Can't move
- if ( walkable && !CanWalk(theItem->X, theItem->Y, dir, dist, false) )
- return false;
- //Otherwise, check direction
- if ( dir == DIR_UP && (!preventOffScreen || theItem->Y - dist > 0) )
- theItem->Y -= dist;
- else if ( dir == DIR_DOWN && (!preventOffScreen || theItem->Y + dist < SCREEN_HEIGHT) )
- theItem->Y += dist;
- else if ( dir == DIR_LEFT && (!preventOffScreen || theItem->X - dist > 0))
- theItem->X -= dist;
- else if ( dir == DIR_RIGHT && (!preventOffScreen || theItem->X + dist < SCREEN_WIDTH) )
- theItem->X += dist;
- else
- return false;
- return true;
- }
- //===============================================================================
- //Items and Equipment
- //===============================================================================
- //Returns true if Link is pressing the button for an item
- bool pressingItem(int id)
- {
- return ( (GetEquipmentA()==id && Link->PressA)
- ||(GetEquipmentB()==id && Link->PressB) );
- }
- //Returns the id of the highest level item of the given class that Link has acquired.
- //Unlike GetHighestLevelItem(), only applies to items Link owns
- int GetCurrentItem(int itemclass)
- {
- itemdata id;
- int ret = -1;
- int curlevel = -1000;
- for(int i = 0; i < MAX_ITEMS; i++){
- if(!Link->Item[i])
- continue;
- id = Game->LoadItemData(i);
- if(id->Family != itemclass)
- continue;
- if(id->Level > curlevel){
- curlevel = id->Level;
- ret = i;
- }
- }
- return ret;
- }
- //Gives the specified item with hold up animation and optional fanfare
- //keep: Whether to actually give the item
- //twoHand: Use 1 or 2 hand animation
- //sfx: Whether to play item fanfare
- void holdUpItem(int id, bool keep, bool twoHand, bool sfx)
- {
- if ( sfx )
- Game->PlaySound(SFX_PICKUP);
- if ( twoHand )
- Link->Action = LA_HOLD2LAND;
- else
- Link->Action = LA_HOLD1LAND;
- Link->HeldItem = id;
- //Give the item and its counter effects
- if(keep){
- Link->Item[id] = true;
- itemdata data = Game->LoadItemData(id);
- //Increase capacity
- if(data->MaxIncrement > 0 && data->Max > Game->MCounter[data->Counter]){
- Game->MCounter[data->Counter] = Min(Game->MCounter[data->Counter]+data->MaxIncrement, data->Max);
- }
- //Increase count
- if(data->Amount > 0)
- Game->Counter[data->Counter] = Min(Game->Counter[data->Counter]+data->Amount, Game->MCounter[data->Counter]);
- }
- }
- //===============================================================================
- //Screen Freezing
- //===============================================================================
- //WARNING: DO NOT USE IN AN FFC SCRIPT OR THE FFC WILL FREEZE ITSELF!
- //Use in global scripts only.
- void freezeScreen()
- {
- ffc freezeAll = Screen->LoadFFC(FFC_FREEZEALL);
- freezeAll->Data = CMB_FREEZEALL;
- ffc freezeFFC = Screen->LoadFFC(FFC_FREEZEFFC);
- freezeFFC->Data = CMB_FREEZEFFC;
- }
- void unfreezeScreen()
- {
- ffc freezeAll = Screen->LoadFFC(FFC_FREEZEALL);
- freezeAll->Data = CMB_BLANK;
- ffc freezeFFC = Screen->LoadFFC(FFC_FREEZEFFC);
- freezeFFC->Data = CMB_BLANK;
- }
- //===============================================================================
- //Weapons
- //===============================================================================
- //Toggles weapon blockability by adjusting its direction
- int toggleBlock (int dir)
- {
- if(dir == DIR_UP)
- return 8;
- if(dir == DIR_DOWN)
- return 12;
- if(dir == DIR_LEFT)
- return 14;
- if(dir == DIR_RIGHT)
- return 10;
- if(dir == DIR_LEFTUP)
- return 15;
- if(dir == DIR_RIGHTUP)
- return 9;
- if(dir == DIR_LEFTDOWN)
- return 13;
- if(dir == DIR_RIGHTDOWN)
- return 11;
- if(dir==8)
- return DIR_UP;
- if(dir==9)
- return DIR_RIGHTUP;
- if(dir==10)
- return DIR_RIGHT;
- if(dir==11)
- return DIR_RIGHTDOWN;
- if(dir==12)
- return DIR_DOWN;
- if(dir==13)
- return DIR_LEFTDOWN;
- if(dir==14)
- return DIR_LEFT;
- if(dir==15)
- return DIR_LEFTUP;
- return dir;
- }
- //Get the correct flip for a 4-dir weapon based on its direction
- int getFlip(int dir)
- {
- if ( dir == DIR_UP )
- return FLIP_NO;
- if ( dir == DIR_DOWN )
- return FLIP_B;
- if ( dir == DIR_LEFT )
- return ROTATE_CCW;
- if ( dir == DIR_RIGHT )
- return ROTATE_CW;
- return -1;
- }
- //Sets the flip for a 4-dir weapon based on a single sprite
- void setFlip ( lweapon weapon )
- {
- int flip = getFlip(weapon->Dir);
- if(flip >= 0)
- weapon->Flip = flip;
- }
- void setFlip ( eweapon weapon ){
- int flip = getFlip(weapon->Dir);
- if(flip >= 0)
- weapon->Flip = flip;
- }
- //Sets flip for a 4-dir sword based on two sprites (up and right)
- void setFlipSword ( lweapon weapon ){
- if ( weapon->Dir >= DIR_LEFT )
- weapon->Tile++;
- if ( weapon->Dir == DIR_DOWN )
- weapon->Flip = FLIP_B;
- else if ( weapon->Dir == DIR_LEFT )
- weapon->Flip = FLIP_H;
- }
- void setFlipSword ( eweapon weapon ){
- if ( weapon->Dir >= DIR_LEFT )
- weapon->Tile++;
- if ( weapon->Dir == DIR_DOWN )
- weapon->Flip = FLIP_B;
- else if ( weapon->Dir == DIR_LEFT )
- weapon->Flip = FLIP_H;
- }
- //===============================================================================
- //Other
- //===============================================================================
- void permaSecrets(){
- Screen->TriggerSecrets();
- Screen->State[ST_SECRET] = true;
- }
- void tempSecrets(){
- Screen->TriggerSecrets();
- Screen->State[ST_SECRET] = false;
- }
- //Makes secrets permanent if "Secrets are temporary" is not checked
- void screenSecrets(){
- Screen->TriggerSecrets();
- if(!(Screen->Flags[SF_SECRETS]&2)){
- Screen->State[ST_SECRET] = true;
- }
- }
- bool WaitframeCheckScreenChange(){
- int old_dmap_screen = Game->GetCurDMapScreen();
- int old_dmap = Game->GetCurDMap();
- Waitframe();
- return (old_dmap!=Game->GetCurDMap() || old_dmap_screen!=Game->GetCurDMapScreen());
- }
- bool WaitframeCheckWarp(){
- return ( WaitframeCheckScreenChange() && !(Link->Action==LA_SCROLLING));
- }
- //Draw an inverted circle (fill whole screen except circle)
- void InvertedCircle(int bitmapID, int layer, int x, int y, int radius, int scale, int fillcolor){
- Screen->SetRenderTarget(bitmapID); //Set the render target to the bitmap.
- Screen->Rectangle(layer, 0, 0, 256, 176, fillcolor, 1, 0, 0, 0, true, 128); //Cover the screen
- Screen->Circle(layer, x, y, radius, 0, scale, 0, 0, 0, true, 128); //Draw a transparent circle.
- Screen->SetRenderTarget(RT_SCREEN); //Set the render target back to the screen.
- Screen->DrawBitmap(layer, bitmapID, 0, 0, 256, 176, 0, 56, 256, 176, 0, true); //Draw the bitmap
- }
- bool LinkOnComboType(int type){
- return(Screen->ComboT[ComboAt(CenterLinkX(), CenterLinkY())] == type);
- }
- bool LinkOnTallGrass(){
- return ( LinkOnComboType(CT_TALLGRASS)
- || LinkOnComboType(CT_TALLGRASSC)
- || LinkOnComboType(CT_TALLGRASSNEXT)
- );
- }
- void closingWipe(int wipetime){
- for(int i = wipetime; i > 0; i--){
- InvertedCircle(4, 6, CenterLinkX(), CenterLinkY(), Floor(300/wipetime)*i, 1, 15);
- WaitNoAction();
- }
- }
- void openingWipe(int wipetime){
- for(int i = 0; i < wipetime; i++){
- InvertedCircle(4, 6, CenterLinkX(), CenterLinkY(), Floor(300/wipetime)*i, 1, 15);
- WaitNoAction();
- }
- }
- //Get the color value given CSet and in-CSet color
- int color(int cset, int csetColor){
- return (cset*16) + csetColor;
- }
- //Simulates a 2D array
- //Returns the index of an array given row, column, and number of rows
- int arr2D ( int row, int col, int numCols ){
- return (row * numCols) + col;
- }
- //Extracted this method from ffcscript.zh for common usage
- //If force is true, takes over the last FFC even if it's used
- ffc loadUnusedFFC(bool force){
- ffc theFFC;
- for(int i = FFCS_MIN_FFC; i <= FFCS_MAX_FFC; i++){
- theFFC=Screen->LoadFFC(i); //Check each FFC
- if ( ffcIsBlank(theFFC) )
- return theFFC; //Return it
- if ( force && i == FFCS_MAX_FFC ) //Force last FFC
- return theFFC;
- }
- //No FFC found; return an invalid one
- ffc invalidFFC;
- return invalidFFC;
- }
- //Tells whether an FFC is blank and unused
- bool ffcIsBlank(ffc this){
- return ( this->Script == 0 && //If not running a script
- ( this->Data == 0 || this->Data == FFCS_INVISIBLE_COMBO)); //And blank combo
- }
- //Draws the given time in frames as minutes and seconds
- //Taken from "Hot Rooms" by Zecora
- void drawTime(int layer, int x, int y, int frames){
- drawTime(layer, x, y, FONT_S, COLOR_WHITE, COLOR_BLACK, TF_NORMAL, frames);
- }
- void drawTime(int layer, int x, int y, int font, int color, int bgcolor, int format, int frames){
- int seconds = Div(frames, 60); //Total seconds
- int minutes = Div(seconds, 60); //Total minutes
- seconds %= 60; //Remaining seconds (0 - 59)
- int string[5]; //Create an array of characters.
- itoa(string, 0, minutes); //Add the minutes to the array.
- string[strlen(string)] = ':'; //Add the : after the minutes.
- if(seconds < 10) //Single-digit seconds: add '0' before count
- string[strlen(string)] = '0';
- itoa(string, strlen(string), seconds);
- Screen->DrawString(layer, x, y, font, color, bgcolor, format, string, 128);
- }
- // Has a 1 in n chance of returning true
- bool nChance(int chance)
- {
- return Rand(chance) == 0;
- }
- // Given integer n, has an n% chance of returning true.
- bool percentChance(int chance)
- {
- return Rand(100) < chance;
- }
- //===============================================================================
- //Debug
- //===============================================================================
- //Shortcut for drawInteger for debug output
- //Each debug item should have a unique "num" (match between value and label)
- void debugValue ( int num, float value ){
- debugValue(num, value, 0);
- }
- void debugValue ( int num, float value, int places ){
- places = Clamp(places, 0, 4);
- Screen->DrawInteger(6, 100, 2+10*num, FONT_S, COLOR_WHITE, COLOR_BLACK, -1, -1, value, places, OP_OPAQUE);
- }
- void debugValue( int num, bool value){
- int trueString[] = "true";
- int falseString[] = "false";
- Screen->DrawString(6, 100, 2+10*num, FONT_S, COLOR_WHITE, COLOR_BLACK, TF_NORMAL, Cond(value, trueString, falseString), OP_OPAQUE);
- }
- void debugLabel ( int num, int string ){
- Screen->DrawString(6, 2, 2+10*num, FONT_S, COLOR_WHITE, COLOR_BLACK, TF_NORMAL, string, OP_OPAQUE);
- }
- //Both functions in one call, matching "num"
- void debug ( int num, int string, float value ){
- debugLabel(num, string);
- debugValue(num, value, 0);
- }
- void debug ( int num, int string, float value, int places ){
- debugLabel(num, string);
- debugValue(num, value, places);
- }
- void debug ( int num, int string, bool value ){
- debugLabel(num, string);
- debugValue(num, value);
- }
- bool SelectPressInput(int input){
- if(input == 0) return Link->PressA;
- else if(input == 1) return Link->PressB;
- else if(input == 2) return Link->PressL;
- else if(input == 3) return Link->PressR;
- }
- void SetInput(int input, bool state){
- if(input == 0) Link->InputA = state;
- else if(input == 1) Link->InputB = state;
- else if(input == 2) Link->InputL = state;
- else if(input == 3) Link->InputR = state;
- }
- ffc script stepMsg
- {
- void run(int m, int sens)
- {
- if ( !sens ) sens = 8;
- while(1)
- {
- if ( DistX(this, sens) )
- {
- if ( DistY(this, sens) )
- {
- break;
- }
- }
- Waitframe();
- }
- Screen->Message(m);
- }
- }
- ffc script EnemyMusic
- {
- void run(int bmidi, int nmidi)
- {
- while(true)
- {
- if (Screen->NumNPCs() != 0)
- {
- Game->PlayMIDI(bmidi);
- }
- else
- {
- Game->PlayMIDI(nmidi);
- }
- Waitframe();
- }
- }
- }
- const int EQ_QUAKE_TIME = 90;
- ffc script Earthquake
- {
- void run(int wait)
- {
- Waitframes(wait);
- Screen->Quake = EQ_QUAKE_TIME;
- Link->SwordJinx = EQ_QUAKE_TIME;
- Link->ItemJinx = EQ_QUAKE_TIME;
- }
- }
- item script itemBundle
- {
- void run(int item1, int item2, int item3, int item4, int item5, int item6, int item7, int item8)
- {
- if(item1 > 0)
- Link->Item[item1] = true;
- if(item2 > 0)
- Link->Item[item2] = true;
- if(item3 > 0)
- Link->Item[item3] = true;
- if(item4 > 0)
- Link->Item[item4] = true;
- if(item5 > 0)
- Link->Item[item5] = true;
- if(item6 > 0)
- Link->Item[item6] = true;
- if(item7 > 0)
- Link->Item[item7] = true;
- if(item8 > 0)
- Link->Item[item8] = true;
- // Display Item pickup message?
- if(item1 < 0)
- {
- Screen->Message(item1 * -1);
- }
- }//!End void run()
- }//!End item script itemBundle
- bool OnPlatform (ffc this){
- if(CenterLinkX() < this->X) return false;
- else if(CenterLinkX() >= this->X + this->EffectWidth) return false;
- else if(CenterLinkY() < this->Y) return false;
- else if(CenterLinkY() >= this->Y + this->EffectHeight) return false;
- else return true;
- }
- ffc script PermanentTieredSecrets
- {
- void run(int D, int Layer, int NumStates){
- //Triggers the number of screen secrets stored in Screen->D when you enter the screen
- if(Screen->D[D]>0){
- for(int i=0; i<Screen->D[D]; i++){
- Screen->TriggerSecrets();
- }
- }
- //Saves the combo position and combo under the FFC
- int ComboPos = ComboAt(this->X+8, this->Y+8);
- int Combo;
- if(Layer>0)
- Combo = GetLayerComboD(Layer, ComboPos);
- else if(Layer==0)
- Combo = Screen->ComboD[ComboPos];
- while(true){
- //Detects if the combo under the FFC changes and increases Screen->D
- if(Layer>0&&GetLayerComboD(Layer, ComboPos)!=Combo){
- Combo = GetLayerComboD(Layer, ComboPos);
- Screen->D[D]++;
- }
- else if(Layer==0&&Screen->ComboD[ComboPos]!=Combo){
- Combo = Screen->ComboD[ComboPos];
- Screen->D[D]++;
- }
- //Wraps Screen->D if NumStates is set, otherwise caps Screen->D at 100
- if(NumStates>0&&Screen->D[D]>=NumStates)
- Screen->D[D] -= NumStates;
- else if(NumStates==0&&Screen->D[D]>100){
- Screen->D[D] = 100;
- }
- Waitframe();
- }
- }
- }
- const int CUTSCENETRIGGER_SHOW_HITBOXES = 0; //For debugging problems with the script's hitboxes, set this to 1.
- const int C_CUTSCENETRIGGER_HITBOX = 0x01; //Color for the debug hitboxes
- const int D_CUTSCENETRIGGER = 0; //Screen->D used for cutscene triggers
- //D0: The DMap to warp to for the cutscene
- //D1: The screen to warp to IN DECIMAL. Screens in ZQuest are numbered in hex but FFCs only take arguments
- // in decimal, so you'll have to convert.
- //D2: Width of the trigger hitbox
- //D3: Height of the trigger hitbox
- //D4: Set this to a number 1-17 to make the cutscene only play once. By giving FFCs different D4 arguments,
- // you can have multiple triggers for different permanent cutscenes on a screen.
- //D5: If you want the trigger to check for a flag under Link, set this to the number of the flag.
- // If you want it to check for an item, set this to a negative Item ID.
- //D6: The X position to try to walk Link to. 0 for no target point.
- //D7: The Y position to try to walk Link to. 0 for no target point.
- ffc script CutsceneTrigger{
- void run(int newDMap, int newScreen, int w, int h, int oneUse, int checkItemorFlag, int targetX, int targetY){
- int dbit;
- if(oneUse>0){
- dbit = 1<<(oneUse-1);
- }
- //If Link starts standing on the cutscene hitbox, wait for him to step off
- while(Link->X+8 >= this->X && Link->X+8 <= this->X+w-1 && Link->Y+12 >= this->Y && Link->Y+12 <= this->Y+h-1 ){
- if(CUTSCENETRIGGER_SHOW_HITBOXES){
- Screen->Rectangle(6, this->X-1, this->Y-1, this->X+w-1+1, this->Y+h-1+1, C_CUTSCENETRIGGER_HITBOX, 1, 0, 0, 0, false, 64);
- Screen->Rectangle(6, this->X, this->Y, this->X+w-1, this->Y+h-1, C_CUTSCENETRIGGER_HITBOX, 1, 0, 0, 0, false, 128);
- Screen->Rectangle(6, this->X+1, this->Y+1, this->X+w-1-1, this->Y+h-1-1, C_CUTSCENETRIGGER_HITBOX, 1, 0, 0, 0, true, 64);
- }
- Waitframe();
- }
- //Check if the cutscene has already been triggered
- if(oneUse&&Screen->D[D_CUTSCENETRIGGER]&dbit){
- Quit();
- }
- while(true){
- if(CUTSCENETRIGGER_SHOW_HITBOXES){
- Screen->Rectangle(6, this->X-1, this->Y-1, this->X+w-1+1, this->Y+h-1+1, C_CUTSCENETRIGGER_HITBOX, 1, 0, 0, 0, false, 64);
- Screen->Rectangle(6, this->X, this->Y, this->X+w-1, this->Y+h-1, C_CUTSCENETRIGGER_HITBOX, 1, 0, 0, 0, false, 128);
- Screen->Rectangle(6, this->X+1, this->Y+1, this->X+w-1-1, this->Y+h-1-1, C_CUTSCENETRIGGER_HITBOX, 1, 0, 0, 0, false, 64);
- }
- //Find if Link has collided with the trigger hitbox
- if(Link->X+8 >= this->X && Link->X+8 <= this->X+w-1 && Link->Y+12 >= this->Y && Link->Y+12 <= this->Y+h-1 ){
- if(CUTSCENETRIGGER_SHOW_HITBOXES){
- Screen->Rectangle(6, this->X+2, this->Y+2, this->X+w-1-2, this->Y+h-1-2, C_CUTSCENETRIGGER_HITBOX, 1, 0, 0, 0, true, 64);
- }
- //If Link meets one the requirements to trigger the cutscene, break out of the loop
- if(checkItemorFlag==0){
- break;
- }
- //If the checkItemorFlag argument is negative, check for an item
- else if(checkItemorFlag<0){
- if(Link->Item[Abs(checkItemorFlag)])
- break;
- }
- //Else check for a screen flag
- else if(ComboFI(Link->X+8, Link->Y+12, checkItemorFlag)){
- break;
- }
- }
- Waitframe();
- }
- if(targetX>0||targetY>0){
- //Move Link either until he's in position or 4 seconds have passed
- for(int i=0; i<=240&&(Link->X!=targetX||Link->Y!=targetY); i++){
- //Prevent moving around while moving Link into position
- Link->InputStart = false; Link->PressStart = false;
- Link->InputMap = false; Link->PressMap = false;
- NoAction();
- //Apply inputs that should be active
- if(Abs(Link->X-targetX)<=2){
- Link->X = targetX;
- }
- else{
- if(Link->X<targetX)
- Link->InputRight = true;
- else if(Link->X>targetX)
- Link->InputLeft = true;
- }
- if(Abs(Link->Y-targetY)<=2){
- Link->Y = targetY;
- }
- else{
- if(Link->Y<targetY)
- Link->InputDown = true;
- else if(Link->Y>targetY)
- Link->InputUp = true;
- }
- Waitframe();
- }
- }
- if(oneUse){
- Screen->D[D_CUTSCENETRIGGER] |= dbit;
- }
- Link->PitWarp(newDMap, newScreen);
- }
- }
- int MooshPit[16];
- const int _MP_LASTX = 0;
- const int _MP_LASTY = 1;
- const int _MP_LASTDMAP = 2;
- const int _MP_LASTSCREEN = 3;
- const int _MP_ENTRYX = 4;
- const int _MP_ENTRYY = 5;
- const int _MP_ENTRYDMAP = 6;
- const int _MP_ENTRYSCREEN = 7;
- const int _MP_FALLX = 8;
- const int _MP_FALLY = 9;
- const int _MP_FALLTIMER = 10;
- const int _MP_FALLSTATE = 11;
- const int _MP_DAMAGETYPE = 12;
- const int _MP_SLIDETIMER = 13;
- const int MOOSHPIT_NO_GRID_SNAP = 1; //Set to 1 to prevent Link's falling sprite from snapping to the combo grid.
- const int MOOSHPIT_ENABLE_SLIDEYPITS = 1; //Set to 1 if Link should slide into pits he's partially on
- const int MOOSHPIT_NO_MOVE_WHILE_FALLING = 1; //Set to 1 if you don't want Link able to move while falling
- const int MOOSHPIT_NO_REENTER_STAIRS = 1; //Set to 1 to prevent Link reentering stairs when respawning from a pit. This uses an FFC slot to run the script
- const int MOOSHPIT_STUN_ENEMIES_WHILE_FALLING = 1; //Set to 1 to stun stunnable enemies while falling in a pit
- const int CT_HOLELAVA = 128;
- const int CF_LAVA = 122;
- const int SPR_FALLHOLE = 126; //Sprite for Link falling in a hole
- const int SPR_FALLLAVA = 99; //Sprite for Link falling in lava
- const int SFX_FALLHOLE = 38; //Sound for falling in a hole
- const int SFX_FALLLAVA = 85; //Sound for falling in lava
- const int DAMAGE_FALLHOLE = 8; //How much damage pits deal (1/2 heart default)
- const int DAMAGE_FALLLAVA = 16; //How much damage lava deals (1 heart default)
- const int FFC_MOOSHPIT_AUTOWARPA = 32;
- const int CMB_MOOSHPIT_AUTOWARPA = 2891;
- const int SF_MISC_MOOSHPITWARP = 2;
- const int MOOSHPIT_MIN_FALL_TIME = 60; //Minimum time for the pit's fall animation, to prevent repeated falling in pits
- const int MOOSHPIT_EXTRA_FALL_TIME = 0; //Extra frames at the end of the falling animation before Link respawns
- //Width and height of Link's hitbox for colliding with pits
- const int MOOSHPIT_LINKHITBOXWIDTH = 16;
- const int MOOSHPIT_LINKHITBOXHEIGHT = 16;
- //Width and height of Link's hitbox for colliding with pits/lava in sideview
- const int MOOSHPIT_SIDEVIEW_LINKHITBOXWIDTH = 2;
- const int MOOSHPIT_SIDEVIEW_LINKHITBOXHEIGHT = 2;
- const int MOOSHPIT_SLIDEYPIT_FREQ = 3; //Link will be pushed into slideypits every 1/n frames
- const int MOOSHPIT_SLIDEYPIT_MAXTIME = 20; //Link will be pushed into slideypits more intensely after n frames
- const int MOOSHPIT_SLIDEYPIT_ACCELFREQ = 8; //How often Link accelerates when falling in the pit
- int MooshPit_OnPit(int LinkX, int LinkY, bool countFFCs){
- if(Link->Action==LA_FROZEN||Link->Action==LA_RAFTING||Link->Action==LA_INWIND)
- return -1;
- if(countFFCs){
- if(MooshPit_OnFFC(LinkX, LinkY))
- return -1;
- }
- bool sideview;
- if(Screen->Flags[SF_ROOMTYPE]&100b)
- sideview = true;
- //wew lad
- int width = MOOSHPIT_LINKHITBOXWIDTH;
- int height = MOOSHPIT_LINKHITBOXHEIGHT;
- int total;
- int solidTotal;
- for(int x=0; x<=1; x++){
- for(int y=0; y<=1; y++){
- int X; int Y;
- if(sideview){ //Hitbox functions differently in sideview
- width = MOOSHPIT_SIDEVIEW_LINKHITBOXWIDTH;
- height = MOOSHPIT_SIDEVIEW_LINKHITBOXHEIGHT;
- X = Floor(LinkX+7-width/2+(width-1)*x)+1;
- Y = Floor(LinkY+7-height/2+(height-1)*y)+1;
- }
- else{
- X = Floor(LinkX+7-width/2+(width-1)*x)+1;
- Y = Floor(LinkY+11-height/2+(height-1)*y)+1;
- }
- //If one corner of Link's hitbox is on a pit, flag that corner as covered
- if(Screen->ComboT[ComboAt(X, Y)]==CT_HOLELAVA){
- total |= 1<<(1+(x+y*2));
- }
- //If Link is on a solid combo, count that corner as a pit
- if(Screen->isSolid(X, Y)){
- solidTotal |= 1<<(x+y*2);
- }
- }
- }
- if(total>0) //Assuming Link is on at least one actual pit, add up the solid and nonsolid pits
- return (total>>1)|(solidTotal<<4);
- return -1;
- }
- bool MooshPit_OnFFC(int LinkX, int LinkY){
- for(int i=1; i<=32; i++){ //Cycle through every FFC
- ffc f = Screen->LoadFFC(i);
- //Check if the FFC is solid
- if(f->Data>0&&!f->Flags[FFCF_CHANGER]&&!f->Flags[FFCF_ETHEREAL]){
- //Check if Link collides with the FFC
- if(RectCollision(LinkX+4, LinkY+9, LinkX+11, LinkY+14, f->X, f->Y, f->X+f->EffectWidth-1, f->Y+f->EffectHeight-1)){
- return true;
- }
- }
- }
- //If Link doesn't collide with any FFC, return false
- return false;
- }
- void MooshPit_StunEnemies(){
- for(int i=Screen->NumNPCs(); i>=1; i--){ //Cycle through every enemy
- npc n = Screen->LoadNPC(i);
- //Make it so the enemy's stun never falls below 1
- n->Stun = Max(n->Stun, 1);
- }
- }
- void MooshPit_Init(){
- MooshPit[_MP_LASTX] = Link->X;
- MooshPit[_MP_LASTY] = Link->Y;
- MooshPit[_MP_LASTDMAP] = Game->GetCurDMap();
- MooshPit[_MP_LASTSCREEN] = Game->GetCurDMapScreen();
- MooshPit[_MP_ENTRYX] = Link->X;
- MooshPit[_MP_ENTRYY] = Link->Y;
- MooshPit[_MP_ENTRYDMAP] = Game->GetCurDMap();
- MooshPit[_MP_ENTRYSCREEN] = Game->GetCurDMapScreen();
- MooshPit[_MP_FALLSTATE] = 0;
- MooshPit[_MP_FALLTIMER] = 0;
- Link->CollDetection = true;
- Link->Invisible = false;
- }
- void MooshPit_Update(){
- int i;
- bool isWarp;
- if(Screen->Flags[SF_MISC]&(1<<SF_MISC_MOOSHPITWARP))
- isWarp = true;
- bool sideview;
- if(Screen->Flags[SF_ROOMTYPE]&100b)
- sideview = true;
- if(Link->Action!=LA_SCROLLING){
- //Update the entry point whenever the screen changes
- if(MooshPit[_MP_ENTRYDMAP]!=Game->GetCurDMap()||MooshPit[_MP_ENTRYSCREEN]!=Game->GetCurDMapScreen()){
- MooshPit[_MP_ENTRYX] = Link->X;
- MooshPit[_MP_ENTRYY] = Link->Y;
- MooshPit[_MP_ENTRYDMAP] = Game->GetCurDMap();
- MooshPit[_MP_ENTRYSCREEN] = Game->GetCurDMapScreen();
- }
- if(MooshPit[_MP_FALLSTATE]==0){ //Not falling in pit
- int onPit = MooshPit_OnPit(Link->X, Link->Y, true);
- //Check if slidey pits are enabled and it's not sideview
- if(MOOSHPIT_ENABLE_SLIDEYPITS&&!IsSideview()){
- if(Link->Z<=0&&onPit>-1){ //If Link is partially on a pit
- int slideVx; int slideVy;
- int reps = 1;
- //Check if it's a frame Link should be moved
- if(MooshPit[_MP_SLIDETIMER]%MOOSHPIT_SLIDEYPIT_FREQ==0||MooshPit[_MP_SLIDETIMER]>=MOOSHPIT_SLIDEYPIT_MAXTIME){
- if((onPit&0111b)==0111b){ //Going up-left
- slideVx = -1;
- slideVy = -1;
- }
- else if((onPit&1011b)==1011b){ //Going up-right
- slideVx = 1;
- slideVy = -1;
- }
- else if((onPit&1101b)==1101b){ //Going down-left
- slideVx = -1;
- slideVy = 1;
- }
- else if((onPit&1110b)==1110b){ //Going down-right
- slideVx = 1;
- slideVy = 1;
- }
- else if((onPit&0011b)==0011b){ //Going up
- slideVy = -1;
- }
- else if((onPit&1100b)==1100b){ //Going down
- slideVy = 1;
- }
- else if((onPit&0101b)==0101b){ //Going left
- slideVx = -1;
- }
- else if((onPit&1010b)==1010b){ //Going right
- slideVx = 1;
- }
- else if((onPit&0001b)==0001b){ //Going up-left
- slideVx = -1;
- slideVy = -1;
- }
- else if((onPit&0010b)==0010b){ //Going up-right
- slideVx = 1;
- slideVy = -1;
- }
- else if((onPit&0100b)==0100b){ //Going down-left
- slideVx = -1;
- slideVy = 1;
- }
- else if((onPit&1000b)==1000b){ //Going down-right
- slideVx = 1;
- slideVy = 1;
- }
- //DEBUG DRAWS
- //VX
- // Screen->DrawInteger(6, 0, 0, FONT_Z1, 0x01, 0x0F, -1, -1, slideVx, 0, 128);
- //VY
- // Screen->DrawInteger(6, 0, 8, FONT_Z1, 0x01, 0x0F, -1, -1, slideVy, 0, 128);
- //ONPIT BITS
- // Screen->DrawInteger(6, 0, 16, FONT_Z1, 0x01, 0x0F, -1, -1, (onPit&1000b)>>3, 0, 128);
- // Screen->DrawInteger(6, 8, 16, FONT_Z1, 0x01, 0x0F, -1, -1, (onPit&0100b)>>2, 0, 128);
- // Screen->DrawInteger(6, 16, 16, FONT_Z1, 0x01, 0x0F, -1, -1, (onPit&0010b)>>1, 0, 128);
- // Screen->DrawInteger(6, 24, 16, FONT_Z1, 0x01, 0x0F, -1, -1, (onPit&0001b), 0, 128);
- //If Link is over the max slide time, increase the speed every 4 frames
- if(MooshPit[_MP_SLIDETIMER]>=MOOSHPIT_SLIDEYPIT_MAXTIME)
- reps += Floor((MooshPit[_MP_SLIDETIMER]-MOOSHPIT_SLIDEYPIT_MAXTIME)/MOOSHPIT_SLIDEYPIT_ACCELFREQ);
- }
- for(i=0; i<reps; i++){
- if(slideVx<0&&CanWalk(Link->X, Link->Y, DIR_LEFT, 1, false)){
- Link->X--;
- }
- else if(slideVx>0&&CanWalk(Link->X, Link->Y, DIR_RIGHT, 1, false)){
- Link->X++;
- }
- if(slideVy<0&&CanWalk(Link->X, Link->Y, DIR_UP, 1, false)){
- Link->Y--;
- }
- else if(slideVy>0&&CanWalk(Link->X, Link->Y, DIR_DOWN, 1, false)){
- Link->Y++;
- }
- }
- MooshPit[_MP_SLIDETIMER]++;
- }
- else{
- MooshPit[_MP_SLIDETIMER] = 0;
- }
- }
- if(onPit>-1){
- //Combine solid combo bits with pit bits
- onPit |= (onPit>>4);
- //Remove non pit bits
- onPit &= 1111b;
- }
- if(Link->Z<=0&&onPit==15){ //If Link steps on a pit
- int underLink;
- if(!sideview){
- underLink = ComboAt(Link->X+8, Link->Y+12);
- if(Screen->ComboT[underLink]!=CT_HOLELAVA){
- for(i=0; i<4; i++){
- underLink = ComboAt(Link->X+15*(i%2), Link->Y+8+7*Floor(i/2));
- if(Screen->ComboT[underLink]==CT_HOLELAVA)
- break;
- }
- }
- }
- else{
- underLink = ComboAt(Link->X+8, Link->Y+8);
- if(Screen->ComboT[underLink]!=CT_HOLELAVA){
- for(i=0; i<4; i++){
- underLink = ComboAt(Link->X+15*(i%2), Link->Y+15*Floor(i/2));
- if(Screen->ComboT[underLink]==CT_HOLELAVA)
- break;
- }
- }
- }
- lweapon fall;
- //Check if the combo is lava
- if(ComboFI(underLink, CF_LAVA)){
- //Play sound and display animation
- Game->PlaySound(SFX_FALLLAVA);
- fall = CreateLWeaponAt(LW_SCRIPT10, Link->X, Link->Y);
- if(!MOOSHPIT_NO_GRID_SNAP){
- fall->X = ComboX(underLink);
- fall->Y = ComboY(underLink);
- }
- fall->UseSprite(SPR_FALLLAVA);
- fall->CollDetection = false;
- fall->DeadState = fall->ASpeed*fall->NumFrames;
- //Mark as lava damage
- MooshPit[_MP_DAMAGETYPE] = 1;
- }
- //Otherwise it's a pit
- else{
- //Play sound and display animation
- Game->PlaySound(SFX_FALLHOLE);
- fall = CreateLWeaponAt(LW_SCRIPT10, Link->X, Link->Y);
- if(!MOOSHPIT_NO_GRID_SNAP){
- fall->X = ComboX(underLink);
- fall->Y = ComboY(underLink);
- if(isWarp){
- Link->X = ComboX(underLink);
- Link->Y = ComboY(underLink);
- }
- }
- fall->UseSprite(SPR_FALLHOLE);
- fall->CollDetection = false;
- fall->DeadState = fall->ASpeed*fall->NumFrames;
- //Mark as hole damage
- MooshPit[_MP_DAMAGETYPE] = 0;
- }
- MooshPit[_MP_FALLX] = Link->X;
- MooshPit[_MP_FALLY] = Link->Y;
- //Cooldown should last as long as the fall animation
- MooshPit[_MP_FALLSTATE] = 1;
- MooshPit[_MP_FALLTIMER] = Max(MOOSHPIT_MIN_FALL_TIME, fall->DeadState+MOOSHPIT_EXTRA_FALL_TIME);
- //Render Link invisible and intangible
- Link->Invisible = true;
- Link->CollDetection = false;
- NoAction();
- }
- else if(MooshPit_OnPit(Link->X, Link->Y, false)==-1&&Link->Action!=LA_FROZEN){ //All other times, while Link is on solid ground, record Link's last position
- if(sideview){
- //Link has no Z value in sideview, so we check if he's on a platform instead
- if(OnSidePlatform(Link->X, Link->Y)){
- MooshPit[_MP_LASTDMAP] = Game->GetCurDMap();
- MooshPit[_MP_LASTSCREEN] = Game->GetCurDMapScreen();
- MooshPit[_MP_LASTX] = Link->X;
- MooshPit[_MP_LASTY] = Link->Y;
- }
- }
- else{
- if(Link->Z<=0){
- MooshPit[_MP_LASTDMAP] = Game->GetCurDMap();
- MooshPit[_MP_LASTSCREEN] = Game->GetCurDMapScreen();
- MooshPit[_MP_LASTX] = Link->X;
- MooshPit[_MP_LASTY] = Link->Y;
- }
- }
- }
- }
- else if(MooshPit[_MP_FALLSTATE]==1){ //Falling animation
- if(MooshPit[_MP_FALLTIMER]>0)
- MooshPit[_MP_FALLTIMER]--;
- if(MOOSHPIT_STUN_ENEMIES_WHILE_FALLING)
- MooshPit_StunEnemies();
- Link->Jump = 0;
- Link->Z = 0;
- //Keep Link invisible just in case
- Link->Invisible = true;
- Link->CollDetection = false;
- NoAction();
- if(MooshPit[_MP_FALLTIMER]==0){
- MooshPit[_MP_SLIDETIMER] = 0;
- if(!isWarp||MooshPit[_MP_DAMAGETYPE]==1){ //If the pit isn't a warp, deal damage and move Link back to the return point
- //If the entry would dump Link back in the pit, dump him out at the failsafe position
- if(MooshPit_OnPit(MooshPit[_MP_ENTRYX], MooshPit[_MP_ENTRYY], false)==15){
- if(MOOSHPIT_NO_REENTER_STAIRS){
- //Call a script to place an FFC under Link to prevent reentering stairs
- int scriptName[] = "MooshPit_StairsFix";
- int ffcNum = RunFFCScript(Game->GetFFCScript(scriptName), 0);
- if(ffcNum>0){
- ffc f = Screen->LoadFFC(ffcNum);
- f->Flags[FFCF_ETHEREAL] = false;
- f->X = MooshPit[_MP_LASTX];
- f->Y = MooshPit[_MP_LASTY];
- }
- }
- Link->X = MooshPit[_MP_LASTX];
- Link->Y = MooshPit[_MP_LASTY];
- //If the failsafe position was on a different screen, warp there
- if(Game->GetCurDMap()!=MooshPit[_MP_LASTDMAP]||Game->GetCurDMapScreen()!=MooshPit[_MP_LASTSCREEN]){
- Link->PitWarp(MooshPit[_MP_LASTDMAP], MooshPit[_MP_LASTSCREEN]);
- }
- Link->Invisible = false;
- Link->CollDetection = true;
- }
- else{
- if(MOOSHPIT_NO_REENTER_STAIRS){
- //Call a script to place an FFC under Link to prevent reentering stairs
- int scriptName[] = "MooshPit_StairsFix";
- int ffcNum = RunFFCScript(Game->GetFFCScript(scriptName), 0);
- if(ffcNum>0){
- ffc f = Screen->LoadFFC(ffcNum);
- f->Flags[FFCF_ETHEREAL] = false;
- f->X = MooshPit[_MP_ENTRYX];
- f->Y = MooshPit[_MP_ENTRYY];
- }
- }
- //Move Link to the entry and make him visible
- Link->X = MooshPit[_MP_ENTRYX];
- Link->Y = MooshPit[_MP_ENTRYY];
- Link->Invisible = false;
- Link->CollDetection = true;
- }
- //Subtract HP based on damage type
- if(MooshPit[_MP_DAMAGETYPE]==1)
- Link->HP -= DAMAGE_FALLLAVA;
- else
- Link->HP -= DAMAGE_FALLHOLE;
- //Play hurt sound and animation
- Link->Action = LA_GOTHURTLAND;
- Link->HitDir = -1;
- Game->PlaySound(SFX_OUCH);
- MooshPit[_MP_FALLSTATE] = 0;
- }
- else{
- MooshPit[_MP_FALLSTATE] = 2;
- MooshPit[_MP_FALLTIMER] = 1;
- ffc warp = Screen->LoadFFC(FFC_MOOSHPIT_AUTOWARPA);
- warp->Data = CMB_MOOSHPIT_AUTOWARPA;
- warp->Flags[FFCF_CARRYOVER] = false;
- }
- }
- }
- else if(MooshPit[_MP_FALLSTATE]==2){ //Just warped
- if(sideview){
- Link->X = MooshPit[_MP_FALLX];
- Link->Y = 0;
- }
- else{
- Link->X = MooshPit[_MP_FALLX];
- Link->Y = MooshPit[_MP_FALLY];
- Link->Z = 176;
- }
- Link->Invisible = false;
- Link->CollDetection = true;
- if(MOOSHPIT_NO_MOVE_WHILE_FALLING){
- MooshPit[_MP_FALLSTATE] = 3;
- NoAction();
- }
- else
- MooshPit[_MP_FALLSTATE] = 0;
- MooshPit[_MP_FALLTIMER] = 0;
- }
- else if(MooshPit[_MP_FALLSTATE]==3){ //Falling into a new room (no action)
- if(MOOSHPIT_STUN_ENEMIES_WHILE_FALLING)
- MooshPit_StunEnemies();
- NoAction();
- if(IsSideview()){
- if(OnSidePlatform(Link->X, Link->Y))
- MooshPit[_MP_FALLSTATE] = 0;
- }
- else{
- if(Link->Z<=0)
- MooshPit[_MP_FALLSTATE] = 0;
- }
- }
- }
- }
- void MooshPit_ResetEntry(){
- MooshPit[_MP_ENTRYX] = Link->X;
- MooshPit[_MP_ENTRYY] = Link->Y;
- MooshPit[_MP_ENTRYDMAP] = Game->GetCurDMap();
- MooshPit[_MP_ENTRYSCREEN] = Game->GetCurDMapScreen();
- }
- const int WATER_CURRENT_FREQ = 5; //# of frames between moving Link (CANNOT BE LOWER THAN 0)
- const int WATER_CURRENT_FLAG = 98; //First of 4 flags to use in the order Up, Down, Left, Right
- void doCurrents (){
- if ( Link->Action==LA_SWIMMING || Link->Action==LA_DIVING ){//If Link is swimming...
- //Move Link based on the current's direction...
- //but make sure it isn't solid
- //Up
- if( ComboFI(Link->X,Link->Y+8, WATER_CURRENT_FLAG) //If swimming in the appropriate flag
- //And the following combos ahead of Link are not solid
- && !Screen->isSolid(Link->X,Link->Y+6) //NW
- && !Screen->isSolid(Link->X+7,Link->Y+6) //N
- && !Screen->isSolid(Link->X+15,Link->Y+6) //NE
- //Check if the combo below Link is water to prevent getting pushed out
- && waterCheck( ComboAt(Link->X,Link->Y+6))
- && waterCheck( ComboAt(Link->X+7,Link->Y+6))
- && waterCheck( ComboAt(Link->X+15,Link->Y+6))
- )
- Link->Y -= 2;
- //Down
- if( ComboFI(Link->X,Link->Y+8, WATER_CURRENT_FLAG+1 )
- && !Screen->isSolid(Link->X,Link->Y+17) //SW
- && !Screen->isSolid(Link->X+7,Link->Y+17) //S
- && !Screen->isSolid(Link->X+15,Link->Y+17) //SE
- && waterCheck( ComboAt(Link->X,Link->Y+17))
- && waterCheck( ComboAt(Link->X+7,Link->Y+17))
- && waterCheck( ComboAt(Link->X+15,Link->Y+17))
- )
- Link->Y += 2;
- //Left
- if( ComboFI(Link->X,Link->Y+8, WATER_CURRENT_FLAG+2 )
- && !Screen->isSolid(Link->X-2,Link->Y+8) //NW
- && !Screen->isSolid(Link->X-2,Link->Y+15) //SW
- )
- Link->X -= 2;
- //Right
- if( ComboFI(Link->X,Link->Y+8, WATER_CURRENT_FLAG+3 )
- && !Screen->isSolid(Link->X+17,Link->Y+8) //NE
- && !Screen->isSolid(Link->X+17,Link->Y+15) //SE
- && waterCheck( ComboAt(Link->X+17,Link->Y+8) )
- && waterCheck( ComboAt(Link->X+17,Link->Y+15) )
- )
- Link->X += 2;
- }
- }
- //Prevents Link from swimming on land
- void swimLandCheck(){
- if( !waterCheck( ComboAt(Link->X,Link->Y+8) ) //If Link is not in the water...
- && ( Link->Action==LA_SWIMMING || Link->Action==LA_DIVING ) ) //and swimming...
- Link->Action = LA_NONE; //Make him stop swimming
- }
- //Checks if the designated combo is any water type
- bool waterCheck(int cmb){
- if( Screen->ComboT[cmb] == CT_WATER
- || Screen->ComboT[cmb] == CT_SWIMWARP
- || Screen->ComboT[cmb] == CT_SWIMWARPB
- || Screen->ComboT[cmb] == CT_SWIMWARPC
- || Screen->ComboT[cmb] == CT_SWIMWARPD
- || Screen->ComboT[cmb] == CT_DIVEWARP
- || Screen->ComboT[cmb] == CT_DIVEWARPB
- || Screen->ComboT[cmb] == CT_DIVEWARPC
- || Screen->ComboT[cmb] == CT_DIVEWARPD
- )
- return true; //The combo is water
- return false;
- }
- // This enables FFCs to be solid without having to lay a solid combo under it.
- //
- void GB_SolidifyFFC(ffc this){
- int tho=(this->EffectHeight-16);
- int two=(this->EffectWidth-16);
- int onscreenedge;
- //This detects if link is on the edge of the screen
- if(Link->X<8 || Link->Y<8 || Link->X>232 || Link->Y>152){
- onscreenedge=1;
- }
- else{
- onscreenedge=0;
- }
- //This checks if you're above or below the NPC to create an overhead effect
- if(Link->Y<this->Y-8+tho && onscreenedge==0){
- this->Flags[FFCF_OVERLAY] = true;
- }
- else{
- this->Flags[FFCF_OVERLAY] = false;
- }
- if((Abs(Link->X - this->X-two) < 10) && (Link->Y <= this->Y+tho + 12) && (Link->Y > this->Y+tho+8)){
- Link->Y = this->Y+tho+12;
- }
- if((Abs(Link->Y - this->Y-tho) < 10) && (Link->X >= this->X - 12) && (Link->X < this->X+two-8)){
- Link->X = this->X-12;
- }
- if((Abs(Link->X - this->X-two) < 10) && (Link->Y >= this->Y+tho - 12) && (Link->Y < this->Y+tho-8)){
- Link->Y = this->Y+tho-12;
- }
- if((Abs(Link->Y - this->Y-tho) < 10) && (Link->X <= this->X+two + 12) && (Link->X > this->X+two+8)){
- Link->X = this->X+two+12;
- }
- }
- const int COMBOFX_NOT_TRIGGERED_BY_PUSH = 1; //Set to 1 if you don't want push blocks triggering slash effects (like with a pushable pot)
- const int NPC_COMBOSFX_DROPSET = 85; //Item dropset enemy (Fire by default)
- const int COMBOSFX_CHECKALL = 1; //If set to 1, the script will check all combos on screen every frame. This is generally slower and not advised, but there may be cases you'd want this.
- void CSA_AutoSlashable_Update(int lastDMapScreen){
- if(lastDMapScreen[0]!=Game->GetCurDMap()||lastDMapScreen[1]!=Game->GetCurDMapScreen()){
- int i; int j; int k;
- int autoSlashableID[65280];
- int autoSlashableData[2056];
- autoSlashableData[0] = 0;
- //AUTO SLASHABLES HERE
- //Add your auto slashables with the provided function here
- // COMBO SFX TYPE GFX CS FRAMES ASPEED RAND/DROPSET
- //EXAMPLE:
- //CSA_AddAutoSlashable(autoSlashableID, autoSlashableData, 7680, 41, 2, 52020, 2, 0, 0, 0); //Bush - Green
- //End of auto slashables
- for(i=0; i<176; i++){
- int cd = Screen->ComboD[i];
- if(autoSlashableID[cd]){
- int scr[] = "ComboSFXAnim";
- int args[8];
- k = autoSlashableID[cd];
- for(j=0; j<8; j++){
- args[j] = autoSlashableData[k*8+j];
- }
- RunFFCScript(Game->GetFFCScript(scr), args);
- autoSlashableID[cd] = 0;
- }
- }
- lastDMapScreen[0] = Game->GetCurDMap();
- lastDMapScreen[1] = Game->GetCurDMapScreen();
- }
- }
- ffc script ComboSFXAnim{
- void run(int combo, int sfx, int type, int gfx, int cs, int frames, int aspeed, int rand_or_dropset){
- int i; int j; int k;
- int comboCount; //Max index of positions[]
- int positions[176]; //Keeps track of all combo position (0-175) currently being tracked
- int lastCombo[176]; //Last known combo of every position onscreen
- bool hadCombo[176]; //Used for when COMBOSFX_CHECKALL is used in combination with negative combo ID
- //Negative combo ID makes it animate every time the combo changes
- bool everyFrame = false;
- if(combo<0){
- combo = Abs(combo);
- everyFrame = true;
- }
- for(i=0; i<176; i++){
- positions[i] = -1;
- lastCombo[i] = Screen->ComboD[i];
- }
- //Find all valid combos
- for(i=0; i<176; i++){
- if(Screen->ComboD[i]==combo||COMBOSFX_CHECKALL){
- positions[comboCount] = i;
- if(Screen->ComboD[i]==combo)
- hadCombo[i] = true;
- comboCount++;
- }
- }
- int lastMovingBlockX;
- int lastMovingBlockY;
- int movingBlockPositionIndex = -1; //Array index for the moving block's combo position
- while(true){
- bool blockStartedMoving = false;
- bool blockStoppedMoving = false;
- //If the push block is active
- if(Screen->MovingBlockX>-1&&Screen->MovingBlockY>-1){
- //If this is the first frame it was active
- if(lastMovingBlockX==-1){
- blockStartedMoving = true;
- }
- }
- //If the push block was previously active
- if(lastMovingBlockX>-1&&lastMovingBlockY>-1){
- //If it isn't active anymore
- if(Screen->MovingBlockX==-1){
- blockStoppedMoving = true;
- }
- }
- //Only check combos that had the right ID on init
- for(i=0; i<comboCount; i++){
- j = positions[i];
- if(j>-1){
- //Whenever it changes
- if(Screen->ComboD[j]!=lastCombo[j]){
- //Keeps track of whether a push block triggered the combo change
- bool wasPushBlockTriggered;
- if(COMBOFX_NOT_TRIGGERED_BY_PUSH){
- if(blockStartedMoving){
- //If the push block was triggered by this combo
- if(ComboAt(Screen->MovingBlockX+8, Screen->MovingBlockY+8)==j){
- wasPushBlockTriggered = true;
- }
- }
- if(blockStoppedMoving){
- //If the push block ended up on this combo
- if(ComboAt(lastMovingBlockX+8, lastMovingBlockY+8)==j){
- wasPushBlockTriggered = true;
- }
- }
- }
- if(Screen->ComboD[j]==combo)
- hadCombo[j] = true;
- //Do the animation if other conditions are right
- bool doAnim = false;
- if(!everyFrame){
- if(lastCombo[j]==combo)
- doAnim = true;
- }
- else{
- if(hadCombo[j])
- doAnim = true;
- }
- if(wasPushBlockTriggered)
- doAnim = false;
- if(doAnim){
- Game->PlaySound(sfx);
- //Create and kill an enemy if the dropset is set
- if(rand_or_dropset<0){
- npc n = CreateNPCAt(NPC_COMBOSFX_DROPSET, ComboX(j), ComboY(j));
- n->ItemSet = Abs(rand_or_dropset);
- n->HP = -1000;
- n->DrawYOffset = -1000;
- }
- if(type>1){ //Particle animations
- int scr[] = "CSA_Animations";
- int args[8];
- args[0] = type-2;
- args[1] = gfx;
- args[2] = cs;
- args[3] = frames;
- args[4] = aspeed;
- args[5] = rand_or_dropset;
- ffc f = Screen->LoadFFC(RunFFCScript(Game->GetFFCScript(scr), args));
- f->X = ComboX(j);
- f->Y = ComboY(j);
- }
- else if(type==1){ //Sprite animation
- lweapon poof = CreateLWeaponAt(LW_SCRIPT10, ComboX(j), ComboY(j));
- poof->UseSprite(gfx);
- poof->DrawYOffset = 0;
- if(cs>0)
- poof->CSet = cs;
- poof->DeadState = poof->NumFrames*poof->ASpeed;
- if(rand_or_dropset>1){
- poof->OriginalTile += Rand(rand_or_dropset)*poof->NumFrames;
- poof->Tile = poof->OriginalTile;
- }
- }
- }
- lastCombo[j] = Screen->ComboD[j];
- }
- }
- }
- if(blockStartedMoving){
- //Find if the moving block is starting on one of the combo positions in the array
- k = ComboAt(Screen->MovingBlockX+8, Screen->MovingBlockY+8);
- for(i=0; i<comboCount; i++){
- j = positions[i];
- if(j==k){
- movingBlockPositionIndex = i;
- break;
- }
- }
- }
- else if(blockStoppedMoving){
- //If the moving block was in the array, update its position
- if(movingBlockPositionIndex>-1){
- k = ComboAt(lastMovingBlockX+8, lastMovingBlockY+8);
- positions[movingBlockPositionIndex] = k;
- }
- movingBlockPositionIndex = -1;
- }
- lastMovingBlockX = Screen->MovingBlockX;
- lastMovingBlockY = Screen->MovingBlockY;
- Waitframe();
- }
- }
- }
- ffc script CSA_Animations{
- void run(int type, int gfx, int cs, int frames, int aspeed, int rand_or_dropset){
- this->Flags[FFCF_ETHEREAL] = true;
- int i; int j; int k;
- int thisNum;
- for(i=1; i<=32; i++){
- ffc f = Screen->LoadFFC(i);
- if(f->Script==this->Script){
- if(f==this)
- break;
- else
- thisNum++;
- }
- }
- if(type==0){ //Bush leaves
- for(i=0; i<8; i++){
- for(j=0; j<3; j++){
- TileAnim_BushAnim(this->X-8, this->Y, gfx, cs, i, thisNum);
- Waitframe();
- }
- }
- }
- else{
- int particleX[32];
- int particleY[32];
- int particleTile[32];
- int particleA[32];
- int particleS[32];
- int particleT[32];
- int particleMT[32];
- int particleAnim[32];
- int particle[16] = {999, particleX, particleY, particleTile, particleA, particleS, particleT, particleMT, particleAnim};
- if(type==1){ //Random spread
- for(i=0; i<12; i++){
- j = gfx;
- if(rand_or_dropset>1)
- j += Rand(rand_or_dropset)*Max(frames, 1);
- Particle_Add(particle, this->X+Rand(-4, 4), this->Y+Rand(-4, 4), j, Rand(360), Rand(20, 120)/100, Rand(12, 18));
- }
- //Run until all particles are dead
- while(particle[0]>0){
- Particle_Update(particle, frames, aspeed, cs);
- Waitframe();
- }
- }
- else if(type==2){ //Aimed spread
- k = Angle(Link->X, Link->Y, this->X, this->Y);
- for(i=0; i<6; i++){
- j = gfx;
- if(rand_or_dropset>1)
- j += Rand(rand_or_dropset)*Max(frames, 1);
- Particle_Add(particle, this->X+Rand(-4, 4), this->Y+Rand(-4, 4), j, k+Rand(-20, 20), Rand(5, 20)/10, Rand(12, 18));
- }
- //Run until all particles are dead
- while(particle[0]>0){
- Particle_Update(particle, frames, aspeed, cs);
- Waitframe();
- }
- }
- }
- }
- void Particle_Update(int particle, int frames, int aspeed, int cs){
- int particleX = particle[1];
- int particleY = particle[2];
- int particleTile = particle[3];
- int particleA = particle[4];
- int particleS = particle[5];
- int particleT = particle[6];
- int particleMT = particle[7];
- int particleAnim = particle[8];
- particle[0] = 0; //Reset particle counter for the frame
- for(int i=0; i<32; i++){
- if(particleT[i]>0){
- particle[0]++;
- //Movement
- particleX[i] += VectorX(particleS[i], particleA[i]);
- particleY[i] += VectorY(particleS[i], particleA[i]);
- //Animations
- int til = particleTile[i];
- if(frames>0){
- if(aspeed==0){
- int j = Floor((particleMT[i]-particleT[i])/(particleMT[i]/frames));
- til = particleTile[i]+Clamp(j, 0, frames-1);
- }
- else{
- til = particleTile[i] + Floor(particleAnim[i]/aspeed);
- particleAnim[i] = (particleAnim[i]+1)%(frames*aspeed);
- }
- }
- //Drawing
- Screen->FastTile(4, particleX[i], particleY[i], til, cs, 128);
- particleT[i]--;
- }
- }
- }
- int Particle_Add(int particle, int x, int y, int tile, int angle, int step, int time){
- int particleX = particle[1];
- int particleY = particle[2];
- int particleTile = particle[3];
- int particleA = particle[4];
- int particleS = particle[5];
- int particleT = particle[6];
- int particleMT = particle[7];
- int particleAnim = particle[8];
- for(int i=0; i<32; i++){
- //Find unused particle, set the stuff
- if(particleT[i]==0){
- particleX[i] = x;
- particleY[i] = y;
- particleTile[i] = tile;
- particleA[i] = angle;
- particleS[i] = step;
- particleT[i] = time;
- particleMT[i] = time;
- particleAnim[i] = 0;
- return i;
- }
- }
- }
- void TileAnim_BushAnim(int x, int y, int tile, int cset, int frame, int thisNum){
- int posX[32] = {16, 6, 20, 14, //Frame 1
- 16, 9, 17, 14, //Frame 2
- 17, 10, 14, 12, //Frame 3
- 17, 11, 15, 11, //Frame 4
- 19, 8, 18, 10, //Frame 5
- 20, 4, 19, 9, //Frame 6
- 21, 3, 22, 8, //Frame 7
- 14, 1, 16, 7}; //Frame 8
- int posY[32] = {11, 8, 7, 1, //Frame 1
- 14, 9, 8, -1, //Frame 2
- 16, 10, 10, -2, //Frame 3
- 18, 10, 10, -3, //Frame 4
- 20, 10, 14, -4, //Frame 5
- 21, 10, 14, -6, //Frame 6
- 23, 9, 14, -9, //Frame 7
- 24, 7, 21, -11};//Frame 8
- int flip[32] = {0, 0, 1, 0, //Frame 1
- 0, 0, 1, 0, //Frame 2
- 1, 0, 1, 0, //Frame 3
- 0, 1, 0, 3, //Frame 4
- 0, 1, 0, 0, //Frame 5
- 0, 0, 0, 0, //Frame 6
- 0, 0, 1, 0, //Frame 7
- 1, 1, 0, 0}; //Frame 8
- for(int i=0; i<4; i++){
- Screen->DrawTile(4, x+posX[frame*4+i]-4, y+posY[frame*4+i]-4, tile+i, 1, 1, cset, -1, -1, 0, 0, 0, flip[frame*4+i], true, 128);
- }
- }
- }
- void CSA_AddAutoSlashable(int autoSlashableID, int autoSlashableData, int combo, int sfx, int type, int gfx, int cs, int frames, int aspeed, int rand_or_dropset){
- ++autoSlashableData[0];
- int k = autoSlashableData[0];
- autoSlashableID[combo] = k;
- autoSlashableData[k*8+0] = combo;
- autoSlashableData[k*8+1] = sfx;
- autoSlashableData[k*8+2] = type;
- autoSlashableData[k*8+3] = gfx;
- autoSlashableData[k*8+4] = cs;
- autoSlashableData[k*8+5] = frames;
- autoSlashableData[k*8+6] = aspeed;
- autoSlashableData[k*8+7] = rand_or_dropset;
- autoSlashableData[0] = Min(autoSlashableData[0], 256);
- }
- const int dayLength = 5; //Length of a day or night in minutes;
- const int I_NIGHT = 45; //An unused item ID, placed into Link's inventory or removed to change day/night
- const int dayDMAP0 = 0; //Daytime DMap #0
- const int nightDMAP0 = 1; //Night DMap #0
- const int dayDMAP1 = -1; //Daytime DMap #1
- const int nightDMAP1 = -1; //Night DMap #1
- const int dayDMAP24 = 24; //Daytime DMap #2
- const int nightDMAP24 = 25; //Night DMap #2
- const int dayDMAP25 = -25; //Daytime DMap #3
- const int nightDMAP25 = -25; //Night DMap #3
- const int dayDMAP11 = 11; //Daytime DMap #4
- const int nightDMAP11 = 12; //Night DMap #4
- const int dayDMAP12 = -12; //Daytime DMap #5
- const int nightDMAP12 = -12; //Night DMap #5
- const int dayDMAP13 = 13; //Daytime DMap #6
- const int nightDMAP13 = 14; //Night DMap #6
- const int dayDMAP14 = -14; //Daytime DMap #7
- const int nightDMAP14 = -14; //Night DMap #7
- const int dayDMAP26 = 26; //Daytime DMap #6
- const int nightDMAP26 = 27; //Night DMap #6
- const int dayDMAP27 = -27; //Daytime DMap #7
- const int nightDMAP27 = -27; //Night DMap #7
- global script FairyQSTglobal
- {void changeNight(bool cycle)
- {if(cycle){
- if(Link->Item[I_NIGHT])Link->Item[I_NIGHT]=false;
- else{Link->Item[I_NIGHT]=true;}
- }if(Game->GetCurScreen()!=128){
- if(dayDMAP0>=0&&nightDMAP0>=0){
- if(Game->GetCurDMap()==dayDMAP0 && Link->Item[I_NIGHT]){
- Link->PitWarp(nightDMAP0, Game->GetCurScreen());
- } else if(Game->GetCurDMap()==nightDMAP0 && !Link->Item[I_NIGHT]){
- Link->PitWarp(dayDMAP0, Game->GetCurScreen());
- }
- }
- if(dayDMAP1>=0&&nightDMAP1>=0){
- if(Game->GetCurDMap()==dayDMAP1 && Link->Item[I_NIGHT]){
- Link->PitWarp(nightDMAP1, Game->GetCurScreen());
- } else if(Game->GetCurDMap()==nightDMAP1 && !Link->Item[I_NIGHT]){
- Link->PitWarp(dayDMAP1, Game->GetCurScreen());
- }
- }
- if(dayDMAP24>=24&&nightDMAP24>=24){
- if(Game->GetCurDMap()==dayDMAP24 && Link->Item[I_NIGHT]){
- Link->PitWarp(nightDMAP24, Game->GetCurScreen());
- } else if(Game->GetCurDMap()==nightDMAP24 && !Link->Item[I_NIGHT]){
- Link->PitWarp(dayDMAP24, Game->GetCurScreen());
- }
- }
- if(dayDMAP25>=24&&nightDMAP25>=24){
- if(Game->GetCurDMap()==dayDMAP25 && Link->Item[I_NIGHT]){
- Link->PitWarp(nightDMAP25, Game->GetCurScreen());
- } else if(Game->GetCurDMap()==nightDMAP25 && !Link->Item[I_NIGHT]){
- Link->PitWarp(dayDMAP25, Game->GetCurScreen());
- }
- }
- if(dayDMAP11>=11&&nightDMAP11>=11){
- if(Game->GetCurDMap()==dayDMAP11 && Link->Item[I_NIGHT]){
- Link->PitWarp(nightDMAP11, Game->GetCurScreen());
- } else if(Game->GetCurDMap()==nightDMAP11 && !Link->Item[I_NIGHT]){
- Link->PitWarp(dayDMAP11, Game->GetCurScreen());
- }
- }
- if(dayDMAP12>=11&&nightDMAP12>=11){
- if(Game->GetCurDMap()==dayDMAP12 && Link->Item[I_NIGHT]){
- Link->PitWarp(nightDMAP12, Game->GetCurScreen());
- } else if(Game->GetCurDMap()==nightDMAP12 && !Link->Item[I_NIGHT]){
- Link->PitWarp(dayDMAP12, Game->GetCurScreen());
- }
- }
- if(dayDMAP13>=13&&nightDMAP13>=13){
- if(Game->GetCurDMap()==dayDMAP13 && Link->Item[I_NIGHT]){
- Link->PitWarp(nightDMAP13, Game->GetCurScreen());
- } else if(Game->GetCurDMap()==nightDMAP13 && !Link->Item[I_NIGHT]){
- Link->PitWarp(dayDMAP13, Game->GetCurScreen());
- }
- }
- if(dayDMAP14>=13&&nightDMAP14>=13){
- if(Game->GetCurDMap()==dayDMAP14 && Link->Item[I_NIGHT]){
- Link->PitWarp(nightDMAP14, Game->GetCurScreen());
- } else if(Game->GetCurDMap()==nightDMAP14 && !Link->Item[I_NIGHT]){
- Link->PitWarp(dayDMAP14, Game->GetCurScreen());
- }
- }
- if(dayDMAP26>=26&&nightDMAP26>=26){
- if(Game->GetCurDMap()==dayDMAP26 && Link->Item[I_NIGHT]){
- Link->PitWarp(nightDMAP26, Game->GetCurScreen());
- } else if(Game->GetCurDMap()==nightDMAP26 && !Link->Item[I_NIGHT]){
- Link->PitWarp(dayDMAP26, Game->GetCurScreen());
- }
- }
- if(dayDMAP27>=26&&nightDMAP27>=26){
- if(Game->GetCurDMap()==dayDMAP27 && Link->Item[I_NIGHT]){
- Link->PitWarp(nightDMAP27, Game->GetCurScreen());
- } else if(Game->GetCurDMap()==nightDMAP27 && !Link->Item[I_NIGHT]){
- Link->PitWarp(dayDMAP27, Game->GetCurScreen());
- }
- }// You can copy this entire IF statement and change it to, say, dayDMAP10 and nightDMAP11 to create an
- // additional DMap to have a day/night cycle for. This can be done indefinitely.
- }
- }
- void run(){
- int frame = 0;
- int min = 0;
- MooshPit_Init();
- int waterCounter = 0;
- int lastDMapScreen[2];
- while(true){
- MooshPit_Update();
- bool cycle = false;
- if(min==dayLength){cycle=true;min=0;}
- changeNight(cycle);
- Waitdraw();
- frame++;
- if(frame==3600){
- frame=0;
- min++;
- if ( waterCounter >= WATER_CURRENT_FREQ )
- {
- doCurrents();
- waterCounter = 0;
- }
- waterCounter++;
- swimLandCheck();
- }
- CSA_AutoSlashable_Update(lastDMapScreen);
- Waitdraw();
- Waitframe();
- }
- }
- }
- ffc script MooshPit_StairsFix{
- void run(){
- this->Flags[FFCF_ETHEREAL] = false;
- while(LinkCollision(this)){
- Waitframe();
- }
- this->X = 0;
- this->Y = 0;
- this->Data = 0;
- }
- }
- ffc script flowingWater{
- void run ( int frequency ){
- if( frequency < 1 )
- frequency = WATER_CURRENT_FREQ;
- while ( true ){
- doCurrents();
- Waitframes(frequency);
- swimLandCheck();
- }
- }
- }
- lweapon script scr9
- {
- void run()
- {
- TraceS("Running Weapon Script scr9"); TraceNL();
- int clk = 200;
- this->X = 50; this->Y = 50;
- while(1)
- {
- //++this->ScriptTile;
- if ( Input->ReadKey[KEY_P] )
- {
- this->DeadState = WDS_DEAD;
- Trace(this->DeadState);
- }
- Waitframe();
- }
- }
- }
- npc script n
- {
- void run()
- {
- while(this->isValid())
- {
- //TraceS("NPC Script N is Running"); TraceNL();
- //TraceS("CanMove returned: "); TraceB(this->CanMove({this->Dir,4,0}));
- bool can = this->CanMove({this->Dir});
- if ( !can ) { TraceS("CanMove returned false."); TraceNL(); }
- if ( Input->ReadKey[KEY_N] ) this->Attack();
- if ( Input->ReadKey[KEY_K] ) this->Remove();
- if ( Input->ReadKey[KEY_L] ) this->Slide();
- Waitframe();
- }
- }
- }
- npc script floater_old
- {
- void run()
- {
- TraceS("Running npc script 'test'"); TraceNL();
- this->Dir = Rand(0,3);
- while(this->isValid())
- {
- this->FloatingWalk({10,200,2});
- Waitframe();
- }
- }
- }
- npc script floater
- {
- void run()
- {
- int attack_clk;
- TraceS("Running npc script 'test'"); TraceNL();
- this->Dir = Rand(0,3);
- switch(this->Dir)
- {
- case DIR_UP: this->ScriptTile = 862; break;
- case DIR_DOWN: this->ScriptTile = 861; break;
- case DIR_LEFT: this->ScriptTile = 882; break;
- case DIR_RIGHT: this->ScriptTile = 881; break;
- default: break;
- }
- this->ScriptTile = this->Tile;
- while(this->isValid())
- {
- switch(this->Dir)
- {
- case DIR_UP: this->ScriptTile = 862; break;
- case DIR_DOWN: this->ScriptTile = 861; break;
- case DIR_LEFT: this->ScriptTile = 882; break;
- case DIR_RIGHT: this->ScriptTile = 881; break;
- default: break;
- }
- //this->ScriptTile;
- //if ( this->CanMove(this->Dir) )
- //{
- this->FloatingWalk({10,200,2});
- //}
- if ( this->LinedUp(200,true) )
- {
- if ( this->LinkInRange(100) )
- {
- if (!attack_clk)
- {
- attack_clk = 100;
- this->Attack();
- }
- }
- }
- if (attack_clk) --attack_clk;
- Waitframe();
- }
- }
- }
- npc script walker
- {
- void run()
- {
- int attack_clk;
- TraceS("Running npc script 'test'"); TraceNL();
- this->Dir = Rand(0,3);
- switch(this->Dir)
- {
- case DIR_UP: this->ScriptTile = 862; break;
- case DIR_DOWN: this->ScriptTile = 861; break;
- case DIR_LEFT: this->ScriptTile = 882; break;
- case DIR_RIGHT: this->ScriptTile = 881; break;
- default: break;
- }
- this->ScriptTile = this->Tile;
- while(this->isValid())
- {
- switch(this->Dir)
- {
- case DIR_UP: this->ScriptTile = 862; break;
- case DIR_DOWN: this->ScriptTile = 861; break;
- case DIR_LEFT: this->ScriptTile = 882; break;
- case DIR_RIGHT: this->ScriptTile = 881; break;
- default: break;
- }
- //this->ScriptTile;
- //if ( this->CanMove(this->Dir) )
- //{
- this->HaltingWalk({10,1,0,50,2});
- //}
- if ( this->LinedUp(200,true) )
- {
- if ( this->LinkInRange(100) )
- {
- if (!attack_clk)
- {
- attack_clk = 100;
- this->Attack();
- }
- }
- }
- if (attack_clk) --attack_clk;
- Waitframe();
- }
- }
- }
- ffc script Only_Move_With_Secrets{
- void run(int initial_x, int initial_y){
- initial_x = this->Vx;
- initial_y = this->Vy;
- this->Vx = 0;
- this->Vy = 0;
- while (!Screen->State[ST_SECRET]) Waitframe();
- this->Vx = initial_x;
- this->Vy = initial_y;
- }
- }
- ffc script CaveItemRoomWarp
- {
- untyped cachedData[NUM_CACHED_DATA] = {-1, -1};
- enum cachedIndex
- {
- CACHED_COMBO,
- CACHED_SPECIALITEM_SCRIPT,
- NUM_CACHED_DATA
- };
- define CARRY_ONLY_SPECIALITEM = NOCARRY_B_SECRET | NOCARRY_B_ITEM | NOCARRY_B_LOCKBLOCK | NOCARRY_B_BOSSLOCKBLOCK | NOCARRY_B_CHEST | NOCARRY_B_LOCKEDCHEST | NOCARRY_B_BOSSCHEST;
- /**
- * SETUP:
- * Set the combo for this FFC to any tile warping combo
- * - example: Stair [A], Cave (Walk Down) [A]
- * - if it is set to anything else, the lowest-numbered valid 'Stairs[A]' combo will be used.
- * Set the tile warp on the screen to the destination you desire.
- * - Also set the warp type, return square, etc; do not use 'Cave/Item Cellar'
- * On the destination screen, both sidewarp A and tilewarp A will be set to return to the origin.
- * -Set these warps for any sides/tiles you want to return you.
- * -They will automatically use the same warp type you warped with as well
- * -The return warps will send you to the same-letter return square that you set for the warp
- *
- * Extra (optional) features:
- * - ITEM: If d0 is an item ID, then it will place that item on the target screen, tied to the SOURCE screen's `ST_SPECIALITEM` state.
- * -To disable this, use a negative number.
- * -You cannot use this and also use screen state carryover on the target screen.
- * -You cannot use this and also use a screen script on the target screen, unless it is the SpawnSpecialItem script.
- * -To position the item placement, set up the SpawnSpecialItem script on the target screen (ignoring it's itemID parameter)
- *
- */
- void run(int itemid)
- {
- combodata cd = Game->LoadComboData(this->Data);
- int tilewarp;
- switch(cd->Type) //start What Tilewarp?
- {
- case CT_CAVE:
- case CT_CAVE2:
- case CT_DIVEWARP:
- case CT_PIT:
- case CT_STAIR:
- case CT_SWIMWARP:
- tilewarp = TILEWARP_A;
- break;
- case CT_CAVEB:
- case CT_CAVE2B:
- case CT_DIVEWARPB:
- case CT_PITB:
- case CT_STAIRB:
- case CT_SWIMWARPB:
- tilewarp = TILEWARP_B;
- break;
- case CT_CAVEC:
- case CT_CAVE2C:
- case CT_DIVEWARPC:
- case CT_PITC:
- case CT_STAIRC:
- case CT_SWIMWARPC:
- tilewarp = TILEWARP_C;
- break;
- case CT_CAVED:
- case CT_CAVE2D:
- case CT_DIVEWARPD:
- case CT_PITD:
- case CT_STAIRD:
- case CT_SWIMWARPD:
- tilewarp = TILEWARP_D;
- break;
- default:
- {
- tilewarp = TILEWARP_A;
- if(cachedData[CACHED_COMBO]>-1)
- {
- this->Data = cachedData[CACHED_COMBO];
- break;
- }
- combodata cd;
- for(int q = 1; q < MAX_COMBOS; ++q)
- {
- cd = Game->LoadComboData(q);
- if(cd->Type == CT_STAIR)
- {
- cachedData[CACHED_COMBO] = q;
- break;
- }
- }
- unless(cachedData[CACHED_COMBO]>-1) //No stairs combos in the ENTIRE COMBOLIST?
- {
- cd->Type = CT_STAIR;
- cachedData[CACHED_COMBO] = cd->ID;
- }
- this->Data = cachedData[CACHED_COMBO];
- }
- } //end
- unless(cachedData[CACHED_SPECIALITEM_SCRIPT]>-1)
- {
- cachedData[CACHED_SPECIALITEM_SCRIPT] = Game->GetScreenScript("SpawnSpecialItem");
- }
- int dmapID = Screen->GetTileWarpDMap(tilewarp);
- dmapdata destDMap = Game->LoadDMapData(dmapID);
- mapdata md = Game->LoadMapData(destDMap->Map, DMapToMap(Screen->GetTileWarpScreen(tilewarp), dmapID));
- int warptype = Screen->GetTileWarpType(tilewarp);
- int curmap = Game->GetCurMap();
- int curdmap = Game->GetCurDMap();
- int curscreen = Game->GetCurScreen();
- int retsquare = Screen->TileWarpReturnSquare[tilewarp];
- bool doItem = itemid>=0;
- while(true)
- {
- if(Distance(this->X, this->Y, Link->X, Link->Y)<24)
- {
- md->TileWarpDMap[TILEWARP_A] = curdmap;
- md->TileWarpScreen[TILEWARP_A] = curscreen;
- md->SideWarpDMap[SIDEWARP_A] = curdmap;
- md->SideWarpScreen[SIDEWARP_A] = curscreen;
- md->TileWarpType[TILEWARP_A] = warptype;
- md->SideWarpType[SIDEWARP_A] = warptype;
- md->TileWarpReturnSquare[TILEWARP_A] = retsquare;
- md->SideWarpReturnSquare[SIDEWARP_A] = retsquare;
- if(doItem)
- {
- md->State[ST_SPECIALITEM] = Screen->State[ST_SPECIALITEM];
- unless(Screen->State[ST_SPECIALITEM])
- {
- md->NextMap = curmap;
- md->NextScreen = curscreen;
- md->NoCarry = CARRY_ONLY_SPECIALITEM;
- md->Script = cachedData[CACHED_SPECIALITEM_SCRIPT];
- md->InitD[0] = itemid;
- }
- }
- while(Distance(this->X, this->Y, Link->X, Link->Y)<24) Waitframe();
- }
- Waitframe();
- }
- }
- }
- screendata script SpawnSpecialItem
- {
- define DEFAULT_X = (256/2)-8;
- define DEFAULT_Y = (176/2)-8;
- /**
- * Setup:
- * d0: Item ID (ignore if using this with CaveItemRoomWarp)
- * d1: Item X position
- * d2: Item Y position
- */
- void run(int spawnItemID, int itemX, int itemY)
- {
- if(this->State[ST_SPECIALITEM]) return;
- unless(itemX) itemX = DEFAULT_X;
- unless(itemY) itemY = DEFAULT_Y;
- item spitem = CreateItemAt(spawnItemID, itemX, itemY);
- spitem->Pickup = IP_ST_SPECIALITEM | IP_HOLDUP;
- }
- }
- npc script FleshyDodongo
- {
- void run()
- {
- //Make the first instance of the enemy invisible
- this->DrawYOffset = -1000;
- this->CollDetection = false;
- //Spawn a second enemy for the body with no script
- npc body = CreateNPCAt(this->ID, this->X, this->Y);
- body->Script = 0;
- body->Extend = 3;
- int vars[16];
- //vars[0] - Animation Clock
- while(true)
- {
- //The controller enemy handles movement
- this->ConstantWalk({this->Rate, this->Homing, this->Hunger});
- //Then update's the body's position and animation
- FD_UpdateBody(this, vars, body);
- //When the body dies, center it and kill the controller too
- if(body->HP<=0)
- {
- int x = CenterX(body);
- int y = CenterY(body);
- body->X = x-8;
- body->Y = y-8;
- body->TileWidth = 1;
- body->TileHeight = 1;
- body->HitWidth = 16;
- body->HitHeight = 16;
- this->HP = -1000;
- this->ItemSet = 0;
- Quit();
- }
- Waitframe();
- }
- }
- void FD_UpdateBody(npc this, int vars, npc body)
- {
- ++vars[0];
- //Get the enemy's current frame based off F.Rate
- int f4 = Floor(vars[0]/(this->ASpeed/4));
- //Keep the frame wrapped from 0-3
- if(f4==4)
- {
- f4 = 0;
- vars[0] = 0;
- }
- //Update tiles, hitboxes, and position based on the controller's
- switch(this->Dir)
- {
- case DIR_DOWN:
- body->X = this->X;
- body->Y = this->Y-16;
- body->TileWidth = 1;
- body->TileHeight = 2;
- body->HitWidth = 16;
- body->HitHeight = 32;
- body->Tile = this->OriginalTile + 4 + f4;
- body->OriginalTile = body->Tile;
- break;
- case DIR_LEFT:
- body->X = this->X;
- body->Y = this->Y;
- body->TileWidth = 2;
- body->TileHeight = 1;
- body->HitWidth = 32;
- body->HitHeight = 16;
- body->Tile = this->OriginalTile + 40 + f4 * 2;
- body->OriginalTile = body->Tile;
- break;
- case DIR_RIGHT:
- body->X = this->X-16;
- body->Y = this->Y;
- body->TileWidth = 2;
- body->TileHeight = 1;
- body->HitWidth = 32;
- body->HitHeight = 16;
- body->Tile = this->OriginalTile + 60 + f4 * 2;
- body->OriginalTile = body->Tile;
- break;
- default:
- body->X = this->X;
- body->Y = this->Y;
- body->TileWidth = 1;
- body->TileHeight = 2;
- body->HitWidth = 16;
- body->HitHeight = 32;
- body->Tile = this->OriginalTile + f4;
- body->OriginalTile = body->Tile;
- }
- }
- }
- npc script wolfie
- {
- void run()
- {
- int clks[1];
- while(1)
- {
- this->ConstantWalk({this->Rate, this->Homing, this->Hunger});
- nmes::transform2x1(this,clks);
- Waitframe();
- }
- }
- }
- namespace nmes
- {
- void transform2x1(npc n, int clk)
- {
- ++clk[0];
- int f4 = Floor(clk[0]/(n->ASpeed/4));
- if( f4 >= 4 ) { f4 = 0; clk[0] = 0;}
- switch(n->Dir)
- {
- case DIR_DOWN:
- n->Tile = (Game->LoadNPCData(n->ID)->Tile) + 4 + f4;
- n->OriginalTile = n->Tile;
- n->HitXOffset = 0;
- n->HitYOffset = -16;
- n->DrawXOffset = 0;
- n->DrawYOffset = -16;
- n->TileWidth = 1;
- n->TileHeight = 2;
- n->HitWidth = 16;
- n->HitHeight = 32;
- break;
- case DIR_RIGHT:
- n->Tile = (Game->LoadNPCData(n->ID)->Tile) + 60 + (f4 * 2);
- n->OriginalTile = n->Tile;
- n->HitXOffset = -16;
- n->HitYOffset = 0;
- n->DrawXOffset = -16;
- n->DrawYOffset = 0;
- n->TileWidth = 2;
- n->TileHeight = 1;
- n->HitWidth = 32;
- n->HitHeight = 16;
- break;
- case DIR_LEFT:
- n->Tile = (Game->LoadNPCData(n->ID)->Tile) + 40 + (f4 *2);
- n->OriginalTile = n->Tile;
- n->TileWidth = 2;
- n->TileHeight = 1;
- n->HitWidth = 32;
- n->HitHeight = 16;
- n->HitXOffset = 0;
- n->HitYOffset = 0;
- n->DrawXOffset = 0;
- n->DrawYOffset = 0;
- break;
- case DIR_UP:
- n->Tile = (Game->LoadNPCData(n->ID)->Tile) + f4;
- n->OriginalTile = n->Tile;
- n->TileWidth = 1;
- n->TileHeight = 2;
- n->HitWidth = 16;
- n->HitHeight = 32;
- n->HitXOffset = 0;
- n->HitYOffset = 0;
- n->DrawXOffset = 0;
- n->DrawYOffset = 0;
- break;
- }
- }
- }
- ffc script chestSound{
- void run(int sfx, int comboID){
- while(true){
- if ( Screen->ComboD[ComboAt(this->X, this->Y)] == comboID && sfx ) {
- Game->PlaySound(sfx);
- this->Data = 0;
- this->Script = 0;
- Quit();
- }
- Waitframe();
- }
- }
- }
- item script SlashScroll
- {
- void run()
- {
- Game->Generic[GEN_CANSLASH] = 1;
- }
- }
- npc script wolfie2
- {
- void run()
- {
- int clks[1];
- lweapon bite = Screen->CreateLWeapon(EW_SCRIPT1);
- bite->X = this->X;
- bite->Y = this->Y;
- bite->HitHeight = 8;
- bite->HitWidth = 16;
- bite->DrawYOffset = -32768;
- bite->Damage = 2;
- while(1)
- {
- this->ConstantWalk({this->Rate, this->Homing, this->Hunger});
- unless(bite->isValid())
- {
- bite = Screen->CreateLWeapon(EW_SCRIPT1);
- bite->DrawYOffset = -32768;
- bite->Damage = 2;
- }
- if(bite->isValid())
- {
- wolfnme::positionbite(this, bite);
- wolfnme::transformbite(this, bite);
- }
- Waitdraw();
- wolfnme::transform2x1(this,clks);
- Waitframe();
- }
- }
- }
- namespace wolfnme
- {
- void positionbite(npc n, lweapon bite)
- {
- switch(n->Dir)
- {
- case DIR_UP:
- bite->X = n->X; bite->Y = n->Y -1; bite->HitYOffset = -2; bite->HitXOffset = 0; break;
- case DIR_DOWN:
- bite->X = n->X; bite->Y = n->Y + 1; bite->HitYOffset = 24; bite->HitXOffset = 0; break;
- case DIR_LEFT:
- bite->X = n->X - 1; bite->Y = ((n->Y > 0) ? n->Y : n->Y + 1); bite->HitYOffset = 0; bite->HitXOffset = -2; break;
- case DIR_RIGHT:
- bite->X = n->X + 1; bite->Y = ((n->Y > 0) ? n->Y : n->Y + 1); bite->HitYOffset = 0; bite->HitXOffset = 25; break;
- }
- }
- void transformbite(npc n, lweapon l)
- {
- switch(n->Dir)
- {
- case DIR_DOWN:
- case DIR_UP:
- {
- l->HitWidth = 16;
- l->HitHeight = 8;
- break;
- }
- case DIR_RIGHT:
- case DIR_LEFT:
- {
- l->HitWidth = 8;
- l->HitHeight = 16;
- break;
- }
- }
- }
- void transform2x1(npc n, int clk)
- {
- ++clk[0];
- int f4 = Floor(clk[0]/(n->ASpeed/4));
- if( f4 >= 4 ) { f4 = 0; clk[0] = 0;}
- switch(n->Dir)
- {
- case DIR_DOWN:
- {
- n->Tile = (Game->LoadNPCData(n->ID)->Tile) + 4 + f4;
- n->OriginalTile = n->Tile;
- n->TileWidth = 1;
- n->TileHeight = 2;
- n->HitWidth = 16;
- n->HitHeight = 32;
- break;
- }
- case DIR_RIGHT:
- {
- n->Tile = (Game->LoadNPCData(n->ID)->Tile) + 60 + (f4 * 2);
- n->OriginalTile = n->Tile;
- n->TileWidth = 2;
- n->TileHeight = 1;
- n->HitWidth = 32;
- n->HitHeight = 16;
- break;
- }
- case DIR_LEFT:
- {
- n->Tile = (Game->LoadNPCData(n->ID)->Tile) + 40 + (f4 *2);
- n->OriginalTile = n->Tile;
- n->TileWidth = 2;
- n->TileHeight = 1;
- n->HitWidth = 32;
- n->HitHeight = 16;
- break;
- }
- case DIR_UP:
- {
- n->Tile = (Game->LoadNPCData(n->ID)->Tile) + f4;
- n->OriginalTile = n->Tile;
- n->TileWidth = 1;
- n->TileHeight = 2;
- n->HitWidth = 16;
- n->HitHeight = 32;
- break;
- }
- }
- }
- }
- ////////////////////////////////
- /// Music.zh ///
- /// v1.3.6 - 26th Mar, 2019 ///
- /// By: ZoriaRPG ///
- ////////////////////////////////////////////////////////////////////////////////////////////////////
- /// A series of FFCs, and utility functions for playing MIDIs, Enhanced Music, and Sound Effects ///
- /// 1.3.3: Optimisation for inclusion with ZC 2.53 Gamma 4 ///
- /// 1.3.4: Fixes to NPC_MIDI and NPC_Music ///
- /// 1.3.5: More Fixes to NPC_MIDI and NPC_Music ///
- /// 1.3.6: Renamed BossMusic to MusicZH_BossMusic to avoid a conflict with Classic.zh. ///
- ////////////////////////////////////////////////////////////////////////////////////////////////////
- //#include "std.zh"
- //#include "string.zh"
- const int MIDI_DEFEATBOSS = 0; //Set to default midi to play for Victory Music.
- //ZC will use this if enhanced Victory music is not available.
- const int DEFAULT_BOSS_MUSIC = 0; //Sets a default boss music file to play.
- ///////////////
- /// SCRIPTS ///
- ///////////////
- /////////////////////
- /// Sound Effects ///
- /////////////////////
- // Ties SFX to an item, that is otherwise normally hardcoded. used for the Sonic Wand in LoE.
- item script playSound
- {
- void run(int sfx)
- {
- Game->PlaySound(sfx);
- }
- }
- /////////////////
- /// MIDI Only ///
- /////////////////
- //Plays MIDI specified at D0. Place on a screen, to change the MIDI for that screen, only.
- //Plays at all times on that screen, and uses no conditions.
- ffc script playMIDI
- {
- void run(int midiNumber)
- {
- Game->PlayMIDI(midiNumber);
- }
- }
- /////////////////////////
- /// Conditional MIDIs ///
- /////////////////////////
- //play a MIDI while an enemy with a specific ID is on-screen
- ffc script NPC_MIDI
- {
- void run(int npc_ID, int midi)
- {
- //int originalMIDi = //share these two
- //int originalMusic[3] = //midi, enh music, track
- //store the normal midi or music
- //check for the npc and while it is on-screen
- //change the midi
- Waitframes(6);
- //LogPrint("NPC_MIDI passed %s \n", "Waitframes(1)");
- //if it dies, change back
- int q[4]; npc n; bool found;
- int enh_music[256] = {0};
- Game->GetDMapMusicFilename(Game->GetCurDMap(), enh_music);
- int enh_trk = Game->GetDMapMusicTrack(Game->GetCurDMap());
- for ( q[0] = 0; q[0] < 256; ++q[0] ) { if ( enh_music[q] == ' ' ) enh_music[q] = 0; } //kill the space.
- bool enhanced = ( enh_music[0] != 0 ); //is the dmap music enhanced?
- int originalmusic = Game->DMapMIDI[Game->GetCurDMap()];
- while(!Screen->NumNPCs())
- {
- //LogPrint("NPC_MIDI is %s \n", "Waiting (!Screen->NumNPCs())");
- Waitframe();
- }
- while(true){
- for ( q[0] = Screen->NumNPCs(); q[0] > 0; --q[0] ) {
- n = Screen->LoadNPC(q);
- if ( n->ID == npc_ID )
- {
- //LogPrint("NPC_MIDI %s \n", "matched the input npc");
- q[1] = 1; break;
- }
- q[1] = 0;
- }
- if ( q[1] ) //found the npc
- {
- //LogPrint("NPC_MIDI %s \n", "if(q[1])");
- if ( !q[2] )
- {
- //LogPrint("NPC_MIDI %s \n", "if(!q[2])");
- Game->PlayMIDI( midi );
- q[2] = 1;
- }
- }
- if ( q[2] ) break;
- Waitframe();
- }
- bool stillalive;
- while(1)
- {
- for ( int w = Screen->NumNPCs(); w > 0; --w )
- {
- npc n = Screen->LoadNPC(w);
- if ( n->ID == npc_ID )
- {
- //LogPrint("npc_ID is: %d \n", npc_ID);
- //LogPrint("NPC_MIDI is at %s \n", "still alive");
- stillalive = true;
- break;
- }
- stillalive = false;
- }
- if ( stillalive ) { Waitframe(); continue; }
- if ( !stillalive )
- {
- //LogPrint("NPC_MIDI is at %s \n", "!still alive");
- break;
- }
- Waitframe();
- }
- //LogPrint("NPC_MIDI is at %s \n", "!NumNPCsOf(npc_id)");
- Waitframes(10);
- //LogPrint("NPC_MIDI %s \n", "PlayEnhancedMusic");
- Game->PlayEnhancedMusic(enh_music, enh_trk);
- if ( !enhanced )
- {
- //LogPrint("NPC_MIDI %s \n", "!enhanced");
- Game->PlayMIDI(originalmusic);
- }
- }
- }
- //play enhanced music while an enemy with a specific ID is on-screen
- ffc script NPC_Music
- {
- void run(int npc_ID, int music_string, int track)
- {
- //int originalMIDi = //share these two
- //int originalMusic[3] = //midi, enh music, track
- //store the normal midi or music
- //check for the npc and while it is on-screen
- //change the midi
- Waitframes(6);
- //if it dies, change back
- int q[4]; npc n; bool found;
- int enh_music[256] = {0};
- Game->GetDMapMusicFilename(Game->GetCurDMap(), enh_music);
- int enh_trk = Game->GetDMapMusicTrack(Game->GetCurDMap());
- for ( q[0] = 0; q[0] < 256; ++q[0] ) { if ( enh_music[q] == ' ' ) enh_music[q] = 0; } //kill the space.
- bool enhanced = ( enh_music[0] != 0 ); //is the dmap music enhanced?
- bool playing;
- int originalmusic = Game->DMapMIDI[Game->GetCurDMap()];
- while(!Screen->NumNPCs()) Waitframe();
- while(true){
- for ( q[0] = Screen->NumNPCs(); q[0] > 0; --q[0] )
- {
- n = Screen->LoadNPC(q);
- if ( n->ID == npc_ID )
- {
- q[1] = 1; break;
- }
- q[1] = 0;
- }
- if ( q[1] )
- {
- if ( !q[2] )
- {
- playing = PlayEnhMusicFile(music_string, track);
- q[2] = 1;
- }
- }
- if ( q[2] ) break;
- Waitframe();
- }
- bool stillalive;
- while(1)
- {
- for ( int w = Screen->NumNPCs(); w > 0; --w )
- {
- npc n = Screen->LoadNPC(w);
- if ( n->ID == npc_ID )
- {
- //LogPrint("npc_ID is: %d \n", npc_ID);
- //LogPrint("NPC_MIDI is at %s \n", "still alive");
- stillalive = true;
- break;
- }
- stillalive = false;
- }
- if ( stillalive ) { Waitframe(); continue; }
- if ( !stillalive )
- {
- //LogPrint("NPC_MIDI is at %s \n", "!still alive");
- break;
- }
- Waitframe();
- }
- //LogPrint("NPC_MIDI is at %s \n", "!NumNPCsOf(npc_id)");
- Waitframes(10);
- //LogPrint("NPC_MIDI %s \n", "PlayEnhancedMusic");
- Game->PlayEnhancedMusic(enh_music, enh_trk);
- if ( enhanced ) Game->PlayEnhancedMusic(enh_music, enh_trk);
- else Game->PlayMIDI(originalmusic);
- }
- }
- // These scripts will play MIDI files based on conditions set in the script args.
- // D0: MIDI file to play while boss is on the screen.
- // D1: The Screen Register (Screen->D[reg]) to use.
- // D2: Victory MIDI to play when boss is defeated. If set to 0, the MIDI set by constant MIDI_DEFEATBOSS plays.
- // D3: The duration of the victory music.
- //
- // If set to 0, the track will not play.
- // If set to greater than 0, the track will play for a specific duration, as follows:
- // To set using minutes, and seconds, set up minutes as the integer portion of the arg, and seconds as the decimal portion:
- // e.g. 00005.0260 is 5 mins, 26 seconds.
- // This works to a fineness of 1/10 second, so 00010.0136 is 10 minutes, 13.6 seconds.
- // If you wish to specify the duration in frames, set the ten-thousands place to '1', and the rest of the value to the number of frames.
- // e.g. 10526.1023 = 5,261,023 frames.
- // e.g. 10001.3591 = 13,591 frames.
- //
- // D4: The enemy ID of the 'boss':
- //
- // A value of zero here, instructs the FFC not to change the Screen->D[reg] value. Leave this at zero, if the enemy does this.
- // Otherwise, set this to -1 (negative one) if you want the Victory music to play when all screen NPCs are dead...or...
- // a positive value matching an enemy ID that is on the screen, if you want to play the Victory music when all enemies with that ID are dead.
- ffc script MusicZH_BossMusic
- {
- void run(int bossMIDI, int reg, int victoryMIDI, int vict_dur, int enem)
- {
- Waitframes(6);
- int curScreen = Game->GetCurScreen();
- int dat = Game->GetScreenD(curScreen,reg);
- if ( dat == 0 ) {
- if ( bossMIDI > 0 )
- {
- Game->PlayMIDI(bossMIDI);
- }
- else
- {
- Game->PlayMIDI(DEFAULT_BOSS_MUSIC);
- }
- }
- int curDMap = Game->GetCurDMap();
- int stdMIDI = Game->DMapMIDI[curDMap];
- int VictoryClockMethod = _Music_zh__GetDigit(vict_dur, 4);
- int dur;
- if ( VictoryClockMethod == 0 )
- {
- dur = MusicFrames(vict_dur); //Convert victory music into frames.
- }
- if ( VictoryClockMethod > 0 )
- {
- dur = _Music_zh__GetPartialArg(vict_dur,3,8); //Use the full value of loopBossMusic as frame in int.
- }
- while(true)
- {
- dat = Game->GetScreenD(curScreen,reg);
- if ( enem == -1 && !Screen->NumNPCs() )
- {
- Game->SetScreenD(curScreen,reg,1);
- }
- if ( enem == 0 )
- {
- //Should we do anything special?
- //A zero value is intended to be used if we don;t want the FFC to set Screen->D to 1.
- //-1 if we do it based on all enemies being dead.
- //A positive value trips it if there are no enemies of that ID on the screen.
- }
- if ( enem > 0 && !NumNPCsOf(enem) )
- {
- Game->SetScreenD(curScreen,reg,1);
- }
- dat = Game->GetScreenD(curScreen,reg);
- if ( dat > 0 )
- {
- if ( dur > 0 )
- {
- if ( victoryMIDI > 0 )
- {
- Game->PlayMIDI(MIDI_DEFEATBOSS);
- }
- else
- {
- Game->PlayMIDI(MIDI_DEFEATBOSS);
- }
- for ( int q = 0; q <= dur; ++q )
- {
- Waitframe();
- }
- }
- Game->PlayMIDI(stdMIDI);
- }
- Waitframe();
- }
- }
- }
- //////////////////////
- /// Enhanced Music ///
- //////////////////////
- /// These scripts will play 'enhanced music', using values set in script args.
- /// If an enhanced music file is not available (e.g. the player does not have it, or elects
- /// not to use it, then they will play a back-up MIDI file, also set by script args.
- // D0: MIDI number to default to for this boss, if no enhanced music is available.
- // Split argument, high and low at decimal point:
- // #####.xxxx -> Backup MIDI file to play if enhanced BOSS music is not available.
- // xxxxx.#### -> Backup MIDI file to play if enhanced VICTORY music is not available.
- // D1: Screen->D reg to set/check.
- // D2: The duration of the victory music.
- // If set to 0, the track will not play.
- // If set to greater than 0, the track will play for a specific duration, as follows:
- // To set using minutes, and seconds, set up minutes as the integer portion of the arg, and seconds as the decimal portion:
- // e.g. 00005.0260 is 5 mins, 26 seconds.
- // This works to a fineness of 1/10 second, so 00010.0136 is 10 minutes, 13.6 seconds.
- // If you wish to specify the duration in frames, set the ten-thousands place to '1', and the rest of the value to the number of frames.
- // e.g. 10526.1023 = 5,261,023 frames.
- // e.g. 10001.3591 = 13,591 frames.
- //
- // D3: The STRING number, and track number, for Boss Music. Split arg, high and low at decimal point:
- // #####.xxxx -> The file number.
- // xxxxx.#### -> The track number to play.
- // Uses string ID from internal strings table.
- // D4: The STRING number, and track number, for Victory Music. Split arg, high and low at decimal point:
- // #####.xxxx -> The file number.
- // xxxxx.#### -> The track number to play.
- // Uses string ID from internal strings table.
- // D5: The point in the track to pause, then loop
- //
- // If set to 0, the track with loop only when it ends.
- // If set to greater than 0, the track will loop befor eit ends, as follows:
- // To loop by setting minutes, and seconds, set up minutes as the integer portion of the arg, and seconds as the decimal portion:
- // e.g. 00005.0260 is 5 mins, 26 seconds.
- // This works to a fineness of 1/10 second, so 00010.0136 is 10 minutes, 13.6 seconds.
- // If you wish to specify the loop in frames, set the ten-thousands place to '1', and the rest of the value to the number of frames.
- // e.g. 10526.1023 = 5,261,023 frames.
- // e.g. 10001.3591 = 13,591 frames.
- //
- // D6: This value instructs the FFC to set Screen->D[reg] = 1 when enemies are dead.
- // A value of zero here, instructs the FFC not to change the Screen->D[reg] value. Leave this at zero, if the enemy does this.
- // Otherwise, set this to -1 (negative one) if you want the Victory music to play when all screen NPCs are dead...or...
- // a positive value matching an enemy ID that is on the screen, if you want to play the Victory music when all enemies with that ID are dead.
- //
- // D7: If set to '1' or above, this will trace informationt o allegro.log for you as debug datum.
- //Version 0.44 - Strings set by String Table (ZQuest String Editor, not hardcoded)
- ffc script BossMusicEnhanced_InternalStrings
- {
- //Credit Moosh for reminding me that reading internal strings in the string table is a thing.
- void run(int midiNumber_victoryMidiNumber, int reg, int vict_dur, float musicBoss_trkBoss, float musicVictory_trkVictory, float loopBossMusic, int enem, int debug)
- {
- int curScreen = Game->GetCurScreen();
- int curDMAP = Game->GetCurDMap();
- int curDmap = Game->GetCurDMap();
- int dat = Game->GetScreenD(curScreen,reg);
- int stdMIDI = Game->DMapMIDI[curDMAP];
- int dmapMusicBuffer[512]=" ";
- Game->GetDMapMusicFilename(curDMAP, dmapMusicBuffer);
- int midiNumber = _Music_zh__GetHighArgument(midiNumber_victoryMidiNumber); //#####.xxxx
- int victoryMIDI = _Music_zh__GetLowArgument(midiNumber_victoryMidiNumber); //xxxxx.####
- int musicBoss = _Music_zh__GetHighArgument(musicBoss_trkBoss); //#####.xxxx
- int trkBoss = _Music_zh__GetLowArgument(musicBoss_trkBoss); //xxxxx.####
- int musicVictory = _Music_zh__GetHighArgument(musicVictory_trkVictory);
- int trkVictory = _Music_zh__GetLowArgument(musicVictory_trkVictory); //xxxxx.####
- int dmapTrack = Game->GetDMapMusicTrack(curDMAP);
- int q;
- int boss_buffer[256]=" "; //two-digit number, plus four-digit extension, plus NULL.
- int victory_buffer[256]=" "; //Buffer for Victory Music Filename.
- Game->GetMessage(musicVictory, victory_buffer);
- Game->GetMessage(musicBoss, boss_buffer);
- //Print filenames to allegro.log.
- if ( debug )
- {
- int loading[]="Attempting to load file: ";
- TraceNL();
- TraceS(loading);
- TraceNL();
- TraceS(boss_buffer);
- TraceNL();
- TraceS(loading);
- TraceNL();
- TraceS(victory_buffer);
- TraceNL();
- }
- int playingBoss[]="Playing Boss Music";
- int playingVictory[]="Playing Victory Music";
- int errLoading[]="Error loading track.";
- int LoopClockMethod = _Music_zh__GetDigit(loopBossMusic, 4);
- //Convert mins and seconds.
- int BossMusicDuration;
- if ( LoopClockMethod == 0 )
- {
- BossMusicDuration = MusicFrames(loopBossMusic); //Convert loopBossMusic into time.
- }
- if ( LoopClockMethod > 0 )
- {
- BossMusicDuration = _Music_zh__GetPartialArg(loopBossMusic,3,8); //Use the full value of loopBossMusic as frame in int.
- }
- int VictoryClockMethod = _Music_zh__GetDigit(vict_dur, 4);
- int dur;
- if ( VictoryClockMethod == 0 )
- {
- dur = MusicFrames(vict_dur); //Convert victory music into frames.
- }
- if ( VictoryClockMethod > 0 )
- {
- dur = _Music_zh__GetPartialArg(vict_dur,3,8); //Use the full value of loopBossMusic as frame in int.
- }
- for ( q = 0; q < 256; q++ ) { if ( boss_buffer[q] == ' ' ) boss_buffer[q] = 0; } //kill the space.
- for ( q = 0; q < 256; q++ ) { if ( victory_buffer[q] == ' ' ) victory_buffer[q] = 0; } //kill the space.
- bool playing = false;
- Waitframes(6); //Wait for enemies to spawn. //Moved up here in 1.3.4
- while(true)
- {
- //Waitframes(5); 1.3.4
- dat = Game->GetScreenD(curScreen,reg);
- //Waitframes(6); //Wait for enemies to spawn. 1.3.4
- //Set Screen->D[reg] = 1 if the enemy is dead.
- if ( enem == -1 && !Screen->NumNPCs() )
- {
- Game->SetScreenD(curScreen,reg,1);
- }
- if ( enem == 0 )
- {
- //Should we do anything special?
- //A zero value is intended to be used if we don't want the FFC to set Screen->D to 1.
- //-1 if we do it based on all enemies being dead.
- //A positive value trips it if there are no enemies of that ID on the screen.
- }
- if ( enem > 0 && !NumNPCsOf(enem) )
- {
- Game->SetScreenD(curScreen,reg,1);
- }
- dat = Game->GetScreenD(curScreen,reg);
- if ( dat == 0 && loopBossMusic == 0 && !playing )
- {
- Game->PlayEnhancedMusic(boss_buffer, trkBoss);
- if ( ! Game->PlayEnhancedMusic(boss_buffer, trkBoss) )
- {
- if ( midiNumber > 0 )
- {
- Game->PlayMIDI(midiNumber); //Play MIDI if enhanced music is not available.
- }
- else
- {
- Game->PlayMIDI(DEFAULT_BOSS_MUSIC); //Play default music if midiNumber is set to '0'.
- }
- }
- playing = true;
- }
- if ( dat == 0 && loopBossMusic > 0 )
- {
- //set up music loop
- for ( int q = BossMusicDuration; q >=0; --q )
- {
- if ( q == BossMusicDuration && dat == 0 )
- {
- Game->PlayEnhancedMusic(boss_buffer, trkBoss);
- if ( ! Game->PlayEnhancedMusic(boss_buffer, trkBoss) )
- {
- Game->PlayMIDI(midiNumber); //Play MIDI if enhanced music is not available.
- }
- }
- if ( enem == -1 && !Screen->NumNPCs() )
- {
- Game->SetScreenD(curScreen,reg,1);
- }
- if ( enem == 0 )
- {
- //Should we do anything special?
- //A zero value is intended to be used if we don;t want the FFC to set Screen->D to 1.
- //-1 if we do it based on all enemies being dead.
- //A positive value trips it if there are no enemies of that ID on the screen.
- }
- if ( enem > 0 && !NumNPCsOf(enem) )
- {
- Game->SetScreenD(curScreen,reg,1);
- }
- dat = Game->GetScreenD(curScreen,reg);
- if ( dat > 0 )
- {
- break;
- }
- Waitframe();
- }
- }
- if ( dat == 0 && loopBossMusic == 0 && !playing )
- {
- Game->PlayEnhancedMusic(boss_buffer, trkBoss);
- if ( ! Game->PlayEnhancedMusic(boss_buffer, trkBoss) )
- {
- if ( midiNumber > 0 )
- {
- Game->PlayMIDI(midiNumber); //Play MIDI if enhanced music is not available.
- }
- else
- {
- Game->PlayMIDI(DEFAULT_BOSS_MUSIC); //Plays default if not specified.
- }
- }
- playing = true;
- }
- dat = Game->GetScreenD(curScreen,reg);
- if ( dat > 0 )
- {
- if ( dur > 0 )
- {
- Game->PlayEnhancedMusic(victory_buffer, trkVictory);
- if ( ! Game->PlayEnhancedMusic(victory_buffer, trkVictory) )
- {
- if ( victoryMIDI > 0 )
- {
- Game->PlayMIDI(victoryMIDI);
- }
- else
- {
- Game->PlayMIDI(MIDI_DEFEATBOSS); //Plays default if Victory MIDI not specified.
- }
- }
- for ( int q = 0; q <= dur; ++q )
- {
- Waitframe(); //Pause for duration of victory music.
- }
- }
- Game->PlayEnhancedMusic(dmapMusicBuffer, dmapTrack);
- if ( ! Game->PlayEnhancedMusic(dmapMusicBuffer, dmapTrack) )
- {
- Game->PlayMIDI(stdMIDI);
- }
- Quit();
- }
- Waitframe();
- }
- }
- }
- // D0: MIDI number to default to for this boss, if no enhanced music is available.
- // Split argument, high and low at decimal point:
- // #####.xxxx -> Backup MIDI file to play if enhanced BOSS music is not available.
- // xxxxx.#### -> Backup MIDI file to play if enhanced VICTORY music is not available.
- // D1: Screen->D reg to set/check.
- // D2: Set to a value of '1' or higher, to use durations.
- // D3: Sets file type for both enhanced music tracks. Split argument, high and low at decimal point:
- // xxx##.xxxx -> Type for Boss Music file
- // xxxxx.xx## -> Type for Victory Music file
- // D4: The file number, and track number, for Boss Music. Split arg, high and low at decimal point:
- // #####.xxxx -> The file number.
- // xxxxx.#### -> The track number to play.
- // D5: The file number, and track number, for Victory Music. Split arg, high and low at decimal point:
- // #####.xxxx -> The file number.
- // xxxxx.#### -> The track number to play.
- // D6: The point in the track to pause, then loop.
- //
- // If set to 0, the track with loop only when it ends.
- // If set to greater than 0, the track will loop befor eit ends, as follows:
- // To loop by setting minutes, and seconds, set up minutes as the integer portion of the arg, and seconds as the decimal portion:
- // e.g. 00005.0260 is 5 mins, 26 seconds.
- // This works to a fineness of 1/10 second, so 00010.0136 is 10 minutes, 13.6 seconds.
- // If you wish to specify the loop in frames, set the ten-thousands place to '1', and the rest of the value to the number of frames.
- // e.g. 10526.1023 = 5,261,023 frames.
- // e.g. 10001.3591 = 13,591 frames.
- //
- // D7: This value instructs the FFC to set Screen->D[reg] = 1 when enemies are dead.
- // #####.xxxx -> A value of zero here, instructs the FFC not to change the Screen->D[reg] value. Leave this at zero, if the enemy does this.
- // Otherwise, set this to -1 (negative one) if you want the Victory music to play when all screen NPCs are dead...or...
- // a positive value matching an enemy ID that is on the screen, if you want to play the Victory music when all enemies with that ID are dead.
- // xxxxx.#### -> Set to '1' or higher to enable debugging reports to allegro.log.
- //
- //Version 0.44 (Numbered Files)
- ffc script BossMusicEnhanced_old
- {
- void run(int midiNumber_victoryMidiNumber, int reg, int victoryDur, float musicType_musicTypeVictory, float musicBoss_trkBoss, float musicVictory_trkVictory, float loopBossMusic, int enem_debug)
- {
- int curScreen = Game->GetCurScreen();
- int curDMAP = Game->GetCurDMap();
- int curDmap = Game->GetCurDMap();
- int dat = Game->GetScreenD(curScreen,reg);
- int stdMIDI = Game->DMapMIDI[curDMAP];
- int enem = _Music_zh__GetHighArgument(enem_debug);
- int debug= _Music_zh__GetLowArgument(enem_debug);
- int dmapMusicBuffer[512]=" ";
- Game->GetDMapMusicFilename(curDMAP, dmapMusicBuffer);
- int midiNumber = _Music_zh__GetHighArgument(midiNumber_victoryMidiNumber); //#####.xxxx
- int victoryMIDI = _Music_zh__GetLowArgument(midiNumber_victoryMidiNumber); //xxxxx.####
- int musicType = _Music_zh__GetHighArgument(musicType_musicTypeVictory); //xxx##.xxxx
- int musicType_Victory = _Music_zh__GetLowArgument(musicType_musicTypeVictory); //xxxxx.xx##
- int musicBoss = _Music_zh__GetHighArgument(musicBoss_trkBoss); //#####.xxxx
- int trkBoss = _Music_zh__GetLowArgument(musicBoss_trkBoss); //xxxxx.####
- int musicVictory = _Music_zh__GetHighArgument(musicVictory_trkVictory); //#####.xxxx
- int trkVictory = _Music_zh__GetLowArgument(musicVictory_trkVictory); //xxxxx.####
- int dmapTrack = Game->GetDMapMusicTrack(curDMAP);
- int mp3[]=".mp3";
- int vgm[]=".vgm";
- int nsf[]=".nsf";
- int ogg[]=".ogg";
- int s3m[]=".s3m";
- int mod[]=".mod";
- int spc[]=".spc";
- int gym[]=".gym";
- int gbs[]=".gbs";
- int it_format[]=".it";
- int xm[]=".xm";
- int boss_buffer[7]=" "; //two-digit number, plus four-digit extension, plus NULL.
- int victory_buffer[7]=" "; //Buffer for Victory Music Filename.
- int strBoss[2]=" "; //The two digit value of musicBoss arg.
- int strVictory[2]=" "; //The two digit value of musicVictory is stored here.
- //int bossMusic[]=" "; //Must read value from enhBoss, append .mp3 to it, and
- ///Set up Boss Music Filename String
- itoa(strBoss, musicBoss); //Copy the value of arg musicBoss into string strBoss.
- strncpy(boss_buffer, strBoss, 2); //Copy filename (two-digit number) to buffer.
- if ( musicType == 0 ) strcat(boss_buffer, mp3); //Append datatype to buffer (MP3)
- else if ( musicType == 1 ) strcat(boss_buffer, vgm); //Append datatype to buffer ( Video Game Music format)
- else if ( musicType == 2 ) strcat(boss_buffer, nsf); //Append datatype to buffer ( NES Sound File )
- else if ( musicType == 3 ) strcat(boss_buffer, ogg); //Append datatype to buffer ( The Xiph.org open music format )
- else if ( musicType == 4 ) strcat(boss_buffer, s3m); //Append datatype to buffer ( ScreamTracker 3 module file )
- else if ( musicType == 5 ) strcat(boss_buffer, mod); //Append datatype to buffer ( Tracker Module file )
- else if ( musicType == 6 ) strcat(boss_buffer, spc); //Append datatype to buffer ( Super NES / SuFami soound file )
- else if ( musicType == 7 ) strcat(boss_buffer, gym); //Append datatype to buffer ( Genesis / Megadrive sound file )
- else if ( musicType == 8 ) strcat(boss_buffer, gbs); //Append datatype to buffer ( Gameboy sound file )
- else if ( musicType == 9 ) strcat(boss_buffer, it_format); //Append datatype to buffer ( Impulse Tracker audio file )
- else if ( musicType == 10 ) strcat(boss_buffer, xm); //Append datatype to buffer ( Triton FastTracker 2 'Extended Module' format }
- ///Other formats.
- //Set up Victory Music Filename String
- itoa(strVictory, musicVictory); //Copy the value of arg musicVictory into string strVictory.
- strncpy(victory_buffer, strVictory, 2); //Copy filename (two-digit number) to buffer.
- if ( musicType_Victory == 0 ) strcat(victory_buffer, mp3); //Append datatype to buffer (MP3)
- else if ( musicType_Victory == 1 ) strcat(victory_buffer, vgm); //Append datatype to buffer ( Video Game Music format)
- else if ( musicType_Victory == 2 ) strcat(victory_buffer, nsf); //Append datatype to buffer ( NES Sound File )
- else if ( musicType_Victory == 3 ) strcat(victory_buffer, ogg); //Append datatype to buffer ( The Xiph.org open music format )
- else if ( musicType_Victory == 4 ) strcat(victory_buffer, s3m); //Append datatype to buffer ( ScreamTracker 3 module file )
- else if ( musicType_Victory == 5 ) strcat(victory_buffer, mod); //Append datatype to buffer ( Tracker Module file )
- else if ( musicType_Victory == 6 ) strcat(victory_buffer, spc); //Append datatype to buffer ( Super NES / SuFami soound file )
- else if ( musicType_Victory == 7 ) strcat(victory_buffer, gym); //Append datatype to buffer ( Genesis / Megadrive sound file )
- else if ( musicType_Victory == 8 ) strcat(victory_buffer, gbs); //Append datatype to buffer ( Gameboy sound file )
- else if ( musicType_Victory == 9 ) strcat(victory_buffer, it_format); //Append datatype to buffer ( Impulse Tracker audio file )
- else if ( musicType_Victory == 10 ) strcat(victory_buffer, xm); //Append datatype to buffer ( Triton FastTracker 2 'Extended Module' format }
- ///Other formats.
- //Print filenames to allegro.log.
- if ( debug )
- {
- int loading[]="Attempting to load file: ";
- TraceNL();
- TraceS(loading);
- TraceNL();
- TraceS(boss_buffer);
- TraceNL();
- TraceS(loading);
- TraceNL();
- TraceS(victory_buffer);
- TraceNL();
- }
- int playingBoss[]="Playing Boss Music";
- int playingVictory[]="Playing Victory Music";
- int errLoading[]="Error loading track.";
- int LoopClockMethod = _Music_zh__GetDigit(loopBossMusic, 4);
- //Convert mins and seconds.
- int BossMusicDuration;
- if ( LoopClockMethod == 0 )
- {
- BossMusicDuration = MusicFrames(loopBossMusic); //Convert loopBossMusic into time.
- }
- if ( LoopClockMethod > 0 )
- {
- BossMusicDuration = _Music_zh__GetPartialArg(loopBossMusic,3,8); //Use the full value of loopBossMusic as frame in int.
- }
- int VictoryDuration;
- int VictoryDurMethod = _Music_zh__GetDigit(victoryDur, 4);
- if ( VictoryDurMethod == 0 )
- {
- VictoryDuration = MusicFrames(victoryDur); //Convert loopBossMusic into time.
- }
- if ( VictoryDurMethod > 0 )
- {
- VictoryDuration = _Music_zh__GetPartialArg(victoryDur,3,8); //Use the full value of loopBossMusic as frame in int.
- }
- bool playing = false;
- Waitframes(6); //Wait for enemies to spawn. //Moved up here in 1.3.4
- while(true)
- {
- dat = Game->GetScreenD(curScreen,reg);
- //Waitframes(6); //Wait for enemies to spawn. 1.3.4
- //Set Screen->D[reg] = 1 if the enemy is dead.
- if ( enem == -1 && !Screen->NumNPCs() )
- {
- Game->SetScreenD(curScreen,reg,1);
- }
- if ( enem == 0 )
- {
- //Should we do anything special?
- //A zero value is intended to be used if we don;t want the FFC to set Screen->D to 1.
- //-1 if we do it based on all enemies being dead.
- //A positive value trips it if there are no enemies of that ID on the screen.
- }
- if ( enem > 0 && !NumNPCsOf(enem) )
- {
- Game->SetScreenD(curScreen,reg,1);
- }
- dat = Game->GetScreenD(curScreen,reg);
- if ( dat == 0 && loopBossMusic == 0 && !playing )
- {
- Game->PlayEnhancedMusic(boss_buffer, trkBoss);
- if ( ! Game->PlayEnhancedMusic(boss_buffer, trkBoss) )
- {
- if ( midiNumber > 0 )
- {
- Game->PlayMIDI(midiNumber); //Play MIDI if enhanced music is not available.
- }
- else
- {
- Game->PlayMIDI(DEFAULT_BOSS_MUSIC); //Play default if not assigned.
- }
- }
- playing = true;
- }
- if ( dat == 0 && loopBossMusic > 0 )
- {
- //set up music loop
- for ( int q = BossMusicDuration; q >=0; q-- ){
- if ( q == BossMusicDuration && dat == 0 )
- {
- Game->PlayEnhancedMusic(boss_buffer, trkBoss);
- if ( ! Game->PlayEnhancedMusic(boss_buffer, trkBoss) )
- {
- if ( midiNumber > 0 )
- {
- Game->PlayMIDI(midiNumber); //Play MIDI if enhanced music is not available.
- }
- else
- {
- Game->PlayMIDI(DEFAULT_BOSS_MUSIC); //Play default if not assigned.
- }
- }
- }
- if ( enem == -1 && !Screen->NumNPCs() )
- {
- Game->SetScreenD(curScreen,reg,1);
- }
- if ( enem == 0 )
- {
- //Should we do anything special?
- //A zero value is intended to be used if we don;t want the FFC to set Screen->D to 1.
- //-1 if we do it based on all enemies being dead.
- //A positive value trips it if there are no enemies of that ID on the screen.
- }
- if ( enem > 0 && !NumNPCsOf(enem) )
- {
- Game->SetScreenD(curScreen,reg,1);
- }
- dat = Game->GetScreenD(curScreen,reg);
- if ( dat > 0 )
- {
- break;
- }
- Waitframe();
- }
- }
- if ( dat == 0 && loopBossMusic == 0 && !playing )
- {
- Game->PlayEnhancedMusic(boss_buffer, trkBoss);
- if ( ! Game->PlayEnhancedMusic(boss_buffer, trkBoss) )
- {
- if ( midiNumber > 0 )
- {
- Game->PlayMIDI(midiNumber); //Play MIDI if enhanced music is not available.
- }
- else
- {
- Game->PlayMIDI(DEFAULT_BOSS_MUSIC); //Play default if not assigned.
- }
- }
- playing = true;
- }
- dat = Game->GetScreenD(curScreen,reg);
- if ( dat > 0 )
- {
- if ( VictoryDuration > 0 )
- {
- Game->PlayEnhancedMusic(victory_buffer, trkVictory);
- if ( ! Game->PlayEnhancedMusic(victory_buffer, trkVictory) )
- {
- if ( victoryMIDI > 0 )
- {
- Game->PlayMIDI(victoryMIDI);
- }
- else
- {
- Game->PlayMIDI(MIDI_DEFEATBOSS);
- }
- }
- for ( int q = 0; q <= VictoryDuration; q++ )
- {
- Waitframe(); //Pause for duration of victory music.
- }
- }
- Game->PlayEnhancedMusic(dmapMusicBuffer, dmapTrack);
- if ( ! Game->PlayEnhancedMusic(dmapMusicBuffer, dmapTrack) )
- {
- Game->PlayMIDI(stdMIDI);
- }
- Quit();
- }
- Waitframe();
- }
- }
- }
- /////////////////
- /// FUNCTIONS ///
- /////////////////
- //Pass a float to either of these, to convert raw float into mins and seconds as:
- // #####.xxxx = # mins x seconds. Example:
- // 00003.0050 = 3 mins, 5 seconds.
- // 00001.0012 = 1 minute, 5.2 seconds.
- //Timers are functional to a total clock of 3579 seconds (59 mins, 39 seconds).
- int MusicSeconds(float seconds)
- {
- int music_seconds = _Music_zh__GetLowArgument(seconds);
- return music_seconds * 6;
- }
- int MusicMinutes(float mins)
- {
- int music_minutes = _Music_zh__GetHighArgument(mins);
- return music_minutes * 360;
- }
- //Returns total time in frames, so that ZC understands it.
- int MusicFrames(float val)
- {
- int mins = MusicMinutes(val);
- int seconds = MusicSeconds(val);
- return mins+seconds;
- }
- int _Music_zh__GetRemainderAsInt(int v)
- {
- int r = (v - (v << 0)) * 10000;
- return r;
- }
- // This function breaks up the value of an argument into individual digits. It is combined with the function GetDigit below.
- int _Music_zh__GetDigit(int n, int place)
- {
- //GetDigit and related functions by Gleeok
- place = Clamp(place, -4, 4);
- if(place < 0){
- n = _Music_zh__GetRemainderAsInt(n);
- place += 4;
- }
- int r = ((n / Pow(10, place)) % 10) << 0;
- return r;
- }
- int _Music_zh__GetHighArgument(int arg)
- {
- return arg >> 0;
- }
- int _Music_zh__GetLowArgument(int arg)
- {
- return (arg - (arg >> 0)) * 10000;
- }
- int _Music_zh__GetPartialArg(int arg, int place, int num)
- {
- place = Clamp(place, -4, 4);
- int r;
- int adj = 1;
- for(int i = num-1; i > -1; i--)
- {
- if(place - i < -4) continue;
- r += _Music_zh__GetDigit(arg, place - i) * adj;
- adj *= 10;
- }
- return r;
- }
- // Plays enhanced music file by reading the string 'str_id' from Quest->Strings, at a specified track 'track_id'.
- // If track_id is positive, it uses this track.
- // If track_id is negative, it uses the message string equal to the inverse value (so -20 is string ID 20)
- // to set the track ID.
- // Returns true if playing, false otherwise.
- bool PlayEnhMusicFile(int str_id, int track_id)
- {
- int musicBuffer[256]=" ";
- int track_buffer[256]=" ";
- int q; int trk;
- Game->GetMessage(str_id, musicBuffer);
- for ( q = 0; q < 256; ++q ) { if ( musicBuffer[q] == ' ' ) musicBuffer[q] = 0; } //Kill GetMessage trailing spaces.
- if ( track_id < 0 )
- {
- Game->GetMessage((track_id * -1), track_buffer);
- for ( q = 0; q < 256; ++q )
- {
- if ( track_buffer[q] == ' ' ) track_buffer[q] = 0;
- } //Kill GetMessage trailing spaces.
- trk = atoi(track_buffer);
- }
- else trk = track_id;
- //Kill GetMessage trailing spaces.
- bool play = Game->PlayEnhancedMusic(musicBuffer, trk);
- return ( play );
- }
- int Legacy_PlayEnhMusicFile(int str_id, int track_id) { if ( PlayEnhMusicFile(str_id, track_id) ) return 1; return 0; }
- ffc script music_zh_spawnnpc
- {
- void run(int nid)
- {
- int pos;
- for ( int q = 0; q < 176; q++ )
- {
- if ( Screen->ComboF[q] == 37 ) pos = q;
- }
- while(1){
- if ( Collision(this) )
- {
- npc n = Screen->CreateNPC(nid);
- n->X = ComboX(pos); n->Y = ComboY(pos);
- Quit();
- }
- Waitframe();
- }
- }
- }
- void WandSound(int sound)
- {
- int itmA = GetEquipmentA();
- int itmB = GetEquipmentB();
- itemdata ida = Game->LoadItemData(itmA);
- itemdata idb = Game->LoadItemData(itmB);
- if ( ( ida->Family == IC_WAND && Link->PressA ) || ( idb->Family == IC_WAND && Link->PressB ) )
- {
- if ( !NumLWeaponsOf(LW_WAND) ) { Game->PlaySound(sound); }
- }
- }
- global script Music_ZH_Global_Active
- {
- void run(){
- while(true){
- WandSound(30);
- Waitdraw();
- Waitframe();
- }
- }
- }
- ffc script fade
- {
- void run(int warptile)
- {
- bool waiting = true;
- while(waiting) { Waitframe(); }
- this->Data = warptile; this->X = Link->X; this->Y = Link->Y;
- }
- }
- ffc script Hoffs_Message_Script
- {
- void run(int string, int delay, int no_return, int string2, int toggle, int screen_var, int item_id)
- {
- //This variable is used to check if you have entered the screen before
- int screen_check = 1;
- //If you have chosen to use a delay(more then 0)
- if (delay > 0)
- {
- //Wait for "delay" amount of frames. 60 frames = 1 second
- Waitframes(delay);
- }
- //If you want to show a string depending on if you have a certain item or not
- if ((item_id > 0))
- {
- //If you do not have a certain item
- if (!Link->Item[item_id])
- {
- //Show the first string on the screen
- Screen->Message(string);
- }
- //If you do have that item
- else if(Link->Item[item_id])
- {
- //Show the second string on the screen
- Screen->Message(string2);
- }
- }
- else
- {
- //This runs the first time you enter the screen
- if (Screen->D[screen_var] != screen_check)
- {
- //Show the first string on the screen
- Screen->Message(string);
- //If you have chosen to use a second string
- if (string2 > 0)
- {
- //Set Screen->D[screen_var] to be equal to screen_check(1)
- Screen->D[screen_var] = screen_check;
- }
- }
- //This runs if you have chosen to use a second string,
- //and you have already visited the screen once before
- else
- {
- //Show the second string on the screen
- Screen->Message(string2);
- //If you want to toggle between string1 and string2 every time you enter the screen
- if (toggle > 0)
- {
- //Now Zelda Classic will think that you have never visited the screen before :)
- //(Seriously, this just changes the Screen->D[screen_var] variable to the default value)
- Screen->D[screen_var] = 0;
- }
- }
- //This only runs if you have set D2(no_return) to 1 or more
- if (no_return > 0)
- {
- //Set Screen->D[screen_var] to be equal to screen_check(1)
- Screen->D[screen_var] = screen_check;
- }
- }
- }
- }
- const int COMPASS_BEEP = 7; //Set this to the SFX id you want to hear when you have the compass,
- //Instructions:
- //1.- Compile and add this to your ZQuest buffer.
- //2.- Add an FFC with this script attached to the screen where you want to hear the compass beep.
- //3.- Let the script do the rest.
- //How does it work:
- //The script checks if ANY of the following has been done:
- //a) Item or Special Item has been picked up.
- //b) Any type of chest has been opened.
- //c) If NOTHING of the above has been done, the script runs. Otherwise, no SFX is heard.
- ffc script CompassBeep{
- void run(){
- if(!Screen->State[ST_ITEM] &&
- !Screen->State[ST_CHEST] &&
- !Screen->State[ST_LOCKEDCHEST] &&
- !Screen->State[ST_BOSSCHEST] &&
- !Screen->State[ST_SPECIALITEM] && (Game->LItems[Game->GetCurLevel()] & LI_COMPASS)){
- Game->PlaySound(COMPASS_BEEP);
- }
- }
- }
- ffc script SpinAttackCheck{
- void run(int sfx){
- if ( Screen->State[ST_SECRET] )
- Quit();
- bool spin;
- while(true){
- if ( Link->Action == LA_SPINNING )
- spin = true;
- if ( !Link->Action == LA_SPINNING && spin ) {
- if ( sfx == 0 )
- Game->PlaySound(27);
- if ( sfx > 0 )
- Game->PlaySound(sfx);
- Screen->TriggerSecrets();
- Screen->State[ST_SECRET] = true;
- Quit();
- }
- Waitframe();
- }
- }
- }
- const int SFX_SWITCH_PRESS = 67; //SFX when a switch is pressed
- const int SFX_SWITCH_RELEASE = 67; //SFX when a switch is released
- const int SFX_SWITCH_ERROR = 68; //SFX when the wrong switch is pressed
- int Switch_Pressed(int x, int y){
- int xOff = 0;
- int yOff = 4;
- int xDist = 8;
- int yDist = 8;
- if(Abs(Link->X+xOff-x)<=xDist&&Abs(Link->Y+yOff-y)<=yDist)
- return 1;
- if(Screen->MovingBlockX>-1){
- if(Abs(Screen->MovingBlockX-x)<=8&&Abs(Screen->MovingBlockY-y)<=8)
- return 1;
- }
- if(Screen->isSolid(x+4, y+4)||
- Screen->isSolid(x+12, y+4)||
- Screen->isSolid(x+4, y+12)||
- Screen->isSolid(x+12, y+12)){
- return 2;
- }
- return 0;
- }
- ffc script Switch_Secret{
- void run(int perm, int id, int sfx){
- int d;
- int db;
- if(id>0){
- d = Floor((id-1)/16);
- db = 1<<((id-1)%16);
- }
- if(perm){
- if(id>0){
- if(Screen->D[d]&db){
- this->Data++;
- Screen->TriggerSecrets();
- Quit();
- }
- }
- else if(Screen->State[ST_SECRET]){
- this->Data++;
- Quit();
- }
- }
- while(!Switch_Pressed(this->X, this->Y)){
- Waitframe();
- }
- this->Data++;
- Screen->TriggerSecrets();
- Game->PlaySound(SFX_SWITCH_PRESS);
- if(sfx==0)
- Game->PlaySound(SFX_SECRET);
- else if(sfx>0)
- Game->PlaySound(sfx);
- if(perm){
- if(id>0)
- Screen->D[d]|=db;
- else
- Screen->State[ST_SECRET] = true;
- }
- }
- }
- ffc script Switch_Remote{
- void run(int pressure, int id, int flag, int sfx){
- int data = this->Data;
- int i; int j; int k;
- int d;
- int db;
- if(id>0){
- d = Floor((id-1)/16);
- db = 1<<((id-1)%16);
- }
- int comboD[176];
- for(i=0; i<176; i++){
- if(Screen->ComboF[i]==flag){
- comboD[i] = Screen->ComboD[i];
- Screen->ComboF[i] = 0;
- }
- }
- if(id>0){
- if(Screen->D[d]&db){
- this->Data = data+1;
- for(i=0; i<176; i++){
- if(comboD[i]>0){
- Screen->ComboD[i] = comboD[i]+1;
- }
- }
- Quit();
- }
- }
- if(pressure){
- while(true){
- while(!Switch_Pressed(this->X, this->Y)){
- Waitframe();
- }
- this->Data = data+1;
- Game->PlaySound(SFX_SWITCH_PRESS);
- for(i=0; i<176; i++){
- if(comboD[i]>0){
- Screen->ComboD[i] = comboD[i]+1;
- }
- }
- while(Switch_Pressed(this->X, this->Y)){
- Waitframe();
- }
- this->Data = data;
- Game->PlaySound(SFX_SWITCH_RELEASE);
- for(i=0; i<176; i++){
- if(comboD[i]>0){
- Screen->ComboD[i] = comboD[i];
- }
- }
- }
- }
- else{
- while(!Switch_Pressed(this->X, this->Y)){
- Waitframe();
- }
- this->Data = data+1;
- Game->PlaySound(SFX_SWITCH_PRESS);
- if(sfx>0)
- Game->PlaySound(sfx);
- else
- Game->PlaySound(SFX_SECRET);
- for(i=0; i<176; i++){
- if(comboD[i]>0){
- Screen->ComboD[i] = comboD[i]+1;
- }
- }
- if(id>0){
- Screen->D[d] |= db;
- }
- }
- }
- }
- ffc script Switch_HitAll{
- void run(int switchCmb, int pressure, int perm, int id, int flag, int sfx, int switchID){
- int i; int j; int k;
- int d;
- int db;
- if(flag==0)
- id = 0;
- int comboD[176];
- if(id>0){
- d = Floor((id-1)/16);
- db = 1<<((id-1)%16);
- for(i=0; i<176; i++){
- if(Screen->ComboF[i]==flag){
- comboD[i] = Screen->ComboD[i];
- Screen->ComboF[i] = 0;
- }
- }
- }
- int switches[34];
- int switchD[34];
- int switchDB[34];
- switchD[0] = switchID;
- bool switchesPressed[34];
- k = SizeOfArray(switches)-2;
- for(i=0; i<176&&switches[0]<k; i++){
- if(Screen->ComboD[i]==switchCmb){
- j = 2+switches[0];
- switches[j] = i;
- if(!pressure&&switchID>0){
- switchD[j] = Floor((switchID+switches[0]-1)/16);
- switchDB[j] = 1<<((switchID+switches[0]-1)%16);
- if(Screen->D[switchD[j]]&switchDB[j]){
- switchesPressed[j] = true;
- Screen->ComboD[i] = switchCmb+1;
- switches[1]++;
- }
- }
- switches[0]++;
- }
- }
- if(perm){
- if(id>0){
- if(Screen->D[d]&db){
- for(i=2; i<switches[0]+2; i++){
- Screen->ComboD[switches[i]] = switchCmb+1;
- switchesPressed[i] = true;
- }
- for(i=0; i<176; i++){
- if(comboD[i]>0){
- Screen->ComboD[i] = comboD[i]+1;
- }
- }
- while(true){
- Switches_Update(switches, switchD, switchDB, switchesPressed, switchCmb, false);
- Waitframe();
- }
- }
- }
- if(Screen->State[ST_SECRET]){
- for(i=2; i<switches[0]+2; i++){
- Screen->ComboD[switches[i]] = switchCmb+1;
- switchesPressed[i] = true;
- }
- while(true){
- Switches_Update(switches, switchD, switchDB, switchesPressed, switchCmb, false);
- Waitframe();
- }
- }
- }
- if(pressure){
- while(switches[1]<switches[0]){
- Switches_Update(switches, switchD, switchDB, switchesPressed, switchCmb, true);
- Waitframe();
- }
- if(id>0){
- if(sfx>0)
- Game->PlaySound(sfx);
- else
- Game->PlaySound(SFX_SECRET);
- for(i=0; i<176; i++){
- if(comboD[i]>0){
- Screen->ComboD[i] = comboD[i]+1;
- }
- }
- }
- else{
- if(sfx>0)
- Game->PlaySound(sfx);
- else
- Game->PlaySound(SFX_SECRET);
- Screen->TriggerSecrets();
- }
- if(perm){
- if(id>0)
- Screen->D[d] |= db;
- else
- Screen->State[ST_SECRET] = true;
- }
- }
- else{
- while(switches[1]<switches[0]){
- Switches_Update(switches, switchD, switchDB, switchesPressed, switchCmb, false);
- Waitframe();
- }
- if(id>0){
- if(sfx>0)
- Game->PlaySound(sfx);
- else
- Game->PlaySound(SFX_SECRET);
- for(i=0; i<176; i++){
- if(comboD[i]>0){
- Screen->ComboD[i] = comboD[i]+1;
- }
- }
- }
- else{
- if(sfx>0)
- Game->PlaySound(sfx);
- else
- Game->PlaySound(SFX_SECRET);
- Screen->TriggerSecrets();
- }
- if(perm){
- if(id>0)
- Screen->D[d] |= db;
- else
- Screen->State[ST_SECRET] = true;
- }
- }
- while(true){
- Switches_Update(switches, switchD, switchDB, switchesPressed, switchCmb, false);
- Waitframe();
- }
- }
- void Switches_Update(int switches, int switchD, int switchDB, bool switchesPressed, int switchCmb, bool pressure){
- if(pressure)
- switches[1] = 0;
- for(int i=0; i<switches[0]; i++){
- int j = i+2;
- int k = switches[j];
- int p = Switch_Pressed(ComboX(k), ComboY(k));
- if(p){
- if(p!=2)
- Screen->ComboD[k] = switchCmb+1;
- if(!switchesPressed[j]){
- Game->PlaySound(SFX_SWITCH_PRESS);
- if(switchD[0]>0){
- Screen->D[switchD[j]] |= switchDB[j];
- }
- switchesPressed[j] = true;
- if(!pressure)
- switches[1]++;
- }
- if(pressure)
- switches[1]++;
- }
- else{
- if(switchesPressed[j]){
- if(pressure){
- Game->PlaySound(SFX_SWITCH_RELEASE);
- Screen->ComboD[k] = switchCmb;
- switchesPressed[j] = false;
- }
- else{
- if(Screen->ComboD[k]!=switchCmb+1)
- Screen->ComboD[k] = switchCmb+1;
- }
- }
- }
- }
- }
- }
- ffc script Switch_Trap{
- void run(int enemyid, int count){
- while(!Switch_Pressed(this->X, this->Y)){
- Waitframe();
- }
- this->Data++;
- Game->PlaySound(SFX_SWITCH_PRESS);
- Game->PlaySound(SFX_SWITCH_ERROR);
- for(int i=0; i<count; i++){
- int pos = Switch_GetSpawnPos();
- npc n = CreateNPCAt(enemyid, ComboX(pos), ComboY(pos));
- Game->PlaySound(SFX_FALL);
- n->Z = 176;
- Waitframes(20);
- }
- }
- int Switch_GetSpawnPos(){
- int pos;
- bool invalid = true;
- int failSafe = 0;
- while(invalid&&failSafe<512){
- pos = Rand(176);
- if(Switch_ValidSpawn(pos))
- return pos;
- }
- for(int i=0; i<176; i++){
- pos = i;
- if(Switch_ValidSpawn(pos))
- return pos;
- }
- }
- bool Switch_ValidSpawn(int pos){
- int x = ComboX(pos);
- int y = ComboY(pos);
- if(Screen->isSolid(x+4, y+4)||
- Screen->isSolid(x+12, y+4)||
- Screen->isSolid(x+4, y+12)||
- Screen->isSolid(x+12, y+12)){
- return false;
- }
- if(ComboFI(pos, CF_NOENEMY)||ComboFI(pos, CF_NOGROUNDENEMY))
- return false;
- int ct = Screen->ComboT[pos];
- if(ct==CT_NOENEMY||ct==CT_NOGROUNDENEMY||ct==CT_NOJUMPZONE)
- return false;
- if(ct==CT_WATER||ct==CT_LADDERONLY||ct==CT_HOOKSHOTONLY||ct==CT_LADDERHOOKSHOT)
- return false;
- if(ct==CT_PIT||ct==CT_PITB||ct==CT_PITC||ct==CT_PITD||ct==CT_PITR)
- return false;
- return true;
- }
- }
- ffc script Switch_Sequential{
- void run(int flag, int perm, int sfx){
- int i; int j; int k;
- int switches[34];
- int switchCmb[34];
- int switchMisc[8];
- bool switchesPressed[34];
- k = SizeOfArray(switches)-2;
- for(i=0; i<176&&switches[0]<k; i++){
- if(Screen->ComboF[i]==flag){
- j = 2+switches[0];
- switches[j] = i;
- switchCmb[j] = Screen->ComboD[i];
- switches[0]++;
- }
- }
- int switchOrder[34];
- Switches_Organize(switches, switchOrder);
- if(perm&&Screen->State[ST_SECRET]){
- for(i=0; i<switches[0]; i++){
- switchesPressed[i+2] = true;
- }
- while(true){
- Switches_Update(switches, switchesPressed, switchOrder, switchCmb, switchMisc, false);
- Waitframe();
- }
- }
- while(switches[1]<switches[0]){
- Switches_Update(switches, switchesPressed, switchOrder, switchCmb, switchMisc, true);
- if(switchMisc[0]==1){
- switchMisc[0] = 0;
- for(i=0; i<30; i++){
- Switches_Update(switches, switchesPressed, switchOrder, switchCmb, switchMisc, false);
- Waitframe();
- }
- while(Switches_LinkOn(switches)){
- Switches_Update(switches, switchesPressed, switchOrder, switchCmb, switchMisc, false);
- Waitframe();
- }
- }
- Waitframe();
- }
- if(sfx>0)
- Game->PlaySound(sfx);
- else
- Game->PlaySound(SFX_SECRET);
- Screen->TriggerSecrets();
- if(perm)
- Screen->State[ST_SECRET] = true;
- for(i=0; i<switches[0]; i++){
- switchesPressed[i+2] = true;
- }
- while(true){
- Switches_Update(switches, switchesPressed, switchOrder, switchCmb, switchMisc, false);
- Waitframe();
- }
- }
- void Switches_Organize(int switches, int switchOrder){
- bool banned[34];
- for(int j=0; j<switches[0]; j++){
- int lowest = -1;
- int lowestIndex = -1;
- for(int i=0; i<switches[0]; i++){
- int c = Screen->ComboD[switches[i+2]];
- if(c!=-1&&!banned[i+2]){
- if(lowest==-1||c<lowest){
- lowest = c;
- lowestIndex = i+2;
- }
- }
- }
- switchOrder[j] = lowestIndex;
- banned[lowestIndex] = true;
- }
- }
- bool Switches_LinkOn(int switches){
- for(int i=0; i<switches[0]; i++){
- int j = i+2;
- int k = switches[j];
- int p = Switch_Pressed(ComboX(k), ComboY(k));
- if(p==1)
- return true;
- }
- return false;
- }
- void Switches_Update(int switches, bool switchesPressed, int switchOrder, int switchCmb, int switchMisc, bool canPress){
- bool reset;
- for(int i=0; i<switches[0]; i++){
- int j = i+2;
- int k = switches[j];
- int p = Switch_Pressed(ComboX(k), ComboY(k));
- if(!switchesPressed[j]){
- if(p!=2)
- Screen->ComboD[k] = switchCmb[j];
- if(p&&canPress){
- if(j==switchOrder[switches[1]]){
- switches[1]++;
- Game->PlaySound(SFX_SWITCH_PRESS);
- switchesPressed[j] = true;
- }
- else{
- switches[1] = 0;
- Game->PlaySound(SFX_SWITCH_ERROR);
- reset = true;
- }
- }
- }
- else{
- if(p!=2)
- Screen->ComboD[k] = switchCmb[j]+1;
- if(p==0&&canPress){
- Game->PlaySound(SFX_SWITCH_RELEASE);
- switchesPressed[j] = false;
- }
- }
- }
- if(reset){
- switchMisc[0] = 1;
- for(int i=0; i<switches[0]; i++){
- int j = i+2;
- int k = switches[j];
- int p = Switch_Pressed(ComboX(k), ComboY(k));
- switchesPressed[j] = false;
- }
- }
- }
- }
- // Edit the following constants according to your tileset.
- // All combos between and including these two values will be considered regular diggable combos.
- // The combo dug by the player will change, and there will be a chance for an item drop.
- const int DigComboStart=3266;
- const int DigComboEnd=3273;
- // The following combos are similarly diggable, but turn into a different kind of combo and
- // do not give item drops. You can use this to have secret stairs, for example.
- // Important: Make sure these combos directly follow the DigComboEnd one.
- const int DigSpecialStart=3274;
- const int DigSpecialEnd=3277;
- // A regular diggable combo will turn into this combo when you use the shovel on it.
- const int DugComboNormal=3278;
- // A special combo will turn into this combo when you use the shovel on it.
- // You can, for example, make it a tile warp, so the player can dig for secret entrances.
- // Set up the warps and the arrival points on your ZQuest screen as usual.
- const int DugComboSpecial=3279;
- // This is the sound to be played when you successfully dig.
- const int ShovelSound=4;
- // The sound to be played when you attempt to dig an undiggable combo.
- const int ShovelFail=51;
- // The secret sound to be played when you dig a special combo.
- const int SecretSound=25;
- 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;
- }
- }
- }
- }
- //D0: ID of the item
- //D1: Price of the item
- //D2: Message that plays when the item is bought
- //D3: Message that plays when you don't have enough rupees
- //D4: Input type 0=A 1=B 2=L 3=R
- ffc script SimpleShop{
- void run(int itemID, int price, int m, int n, int input){
- int loc = ComboAt(this->X,this->Y);
- while(true){
- while(!AgainstComboBase(loc) || !SelectPressInput(input)) Waitframe();
- SetInput(input,false);
- if(Game->Counter[CR_RUPEES] >= price){
- Game->DCounter[CR_RUPEES] -= price;
- item shpitm = CreateItemAt(itemID, Link->X, Link->Y);
- shpitm->Pickup = IP_HOLDUP;
- Screen->Message(m);
- }
- else{
- Screen->Message(n);
- }
- Waitframe();
- }
- }
- bool AgainstComboBase(int loc){
- return Link->Z == 0 && (Link->Dir == DIR_UP && Link->Y == ComboY(loc)+8 && Abs(Link->X-ComboX(loc)) < 8);
- }
- }
- ffc script Signpost{
- void run(int m,int input){
- int loc = ComboAt(this->X,this->Y);
- while(true){
- while(!AgainstComboBase(loc) || !SelectPressInput(input)) Waitframe();
- SetInput(input,false);
- Screen->Message(m);
- Waitframe();
- }
- }
- bool AgainstComboBase(int loc){
- return Link->Z == 0 && (Link->Dir == DIR_UP && Link->Y == ComboY(loc)+8 && Abs(Link->X-ComboX(loc)) < 8);
- }
- }
- ffc script ButtonDisabler
- {
- void run()
- {
- while(true)
- {
- Game->SkipF6 = true;
- Link->InputStart = false; Link->PressStart = false;
- Link->InputMap = false; Link->PressMap = false;
- NoAction();
- Waitframe();
- }
- }
- }
- //Instructions:
- //1. Make a new combo with inherent flag 16 (or any secret flag)
- //2. Set this FFC to the above combo
- //3. When secrets are triggered by blocks, this script will make it permanent
- ffc script blockPermSecrets{
- void run(){
- int thisCombo = this->Data;
- while(!Screen->State[ST_SECRET]){
- if(this->Data != thisCombo) Screen->State[ST_SECRET] = true;
- Waitframe();
- }
- }
- }
- screendata script ChangeEnemies
- {
- void run(int changeItem, int e1, int e2, int e3, int ne1, int ne2, int ne3)
- {
- unless(Hero->Item[changeItem]) Quit();
- for(int q = 0; q < 10; ++q)
- {
- if(Screen->Enemy[q] == e1)
- Screen->Enemy[q] = ne1;
- else if(Screen->Enemy[q] == e2)
- Screen->Enemy[q] = ne2;
- else if(Screen->Enemy[q] == e3)
- Screen->Enemy[q] = ne3;
- }
- }
- }
- ffc script NewScreenChanger
- {
- void run(int changeItem, int e1, int e2, int e3, int ne1, int ne2, int ne3)
- {
- unless(Hero->Item[changeItem]) Quit();
- for(int q = 0; q < 10; ++q)
- {
- if(Screen->Enemy[q] == e1)
- Screen->Enemy[q] = ne1;
- else if(Screen->Enemy[q] == e2)
- Screen->Enemy[q] = ne2;
- else if(Screen->Enemy[q] == e3)
- Screen->Enemy[q] = ne3;
- }
- }
- }
- const int SAGESSTONE_SOUND = 136; //Set this to the SFX id you want to hear when you have the compass,
- //Instructions:
- //1.- Compile and add this to your ZQuest buffer.
- //2.- Add an FFC with this script attached to the screen where you want to hear the compass beep.
- //3.- Let the script do the rest.
- //How does it work:
- //The script checks if ANY of the following has been done:
- //a) Item or Special Item has been picked up.
- //b) Any type of chest has been opened.
- //c) If NOTHING of the above has been done, the script runs. Otherwise, no SFX is heard.
- ffc script StonesOfSages{
- void run(){
- if(!Screen->State[ST_ITEM] &&
- !Screen->State[ST_CHEST] &&
- !Screen->State[ST_LOCKEDCHEST] &&
- !Screen->State[ST_BOSSCHEST] &&
- !Screen->State[ST_SPECIALITEM] && (Game->LItems[Game->GetCurLevel()] & LI_COMPASS)){
- Game->PlaySound(SAGESSTONE_SOUND);
- }
- }
- }
- screendata script ChangeEnemiesAndMidi
- {
- void run(int changeItem, int e1, int e2, int e3, int ne1, int ne2, int ne3, int midi)
- {
- unless(Hero->Item[changeItem]) Quit();
- for(int q = 0; q < 10; ++q)
- {
- if(Screen->Enemy[q] == e1)
- Screen->Enemy[q] = ne1;
- else if(Screen->Enemy[q] == e2)
- Screen->Enemy[q] = ne2;
- else if(Screen->Enemy[q] == e3)
- Screen->Enemy[q] = ne3;
- }
- unless(midi) return;
- if(midi == -1)
- {
- midi = Game->LoadDMapData(Game->GetCurDMap())->MIDI;
- }
- Audio->PlayMIDI(midi);
- }
- }
- item script FlareSwordItem{
- void run(int nothing, int firesprite){
- int name[] = "FlareSwordFFC";
- int args[8];
- args[0] = firesprite;
- RunFFCScript(Game->GetFFCScript(name), args);
- }
- }
- ffc script FlareSwordFFC
- {void run(int firesprite)
- {
- int SwordX;
- int SwordY;
- int PreviousSwordX;
- int PreviousSwordY;
- int SwordDmg;
- while(true){
- SwordX = -1000;
- SwordY = -1000;
- for (int i = Screen->NumLWeapons(); i > 0; i--) {
- lweapon wpn = Screen->LoadLWeapon(i);
- if ( wpn->ID == LW_SWORD ) {
- SwordX = wpn->X;
- SwordY = wpn->Y;
- SwordDmg = wpn->Damage;
- }
- }
- if ( SwordX == -1000 && SwordY == -1000 )
- Quit();
- if ( Link->Action != LA_CHARGING && Link->Action != LA_GOTHURTLAND && (SwordX != PreviousSwordX || SwordY != PreviousSwordY) ) {
- Game->PlaySound(13);
- lweapon wpn = CreateLWeaponAt(LW_FIRE, SwordX, SwordY);
- wpn->UseSprite(firesprite);
- wpn->Damage = SwordDmg;
- wpn->Step = 0;
- }
- PreviousSwordX = SwordX;
- PreviousSwordY = SwordY;
- Waitframe();
- }
- }
- }
- itemsprite script FlareSwordSprite
- {void run(int firesprite)
- {
- int SwordX;
- int SwordY;
- int PreviousSwordX;
- int PreviousSwordY;
- int SwordDmg;
- while(true){
- SwordX = -1000;
- SwordY = -1000;
- for (int i = Screen->NumLWeapons(); i > 0; i--) {
- lweapon wpn = Screen->LoadLWeapon(i);
- if ( wpn->ID == LW_SWORD ) {
- SwordX = wpn->X;
- SwordY = wpn->Y;
- SwordDmg = wpn->Damage;
- }
- }
- if ( SwordX == -1000 && SwordY == -1000 )
- Quit();
- if ( Link->Action != LA_CHARGING && Link->Action != LA_GOTHURTLAND && (SwordX != PreviousSwordX || SwordY != PreviousSwordY) ) {
- Game->PlaySound(13);
- lweapon wpn = CreateLWeaponAt(LW_FIRE, SwordX, SwordY);
- wpn->UseSprite(firesprite);
- wpn->Damage = SwordDmg;
- wpn->Step = 0;
- }
- PreviousSwordX = SwordX;
- PreviousSwordY = SwordY;
- Waitframe();
- }
- }
- }
- lweapon script FireRod
- {
- void run()
- {
- lweapon flame = Screen->CreateLWeapon(LW_FIRE);
- while(this->isValid())
- {
- flame->X = this->X;
- flame->Y = this->Y;
- flame->Dir = this->Dir;
- Waitframe();
- }
- }
- }
- lweapon script bombarrow
- {
- void run()
- {
- itemdata bomb; bool found; bool super; int x; int y; int pow;
- bomb = Game->LoadItemData(Link->ItemA);
- if ( bomb->Family == IC_BOMB ) found = true;
- if ( bomb->Family == IC_SBOMB ) { found = true; super = true; }
- if ( !found )
- {
- bomb = Game->LoadItemData(Link->ItemB);
- if ( bomb->Family == IC_BOMB ) { found = true; }
- if ( bomb->Family == IC_SBOMB ) { found = true; super = true; }
- }
- if ( !found ) Quit(); //quit if bombs not in a slot
- else
- {
- pow = bomb->Power;
- if ( super )
- {
- if ( !Game->Counter[CR_SBOMBS] ) Quit(); //quit if not enough bombs
- else --Game->Counter[CR_SBOMBS];
- }
- else
- {
- if ( !Game->Counter[CR_BOMBS] ) Quit(); //quit if not enough bombs
- else --Game->Counter[CR_BOMBS];
- }
- }
- while(this->isValid())
- {
- x = this->X; y = this->Y;
- if ( this->DeadState != WDS_ALIVE ) //When the arrow itself dies, make an explosion.
- {
- lweapon boom = Screen->CreateLWeapon( (( super ) ? LW_SBOMBBLAST : LW_BOMBBLAST ));
- boom->Damage = pow;
- boom->X = x;
- boom->Y = y;
- }
- Waitframe();
- }
- }
- }
- eweapon script dairaaxe
- {
- void run()
- {
- this->X = Clamp(this->X, 1, 255);
- this->Y = Clamp(this->Y, 1, 175);
- int timer = 22;
- while(this->isValid())
- {
- this->X = Clamp(this->X, 1, 255);
- this->Y = Clamp(this->Y, 1, 175);
- --timer;
- if ( timer < 1 ) { Remove(this); Quit(); }
- Waitframe();
- }
- }
- }
- const int RESET_NPC_LAYER_ON_ENTRY = 1; //This fix will replace all CMB_NPC_SOLID tiles with CMB_NPC_HIDDEN
- //when entering the screen. This should prevent problems with shared
- //layers. If you don't want this fix, set it to 0.
- const int NPCSCRIPT_ITEMCHECK_ONLY_UPDATES_ON_SCREEN_ENTRY = 1; //Set to 1 if you want itemcheck NPCs to only disappear
- //after you leave the screen.
- const int NPCSCRIPT_WAITS_UNTIL_SCRIPTS_FINISH = 1; //This will make the script wait until a called script
- //finishes before resuming, fixing issues where you talk
- //to the NPC a second time while you should be frozen
- const int LAYER_NPC = 1; //The layer NPCs use for solid combos
- const int CMB_NPC_HIDDEN = 0; //Non-solid combo used for hidden NPCs
- const int CMB_NPC_SOLID = 43; //Solid combo placed under visible NPCs
- const int LAYER_NPC_CANTALK = 4; //The layer used for the speech bubble
- const int CMB_NPC_CANTALK = 9059; //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
- ffc script NPCScript_Simple{
- void run(int String, int Script, int D0, int D1, int D2, int D3, int D4, int D5){
- //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;
- while(true){
- //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);
- if(Script>0){
- int Args[8] = {D0, D1, D2, D3, D4, D5};
- RunFFCScript(Script, Args);
- }
- }
- }
- //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){
- int Args[8] = {D0, D1, D2, D3, D4, D5};
- RunFFCScript(Script, Args);
- }
- }
- }
- //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){
- int Args[8] = {D0, D1, D2, D3, D4, D5};
- RunFFCScript(Script, Args);
- }
- }
- }
- //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){
- int Args[8] = {D0, D1, D2, D3, D4, D5};
- RunFFCScript(Script, Args);
- }
- }
- }
- Waitframe();
- }
- }
- }
- ffc script playsfx{
- void run(int s, int wait, int r){
- if (r == 0){
- Waitframes(wait);
- Game->PlaySound(s);
- }
- else{
- while(true){
- Waitframes(wait);
- Game->PlaySound(s);
- }
- }
- }
- }
- ffc script NPCScript{
- void run(int String, int ItemCheck, int Type, int Arg1, int Arg2, int NoSolid, int Script, int ScriptArg){
- //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();
- }
- //Shared Layer Fix
- if(RESET_NPC_LAYER_ON_ENTRY==1){
- if(Screen->LoadFFC(FindFFCRunning(this->Script))==this){
- for(int i=0; i<176; i++){
- if(GetLayerComboD(LAYER_NPC, i)==CMB_NPC_SOLID){
- SetLayerComboD(LAYER_NPC, i, CMB_NPC_HIDDEN);
- }
- }
- }
- }
- //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);
- }
- }
- }
- }
- bool canItemCheck = true;
- while(true){
- //Prevent checking items past the first frame if the rule is checked
- if(!NPCSCRIPT_ITEMCHECK_ONLY_UPDATES_ON_SCREEN_ENTRY)
- canItemCheck = true;
- //Removes NPCs if Link has the required item
- if(ItemCheck>0&&canItemCheck){
- 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();
- }
- }
- canItemCheck = false;
- //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);
- }
- }
- int dialogueBox1[] = "DialogueBranch_Simple";
- int dialogueBox2[] = "DialogueBranch_Advanced";
- int scrDB1 = Game->GetFFCScript(dialogueBox1);
- int scrDB2 = Game->GetFFCScript(dialogueBox2);
- bool noTalk;
- if(CountFFCsRunning(scrDB1)>0)
- noTalk = true;
- if(CountFFCsRunning(scrDB2)>0)
- noTalk = true;
- //Facing Up
- if(!noTalk&&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);
- if(Script>0){
- int args[8] = {ScriptArg};
- int i = RunFFCScript(Script, args);
- if(NPCSCRIPT_WAITS_UNTIL_SCRIPTS_FINISH){
- ffc f = Screen->LoadFFC(i);
- while(f->Script==Script){
- Waitframe();
- }
- }
- }
- }
- }
- //Facing Down
- else if(!noTalk&&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){
- int args[8] = {ScriptArg};
- int i = RunFFCScript(Script, args);
- if(NPCSCRIPT_WAITS_UNTIL_SCRIPTS_FINISH){
- ffc f = Screen->LoadFFC(i);
- while(f->Script==Script){
- Waitframe();
- }
- }
- }
- }
- }
- //Facing Left
- else if(!noTalk&&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){
- int args[8] = {ScriptArg};
- int i = RunFFCScript(Script, args);
- if(NPCSCRIPT_WAITS_UNTIL_SCRIPTS_FINISH){
- ffc f = Screen->LoadFFC(i);
- while(f->Script==Script){
- Waitframe();
- }
- }
- }
- }
- }
- //Facing Right
- else if(!noTalk&&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){
- int args[8] = {ScriptArg};
- int i = RunFFCScript(Script, args);
- if(NPCSCRIPT_WAITS_UNTIL_SCRIPTS_FINISH){
- ffc f = Screen->LoadFFC(i);
- while(f->Script==Script){
- Waitframe();
- }
- }
- }
- }
- }
- Waitframe();
- }
- }
- }
- const int D_TRADE = 0; //Screen->D value used for the trade sequence state
- ffc script TradeSequence{
- void run(int CheckItem, int TradeItem, int NoItemString, int HasItemString, int TradedString){
- //Check if the player has already traded
- if(Screen->D[D_TRADE]==0){
- //If player hasn't traded and has the required item, play HasItemString, give the new item, and take the old item
- if(Link->Item[CheckItem]){
- Screen->Message(HasItemString);
- WaitNoAction();
- item itm = CreateItemAt(TradeItem, Link->X, Link->Y);
- itm->Pickup = IP_HOLDUP;
- Link->Item[CheckItem] = false;
- Screen->D[D_TRADE] = 1;
- WaitNoAction();
- }
- //If player hasn't traded and doesn't have the required item, play NoItemString
- else{
- Screen->Message(NoItemString);
- WaitNoAction();
- }
- }
- //If the player has already traded, play TradedString
- else{
- Screen->Message(TradedString);
- WaitNoAction();
- }
- }
- }
- const int CT_CLIFF = 142; //This is the combo type used for the cliffs. Look in std_constants.zh for reference. It's Script 1 (142) by default.
- const int CLIFF_PAUSE = 15; //This is the number of frames (60ths of a second) Link must walk into the cliff before jumping
- ffc script GBCliff{
- bool CheckCliffDirection(int Combo){
- int Dir;
- if(Screen->ComboS[Combo]==0101b)
- Dir = DIR_UP;
- else if(Screen->ComboS[Combo]==1010b)
- Dir = DIR_DOWN;
- else if(Screen->ComboS[Combo]==0011b)
- Dir = DIR_LEFT;
- else if(Screen->ComboS[Combo]==1100b)
- Dir = DIR_RIGHT;
- else
- return false;
- if(Dir==Link->Dir)
- return true;
- return false;
- }
- void run(){
- int PushCounter = 0;
- while(true){
- if(Link->Dir==DIR_UP&&!CanWalk(Link->X, Link->Y, DIR_UP, 1, false)&&Link->InputUp&&Screen->ComboT[ComboAt(Link->X+8, Link->Y+14)]==CT_CLIFF&&CheckCliffDirection(ComboAt(Link->X+8, Link->Y+14))&&(Link->Action==LA_WALKING||Link->Action==LA_NONE)){
- PushCounter++;
- if(PushCounter>=CLIFF_PAUSE){
- Game->PlaySound(SFX_JUMP);
- Link->Jump = 2;
- int Y = Link->Y;
- for(int i=0; i<26; i++){
- Y -= 0.61;
- Link->Y = Y;
- WaitNoAction();
- }
- PushCounter = 0;
- }
- }
- else if(Link->Dir==DIR_DOWN&&!CanWalk(Link->X, Link->Y, DIR_DOWN, 1, false)&&Link->InputDown&&Screen->ComboT[ComboAt(Link->X+8, Link->Y+12)]==CT_CLIFF&&CheckCliffDirection(ComboAt(Link->X+8, Link->Y+12))&&(Link->Action==LA_WALKING||Link->Action==LA_NONE)){
- PushCounter++;
- if(PushCounter>=CLIFF_PAUSE){
- Game->PlaySound(SFX_JUMP);
- Link->Jump = 1;
- int Combo = ComboAt(Link->X+8, Link->Y+12);
- int CliffHeight = 1;
- for(int i=1; i<11; i++){
- if(Screen->isSolid(ComboX(Combo)+8, ComboY(Combo)+8+16*i))
- CliffHeight++;
- else
- break;
- }
- Link->Z = CliffHeight*16;
- Link->Y += CliffHeight*16;
- while(Link->Z>0){
- WaitNoAction();
- }
- PushCounter = 0;
- }
- }
- else if(Link->Dir==DIR_LEFT&&!CanWalk(Link->X, Link->Y, DIR_LEFT, 1, false)&&Link->InputLeft&&Screen->ComboT[ComboAt(Link->X+4, Link->Y+8)]==CT_CLIFF&&CheckCliffDirection(ComboAt(Link->X+4, Link->Y+8))&&(Link->Action==LA_WALKING||Link->Action==LA_NONE)){
- PushCounter++;
- if(PushCounter>=CLIFF_PAUSE){
- Game->PlaySound(SFX_JUMP);
- Link->Jump = 2;
- int X = Link->X;
- for(int i=0; i<26; i++){
- X -= 0.92;
- if(i==13){
- Link->Z += 16;
- Link->Y += 16;
- }
- Link->X = X;
- WaitNoAction();
- }
- while(Link->Z>0){
- WaitNoAction();
- }
- PushCounter = 0;
- }
- }
- else if(Link->Dir==DIR_RIGHT&&!CanWalk(Link->X, Link->Y, DIR_RIGHT, 1, false)&&Link->InputRight&&Screen->ComboT[ComboAt(Link->X+12, Link->Y+8)]==CT_CLIFF&&CheckCliffDirection(ComboAt(Link->X+12, Link->Y+8))&&(Link->Action==LA_WALKING||Link->Action==LA_NONE)){
- PushCounter++;
- if(PushCounter>=CLIFF_PAUSE){
- Game->PlaySound(SFX_JUMP);
- Link->Jump = 2;
- int X = Link->X;
- for(int i=0; i<26; i++){
- X += 0.92;
- if(i==13){
- Link->Z += 16;
- Link->Y += 16;
- }
- Link->X = X;
- WaitNoAction();
- }
- while(Link->Z>0){
- WaitNoAction();
- }
- PushCounter = 0;
- }
- }
- else{
- PushCounter = 0;
- }
- Waitframe();
- }
- }
- }
- ffc script GBDungeonCliff{
- void run(int CliffCombo){
- int PushCounter = 0;
- while(true){
- if(Link->Dir==DIR_UP&&!CanWalk(Link->X, Link->Y, DIR_UP, 1, false)&&Link->InputUp&&Screen->ComboD[ComboAt(Link->X+8, Link->Y+7)]==CliffCombo&&(Link->Action==LA_WALKING||Link->Action==LA_NONE)){
- PushCounter++;
- if(PushCounter>=CLIFF_PAUSE){
- Game->PlaySound(SFX_JUMP);
- Link->Jump = 2;
- int Y = Link->Y;
- for(int i=0; i<26; i++){
- Y -= 0.92;
- Link->Y = Y;
- WaitNoAction();
- }
- PushCounter = 0;
- }
- }
- else if(Link->Dir==DIR_DOWN&&!CanWalk(Link->X, Link->Y, DIR_DOWN, 1, false)&&Link->InputDown&&Screen->ComboD[ComboAt(Link->X+8, Link->Y+16)]==CliffCombo+1&&(Link->Action==LA_WALKING||Link->Action==LA_NONE)){
- PushCounter++;
- if(PushCounter>=CLIFF_PAUSE){
- Game->PlaySound(SFX_JUMP);
- Link->Jump = 1;
- int Combo = ComboAt(Link->X+8, Link->Y+12);
- int CliffHeight = 1;
- for(int i=1; i<11; i++){
- if(Screen->isSolid(ComboX(Combo)+8, ComboY(Combo)+8+16*i))
- CliffHeight++;
- else
- break;
- }
- Link->Z = CliffHeight*16-8;
- Link->Y += CliffHeight*16-8;
- while(Link->Z>0){
- WaitNoAction();
- }
- PushCounter = 0;
- }
- }
- else if(Link->Dir==DIR_LEFT&&!CanWalk(Link->X, Link->Y, DIR_LEFT, 1, false)&&Link->InputLeft&&Screen->ComboD[ComboAt(Link->X-1, Link->Y+8)]==CliffCombo+2&&(Link->Action==LA_WALKING||Link->Action==LA_NONE)){
- PushCounter++;
- if(PushCounter>=CLIFF_PAUSE){
- Game->PlaySound(SFX_JUMP);
- Link->Jump = 2;
- int X = Link->X;
- for(int i=0; i<26; i++){
- X -= 1.23;
- Link->X = X;
- WaitNoAction();
- }
- PushCounter = 0;
- }
- }
- else if(Link->Dir==DIR_RIGHT&&!CanWalk(Link->X, Link->Y, DIR_RIGHT, 1, false)&&Link->InputRight&&Link->InputRight&&Screen->ComboD[ComboAt(Link->X+16, Link->Y+8)]==CliffCombo+3&&(Link->Action==LA_WALKING||Link->Action==LA_NONE)){
- PushCounter++;
- if(PushCounter>=CLIFF_PAUSE){
- Game->PlaySound(SFX_JUMP);
- Link->Jump = 2;
- int X = Link->X;
- for(int i=0; i<26; i++){
- X += 1.23;
- Link->X = X;
- WaitNoAction();
- }
- }
- }
- else{
- PushCounter = 0;
- }
- Waitframe();
- }
- }
- }
- item script Frogforce{
- void run(){
- Game->End();
- }
- }
- npc script stealitems
- {
- void run(int min, int max, int counterA, int counterB, int counterC, int counterD, int sfx)
- {
- min = ( min > -1 ) ? min : 0;
- max = ( max > 0 ) ? max : 1;
- int num = Rand(min,max);
- int counters[4] = { counterA, counterB, counterC, counterD };
- int sel = counters[Rand(4)];
- while(1)
- {
- if ( sel ) //don't affect counter 0 (life)
- {
- if ( Collision(this) && (Hero->HitDir > -1) )
- {
- Audio->PlaySound(sfx);
- //Don't roll over.
- if ( (Game->Counter[sel] - num) >= 0 ) Game->Counter[sel] -= num;
- else
- {
- Game->Counter[sel] = ( num > 0 ) ? 0 : Game->Counter[sel];
- }
- while(Hero->HitDir > -1) { Waitframe(); } //Don't steal again unless Link is hit again.
- }
- }
- num = Rand(min,max);
- sel = counters[Rand(4)];
- Waitframe();
- }
- }
- }
- //! The initial combo used for this ffc (on the screen) should be a rupee icon with a numeric cost.
- //! The next combo in the list, should be blank.
- //Combos
- const int CMB_CHEST_GAME_CLOSED = 2640; //The 'closed' chest combo.
- //! This should be combo type 'none', and solid.
- const int CMB_CHEST_GAME_OPEN = 2641; //The closed chest combo.
- //! This should be the combo immediately after CMB_CHEST_GAME_CLOSED', with a type of 'none'.
- //Strings
- const int MSG_CHEST_GAME_RULES = 367; //Screen->Message string that explains the game rules to the player.
- const int MSG_CHEST_GAME_OVER = 366; //Screen->Message string for the end of a game round.
- //Sounds
- const int SFX_OPEN_CHEST = 20; //The sound that will play when Link opens a chest, and an item is awarded.
- const int SFX_CHEST_GAME_SPECIAL_PRIZE_FANFARE = 27; //The sound to play when the player finds the special item in a chest.
- const int SFX_CHEST_GAME_START = 35; //The sound to play when the player starts the game.
- //Other Settings and Options
- const int CHEST_GAME_SCREEN_D_REGISTER = 5; //The Screen->D[index] used to store if the main prize has been awarded.
- const int CHEST_GAME_HOLDUP_TYPE = 4; // The type of item hold-up tp use. 4 = LA_HOLD1LAND(one hand); 5 = LA_HOLD2LAND(two hands)
- const int CHEST_GAME_ALLOW_REPLAY = 0; //Set to '1' to allow the player to play again without leaving the screen.
- const int TIME_INPUT_UP_OPEN_CHEST = 50; //The number of frames of inputting up will open a closed chest.
- const int OPEN_CHESTS_FROM_SIDES_OR_ABOVE = 1; //Set to '0' to only permit opening them from the bottom.
- // Chest Game FFC
- //~ //D0: Number of chests to allow the player to open, per play.
- //~ //D1: ID of special prize to award.
- //~ //D2: Percentage chance of awarding special prize.
- //~ //D3: Backup prize, if special prize already awarded (e.g. 100 rupees, instead of a heart piece). Set to '0' to not offer a backup prize.
- //~ //D4: Cost per play.
- //~ //D5: String for game rules.
- //~ //D6: String to play at end of game.
- //~ //D7: Set to '1' to allow replaying without leaving the screen.
- ffc script ChestMiniGame{
- void run(int max_chests_Link_can_open, int specialPrize, int percentMainPrize, int backupPrize, int costPerPlay, int msgRules, int msgEnd, int allowReplay){
- //Populate with the IDs of prizes to award. Each index is a 1% chance.
- int chestPrizes[]= { 183, 0, 30, 0, 39, 0, 39, 0, 2, 3,
- 0, 0, 23, 72, 0, 72, 72, 79, 80, 3,
- 0, 2, 39, 38, 71, 60, 0, 40, 0, 87,
- 87, 0, 86, 80, 0, 0, 2, 29, 60, 2,
- 0, 71, 73, 0, 87, 73, 0, 79, 38, 0,
- 145, 80, 59, 86, 0, 0, 38, 0, 0, 0,
- 0, 38, 2, 0, 60, 71, 2, 1, 73, 145,
- 1, 70, 0, 78, 0, 0, 0, 80, 0, 86,
- 79, 0, 70, 0, 70, 0, 0, 0, 23, 0,
- 0, 2, 0, 10, 0, 38, 2, 70, 70, 86 };
- int initialData = this->Data; //Store the initial combo, to revert, if replay is enabled.
- int chestComboSpots[176];
- int check;
- int cmb;
- int mainprize;
- int timer = TIME_INPUT_UP_OPEN_CHEST;
- bool openchest;
- int has_opened_number_of_chests;
- bool award_main_prize;
- bool gameRunning;
- bool gameOver;
- item i;
- bool giveprize;
- bool awardnormalprize;
- if ( msgRules ) Screen->Message(msgRules);
- else Screen->Message(MSG_CHEST_GAME_RULES); //Show the string for the chest game rules.
- while(true) {
- if ( max_chests_Link_can_open == has_opened_number_of_chests ) gameOver = true;
- if ( gameOver && ( !CHEST_GAME_ALLOW_REPLAY && !allowReplay ) || allowReplay < 0 ) break;
- if ( gameOver && ( CHEST_GAME_ALLOW_REPLAY || allowReplay > 0 ) ) {
- gameOver = false;
- gameRunning = false;
- this->Data = initialData;
- for ( int q = 0; q < 176; q++ ) {
- if ( Screen->ComboD[q] == CMB_CHEST_GAME_OPEN ) Screen->ComboD[q] = CMB_CHEST_GAME_CLOSED;
- }
- has_opened_number_of_chests = 0;
- }
- if ( LinkCollision(this) && Game->Counter[CR_RUPEES] > costPerPlay && ____Xor(Link->PressA,Link->PressB) && !gameRunning ) {
- //If Link collides with the ffc, which should show the cost, and presses a button, start the game.
- if ( SFX_CHEST_GAME_START ) Game->PlaySound(SFX_CHEST_GAME_START);
- gameRunning = true;
- Game->DCounter[CR_RUPEES] -= costPerPlay;
- this->Data++; //increase to the next combo, removing the cost icon.
- }
- if ( gameRunning ) {
- //Check to see if the combo above Link is a chest.
- if ( Link->Dir == DIR_UP ){
- cmb = Screen->ComboD[ ___AdjacentCombo(ComboAt(Link->X+8, Link->Y+8),Link->Dir) ];
- if ( cmb == CMB_CHEST_GAME_CLOSED ) {
- if ( timer && Link->InputUp ) timer--;
- if ( timer <= 0 || ____Xor(Link->PressA,Link->PressB)) {
- has_opened_number_of_chests++;
- if ( SFX_OPEN_CHEST ) Game->PlaySound(SFX_OPEN_CHEST);
- Screen->ComboD[ ___AdjacentCombo(ComboAt(Link->X+8, Link->Y+8),Link->Dir) ]++;
- timer = TIME_INPUT_UP_OPEN_CHEST;
- giveprize = true;
- Link->InputUp = false;
- }
- }
- else timer = TIME_INPUT_UP_OPEN_CHEST;
- }
- else if ( Link->Dir == DIR_DOWN && OPEN_CHESTS_FROM_SIDES_OR_ABOVE ){
- cmb = Screen->ComboD[ ___AdjacentCombo(ComboAt(Link->X+8, Link->Y+8),Link->Dir) ];
- if ( cmb == CMB_CHEST_GAME_CLOSED ) {
- if ( timer > 0 && Link->InputDown ) timer--;
- if ( timer <= 0 || ____Xor(Link->PressA,Link->PressB) ) {
- has_opened_number_of_chests++;
- if ( SFX_OPEN_CHEST ) Game->PlaySound(SFX_OPEN_CHEST);
- Screen->ComboD[ ___AdjacentCombo(ComboAt(Link->X+8, Link->Y+8),Link->Dir) ]++;
- timer = TIME_INPUT_UP_OPEN_CHEST;
- giveprize = true;
- Link->InputUp = false;
- }
- }
- else timer = TIME_INPUT_UP_OPEN_CHEST;
- }
- else if ( Link->Dir == DIR_LEFT && OPEN_CHESTS_FROM_SIDES_OR_ABOVE ) {
- cmb = Screen->ComboD[ ___AdjacentCombo(ComboAt(Link->X+8, Link->Y+8),Link->Dir) ];
- if ( cmb == CMB_CHEST_GAME_CLOSED ) {
- if ( timer > 0 && Link->InputLeft ) timer--;
- if ( timer <= 0 || ____Xor(Link->PressA,Link->PressB) ) {
- has_opened_number_of_chests++;
- if ( SFX_OPEN_CHEST ) Game->PlaySound(SFX_OPEN_CHEST);
- Screen->ComboD[ ___AdjacentCombo(ComboAt(Link->X+8, Link->Y+8),Link->Dir) ]++;
- timer = TIME_INPUT_UP_OPEN_CHEST;
- giveprize = true;
- Link->InputUp = false;
- }
- }
- else timer = TIME_INPUT_UP_OPEN_CHEST;
- }
- else if ( Link->Dir == DIR_RIGHT && OPEN_CHESTS_FROM_SIDES_OR_ABOVE ) {
- cmb = Screen->ComboD[ ___AdjacentCombo(ComboAt(Link->X+8, Link->Y+8),Link->Dir)];
- if ( cmb == CMB_CHEST_GAME_CLOSED ) {
- if ( timer > 0 && Link->InputRight ) timer--;
- if ( timer <= 0 || ____Xor(Link->PressA,Link->PressB) ) {
- has_opened_number_of_chests++;
- if ( SFX_OPEN_CHEST ) Game->PlaySound(SFX_OPEN_CHEST);
- Screen->ComboD[ ___AdjacentCombo(ComboAt(Link->X+8, Link->Y+8),Link->Dir) ]++;
- timer = TIME_INPUT_UP_OPEN_CHEST;
- giveprize = true;
- Link->InputUp = false;
- }
- }
- else timer = TIME_INPUT_UP_OPEN_CHEST;
- }
- if ( giveprize ) {
- check = Rand(1,100); //Make a check, to use for determining if the main prize should e awarded.
- if ( check <= percentMainPrize ) award_main_prize = true; //If that check passes, then we will award the main prize.
- if ( check > percentMainPrize ) { awardnormalprize = true; check = Rand(0,SizeOfArray(chestPrizes)); }//Otherwise, reuse that var, and make a new check to determine
- //the prize to award from the table.
- int itm;
- if ( !awardnormalprize && award_main_prize && !Screen->D[CHEST_GAME_SCREEN_D_REGISTER] ) { //The main prize has not been awarded, and has been randomly chosen.
- Game->PlaySound(SFX_CHEST_GAME_SPECIAL_PRIZE_FANFARE); //Play the fanfare...
- i = Screen->CreateItem(specialPrize); //Assign the pointer, and make the item.
- itm = specialPrize; //Set the value of the item ID to a var so that we can use it for holding it up.
- }
- if ( !awardnormalprize && award_main_prize && Screen->D[CHEST_GAME_SCREEN_D_REGISTER] && backupPrize ) { //The main prize has already been awarded, so recheck.
- Game->PlaySound(SFX_CHEST_GAME_SPECIAL_PRIZE_FANFARE); //Play the special award fanfare...
- i = Screen->CreateItem(backupPrize); //Assign the pointer, and make the item.
- itm = backupPrize; //Set the value of the item ID to a var so that we can use it for holding it up.
- }
- if ( awardnormalprize && check ) { //Otherwise, if the check to award a special prize did not pass..
- Game->PlaySound(SFX_OPEN_CHEST); //otherwise, play the default.
- i = Screen->CreateItem(chestPrizes[check]); //Award a normal prize, from the list.
- itm = chestPrizes[check]; //Set the value of the item ID to a var so that we can use it for holding it up.
- }
- if ( check ) { //if we're awarding a prize...
- i -> X = Link->X;
- i -> Y = Link->Y;
- if ( CHEST_GAME_HOLDUP_TYPE ) { //If the setting to hold the item overhead is enabled...
- Link->Action = CHEST_GAME_HOLDUP_TYPE; //Hold the item overhead, using the value of that setting.
- Link->HeldItem = itm;
- }
- if ( award_main_prize ) { Screen->D[CHEST_GAME_SCREEN_D_REGISTER] = 1; award_main_prize = false; } //Set the register so that Link cannot collect the special prize again.
- giveprize = false;
- while( Link->Action == LA_HOLD1LAND ) Waitframe();
- }
- else Remove(i); //if check is zero, remove the item pointer.
- //This allows chances of getting nothing at all.
- }
- if ( has_opened_number_of_chests >= max_chests_Link_can_open ) {
- gameOver = true;
- gameRunning = false;
- if ( msgEnd ) Screen->Message(msgEnd);
- else Screen->Message(MSG_CHEST_GAME_OVER);
- }
- }
- Waitframe();
- }
- //If we reach here, then the chest game is over.
- this->Data = 0;
- this->Script = 0;
- Quit();
- }
- //Constants for AdjacentCombo()
- //This now uses DIR_* constants, so you can do AdjacentCombo(cmb,Link->Dir)
- //Returns the Nth combo index of a combo based on a central point, and a direction.
- //For example, combo 22 + COMBO_UPRIGHT returns '7',
- //as combo 7 is to the upper-right of combo 22.
- int ___AdjacentCombo(int cmb, int dir){
- int combooffsets[13]={-0x10, 0x10, -1, 1, -0x11, -0x0F, 0x0F, 0x11};
- if ( cmb % 16 == 0 ) combooffsets[9] = 1;
- if ( (cmb & 15) == 1 ) combooffsets[10] = 1;
- if ( cmb < 0x10 ) combooffsets[11] = 1; //if it's the top row
- if ( cmb > 0x9F ) combooffsets[12] = 1; //if it's on the bottom row
- if ( combooffsets[9] && ( dir == 7 || dir == 0 || dir == 6 || dir == 0 ) ) return 0; //if the left columb
- if ( combooffsets[10] && ( dir == 3 || dir == 2 || dir == 4 ) ) return 0; //if the right column
- if ( combooffsets[11] && ( dir == 1 || dir == 2 || dir == 0 || dir == 0 ) ) return 0; //if the top row
- if ( combooffsets[12] && ( dir == 5 || dir == 4 || dir == 6 ) ) return 0; //if the bottom row
- else if ( cmb >= 0 && cmb <= 176 ) return cmb + combooffsets[dir];
- else return -1;
- }
- //Xor comparison of two boolean values.
- bool ____Xor(bool valA, bool valB){
- if ( !valA && valB ) return true;
- else if ( valA && !valB ) return true;
- return false;
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement