#include_function "lib\Ikareimu\Common\Math.dnh"
#include_function "lib\Ikareimu\System\Polarity.dnh"
#include_function "lib\Ikareimu\System\Shield.dnh"
/******************************************
* Variables                               *
******************************************/

let imgLaser = "lib\Ikareimu\img\playerlaser.png";

/******************************************
* Public Functions                        *
******************************************/

// Empties the power when the bomb key is pushed.
// Creates the appropriate amount and color of lasers.

sub PlayerLaserManager_Initialize {
  LoadGraphic(imgLaser);
}

sub PlayerLaserManager_Run {
  if(GetKeyState(VK_BOMB) == KEY_PUSH){
    if(GetPower >= 10){
      PlayerLasers_create;
      EmptyPower;
      ExplosionEffect(GetPlayerX, GetPlayerY, GetPolarity);
    }
  }
}

/******************************************
* Private Functions                       *
******************************************/

task PlayerLasers_create {
  let LaserNum = floor(GetPower/10);
  ascent(i in 0..floor(LaserNum/2)){
    PlayerLaser_create(10-i, 80-i*10);
    loop(2){yield;}
      PlayerLaser_create(10-i, 100+i*10);
    }
    if(LaserNum%2 == 1){
      PlayerLaser_create(10-(floor(GetPower/10))/2, 80 - (floor(GetPower/10))/2*10);
    }
    return;
}

task PlayerLaser_create(speed, angle){
  // initialize intial behavior
  let obj = Obj_Create(OBJ_SHOT);
  let anglechange = 2;
  let timer = 0;
  let LaserPolarity = GetPolarity;
  Obj_SetPosition(obj, GetPlayerX, GetPlayerY);
  Obj_SetSpeed(obj, speed);
  Obj_SetAngle(obj, angle);
  ObjShot_SetDamage(obj, 0);
  ObjShot_SetPenetration(obj, 1);
  ObjShot_SetGraphic(obj, RED01);
  Obj_SetAutoDelete(obj, false);
  Obj_SetAlpha(obj, 0);
  PlayerLaser_spawnTail(obj, LaserPolarity);
  //wait while turning and decelerating
  loop(10){
    Obj_SetSpeed(obj, Obj_GetSpeed(obj) - 0.5);
    if(angle > 90){
      Obj_SetAngle(obj, Obj_GetAngle(obj) + anglechange);
    }
    if(angle < 90){
      Obj_SetAngle(obj, Obj_GetAngle(obj) - anglechange);
    }
    anglechange += 0.6;
    PlayerLaser_detectCollision(obj, LaserPolarity);
    yield;
  }
  //choose target closest to it
  let target = -1;
  let targetX = 0;
  let targetY = 0;
  let closestDistance = 65535;
  ascent(enemy in EnumEnemyBegin..EnumEnemyEnd){
    let enemyID = EnumEnemyGetID(enemy);
    let enemyX = GetEnemyInfo(enemyID, ENEMY_X);
    let enemyY = GetEnemyInfo(enemyID, ENEMY_Y);
    let enemyLife = GetEnemyInfo(enemyID, ENEMY_LIFE);
    let enemyDistance = GetDistance(Obj_GetX(obj), Obj_GetY(obj), enemyX, enemyY);
    if(enemyDistance < closestDistance &&
      (enemyLife > 10000 || (GetEnemyLife >= enemyLife && GetEnemyLife>0))){
      closestDistance = enemyDistance;
      target = enemyID;
      targetX = enemyX;
      targetY = enemyY;
    }
  }
  //change behavior per frame based on conditions until deleted
  while(!Obj_BeDeleted(obj)){
    anglechange += 0.6;
    //accelerate until speed is 15 or greater
    if(Obj_GetSpeed(obj)<15){
        Obj_SetSpeed(obj, Obj_GetSpeed(obj) + 0.4);
    }
    if(timer<=120){
      //if there is a target
      if(GetEnemyInfoDefault(target, ENEMY_LIFE, 0) > 10000 ||
        (GetEnemyLife >= GetEnemyInfoDefault(target, ENEMY_LIFE, 0) && GetEnemyLife>0)){
        targetX = GetEnemyInfoDefault(target, ENEMY_X, 0);
        targetY = GetEnemyInfoDefault(target, ENEMY_Y, 0);
        let objAngle = Obj_GetAngle(obj);
        while(objAngle >= 360){
          objAngle -= 360;
        }
        while(objAngle < 0){
          objAngle += 360;
        }
        let angleToTarget = GetAngleFrom(Obj_GetX(obj), Obj_GetY(obj), targetX, targetY);
        while(angleToTarget >= 360){
          angleToTarget -= 360;
        }
        while(angleToTarget < 0){
          angleToTarget += 360;
        }
        let angleDifference = objAngle - angleToTarget;
        //if difference of angle is less than 8, make shot face target
        if((angleDifference<=anglechange && angleDifference>=-anglechange) || angleDifference>=360-anglechange || angleDifference<=-360+anglechange){
          Obj_SetAngle(obj, angleToTarget);
        }
        //if difference of angle is less than 180, make shot turn clockwise
        else if((angleDifference<=180 && angleDifference>=0) || angleDifference <= -180){
          Obj_SetAngle(obj, Obj_GetAngle(obj) - anglechange);
        }
        //if difference of angle is greater than 180, make shot turn counterclockwise
        else if(angleDifference > 180 || (angleDifference<=0 && angleDifference>=-180)){
          Obj_SetAngle(obj, Obj_GetAngle(obj) + anglechange);
        }
      }
      //check for another enemy if target is dead
      else {
        target = -1;
        closestDistance = 65535;
        ascent(enemy in EnumEnemyBegin..EnumEnemyEnd){
          let enemyID = EnumEnemyGetID(enemy);
          let enemyX = GetEnemyInfo(enemyID, ENEMY_X);
          let enemyY = GetEnemyInfo(enemyID, ENEMY_Y);
          let enemyLife = GetEnemyInfo(enemyID, ENEMY_LIFE);
          let distance = GetDistance(Obj_GetX(obj), Obj_GetY(obj), enemyX, enemyY);
          if(distance < closestDistance && (enemyLife > 10000 ||
            (GetEnemyLife >= enemyLife && GetEnemyLife>0))){
            closestDistance = distance;
            target = enemyID;
            targetX = enemyX;
            targetY = enemyY;
          }
        }
      }
    }
    PlayerLaser_detectCollision(obj, LaserPolarity);
    if(Obj_GetX(obj) < GetClipMinX-200 || Obj_GetX(obj) > GetClipMaxX+200 || Obj_GetY(obj) < GetClipMinY-200 || Obj_GetY(obj) > GetClipMaxY+200){
      Obj_Delete(obj);
    }
    timer++;
    yield;
  }
  return;
}

task PlayerLaser_spawnTail(parent, graphic){
  let parentX = Obj_GetX(parent);
  let parentY = Obj_GetY(parent);
  let parentAngle = Obj_GetAngle(parent);
  let tail = Obj_Create(OBJ_EFFECT);
  ObjEffect_SetTexture(tail, imgLaser);
  ObjEffect_SetRenderState(tail, ADD);
  ObjEffect_SetPrimitiveType(tail, PRIMITIVE_TRIANGLESTRIP);
  ObjEffect_SetLayer(tail, 5);
  ObjEffect_CreateVertex(tail, 50);
  if(graphic==RED){
    ascent(i in 0..25){
      ObjEffect_SetVertexUV(tail, i*2, 0, 0+i*5);
      ObjEffect_SetVertexUV(tail, i*2+1, 26, 0+i*5);
    }
  }
  if(graphic==BLUE){
    ascent(i in 0..25){
      ObjEffect_SetVertexUV(tail, i*2, 26, 0+i*5);
      ObjEffect_SetVertexUV(tail, i*2+1, 52, 0+i*5);
    }
  }
  ascent(i in 0..25){
    ObjEffect_SetVertexXY(tail, i*2, parentX+cos(parentAngle-90)*8, parentY+sin(parentAngle-90)*8);
    ObjEffect_SetVertexXY(tail, i*2+1, parentX+cos(parentAngle+90)*8, parentY+sin(parentAngle+90)*8);
  }
  let childX = [];
  let childY = [];
  let childAngle = [];
  loop(24){
    childX = childX ~ [parentX];
    childY = childY ~ [parentY];
    childAngle = childAngle ~ [parentAngle];
  }
  
  let deleteCounter = 25;
  loop {
    descent(i in 1..24){
      childX[i] = childX[i-1];
      childY[i] = childY[i-1];
      childAngle[i] = childAngle[i-1];
    }
    childX[0] = parentX;
    childY[0] = parentY;
    childAngle[0] = parentAngle;
    if(!Obj_BeDeleted(parent)){
      parentX = Obj_GetX(parent);
      parentY = Obj_GetY(parent);
      parentAngle = Obj_GetAngle(parent);
    }
    
    ObjEffect_SetVertexXY(tail, 0, parentX+cos(parentAngle-90)*5, parentY+sin(parentAngle-90)*5);
    ObjEffect_SetVertexXY(tail, 1, parentX+cos(parentAngle+90)*5, parentY+sin(parentAngle+90)*5);
    ascent(i in 1..25){
      ObjEffect_SetVertexXY(tail, i*2, childX[i-1]+cos(childAngle[i-1]-90)*5, childY[i-1]+sin(childAngle[i-1]-90)*5);
      ObjEffect_SetVertexXY(tail, i*2+1, childX[i-1]+cos(childAngle[i-1]+90)*5, childY[i-1]+sin(childAngle[i-1]+90)*5);
    }
    if(Obj_BeDeleted(parent)){
      deleteCounter -= 1;
      if(deleteCounter==0){
        Obj_Delete(tail);
        return;
      }
    }
    yield;
  }
}

function PlayerLaser_detectCollision(objID, polarity) {
  let CollisionAreas = GetCommonDataDefault("SetCollisionA", []);
  let len = length(CollisionAreas);
  ascent(i in 0..len){
    if(GetDistance(Obj_GetX(objID), Obj_GetY(objID), CollisionAreas[i][0], CollisionAreas[i][1]) <= CollisionAreas[i][2]){
    let damage = 50;
    Obj_Delete(objID);
    if((polarity==RED && CollisionAreas[i][3]==BLUE) || (polarity==BLUE && CollisionAreas[i][3]==RED)){
      damage = 100;
    }
      let obj = Obj_Create(OBJ_SHOT);
    Obj_SetPosition(obj, CollisionAreas[i][0], CollisionAreas[i][1]);
    Obj_SetSpeed(obj, 0);
    Obj_SetAngle(obj, 0);
    Obj_SetAlpha(obj, 0);
    ObjShot_SetGraphic(obj, WHITE05);
    ObjShot_SetDamage(obj, damage);
    ObjShot_SetPenetration(obj, 1);
    yield;
    yield;
    Obj_Delete(obj);
    return ;
  }
  }
}

task ExplosionEffect(x, y, polarity){
  let effect = Obj_Create(OBJ_EFFECT);
  ObjEffect_SetTexture(effect, imgShield);
  ObjEffect_SetRenderState(effect, ADD);
  ObjEffect_SetPrimitiveType(effect, PRIMITIVE_TRIANGLEFAN);
  ObjEffect_CreateVertex(effect, 4);
  if(polarity == RED){
    ObjEffect_SetVertexUV(effect, 0, 0, 0);
    ObjEffect_SetVertexUV(effect, 1, 64, 0);
    ObjEffect_SetVertexUV(effect, 2, 64, 64);
    ObjEffect_SetVertexUV(effect, 3, 0, 64);
  }
  if(polarity == BLUE){
    ObjEffect_SetVertexUV(effect, 0, 0, 64);
    ObjEffect_SetVertexUV(effect, 1, 64, 64);
    ObjEffect_SetVertexUV(effect, 2, 64, 128);
    ObjEffect_SetVertexUV(effect, 3, 0, 128);
  }
  ascent(i in 0..20){
    ObjEffect_SetVertexXY(effect, 0, x-i*15, y-i*15);
    ObjEffect_SetVertexXY(effect, 1, x+i*15, y-i*15);
    ObjEffect_SetVertexXY(effect, 2, x+i*15, y+i*15);
    ObjEffect_SetVertexXY(effect, 3, x-i*15, y+i*15);
  ascent(j in 0..4){
    ObjEffect_SetVertexColor(effect, j, 255-i*13, 255, 255, 255);
  }
  yield;
  }
  Obj_Delete(effect);
  return;
}