package ru.alastar.game;
import java.util.ArrayList;
import java.util.Hashtable;
import java.util.Timer;
import java.util.TimerTask;
import com.alastar.game.enums.Type;
import com.alastar.game.enums.TypeId;
import com.alastar.game.enums.UpdateType;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.math.Vector3;
import com.badlogic.gdx.physics.box2d.Body;
import com.badlogic.gdx.physics.box2d.BodyDef;
import com.badlogic.gdx.physics.box2d.BodyDef.BodyType;
import com.badlogic.gdx.physics.box2d.CircleShape;
import com.badlogic.gdx.physics.box2d.Fixture;
import com.badlogic.gdx.physics.box2d.FixtureDef;
import ru.alastar.enums.EntityType;
import ru.alastar.game.projectiles.TestProjectile;
import ru.alastar.game.systems.BattleSystem;
import ru.alastar.game.systems.SkillsSystem;
import ru.alastar.game.systems.gui.NetGUIAnswer;
import ru.alastar.game.systems.gui.NetGUIInfo;
import ru.alastar.game.systems.gui.NetGUISystem;
import ru.alastar.game.systems.gui.hadlers.GUIHandler;
import ru.alastar.game.systems.gui.hadlers.PlayerButtonGUIHandler;
import ru.alastar.main.Main;
import ru.alastar.main.net.ConnectedClient;
import ru.alastar.main.net.Server;
import ru.alastar.main.net.responses.AddEntityResponse;
import ru.alastar.main.net.responses.AddEquipResponse;
import ru.alastar.main.net.responses.RemovePacket;
import ru.alastar.main.net.responses.SpeechResponse;
import ru.alastar.main.net.responses.TargetInfoResponse;
import ru.alastar.main.net.responses.TargetResponse;
import ru.alastar.main.net.responses.UpdatePlayerResponse;
import ru.alastar.physics.IPhysic;
import ru.alastar.physics.PhysicalData;
import ru.alastar.world.ServerTile;
import ru.alastar.world.ServerWorld;
public class Entity extends Transform implements IUpdate, IPhysic
{
public int id = -1;
public String caption = "Generic Entity";
public EntityType type = EntityType.Human;
public Stats stats;
public Skills skills;
public boolean invul = false;
public float invulTime = 15; // in
// seconds
public static int startHits = 15;
public ServerWorld world;
public int height = 2;
public long lastMoveTime = System.currentTimeMillis();
public Hashtable<String, NetGUIInfo> gui = new Hashtable<String, NetGUIInfo>();
public Hashtable<String, GUIHandler> handlingGUIs = new Hashtable<String, GUIHandler>();
public Entity target = null;
public boolean warMode = false;
public Timer battleTimer = null;
public ArrayList<IUpdate> allAround;
public boolean isAI = false;
public ru.alastar.game.ai.AI AI = null;
public float speedMod = 4F;
// Physics
public BodyDef bodyDef;
public Body body;
FixtureDef fixtureDef;
Fixture fixture;
CircleShape circle;
private int MAX_VELOCITY = 3;
private Timer updateTimer = null;
private PhysicalData pData;
private boolean active = false;
public Entity(int i, String c, EntityType t, float f, float g, float h,
Skills sk, Stats st, ServerWorld w)
{
super((int) h);
this.id = i;
this.caption = c;
this.type = t;
this.skills = sk;
this.stats = st;
this.world = w;
this.allAround = new ArrayList<IUpdate>();
// Physics
bodyDef = new BodyDef();
bodyDef.type = BodyType.DynamicBody;
bodyDef.position.set(f, g);
bodyDef.linearDamping = 1.5F;
}
public Vector2 getCurrentPosition()
{
if (active)
return body.getPosition();
else
return bodyDef.position;
}
public void setActive()
{
body = world.getPhysic().createBody(bodyDef);
pData = new PhysicalData(this.z, false, this);
// body.setUserData(pData);
circle = new CircleShape();
circle.setRadius(0.5f);
fixtureDef = new FixtureDef();
fixtureDef.shape = circle;
fixtureDef.density = 1f;
fixtureDef.friction = 1f;
fixtureDef.restitution = 0.6f;
fixture = body.createFixture(fixtureDef);
fixture.setUserData((IPhysic)this);
active = true;
circle.dispose();
final Entity e = this;
updateTimer = new Timer();
updateTimer.scheduleAtFixedRate(new TimerTask()
{
@Override
public void run()
{
if (e.body.isActive())
Server.UpdatePosition(e);
else
{
}
}
}, 100, 100);
}
@Override
public void UpdatePhysicalData(int z, boolean b)
{
this.pData.setZ(z);
this.pData.setIgnore(b);
}
public void RemoveYourself(int aId)
{
if (active)
{
updateTimer.cancel();
tryStopAttack();
body.destroyFixture(fixture);
world.getPhysic().destroyBody(body);
// for (IUpdate e : allAround)
// {
// if (e != this)
// e.tryRemoveNear(this);
// }
world.RemoveEntity(this);
Server.saveEntity(this, aId);
Server.unloadInventory(id);
Server.unloadEquip(id);
Server.inventories.remove(id);
Server.equips.remove(id);
Server.entities.remove(id);
}
// Main.Log("[LOGIN]", "Entity removed. Count:" +
// Server.entities.size());
}
public void setRebirthHitsAmount()
{
this.stats.set("Hits", startHits, this);
world.UpdateTargetInfo(this, stats);
}
public void toggleWar(boolean val)
{
this.warMode = val;
this.world.UpdateEntity(this);
}
public boolean tryMove(float x, float y)
{
// Main.Log("[DEBUG]", "Try move. x:" + x + " y:" + y);
/*
* int obstacleHeight = 0; for (int i = 0; i < height; ++i) { if
* (world.GetTile(((int) (this.pos.x + Math.floor(x))), ((int)
* (this.pos.y + Math.floor(y))), (int) this.pos.z + i) != null)
* ++obstacleHeight; } // Main.Log("[INPUT]","obstacle height: " +
* obstacleHeight); if (obstacleHeight < height) { this.pos.x += x;
* this.pos.y += y; this.pos.z += obstacleHeight; CheckIfInAir();
* Server.UpdateEntityPosition(this); // lastMoveTime =
* System.currentTimeMillis(); // Main.Log("[INPUT]","player moved " +
* this.pos.x + " " + this.pos.y ); return true; } else { Tile t =
* world.GetTile(((int) (this.pos.x + Math.floor(x))), ((int)
* (this.pos.y + Math.floor(y))), (int) this.pos.z); //
* Main.Log("[INPUT]","Tile is not null"); if (t != null) { if
* (t.passable) { // Main.Log("[INPUT]","Tile is passable!");
*
* this.pos.x += x; this.pos.y += y; this.pos.z += 1; CheckIfInAir();
*
* Server.UpdateEntityPosition(this); //lastMoveTime =
* System.currentTimeMillis(); // Main.Log("[INPUT]","player moved");
* return true; } else { // Main.Log("[INPUT]","Tile is not passable!");
*
* return false; } } else { // Main.Log("[INPUT]","path is passable!");
*
* this.pos.x += x; this.pos.y += y; CheckIfInAir();
*
* Server.UpdateEntityPosition(this); //lastMoveTime =
* System.currentTimeMillis(); // Main.Log("[INPUT]","player moved");
* return true; }
*
* }
*/
if (System.currentTimeMillis() - lastMoveTime > 100)
{
Vector2 vel = this.body.getLinearVelocity();
Vector2 pos = this.body.getPosition();
// Main.Log("[INPUT]","max velocity " + MAX_VELOCITY +
// " x velocity " + vel.x + " y velocity " + vel.y);
if (vel.x > -MAX_VELOCITY && vel.y > -MAX_VELOCITY
&& vel.x < MAX_VELOCITY && vel.y < MAX_VELOCITY)
{
this.body.applyLinearImpulse(x * speedMod, y * speedMod, pos.x
+ x, pos.y + y, true);
CheckZ(pos, new Vector2(pos.x + x, pos.y + y));
CheckIfInAir();
UpdatePhysicalData((int) this.z, false);
lastMoveTime = System.currentTimeMillis();
return true;
}
} else
return false;
return false;
}
private void CheckZ(Vector2 from, Vector2 to)
{
ServerTile toTile = world.GetTile(new Vector3((int) to.x, (int) to.y,
this.z));
if (toTile != null)
{
int obstacleHeight = 0;
ServerTile toTileAbove;
for (int i = 1; i <= this.height; ++i)
{
toTileAbove = world.GetTile(new Vector3((int) to.x, (int) to.y,
this.z + i));
if (toTileAbove != null)
++obstacleHeight;
}
if (obstacleHeight < 1)
{
if (toTile.passable)
{
// Main.Log("[ZCheck]", "New z! Its now " + z + " after " +
// (toTile.position.z + 1));
this.z = (int) toTile.position.z + 1;
}
}
}
}
private void CheckIfInAir()
{
ServerTile t;
for (int z = this.z - 1; z > world.zMin; --z)
{
t = world.GetTile(new Vector3((int) body.getPosition().x,
(int) body.getPosition().y, z));
if (t == null)
{
this.z = z;
// Main.Log("[ZCheck]", "Fallen! now z is " + this.z);
} else
break;
}
}
public void AddGUI(NetGUIInfo info)
{
this.gui.put(info.name, info);
}
public boolean haveGUI(String name)
{
if (getGUI(name) != null)
return true;
else
return false;
}
public NetGUIInfo getGUI(String name)
{
return this.gui.get(name);
}
public void tryAttack(Entity e)
{
if (e != null)
{
if (SkillsSystem.getChanceFromSkill(this.skills.vals.get("Swords")) > Server.random
.nextFloat())
{
if (this.isAI)
{
this.AI.OnHitEntity(e);
}
e.dealDamage(this, BattleSystem.calculateDamage(this, e));
SkillsSystem
.tryRaiseSkill(this, this.skills.vals.get("Swords"));
} else
{
Server.sendSpeech(this, "miss");
SkillsSystem
.tryRaiseSkill(this, this.skills.vals.get("Swords"));
}
}
}
private void dealDamage(Entity entity, int calculateDamage)
{
int curHits = this.stats.get("Hits").value;
if ((curHits - calculateDamage) > 0)
{
if (SkillsSystem.getChanceFromSkill(this.skills.vals
.get("Parrying")) > Server.random.nextFloat())
{
SkillsSystem.tryRaiseSkill(this,
this.skills.vals.get("Parrying"));
} else
{
this.stats.set("Hits", curHits - calculateDamage, this);
world.UpdateTargetInfo(this, this.stats);
SkillsSystem.tryRaiseSkill(this,
this.skills.vals.get("Parrying"));
}
if (this.isAI)
{
this.AI.OnGetDamage(entity, calculateDamage);
}
if (target == null)
{
target = entity;
startAttack(entity);
}
Server.sendSpeech(this, Integer.toString(calculateDamage));
} else
{
Server.EntityDead(this, entity);
}
}
public void tryStopAttack()
{
if (battleTimer != null)
battleTimer.cancel();
battleTimer = null;
NullfillTarget();
if (this.isAI)
this.AI.OnLostTarget();
}
private void NullfillTarget()
{
if (!isAI)
{
TargetResponse r = new TargetResponse();
r.id = -1;
Server.SendTo(Server.getClient(this).connection, r);
}
target = null;
}
public void startAttack(Entity entity)
{
if (battleTimer == null)
{
// System.out.println("Start Attack. Weapon speed: " +
// (long)BattleSystem.getWeaponSpeed(this)*1000);
if (entity.target == null)
{
entity.target = this;
entity.startAttack(this);
}
battleTimer = new Timer();
final Entity e = this;
battleTimer.scheduleAtFixedRate(new TimerTask()
{
@Override
public void run()
{
if (target != null)
{
// System.out.println("target is not null");
if (target.stats.get("Hits").value > 0)
{
// System.out.println("and it's alive");
// System.out.println("Dst is " +
// target.pos.dst2(e.pos));
if (target.body.getPosition().dst2(
e.body.getPosition()) <= BattleSystem
.getWeaponRange(e))
{
// System.out.println("and reachable for weapon("+target.pos.dst(e.pos)+")");
if (!target.invul)
{
// System.out.println("and not invul");
tryAttack(target);
} else
{
target = null;
battleTimer.cancel();
battleTimer = null;
}
}
} else
{
target = null;
battleTimer.cancel();
battleTimer = null;
}
} else
{
target = null;
battleTimer.cancel();
battleTimer = null;
}
}
}, 0, (long) BattleSystem.getWeaponSpeed(this) * 1000);
}
}
public void AddGUIHandler(String string, GUIHandler guiHandler)
{
handlingGUIs.put(string, guiHandler);
}
public void RemoveGUIHandler(String string)
{
handlingGUIs.remove(string);
}
public void invokeGUIHandler(NetGUIAnswer r, ConnectedClient c)
{
if (handlingGUIs.containsKey(r.name))
handlingGUIs.get(r.name).handle(r.value.split(" "), c);
}
public void closeGUI(String string)
{
this.gui.remove(string.toLowerCase());
NetGUISystem.closeGUI(string, this);
}
public void actToTarget(Entity e)
{
if (e != this)
{
TargetResponse r = new TargetResponse();
r.id = e.id;
TargetInfoResponse tir = new TargetInfoResponse();
tir.id = e.id;
tir.hits = e.stats.get("Hits").value;
tir.mhits = e.stats.get("Hits").maxValue;
if (this.isAI)
AI.OnTarget(e);
else
{
Server.SendTo(Server.getClient(this).connection, tir);
Server.SendTo(Server.getClient(this).connection, r);
}
if (warMode)
{
if (target != e)
{
Server.warnEntity(this, "You're attacking " + e.caption
+ "!", 1);
Server.warnEntity(e, "You were attacked by " + this.caption
+ "!", 1);
}
this.target = e;
startAttack(e);
// Main.Log("[DEBUG]", "Player " + this.caption + " attacks "
// + e.caption + "!");
} else
{
// Main.Log("[DEBUG]", "Player " + this.caption
// + " just like to click on " + e.caption);
}
}
}
public void ProcessDropdown(ConnectedClient c)
{
if (c.controlledEntity.haveGUI("dropdown"))
{
c.controlledEntity.closeGUI("dropdown");
}
NetGUISystem.OpenGUI(NetGUISystem.CreateGUIInfo("dropdown",
new Vector2(this.body.getPosition().x,
this.body.getPosition().y + this.z),
new Vector2(50, 50), "", "com.alastar.game.gui.GUIDropdown",
"", "Player"), c);
c.controlledEntity.AddGUIHandler("dropdown",
new PlayerButtonGUIHandler());
if (isAI)
{
Server.sendDropdownFor(AI, c, this.body.getPosition().x,
this.body.getPosition().y + this.z);
}
}
public void handleSpeech(String msg, Entity e)
{
if (isAI)
{
AI.OnHear(e, msg);
} else if (Server.getClient(this) != null)
{
SpeechResponse r = new SpeechResponse();
r.msg = "\'" + msg + "\'";
r.id = e.id;
Server.SendTo(Server.getClient(this).connection, r);
}
}
@Override
public void tryAddToNear(IUpdate e)
{
if (!allAround.contains(e))
{
allAround.add(e);
e.UpdateTo(Server.getClient(this));
}
/*
* AddEntityResponse r = new AddEntityResponse(); ConnectedClient c =
* Server.getClient(this);
*
* r.caption = e.caption; r.id = e.id; r.x = (int)
* e.body.getPosition().x; r.y = (int) e.body.getPosition().y; r.z =
* (int) e.z; r.type = e.type; r.warMode = e.warMode;
*
* if(c != null){ Server.SendTo(c.connection, r); Equip eq =
* Server.getEquip(e); AddEquipResponse aer = new AddEquipResponse();
* Item it; for(String slot: eq.contents.keySet()) { it =
* eq.contents.get(slot).item; if(it != null) { aer.amount = it.amount;
* aer.attrs = it.attributes.values; aer.captiion = it.caption; aer.eid
* = e.id; aer.id = it.id; aer.slot = slot; aer.type = it.type; //
* Main.Log("[DEBUG]", "Slot " + slot + " was sended!");
* Server.SendTo(c.connection, aer); } } }
*
* if(isAI && e.id != this.id) AI.OnSeeEntity(e);
*
* }
*/
}
public boolean alreadyTargets()
{
if (target == null)
return false;
else
return true;
}
@Override
public void UpdateTo(ConnectedClient c)
{
AddEntityResponse r = new AddEntityResponse();
r.caption = caption;
r.id = id;
r.x = (int) body.getPosition().x;
r.y = (int) body.getPosition().y;
r.z = (int) z;
r.type = type;
r.warMode = warMode;
if (c != null)
{
Server.SendTo(c.connection, r);
Equip eq = Server.getEquip(this);
AddEquipResponse aer = new AddEquipResponse();
Item it;
for (String slot : eq.contents.keySet())
{
it = eq.contents.get(slot).item;
if (it != null)
{
aer.amount = it.amount;
aer.attrs = it.attributes.values;
aer.captiion = it.caption;
aer.eid = this.id;
aer.id = it.id;
aer.slot = slot;
aer.type = it.type;
Server.SendTo(c.connection, aer);
}
}
}
}
@Override
public void RemoveTo(ConnectedClient c)
{
RemovePacket r = new RemovePacket();
r.id = this.id;
r.type = TypeId.getTypeId(Type.Entity);
if (c != null)
Server.SendTo(c.connection, r);
}
@Override
public void tryRemoveNear(IUpdate i)
{
if (allAround.contains(i))
{
allAround.remove(i);
i.RemoveTo(Server.getClient(this));
}
}
@Override
public int getType()
{
return TypeId.getTypeId(Type.Entity);
}
@Override
public void UpdateAround()
{
world.UpdateNear(this);
ConnectedClient c;
UpdatePlayerResponse r = new UpdatePlayerResponse();
r.id = id;
r.updType = UpdateType.Position;
r.x = body.getPosition().x;
r.y = body.getPosition().y;
r.z = z;
if (Server.getClient(this) != null)
Server.SendTo(Server.getClient(this).connection, r);
for (IUpdate ent : allAround)
{
if (ent.getType() == TypeId.getTypeId(Type.Entity))
{
c = Server.getClient((Entity) ent);
if (c != null)
Server.SendTo(c.connection, r);
}
}
}
@Override
public ServerWorld getWorld()
{
return world;
}
@Override
public Vector2 getPosition()
{
return this.body.getPosition();
}
@Override
public ArrayList<IUpdate> getAround()
{
return allAround;
}
@Override
public PhysicalData getData()
{
return pData;
}
public void act(float angle)
{
if(warMode)
{
TestProjectile t = new TestProjectile(Server.getProjFreeId(), new Vector3(this.getPosition().x, this.getPosition().y, this.z), this, angle);
t.Launch();
// Main.Log("[ACTION]"," War action with angle: " + angle);
}
else
{
// Main.Log("[ACTION]"," Action with angle: " + angle);
}
}
@Override
public int getId()
{
return id;
}
}