package com.shade.entities;
import org.newdawn.slick.Graphics;
import org.newdawn.slick.Image;
import org.newdawn.slick.Input;
import org.newdawn.slick.SlickException;
import org.newdawn.slick.Sound;
import org.newdawn.slick.geom.Circle;
import org.newdawn.slick.geom.Shape;
import org.newdawn.slick.state.StateBasedGame;
import com.shade.base.Entity;
import com.shade.base.Level;
import com.shade.base.util.State;
import com.shade.base.util.StateManager;
import com.shade.crash.CrashLevel;
import com.shade.crash.Repelable;
import com.shade.entities.bird.Bird;
import com.shade.entities.mushroom.Mushroom;
import com.shade.entities.util.Sizzle2;
import com.shade.entities.util.Sparkler;
import com.shade.lighting.LuminousEntity;
public class Player extends Linkable {
public static final int INVINCIBLE_START = 3000;
public static final float MIN_SPEED = 2.4f;
public static final float MAX_SPEED = 3.6f;
public static final float INITIAL_SPEED = MAX_SPEED / 2 + MIN_SPEED / 2;
private static final int MUSHROOM_LIMIT = 3;
private static final int PLAYER_HEIGHT = 3;
private enum PlayerState {
NORMAL, STUNNED
};
private StateManager manager;
protected Image normal;
private float luminosity;
private Sound register, damage;
private boolean impeded;
private float mileage;
protected int invincibleTimer, flipper, flipthreshold;
private Sizzle2[] sizzles;
private float speed;
public Player(int x, int y) throws SlickException {
initShape(x, y);
initResources();
initSizzles();
initStates();
invincibleTimer = INVINCIBLE_START;
flipthreshold = 1;
speed = INITIAL_SPEED;
}
public void initSizzles() {
sizzles = new Sizzle2[8];
for (int i = 0; i < sizzles.length; i++) {
int x = (int) (Math.cos(Math.PI * 2 * i / 8) * getWidth() * 2 / 5);
int y = (int) (Math.sin(Math.PI * 2 * i / 8) * getHeight() * 2 / 5);
try {
sizzles[i] = new Sizzle2(this,10, x, y, "entities/sparkle/puff.png");
} catch (Exception e) {
e.printStackTrace();
}
}
}
private void sizzle(Graphics g) {
for (int i = 0; i < sizzles.length; i++) {
sizzles[i].animate(g);
}
}
private void initShape(int x, int y) {
shape = new Circle(x, y, 18);
}
private void initResources() throws SlickException {
normal = new Image("entities/player/player.png");
register = new Sound("entities/player/register.ogg");
damage = new Sound("entities/player/hit.ogg");
}
private void initStates() {
manager = new StateManager();
manager.add(new NormalState());
manager.add(new StunnedState());
}
public void stun() {
manager.enter(Player.PlayerState.STUNNED);
damage.play();
}
private class NormalState implements State {
public boolean isNamed(Object state) {
return state == PlayerState.NORMAL;
}
public void enter() {
}
public int getRole() {
// TODO Auto-generated method stub
return 0;
}
public void onCollision(Entity obstacle) {
if (obstacle.getRole() == Roles.BASKET.ordinal() && next != null) {
Linkable m = next;
next = null;
Linkable l = (Linkable) obstacle;
l.attach(m);
register.play();
}
if (obstacle.getRole() == Roles.MONSTER.ordinal()) {
manager.enter(Player.PlayerState.STUNNED);
damage.play();
}
if (obstacle.getRole() == Roles.BIRD.ordinal()) {
Bird b = (Bird) obstacle;
if (b.isAttacking()) {
manager.enter(Player.PlayerState.STUNNED);
damage.play();
}
}
if (obstacle.getRole() == Roles.SANDPIT.ordinal()) {
impeded = true;
}
}
public void render(StateBasedGame game, Graphics g) {
double inverse = INVINCIBLE_START * 7 / 6 - invincibleTimer;
if (Math.sin(inverse * inverse / (40000.0 * Math.PI)) > 0) {
normal.drawCentered(getXCenter(), getYCenter());
}
if (invincibleTimer <= 0) {
normal.drawCentered(getXCenter(), getYCenter());
sizzle(g);
}
}
public void update(StateBasedGame game, int delta) {
testAndMove(game.getContainer().getInput(), delta);
testAndWrap();
for (int i = 0; i < sizzles.length; i++)
sizzles[i].update(delta);
impeded = false;
if(invincibleTimer-delta<0&&invincibleTimer>0)
for (int i = 0; i < sizzles.length; i++)
sizzles[i].resetTimer();
if (invincibleTimer > 0) {
invincibleTimer -= delta;
}
}
private void testAndMove(Input input, int delta) {
xVelocity = 0;
yVelocity = 0;
if (input.isKeyDown(Input.KEY_LEFT)) {
xVelocity--;
}
if (input.isKeyDown(Input.KEY_RIGHT)) {
xVelocity++;
}
if (input.isKeyDown(Input.KEY_UP)) {
yVelocity--;
}
if (input.isKeyDown(Input.KEY_DOWN)) {
yVelocity++;
}
double mag = Math.sqrt(xVelocity * xVelocity + yVelocity
* yVelocity);
// make it uniform speed
float sped = (impeded) ? speed / 2 : speed;
xVelocity = (float) (1.0 * sped * xVelocity / mag);
yVelocity = (float) (1.0 * sped * yVelocity / mag);
if (mag != 0) {
nudge(xVelocity, yVelocity);
mileage += sped;
} else {
xVelocity = 0;
yVelocity = 0;
}
}
}
public void setSpeed(float newSpeed) {
speed = newSpeed;
}
private class StunnedState implements State {
private int timer;
private int failmer;
public boolean isNamed(Object state) {
return state == PlayerState.STUNNED;
}
public void enter() {
scatterShrooms();
for (int i = 0; i < sizzles.length; i++)
sizzles[i].resetTimer();
timer = 0;
failmer = 0;
}
// HACK! TODO: KILL HACK!
private void scatterShrooms() {
Linkable la = next;
while (la != null) {
Mushroom m = (Mushroom) la;
la = la.next;
m.scatter();
}
}
public int getRole() {
// TODO Auto-generated method stub
return PlayerState.STUNNED.ordinal();
}
public void onCollision(Entity obstacle) {
}
public void render(StateBasedGame game, Graphics g) {
if (failmer % 5 > 2) {
normal.drawCentered(getXCenter(), getYCenter());
}
}
public void update(StateBasedGame game, int delta) {
timer += delta;
failmer++;
if (timer > 800){
manager.enter(PlayerState.NORMAL);
invincibleTimer = 2000;
}
}
private void testAndMove(Input input, int delta) {
xVelocity = 0;
yVelocity = 0;
if (input.isKeyDown(Input.KEY_LEFT)) {
xVelocity--;
}
if (input.isKeyDown(Input.KEY_RIGHT)) {
xVelocity++;
}
if (input.isKeyDown(Input.KEY_UP)) {
yVelocity--;
}
if (input.isKeyDown(Input.KEY_DOWN)) {
yVelocity++;
}
double mag = Math.sqrt(xVelocity * xVelocity + yVelocity
* yVelocity);
// make it uniform speed
float sped = (impeded) ? speed / 2 : speed;
xVelocity = (float) (1.0 * sped * xVelocity / mag);
yVelocity = (float) (1.0 * sped * yVelocity / mag);
if (mag != 0) {
nudge(xVelocity, yVelocity);
} else {
xVelocity = 0;
yVelocity = 0;
}
}
}
@Override
public void attach(Linkable l) {
if (next == null) {
super.attach(l);
return;
}
int i = 1;
Linkable head = next;
while (head.next != null) {
i++;
head = head.next;
}
if (i < MUSHROOM_LIMIT) {
super.attach(l);
}
}
public Shape castShadow(float direction, float depth) {
return null;
}
public float getLuminosity() {
float max = 0;
for (int i = 0; i < sizzles.length; i++) {
max += sizzles[i].getLuminosity();
}
return invincibleTimer > 0 || manager.currentState().getRole()==PlayerState.STUNNED.ordinal() ? 0 : max;
}
public int getZIndex() {
return PLAYER_HEIGHT;
}
public void setLuminosity(float l) {
luminosity = l;
}
public void addToLevel(Level<?> l) {
}
public float totalMileage() {
return mileage;
}
public boolean isStunned() {
return manager.currentState().isNamed(PlayerState.STUNNED);
}
public int getRole() {
return Roles.PLAYER.ordinal();
}
public void setSmokeCount(int count) {
// smoky.changeCount(count);
}
public int getSmokeCount() {
// return smoky.getCount();
return 0;
}
public void onCollision(Entity obstacle) {
manager.onCollision(obstacle);
if (obstacle.getRole() == Roles.OBSTACLE.ordinal()) {
Repelable b = (Repelable) obstacle;
b.repel(this);
}
/*
* TODO: determine if we want the chest to be an obstacle. if
* (obstacle.getRole() == Roles.TREASURE.ordinal()) { Repelable b =
* (Repelable) obstacle; b.repel(this); }
*/
}
public void removeFromLevel(Level<?> l) {
CrashLevel level = (CrashLevel) l;
try {
level.add(new MockPlayer((int) getXCenter(), (int) getYCenter()));
} catch (SlickException e) {
e.printStackTrace();
}
}
public void render(StateBasedGame game, Graphics g) {
//ghost.animate(g);
if (speed > MAX_SPEED - .4) {
//smoky.animate(g);
}
manager.render(game, g);
}
public void update(StateBasedGame game, int delta) {
manager.update(game, delta);
}
public int compareTo(LuminousEntity e) {
return getZIndex() - e.getZIndex();
}
}