Add GameDataComponent which holds current game's data (score, lives, etc)
Now more like an actual game. Score, lives, and when you die, you get respawned. If you die rnough times, you Game Over, and your lives and score are reset. Each time you get 10000 points, you gain a life! Add GameMode enum Add GameDataSystem which manipulates the current game data based on events. Add GameDataRenderSystem which renders the current game data. Add AsteroidHitEvent and PlayerDeathEvent which are are fired when an asteroid is destroyed or the player is killed, respectively. Add SpriteBatch to Graphics
This commit is contained in:
parent
c3b806f79f
commit
fa809148a7
@ -17,4 +17,6 @@ public class Constants {
|
|||||||
public static final float ASTEROID_SPAWN_DELAY = 1f;
|
public static final float ASTEROID_SPAWN_DELAY = 1f;
|
||||||
public static final int ASTEROID_SPAWN_COUNT = 4;
|
public static final int ASTEROID_SPAWN_COUNT = 4;
|
||||||
|
|
||||||
|
public static final int NEW_LIFE_SCORE = 10000;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
24
core/src/com/me/asteroids/GameMode.java
Normal file
24
core/src/com/me/asteroids/GameMode.java
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
package com.me.asteroids;
|
||||||
|
|
||||||
|
public enum GameMode {
|
||||||
|
|
||||||
|
PLAYING,
|
||||||
|
DIED(3f),
|
||||||
|
GAME_OVER(4f),
|
||||||
|
;
|
||||||
|
|
||||||
|
private final float modeTimer;
|
||||||
|
|
||||||
|
GameMode() {
|
||||||
|
this(0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
GameMode(float modeTimer) {
|
||||||
|
this.modeTimer = modeTimer;
|
||||||
|
}
|
||||||
|
|
||||||
|
public float getTimer() {
|
||||||
|
return modeTimer;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -4,6 +4,7 @@ import com.badlogic.gdx.Gdx;
|
|||||||
import com.badlogic.gdx.graphics.Camera;
|
import com.badlogic.gdx.graphics.Camera;
|
||||||
import com.badlogic.gdx.graphics.GL20;
|
import com.badlogic.gdx.graphics.GL20;
|
||||||
import com.badlogic.gdx.graphics.OrthographicCamera;
|
import com.badlogic.gdx.graphics.OrthographicCamera;
|
||||||
|
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
|
||||||
import com.badlogic.gdx.graphics.glutils.ShapeRenderer;
|
import com.badlogic.gdx.graphics.glutils.ShapeRenderer;
|
||||||
import com.badlogic.gdx.utils.viewport.FitViewport;
|
import com.badlogic.gdx.utils.viewport.FitViewport;
|
||||||
import com.badlogic.gdx.utils.viewport.Viewport;
|
import com.badlogic.gdx.utils.viewport.Viewport;
|
||||||
@ -17,6 +18,7 @@ public class Graphics {
|
|||||||
private Viewport viewport;
|
private Viewport viewport;
|
||||||
|
|
||||||
private ShapeRenderer shapeRenderer;
|
private ShapeRenderer shapeRenderer;
|
||||||
|
private SpriteBatch spriteBatch;
|
||||||
|
|
||||||
public Graphics(int worldWidth, int worldHeight) {
|
public Graphics(int worldWidth, int worldHeight) {
|
||||||
this.worldWidth = worldWidth;
|
this.worldWidth = worldWidth;
|
||||||
@ -28,6 +30,7 @@ public class Graphics {
|
|||||||
this.viewport = new FitViewport(worldWidth, worldHeight, camera);
|
this.viewport = new FitViewport(worldWidth, worldHeight, camera);
|
||||||
|
|
||||||
this.shapeRenderer = new ShapeRenderer();
|
this.shapeRenderer = new ShapeRenderer();
|
||||||
|
this.spriteBatch = new SpriteBatch();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void initialize() {
|
public void initialize() {
|
||||||
@ -53,6 +56,10 @@ public class Graphics {
|
|||||||
return shapeRenderer;
|
return shapeRenderer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public SpriteBatch getSpriteBatch() {
|
||||||
|
return spriteBatch;
|
||||||
|
}
|
||||||
|
|
||||||
private void updateDimensions() {
|
private void updateDimensions() {
|
||||||
viewport.setWorldSize(worldWidth, worldHeight);
|
viewport.setWorldSize(worldWidth, worldHeight);
|
||||||
viewport.update(screenWidth, screenHeight, true);
|
viewport.update(screenWidth, screenHeight, true);
|
||||||
|
28
core/src/com/me/asteroids/components/GameDataComponent.java
Normal file
28
core/src/com/me/asteroids/components/GameDataComponent.java
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
package com.me.asteroids.components;
|
||||||
|
|
||||||
|
import com.me.asteroids.GameMode;
|
||||||
|
import com.me.common.ecs.Component;
|
||||||
|
|
||||||
|
public class GameDataComponent implements Component {
|
||||||
|
|
||||||
|
public int score;
|
||||||
|
public int lives;
|
||||||
|
public int newLifeScore;
|
||||||
|
|
||||||
|
public GameMode gameMode;
|
||||||
|
public float gameModeTimer;
|
||||||
|
|
||||||
|
public GameDataComponent() {
|
||||||
|
reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void reset() {
|
||||||
|
this.score = 0;
|
||||||
|
this.lives = 3;
|
||||||
|
this.newLifeScore = 0;
|
||||||
|
|
||||||
|
this.gameMode = GameMode.PLAYING;
|
||||||
|
this.gameModeTimer = 0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
14
core/src/com/me/asteroids/events/AsteroidHitEvent.java
Normal file
14
core/src/com/me/asteroids/events/AsteroidHitEvent.java
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
package com.me.asteroids.events;
|
||||||
|
|
||||||
|
import com.me.asteroids.components.AsteroidComponent;
|
||||||
|
import com.me.common.ecs.event.Event;
|
||||||
|
|
||||||
|
public class AsteroidHitEvent extends Event {
|
||||||
|
|
||||||
|
public AsteroidComponent asteroid;
|
||||||
|
|
||||||
|
public AsteroidHitEvent(AsteroidComponent asteroid) {
|
||||||
|
this.asteroid = asteroid;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
14
core/src/com/me/asteroids/events/PlayerDeathEvent.java
Normal file
14
core/src/com/me/asteroids/events/PlayerDeathEvent.java
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
package com.me.asteroids.events;
|
||||||
|
|
||||||
|
import com.me.common.ecs.Entity;
|
||||||
|
import com.me.common.ecs.event.Event;
|
||||||
|
|
||||||
|
public class PlayerDeathEvent extends Event {
|
||||||
|
|
||||||
|
public Entity player;
|
||||||
|
|
||||||
|
public PlayerDeathEvent(Entity player) {
|
||||||
|
this.player = player;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -14,17 +14,22 @@ import com.me.asteroids.components.BulletComponent;
|
|||||||
import com.me.asteroids.components.ColliderComponent;
|
import com.me.asteroids.components.ColliderComponent;
|
||||||
import com.me.asteroids.components.DebrisComponent;
|
import com.me.asteroids.components.DebrisComponent;
|
||||||
import com.me.asteroids.components.DecayComponent;
|
import com.me.asteroids.components.DecayComponent;
|
||||||
|
import com.me.asteroids.components.GameDataComponent;
|
||||||
import com.me.asteroids.components.ModelComponent;
|
import com.me.asteroids.components.ModelComponent;
|
||||||
import com.me.asteroids.components.PlayerComponent;
|
import com.me.asteroids.components.PlayerComponent;
|
||||||
import com.me.asteroids.components.PositionComponent;
|
import com.me.asteroids.components.PositionComponent;
|
||||||
import com.me.asteroids.components.VelocityComponent;
|
import com.me.asteroids.components.VelocityComponent;
|
||||||
import com.me.asteroids.components.model.PolygonModel;
|
import com.me.asteroids.components.model.PolygonModel;
|
||||||
|
import com.me.asteroids.events.AsteroidHitEvent;
|
||||||
import com.me.asteroids.events.BulletAsteroidCollisionEvent;
|
import com.me.asteroids.events.BulletAsteroidCollisionEvent;
|
||||||
import com.me.asteroids.events.PlayerASteroidCollisionEvent;
|
import com.me.asteroids.events.PlayerASteroidCollisionEvent;
|
||||||
|
import com.me.asteroids.events.PlayerDeathEvent;
|
||||||
import com.me.asteroids.events.ScreenWrapEvent;
|
import com.me.asteroids.events.ScreenWrapEvent;
|
||||||
import com.me.asteroids.systems.AsteroidSpawningSystem;
|
import com.me.asteroids.systems.AsteroidSpawningSystem;
|
||||||
import com.me.asteroids.systems.CollisionSystem;
|
import com.me.asteroids.systems.CollisionSystem;
|
||||||
import com.me.asteroids.systems.DecaySystem;
|
import com.me.asteroids.systems.DecaySystem;
|
||||||
|
import com.me.asteroids.systems.GameDataRenderSystem;
|
||||||
|
import com.me.asteroids.systems.GameDataSystem;
|
||||||
import com.me.asteroids.systems.ModelRenderSystem;
|
import com.me.asteroids.systems.ModelRenderSystem;
|
||||||
import com.me.asteroids.systems.MovementSystem;
|
import com.me.asteroids.systems.MovementSystem;
|
||||||
import com.me.asteroids.systems.PlayerInputSystem;
|
import com.me.asteroids.systems.PlayerInputSystem;
|
||||||
@ -53,10 +58,10 @@ public class GameScreen extends Screen implements Listener {
|
|||||||
public void setup() {
|
public void setup() {
|
||||||
batch = new SpriteBatch();
|
batch = new SpriteBatch();
|
||||||
font = new BitmapFont();
|
font = new BitmapFont();
|
||||||
font.setColor(Color.RED);
|
|
||||||
|
|
||||||
engine = new Engine();
|
engine = new Engine();
|
||||||
|
|
||||||
|
engine.registerComponentClass(GameDataComponent.class);
|
||||||
engine.registerComponentClass(PlayerComponent.class);
|
engine.registerComponentClass(PlayerComponent.class);
|
||||||
engine.registerComponentClass(BulletComponent.class);
|
engine.registerComponentClass(BulletComponent.class);
|
||||||
engine.registerComponentClass(AsteroidComponent.class);
|
engine.registerComponentClass(AsteroidComponent.class);
|
||||||
@ -68,6 +73,9 @@ public class GameScreen extends Screen implements Listener {
|
|||||||
engine.registerComponentClass(AccelerationComponent.class);
|
engine.registerComponentClass(AccelerationComponent.class);
|
||||||
engine.registerComponentClass(ModelComponent.class);
|
engine.registerComponentClass(ModelComponent.class);
|
||||||
|
|
||||||
|
GameDataSystem system = new GameDataSystem(engine);
|
||||||
|
|
||||||
|
engine.registerSystem(system);
|
||||||
engine.registerSystem(new PlayerInputSystem(engine));
|
engine.registerSystem(new PlayerInputSystem(engine));
|
||||||
engine.registerSystem(new AsteroidSpawningSystem(engine));
|
engine.registerSystem(new AsteroidSpawningSystem(engine));
|
||||||
engine.registerSystem(new DecaySystem(engine));
|
engine.registerSystem(new DecaySystem(engine));
|
||||||
@ -75,11 +83,17 @@ public class GameScreen extends Screen implements Listener {
|
|||||||
engine.registerSystem(new CollisionSystem(engine));
|
engine.registerSystem(new CollisionSystem(engine));
|
||||||
engine.registerSystem(new ScreenWrapSystem(engine));
|
engine.registerSystem(new ScreenWrapSystem(engine));
|
||||||
engine.registerSystem(new ModelRenderSystem(engine, graphics));
|
engine.registerSystem(new ModelRenderSystem(engine, graphics));
|
||||||
|
engine.registerSystem(new GameDataRenderSystem(engine, graphics, font));
|
||||||
|
|
||||||
|
engine.registerListener(system);
|
||||||
engine.registerListener(this.new EventListener(engine));
|
engine.registerListener(this.new EventListener(engine));
|
||||||
|
|
||||||
engine.ready();
|
engine.ready();
|
||||||
|
|
||||||
|
Entity gameData = engine.createEntity();
|
||||||
|
gameData.addComponent(new GameDataComponent());
|
||||||
|
gameData.activate();
|
||||||
|
|
||||||
Entity player = EntityFactory.createPlayer(engine);
|
Entity player = EntityFactory.createPlayer(engine);
|
||||||
player.activate();
|
player.activate();
|
||||||
}
|
}
|
||||||
@ -91,7 +105,8 @@ public class GameScreen extends Screen implements Listener {
|
|||||||
|
|
||||||
if (Constants.DEBUG) {
|
if (Constants.DEBUG) {
|
||||||
batch.begin();
|
batch.begin();
|
||||||
font.draw(batch, String.format("FPS: %d, Entities: %d", Gdx.graphics.getFramesPerSecond(), engine.getEntityCount()), 50, 50);
|
font.setColor(Color.RED);
|
||||||
|
font.draw(batch, String.format("FPS: %d, Entities: %d", Gdx.graphics.getFramesPerSecond(), engine.getEntityCount()), 15, 15 + font.getCapHeight());
|
||||||
batch.end();
|
batch.end();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -134,9 +149,10 @@ public class GameScreen extends Screen implements Listener {
|
|||||||
if (model.contains(bulletPosition)) {
|
if (model.contains(bulletPosition)) {
|
||||||
// AABBs intersect but let's only consider it a hit if the bullet's position
|
// AABBs intersect but let's only consider it a hit if the bullet's position
|
||||||
// is actually inside the asteroid
|
// is actually inside the asteroid
|
||||||
|
AsteroidComponent asteroid = asteroidMapper.get(event.getAsteroid());
|
||||||
|
engine.callEvent(new AsteroidHitEvent(asteroid));
|
||||||
event.getBullet().remove();
|
event.getBullet().remove();
|
||||||
int generation = asteroidMapper.get(event.getAsteroid()).generation;
|
if (asteroid.generation < 2) {
|
||||||
if (generation < 2) {
|
|
||||||
for (Entity shard : EntityFactory.splitAsteroidIntoChunks(engine, event.getAsteroid(), 2, 2/3f)) {
|
for (Entity shard : EntityFactory.splitAsteroidIntoChunks(engine, event.getAsteroid(), 2, 2/3f)) {
|
||||||
shard.activate();
|
shard.activate();
|
||||||
}
|
}
|
||||||
@ -146,7 +162,6 @@ public class GameScreen extends Screen implements Listener {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
event.getAsteroid().remove();
|
event.getAsteroid().remove();
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -156,6 +171,7 @@ public class GameScreen extends Screen implements Listener {
|
|||||||
PolygonModel player = (PolygonModel) modelMapper.get(event.getPlayer()).model;
|
PolygonModel player = (PolygonModel) modelMapper.get(event.getPlayer()).model;
|
||||||
|
|
||||||
if (asteroid.contains(player.getVertices()) || player.contains(asteroid.getVertices())) {
|
if (asteroid.contains(player.getVertices()) || player.contains(asteroid.getVertices())) {
|
||||||
|
engine.callEvent(new PlayerDeathEvent(event.getPlayer()));
|
||||||
event.getPlayer().deactivate();
|
event.getPlayer().deactivate();
|
||||||
for (Entity debris : EntityFactory.createDebris(engine, event.getPlayer())) {
|
for (Entity debris : EntityFactory.createDebris(engine, event.getPlayer())) {
|
||||||
debris.activate();
|
debris.activate();
|
||||||
|
62
core/src/com/me/asteroids/systems/GameDataRenderSystem.java
Normal file
62
core/src/com/me/asteroids/systems/GameDataRenderSystem.java
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
package com.me.asteroids.systems;
|
||||||
|
|
||||||
|
import com.badlogic.gdx.graphics.Color;
|
||||||
|
import com.badlogic.gdx.graphics.g2d.BitmapFont;
|
||||||
|
import com.badlogic.gdx.graphics.g2d.GlyphLayout;
|
||||||
|
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
|
||||||
|
import com.me.asteroids.Constants;
|
||||||
|
import com.me.asteroids.Graphics;
|
||||||
|
import com.me.asteroids.components.GameDataComponent;
|
||||||
|
import com.me.common.ecs.ComponentMapper;
|
||||||
|
import com.me.common.ecs.Engine;
|
||||||
|
import com.me.common.ecs.Entity;
|
||||||
|
import com.me.common.ecs.EntitySystem;
|
||||||
|
|
||||||
|
public class GameDataRenderSystem extends EntitySystem {
|
||||||
|
|
||||||
|
private ComponentMapper<GameDataComponent> gameDataMapper;
|
||||||
|
|
||||||
|
private SpriteBatch batch;
|
||||||
|
private BitmapFont font;
|
||||||
|
private GlyphLayout gameOverLayout;
|
||||||
|
|
||||||
|
private GameDataComponent gameData;
|
||||||
|
|
||||||
|
public GameDataRenderSystem(Engine engine, Graphics graphics, BitmapFont font) {
|
||||||
|
super(engine, GameDataComponent.class);
|
||||||
|
gameDataMapper = engine.getComponentMapper(GameDataComponent.class);
|
||||||
|
batch = graphics.getSpriteBatch();
|
||||||
|
this.font = font;
|
||||||
|
this.gameOverLayout = new GlyphLayout(font, "GAME OVER");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void preProcess() {
|
||||||
|
batch.begin();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void processEntity(Entity entity, float dt) {
|
||||||
|
if(gameData == null) {
|
||||||
|
gameData = gameDataMapper.get(entity);
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (gameData.gameMode) {
|
||||||
|
case GAME_OVER:
|
||||||
|
font.setColor(Color.RED);
|
||||||
|
font.draw(batch, "GAME OVER", Constants.HALF_WIDTH - (gameOverLayout.width / 2), Constants.HALF_HEIGHT);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
font.setColor(Color.CHARTREUSE);
|
||||||
|
font.draw(batch, "Score: " + gameData.score, 15, Constants.HEIGHT - 15);
|
||||||
|
font.draw(batch, "Lives: " + gameData.lives, 15, Constants.HEIGHT - 30);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void postProcess() {
|
||||||
|
batch.end();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
102
core/src/com/me/asteroids/systems/GameDataSystem.java
Normal file
102
core/src/com/me/asteroids/systems/GameDataSystem.java
Normal file
@ -0,0 +1,102 @@
|
|||||||
|
package com.me.asteroids.systems;
|
||||||
|
|
||||||
|
import com.me.asteroids.Constants;
|
||||||
|
import com.me.asteroids.GameMode;
|
||||||
|
import com.me.asteroids.components.GameDataComponent;
|
||||||
|
import com.me.asteroids.components.PositionComponent;
|
||||||
|
import com.me.asteroids.components.VelocityComponent;
|
||||||
|
import com.me.asteroids.events.AsteroidHitEvent;
|
||||||
|
import com.me.asteroids.events.PlayerDeathEvent;
|
||||||
|
import com.me.common.ecs.ComponentMapper;
|
||||||
|
import com.me.common.ecs.Engine;
|
||||||
|
import com.me.common.ecs.Entity;
|
||||||
|
import com.me.common.ecs.EntitySystem;
|
||||||
|
import com.me.common.ecs.event.EventHandler;
|
||||||
|
import com.me.common.ecs.event.Listener;
|
||||||
|
|
||||||
|
public class GameDataSystem extends EntitySystem implements Listener {
|
||||||
|
|
||||||
|
private ComponentMapper<GameDataComponent> gameDataMapper;
|
||||||
|
|
||||||
|
private GameDataComponent gameData;
|
||||||
|
|
||||||
|
public GameDataSystem(Engine engine) {
|
||||||
|
super(engine, GameDataComponent.class);
|
||||||
|
gameDataMapper = engine.getComponentMapper(GameDataComponent.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void processEntity(Entity entity, float dt) {
|
||||||
|
if(gameData == null) {
|
||||||
|
gameData = gameDataMapper.get(entity);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (gameData.gameModeTimer > 0 && (gameData.gameModeTimer -= dt) < 0) {
|
||||||
|
switch (gameData.gameMode) {
|
||||||
|
case DIED:
|
||||||
|
if (--gameData.lives >= 0) {
|
||||||
|
resetPlayer();
|
||||||
|
setGameMode(GameMode.PLAYING);
|
||||||
|
} else {
|
||||||
|
setGameMode(GameMode.GAME_OVER);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case GAME_OVER:
|
||||||
|
gameData.reset();
|
||||||
|
resetPlayer();
|
||||||
|
setGameMode(GameMode.PLAYING);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventHandler
|
||||||
|
public void onAsteroidHit(AsteroidHitEvent event) {
|
||||||
|
if (gameData == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (event.asteroid.generation) {
|
||||||
|
case 0:
|
||||||
|
gameData.score += 20;
|
||||||
|
gameData.newLifeScore += 20;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
gameData.score += 50;
|
||||||
|
gameData.newLifeScore += 50;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
gameData.score += 100;
|
||||||
|
gameData.newLifeScore += 100;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (gameData.newLifeScore >= Constants.NEW_LIFE_SCORE) {
|
||||||
|
gameData.newLifeScore -= Constants.NEW_LIFE_SCORE;
|
||||||
|
gameData.lives++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@EventHandler
|
||||||
|
public void onPlayerDeath(PlayerDeathEvent event) {
|
||||||
|
if (gameData == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
setGameMode(GameMode.DIED);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void resetPlayer() {
|
||||||
|
Entity player = engine.getEntities().get(1);
|
||||||
|
PositionComponent position = player.getComponent(PositionComponent.class);
|
||||||
|
position.rotation = 90;
|
||||||
|
position.position.set(Constants.HALF_WIDTH, Constants.HALF_HEIGHT);
|
||||||
|
player.getComponent(VelocityComponent.class).velocity.set(0, 0);
|
||||||
|
player.activate();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setGameMode(GameMode mode) {
|
||||||
|
gameData.gameMode = mode;
|
||||||
|
gameData.gameModeTimer = mode.getTimer();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user