const int SFX_COLORSORT_PICK = 4;//Sound to play when picking ball from jar const int SFX_COLORSORT_MOVE = 16;//Sound to play when putting a ball into jar const int SFX_COLORSORT_SPECIAL_TRIGGER = 47;//Sound to play on special trigger const int TILE_COLORSORT_TOP = 36169; //Tile used for jar top const int TILE_COLORSORT_MIDDLE = 36170;//Tile used for jar middle const int TILE_COLORSORT_BOTTOM = 36171;//Tile used for jar bottom const int TILE_COLORSORT_BALL = 36147;//Tiles used to render balls. Must be ID of leftmost ball tile. const int TILE_COLORSORT_GOAL = 36172;//Tile used to mark completed jars const int TILE_COLORSORT_COLOR_HINT = 36189;//Tiles used to render color clues at jar bases. Must be ID of leftmost tile. This row and TILE_COLORSORT_BALL tile row must have the same color order. const int TILE_COLORSORT_EMPTY_HINT = 36188;//Tile used to indicate that jar must be empty to solve the puzzle. const int LINK_MISC_BALL_IN_HAND = 0;//Link Misc variable to track which ball Link has in hand. const int LINK_MISC_PREV_JAR = 1;//Link Misc variable to track which jar Link was drawn from. const int CSET_COLORSORT = 7; //CSet used to render jars. const int CSET_COLORSORT_BALLS = 2;//CSet used to render balls. const int CSET_COLORSORT_GOAL = 8;//CSet used to mark completed jars const int CSET_COLORSORT_SPECIAL_GOAL = 5;//CSet used to mark special-triggered jars const int COLORSORT_SIZE_PER_UNIT = 8;//Unit to pixel conversion rate. Used for rendering script draws. const int SCREEN_D_COLORSORT_SPECIAL_TRIGGER = 0;//Screen D register used to track special-triggered jars //Color/gem sorting puzzle. //You have a number of jars. Some of them have colored gems stacked one on top of another. //You can grab top gem from jap and drop it into another jar, adding it on top of the stack. //If all jars are either empty, or full of same-colored gems, puzzle is solved. //Some jars have colored base and can be completed oly if filled with gems of specific color. // //1. Set up tiles to render jars, balls and goal marks. Tiles must be as tall as COLORSORT_SIZE_PER_UNIT constant, rest should be transparent. // Balls must be consecutive. //2. Also for color targeted jars set up a sequence of tiles with the same color order as balls needed to render color clues on jar bases // And one tile for clue that jar must be empty. //3. Set up constants inside script file. For instance, TILE_COLORSORT_BALL to ID of leftmost ball tile. //4. Set up combo for bottom part of the jar what looks like, if jar was empty. //5. Place jar FFC`s with combo from step 4 as Data and assigned script. Make sure there is a solid combo underneath FFC and free spot 1 space south. // D0 to D2. IDs of ball colors (0-6), starting from bottom. Color are read in pairs. // #####.____ - lower ball // _____.#### - higher ball // D3 - #####.____ - jar capacity, in units. // _____.#### - add together: 1 - It`s prohibited to place a ball onto different-colored one, unless placed back where it was taken from. 2 - ban placing colored balls into jar that had special trigger already activated (D5 != 0). // D4 - Target color. The jar must be filled with gems of this color ID to count as complete. -1 - jar must be empty for puzzle to be solved. 0 - any color. // D5 - Special trigger option in completing jar. >0 - ID of Item awarded, <0 - Instant secret trigger. Balls will disappear on special trigger. // D6 - Screen D bit ID to track special triggers. Musi be unique for each jar in the screen. ffc script ColorSortPipe{ void run(int ball1, int ball2, int ball3, int set, int targcolor, int specialtrigger, int dbit){ int balls[6]={GetHighFloat(ball1), GetLowFloat(ball1),GetHighFloat(ball2), GetLowFloat(ball2), GetHighFloat(ball3), GetLowFloat(ball3)}; BallGravity(balls); Link->Misc[LINK_MISC_BALL_IN_HAND]=0; Link->Misc[LINK_MISC_PREV_JAR]=0; int cap = GetHighFloat(set); int flags = GetLowFloat(set); int drawy = this->Y; if (JarCompleted(balls,cap,targcolor) && specialtrigger==0) this->InitD[7]=1; else this->InitD[7]=0; while(true){ if ((Link->Y == this->Y + 8 && (Link->X < this->X + 8 && Link->X > this->X - 8) && Link->Dir == DIR_UP)){ if (Link->PressEx1){ if (Link->Misc[LINK_MISC_BALL_IN_HAND] == 0){ if ( GetLastNonZero(balls)>0){ Game->PlaySound(SFX_COLORSORT_PICK); Link->Misc[LINK_MISC_BALL_IN_HAND] = RemoveFromArray (balls); Link->Misc[LINK_MISC_PREV_JAR] = FFCNum(this); if (specialtrigger>0){ if (!GetScreenDBit(SCREEN_D_COLORSORT_SPECIAL_TRIGGER, dbit) && JarCompleted(balls,cap,targcolor)){ if (specialtrigger>0) item it = CreateItemAt(specialtrigger,Link->X,Link->Y); else if (!Screen->State[ST_SECRET]) { Game->PlaySound(SFX_SECRET); Screen->TriggerSecrets(); Screen->State[ST_SECRET] = true; } SetScreenDBit(SCREEN_D_COLORSORT_SPECIAL_TRIGGER, dbit, true); Game->PlaySound(SFX_COLORSORT_SPECIAL_TRIGGER); for (int i=0;i<6;i++){ balls[i]=0; } } } if (!GetScreenDBit(SCREEN_D_COLORSORT_SPECIAL_TRIGGER, dbit))this->InitD[7]=0; if (JarCompleted(balls, cap, targcolor)) this->InitD[7]=1; } } else{ if (BallFitInJar(flags, this, balls)){ if (balls[cap-1]==0){ AppendToArray(balls, Link->Misc[LINK_MISC_BALL_IN_HAND]); Link->Misc[LINK_MISC_BALL_IN_HAND]=0; Link->Misc[LINK_MISC_PREV_JAR]=0; Game->PlaySound(SFX_COLORSORT_MOVE); if (specialtrigger==0){ this->InitD[7]=0; if (JarCompleted(balls,cap,targcolor)) this->InitD[7]=1; for (int i=1; i<=33; i++){ if (i==33){ Game->PlaySound(SFX_SECRET); Screen->TriggerSecrets(); Screen->State[ST_SECRET] = true; break; } ffc s = Screen->LoadFFC(i); if (s->Script!=this->Script) continue; if (s->InitD[7]==0) break; } } else if (!GetScreenDBit(SCREEN_D_COLORSORT_SPECIAL_TRIGGER, dbit) && JarCompleted(balls,cap,targcolor)){ if (specialtrigger>0){ item it = CreateItemAt(specialtrigger,Link->X,Link->Y); it->Pickup +=IP_HOLDUP; } else if (!Screen->State[ST_SECRET]) { Game->PlaySound(SFX_SECRET); Screen->TriggerSecrets(); Screen->State[ST_SECRET] = true; } SetScreenDBit(SCREEN_D_COLORSORT_SPECIAL_TRIGGER, dbit, true); Game->PlaySound(SFX_COLORSORT_SPECIAL_TRIGGER); for (int i=0;i<6;i++){ balls[i]=0; } Waitframe(); this->InitD[7]=1; for (int i=1; i<=33; i++){ if (i==33){ Game->PlaySound(SFX_SECRET); Screen->TriggerSecrets(); Screen->State[ST_SECRET] = true; break; } ffc s = Screen->LoadFFC(i); if (s->Script!=this->Script) continue; if (s->InitD[7]==0) break; } } } } } } } //render jars and colored balls in them drawy = this->Y; for (int i = 0; i<SizeOfArray(balls); i++){ if (balls[i]>0)Screen->FastTile(Cond(i==0, 1, 4), this->X, drawy, TILE_COLORSORT_BALL+balls[i]-1,CSET_COLORSORT_BALLS , OP_OPAQUE); drawy-=COLORSORT_SIZE_PER_UNIT; } drawy = this->Y; for (int t=1; t<=cap+1; t++){ int tile = TILE_COLORSORT_MIDDLE; if (t==1) tile = TILE_COLORSORT_BOTTOM; if (t ==cap+1) tile = TILE_COLORSORT_TOP; Screen->FastTile(Cond(t==1, 0, 4), this->X, drawy, tile, CSET_COLORSORT, OP_OPAQUE); //Screen->DrawTile(Cond(t==1, 2, 4), this->X, drawy, tile, 1, 1, CSET_WATERJAR, -1, -1, 0, 0, 0, 0, true, OP_OPAQUE); drawy-=COLORSORT_SIZE_PER_UNIT; } drawy+=COLORSORT_SIZE_PER_UNIT; if (this->InitD[7]>0)Screen->FastTile(4, this->X, drawy, TILE_COLORSORT_GOAL,Cond(GetScreenDBit(SCREEN_D_COLORSORT_SPECIAL_TRIGGER, dbit),CSET_COLORSORT_SPECIAL_GOAL,CSET_COLORSORT_GOAL),OP_OPAQUE); if (Link->Misc[LINK_MISC_BALL_IN_HAND]>0)Screen->FastTile(3, Link->X, Link->Y-8, TILE_COLORSORT_BALL+Link->Misc[LINK_MISC_BALL_IN_HAND]-1, CSET_COLORSORT_BALLS, OP_OPAQUE); if (targcolor>0)Screen->FastTile(3,this->X, this->Y, TILE_COLORSORT_COLOR_HINT+targcolor-1,CSET_COLORSORT_BALLS,OP_OPAQUE); if (targcolor<0)Screen->FastTile(3,this->X, this->Y, TILE_COLORSORT_EMPTY_HINT,CSET_COLORSORT_BALLS,OP_OPAQUE); Waitframe(); } } } bool BallFitInJar(int flags, ffc f, int balls){ if ((flags&2)>0 && GetScreenDBit(SCREEN_D_COLORSORT_SPECIAL_TRIGGER, f->InitD[6])) return false; if (GetLastNonZero(balls)==0) return true; if ((flags&1)>0 && Link->Misc[LINK_MISC_BALL_IN_HAND]!=GetLastNonZero(balls) && Link->Misc[LINK_MISC_PREV_JAR]!=FFCNum(f))return false; return true; } bool JarCompleted(int arr, int cap, int targcolor){ if(GetLastNonZero(arr)==0 && targcolor==0)return true; if(GetLastNonZero(arr)>0 && targcolor<0)return false; int check = arr[0]; if (targcolor>0 && check!=targcolor) return false; for(int i=0; i<cap; i++){ if (arr[i]!=check)return false; } return true; } void BallGravity(int arr){ for( int i=1; i<6; i++){ if (arr[i]==0)continue; int p=i; while(arr[p-1]==0){ SwapArray(arr, p, p-1); p--; } } } void AppendToArray(int arr, int a){ for (int i =0; i<SizeOfArray(arr);i++){ if (arr[i]>0) continue; arr[i]=a; return; } } int GetLastNonZero(int arr){ for (int i=SizeOfArray(arr)-1; i>=0;i--){ if (arr[i]==0) continue; return arr[i]; } return 0; } int RemoveFromArray (int arr){ for (int i=SizeOfArray(arr)-1; i>=0;i--){ if (arr[i]==0) continue; int ret = arr[i]; arr[i]=0; return ret; } } //Swaps two elements in the given array void SwapArray(int arr, int pos1, int pos2){ int r = arr[pos1]; arr[pos1]=arr[pos2]; arr[pos2]=r; }