text: import Enemy from "./enemy.js"
  import Vulnerable from "./vulnerable.js"
  import * as Playnewton from "../playnewton.js"
  import Z_ORDER from "../utils/z_order.js";
  import Sara from "./sara.js";
  import { BulletAnimations, Gun } from "./bullet.js";
  
  const FLY_SPEED = 2;
  const FLEE_SPEED = 4;
  
  const HEAD_HEALTH = 4;
  const PART_HEALTH = 2;
  
  const DISTANCE_BETWEEN_PARTS = 24;
  
  /**
   * @readonly
   * @enum {number}
   */
  const DragonPartState = {
      IDLE: 1,
      HURT: 2,
      DYING: 3,
      DEAD: 4
  };
  
  /**
   * 
   * @type DragonPartAnimations
   */
  class DragonPartAnimations {
      /**
       * @type GPU_SpriteAnimation
       */
      flyLeft;
      /**
       * @type GPU_SpriteAnimation
       */
      hurtLeft;
      /**
       * @type GPU_SpriteAnimation
       */
      dyingLeft;
  
      /**
        * @type GPU_SpriteAnimation
        */
      flyRight;
  
      /**
       * @type GPU_SpriteAnimation
       */
      hurtRight;
  
      /**
       * @type GPU_SpriteAnimation
       */
      dyingRight;
  }
  
  /**
   * 
   * @type DragonAnimations
   */
  class DragonAnimations {
      /**
       * @type DragonPartAnimations
       */
      head = new DragonPartAnimations();
      /**
       * @type DragonPartAnimations
       */
      body = new DragonPartAnimations();
      /**
       * @type DragonPartAnimations
       */
      tail = new DragonPartAnimations();
  }
  
  class DragonPart extends Vulnerable {
  
      /**
       * @type DragonPart
       */
      previousPart;
  
      /**
       * @type DragonPartAnimations
       */
      animations;
  
      /**
       * @type DragonPartState
       */
      state;
  
      /**
       * @type GPU_Sprite
       */
      sprite;
  
      /**
       * 
       * @type Playnewton.PPU_Body
       */
      body;
  
      /**
       * @type Playnewton.CLOCK_Timer
       */
      hurtTimer = new Playnewton.CLOCK_Timer(3000);
  
      /**
       * @type number
       */
      health = PART_HEALTH;
  
      get dead() {
          return this.health <= 0;
      }
  
      get bulletable() {
          return true;
      }
  
      constructor() {
          super();
          this.state = DragonPartState.IDLE;
      }
  
      get isGoingLeft() {
          if (this.previousPart) {
              return this.previousPart.body.centerX < this.body.centerX;
          } else {
              return this.body.velocity.x <= 0;
          }
      }
  
      UpdateSprite() {
          switch (this.state) {
              case DragonPartState.IDLE:
                  Playnewton.GPU.SetSpriteAnimation(this.sprite, this.isGoingLeft ? this.animations.flyLeft : this.animations.flyRight);
                  break;
              case DragonPartState.HURT:
                  Playnewton.GPU.SetSpriteAnimation(this.sprite, this.isGoingLeft ? this.animations.hurtLeft : this.animations.hurtRight);
                  if (this.hurtTimer.elapsed) {
                      this.state = DragonPartState.IDLE;
                  }
                  break;
              case DragonPartState.DYING:
                  Playnewton.GPU.SetSpriteAnimation(this.sprite, this.isGoingLeft ? this.animations.dyingLeft : this.animations.dyingRight);
                  break;
          }
          Playnewton.GPU.SetSpritePosition(this.sprite, this.body.position.x, this.body.position.y);
      }
      
      UpdateBody() {
          while(this.previousPart && this.previousPart.dead) {
              this.previousPart = this.previousPart.previousPart;
          }
          switch (this.state) {
              case DragonPartState.IDLE:
              case DragonPartState.HURT:
                  if (this.previousPart) {
                      let dx = this.previousPart.body.centerX - this.body.centerX;
                      let dy = this.previousPart.body.centerY - this.body.centerY;
                      let distance = Math.sqrt(dx ** 2 + dy ** 2);
                      if (distance > DISTANCE_BETWEEN_PARTS) {
                          let s = FLY_SPEED / distance;
                          dx *= s;
                          dy *= s;
                      } else {
                          dx = 0;
                          dy = 0;
                      }
                      Playnewton.PPU.SetBodyVelocity(this.body, dx, dy);
                  }
                  break;
              case DragonPartState.DYING:
                  Playnewton.PPU.SetBodyVelocityBounds(this.body, -this.fleeSpeed, this.fleeSpeed, -this.fleeSpeed, this.fleeSpeed);
                  Playnewton.PPU.SetBodyVelocity(this.body, 0, FLEE_SPEED);
                  if (!Playnewton.PPU.CheckIfBodyIsInWorldBound(this.body)) {
                      Playnewton.GPU.DisableSprite(this.sprite);
                      Playnewton.PPU.DisableBody(this.body);
                      this.state = DragonPartState.DEAD;
                  }
                  break;
              case DragonPartState.DEAD:
                  break;
          }
  
      }
  
      Hurt() {
          switch (this.state) {
              case DragonPartState.IDLE:
                  this.health = Math.max(this.health - 1, 0);
                  if (this.dead) {
                      this.state = DragonPartState.DYING;
                  } else {
                      this.state = DragonPartState.HURT;
                      this.hurtTimer.Start();
                  }
                  break;
          }
      }
  }
  
  class DragonHead extends DragonPart {
  
      /**
   * @type Array<Playnewton.PPU_Point>
   */
      destinations = [];
  
      /**
       * @type number
       */
      currentDestination = 0;
  
      /**
       * @type number
       */
      destinationIncrement = 1;
  
      /**
       * @param {number} x 
       * @param {number} y 
       */
      constructor(x, y) {
          super();
          this.health = Infinity;
          this.animations = Dragon.animations.head;
          this.sprite = Playnewton.GPU.CreateSprite();
          Playnewton.GPU.SetSpriteAnimation(this.sprite, this.animations.flyLeft);
          Playnewton.GPU.SetSpriteZ(this.sprite, Z_ORDER.ENEMIES);
          Playnewton.GPU.EnableSprite(this.sprite);
  
          this.body = Playnewton.PPU.CreateBody();
          Playnewton.PPU.SetBodyRectangle(this.body, 0, 0, 27, 18);
          Playnewton.PPU.SetBodyPosition(this.body, x, y);
          Playnewton.PPU.SetBodyVelocityBounds(this.body, -FLY_SPEED, FLY_SPEED, -FLY_SPEED, FLY_SPEED);
          Playnewton.PPU.EnableBody(this.body);
  
          const path = [{ x: 840, y: 0 }, { x: 800, y: 40 }, { x: 776, y: 88 }, { x: 768, y: 104 }, { x: 720, y: 112 }, { x: 688, y: 80 }, { x: 648, y: 88 }, { x: 640, y: 112 }, { x: 624, y: 360 }, { x: 640, y: 440 }, { x: 704, y: 496 }, { x: 864, y: 488 }, { x: 912, y: 424 }, { x: 888, y: 336 }, { x: 856, y: 304 }, { x: 840, y: 256 }, { x: 824, y: 200 }, { x: 824, y: 168 }, { x: 824, y: 112 }, { x: 792, y: 80 }, { x: 728, y: 104 }, { x: 712, y: 136 }, { x: 696, y: 168 }, { x: 672, y: 176 }, { x: 640, y: 152 }, { x: 608, y: 128 }, { x: 576, y: 128 }, { x: 552, y: 152 }, { x: 520, y: 160 }, { x: 504, y: 192 }, { x: 520, y: 224 }, { x: 608, y: 336 }, { x: 600, y: 416 }, { x: 568, y: 448 }, { x: 544, y: 488 }, { x: 600, y: 512 }, { x: 744, y: 408 }, { x: 792, y: 360 }, { x: 824, y: 328 }, { x: 824, y: 288 }, { x: 800, y: 248 }, { x: 768, y: 208 }, { x: 744, y: 152 }, { x: 736, y: 80 }, { x: 752, y: 40 }, { x: 800, y: 32 }, { x: 832, y: 80 }, { x: 832, y: 152 }, { x: 792, y: 192 }, { x: 728, y: 208 }, { x: 656, y: 168 }, { x: 608, y: 144 }, { x: 568, y: 176 }, { x: 528, y: 184 }, { x: 464, y: 152 }, { x: 432, y: 120 }, { x: 384, y: 120 }, { x: 360, y: 136 }, { x: 336, y: 152 }, { x: 296, y: 128 }, { x: 256, y: 96 }, { x: 224, y: 96 }, { x: 192, y: 112 }, { x: 144, y: 136 }, { x: 128, y: 160 }, { x: 104, y: 200 }, { x: 88, y: 240 }, { x: 80, y: 312 }, { x: 104, y: 368 }, { x: 128, y: 424 }, { x: 168, y: 464 }, { x: 216, y: 496 }, { x: 280, y: 488 }, { x: 320, y: 456 }, { x: 376, y: 424 }, { x: 424, y: 408 }, { x: 464, y: 408 }, { x: 496, y: 432 }, { x: 544, y: 456 }, { x: 608, y: 448 }, { x: 664, y: 400 }, { x: 712, y: 368 }, { x: 768, y: 368 }, { x: 808, y: 400 }, { x: 848, y: 400 }, { x: 888, y: 360 }, { x: 904, y: 312 }, { x: 904, y: 264 }, { x: 880, y: 232 }, { x: 840, y: 200 }, { x: 784, y: 144 }, { x: 752, y: 88 }, { x: 720, y: 48 }, { x: 672, y: 48 }, { x: 640, y: 88 }, { x: 616, y: 144 }, { x: 608, y: 192 }, { x: 608, y: 240 }, { x: 608, y: 288 }, { x: 600, y: 312 }, { x: 584, y: 320 }, { x: 560, y: 352 }, { x: 560, y: 416 }, { x: 568, y: 448 }, { x: 592, y: 488 }, { x: 632, y: 512 }, { x: 704, y: 520 }, { x: 808, y: 504 }, { x: 856, y: 464 }, { x: 872, y: 432 }, { x: 888, y: 376 }, { x: 896, y: 320 }, { x: 896, y: 240 }, { x: 896, y: 192 }, { x: 888, y: 144 }, { x: 864, y: 104 }, { x: 824, y: 72 }, { x: 800, y: 64 }, { x: 728, y: 80 }, { x: 688, y: 96 }, { x: 648, y: 128 }, { x: 616, y: 176 }, { x: 600, y: 232 }, { x: 584, y: 280 }, { x: 584, y: 296 }, { x: 576, y: 344 }, { x: 576, y: 384 }, { x: 584, y: 416 }, { x: 608, y: 472 }, { x: 640, y: 504 }, { x: 696, y: 512 }, { x: 760, y: 512 }, { x: 816, y: 480 }, { x: 848, y: 424 }, { x: 848, y: 400 }, { x: 832, y: 352 }, { x: 800, y: 312 }, { x: 760, y: 288 }, { x: 680, y: 280 }, { x: 648, y: 288 }, { x: 600, y: 312 }, { x: 576, y: 320 }, { x: 520, y: 328 }, { x: 472, y: 304 }, { x: 440, y: 280 }, { x: 392, y: 240 }, { x: 360, y: 232 }, { x: 272, y: 224 }, { x: 232, y: 232 }, { x: 192, y: 248 }, { x: 168, y: 264 }, { x: 136, y: 312 }, { x: 120, y: 376 }, { x: 136, y: 424 }, { x: 184, y: 464 }, { x: 208, y: 472 }, { x: 280, y: 504 }, { x: 360, y: 512 }, { x: 432, y: 512 }, { x: 544, y: 504 }, { x: 672, y: 496 }, { x: 800, y: 464 }, { x: 824, y: 432 }, { x: 840, y: 392 }, { x: 848, y: 344 }, { x: 848, y: 288 }, { x: 840, y: 248 }, { x: 816, y: 192 }, { x: 784, y: 152 }, { x: 744, y: 128 }, { x: 680, y: 112 }, { x: 656, y: 112 }, { x: 640, y: 112 }, { x: 608, y: 120 }, { x: 600, y: 136 }, { x: 584, y: 192 }, { x: 584, y: 216 }, { x: 584, y: 240 }, { x: 608, y: 288 }, { x: 696, y: 368 }, { x: 752, y: 408 }, { x: 776, y: 424 }, { x: 792, y: 448 }, { x: 832, y: 464 }, { x: 872, y: 448 }, { x: 896, y: 408 }, { x: 928, y: 344 }, { x: 936, y: 280 }, { x: 936, y: 216 }, { x: 928, y: 152 }, { x: 904, y: 72 }, { x: 888, y: 64 }, { x: 864, y: 64 }, { x: 832, y: 80 }, { x: 816, y: 120 }, { x: 800, y: 168 }, { x: 784, y: 192 }, { x: 776, y: 200 }, { x: 736, y: 216 }, { x: 712, y: 208 }, { x: 680, y: 184 }, { x: 656, y: 152 }, { x: 632, y: 144 }, { x: 592, y: 160 }, { x: 560, y: 208 }, { x: 560, y: 240 }, { x: 592, y: 312 }, { x: 608, y: 336 }, { x: 640, y: 376 }, { x: 656, y: 400 }, { x: 664, y: 440 }, { x: 648, y: 464 }, { x: 608, y: 488 }, { x: 576, y: 472 }, { x: 536, y: 456 }, { x: 512, y: 416 }, { x: 496, y: 352 }, { x: 488, y: 312 }, { x: 496, y: 256 }, { x: 536, y: 168 }, { x: 576, y: 128 }, { x: 624, y: 80 }, { x: 720, y: 40 }, { x: 800, y: 24 }, { x: 864, y: 56 }, { x: 920, y: 112 }, { x: 920, y: 152 }, { x: 912, y: 240 }, { x: 888, y: 288 }, { x: 832, y: 328 }, { x: 800, y: 352 }, { x: 752, y: 344 }, { x: 688, y: 312 }, { x: 672, y: 256 }, { x: 672, y: 192 }, { x: 712, y: 112 }, { x: 760, y: 40 }, { x: 848, y: 0 }, { x: 880, y: 24 }, { x: 888, y: 72 }, { x: 880, y: 144 }, { x: 840, y: 208 }, { x: 792, y: 240 }, { x: 728, y: 280 }];
          for (let pos of path) {
              this.destinations.push(new Playnewton.PPU_Point(pos.x, pos.y));
          }
      }
  
      UpdateBody() {
          switch (this.state) {
              case DragonPartState.IDLE:
                  this.flyAround();
                  break;
              case DragonPartState.HURT:
                  this.flyAround();
                  if (this.hurtTimer.elapsed) {
                      this.state = DragonPartState.IDLE;
                  }
                  break;
              case DragonPartState.DYING:
                  Playnewton.PPU.SetBodyVelocityBounds(this.body, -FLEE_SPEED, FLEE_SPEED, -FLEE_SPEED, FLEE_SPEED);
                  Playnewton.PPU.SetBodyVelocity(this.body, -FLEE_SPEED, FLEE_SPEED);
                  if (!Playnewton.PPU.CheckIfBodyIsInWorldBound(this.body)) {
                      Playnewton.GPU.DisableSprite(this.sprite);
                      Playnewton.PPU.DisableBody(this.body);
                      this.state = DragonPartState.DEAD;
                  }
                  break;
              case DragonPartState.DEAD:
                  break;
          }
      }
  
      UpdateSprite() {
          let isGoingLeft = this.isGoingLeft;
          switch (this.state) {
              case DragonPartState.IDLE:
                  Playnewton.GPU.SetSpriteAnimation(this.sprite, isGoingLeft ? this.animations.flyLeft : this.animations.flyRight);
                  break;
              case DragonPartState.HURT:
                  Playnewton.GPU.SetSpriteAnimation(this.sprite, isGoingLeft ? this.animations.hurtLeft : this.animations.hurtRight);
                  break;
              case DragonPartState.DYING:
                  Playnewton.GPU.SetSpriteAnimation(this.sprite, isGoingLeft ? this.animations.dyingLeft : this.animations.dyingRight);
                  break;
          }
          if (isGoingLeft) {
              Playnewton.GPU.SetSpritePosition(this.sprite, this.body.position.x - 5, this.body.position.y - 6);
          } else {
              Playnewton.GPU.SetSpritePosition(this.sprite, this.body.position.x - 22, this.body.position.y - 6);
          }
  
      }
  
      flyAround() {
          if (this.destinations.length > 0) {
              let destination = this.destinations[this.currentDestination];
              let dx = destination.x - this.body.centerX;
              let dy = destination.y - this.body.centerY;
              let distance = Math.sqrt(dx ** 2 + dy ** 2);
              if (distance < 32) {
                  this.currentDestination += this.destinationIncrement;
                  if (this.currentDestination >= this.destinations.length) {
                      this.currentDestination = this.destinations.length - 1;
                      this.destinationIncrement = -1;
                  }
                  if (this.currentDestination <= 0) {
                      this.currentDestination = 0;
                      this.destinationIncrement = 1;
                  }
              }
              let s = FLY_SPEED / distance;
              dx *= s;
              dy *= s;
              Playnewton.PPU.SetBodyVelocity(this.body, dx, dy);
          }
      }
  
  }
  
  class DragonBody extends DragonPart {
      /**
       * @param {number} x
       * @param {number} y
       */
      constructor(x, y) {
          super();
          this.animations = Dragon.animations.body;
          this.sprite = Playnewton.GPU.CreateSprite();
          Playnewton.GPU.SetSpriteAnimation(this.sprite, this.animations.flyLeft);
          Playnewton.GPU.SetSpriteZ(this.sprite, Z_ORDER.ENEMIES);
          Playnewton.GPU.EnableSprite(this.sprite);
  
          this.body = Playnewton.PPU.CreateBody();
          Playnewton.PPU.SetBodyRectangle(this.body, 4, 6, 20, 22);
          Playnewton.PPU.SetBodyPosition(this.body, x, y);
          Playnewton.PPU.SetBodyVelocityBounds(this.body, -FLY_SPEED, FLY_SPEED, -FLY_SPEED, FLY_SPEED);
          Playnewton.PPU.EnableBody(this.body);
      }
  }
  
  class DragonTail extends DragonPart {
      /**
       * @param {number} x
       * @param {number} y
       */
      constructor(x, y) {
          super();
          this.health = Infinity;
          this.animations = Dragon.animations.tail;
          this.sprite = Playnewton.GPU.CreateSprite();
          Playnewton.GPU.SetSpriteAnimation(this.sprite, this.animations.flyLeft);
          Playnewton.GPU.SetSpriteZ(this.sprite, Z_ORDER.ENEMIES);
          Playnewton.GPU.EnableSprite(this.sprite);
  
          this.body = Playnewton.PPU.CreateBody();
          Playnewton.PPU.SetBodyRectangle(this.body, 5, 6, 27, 18);
          Playnewton.PPU.SetBodyPosition(this.body, x, y);
          Playnewton.PPU.SetBodyVelocityBounds(this.body, -FLY_SPEED, FLY_SPEED, -FLY_SPEED, FLY_SPEED);
          Playnewton.PPU.EnableBody(this.body);
      }
  
      UpdateBody() {
          super.UpdateBody();
          if(!this.previousPart) {
              this.health = 0;
              this.state = DragonPartState.DYING;
          }
      }
  }
  
  export default class Dragon extends Enemy {
  
      /**
       * @type Array<DragonPart>
       */
      parts = [];
  
      get dead() {
          return this.parts.every(part => part.dead);
      }
  
      /**
       * @type Array<Vulnerable>
       */
      get weak_spots() {
          return this.parts;
      }
  
      /**
       * @type Gun
       */
      leftGun;
  
      /**
       * @type Gun
       */
      rightGun;
  
      /**
       * @type DragonAnimations
       */
      static animations;
  
      /**
       * @type BulletAnimations
       */
      static bulletLeftAnimations;
  
      /**
       * @type BulletAnimations
       */
      static bulletRightAnimations
  
      static async Load() {
          let bitmap = await Playnewton.DRIVE.LoadBitmap("sprites/capuchine.png");
  
          let spriteset = Playnewton.GPU.CreateSpriteset(bitmap, [
              { name: "head-left-fly00", x: 33, y: 65, w: 53, h: 30 },
              { name: "head-left-fly01", x: 33, y: 97, w: 53, h: 30 },
              { name: "head-left-fly02", x: 33, y: 129, w: 53, h: 30 },
              { name: "head-left-hurt00", x: 97, y: 65, w: 53, h: 30 },
              { name: "head-left-hurt01", x: 161, y: 65, w: 53, h: 30 },
  
              { name: "head-right-fly00", x: 33, y: 161, w: 53, h: 30 },
              { name: "head-right-fly01", x: 33, y: 193, w: 53, h: 30 },
              { name: "head-right-fly02", x: 33, y: 225, w: 53, h: 30 },
              { name: "head-right-hurt00", x: 97, y: 97, w: 53, h: 30 },
              { name: "head-right-hurt01", x: 161, y: 97, w: 53, h: 30 },
  
              { name: "body-left-fly00", x: 1, y: 33, w: 30, h: 30 },
              { name: "body-left-hurt00", x: 33, y: 33, w: 30, h: 30 },
  
              { name: "body-right-fly00", x: 1, y: 33, w: 30, h: 30 },
              { name: "body-right-hurt00", x: 33, y: 33, w: 30, h: 30 },
  
              { name: "tail-left-fly00", x: 129, y: 1, w: 49, h: 30 },
              { name: "tail-left-hurt00", x: 179, y: 1, w: 49, h: 30 },
  
              { name: "tail-right-fly00", x: 129, y: 33, w: 49, h: 30 },
              { name: "tail-right-hurt00", x: 179, y: 33, w: 49, h: 30 },
  
              //todo
              { name: "bullet-left-fly00", x: 96, y: 128, w: 32, h: 32 },
              { name: "bullet-left-fly01", x: 128, y: 128, w: 32, h: 32 },
              { name: "bullet-left-fly02", x: 160, y: 128, w: 32, h: 32 },
              { name: "bullet-left-fly03", x: 192, y: 128, w: 32, h: 32 },
              { name: "bullet-left-fly04", x: 96, y: 160, w: 32, h: 32 },
              { name: "bullet-left-fly05", x: 128, y: 160, w: 32, h: 32 },
              { name: "bullet-left-fly06", x: 160, y: 160, w: 32, h: 32 },
              { name: "bullet-left-fly07", x: 192, y: 160, w: 32, h: 32 },
  
              { name: "bullet-right-fly00", x: 96, y: 192, w: 32, h: 32 },
              { name: "bullet-right-fly01", x: 128, y: 192, w: 32, h: 32 },
              { name: "bullet-right-fly02", x: 160, y: 192, w: 32, h: 32 },
              { name: "bullet-right-fly03", x: 192, y: 192, w: 32, h: 32 },
              { name: "bullet-right-fly04", x: 96, y: 224, w: 32, h: 32 },
              { name: "bullet-right-fly05", x: 128, y: 224, w: 32, h: 32 },
              { name: "bullet-right-fly06", x: 160, y: 224, w: 32, h: 32 },
              { name: "bullet-right-fly07", x: 192, y: 224, w: 32, h: 32 },
  
              { name: "bullet-explode00", x: 64, y: 34, w: 16, h: 16 },
              { name: "bullet-explode01", x: 64, y: 51, w: 16, h: 16 },
              { name: "bullet-explode02", x: 64, y: 68, w: 16, h: 16 },
              { name: "bullet-explode03", x: 64, y: 85, w: 16, h: 16 }
          ]);
  
          Dragon.animations = new DragonAnimations();
  
          Dragon.animations.head.flyLeft = Playnewton.GPU.CreateAnimation(spriteset, [
              { name: "head-left-fly00", delay: 100 },
              { name: "head-left-fly01", delay: 100 },
              { name: "head-left-fly02", delay: 100 }
          ]);
  
          Dragon.animations.head.dyingLeft = Dragon.animations.head.hurtLeft = Playnewton.GPU.CreateAnimation(spriteset, [
              { name: "head-left-hurt00", delay: 100 },
              { name: "head-left-hurt01", delay: 100 }
          ]);
  
          Dragon.animations.body.flyLeft = Playnewton.GPU.CreateAnimation(spriteset, [
              { name: "body-left-fly00", delay: 1000 }
          ]);
  
          Dragon.animations.body.dyingLeft = Dragon.animations.body.hurtLeft = Playnewton.GPU.CreateAnimation(spriteset, [
              { name: "body-left-hurt00", delay: 100 },
              { name: "body-left-fly00", delay: 100 },
          ]);
  
          Dragon.animations.tail.flyLeft = Playnewton.GPU.CreateAnimation(spriteset, [
              { name: "tail-left-fly00", delay: 1000 }
          ]);
  
          Dragon.animations.tail.dyingLeft = Dragon.animations.tail.hurtLeft = Playnewton.GPU.CreateAnimation(spriteset, [
              { name: "tail-left-hurt00", delay: 100 },
              { name: "tail-left-fly00", delay: 100 }
          ]);
  
          Dragon.animations.head.flyRight = Playnewton.GPU.CreateAnimation(spriteset, [
              { name: "head-right-fly00", delay: 100 },
              { name: "head-right-fly01", delay: 100 },
              { name: "head-right-fly02", delay: 100 }
          ]);
  
          Dragon.animations.head.dyingRight = Dragon.animations.head.hurtRight = Playnewton.GPU.CreateAnimation(spriteset, [
              { name: "head-right-hurt00", delay: 100 },
              { name: "head-right-hurt01", delay: 100 }
          ]);
  
          Dragon.animations.body.flyRight = Playnewton.GPU.CreateAnimation(spriteset, [
              { name: "body-right-fly00", delay: 1000 }
          ]);
  
          Dragon.animations.body.dyingRight = Dragon.animations.body.hurtRight = Playnewton.GPU.CreateAnimation(spriteset, [
              { name: "body-right-hurt00", delay: 100 },
              { name: "body-right-fly00", delay: 100 },
          ]);
  
          Dragon.animations.tail.flyRight = Playnewton.GPU.CreateAnimation(spriteset, [
              { name: "tail-right-fly00", delay: 1000 }
          ]);
  
          Dragon.animations.tail.dyingRight = Dragon.animations.tail.hurtRight = Playnewton.GPU.CreateAnimation(spriteset, [
              { name: "tail-right-hurt00", delay: 100 },
              { name: "tail-right-fly00", delay: 100 }
          ]);
  
          Dragon.bulletLeftAnimations = new BulletAnimations();
          Dragon.bulletRightAnimations = new BulletAnimations();
  
          Dragon.bulletLeftAnimations.grow = Playnewton.GPU.CreateAnimation(spriteset, [
              { name: "bullet-left-fly00", delay: 10 }
          ]);
  
          Dragon.bulletRightAnimations.grow = Playnewton.GPU.CreateAnimation(spriteset, [
              { name: "bullet-right-fly00", delay: 10 }
          ]);
  
          Dragon.bulletLeftAnimations.fly = Playnewton.GPU.CreateAnimation(spriteset, [
              { name: "bullet-left-fly00", delay: 40 },
              { name: "bullet-left-fly01", delay: 40 },
              { name: "bullet-left-fly02", delay: 40 },
              { name: "bullet-left-fly03", delay: 40 },
              { name: "bullet-left-fly04", delay: 40 },
              { name: "bullet-left-fly05", delay: 40 },
              { name: "bullet-left-fly06", delay: 40 },
              { name: "bullet-left-fly07", delay: 40 }
          ]);
  
          Dragon.bulletRightAnimations.fly = Playnewton.GPU.CreateAnimation(spriteset, [
              { name: "bullet-right-fly00", delay: 40 },
              { name: "bullet-right-fly01", delay: 40 },
              { name: "bullet-right-fly02", delay: 40 },
              { name: "bullet-right-fly03", delay: 40 },
              { name: "bullet-right-fly04", delay: 40 },
              { name: "bullet-right-fly05", delay: 40 },
              { name: "bullet-right-fly06", delay: 40 },
              { name: "bullet-right-fly07", delay: 40 }
          ]);
  
          Dragon.bulletLeftAnimations.explode = Dragon.bulletRightAnimations.explode = Playnewton.GPU.CreateAnimation(spriteset, [
              { name: "bullet-explode00", delay: 100 },
              { name: "bullet-explode01", delay: 100 },
              { name: "bullet-explode02", delay: 100 },
              { name: "bullet-explode03", delay: 100 }
          ]);
      }
  
      static Unload() {
          Dragon.animations = null;
          Dragon.bulletLeftAnimations = null;
          Dragon.bulletRightAnimations = null;
      }
  
      constructor(x, y) {
          super();
          const nbParts = 8;
          this.parts.unshift(new DragonTail(x + nbParts * DISTANCE_BETWEEN_PARTS, y));
          for (let i = nbParts - 1; i >= 1; i--) {
              this.parts.unshift(new DragonBody(x + i * DISTANCE_BETWEEN_PARTS, y));
          }
          this.parts.unshift(new DragonHead(x, y));
          for (let i = 1; i < this.parts.length; i++) {
              this.parts[i].previousPart = this.parts[i - 1];
          }
          this.leftGun = new Gun(Dragon.bulletLeftAnimations, 5, 100, 1);
          this.rightGun = new Gun(Dragon.bulletRightAnimations, 5, 100, 1);
      }
  
      get isGoingLeft() {
          return this.parts[0].body.velocity.x <= 0;
      }
  
      UpdateSprite() {
          for (let p of this.parts) {
              p.UpdateSprite();
          }
          this.leftGun.UpdateSprite();
          this.rightGun.UpdateSprite();
      }
  
      UpdateBody() {
          let nbAliveParts = this.parts.reduce((count, part) => {
              return count + (part.dead ? 0 : 1);
          }, 0);''
          if(nbAliveParts === 2 && this.parts[0].health === Infinity) {
              this.parts[0].health = HEAD_HEALTH;
          }
          for (let p of this.parts) {
              p.UpdateBody();
          }
          this.leftGun.UpdateBody();
          this.rightGun.UpdateBody();
      }
  
      /**
       * 
       * @param {Sara} sara 
       */
      Pursue(sara) {
          let headPos = this.parts[0].body.position;
          if (this.isGoingLeft) {
              if (sara.body.position.x < headPos.x) {
                  this.leftGun.fire(headPos.x - 18, headPos.y + 8, -8, 0);
              }
          } else {
              if (sara.body.position.x > headPos.x) {
                  this.rightGun.fire(headPos.x + 18, headPos.y + 8, 8, 0);
              }
          }
  
          this.leftGun.Pursue(sara);
          this.rightGun.Pursue(sara);
      }
  }