//Utility methods for 2D scripting (currently used at Maze and Slider Minigames)

function CirclePixelIterator::NewCirclePixelIterator()
{
   return new ScriptObject( )
   {
      canSaveDynamicFields = "1";
      className = "CirclePixelIterator";     
   };
}

function CirclePixelIterator::init(%this, %x0, %y0, %rad, %dontIterLast)
{
   if (%dontIterLast && %this.x0 !$= "")
   {
      %this.lastX0 = %this.x0;
      %this.lastY0 = %this.y0;
   }
   else
      %this.lastX0 = "";
   
   %this.x0 = %x0;
   %this.y0 = %y0;
   %this.rad = %rad;
   %this.radSquare = %rad * %rad;
   %this.maxX = %x0 + %rad;
   %this.maxY = %y0 + %rad;

   %this.x = %x0 - %rad;
   %this.y = %y0 - %rad;
   
   %this.next();
}

function CirclePixelIterator::next(%this)
{
   %x = %this.x;
   %y = %this.y;
   
   
   while (true)
   {
      if (%y++ > %this.maxY)
      {
         if (%x++ > %this.maxX)
            return false;

         %y = %this.y0 - %this.rad;
      }
      
      %deltaX = %x - %this.x0;
      %deltaY = %y - %this.y0;
      
      if (%deltaX*%deltaX + %deltaY*%deltaY <= %this.radSquare)
      {
         if (%this.lastX0 !$= "")
         {
            %deltaX = %x - %this.lastX0;
            %deltaY = %y - %this.lastY0;
            
            if (%deltaX*%deltaX + %deltaY*%deltaY > %this.radSquare)
               break;
         }
         else
            break;
      }
   }

   %this.x = %x;
   %this.y = %y;
   
   return true;   
}

function LinePixelIterator::NewLinePixelIterator()
{
   return new ScriptObject( )
   {
      canSaveDynamicFields = "1";
      className = "LinePixelIterator";     
   };
}

function LinePixelIterator::init(%this, %x1, %y1, %x2, %y2)
{
   %this.x1 = %x1;
   %this.y1 = %y1;

   %deltaX = %x2-%x1;
   %deltaY = %y2-%y1;

   if (mAbs(%deltaX) > mAbs(%deltaY))
   {
      %this.isYfromX = true;
      %this.coef = %deltaY/%deltaX;
      %this.end = %x2;

      if (%x2 > %x1)
         %this.step = 1;
      else
         %this.step = -1;
   }
   else
   {
      %this.isYfromX = false;
      %this.coef = %deltaX/%deltaY;
      %this.end = %y2;

      if (%y2 > %y1)
         %this.step = 1;
      else
         %this.step = -1;
   }

   %this.x = %x1;
   %this.y = %y1;
}

function LinePixelIterator::next(%this)
{
   if (%this.isYfromX)
   {
      if (%this.x == %this.end)
         return false;

      %this.x += %this.step;
         
      %this.y = mRound(%this.y1 + (%this.x - %this.x1) * %this.coef);
   }
   else
   {  
      if (%this.y == %this.end)
         return false;
      
      %this.y += %this.step;
         
      %this.x = mRound(%this.x1 + (%this.y - %this.y1) * %this.coef);
   }
   
   return true;
}

function GuiControl::isPointInside(%this, %x, %y)
{
   %x1 = getWord(%this.getPosition(), 0);
   %y1 = getWord(%this.getPosition(), 1);
   
   if (%x >= %x1 && %x < (%x1 + getWord(%this.getExtent(), 0)) 
       && %y >= %y1 && %y < (%y1 + getWord(%this.getExtent(), 1)))
         return true;
   
   return false;
}

function GuiControl::cornersCollideWith(%this, %guiObj)
{
   if (%guiObj.isPointInside(getWord(%this.getPosition(), 0), getWord(%this.getPosition(), 1)))
      return true;
   
   if (%guiObj.isPointInside(getWord(%this.getPosition(), 0),
                             getWord(%this.getPosition(), 1) + getWord(%this.getExtent(), 1)))
      return true;

   if (%guiObj.isPointInside(getWord(%this.getPosition(), 0) + getWord(%this.getExtent(), 0),
                             getWord(%this.getPosition(), 1)))
      return true;

   if (%guiObj.isPointInside(getWord(%this.getPosition(), 0) + getWord(%this.getExtent(), 0),
                             getWord(%this.getPosition(), 1) + getWord(%this.getExtent(), 1)))
      return true;

   return false;
}

function GuiControl::getCenterX(%this)
{
   return mRound(getWord(%this.getPosition(), 0) + getWord(%this.getExtent(), 0)/2);
}

function GuiControl::getCenterY(%this)
{
   return mRound(getWord(%this.getPosition(), 1) + getWord(%this.getExtent(), 1)/2);
}

function GuiControl::setCenterPos(%this, %x, %y)
{
   %this.setPosition(%x - getWord(%this.getExtent(), 0)/2, %y - getWord(%this.getExtent(), 1)/2);   
}

function GuiControl::scaleFromCenter(%this, %xScale, %yScale)
{
   %x = %this.getCenterX();
   %y = %this.getCenterY();   
   
   %ext = %this.getExtent();
   
   %this.setExtent(getWord(%ext, 0)*%xScale, getWord(%ext, 1)*%yScale);
   
   %this.setCenterPos(%x, %y);
}

function GuiContainer::getChildAt(%this, %x, %y)
{
   for (%i = %this.getCount() - 1; %i >= 0; %i--)
   {
      if (%this.getObject(%i).isPointInside(%x, %y))
         return %this.getObject(%i);
   }
   
   return "";
}

function GuiContainer::getCollision(%this, %guiObj, %x, %y)
{
   %cWd = getWord(%guiObj.getExtent(), 0) - 1;    
   %cHg = getWord(%guiObj.getExtent(), 1) - 1;    
   
   if (%x < 0 || %x + %cWd >= getWord(%this.getExtent(), 0)
       || %y < 0 || %y + %cHg >= getWord(%this.getExtent(), 1))   
      return %this;

   for (%i = %this.getCount() - 1; %i >= 0; %i--)
   {
      %obj = %this.getObject(%i);
      
      if (%obj == %guiObj)
         continue;
         
      if (%obj.isPointInside(%x, %y) || %obj.isPointInside(%x + %cWd, %y) || 
          %obj.isPointInside(%x, %y + %cHg) || %obj.isPointInside(%x + %cWd, %y + %cHg))
         return %obj;
   }
   
   return "";
}

//Not in use (probably is too slow)...
function GuiContainer::getMoveCollision(%this, %child, %x, %y)
{
   if (%this.lineIter $= "")
      %this.lineIter = LinePixelIterator::NewLinePixelIterator();
      
   %lineIter = %this.lineIter;   

   %lineIter.init(getWord(%child.getPosition(), 0), getWord(%child.getPosition(), 1), %x, %y);

   %x = %lineIter.x;
   %y = %lineIter.y;
   
   while (%lineIter.next())
   {
      %obj = %this.getCollision(%child, %lineIter.x, %lineIter.x);
      
      if (%obj != 0)
         return %this SPC %x SPC %y;
      
      %x = %lineIter.x;
      %y = %lineIter.y;
   }
   
   return "";
}

function GuiRegTimer::NewGuiRegTimer(%x, %y, %width, %height, %initialTimeInSec, %endCallback)
{
   %timer = new GuiControl() {
      canSaveDynamicFields = "1";
      className = "GuiRegTimer";     
      Enabled = "1";
      isContainer = "1";
      HorizSizing = "relative";
      VertSizing = "relative";
      Position = %x SPC %y;
      Extent = %width SPC %height;
      MinExtent = "8 2";
      canSave = "1";
      Visible = "1";
      hovertime = "1000";
      alpha = "1";
      color = "255 255 255 255";
      unitClip = "0 0 1 1";
          time = %initialTimeInSec + 1; // ONE MORE TO BE DECREMENTED AT UPDATED
          endCallback = %endCallback;

      new GuiBitmapCtrl() {
         canSaveDynamicFields = "0";
         Enabled = "1";
         isContainer = "0";
         HorizSizing = "relative";
         VertSizing = "relative";
         Position = (%width/4) SPC 0;
         Extent = (%width/4) SPC %height;
         MinExtent = "2 2";
         canSave = "1";
         Visible = "1";
         hovertime = "1000";
         alpha = "1";
         color = "255 255 255 255";
         unitClip = "0 0 1 1";
         bitmap = "scriptsAndAssets/data/ui/ho/timer/colon.png";
         wrap = "0";
         readWriteTex = "0";
      };
   };
   
   %timer.min = new GuiBitmapCtrl() {
      canSaveDynamicFields = "0";
      Enabled = "1";
      isContainer = "0";
      HorizSizing = "relative";
      VertSizing = "relative";
      Position = "0 0";
      Extent = (%width/4) SPC %height;
      MinExtent = "2 2";
      canSave = "1";
      Visible = "1";
      hovertime = "1000";
      alpha = "1";
      color = "255 255 255 255";
      unitClip = "0 0 1 1";
      bitmap = "scriptsAndAssets/data/ui/ho/timer/0";
      wrap = "0";
      readWriteTex = "0";
   };
   %timer.sec1 = new GuiBitmapCtrl() {
      canSaveDynamicFields = "0";
      Enabled = "1";
      isContainer = "0";
      HorizSizing = "relative";
      VertSizing = "relative";
      Position = (%width/2) SPC 0;
      Extent = (%width/4) SPC %height;
      MinExtent = "2 2";
      canSave = "1";
      Visible = "1";
      hovertime = "1000";
      alpha = "1";
      color = "255 255 255 255";
      unitClip = "0 0 1 1";
      bitmap = "scriptsAndAssets/data/ui/ho/timer/0";
      wrap = "0";
      readWriteTex = "0";
   };
   %timer.sec2 = new GuiBitmapCtrl() {
      canSaveDynamicFields = "0";
      Enabled = "1";
      isContainer = "0";
      HorizSizing = "relative";
      VertSizing = "relative";
      Position = (3*%width/4) SPC 0;
      Extent = (%width/4) SPC %height;
      MinExtent = "2 2";
      canSave = "1";
      Visible = "1";
      hovertime = "1000";
      alpha = "1";
      color = "255 255 255 255";
      unitClip = "0 0 1 1";
      bitmap = "scriptsAndAssets/data/ui/ho/timer/0";
      wrap = "0";
      readWriteTex = "0";
   };

   %timer.add(%timer.min,%timer.sec1,%timer.sec2);

   %timer.decreaseAndUpdate();
   
   %timer.pause = false;
   
   return %timer;
}

function GuiRegTimer::decreaseAndUpdate(%this)
{
   if (!%this.pause)
   {
      %this.time--;

      %min = mFloor(%this.time / 60);
      %this.min.setBitmap("scriptsAndAssets/data/ui/ho/timer/"@%min);

      %seconds = %this.time % 60;
      %sec1 = mFloor(%seconds / 10); // decimal digit
      %sec2 = %seconds % 10; // unitary digit

      %this.sec1.setBitmap("scriptsAndAssets/data/ui/ho/timer/"@%sec1);
      %this.sec2.setBitmap("scriptsAndAssets/data/ui/ho/timer/"@%sec2);
   }
   
   if (%this.time > 0)
      scheduleObjLCA(%this, "Minigame", 1000, "decreaseAndUpdate", 0);
   else
      scheduleLCA("Minigame", 10, 0, %this.endCallback , 0);
}

//use %blinkPeriod < 0 to make it stop blinking
function GuiRegTimer::blink(%this, %blinkPeriod)
{
   if (%blinkPeriod < 0)
   {
      %this.visible = 1;
      cancelScheduleLCA(%this.nextBlinkEvent);
      return;
   }
      
   %this.visible = !%this.visible;
   %this.nextBlinkEvent = scheduleObjLCA(%this, "Minigame", %blinkPeriod, "blink", 1, %blinkPeriod);
}


function ScoreMeter::NewScoreMeter(%x, %y, %miniArtFolder, %regressive, %loseBarAfter)
{
   if (!%regressive)
      %loseBarAfter = -1;
   
   %this = new GuiControl() {
         canSaveDynamicFields = "1";
         Enabled = "1";
         className = "ScoreMeter";
         HorizSizing = "relative";
         VertSizing = "relative";
         Position = %x SPC %y;
         Extent = "586 83"; //from the meter glow
         MinExtent = "2 2";
         canSave = "1";
         Visible = "1";
      };

   %this.meter = new GuiPlasticBitmapCtrl(){
      canSaveDynamicFields = "1";
      Enabled = "1";
      isContainer = "0";
      Profile = "GuiContentProfile";
      HorizSizing = "relative";
      VertSizing = "relative";
      Position = "15 15";
      Extent = "556 52";
      MinExtent = "2 2";
      canSave = "1";
      Visible = "1";
      hovertime = "1000";
      alpha = "1";
      color = "255 255 255 255";
      unitClip = "0 0 1 1";
      useVariable = "0";
      tile = "0";      
      rotation = "0";
      deltaRotation = "0";
      noClip = "0";
      DML = "scriptsAndAssets/data/ui/minigame/meter.png";
   };

   %this.add(%this.meter);
   
   %this.meterGlow = new GuiPlasticBitmapCtrl(){
      canSaveDynamicFields = "0";
      Enabled = "1";
      isContainer = "0";
      Profile = "GuiContentProfile";
      HorizSizing = "relative";
      VertSizing = "relative";
      Position = "0 0";
      Extent = "586 83";
      MinExtent = "2 2";
      canSave = "1";
      Visible = "1";
      hovertime = "1000";
      alpha = "1";
      color = "255 255 255 255";
      unitClip = "0 0 1 1";
      useVariable = "0";
      tile = "0";      
      rotation = "0";
      deltaRotation = "0";
      noClip = "0";
      DML = "scriptsAndAssets/data/ui/minigame/"@%miniArtFolder@"/"@playMinigameDlg.currentLevel@"/meter_glow.png";
   };
   
   %this.add(%this.meterGlow);

   %this.glowAlpha = 1;

   for (%i = 0; %i < 50; %i++)
   {
      %this.meterBar[%i] = new GuiBitmapCtrl() {
         canSaveDynamicFields = "0";
         Enabled = "1";
         isContainer = "0";
         HorizSizing = "relative";
         VertSizing = "relative";
         Position = (43 + %i*10) SPC 27; 
         Extent = "10 31";
         MinExtent = "8 8";
         canSave = "1";
         Visible = %regressive;
         hovertime = "1000";
         alpha = "1";
         color = "255 255 255 255";
         unitClip = "0 0 1 1";
         bitmap = "scriptsAndAssets/data/ui/minigame/score_bar";
         wrap = "0";
      };
      
      %this.add(%this.meterBar[%i]);
   }

   if (%regressive)
   {
      %this.starAtBar[4] = 40;
      %this.starAtBar[3] = 30;
      %this.starAtBar[2] = 20;
      %this.starAtBar[1] = 10;
      %this.starAtBar[0] = 0;
   }
   else
   {
      %this.starAtBar[4] = 49;
      %this.starAtBar[3] = 39;
      %this.starAtBar[2] = 29;
      %this.starAtBar[1] = 19;
      %this.starAtBar[0] = 9;
   }

   for (%i = 0; %i < 5; %i++)
   {
      %this.star[%i] = new GuiBitmapCtrl() {
         canSaveDynamicFields = "0";
         Enabled = "1";
         isContainer = "0";
         HorizSizing = "relative";
         VertSizing = "relative";
         Position = (117 + %i*100) SPC 21; 
         Extent = "45 41";
         MinExtent = "8 8";
         canSave = "1";
         Visible = "1";
         hovertime = "1000";
         alpha = "1";
         color = "255 255 255 255";
         unitClip = "0 0 1 1";
         bitmap = "scriptsAndAssets/data/ui/minigame/star"@(%regressive? "" : "_greyed");
         wrap = "0";
      };
      
      %bar = %this.meterBar[%this.starAtBar[%i]];
      
      %this.star[%i].setCenterPos(%bar.getCenterX(), %bar.getCenterY());
      
      %this.add(%this.star[%i]);
   }

   %this.growingStar = new GuiPlasticBitmapCtrl(){
      canSaveDynamicFields = "0";
      Enabled = "1";
      isContainer = "0";
      Profile = "GuiContentProfile";
      HorizSizing = "relative";
      VertSizing = "relative";
      Position = "0 0";
      Extent = "69 61";
      MinExtent = "2 2";
      canSave = "1";
      Visible = "0";
      hovertime = "1000";
      alpha = "0";
      color = "255 255 255 255";
      unitClip = "0 0 1 1";
      useVariable = "0";
      tile = "0";      
      rotation = "0";
      deltaRotation = "0";
      noClip = "0";
      DML = "scriptsAndAssets/data/ui/minigame/star.png";
   };
   
   %this.add(%this.growingStar);

   %this.curMeterBarInd = %regressive? 49 : 0;
   %this.curStarInd = %regressive? 4 : 0;
   
   %this.regressive = %regressive;

   //used on progressive meter
   %this.barsToAnim = 0;

   //used at the regressive meter
   %this.loseBarAfter = %loseBarAfter;  
   
   
   //REGRESSIVE METER ANIMATION SETTINGS: 
   %this.pulseFromBar = 15;
   %this.pulseDuration = 2000;
   //configuration for the star and bar blinks when they are lost
   %this.numOfBlinks = 1; 
   %this.blinkDuration = 100;
   
   //PROGRESSIVE METER ANIMATION SETTINGS: 
   %this.animDurationPerBar = 175;
   %this.starAnimDuration = 225;

   %this.animGlow();

   if (%this.loseBarAfter > 0)
      scheduleObjLCA(%this, "Minigame", %this.loseBarAfter, "decreaseMeter", 0);

   %this.pause = false;

   return %this;
}

function ScoreMeter::setStarsAtBars(%this, %b0, %b1, %b2, %b3, %b4)
{
   %this.starAtBar[4] = %b4;
   %this.starAtBar[3] = %b3;
   %this.starAtBar[2] = %b2;
   %this.starAtBar[1] = %b1;
   %this.starAtBar[0] = %b0;

   for (%i = 0; %i < 5; %i++)
   {
      %bar = %this.meterBar[%this.starAtBar[%i]];
      
      %this.star[%i].setCenterPos(%bar.getCenterX(), %bar.getCenterY());
      
      %this.add(%this.star[%i]);
   }
}

function ScoreMeter::animGlow(%this)
{
   %this.glowAlpha += 0.1;
   
   if (%this.glowAlpha > 1)
      %this.glowAlpha = -0.95;

   %this.meterGlow.setAlpha(mAbs(%this.glowAlpha));

   scheduleObjLCA(%this, "Minigame", 100, "animGlow", 0);
}

function ScoreMeter::animPulse(%this)
{
   if (getWord(%this.meter.color, 1) < 100)
      %this.meter.animateColor(255, 255, 255, 0, 1000, "0 0");
   else
      %this.meter.animateColor(255, 0, 0, 0, %this.pulseDuration, "0 0");

   scheduleObjLCA(%this, "Minigame", %this.pulseDuration + 50, "animPulse", 0);
}

//ONLY USE FOR THE REGRESSIVE METER
function ScoreMeter::decreaseMeter(%this)
{
   if (!%this.pause)
   {
      %this.meterBar[%this.curMeterBarInd].setVisible(false);
      for (%b = 1; %b <= 2*%this.numOfBlinks; %b++)
         scheduleObjLCA(%this.meterBar[%this.curMeterBarInd], "Minigame", %b*%this.blinkDuration, "setVisible", 1, (%b % 2) == 1);
   
      if (%this.curStarInd == 5)
         %this.curStarInd = 4;         
         
      if (%this.curStarInd >= 0 && %this.curMeterBarInd <= %this.starAtBar[%this.curStarInd])
      {
         %this.star[%this.curStarInd].setBitmap("scriptsAndAssets/data/ui/minigame/star_greyed");
         for (%b = 1; %b <= 2*%this.numOfBlinks; %b++)
            scheduleObjLCA(%this.star[%this.curStarInd], "Minigame", %b*%this.blinkDuration, "setBitmap", 1,
                           (%b % 2) == 1? "scriptsAndAssets/data/ui/minigame/star"
                              : "scriptsAndAssets/data/ui/minigame/star_greyed");

         %this.curStarInd--;
      }
      
      %this.curMeterBarInd--;
   }
      
   if (%this.curMeterBarInd < %this.pulseFromBar)
      %this.animPulse();
   
      
   if (%this.curMeterBarInd >= 0 && %this.loseBarAfter > 0)
      scheduleObjLCA(%this, "Minigame", %this.loseBarAfter, "decreaseMeter", 0);
}

//ONLY USE FOR THE PROGRESSIVE METER
function ScoreMeter::increaseMeter(%this, %numOfBars)
{
   %this.barsToAnim += %numOfBars;
   
   if (%this.curMeterBarInd + %this.barsToAnim > 49)  
      %this.barsToAnim = 49 - %this.curMeterBarInd;
   
   if (%this.barsToAnim > 0) 
      %this.animMeter();
   
   return -1;
}

function ScoreMeter::animMeter(%this)
{
   
   if (%this.barsToAnim == 0) 
      return;
	  
   sfxPlay(AudioPointGiven);
   
   %this.meterBar[%this.curMeterBarInd].scaleFromCenter(1.3, 1.3);
   scheduleObjLCA(%this.meterBar[%this.curMeterBarInd], "Minigame", 
                  %this.animDurationPerBar,"scaleFromCenter", 2, 0.78, 0.78);

   %this.meterBar[%this.curMeterBarInd].setVisible(true);
   
   %this.curMeterBarInd++;
   
   if (mFloor((%this.curMeterBarInd+1)/10) > %this.curStarInd)
   {
      %this.star[%this.curStarInd].setBitmap("scriptsAndAssets/data/ui/minigame/star");
      
      if (%this.curStarInd > 0)
         %this.growingStar.scaleFromCenter(0.497, 0.497);
         
      %this.growingStar.setCenterPos(%this.star[%this.curStarInd].getCenterX(), %this.star[%this.curStarInd].getCenterY());
      %this.growingStar.setAlpha(0.7);
      %this.growingStar.setVisible(true);

      %this.curMAnim = 0;
      %this.animStar();
      
      %this.curStarInd++;
   }
   
   %this.barsToAnim--;
   scheduleObjLCA(%this, "Minigame", %this.animDurationPerBar + 20, "animMeter", 0);
}

function ScoreMeter::animStar(%this)
{
   %step = %this.curMAnim + 1;

   %this.growingStar.setAlpha(0.7 - %step*0.1);
   %this.growingStar.scaleFromCenter(1.15, 1.15);
      
   if (%step < 5)
   {
      %this.curMAnim = %step;
      scheduleObjLCA(%this, "Minigame", mFloor(%this.starAnimDuration/5), "animStar", 0);
   }
   else
   {
      %this.growingStar.setVisible(false);
      %this.curMAnim = "";
	  sfxPlay("AudioStarGain" @ %this.curStarInd);
   }
}

function ScoreMeter::getHintsGained(%this)
{
   if (%this.regressive)
      return %this.curStarInd + 1;
   else
      return (%this.curMeterBarInd + %this.barsToAnim + 1)/10;     
}



