Copy to Clipboard Test

Number Math Path Puzzle. Code

const int SFX_MATH_PATH_MOVE = 16;//Sound to play when making steps on Math Path Puzzle.
const int SFX_MATH_PATH_UNDO = 32;//Sound to play when trekking back steps on Math Path Puzzle.

const int CF_MATH_PATH_PUZZLE = 98;//Combo flag used for marking combos a part of puzzle.

const int CSET_MATH_PATH_CURRENT = 5;//Cset used to paint current position in puzzle.
const int CSET_MATH_PATH_DEFAULT = 2;//Ditto for inactive combos.
const int CSET_MATH_PATH_VALID = 1;//Ditto for valid steps from the current position.
const int CSET_MATH_PATH_GOAL = 8;//Ditto for goal combo.
const int CSET_MATH_PATH_ACTIVE = 7;//Ditto for combos that are parts for traced path.

const int FONT_MATH_PATH_TOTAL = 0;//Font used to render current total in Math puzzle.
const int C_MATH_PATH_TOTAL = 1;//Color used to render current total in Math puzzle.

//Number Math Path Pyzzle.

//2 variants of number path puzzles. 
//1st. You have a grid of combos with numbers on them. Your goal is to connect start combo and end combo in such a way that all adjacent combos in path are numerically adjacent, like 1-2-3-2-3-4 etc...
//2nd. You have a grid of combos with numbers and mathematical symbols drawn on them. The goal is to connect start and end combo sp the path forms a valid mathematical expression. Like 1+1=2. If you succefully pass inequality comparsion checkpoint ("<, >, <=, >=") the current total becomes number you stepped on. If you step on adjacent numbers, the current total will be multpled by 10 and last stepped number will be added to total, as if you input number on calculator.
// Stand on valid number and Press Ex1 to perform a step. Steping on traced path and pressing Ex1 will take back all steps up to that spot on path.

//1. Set up sequence of combos for Math tiles, the sequence must be following: ">=, <=, >, <, =, /, *, -, +, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9";
//2. Build the puzzle using combos from step 1.
//3. Flag all combos used for puzzle with CF_MATH_PATH_PUZZLE combo flag.
//4. Place invisible FFC with combo depicting "0" as combo and assigned script at starting position.
// D0 - 0 - adjacent number path sequence, 1 - math expression composing puzzle.
// D1 - target combo position to solve the puzzle.
// D2 - X coordinate to render current total using FONT_MATH_PATH_TOTAL
// D3 - Y coordinate to render current total using FONT_MATH_PATH_TOTAL
ffc script NumberMatchPath{
	void run (int math, int goalcmb, int drawx, int drawy){
		int number[176];
		int active[176];
		int history[176];
		int ophistory[176];
		int historycmb[176];
		for (int i=0;i<176;i++){
			if (!ComboFI(i,CF_MATH_PATH_PUZZLE)){
				number[i]=1000;
				history[i]=-1;
				historycmb[i]=-1;
				ophistory[i]=0;
				active[i]=-1;
				continue;
			}
			number[i] = Screen->ComboD[i] - this->Data;
			active[i] = 0;
			history[i] = 0;
			historycmb[i]=-1;
			ophistory[i]=0;
			if (i== goalcmb)Screen->ComboC[i] = CSET_MATH_PATH_GOAL;
		}
		int linkcmb = -1;
		int curcmb = ComboAt(CenterX(this), CenterY(this));
		int step = 0;
		int total = number[curcmb];
		int adjcmb=-1;
		int operation = 0;
		Screen->ComboC[curcmb] = CSET_MATH_PATH_CURRENT;
		for (int i=0;i<4;i++){
			adjcmb = AdjacentComboFix(curcmb, i);
			if (adjcmb<0)continue;
			if (!ComboFI(adjcmb,CF_MATH_PATH_PUZZLE)) continue;
			if (Screen->ComboC[adjcmb]==CSET_MATH_PATH_ACTIVE)continue;
			if (MathPathIsValidCombo(this, total, adjcmb, math>0,operation)) Screen->ComboC[adjcmb]=CSET_MATH_PATH_VALID;
		}
		while(true){
			linkcmb = ComboAt(CenterLinkX(),CenterLinkY());
			if (Link->PressEx1 && Screen->ComboC[linkcmb]==CSET_MATH_PATH_VALID){
				Game->PlaySound(SFX_MATH_PATH_MOVE);
				ophistory[step]=operation;
				history[step]=total;
				if (math){
					if (operation==0){
						if (number[linkcmb]<0)operation = Abs(number[linkcmb]);
						else total = total*10+number[linkcmb];
					}
					else{
						if (operation==1)total+=number[linkcmb];
						if (operation==2)total-=number[linkcmb];
						if (operation==3)total*=number[linkcmb];
						if (operation==4)total/=number[linkcmb];
						if (operation>4)total = number[linkcmb];
						operation=0;
					}
				}
				else total = Screen->ComboD[linkcmb]-this->Data;
				historycmb[step]=curcmb;
				step++;
				Screen->ComboC[linkcmb] = CSET_MATH_PATH_CURRENT;
				Screen->ComboC[curcmb] = CSET_MATH_PATH_ACTIVE;
				curcmb = linkcmb;
				for (int i=0;i<176;i++){
					if (Screen->ComboC[i]==CSET_MATH_PATH_VALID){
						if (i==goalcmb)Screen->ComboC[i] = CSET_MATH_PATH_GOAL;
						else Screen->ComboC[i]=CSET_MATH_PATH_DEFAULT;
					}
				}
				for (int i=0;i<4;i++){
					adjcmb = AdjacentComboFix(curcmb, i);
					if (adjcmb<0)continue;
					if (!ComboFI(adjcmb,CF_MATH_PATH_PUZZLE)) continue;
					if (Screen->ComboC[adjcmb]==CSET_MATH_PATH_ACTIVE)continue;
					//Trace(Screen->ComboD[adjcmb] - this->Data);
					if (MathPathIsValidCombo(this, total, adjcmb, math>0,operation)) Screen->ComboC[adjcmb]=CSET_MATH_PATH_VALID;
				}
				if (curcmb==goalcmb){
					this->InitD[7]=1;
					for(int i=1;i<=33;i++){
						if (Screen->State[ST_SECRET]) break;
						if (i==33){
							Game->PlaySound(SFX_SECRET);
							Screen->TriggerSecrets();
							Screen->State[ST_SECRET]=true;
							break;
						}
						ffc n = Screen->LoadFFC(i);
						if (n->Script!=this->Script)continue;
						if (n->InitD[7] == 0) break;
					}
				}
			}
			if (Link->PressEx1 && Screen->ComboC[linkcmb]==CSET_MATH_PATH_ACTIVE){
				Game->PlaySound(SFX_MATH_PATH_UNDO);
				Screen->ComboC[curcmb]=CSET_MATH_PATH_DEFAULT;
				int undocmb = -1;
				bool finishundo = true;
				while(finishundo){					
					step--;
					undocmb = historycmb[step];
					Screen->ComboC[undocmb]=CSET_MATH_PATH_DEFAULT;
					if (undocmb==linkcmb || step<=0)finishundo=false;
					if (ophistory[step]>0){
						total= history[step-1];
						operation = ophistory[step];
					}
					else{
						total = history[step];
						operation=0;
					}
					//Trace(total);
					ophistory[step]=0;
					history[step]=-1;
					historycmb[step]=-1;
				}
				curcmb = linkcmb;
				Screen->ComboC[curcmb] = CSET_MATH_PATH_CURRENT;
				for (int i=0;i<176;i++){
					if (Screen->ComboC[i]==CSET_MATH_PATH_VALID){
						if (i==goalcmb)Screen->ComboC[i] = CSET_MATH_PATH_GOAL;
						else Screen->ComboC[i]=CSET_MATH_PATH_DEFAULT;
					}
				}
				for (int i=0;i<4;i++){
					adjcmb = AdjacentComboFix(curcmb, i);
					if (adjcmb<0)continue;
					if (!ComboFI(adjcmb,CF_MATH_PATH_PUZZLE)) continue;
					if (Screen->ComboC[adjcmb]==CSET_MATH_PATH_ACTIVE)continue;
					//Trace(Screen->ComboD[adjcmb] - this->Data);
					if (MathPathIsValidCombo(this, total, adjcmb, math>0,operation)) Screen->ComboC[adjcmb]=CSET_MATH_PATH_VALID;
				}
			}
			//debugValue(1,total,4);
			//debugValue(2,operation);
			if (math>0)Screen->DrawInteger(2, drawx, drawy,FONT_MATH_PATH_TOTAL, C_MATH_PATH_TOTAL,0 , -1, -1, total, 4, OP_OPAQUE);
			Waitframe();
		}
	}
	
	bool MathPathIsValidCombo(ffc this, int number, int curcmb, bool math, int operation){
		int curnum = Screen->ComboD[curcmb] - this->Data;		
		if (math){
			if (operation==0)return true;
			if (operation>0){
				if (curnum<0) return false;
			}
			if (operation>0 && operation<=4){
				if (operation==4 && curnum==0)return false;
				else return true;
			}
			if (operation==5)return number==curnum;
			if (operation==6)return number>curnum;
			if (operation==7)return number<curnum;
			if (operation==8)return number<=curnum;
			if (operation==9)return number>=curnum;
		}
		else{
			if (curnum<0)return false;
			return Abs(curnum-number)==1;
		}
	}
	
	//Fixed variant of AdjacentCombo function from std_extension.zh
	int AdjacentComboFix(int cmb, int dir)
	{
		int combooffsets[13]={-0x10, 0x10, -1, 1, -0x11, -0x0F, 0x0F, 0x11};
		if ( cmb % 16 == 0 ) combooffsets[9] = -1;//if it's the left edge
		if ( (cmb % 16) == 15 ) combooffsets[10] = -1; //if it's the right edge
		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]==-1 && ( dir == DIR_LEFT || dir == DIR_LEFTUP || dir == DIR_LEFTDOWN ) ) return -1; //if the left columb
		if ( combooffsets[10]==-1 && ( dir == DIR_RIGHT || dir == DIR_RIGHTUP || dir == DIR_RIGHTDOWN ) ) return -1; //if the right column
		if ( combooffsets[11]==-1 && ( dir == DIR_UP || dir == DIR_RIGHTUP || dir == DIR_LEFTUP ) ) return -1; //if the top row
		if ( combooffsets[12]==-1 && ( dir == DIR_DOWN || dir == DIR_RIGHTDOWN || dir == DIR_LEFTDOWN ) ) return -1; //if the bottom row
		if ( cmb >= 0 && cmb < 176 ) return cmb + combooffsets[dir];
		else return -1;
	}
}

//Prints a debug number on each combo in the screen from the given array. It must be 176 ints long.
void DebugCombos(int arr){
	for (int i=0; i<176; i++){
		Screen->DrawInteger(2, ComboX(i), ComboY(i),0, 1,0 , -1, -1, arr[i], 0, OP_OPAQUE);
	}
}