package robombs.game.model; import robombs.game.*; import robombs.game.util.*; import com.threed.jpct.*; import robombs.game.sound.*; /** * A local object that holds a player's data. */ public class LocalPlayerObject extends LocalObject { private Matrix viewRot = new Matrix(); private SimpleVector ellipsoid = new SimpleVector(3.5f, 5, 3.5f); private float turnSpeed = 0; protected float moveSpeed = 0.75f; private boolean isDead = false; private long time = 0; private boolean isActive = false; private PlayerPowers powers=null; private float zoomFactor=1; private long invTime = 0; private SimpleVector movement=null; public LocalPlayerObject(int clientID) { super(clientID); setSpecialValue(Globals.LIVES); powers=new PlayerPowers(); } public LocalPlayerObject() { cid=0; powers=new PlayerPowers(); } public void setClientID(int id) { cid=id; } public void reset() { setSpecialValue(Globals.LIVES); powers=new PlayerPowers(); setViewRotation(new Matrix()); setRotation(new Matrix()); setSpeed(new SimpleVector()); setType(Types.PLAYER); setPosition(new SimpleVector(0,-10000,0)); setAlive(); } public void setTurnSpeed(float speed) { turnSpeed=speed; } public PlayerPowers getPlayerPowers() { return powers; } public SimpleVector getEllipsoid() { return ellipsoid; } /** * Gets the "view rotation". This is the direction in which the player is looking. Not the direction * in which he/she's moving. * @return Matrix the view rotation */ public Matrix getViewRotation() { return viewRot; } /** * Sets the "view rotation". This is the direction in which the player is looking. Not the direction * in which he/she's moving. * @param mat the view direction */ public void setViewRotation(Matrix mat) { viewRot = mat; } public boolean shouldbeTransparent() { return zoomFactor<=0.35f; } /** * Flag the player as dead. */ public synchronized void setDead() { if (!isDead) { setValue(0); isDead = true; time = Ticker.getTime(); long spec=getSpecialValue(); if (spec>0) { spec--; setSpecialValue(spec); } else { setSpecialValue(0); // Just to make sure that's never below 0 for some reason } if (this.getView()!=null) { // Make sure that the coarpse doesn't move on other clients setSpeed(SimpleVector.ORIGIN); } } } /** * Flag the player as alive. */ public synchronized void setAlive() { if (isDead) { isDead = false; time = 0; setValue(100); getPlayerPowers().refillWater(); } } /** * Is the player dead? * @return boolean is he/she? */ public synchronized boolean isDead() { return isDead; } /** * Is the player is dead, here's since how long... * @return long how long is the player dead? */ public long deadSince() { return time; } public SimpleVector getLocalMovementCorrection() { return movement; } public void setLocalMovementCorrection(SimpleVector mc) { if (mc!=null) { movement=new SimpleVector(mc); } else { movement=null; } } /** * Activate a player. An active player is currently playing but can very well be dead. */ public void activate() { isActive = true; } /** * Deactivate a player. */ public void deactivate() { isActive = false; } /** * Is the player active. An active player is currently playing but can very well be dead. * @return boolean is the player active? */ public boolean isActive() { return isActive; } /** * Align the camera to the player. * @param camera the camera that should be aligned */ public void alignCamera(Camera camera, int ticks) { if (getPosition() != null) { if (!isDead() || !isActive()) { for (int i=0; i<ticks; i++) { // Making this interpolation based on ticks fixes the jitter on low fps SimpleVector center=getPosition(); SimpleVector oldCamPos=camera.getPosition(); SimpleVector oldestCamPos=new SimpleVector(oldCamPos); oldCamPos.scalarMul(4f); SimpleVector camPos=new SimpleVector(center); SimpleVector zOffset=getViewRotation().invert3x3().getZAxis(); SimpleVector yOffset=new SimpleVector(0, -50*zoomFactor*zoomFactor, 0); zOffset.scalarMul(-70f*zoomFactor); camPos.add(zOffset); camPos.add(yOffset); camPos.add(oldCamPos); camPos.scalarMul(0.2f); SimpleVector delta=camPos.calcSub(oldestCamPos); float len=delta.length(); if (len!=0) { camera.moveCamera(delta.normalize(), len); } camera.lookAt(center); } } } } /** * Move the player according to key and mouse input. * @param world the world in which the player exists * @param keys the currently pressed keys * @param mouse the mouse input * @param ticks the game time passed since the last call * @param a dummy object used for collision detection. With this, the listener can distinguish between * collision with no source (explosions) and the player. * @return boolean true, if the player has moved. False otherwise. */ public boolean move(World world, KeyStates keys, MouseMapper mouse, long ticks, PlayerDummy dummy, int forcedStepsBack) { // Should be possible to use the player instead of dummy...todo! PlayerPowers pp=getPlayerPowers(); int sick=pp.isSick(); float mul=1; if (sick==PlayerPowers.SLOWER) { mul=0.7f; } if (sick==PlayerPowers.FASTER) { mul=1.3f; } SimpleVector pos = getPosition(); boolean changed = false; if (!isDead() && this.getAnimation()!=Animations.DIE && this.getAnimation()!=Animations.DEAD) { // Don't do this, if either the pos is null (unlikely) or the y-position is very low, // which means that the player doesn't touch the ground but floats in the sky. if (pos != null && pos.y>Globals.skyLimit) { pos.y=-10.01f; setSpeed(new SimpleVector()); pos.add(new SimpleVector(0, ellipsoid.y, 0)); SimpleVector netSpeed=new SimpleVector(); SimpleVector temp=new SimpleVector(); if (KeyStates.up && forcedStepsBack<=0) { changed = true; temp.set(getRotation().getZAxis()); } if (KeyStates.down || forcedStepsBack>0) { changed = true; temp.set(getRotation().getZAxis()); temp.scalarMul(-1); } if (KeyStates.left) { changed = true; SimpleVector temp2=getRotation().getXAxis(); temp2.scalarMul(-1); temp.add(temp2); } if (KeyStates.right) { changed = true; SimpleVector temp2=getRotation().getXAxis(); temp.add(temp2); } if (getLocalMovementCorrection()!=null) { // When entering the collision mode of the bombs, the player get checked // if he's located "inside" the bomb. If that is the case, an alternate // movement vector will be calculated and set. This is, what you see here. // This vector exists on the client only. It will never be transfered over the net. temp=getLocalMovementCorrection(); } else { temp=temp.normalize(); } temp.scalarMul(mul*moveSpeed*(float) ticks); dummy.getTranslationMatrix().setIdentity(); dummy.translate(pos); temp = dummy.checkForCollisionEllipsoid(temp, ellipsoid, 7); pos.add(temp); temp.scalarMul(1f/(float)ticks); netSpeed.add(temp); setSpeed(netSpeed); Matrix rot = getRotation(); int dx = mouse.getDeltaX(); float ts = 0; float angle=SoundManager.ANGLE_NOT_CHANGED; if (dx != 0) { ts = Math.abs(dx) / -(((400-turnSpeed)+1)*10); angle=ts; } if (dx < 0) { viewRot.rotateAxis(viewRot.getYAxis(), ts); rot.rotateY(ts); } if (dx > 0) { viewRot.rotateAxis(viewRot.getYAxis(), -ts); rot.rotateY( -ts); } dummy.setBackRotationMatrix(rot); // Store it in the dummy...collision detection needs it zoomFactor-=0.125f*(float) mouse.getWheel(); if (zoomFactor<Globals.minZoom) { zoomFactor=Globals.minZoom; } if (zoomFactor>Globals.maxZoom) { zoomFactor=Globals.maxZoom; } pos.add(new SimpleVector(0, -ellipsoid.y, 0)); pos.y=-10.01f; setPosition(pos); SoundManager.getInstance().setListener(pos, angle, ticks); } } else { // Nothing moves here anymore... setSpeed(new SimpleVector()); } return changed; } public void setInvincible(boolean inv) { if (inv) { invTime=Ticker.getTime(); } super.setInvincible(inv); } public boolean isInvincible() { boolean ret=super.isInvincible(); if (ret) { if (Ticker.hasPassed(invTime, Globals.invincibleTime)) { ret=false; super.setInvincible(false); } } return ret; } }