finish refactoring
This commit is contained in:
		@@ -106,29 +106,25 @@ public class Bird extends HasPosition {
 | 
			
		||||
	/**
 | 
			
		||||
	 * Bird movement during the game
 | 
			
		||||
	 */
 | 
			
		||||
	public void inGameBorders () {
 | 
			
		||||
		// If the bird did not hit the base, lower it
 | 
			
		||||
		if (y < BASE_COLLISION) {
 | 
			
		||||
			// Change and velocity
 | 
			
		||||
			velocity += gravity;
 | 
			
		||||
	public void moveBird() {
 | 
			
		||||
		// Change and velocity
 | 
			
		||||
		velocity += gravity;
 | 
			
		||||
 | 
			
		||||
			// Lower delay if possible
 | 
			
		||||
			if (delay > 0) { delay--; }
 | 
			
		||||
		// Lower delay if possible
 | 
			
		||||
		if (delay > 0) { delay--; }
 | 
			
		||||
 | 
			
		||||
			// Add rounded velocity to y-coordinate
 | 
			
		||||
			y += (int) velocity;
 | 
			
		||||
		} else {
 | 
			
		||||
			// Play audio and set state to dead
 | 
			
		||||
			FlappyBird.audio.hit();
 | 
			
		||||
			isAlive = false;
 | 
			
		||||
		}
 | 
			
		||||
		// Add rounded velocity to y-coordinate
 | 
			
		||||
		y += (int) velocity;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	public boolean collidesWithBase() {
 | 
			
		||||
		return y >= BASE_COLLISION;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Renders bird
 | 
			
		||||
	 */
 | 
			
		||||
	public void renderBird (Graphics g) {
 | 
			
		||||
	public void paintBird(Graphics g) {
 | 
			
		||||
		// Calculate angle to rotate bird based on y-velocity
 | 
			
		||||
        double rotation = ((90 * (velocity + 25) / 25) - 90) * Math.PI / 180;
 | 
			
		||||
		
 | 
			
		||||
 
 | 
			
		||||
@@ -23,6 +23,9 @@ public class GamePanel extends JPanel implements KeyListener, MouseListener {
 | 
			
		||||
	// Store point when player clicks
 | 
			
		||||
	protected Point clickedPoint = new Point(-1, -1);
 | 
			
		||||
 | 
			
		||||
	// Background
 | 
			
		||||
	protected static int[] backgroundPosition = { 0, 435 };
 | 
			
		||||
 | 
			
		||||
	public GamePanel () {
 | 
			
		||||
		setGameState(new MenuState(this));
 | 
			
		||||
 | 
			
		||||
@@ -50,16 +53,49 @@ public class GamePanel extends JPanel implements KeyListener, MouseListener {
 | 
			
		||||
	/**
 | 
			
		||||
	 * To start game after everything has been loaded
 | 
			
		||||
	 */
 | 
			
		||||
	@Override
 | 
			
		||||
	public void addNotify() {
 | 
			
		||||
		super.addNotify();
 | 
			
		||||
		requestFocusInWindow(); // Ensures the panel gains focus
 | 
			
		||||
		requestFocusInWindow();
 | 
			
		||||
		ready = true;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	public void moveBase(Graphics g) {
 | 
			
		||||
		// Set font and color
 | 
			
		||||
		g.setFont(FlappyBird.flappyFontReal);
 | 
			
		||||
		g.setColor(Color.white);
 | 
			
		||||
 | 
			
		||||
		// Only move screen if bird is alive
 | 
			
		||||
		if (GameState.gameBird.isAlive()) {
 | 
			
		||||
			// Move base
 | 
			
		||||
			// Moving base effect
 | 
			
		||||
			int baseSpeed = 2;
 | 
			
		||||
			backgroundPosition[0] = backgroundPosition[0] - baseSpeed < -435 ? 435 : backgroundPosition[0] - baseSpeed;
 | 
			
		||||
			backgroundPosition[1] = backgroundPosition[1] - baseSpeed < -435 ? 435 : backgroundPosition[1] - baseSpeed;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// Background
 | 
			
		||||
		g.drawImage(FlappyBird.darkTheme ? FlappyBird.textures.get("background2").getImage() :
 | 
			
		||||
				FlappyBird.textures.get("background1").getImage(), 0, 0, null);
 | 
			
		||||
 | 
			
		||||
		// Draw bird
 | 
			
		||||
		GameState.gameBird.paintBird(g);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Needs to be called differently based on screen
 | 
			
		||||
	 */
 | 
			
		||||
	public void paintBase(Graphics g) {
 | 
			
		||||
		// Moving base effect
 | 
			
		||||
		g.drawImage(FlappyBird.textures.get("base").getImage(), backgroundPosition[0], FlappyBird.textures.get("base").getY(), null);
 | 
			
		||||
		g.drawImage(FlappyBird.textures.get("base").getImage(), backgroundPosition[1], FlappyBird.textures.get("base").getY(), null);
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@Override
 | 
			
		||||
	public void paintComponent (Graphics g) {
 | 
			
		||||
	public void paintComponent(Graphics g) {
 | 
			
		||||
		super.paintComponent(g);
 | 
			
		||||
		gameState.renderGameState(g);
 | 
			
		||||
		gameState.paintGameState(g);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	//////////////////////
 | 
			
		||||
 
 | 
			
		||||
@@ -27,13 +27,13 @@ public class Pipe extends HasPosition {
 | 
			
		||||
	// If the bird can get a point passing this pipe
 | 
			
		||||
	public boolean canAwardPoint = true;
 | 
			
		||||
 | 
			
		||||
	public Pipe (String location) {
 | 
			
		||||
	public Pipe(String location) {
 | 
			
		||||
		super(FlappyBird.WIDTH + 5, 0);
 | 
			
		||||
		this.location = location;
 | 
			
		||||
		reset();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	public void reset () {
 | 
			
		||||
	public void reset() {
 | 
			
		||||
		super.x = FlappyBird.WIDTH + 5; // Reset x-coordinate
 | 
			
		||||
 | 
			
		||||
		// Set boundaries for top pipes
 | 
			
		||||
@@ -46,7 +46,7 @@ public class Pipe extends HasPosition {
 | 
			
		||||
	/**
 | 
			
		||||
	 * Moves the pipe
 | 
			
		||||
	 */
 | 
			
		||||
	public void move () {
 | 
			
		||||
	public void move() {
 | 
			
		||||
		super.x += SPEED;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
@@ -55,7 +55,7 @@ public class Pipe extends HasPosition {
 | 
			
		||||
	 * @param  bird The bird.
 | 
			
		||||
	 * @return If bird is colliding with the pipe
 | 
			
		||||
	 */
 | 
			
		||||
	public boolean collide (Bird bird) {
 | 
			
		||||
	public boolean collide(Bird bird) {
 | 
			
		||||
		// Do not allow bird to jump over pipe
 | 
			
		||||
		if (bird.getX() > super.x && bird.getY() < 0 && canAwardPoint) {
 | 
			
		||||
			return true;
 | 
			
		||||
@@ -71,7 +71,7 @@ public class Pipe extends HasPosition {
 | 
			
		||||
	 * Set's pipe's y-coordinate (for bottom pipes)
 | 
			
		||||
	 * @param newY New y-coordinate
 | 
			
		||||
	 */
 | 
			
		||||
	public void setY (int newY) {
 | 
			
		||||
	public void setY(int newY) {
 | 
			
		||||
		y = newY;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -135,7 +135,7 @@ public class Sprites {
 | 
			
		||||
	 * 
 | 
			
		||||
	 * @return     Texture
 | 
			
		||||
	 */
 | 
			
		||||
	public HashMap<String, Texture> getGameTextures () {
 | 
			
		||||
	public HashMap<String, Texture> getGameTextures() {
 | 
			
		||||
		return textures;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -17,9 +17,6 @@ public abstract class GameState {
 | 
			
		||||
	// Game variables //
 | 
			
		||||
	////////////////////
 | 
			
		||||
 | 
			
		||||
	// Background
 | 
			
		||||
	protected static final int[] baseCoords = { 0, 435 };
 | 
			
		||||
 | 
			
		||||
	// Player score
 | 
			
		||||
	protected int score;
 | 
			
		||||
 | 
			
		||||
@@ -33,7 +30,7 @@ public abstract class GameState {
 | 
			
		||||
	public static ArrayList<Pipe> pipes;
 | 
			
		||||
 | 
			
		||||
	// Game bird
 | 
			
		||||
	protected static Bird gameBird;
 | 
			
		||||
	public static Bird gameBird;
 | 
			
		||||
 | 
			
		||||
	// Game panel
 | 
			
		||||
	public GamePanel gamePanel;
 | 
			
		||||
@@ -46,7 +43,6 @@ public abstract class GameState {
 | 
			
		||||
	 * Restarts game by resetting game variables
 | 
			
		||||
	 */
 | 
			
		||||
	public void restart () {
 | 
			
		||||
 | 
			
		||||
		// Reset game statistics
 | 
			
		||||
		score = 0;
 | 
			
		||||
		pipeDistTracker = 0;
 | 
			
		||||
@@ -59,41 +55,7 @@ public abstract class GameState {
 | 
			
		||||
		pipes = new ArrayList<Pipe>();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	public void prepareScreen(Graphics g) {
 | 
			
		||||
		// Set font and color
 | 
			
		||||
		g.setFont(FlappyBird.flappyFontReal);
 | 
			
		||||
		g.setColor(Color.white);
 | 
			
		||||
 | 
			
		||||
		// Only move screen if bird is alive
 | 
			
		||||
		if (gameBird.isAlive()) {
 | 
			
		||||
			// Move base
 | 
			
		||||
			// Moving base effect
 | 
			
		||||
			int baseSpeed = 2;
 | 
			
		||||
			baseCoords[0] = baseCoords[0] - baseSpeed < -435 ? 435 : baseCoords[0] - baseSpeed;
 | 
			
		||||
			baseCoords[1] = baseCoords[1] - baseSpeed < -435 ? 435 : baseCoords[1] - baseSpeed;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// Background
 | 
			
		||||
		g.drawImage(FlappyBird.darkTheme ? FlappyBird.textures.get("background2").getImage() :
 | 
			
		||||
				FlappyBird.textures.get("background1").getImage(), 0, 0, null);
 | 
			
		||||
 | 
			
		||||
		// Draw bird
 | 
			
		||||
		gameBird.renderBird(g);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	public abstract void renderGameState(Graphics g);
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Needs to be called differently based on screen
 | 
			
		||||
	 */
 | 
			
		||||
	public void drawBase (Graphics g) {
 | 
			
		||||
 | 
			
		||||
		// Moving base effect
 | 
			
		||||
		g.drawImage(FlappyBird.textures.get("base").getImage(), baseCoords[0], FlappyBird.textures.get("base").getY(), null);
 | 
			
		||||
		g.drawImage(FlappyBird.textures.get("base").getImage(), baseCoords[1], FlappyBird.textures.get("base").getY(), null);
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	public abstract void paintGameState(Graphics g);
 | 
			
		||||
	public abstract void handleKeyboardEvent(KeyEvent e);
 | 
			
		||||
	public abstract void handleMouseEvent(MouseEvent e);
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -14,32 +14,16 @@ public class MenuState extends GameState {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void renderGameState(Graphics g) {
 | 
			
		||||
        prepareScreen(g);
 | 
			
		||||
    public void paintGameState(Graphics g) {
 | 
			
		||||
        gamePanel.moveBase(g);
 | 
			
		||||
        gamePanel.paintBase(g);
 | 
			
		||||
 | 
			
		||||
        drawBase(g);
 | 
			
		||||
        drawMenu(g);
 | 
			
		||||
        paintMenu(g);
 | 
			
		||||
 | 
			
		||||
        gameBird.menuFloat();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Draws a string centered based on given restrictions
 | 
			
		||||
     *
 | 
			
		||||
     * @param s     String to be drawn
 | 
			
		||||
     * @param w     Constraining width
 | 
			
		||||
     * @param h     Constraining height
 | 
			
		||||
     * @param y     Fixed y-coordinate
 | 
			
		||||
     */
 | 
			
		||||
    public void drawCentered (String s, int w, int h, int y, Graphics g) {
 | 
			
		||||
        FontMetrics fm = g.getFontMetrics();
 | 
			
		||||
 | 
			
		||||
        // Calculate x-coordinate based on string length and width
 | 
			
		||||
        int x = (w - fm.stringWidth(s)) / 2;
 | 
			
		||||
        g.drawString(s, x, y);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected void drawMenu (Graphics g) {
 | 
			
		||||
    protected void paintMenu(Graphics g) {
 | 
			
		||||
        // Title
 | 
			
		||||
        g.drawImage(FlappyBird.textures.get("titleText").getImage(),
 | 
			
		||||
                FlappyBird.textures.get("titleText").getX(),
 | 
			
		||||
@@ -57,15 +41,29 @@ public class MenuState extends GameState {
 | 
			
		||||
                FlappyBird.textures.get("rateButton").getY(), null);
 | 
			
		||||
 | 
			
		||||
        // Credits :p
 | 
			
		||||
        drawCentered("Created by Paul Krishnamurthy", FlappyBird.WIDTH, FlappyBird.HEIGHT, 600, g);
 | 
			
		||||
        paintCenteredText("Created by Paul Krishnamurthy", 600, g);
 | 
			
		||||
        g.setFont(FlappyBird.flappyMiniFont); // Change font
 | 
			
		||||
        drawCentered("www.PaulKr.com", FlappyBird.WIDTH, FlappyBird.HEIGHT, 630, g);
 | 
			
		||||
        paintCenteredText("www.PaulKr.com", 630, g);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Draws a string centered based on given restrictions
 | 
			
		||||
     *
 | 
			
		||||
     * @param text String to be drawn
 | 
			
		||||
     * @param yPos Fixed y-coordinate
 | 
			
		||||
     */
 | 
			
		||||
    protected void paintCenteredText(String text, int yPos, Graphics g) {
 | 
			
		||||
        FontMetrics fm = g.getFontMetrics();
 | 
			
		||||
 | 
			
		||||
        // Calculate x-coordinate based on string length and width
 | 
			
		||||
        int x = (FlappyBird.WIDTH - fm.stringWidth(text)) / 2;
 | 
			
		||||
        g.drawString(text, x, yPos);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Tries to open the review url in default web browser
 | 
			
		||||
     */
 | 
			
		||||
    public void openReviewUrl() {
 | 
			
		||||
    protected void openReviewUrl() {
 | 
			
		||||
        try {
 | 
			
		||||
            if (Desktop.isDesktopSupported()) {
 | 
			
		||||
                Desktop.getDesktop().browse(new URI("http://paulkr.com"));
 | 
			
		||||
 
 | 
			
		||||
@@ -1,9 +1,6 @@
 | 
			
		||||
package com.example.flappybird.states;
 | 
			
		||||
 | 
			
		||||
import com.example.flappybird.FlappyBird;
 | 
			
		||||
import com.example.flappybird.GamePanel;
 | 
			
		||||
import com.example.flappybird.Highscore;
 | 
			
		||||
import com.example.flappybird.Pipe;
 | 
			
		||||
import com.example.flappybird.*;
 | 
			
		||||
 | 
			
		||||
import javax.swing.*;
 | 
			
		||||
import java.awt.*;
 | 
			
		||||
@@ -23,7 +20,42 @@ public class PlayState extends GameState {
 | 
			
		||||
        super(panel);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void startGameScreen (Graphics g) {
 | 
			
		||||
    @Override
 | 
			
		||||
    public void paintGameState(Graphics g) {
 | 
			
		||||
        gamePanel.moveBase(g);
 | 
			
		||||
 | 
			
		||||
        if (gameBird.isAlive()) {
 | 
			
		||||
            // Start at instructions state
 | 
			
		||||
            if (inStartGameState) {
 | 
			
		||||
                paintStartScreen(g);
 | 
			
		||||
            }
 | 
			
		||||
            else {
 | 
			
		||||
                // Start game
 | 
			
		||||
                movePipes(g);
 | 
			
		||||
                gameBird.moveBird();
 | 
			
		||||
                if(gameBird.collidesWithBase()) {
 | 
			
		||||
                    // Play audio and set state to dead
 | 
			
		||||
                    gameBird.killBird();
 | 
			
		||||
                    FlappyBird.audio.hit();
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // Draw base over pipes
 | 
			
		||||
            gamePanel.paintBase(g);
 | 
			
		||||
 | 
			
		||||
            // Draw player score
 | 
			
		||||
            paintScore(g, score, false, 0, 0);
 | 
			
		||||
        }
 | 
			
		||||
        else {
 | 
			
		||||
            movePipes(g);
 | 
			
		||||
            gamePanel.paintBase(g);
 | 
			
		||||
 | 
			
		||||
            // Draw game over assets
 | 
			
		||||
            paintScoreBoard(g);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected void paintStartScreen(Graphics g) {
 | 
			
		||||
        // Set bird's new position
 | 
			
		||||
        gameBird.setGameStartPos();
 | 
			
		||||
 | 
			
		||||
@@ -44,9 +76,9 @@ public class PlayState extends GameState {
 | 
			
		||||
     * @param mini Boolean for drawing small or large numbers
 | 
			
		||||
     * @param x X-coordinate to draw for mini numbers
 | 
			
		||||
     */
 | 
			
		||||
    public void drawScore (Graphics g, int drawNum, boolean mini, int x, int y) {
 | 
			
		||||
    public void paintScore(Graphics g, int drawNum, boolean mini, int x, int y) {
 | 
			
		||||
        // Char array of digits
 | 
			
		||||
        char[] digits = ("" + drawNum).toCharArray();
 | 
			
		||||
        char[] digits = (String.valueOf(drawNum)).toCharArray();
 | 
			
		||||
 | 
			
		||||
        // Calculate width for numeric textures
 | 
			
		||||
        int takeUp = 0;
 | 
			
		||||
@@ -65,7 +97,8 @@ public class PlayState extends GameState {
 | 
			
		||||
 | 
			
		||||
        // Draw every digit
 | 
			
		||||
        for (char digit : digits) {
 | 
			
		||||
            g.drawImage(FlappyBird.textures.get((mini ? "mini-score-" : "score-") + digit).getImage(), drawScoreX, (mini ? y : 60), null);
 | 
			
		||||
            Texture texture = FlappyBird.textures.get((mini ? "mini-score-" : "score-") + digit);
 | 
			
		||||
            g.drawImage(texture.getImage(), drawScoreX, (mini ? y : 60), null);
 | 
			
		||||
 | 
			
		||||
            // Size to add varies based on texture
 | 
			
		||||
            if (mini) {
 | 
			
		||||
@@ -79,7 +112,7 @@ public class PlayState extends GameState {
 | 
			
		||||
    /**
 | 
			
		||||
     * Moves and repositions pipes
 | 
			
		||||
     */
 | 
			
		||||
    public void pipeHandler (Graphics g) {
 | 
			
		||||
    protected void movePipes(Graphics g) {
 | 
			
		||||
 | 
			
		||||
        // Decrease distance between pipes
 | 
			
		||||
        if (gameBird.isAlive()) {
 | 
			
		||||
@@ -162,8 +195,8 @@ public class PlayState extends GameState {
 | 
			
		||||
                    // Kill bird and play sound
 | 
			
		||||
                    gameBird.killBird();
 | 
			
		||||
                    FlappyBird.audio.hit();
 | 
			
		||||
                } else {
 | 
			
		||||
 | 
			
		||||
                }
 | 
			
		||||
                else {
 | 
			
		||||
                    // Checks if bird passes a pipe
 | 
			
		||||
                    if (gameBird.getX() >= p.getX() + Pipe.WIDTH / 2) {
 | 
			
		||||
 | 
			
		||||
@@ -179,7 +212,7 @@ public class PlayState extends GameState {
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void gameOver (Graphics g) {
 | 
			
		||||
    protected void paintScoreBoard(Graphics g) {
 | 
			
		||||
        // Game over text
 | 
			
		||||
        g.drawImage(FlappyBird.textures.get("gameOverText").getImage(),
 | 
			
		||||
                FlappyBird.textures.get("gameOverText").getX(),
 | 
			
		||||
@@ -198,8 +231,8 @@ public class PlayState extends GameState {
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Draw mini fonts for current and best scores
 | 
			
		||||
        drawScore(g, score, true, 303, 276);
 | 
			
		||||
        drawScore(g, highscore.bestScore(), true, 303, 330);
 | 
			
		||||
        paintScore(g, score, true, 303, 276);
 | 
			
		||||
        paintScore(g, highscore.bestScore(), true, 303, 330);
 | 
			
		||||
 | 
			
		||||
        // Handle highscore
 | 
			
		||||
        if (score > highscore.bestScore()) {
 | 
			
		||||
@@ -231,35 +264,6 @@ public class PlayState extends GameState {
 | 
			
		||||
                FlappyBird.textures.get("leaderboard").getY(), null);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void renderGameState(Graphics g) {
 | 
			
		||||
        prepareScreen(g);
 | 
			
		||||
 | 
			
		||||
        if (gameBird.isAlive()) {
 | 
			
		||||
 | 
			
		||||
            // Start at instructions state
 | 
			
		||||
            if (inStartGameState) {
 | 
			
		||||
                startGameScreen(g);
 | 
			
		||||
 | 
			
		||||
            } else {
 | 
			
		||||
                // Start game
 | 
			
		||||
                pipeHandler(g);
 | 
			
		||||
                gameBird.inGameBorders();
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            drawBase(g);                      // Draw base over pipes
 | 
			
		||||
            drawScore(g, score, false, 0, 0); // Draw player score
 | 
			
		||||
 | 
			
		||||
        } else {
 | 
			
		||||
 | 
			
		||||
            pipeHandler(g);
 | 
			
		||||
            drawBase(g);
 | 
			
		||||
 | 
			
		||||
            // Draw game over assets
 | 
			
		||||
            gameOver(g);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void handleKeyboardEvent(KeyEvent e) {
 | 
			
		||||
        int keyCode = e.getKeyCode();
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user