/*
* Copyright (c) 2012. HappyDroids LLC, All rights reserved.
*/
package com.happydroids.droidtowers.entities;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.g2d.Sprite;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.graphics.g2d.SpriteCache;
import com.badlogic.gdx.graphics.g2d.TextureRegion;
import com.badlogic.gdx.math.MathUtils;
import com.badlogic.gdx.math.Rectangle;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.scenes.scene2d.actions.Actions;
import com.badlogic.gdx.utils.Pools;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import com.google.common.eventbus.EventBus;
import com.happydroids.droidtowers.TowerConsts;
import com.happydroids.droidtowers.actions.Action;
import com.happydroids.droidtowers.events.GridObjectBoundsChangeEvent;
import com.happydroids.droidtowers.events.GridObjectEvent;
import com.happydroids.droidtowers.events.GridObjectPlacedEvent;
import com.happydroids.droidtowers.events.SafeEventBus;
import com.happydroids.droidtowers.generators.NameGenerator;
import com.happydroids.droidtowers.grid.GameGrid;
import com.happydroids.droidtowers.gui.GridObjectPopOver;
import com.happydroids.droidtowers.gui.HeadsUpDisplay;
import com.happydroids.droidtowers.math.GridPoint;
import com.happydroids.droidtowers.math.StatLog;
import com.happydroids.droidtowers.scenes.components.SceneManager;
import com.happydroids.droidtowers.types.GridObjectType;
import com.happydroids.droidtowers.types.ProviderType;
import java.util.List;
import java.util.Map;
import java.util.Set;
public abstract class GridObject {
public static final float VISITORS_PER_CLEANING = 35f;
protected static Map<String, TextureRegion> availableDecals;
protected final GridObjectType gridObjectType;
protected final GameGrid gameGrid;
protected GridPoint position;
protected GridPoint size;
protected Vector2 worldPosition;
protected Vector2 worldSize;
protected Color renderColor;
protected Rectangle bounds;
private Set<Action> actions;
private EventBus myEventBus;
private Vector2 worldTop;
private Vector2 worldCenter;
private Vector2 worldCenterBottom;
private Rectangle worldBounds;
protected boolean placed;
protected boolean connectedToTransport;
private boolean connectedToSecurity;
protected int numVisitors;
protected long lastCleanedAt;
protected float surroundingNoiseLevel;
protected float surroundingCrimeLevel;
protected String name;
private boolean displayedPopOver;
protected int loanFromCousinVinnie;
private int variationId;
private List<GridPoint> pointsTouched;
private Set<Avatar> visitorQueue;
private Avatar beingServicedBy;
private StatLog averageNumVisitors;
private int spriteCacheId = -1;
protected Set<String> decalsToDraw;
public GridObject(GridObjectType gridObjectType, GameGrid gameGrid) {
this.gridObjectType = gridObjectType;
this.gameGrid = gameGrid;
name = NameGenerator.randomNameForGridObjectType(getGridObjectType());
position = new GridPoint(0, 0);
size = new GridPoint(gridObjectType.getWidth(), gridObjectType.getHeight());
bounds = new Rectangle(position.x, position.y, size.x, size.y);
visitorQueue = Sets.newHashSet();
averageNumVisitors = new StatLog();
averageNumVisitors.reset(5);
worldPosition = new Vector2();
worldSize = new Vector2(size.getWorldX() * gameGrid.getGridScale(), size.getWorldY() * gameGrid.getGridScale());
worldCenter = new Vector2();
worldCenterBottom = new Vector2();
worldTop = new Vector2();
worldBounds = new Rectangle();
if (gridObjectType.getNumVariations() > 0) {
variationId = MathUtils.random(1, gridObjectType.getNumVariations());
}
setRenderColor(Color.WHITE);
decalsToDraw = Sets.newHashSet();
}
public boolean canShareSpace(GridObject gridObject) {
return gridObjectType.canShareSpace(gridObject);
}
public Rectangle getBounds() {
return bounds;
}
public GridObjectType getGridObjectType() {
return gridObjectType;
}
public abstract Sprite getSprite();
public void updateSprite() {
}
public boolean canBeAt() {
return gridObjectType.canBeAt(this);
}
public GameGrid getGameGrid() {
return gameGrid;
}
public void render(SpriteBatch spriteBatch, SpriteCache spriteCache, Color renderTintColor) {
Sprite sprite = getSprite();
if (sprite != null) {
sprite.setColor(renderColor);
sprite.setPosition(worldPosition.x, worldPosition.y);
sprite.setSize(worldSize.x, worldSize.y);
if (shouldUseSpriteCache()) {
spriteCache.beginCache();
spriteCache.add(sprite);
setSpriteCacheId(spriteCache.endCache());
} else {
sprite.draw(spriteBatch);
}
}
}
public void renderDecals(SpriteBatch spriteBatch) {
if (hasDecals()) {
spriteBatch.setColor(Color.WHITE);
if (decalsToDraw.size() == 1) {
for (String regionName : decalsToDraw) {
TextureRegion region = availableDecals.get(regionName);
spriteBatch.draw(region, getWorldCenter().x - region.getRegionWidth() / 2, getWorldCenter().y - region.getRegionHeight() / 2);
}
} else {
int decalsWidth = 0;
for (String regionName : decalsToDraw) {
TextureRegion region = availableDecals.get(regionName);
decalsWidth = region.getRegionWidth();
}
float startX = getWorldCenter().x - decalsWidth;
for (String regionName : decalsToDraw) {
TextureRegion region = availableDecals.get(regionName);
spriteBatch.draw(region, startX, getWorldCenter().y - region.getRegionHeight() / 2);
startX += region.getRegionWidth();
}
}
}
}
public boolean hasDecals() {
return !decalsToDraw.isEmpty();
}
public boolean tap(GridPoint gridPointAtFinger, int count) {
if (count == 1 && hasPopOver()) {
if (displayedPopOver) {
displayedPopOver = false;
} else {
GridObjectPopOver popOver = makePopOver();
if (popOver != null) {
SceneManager.activeScene().getCameraController().panTo(getWorldCenter().x, getWorldCenter().y, true);
displayedPopOver = true;
popOver.pack();
popOver.getColor().a = 0f;
popOver.addAction(Actions.fadeIn(0.125f));
HeadsUpDisplay.instance().addActor(popOver);
return true;
}
}
}
return false;
}
public boolean pan(GridPoint gridPointAtFinger, GridPoint gridPointDelta) {
return false;
}
public GridPoint getSize() {
return size;
}
public void setSize(GridPoint size) {
setSize(size.x, size.y);
}
public void setSize(int x, int y) {
GridObjectBoundsChangeEvent event = Pools.obtain(GridObjectBoundsChangeEvent.class);
event.setGridObject(this);
size.set(x, y);
updateWorldCoordinates();
broadcastEvent(event);
Pools.free(event);
}
public GridPoint getPosition() {
return position;
}
public void setPosition(GridPoint gridPointAtFinger) {
setPosition(gridPointAtFinger.x, gridPointAtFinger.y);
}
public void setPosition(int x, int y) {
GridObjectBoundsChangeEvent event = Pools.obtain(GridObjectBoundsChangeEvent.class);
event.setGridObject(this);
position.set(x, y);
clampPosition();
updateWorldCoordinates();
checkPlacement(placed);
broadcastEvent(event);
Pools.free(event);
}
public void updateWorldCoordinates() {
worldPosition.set(gameGrid.getGridOrigin().x + (position.getWorldX() * gameGrid.getGridScale()), gameGrid.getGridOrigin().y + (position.getWorldY() * gameGrid.getGridScale()));
worldSize.set(size.getWorldX() * gameGrid.getGridScale(), size.getWorldY() * gameGrid.getGridScale());
worldBounds.set(worldPosition.x, worldPosition.y, worldSize.x, worldSize.y);
worldCenter.set(worldPosition.x + worldSize.x / 2, worldPosition.y + worldSize.y / 2);
worldCenterBottom.set(worldCenter.cpy().sub(0, TowerConsts.GRID_UNIT_SIZE * size.y / 2));
worldTop.set(worldPosition.x + worldSize.x / 2, worldPosition.y + worldSize.y);
updateGridPointsTouched();
}
protected void clampPosition() {
if (position.x < 0) {
position.x = 0;
} else if (position.x + size.x > gameGrid.getGridSize().x) {
position.x = gameGrid.getGridSize().x - size.x;
}
if (position.y < 0) {
position.y = 0;
} else if (position.y + size.y > gameGrid.getGridSize().y) {
position.y = gameGrid.getGridSize().y - size.y;
}
}
public int getCoinsEarned() {
return placed ? gridObjectType.getCoinsEarned() : 0;
}
public int getUpkeepCost() {
return 0;
}
public void setPlaced(boolean state) {
boolean prevState = placed;
placed = state;
checkPlacement(prevState);
}
private void checkPlacement(boolean prevState) {
if (placed) {
setRenderColor(Color.WHITE);
GridObjectPlacedEvent event = Pools.obtain(GridObjectPlacedEvent.class);
event.setGridObject(this);
broadcastEvent(event);
Pools.free(event);
} else {
setRenderColor(gameGrid.canObjectBeAt(this) ? Color.CYAN : Color.RED);
}
}
public boolean isPlaced() {
return placed;
}
public float getNoiseLevel() {
return gridObjectType.getNoiseLevel();
}
public GridPoint getContentSize() {
return size;
}
public GridPoint getContentPosition() {
return position;
}
public List<GridPoint> getGridPointsTouched() {
return pointsTouched;
}
public void updateGridPointsTouched() {
pointsTouched = Lists.newArrayList();
for (int x = position.x; x < position.x + size.x; x++) {
for (int y = position.y; y < position.y + size.y; y++) {
pointsTouched.add(new GridPoint(x, y));
}
}
}
public float distanceToLobby() {
return position.y - TowerConsts.LOBBY_FLOOR;
}
public float distanceFromFloor(float originalFloor) {
return originalFloor - position.y;
}
public Vector2 getWorldCenter() {
return worldCenter;
}
public Vector2 getWorldTop() {
return worldTop;
}
public void setRenderColor(Color renderColor) {
Color baseTint = new Color(gameGrid.getRenderer().getRenderTintColor());
this.renderColor = baseTint.mul(renderColor);
}
public EventBus eventBus() {
if (myEventBus == null) {
myEventBus = new SafeEventBus();
}
return myEventBus;
}
public void update(float deltaTime) {
}
public void broadcastEvent(GridObjectEvent event) {
if (myEventBus != null) {
myEventBus.post(event);
}
gameGrid.events().post(event);
}
public abstract float getDesirability();
protected float getGridScale() {
return gameGrid.getGridScale();
}
public Vector2 getWorldPosition() {
return worldPosition;
}
public Rectangle getWorldBounds() {
return worldBounds;
}
public void adjustToNewLandSize() {
}
public Vector2 getWorldCenterBottom() {
return worldCenterBottom;
}
@SuppressWarnings("RedundantIfStatement")
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (!(o instanceof GridObject)) {
return false;
}
GridObject that = (GridObject) o;
if (gameGrid != null ? !gameGrid.equals(that.gameGrid) : that.gameGrid != null) {
return false;
}
if (gridObjectType != null ? !gridObjectType.equals(that.gridObjectType) : that.gridObjectType != null) {
return false;
}
if (placed != that.placed) {
return false;
}
if (position != null ? !position.equals(that.position) : that.position != null) {
return false;
}
if (size != null ? !size.equals(that.size) : that.size != null) {
return false;
}
return true;
}
@Override
public String toString() {
return "GridObject{" +
"position=" + position +
", gridObjectType=" + gridObjectType +
'}';
}
public float getCrimeLevel() {
return loanFromCousinVinnie > 0 ? 1f : gridObjectType.getCrimeLevel();
}
public boolean isConnectedToSecurity() {
return connectedToSecurity;
}
public void setConnectedToTransport(boolean connectedToTransport) {
this.connectedToTransport = connectedToTransport;
}
public boolean isConnectedToTransport() {
return connectedToTransport && placed;
}
public void setConnectedToSecurity(boolean connectedToSecurity) {
this.connectedToSecurity = connectedToSecurity;
}
public boolean provides(ProviderType... providerType) {
return gridObjectType.provides(providerType);
}
public int getNumVisitors() {
return numVisitors;
}
public long getLastServicedAt() {
return lastCleanedAt;
}
public void recordVisitor(Avatar avatar) {
removeFromVisitorQueue(avatar);
numVisitors += 1;
if (avatar instanceof Janitor || avatar instanceof Maid) {
Janitor janitor = (Janitor) avatar;
if (provides(janitor.servicesTheseProviderTypes)) {
lastCleanedAt = System.currentTimeMillis();
averageNumVisitors.record(numVisitors);
numVisitors = 0;
}
}
}
public float getNormalizedCrimeLevel() {
if (getCrimeLevel() > 0f) {
return getCrimeLevel() * Math.max(1, getNumVisitors()) - gameGrid.positionCache()
.getPosition(position).normalizedDistanceFromSecurity;
} else {
return 0;
}
}
public void setSurroundingNoiseLevel(float noise) {
surroundingNoiseLevel = noise;
}
public void setSurroundingCrimeLevel(float crimeLevel) {
surroundingCrimeLevel = crimeLevel;
}
public float getSurroundingNoiseLevel() {
return surroundingNoiseLevel;
}
public float getSurroundingCrimeLevel() {
return surroundingCrimeLevel;
}
public abstract GridObjectPopOver makePopOver();
public String getName() {
return name != null ? name : gridObjectType.getName();
}
public boolean hasCustomName() {
return name != null;
}
public void setName(String name) {
this.name = name;
}
protected abstract boolean hasPopOver();
public void addLoanFromCousinVinnie(int amountLoaned) {
loanFromCousinVinnie += amountLoaned;
}
public int getAmountLoanedFromCousinVinnie() {
return loanFromCousinVinnie;
}
public boolean hasLoanFromCousinVinnie() {
return loanFromCousinVinnie > 0;
}
public int getVariationId() {
return variationId;
}
public void setVariationId(int variationId) {
this.variationId = variationId;
}
public void removeLoanFromVinnie() {
loanFromCousinVinnie = 0;
}
public boolean canEarnMoney() {
return true;
}
public void addToVisitorQueue(Avatar avatar) {
visitorQueue.add(avatar);
if (avatar instanceof Janitor && !(avatar instanceof SecurityGuard)) {
beingServicedBy = avatar;
}
}
public void removeFromVisitorQueue(Avatar avatar) {
visitorQueue.remove(avatar);
if (beingServicedBy == avatar) {
beingServicedBy = null;
}
}
public int getVisitorQueueSize() {
return visitorQueue.size();
}
public boolean isBeingServiced() {
return beingServicedBy != null;
}
protected float getAvgNumVisitors() {
return averageNumVisitors.getAverage();
}
public float getDirtLevel() {
return MathUtils.clamp(getNumVisitors(), 0, VISITORS_PER_CLEANING) / VISITORS_PER_CLEANING;
}
public boolean touchDown(GridPoint gameGridPoint, Vector2 worldPoint, int pointer) {
return false;
}
public boolean touchUp() {
return false;
}
public boolean shouldUseSpriteCache() {
return isPlaced();
}
public int getSpriteCacheId() {
return spriteCacheId;
}
public void setSpriteCacheId(int spriteCacheId) {
this.spriteCacheId = spriteCacheId;
}
public boolean needsDroids() {
return false;
}
}