How to rotate my ship bullets?

Hey guys, this is my code everything is working fine, I 'm just having trouble making my bullets rotate with my ship image. My ship image moves in all directions apart from the bullets that fire in one direction. How can I do this? What part of the code do I need to change or add?

If you can have a look at my code ill be very grateful, Thank you!

//Variables to store the ships position, direction, and the speed

//Array of intergers, which is used to draw the land
int[] land;

//Where the bullets will be stored 
ArrayList <Bullet> bullets; 

//Game state 
int WAITING =1;
int FINISHED =2;
int state = WAITING;

Ship myShip;


void setup() {
  size(600, 600);

  myShip = new Ship();
  bullets = new ArrayList();
  //Bullet b = new Bullet(X, Y);

  //This will be used to draw the land 
  land = new int [width/10+1];
  for (int i=0; i < land.length; i++) {
    land[i] = int( random(10));
  }
}


void draw() {

  background(155);

  //adding the method to draw
  //myShip.keyPressed();
  drawland();
  myShip.update();
  myShip.drawFinished();
  moveAll();
  displayAll();


  //Checks the state variable it also adds the drawWaiting() method that 
  //get called in the coressponding state
  if (state == WAITING) {
    drawWaiting();
  }
  else if (state == FINISHED) {
  }
}


void drawWaiting() {

  textAlign(CENTER);
  fill(0);
  text("Click to play!", width/2, height/2);
}

void drawland() {

  stroke(0);
  fill(250, 150, 0, 60); 
  //
  //Creates the land using beginShape and endShape
  beginShape();
  vertex(0, height);
  for ( int i=0; i < land.length; i++) {
    vertex( i * 10, height - 50 - land[i] );
  } 
  vertex(width, height);
  endShape(CLOSE);
}

//Mouse clicked method that changes the state from waiting to finished
void mousePressed() {

  if (state == WAITING) {
    state = FINISHED;
  }
} 


void keyPressed() {

  if ( keyCode == LEFT ) {
    myShip.a -= 0.09;
  }
  if ( keyCode == RIGHT ) {
    myShip.a += 0.09;
  }

  if ( keyCode == UP ) {
    myShip.acc += 0.04;

    myShip.accel.x = myShip.acc * sin(myShip.a);
    myShip.accel.y = -myShip.acc * cos(myShip.a);
  }


  if (keyCode == ' ') {

    //I have used myShip because its outside the class and because I used PVector 
    //for my position I have to use that too. 

    Bullet temp = new Bullet(myShip.position.x, myShip.position.y);
    bullets.add(temp);
  }
}




class Bullet//bullet class
        {
          float x;
          float y;
          float speed;
          Bullet(float tx, float ty)
          {  
            x = tx;
            y = ty;
          }
          void display()
          {
            stroke(0);
            fill(255, 0, 0);
            ellipse(x, y, 5, 5);


          }
          void move()
          {
            y -= 5;
          }
        }


        void moveAll()
        {
          for (Bullet temp : bullets)
          {
            temp.move();
          }
        }
        void displayAll()
        {
          for (Bullet temp : bullets)
          {
            temp.display();
          }
        }

    class Ship {

      //Global Variables
      PVector position;
      PVector accel;
      PVector velocity;
      PVector rotation;
      float drag = .9;
      //Ship image
      PImage ship = loadImage("ship.png");

      //How much the ship accelerates 
      float acc = 0;

      //rotation angle
      float a = 0;


      //CONSTRUCTOR
      public Ship() {

        position = new PVector(330, 445);
        accel = new PVector(0, 0);
        velocity = new PVector(0, 0);
      }

      //FUNCTIONS
      void update() {

        drawShip();
        drawFinished();
        velocity.add(accel);
        velocity.mult(drag);
        position.add(velocity);

        acc *= 0.95;

        //Stops the ship when it reaches the surface 
        if (position.y > height - 20 - ship.height/2 ) {
          position.y = height - 20 - ship.height/2;
        }
      }


      void drawShip() {
        pushMatrix();
        //method to use the new pos variable
        translate(position.x, position.y);
        rotate(a);
        stroke(255, 50, 0);
        fill(255, 50, 20);

        for ( int i=4; i >= 0; i--) {
          stroke(255, i*50, 0);
          fill(255, i*50, 20);
          ellipse( 0, 40, min(1, acc*10) *i*4, min(1, acc*10)* i*10);
        }
        image(ship, -ship.width/2, -ship.height/2, ship.width, ship.height);
        popMatrix();
      }

      void drawFinished() {

        textAlign(CENTER);
        fill(0);
        if (position.y > height - 50 - ship.height/2 ) {


          text("you have crashed!", width/2, height/2);
        }
      }
    }

Answers

  • edited March 2014

    ... bullets that fire in one direction.

    What is important is how many angles that direction can be!
    For a Bullet which only descends straight south, class below is pretty enough.
    You just need to instantiate it w/ the same coordinates as the Ship object currently is, plus desired falling speed:

    class Bullet {
      static final int DIM = 4;
      float x, y, s;
    
      Bullet(float xx, float yy, float vy) {
        x = xx;
        y = yy;
        s = vy;
      }
    
      void display() {
        ellipse(x, y, DIM, DIM);
      }
    
      void update() {
        y += s;
      }
    
      boolean check() {
        return y > height; 
      }
    }
    

    However, if there are any non 45° degree angles, you're gonna need a more complex class using PVector for position & speed vectors.
    Just like the 1 used in "Multiple Bullets" example:

    http://studio.processingtogether.com/sp/pad/export/ro.91kLmk61vAOZp/latest

    class Bullet {
      static final short VEL = 5, DIM = 4, FREQ = 2;
      static final color COLOUR = #0000FF;
    
      final PVector pos = new PVector(), spd = new PVector();
      boolean isInactive;
    
      Bullet(PVector loc, PVector vel) {
        rez(loc, vel);
      }
    
      void rez(PVector loc, PVector vel) {
        pos.set(loc);
        spd.set(vel);
    
        isInactive = false;
      }
    
      void display() {
        ellipse(pos.x, pos.y, DIM, DIM);
      }
    
      void update() {
        pos.add(spd);
      }
    
      boolean check() {
        return pos.x > width | pos.x < 0 | pos.y > height | pos.y < 0;
      }
    
      boolean script() {
        if (isInactive)  return false;
    
        display();
        update();
    
        return isInactive = check();
      }
    }
    

    And in order to find correct pos & spd vectors to instantiate a Bullet, we need a function like the 1 below:

    void addBullet() {
      bulletSpd.set(mouseX, mouseY);
      bulletSpd.sub(playerPos);
      bulletSpd.setMag(Bullet.VEL);
    
      bullets.add(new Bullet(playerPos, bulletSpd));
    }
    

    Variable playerPos is the Ship's PVector coordinates.
    While bulletSpd is a helper PVector in which we calculate direction/speed.

    Only diff. is that in your case, target coordinates aren't (mouseX, mouseY) pair.
    Perhaps it's something like (playerPos.x, height)? :-??

  • I posted that in the other thread,,,,

    why start a new one?

  • by now you have three parallel threads for one sketch,,,

    http://forum.processing.org/two/discussion/comment/12043#Comment_12043

  • edited March 2014

    :-(

  • and we can't run the code, because we don't have the image

  • why does the ship rotate so strange?

    like on a circle left and right

    do you want to have the shooting from the ship towards the current mouse pos or always north? if the latter: North or south or what?

  • you have speed in class bullets but not in use - why?

  • You need to improve the Bullet class so that the bullets have their own velocity too. Here I've added some logic that sets them to the ship's velocity - this is probably NOT what you want. Instead, you'll want to base the direction they go off which way (that is, the angle at) the ship is turned - myShip.a.

    class Bullet//bullet class
    {
      float x;
      float y;
      float vx, vy;
      float speed;
      Bullet(float ignored1, float ignored2)
      {  
        x = myShip.position.x;
        y = myShip.position.y;
        vx = myShip.velocity.x;
        vy = myShip.velocity.y;
      }
      void display()
      {
        stroke(0);
        fill(255, 0, 0);
        ellipse(x, y, 5, 5);
      }
      void move()
      {
        x+=vx;
        y+=vy;
      }
    }
    
  • this fires towards mouse, no matter what the ship does

    //Array of intergers, which is used to draw the land
    int[] land;
    
    //Where the bullets will be stored 
    ArrayList <Bullet> bullets; 
    
    //Game state 
    int WAITING =1;
    int FINISHED =2;
    int state = WAITING;
    
    Ship myShip;
    
    
    void setup() {
      size(600, 600);
    
      myShip = new Ship();
      bullets = new ArrayList();
      //Bullet b = new Bullet(X, Y);
    
      //This will be used to draw the land 
      land = new int [width/10+1];
      for (int i=0; i < land.length; i++) {
        land[i] = int( random(10));
      }
    }
    
    
    void draw() {
    
      background(155);
    
      //adding the method to draw
      //myShip.keyPressed();
      drawland();
      myShip.update();
      myShip.drawFinished();
      moveAll();
      displayAll();
    
    
      //Checks the state variable it also adds the drawWaiting() method that 
      //get called in the coressponding state
      if (state == WAITING) {
        drawWaiting();
      }
      else if (state == FINISHED) {
      }
    }
    
    
    void drawWaiting() {
    
      textAlign(CENTER);
      fill(0);
      text("Click to play!", width/2, height/2);
    }
    
    void drawland() {
    
      stroke(0);
      fill(250, 150, 0, 60); 
      //
      //Creates the land using beginShape and endShape
      beginShape();
      vertex(0, height);
      for ( int i=0; i < land.length; i++) {
        vertex( i * 10, height - 50 - land[i] );
      } 
      vertex(width, height);
      endShape(CLOSE);
    }
    
    //Mouse clicked method that changes the state from waiting to finished
    void mousePressed() {
    
      if (state == WAITING) {
        state = FINISHED;
      }
      else 
      {
    
        // fire 
        Bullet temp = new Bullet(myShip.position.x, myShip.position.y);
        bullets.add(temp);
      }
    } 
    
    
    void keyPressed() {
    
      if ( keyCode == LEFT ) {
        myShip.a -= 0.09;
      }
      if ( keyCode == RIGHT ) {
        myShip.a += 0.09;
      }
    
      if ( keyCode == UP ) {
        myShip.acc += 0.04;
    
        myShip.accel.x = myShip.acc * sin(myShip.a); // ???????????????????
        myShip.accel.y = -myShip.acc * cos(myShip.a);
      }
    
    
      if (keyCode == ' ') {
    
        //I have used myShip because its outside the class and because I used PVector 
        //for my position I have to use that too. 
    
    
    
    
    
    
        Bullet temp = new Bullet(myShip.position.x, myShip.position.y);
        bullets.add(temp);
      }
    }
    
    
    // ====================================================
    
    
    class Bullet  
    //  bullet class
    {
      float x;
      float y;
    
      PVector  bulletSpd = new PVector();
    
      Bullet(float tx, float ty)
      {  
        x = tx;
        y = ty;
    
        bulletSpd.set(mouseX, mouseY);
        bulletSpd.sub( myShip.position );
        bulletSpd.setMag(6);
    
        // bullets.add(new Bullet(playerPos, bulletSpd));  // ???????????
      }
    
      void display()
      {
        stroke(0);
        fill(255, 0, 0);
        ellipse(x, y, 5, 5);
      }
    
      void move()
      {
        x += bulletSpd.x;
        y += bulletSpd.y;
      }
      //
    } // class
    
    // ===============================================
    
    
    void moveAll()
    {
      for (Bullet temp : bullets)
      {
        temp.move();
      }
    }
    
    void displayAll()
    {
      for (Bullet temp : bullets)
      {
        temp.display();
      }
    }
    
    // ====================================================
    
    class Ship {
    
      //Global Variables
      PVector position;
      PVector accel;
      PVector velocity;
      PVector rotation;
      float drag = .9;
      //Ship image
      PImage ship = loadImage("ship.png");
    
    
    
      //How much the ship accelerates 
      float acc = 0;
    
      //rotation angle
      float a = 0;
    
    
      //CONSTRUCTOR
      public Ship() {
    
        position = new PVector(330, 445);
        accel = new PVector(0, 0);
        velocity = new PVector(0, 0);
      }
    
      //FUNCTIONS
      void update() {
    
        drawShip();
        drawFinished();
        velocity.add(accel);
        velocity.mult(drag);
        position.add(velocity);
    
        acc *= 0.95;
    
        //Stops the ship when it reaches the surface 
        if (position.y > height - 20 - ship.height/2 ) {
          position.y = height - 20 - ship.height/2;
        }
      }
    
    
      void drawShip() {
        pushMatrix();
        //method to use the new pos variable
        translate(position.x, position.y);
        rotate(a);
        stroke(255, 50, 0);
        fill(255, 50, 20);
    
        for ( int i=4; i >= 0; i--) {
          stroke(255, i*50, 0);
          fill(255, i*50, 20);
          ellipse( 0, 40, min(1, acc*10) *i*4, min(1, acc*10)* i*10);
        }
        image(ship, -ship.width/2, -ship.height/2, ship.width, ship.height);
        // text ("ship", -300/2, -200/2);
        popMatrix();
      }
    
      void drawFinished() {
    
        textAlign(CENTER);
        fill(0);
        if (position.y > height - 50 - ship.height/2 ) {
    
    
          text("you have crashed!", width/2, height/2);
        }
      }
    }
    
  • this fires always to the left but from the top of the ship

    //Array of intergers, which is used to draw the land
    int[] land;
    
    //Where the bullets will be stored 
    ArrayList <Bullet> bullets; 
    
    //Game state 
    int WAITING =1;
    int FINISHED =2;
    int state = WAITING;
    
    Ship myShip;
    
    
    void setup() {
      size(600, 600);
    
      myShip = new Ship();
      bullets = new ArrayList();
      //Bullet b = new Bullet(X, Y);
    
      //This will be used to draw the land 
      land = new int [width/10+1];
      for (int i=0; i < land.length; i++) {
        land[i] = int( random(10));
      }
    }
    
    
    void draw() {
    
      background(155);
    
      //adding the method to draw
      //myShip.keyPressed();
      drawland();
      myShip.update();
      myShip.drawFinished();
      moveAll();
      displayAll();
    
    
      //Checks the state variable it also adds the drawWaiting() method that 
      //get called in the coressponding state
      if (state == WAITING) {
        drawWaiting();
      }
      else if (state == FINISHED) {
        // do nothing
      }
    }
    
    
    void drawWaiting() {
    
      textAlign(CENTER);
      fill(0);
      text("Click to play!", width/2, height/2);
    }
    
    void drawland() {
    
      stroke(0);
      fill(250, 150, 0, 60); 
      //
      //Creates the land using beginShape and endShape
      beginShape();
      vertex(0, height);
      for ( int i=0; i < land.length; i++) {
        vertex( i * 10, height - 50 - land[i] );
      } 
      vertex(width, height);
      endShape(CLOSE);
    }
    
    //Mouse clicked method that changes the state from waiting to finished
    void mousePressed() {
    
      if (state == WAITING) {
        state = FINISHED;
      }
      else 
      {
        // do nothing
      }
    } 
    
    
    void keyPressed() {
    
      if ( keyCode == LEFT ) {
        myShip.a -= 0.09;
      }
      if ( keyCode == RIGHT ) {
        myShip.a += 0.09;
      }
    
      if ( keyCode == UP ) {
        myShip.acc += 0.04;
    
        myShip.accel.x = myShip.acc * sin(myShip.a); // ???????????????????
        myShip.accel.y = -myShip.acc * cos(myShip.a);
      }
    
    
      if (keyCode == ' ') {
    
        //I have used myShip because its outside the class and because I used PVector 
        //for my position I have to use that too. 
        //
        final PVector bulletSpd = new PVector();
        bulletSpd.set(3, 0);
        //bulletSpd.sub(position);
        bulletSpd.normalize();
        bulletSpd.mult(5);
    
        PVector positionbullet = new PVector();
    
        positionbullet.x = -(myShip.ship.height-25) * cos ((myShip.a)) + myShip.position.x;
        positionbullet.y = -(myShip.ship.height-25) * sin ((myShip.a)) + myShip.position.y;
    
        bullets.add( new Bullet(positionbullet, bulletSpd) );
      }
    }
    
    
    // ====================================================
    
    
    class Bullet  
    //  bullet class
    {
      float x;
      float y;
    
      PVector  bulletSpd = new PVector();
    
      Bullet(PVector pos1, PVector spd1)
      {  
        x = pos1.x;
        y = pos1.y;
    
        bulletSpd =   spd1.get();
    
        // bullets.add(new Bullet(playerPos, bulletSpd));  // ???????????
      }
    
      void display()
      {
        stroke(0);
        fill(255, 0, 0);
        ellipse(x, y, 5, 5);
      }
    
      void move()
      {
        x += bulletSpd.x;
        y += bulletSpd.y;
      }
      //
    } // class
    
    // ===============================================
    
    
    void moveAll()
    {
      for (Bullet temp : bullets)
      {
        temp.move();
      }
    }
    
    void displayAll()
    {
      for (Bullet temp : bullets)
      {
        temp.display();
      }
    }
    
    // ====================================================
    
    class Ship {
    
      //Global Variables
      PVector position;
      PVector accel;
      PVector velocity;
      PVector rotation;
      float drag = .9;
      //Ship image
      PImage ship = loadImage("ship.png");
    
    
    
      //How much the ship accelerates 
      float acc = 0;
    
      //rotation angle
      float a = 0;
    
    
      //CONSTRUCTOR
      public Ship() {
    
        position = new PVector(330, 445);
        accel = new PVector(0, 0);
        velocity = new PVector(0, 0);
      }
    
      //FUNCTIONS
      void update() {
    
        drawShip();
        drawFinished();
        velocity.add(accel);
        velocity.mult(drag);
        position.add(velocity);
    
        acc *= 0.95;
    
        //Stops the ship when it reaches the surface 
        if (position.y > height - 20 - ship.height/2 ) {
          position.y = height - 20 - ship.height/2;
        }
      }
    
    
      void drawShip() {
        pushMatrix();
        //method to use the new pos variable
        translate(position.x, position.y);
        rotate(a);
        stroke(255, 50, 0);
        fill(255, 50, 20);
    
        for ( int i=4; i >= 0; i--) {
          stroke(255, i*50, 0);
          fill(255, i*50, 20);
          ellipse( 0, 40, min(1, acc*10) *i*4, min(1, acc*10)* i*10);
        }
        image(ship, -ship.width/2, -ship.height/2, ship.width, ship.height);
        // text ("ship", -300/2, -200/2);
        popMatrix();
      }
    
      void drawFinished() {
    
        textAlign(CENTER);
        fill(0);
        if (position.y > height - 50 - ship.height/2 ) {
    
    
          text("you have crashed!", width/2, height/2);
        }
      }
    }
    
  • this fires from the top of the ship

    towards the direction of the ship

    I like this the most

    //Array of intergers, which is used to draw the land
    int[] land;
    
    //Where the bullets will be stored 
    ArrayList <Bullet> bullets; 
    
    //Game state 
    int WAITING =1;
    int FINISHED =2;
    int state = WAITING;
    
    Ship myShip;
    
    
    void setup() {
      size(600, 600);
    
      myShip = new Ship();
      bullets = new ArrayList();
      //Bullet b = new Bullet(X, Y);
    
      //This will be used to draw the land 
      land = new int [width/10+1];
      for (int i=0; i < land.length; i++) {
        land[i] = int( random(10));
      }
    }
    
    
    void draw() {
    
      background(155);
    
      //adding the method to draw
      //myShip.keyPressed();
      drawland();
      myShip.update();
      myShip.drawFinished();
      moveAll();
      displayAll();
    
    
      //Checks the state variable it also adds the drawWaiting() method that 
      //get called in the coressponding state
      if (state == WAITING) {
        drawWaiting();
      }
      else if (state == FINISHED) {
        // do nothing
      }
    }
    
    
    void drawWaiting() {
    
      textAlign(CENTER);
      fill(0);
      text("Click to play!", width/2, height/2);
    }
    
    void drawland() {
    
      stroke(0);
      fill(250, 150, 0, 60); 
      //
      //Creates the land using beginShape and endShape
      beginShape();
      vertex(0, height);
      for ( int i=0; i < land.length; i++) {
        vertex( i * 10, height - 50 - land[i] );
      } 
      vertex(width, height);
      endShape(CLOSE);
    }
    
    //Mouse clicked method that changes the state from waiting to finished
    void mousePressed() {
    
      if (state == WAITING) {
        state = FINISHED;
      }
      else 
      {
        // do nothing
      }
    } 
    
    
    void keyPressed() {
    
      if ( keyCode == LEFT ) {
        myShip.a -= 0.09;
      }
      if ( keyCode == RIGHT ) {
        myShip.a += 0.09;
      }
    
      if ( keyCode == UP ) {
        myShip.acc += 0.04;
    
        myShip.accel.x = myShip.acc * sin(myShip.a); // ???????????????????
        myShip.accel.y = -myShip.acc * cos(myShip.a);
      }
    
    
      if (keyCode == ' ') {
    
        //I have used myShip because its outside the class and because I used PVector 
        //for my position I have to use that too. 
        //
        PVector bulletSpd = new PVector();
        bulletSpd.set(3, 0);
        //bulletSpd.sub(position);
        bulletSpd.normalize();
        bulletSpd.mult(5);
    
        PVector positionbullet = new PVector();
    
        positionbullet.x = -(myShip.ship.height-25) * cos ((myShip.a)) + myShip.position.x;
        positionbullet.y = -(myShip.ship.height-25) * sin ((myShip.a)) + myShip.position.y;
    
    
        bulletSpd.x = - (myShip.ship.height+25) * cos ((myShip.a)) + positionbullet.x;
        bulletSpd.y = - (myShip.ship.height+25) * sin ((myShip.a)) + positionbullet.y;
    
    
        bulletSpd.sub(positionbullet);
    
        //bulletSpd = positionbullet.get(); 
        bulletSpd.normalize();
        bulletSpd.mult(5);
    
    
        bullets.add( new Bullet(positionbullet, bulletSpd) );
      }
    }
    
    
    // ====================================================
    
    
    class Bullet  
    //  bullet class
    {
      float x;
      float y;
    
      PVector  bulletSpd = new PVector();
    
      Bullet(PVector pos1, PVector spd1)
      {  
        x = pos1.x;
        y = pos1.y;
    
        bulletSpd =   spd1.get();
    
        // bullets.add(new Bullet(playerPos, bulletSpd));  // ???????????
      }
    
      void display()
      {
        stroke(0);
        fill(255, 0, 0);
        ellipse(x, y, 5, 5);
      }
    
      void move()
      {
        x += bulletSpd.x;
        y += bulletSpd.y;
      }
      //
    } // class
    
    // ===============================================
    
    
    void moveAll()
    {
      for (Bullet temp : bullets)
      {
        temp.move();
      }
    }
    
    void displayAll()
    {
      for (Bullet temp : bullets)
      {
        temp.display();
      }
    }
    
    // ====================================================
    
    class Ship {
    
      //Global Variables
      PVector position;
      PVector accel;
      PVector velocity;
      PVector rotation;
      float drag = .9;
      //Ship image
      PImage ship = loadImage("ship.png");
    
    
    
      //How much the ship accelerates 
      float acc = 0;
    
      //rotation angle
      float a = 0;
    
    
      //CONSTRUCTOR
      public Ship() {
    
        position = new PVector(330, 445);
        accel = new PVector(0, 0);
        velocity = new PVector(0, 0);
      }
    
      //FUNCTIONS
      void update() {
    
        drawShip();
        drawFinished();
        velocity.add(accel);
        velocity.mult(drag);
        position.add(velocity);
    
        acc *= 0.95;
    
        //Stops the ship when it reaches the surface 
        if (position.y > height - 20 - ship.height/2 ) {
          position.y = height - 20 - ship.height/2;
        }
      }
    
    
      void drawShip() {
        pushMatrix();
        //method to use the new pos variable
        translate(position.x, position.y);
        rotate(a);
        stroke(255, 50, 0);
        fill(255, 50, 20);
    
        for ( int i=4; i >= 0; i--) {
          stroke(255, i*50, 0);
          fill(255, i*50, 20);
          ellipse( 0, 40, min(1, acc*10) *i*4, min(1, acc*10)* i*10);
        }
        image(ship, -ship.width/2, -ship.height/2, ship.width, ship.height);
        // text ("ship", -300/2, -200/2);
        popMatrix();
      }
    
      void drawFinished() {
    
        textAlign(CENTER);
        fill(0);
        if (position.y > height - 50 - ship.height/2 ) {
    
    
          text("you have crashed!", width/2, height/2);
        }
      }
    }
    
  • Hey, I like the last code better but it fires the bullets from the left side not the top of the Ship. How can I change the starting point of the bullets?

    Screen Shot 2014-03-14 at 12.35.01

  • Answer ✓

    Lines 175 following

  • I got it to work, thanks anyway

  • congrats!

Sign In or Register to comment.