package com.shade.entities.monster; import org.newdawn.slick.Graphics; import org.newdawn.slick.SlickException; import org.newdawn.slick.geom.Circle; import org.newdawn.slick.geom.Shape; import org.newdawn.slick.state.StateBasedGame; import com.crash.Body; import com.shade.base.Entity; import com.shade.base.Level; import com.shade.base.util.StateManager; import com.shade.controls.DayPhaseTimer; import com.shade.crash.CrashLevel; import com.shade.crash.Repelable; import com.shade.entities.Basket; import com.shade.entities.Player; import com.shade.entities.Roles; import com.shade.entities.mushroom.Mushroom; import com.shade.levels.Model; import com.shade.lighting.LuminousEntity; /** * The real deal; this mole is the sum of different mole states. * * No I haven't heard of encapsulation. * * @author Jonathan Jou <j.j@duke.edu> */ public final class Monster extends Body implements LuminousEntity{ protected enum States { PROWLING, SLEEPING, LOST, CHASING, WANDERING, SNIFFING } protected CrashLevel level; protected StateManager manager; protected Mushroom target; protected float heading; protected float range; protected float speed; private float luminosity; public Monster(int x, int y, int range, float speed) throws SlickException { heading = (float) (Math.PI); this.range = range; this.speed = speed; initShape(x, y); initStates(); } private void initShape(float x, float y) { shape = new Circle(x, y, 18f); } private void initStates() throws SlickException { manager = new StateManager(); manager.add(new ProwlingMonster(this)); manager.add(new ChasingMonster(this)); manager.add(new SleepingMonster(this)); manager.add(new LostMonster(this)); manager.add(new SniffingMonster(this)); manager.add(new WanderingMonster(this)); } protected void kill() { level.remove(this); } public void move(double rate){ float x = (float)(Math.cos(heading-Math.PI/2)*speed*rate); float y = (float)(Math.sin(heading-Math.PI/2)*speed*rate); nudge(x,y); } public float getLuminosity() { return luminosity; } public void setLuminosity(float l) { luminosity = l; } public void addToLevel(Level < ? > l) { level = (CrashLevel) l; } public int getRole() { return Roles.MONSTER.ordinal(); } public void onCollision(Entity obstacle) { manager.onCollision(obstacle); if (obstacle.getRole() == Roles.OBSTACLE.ordinal()) { Repelable b = (Repelable) obstacle; b.repel(this); } } public boolean canChase(){ return playerInSight() && playerInRange(); } public boolean playerInSight(){ Player p = (Player)level.getEntitiesByRole(Roles.PLAYER.ordinal())[0]; return level.lineOfSight(this,p, this,(Basket)level.getEntitiesByRole(Roles.BASKET.ordinal())[0]) && p.getLuminosity()>0.6; } public boolean playerInRange(){ Player p = (Player)level.getEntitiesByRole(Roles.PLAYER.ordinal())[0]; float distx = p.getXCenter()-getXCenter(); float disty = p.getYCenter()-getYCenter(); return Math.sqrt(distx*distx+disty*disty)<range; } public void render(StateBasedGame game, Graphics g) { g.rotate(getXCenter(), getYCenter(), (float) Math.toDegrees(heading)); manager.render(game, g); g.resetTransform(); } public void yawn(){ Model mode = (Model)level; if(mode.getTimer().getDaylightStatus()==DayPhaseTimer.DayLightStatus.NIGHT){ manager.enter(States.SLEEPING); } } public void wake(){ Model mode = (Model)level; if(mode.getTimer().getDaylightStatus()==DayPhaseTimer.DayLightStatus.DAWN){ manager.enter(States.PROWLING); } } public void update(StateBasedGame game, int delta) { manager.update(game, delta); testAndWrap(); } /** * Checks whether a linkable is over the edge of the screen and wraps it if * it is. */ protected void testAndWrap() { if (getXCenter() <= 5) { shape.setCenterX(795); } if (getXCenter() > 795) { shape.setCenterX(5); } if (getYCenter() <= 5) { shape.setCenterY(595); } if (getYCenter() > 595) { shape.setCenterY(5); } } public Shape castShadow(float direction, float depth) { return null; } public int getZIndex() { return 2; } public int compareTo(LuminousEntity l) { return getZIndex() - l.getZIndex(); } public void removeFromLevel(Level<?> l) { level.remove(this); } }