package electrosphere.entity.state.life; import java.util.concurrent.CopyOnWriteArrayList; import org.joml.Vector3d; import electrosphere.engine.Globals; import electrosphere.entity.Entity; import electrosphere.entity.EntityUtils; import electrosphere.entity.btree.BehaviorTree; import electrosphere.entity.state.AnimationPriorities; import electrosphere.entity.types.creature.CreatureUtils; import electrosphere.game.data.creature.type.CreatureType; import electrosphere.game.data.creature.type.HealthSystem; import electrosphere.net.parser.net.message.CharacterMessage; import electrosphere.net.parser.net.message.EntityMessage; import electrosphere.renderer.actor.Actor; import electrosphere.server.datacell.utils.DataCellSearchUtils; /** * The status of the life value of a given entity */ public class LifeState implements BehaviorTree { public static enum LifeStateEnum { ALIVE, DYING, DEAD, } LifeStateEnum state = LifeStateEnum.ALIVE; Entity parent; boolean isInvincible; int lifeCurrent; int lifeMax; int iFrameMaxCount; int iFrameCurrent; int deathFrameCurrent = -1; CopyOnWriteArrayList networkMessageQueue = new CopyOnWriteArrayList(); public LifeState(Entity parent, HealthSystem system){ this.parent = parent; isInvincible = false; lifeMax = system.getMaxHealth(); lifeCurrent = lifeMax; iFrameMaxCount = system.getOnDamageIFrames(); iFrameCurrent = 0; } public LifeState(Entity parent, boolean isInvincible, int lifeCurrent, int lifeMax, int iFrameMaxCount) { this.parent = parent; this.isInvincible = isInvincible; this.lifeCurrent = lifeCurrent; this.lifeMax = lifeMax; this.iFrameMaxCount = iFrameMaxCount; } public boolean isIsAlive() { return state == LifeStateEnum.ALIVE; } public boolean isIsInvincible() { return isInvincible; } public int getLifeCurrent() { return lifeCurrent; } public int getLifeMax() { return lifeMax; } public void setState(LifeStateEnum state) { this.state = state; } public void setIsInvincible(boolean isInvincible) { this.isInvincible = isInvincible; } public void setLifeCurrent(int lifeCurrent) { this.lifeCurrent = lifeCurrent; } public void setLifeMax(int lifeMax) { this.lifeMax = lifeMax; } public int getiFrameMaxCount() { return iFrameMaxCount; } public int getiFrameCurrent() { return iFrameCurrent; } public void setiFrameMaxCount(int iFrameMaxCount) { this.iFrameMaxCount = iFrameMaxCount; } public void setiFrameCurrent(int iFrameCurrent) { this.iFrameCurrent = iFrameCurrent; } public void damage(int damage){ if(!isInvincible){ lifeCurrent = lifeCurrent - damage; isInvincible = true; if(lifeCurrent < 0){ lifeCurrent = 0; if(Globals.RUN_SERVER){ state = LifeStateEnum.DYING; Vector3d position = EntityUtils.getPosition(parent); DataCellSearchUtils.getEntityDataCell(parent).broadcastNetworkMessage( EntityMessage.constructKillMessage( Globals.timekeeper.getNumberOfSimFramesElapsed(), parent.getId() ) ); } } else { iFrameCurrent = iFrameMaxCount; } } } public void revive(){ state = LifeStateEnum.ALIVE; isInvincible = false; lifeCurrent = lifeMax; } public void simulate(float deltaTime){ for(EntityMessage message : networkMessageQueue){ networkMessageQueue.remove(message); long updateTime = message.gettime(); switch(message.getMessageSubtype()){ case KILL: //start death if(Globals.RUN_CLIENT){ state = LifeStateEnum.DYING; lifeCurrent = 0; int frameskip = (int)(Globals.timekeeper.getNumberOfSimFramesElapsed() - message.gettime()); deathFrameCurrent = frameskip; } break; default: //silently ignore break; } } switch(state){ case ALIVE: if(iFrameCurrent > 0){ iFrameCurrent--; if(iFrameCurrent == 0){ isInvincible = false; } } break; case DYING: CreatureType creatureType = Globals.gameConfigCurrent.getCreatureTypeLoader().getCreature(CreatureUtils.getType(parent)); if(deathFrameCurrent > creatureType.getHealthSystem().getDeathFrames()){ state = LifeStateEnum.DEAD; } Actor entityActor = EntityUtils.getActor(parent); if(entityActor != null){ String animationToPlay = creatureType.getHealthSystem().getDeathAnimation(); if( !entityActor.isPlayingAnimation() || !entityActor.isPlayingAnimation(animationToPlay) ){ entityActor.playAnimation(animationToPlay,AnimationPriorities.DEATH); entityActor.incrementAnimationTime(0.0001); } } break; case DEAD: if(Globals.RUN_CLIENT && parent == Globals.playerEntity){ if(!Globals.RUN_SERVER){ //destroy current (client) world stuff //only if not also running server } //submit respawn request Globals.clientConnection.queueOutgoingMessage( CharacterMessage.constructRequestSpawnCharacterMessage() ); } break; } } public void addNetworkMessage(EntityMessage networkMessage) { networkMessageQueue.add(networkMessage); } }