package com.palepail.TestGame.Model;
import java.math.BigDecimal;
import java.util.Random;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.math.Rectangle;
import com.badlogic.gdx.math.Vector2;
import com.palepail.TestGame.Actions.Active;
import com.palepail.TestGame.Actions.Flash;
import com.palepail.TestGame.Actions.SmoothMoveTo;
import com.palepail.TestGame.Actions.Wait;
import com.palepail.TestGame.Model.Bullet.Bullet;
import com.palepail.TestGame.Model.Items.Item;
import com.palepail.TestGame.Model.Items.Power;
import com.palepail.TestGame.Utilities.Audio;
import com.palepail.TestGame.Utilities.Configuration;
import com.palepail.TestGame.Utilities.InfoBox;
import com.palepail.TestGame.View.World;
public class Ship extends MovableEntity {
private final float BASE_SPEED = 4f;
private float SLOW_RATE = .5f;
private boolean SLOW = false;
private float slowEffectRotation;
private float slowEffectRotationSpeed = 150;
private int INFLUENCE_SCALE = 5;
private Rectangle influence;
private static int startingLives = 3;
private Rectangle bomb = new Rectangle();
float bombDamage = 100;
private int bombCap = 3;
private int bombs = 30;
private float bombRotation = 0;
private float ROTATION_SPEED = 150;
float bombExplosionSpeed = 15f;
float bombTimer;
float timer;
private int bombDuration = 60;
private float damage;
private float maxDamage = 4;
private float baseDamage = 1;
private float deathDamage = 40;
private float MAX_BOMB_SIZE = 30f * Configuration.gameScale;
private float DEATH_EXPLOSION_SPEED = 10f;
private float MAX_DEATH_EXPLOSION_SIZE = 30f * Configuration.gameScale;
protected int health;
protected int lives;
boolean dead;
protected InfoBox infoBox;
int ticks = 0;
private String spriteName = "Ship";
private boolean bombDropped = false;
public Ship(Vector2 position, float width, float height, float rotation, float SPEED, int damage, InfoBox infoBox) {
super(SPEED, rotation, width, height, position);
fireRate = 4;
this.damage = damage;
setActive(true);
health = 1;
influence = new Rectangle(position.x - ((width * INFLUENCE_SCALE) / 2), position.y
+ ((height * INFLUENCE_SCALE) / 2), width * INFLUENCE_SCALE, height * INFLUENCE_SCALE);
dead = false;
this.lives = startingLives;
this.infoBox = infoBox;
}
public void update(World world) {
super.update(this);
timer += (Gdx.graphics.getDeltaTime() * Configuration.frameRate);
time += Gdx.graphics.getDeltaTime();
while (timer >= 1) {
timer--;
ticks++;
if (bombDropped) {
bombTimer++;
}
shoot(world);
}
if (this.isSLOW()) {
slowEffectRotation += Gdx.graphics.getDeltaTime() * slowEffectRotationSpeed;
if (slowEffectRotation > 360) {
slowEffectRotation -= 360;
}
}
if (health <= 0 && !isDead()) {
killShip(world);
} else if (isDead()&&lives>0)
{
respawn(world);
}
if (bombDropped) {
updateBomb();
}
// if the ship is inactive (player does not have control) the ship will
// try to update any scripts given to it.
if (!active) {
scriptIterator = sequentialScript.iterator();
if (scriptIterator.hasNext()) {
action = scriptIterator.next();
if (action.isDone()) {
scriptIterator.remove();
} else {
action.update(ticks);
}
}
}else{
moveShip(world.getPlayArea());
}
// update all concurrent scripts
scriptIterator = tandemScript.iterator();
if (scriptIterator.hasNext()) {
action = scriptIterator.next();
if (action.isDone()) {
scriptIterator.remove();
} else {
action.update(ticks);
}
}
}
// =====================InfoBox
/**
* @return the infoBox
*/
public InfoBox getInfoBox() {
return infoBox;
}
/**
* @param infoBox
* the infoBox to set
*/
public void setInfoBox(InfoBox infoBox) {
this.infoBox = infoBox;
}
// =====================Bombs
private void updateBomb() {
if (bomb.width < MAX_BOMB_SIZE) {
bomb.width += bomb.width * bombExplosionSpeed * Gdx.graphics.getDeltaTime();
bomb.height += bomb.height * bombExplosionSpeed * Gdx.graphics.getDeltaTime();
bomb.x -= bomb.width * bombExplosionSpeed * Gdx.graphics.getDeltaTime() / 2;
bomb.y -= bomb.height * bombExplosionSpeed * Gdx.graphics.getDeltaTime() / 2;
}
bombRotation += Gdx.graphics.getDeltaTime() * ROTATION_SPEED;
if (bombRotation > 360) {
bombRotation -= 360;
}
if (bombTimer >= bombDuration) {
bomb.width = 0;
bomb.height = 0;
bombDropped = false;
}
}
public void addBomb() {
if (bombs < bombCap) {
bombs++;
}
}
public void dropBomb() {
bombDropped = true;
bombs--;
bombTimer = 0;
bomb = new Rectangle(getPosition().x + (width / 2), getPosition().y + (height / 2), Configuration.gameScale, Configuration.gameScale);
}
/**
* @return the bombDamage
*/
public float getBombDamage() {
return bombDamage;
}
/**
* @param bombDamage
* the bombDamage to set
*/
public void setBombDamage(float bombDamage) {
this.bombDamage = bombDamage;
}
/**
* @return the bombDropped
*/
public boolean isBombDropped() {
return bombDropped;
}
/**
* @param bombDropped
* the bombDropped to set
*/
public void setBombDropped(boolean bombDropped) {
this.bombDropped = bombDropped;
}
/**
* @return the bomb
*/
public Rectangle getBomb() {
return bomb;
}
/**
* @param bomb
* the bomb to set
*/
public void setBomb(Rectangle bomb) {
this.bomb = bomb;
}
/**
* @return the bombs
*/
public int getBombs() {
return bombs;
}
/**
* @param bombs
* the bombs to set
*/
public void setBombs(int bombs) {
this.bombs = bombs;
}
public float getBombRotation() {
return bombRotation;
}
/**
* @return the bombDuration
*/
public int getBombDuration() {
return bombDuration;
}
/**
* @param bombDuration
* the bombDuration to set
*/
public void setBombDuration(int bombDuration) {
this.bombDuration = bombDuration;
}
// =============Movement
private void moveShip(Rectangle playArea) {
if (playArea.x > getBounds().x - width) {
if (velocity.x < 0) {
velocity.x = 0;
}
}
if (getBounds().x + width * 2 > playArea.x + playArea.width) {
if (velocity.x > 0) {
velocity.x = 0;
}
}
if (playArea.y > getBounds().y - height) {
if (velocity.y < 0) {
velocity.y = 0;
}
}
if (getBounds().y + height * 2 > playArea.y + playArea.height) {
if (velocity.y > 0) {
velocity.y = 0;
}
}
position.add(velocity.tmp().mul(Gdx.graphics.getDeltaTime() * SPEED));
bounds.x = position.x;
bounds.y = position.y;
if (!isDead()) {
influence.x = position.x - ((width * (INFLUENCE_SCALE - 1)) / 2);
influence.y = position.y - ((height * (INFLUENCE_SCALE - 1)) / 2);
}
}
public void checkControls() {
float speed = getCurrentSpeed();
if (isMOVE_UP()) {
velocity.y = speed;
} else if (isMOVE_DOWN()) {
velocity.y = -speed;
} else {
velocity.y = 0;
}
if (!isMOVE_DOWN() && !isMOVE_UP()) {
velocity.y = 0;
}
if (isMOVE_LEFT()) {
velocity.x = -speed;
} else if (isMOVE_RIGHT()) {
velocity.x = speed;
} else {
velocity.x = 0;
}
if (!isMOVE_LEFT() && !isMOVE_RIGHT()) {
velocity.x = 0;
}
}
private float getCurrentSpeed() {
float speed = getBASE_SPEED();
if (isSLOW()) {
speed *= SLOW_RATE;
}
return speed;
}
/**
* @return the sLOW_RATE
*/
public float getSLOW_RATE() {
return SLOW_RATE;
}
/**
* @param sLOW_RATE
* the sLOW_RATE to set
*/
public void setSLOW_RATE(float sLOW_RATE) {
SLOW_RATE = sLOW_RATE;
}
/**
* @return the bASE_SPEED
*/
public float getBASE_SPEED() {
return BASE_SPEED;
}
/**
* @return the sLOW
*/
public boolean isSLOW() {
return SLOW;
}
/**
* @param sLOW
* the sLOW to set
*/
public void setSLOW(boolean sLOW) {
SLOW = sLOW;
}
// ======================== Scripts
private void setRespawnScript() {
sequentialScript.add(new SmoothMoveTo(this, new Vector2(10 * Configuration.gameScale, -2 * Configuration.gameScale),
100000));
sequentialScript.add(new Wait(this, 50));
sequentialScript.add(new SmoothMoveTo(this, new Vector2(10 * Configuration.gameScale, 4 * Configuration.gameScale), 3));
sequentialScript.add(new Wait(this, 20));
sequentialScript.add(new Active(this, true));
}
public void setVictoryScript() {
sequentialScript.clear();
this.setActive(false);
sequentialScript.add(new Wait(this, 150));
sequentialScript.add(new SmoothMoveTo(this, new Vector2(10 * Configuration.gameScale, 6 * Configuration.gameScale),
10));
sequentialScript.add(new Wait(this, 25));
sequentialScript.add(new SmoothMoveTo(this, new Vector2(10 * Configuration.gameScale, 4 * Configuration.gameScale),.5f));
sequentialScript.add(new Wait(this, 10));
sequentialScript.add(new SmoothMoveTo(this, new Vector2(10 * Configuration.gameScale, 26 * Configuration.gameScale), 3));
sequentialScript.add(new Wait(this, 4000));
}
// ========================Death and Rebirth
public void killShip(World world) {
ticks = 0;
setDead(true);
setActive(false);
sequentialScript.clear();
setLives(getLives() - 1);
addExplosions(world);
dropItems(world);
position.y = -2 * Configuration.gameScale;
position.x = 10 * Configuration.gameScale;
velocity.x = 0;
velocity.y = 0;
setDamage(baseDamage);
setAlpha(0);
tandemScript.add(new Flash(this,1,192/Configuration.frameRate));
if (getLives() <= 0) {
world.gameOver();
sequentialScript.clear();
position = (new Vector2(10*Configuration.gameScale,-6*Configuration.gameScale));
influence.x = position.x - ((width * (INFLUENCE_SCALE - 1)) / 2);
influence.y = position.y - ((height * (INFLUENCE_SCALE - 1)) / 2);
}else if (isDead() && (lives > 0)) {
setRespawnScript();
}
}
public void dropItems(World world) {
float amountOfPowerToDrop = (getDamage() - 1) * .5f;
for (float x = 0; x < amountOfPowerToDrop; x += .1) {
world.getItems().add(getDroppedPower());
}
}
/**
* @return the dead
*/
public boolean isDead() {
return dead;
}
/**
* @param dead
* the dead to set
*/
public void setDead(boolean dead) {
this.dead = dead;
}
/**
* sets damage to base damage, sets ship to not dead
*/
private void respawn(World world) {
health = 1;
if (ticks < 24) {
deathExplosion();
}
if (ticks >= 80) {
setActive(true);
checkControls();
influence.height = height * INFLUENCE_SCALE;
influence.width = width * INFLUENCE_SCALE;
influence.x = position.x - ((width * (INFLUENCE_SCALE - 1)) / 2);
influence.y = position.y - ((height * (INFLUENCE_SCALE - 1)) / 2);
}
if (ticks > 192) {
ticks = 0;
sequentialScript.clear();
setDead(false);
}
}
private void deathExplosion() {
if (influence.height < MAX_DEATH_EXPLOSION_SIZE) {
float delta = Gdx.graphics.getDeltaTime();
influence.width += influence.width * DEATH_EXPLOSION_SPEED * delta;
influence.height += influence.height * DEATH_EXPLOSION_SPEED * delta;
influence.x -= influence.width * DEATH_EXPLOSION_SPEED * delta / 2;
influence.y -= influence.height * DEATH_EXPLOSION_SPEED * delta / 2;
} else {
influence.height = height * INFLUENCE_SCALE;
influence.width = width * INFLUENCE_SCALE;
influence.x = position.x - ((width * (INFLUENCE_SCALE - 1)) / 2);
influence.y = position.y - ((height * (INFLUENCE_SCALE - 1)) / 2);
}
}
// ========Stats
/**
* @return the lives
*/
public int getLives() {
return lives;
}
/**
* @param lives
* the lives to set
*/
public void setLives(int lives) {
this.lives = lives;
}
/**
* @return the health
*/
public int getHealth() {
return health;
}
/**
* @param health
* the health to set
*/
public void setHealth(int health) {
this.health = health;
}
/**
* @return the area of influence
*/
public Rectangle getInfluence() {
return influence;
}
/**
* @return the damage
*/
public float getDamage() {
return damage;
}
/**
* @param damage
* the damage to set
*/
public void setDamage(float damage) {
this.damage = damage;
}
public void upDamage(float value) {
if (maxDamage-damage>=value) {
damage = round(damage += value, 1);
}else if(value>maxDamage-damage){
damage = maxDamage;
}
}
public static float round(float d, int decimalPlace) {
BigDecimal bd = new BigDecimal(Float.toString(d));
bd = bd.setScale(decimalPlace, BigDecimal.ROUND_HALF_UP);
return bd.floatValue();
}
public void downDamage() {
if (damage > 1) {
damage--;
}
}
public float getBaseDamage() {
return baseDamage;
}
/**
* @return the deathDamage
*/
public float getDeathDamage() {
return deathDamage;
}
// =====items
public Item getDroppedPower() {
Random random = new Random();
float angle = 50 - random.nextInt(100);
Power power = new Power(Power.SPEED, 0, 1f * Configuration.gameScale, 1f * Configuration.gameScale,
new Vector2(getPosition().x + getWidth() / 2, getPosition().y + getHeight() / 2), new Vector2(
new Vector2(getPosition().x + angle, getPosition().y + 90 - Math.abs(angle)).sub(getPosition())
.nor()), .1f);
return power;
}
// ================MISC
public void shoot(World world) {
if (isActive()) {
if (isShooting() && world.getCounter() % fireRate == 0) {
world.addBullet(new Bullet(Bullet.BULLETSPEED, 0, 1 * Configuration.gameScale,
1 * Configuration.gameScale, new Vector2((getPosition().x - (getWidth() / 1.3f))
- ((1 * Configuration.gameScale) / 4), getPosition().y + getHeight() / 2), new Vector2(
new Vector2(getPosition().x, getPosition().y + 90).sub(getPosition()).nor())));
world.addBullet(new Bullet(Bullet.BULLETSPEED, 0, 1 * Configuration.gameScale,
1 * Configuration.gameScale, new Vector2((getPosition().x - (getWidth() / 1.3f))
+ ((1 * Configuration.gameScale) / 4), getPosition().y + getHeight() / 2), new Vector2(
new Vector2(getPosition().x, getPosition().y + 90).sub(getPosition()).nor())));
Audio.shoot();
}
}
}
public float getSlowEffectRotation() {
return slowEffectRotation;
}
public void setSlowEffectRotation(float slowEffectRotation) {
this.slowEffectRotation = slowEffectRotation;
}
public static int getStartingLives() {
return startingLives;
}
public String getSpriteName() {
return spriteName;
}
public void damage(int damage) {
health -= damage;
}
public void reset(World world) {
setDead(false);
setBombs(3);
setLives(Ship.getStartingLives());
health = 1;
setPosition(new Vector2(10 * Configuration.gameScale, 3 * Configuration.gameScale));
getInfoBox().setScore(world.getLevel().getName(), 0);
setActive(true);
setMOVE_DOWN(false);
setMOVE_UP(false);
setMOVE_LEFT(false);
setMOVE_RIGHT(false);
setSLOW(false);
checkControls();
}
public void startPosition() {
setPosition(new Vector2(10 * Configuration.gameScale, 3 * Configuration.gameScale));
setActive(true);
setMOVE_DOWN(false);
setMOVE_UP(false);
setMOVE_LEFT(false);
setMOVE_RIGHT(false);
setSLOW(false);
checkControls();
}
}