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.Polygon;
import org.newdawn.slick.geom.Rectangle;
import org.newdawn.slick.geom.Shape;
import org.newdawn.slick.geom.Transform;
import org.newdawn.slick.geom.Vector2f;
import org.newdawn.slick.state.StateBasedGame;
import com.crash.Body;
import com.shade.base.Entity;
import com.shade.base.Level;
import com.shade.crash.Repelable;
import com.shade.levels.Model;
import com.shade.lighting.LuminousEntity;
import com.shade.util.Geom;
public class TransparentDoor extends Body implements LuminousEntity, Repelable {
private enum ActiveSide {
TOP, RIGHT, BOTTOM, LEFT
};
private static Sound open;
private ActiveSide softspot;
private int zindex;
private float luminosity;
private int times, timer;
private boolean active;
private float x, y, width, height;
private float heading;
private float xPivot, yPivot;
private Image door, arrow;
static {
try {
open = new Sound("entities/door/open.ogg");
} catch (SlickException e) {
e.printStackTrace();
}
}
public TransparentDoor(int x, int y, int z, int r) throws SlickException {
softspot = ActiveSide.values()[r];
int w = (r == 0 || r == 2) ? 60 : 11;
int h = (r == 1 || r == 3) ? 60 : 11;
initShape(x, y, w, h);
this.x = x;
this.y = y;
width = w;
height = h;
initPivot(r);
initResources(r);
zindex = z;
}
private void initResources(int r) throws SlickException {
if (r == 0 || r == 2) {
door = new Image("entities/door/door-horizontal-translucent.png");
}
if (r == 1 || r == 3) {
door = new Image("entities/door/door-vertical-translucent.png");
}
arrow = new Image("entities/door/arrow.png");
if (r == 0) {
arrow.rotate(180);
}
if (r == 1) {
arrow.rotate(-90);
}
if (r == 3) {
arrow.rotate(90);
}
}
private void initPivot(int r) {
if (r == 0) {
xPivot = getX() + getWidth();
yPivot = getYCenter();
}
if (r == 1) {
xPivot = getXCenter();
yPivot = getY() + getHeight();
}
if (r == 2) {
xPivot = getX();
yPivot = getYCenter();
}
if (r == 3) {
xPivot = getXCenter();
yPivot = getY();
}
}
private void initShape(int x, int y, int w, int h) {
shape = new Rectangle(x, y, w, h);
}
public Shape castShadow(float direction, float depth) {
return null;
/*
Vector2f v = Geom.calculateVector(getZIndex() * depth, direction);
Transform t = Transform.createTranslateTransform(v.x, v.y);
Polygon extent = (Polygon) shape.transform(t);
int index = 0;
if (active) {
float distance = Float.MAX_VALUE;
for (int i = 0; i < extent.getPointCount(); i++) {
float[] p = closestPoint(extent.getPoint(i), shape.getPoints());
float d = Geom.distance2(extent.getPoint(i), p[0], p[1]);
if (d < distance) {
index = i;
distance = d;
}
}
} else {
if (v.y > 0) { // bottom
if (v.x > 0) { // right
index = 0;
} else { // left
index = 1;
}
} else { // top
if (v.x > 0) { // right
index = 3;
} else { // left
index = 2;
}
}
}
Polygon shade = new Polygon();
for (int i = 1; i < 4; i++) {
int c = (4 + index + i) % 4;
float[] p = extent.getPoint(c);
shade.addPoint(p[0], p[1]);
}
for (int i = 3; i > 0; i--) {
int c = (4 + index + i) % 4;
float[] p = shape.getPoint(c);
shade.addPoint(p[0], p[1]);
}
return shade;*/
}
/* Find the closest piont in points to s. */
private float[] closestPoint(float[] s, float[] points) {
float[] closest = new float[2];
closest[0] = points[0];
closest[1] = points[1];
float distance = Geom.distance2(s[0], s[1], points[0], points[1]);
for (int i = 2; i < points.length / 2; i++) {
float d = Geom.distance2(s, points[2 * i], points[2 * i + 1]);
if (d < distance) {
closest[0] = points[2 * i];
closest[1] = points[2 * i + 1];
distance = d;
}
}
return closest;
}
public float getLuminosity() {
return luminosity;
}
public int getZIndex() {
return zindex;
}
public void setLuminosity(float l) {
luminosity = l;
}
public void addToLevel(Level<?> l) {
Model m = (Model) l;
if (softspot == ActiveSide.TOP) {
m.add(new Dummy(x + width / 2, y - 20, arrow));
}
if (softspot == ActiveSide.RIGHT) {
m.add(new Dummy(x + width + 20, y + height / 2, arrow));
}
if (softspot == ActiveSide.BOTTOM) {
m.add(new Dummy(x + width / 2, y + height + 20, arrow));
}
if (softspot == ActiveSide.LEFT) {
m.add(new Dummy(x - 20, y + height / 2, arrow));
}
}
public int getRole() {
return Roles.OBSTACLE.ordinal();
}
public void onCollision(Entity obstacle) {
if (obstacle.getRole() == Roles.PLAYER.ordinal() && times > 0) {
activate();
}
if (obstacle.getRole() == Roles.PLAYER.ordinal()) {
if (softspot == ActiveSide.TOP
&& getYCenter() > obstacle.getYCenter()) {
activate();
}
if (softspot == ActiveSide.RIGHT
&& getXCenter() < obstacle.getXCenter()) {
activate();
}
if (softspot == ActiveSide.BOTTOM
&& getYCenter() < obstacle.getYCenter()) {
activate();
}
if (softspot == ActiveSide.LEFT
&& getXCenter() > obstacle.getXCenter()) {
activate();
}
}
}
private void activate() {
if (!active) {
open.play();
}
timer = 0;
active = true;
}
public void removeFromLevel(Level<?> l) {
// TODO Auto-generated method stub
}
public void render(StateBasedGame game, Graphics g) {
g.rotate(xPivot, yPivot, (float) Math.toDegrees(heading));
door.draw(x, y, width, height);
g.resetTransform();
}
public void update(StateBasedGame game, int delta) {
if (game.getContainer().getInput().isKeyPressed(Input.KEY_F)) {
activate();
}
if (active && times < 20) {
shape = shape.transform(Transform.createRotateTransform(
(float) -Math.PI / 40, xPivot, yPivot));
heading -= Math.PI / 40;
times++;
}
if (times == 20) {
timer += delta;
if (timer > 1000) {
active = false;
}
}
if (!active && times != 0) {
shape = shape.transform(Transform.createRotateTransform(
(float) (Math.PI / 40), xPivot, yPivot));
heading += Math.PI / 40;
times--;
}
}
public int compareTo(LuminousEntity o) {
return getZIndex() - o.getZIndex();
}
public void repel(Body b) {
float velx = b.getXVelocity();
float vely = b.getYVelocity();
float playerx = b.getXCenter();
float playery = b.getYCenter();
// determine overlap
float right = playerx - b.getWidth() / 2
- (getXCenter() + width / 2);
float left = playerx + b.getWidth() / 2
- (getXCenter() - width / 2);
float top = playery - b.getHeight() / 2
- (getYCenter() + height / 2);
float bottom = playery + b.getHeight() / 2
- (getYCenter() - height / 2);
float minx = Math.min(Math.abs(right), Math.abs(left));
float miny = Math.min(Math.abs(top), Math.abs(bottom));
if (specialCase(minx, miny)) {
// if we move, move AWAY from the block.
if (Math.abs(playerx - getXCenter() - velx) < Math.abs(playerx
- getXCenter()))
velx = -velx;
b.nudge(-velx, 0);
} else {
if (Math.abs(playery - getYCenter() - vely) < Math.abs(playery
- getYCenter())) {
vely = -vely;
}
b.nudge(0, -vely);
}
}
private boolean specialCase(float minx, float miny) {
if (active) {
return minx > miny;
}
return minx < miny;
}
}