diff --git a/ngengine_public.jar b/ngengine_public.jar index 8c7994ba..5834adb3 100644 Binary files a/ngengine_public.jar and b/ngengine_public.jar differ diff --git a/src/resources/objects/creature/CreatureMessageBuilder.java b/src/resources/objects/creature/CreatureMessageBuilder.java index 86c38910..dd21c99d 100644 --- a/src/resources/objects/creature/CreatureMessageBuilder.java +++ b/src/resources/objects/creature/CreatureMessageBuilder.java @@ -94,7 +94,7 @@ public class CreatureMessageBuilder extends ObjectMessageBuilder { buffer.putInt(creature.getFactionStatus()); - byte[] customizationData = creature.getCustomizationData(); + byte[] customizationData = creature.getCustomization(); if(customizationData.length <= 0) buffer.putShort((short) 0); @@ -265,6 +265,7 @@ public class CreatureMessageBuilder extends ObjectMessageBuilder { buffer.putInt(0); buffer.putInt(0x2C01); buffer.putInt(0); + if(creature.getEquipmentList().isEmpty()) { buffer.putInt(0); @@ -594,6 +595,79 @@ public class CreatureMessageBuilder extends ObjectMessageBuilder { } + public IoBuffer buildHealthDelta(int health) { + + CreatureObject creature = (CreatureObject) object; + + IoBuffer buffer = bufferPool.allocate(15, false).order(ByteOrder.LITTLE_ENDIAN); + buffer.putInt(1); + buffer.putInt(creature.getHamListCounter()); + buffer.put((byte) 2); + buffer.putShort((short) 0); + buffer.putInt(health); + int size = buffer.position(); + buffer.flip(); + buffer = createDelta("CREO", (byte) 6, (short) 1, (short) 0x15, buffer, size + 4); + + return buffer; + + } + + public IoBuffer buildActionDelta(int action) { + + CreatureObject creature = (CreatureObject) object; + + IoBuffer buffer = bufferPool.allocate(15, false).order(ByteOrder.LITTLE_ENDIAN); + buffer.putInt(1); + buffer.putInt(creature.getHamListCounter()); + buffer.put((byte) 2); + buffer.putShort((short) 2); + buffer.putInt(action); + int size = buffer.position(); + buffer.flip(); + buffer = createDelta("CREO", (byte) 6, (short) 1, (short) 0x15, buffer, size + 4); + + return buffer; + + } + + public IoBuffer buildMaxHealthDelta(int health) { + + CreatureObject creature = (CreatureObject) object; + + IoBuffer buffer = bufferPool.allocate(15, false).order(ByteOrder.LITTLE_ENDIAN); + buffer.putInt(1); + buffer.putInt(creature.getHamListCounter()); + buffer.put((byte) 2); + buffer.putShort((short) 0); + buffer.putInt(health); + int size = buffer.position(); + buffer.flip(); + buffer = createDelta("CREO", (byte) 6, (short) 1, (short) 0x16, buffer, size + 4); + + return buffer; + + } + + public IoBuffer buildMaxActionDelta(int action) { + + CreatureObject creature = (CreatureObject) object; + + IoBuffer buffer = bufferPool.allocate(15, false).order(ByteOrder.LITTLE_ENDIAN); + buffer.putInt(1); + buffer.putInt(creature.getHamListCounter()); + buffer.put((byte) 2); + buffer.putShort((short) 2); + buffer.putInt(action); + int size = buffer.position(); + buffer.flip(); + buffer = createDelta("CREO", (byte) 6, (short) 1, (short) 0x16, buffer, size + 4); + + return buffer; + + } + + @Override public void sendListDelta(byte viewType, short updateType, IoBuffer buffer) { // TODO Auto-generated method stub diff --git a/src/resources/objects/creature/CreatureObject.java b/src/resources/objects/creature/CreatureObject.java index 479d2e76..79cbd6ee 100644 --- a/src/resources/objects/creature/CreatureObject.java +++ b/src/resources/objects/creature/CreatureObject.java @@ -54,7 +54,7 @@ import resources.objects.tangible.TangibleObject; import resources.objects.weapon.WeaponObject; @Entity -public class CreatureObject extends SWGObject implements IPersistent { +public class CreatureObject extends TangibleObject implements IPersistent { @NotPersistent private Transaction txn; @@ -67,11 +67,7 @@ public class CreatureObject extends SWGObject implements IPersistent { private int skillsUpdateCounter = 0; // CREO 3 - private byte[] customizationData; - private int optionBitmask = 0; - private int incapTimer = 10; private byte posture = 0; - private String faction; private int factionStatus = 0; private float height; private int battleFatigue = 0; @@ -102,8 +98,6 @@ public class CreatureObject extends SWGObject implements IPersistent { // CREO6 - @NotPersistent - private List defendersList = new ArrayList(); // unused in packets but useful for the server private byte combatFlag = 0; private short level = 0; private String currentAnimation; @@ -118,6 +112,15 @@ public class CreatureObject extends SWGObject implements IPersistent { private byte moodId = 0; private int performanceCounter = 0; private int performanceId = 0; + private int health; + private int action; + @NotPersistent + private int HAMListCounter = 0; + private int maxHealth; + private int maxAction; + @NotPersistent + private int maxHAMListCounter = 0; + private List equipmentList = new ArrayList(); @NotPersistent private int equipmentListUpdateCounter = 0; @@ -136,7 +139,7 @@ public class CreatureObject extends SWGObject implements IPersistent { public CreatureObject(long objectID, Planet planet, Point3D position, Quaternion orientation, String Template) { - super(objectID, planet, position, orientation, Template); + super(objectID, planet, Template, position, orientation); messageBuilder = new CreatureMessageBuilder(this); } @@ -195,27 +198,10 @@ public class CreatureObject extends SWGObject implements IPersistent { } } - public byte[] getCustomizationData() { + @Override + public void setOptionsBitmask(int optionBitmask) { synchronized(objectMutex) { - return customizationData; - } - } - - public void setCustomizationData(byte[] customizationData) { - synchronized(objectMutex) { - this.customizationData = customizationData; - } - } - - public int getOptionBitmask() { - synchronized(objectMutex) { - return optionBitmask; - } - } - - public void setOptionBitmask(int optionBitmask) { - synchronized(objectMutex) { - this.optionBitmask = optionBitmask; + this.optionsBitmask = optionBitmask; } IoBuffer optionDelta = messageBuilder.buildOptionMaskDelta(optionBitmask); @@ -224,18 +210,6 @@ public class CreatureObject extends SWGObject implements IPersistent { } - public int getIncapTimer() { - synchronized(objectMutex) { - return incapTimer; - } - } - - public void setIncapTimer(int incapTimer) { - synchronized(objectMutex) { - this.incapTimer = incapTimer; - } - } - public byte getPosture() { synchronized(objectMutex) { return posture; @@ -254,12 +228,7 @@ public class CreatureObject extends SWGObject implements IPersistent { notifyObservers(objController, true); } - public String getFaction() { - synchronized(objectMutex) { - return faction; - } - } - + @Override public void setFaction(String faction) { synchronized(objectMutex) { this.faction = faction; @@ -523,10 +492,6 @@ public class CreatureObject extends SWGObject implements IPersistent { return missionCriticalObjects; } - public List getDefendersList() { - return defendersList; - } - public byte getCombatFlag() { synchronized(objectMutex) { return combatFlag; @@ -789,4 +754,84 @@ public class CreatureObject extends SWGObject implements IPersistent { } + public int getHealth() { + synchronized(objectMutex) { + return health; + } + } + + public void setHealth(int health) { + synchronized(objectMutex) { + this.health = health; + setMaxHAMListCounter(getHamListCounter() + 1); + } + notifyObservers(messageBuilder.buildHealthDelta(health), true); + } + + public int getAction() { + synchronized(objectMutex) { + return action; + } + } + + public void setAction(int action) { + synchronized(objectMutex) { + this.action = action; + setMaxHAMListCounter(getHamListCounter() + 1); + } + notifyObservers(messageBuilder.buildActionDelta(action), true); + } + + public int getHamListCounter() { + synchronized(objectMutex) { + return HAMListCounter; + } + } + + public void setHamListCounter(int hamListCounter) { + synchronized(objectMutex) { + this.HAMListCounter = hamListCounter; + } + } + + public int getMaxHealth() { + synchronized(objectMutex) { + return maxHealth; + } + } + + public void setMaxHealth(int maxHealth) { + synchronized(objectMutex) { + this.maxHealth = maxHealth; + setMaxHAMListCounter(getMaxHAMListCounter() + 1); + } + notifyObservers(messageBuilder.buildMaxHealthDelta(maxHealth), true); + } + + public int getMaxAction() { + synchronized(objectMutex) { + return maxAction; + } + } + + public void setMaxAction(int maxAction) { + synchronized(objectMutex) { + this.maxAction = maxAction; + setMaxHAMListCounter(getMaxHAMListCounter() + 1); + } + notifyObservers(messageBuilder.buildMaxActionDelta(maxAction), true); + } + + public int getMaxHAMListCounter() { + synchronized(objectMutex) { + return maxHAMListCounter; + } + } + + public void setMaxHAMListCounter(int maxHAMListCounter) { + synchronized(objectMutex) { + this.maxHAMListCounter = maxHAMListCounter; + } + } + } diff --git a/src/resources/objects/tangible/TangibleObject.java b/src/resources/objects/tangible/TangibleObject.java index 7cce2933..d39a7dab 100644 --- a/src/resources/objects/tangible/TangibleObject.java +++ b/src/resources/objects/tangible/TangibleObject.java @@ -23,6 +23,11 @@ package resources.objects.tangible; import java.util.ArrayList; import java.util.List; +import java.util.Vector; + +import org.apache.mina.core.buffer.IoBuffer; + +import resources.objects.creature.CreatureObject; import com.sleepycat.persist.model.NotPersistent; @@ -41,14 +46,17 @@ public class TangibleObject extends SWGObject { // TODO: Thread safety - private int incapTimer = 10; + protected int incapTimer = 10; private int conditionDamage = 0; - - private byte[] customization; + protected int pvpBitmask = 0; + protected byte[] customization; private List componentCustomizations = new ArrayList(); - private int optionsBitmask = 0; + protected int optionsBitmask = 0; private int maxDamage = 0; private boolean staticObject = false; + protected String faction; + @NotPersistent + private Vector defendersList = new Vector(); // unused in packets but useful for the server @NotPersistent private TangibleMessageBuilder messageBuilder; @@ -122,6 +130,100 @@ public class TangibleObject extends SWGObject { public void setStaticObject(boolean staticObject) { this.staticObject = staticObject; } + + public int getPvPBitmask() { + synchronized(objectMutex) { + return optionsBitmask; + } + } + + public void setPvPBitmask(int pvpBitmask) { + synchronized(objectMutex) { + this.pvpBitmask = pvpBitmask; + } + } + + public String getFaction() { + synchronized(objectMutex) { + return faction; + } + } + + public void setFaction(String faction) { + synchronized(objectMutex) { + this.faction = faction; + } + } + + public Vector getDefendersList() { + return defendersList; + } + + public void addDefender(TangibleObject defender) { + + defendersList.add(defender); + + if(this instanceof CreatureObject) { + CreatureObject creature = (CreatureObject) this; + + if(creature.getCombatFlag() == 0) + creature.setCombatFlag((byte) 1); + } + + } + + public void removeDefender(TangibleObject defender) { + + defendersList.remove(defender); + + if(this instanceof CreatureObject) { + CreatureObject creature = (CreatureObject) this; + + if(creature.getCombatFlag() == 1 && defendersList.isEmpty()) + creature.setCombatFlag((byte) 0); + } + + } + + public boolean isAttackableBy(CreatureObject attacker) { + + CreatureObject creature; + + if(this instanceof CreatureObject) { + creature = (CreatureObject) this; + if(creature.getDuelList().contains(attacker) && attacker.getDuelList().contains(this)) + return true; + } + + if(faction.equals("rebel") && attacker.getFaction().equals("rebel")) + return false; + else if(faction.equals("imperial") && attacker.getFaction().equals("imperial")) + return false; + else if(attacker.getSlottedObject("ghost") != null) { + + if(this instanceof CreatureObject && getSlottedObject("ghost") != null) { + + creature = (CreatureObject) this; + + if(creature.getFactionStatus() == 2 && attacker.getFactionStatus() == 2) + return true; + else + return false; + + } + + if((faction.equals("rebel") || faction.equals("imperial")) && attacker.getFactionStatus() >= 1) + return true; + else if((faction.equals("rebel") || faction.equals("imperial")) && attacker.getFactionStatus() == 0) + return false; + + return getPvPBitmask() == 1 || getPvPBitmask() == 2; + + } + + return getPvPBitmask() == 1 || getPvPBitmask() == 2; + } + @Override public void sendBaselines(Client destination) { diff --git a/src/resources/objects/weapon/WeaponObject.java b/src/resources/objects/weapon/WeaponObject.java index ed3a3c48..3fa62289 100644 --- a/src/resources/objects/weapon/WeaponObject.java +++ b/src/resources/objects/weapon/WeaponObject.java @@ -50,23 +50,50 @@ public class WeaponObject extends SWGObject { private WeaponMessageBuilder messageBuilder; private float attackSpeed = 1; + private float maxRange; public WeaponObject(long objectID, Planet planet, String template) { super(objectID, planet, new Point3D(0, 0, 0), new Quaternion(1, 0, 1, 0), template); messageBuilder = new WeaponMessageBuilder(this); + calculateRange(); } + public WeaponObject(long objectID, Planet planet, String template, Point3D position, Quaternion orientation) { super(objectID, planet, position, orientation, template); messageBuilder = new WeaponMessageBuilder(this); + calculateRange(); } public WeaponObject() { super(); messageBuilder = new WeaponMessageBuilder(this); + //calculateRange(); } - + private void calculateRange() { + + int weaponType = getWeaponType(); + + switch(weaponType) { + + case 0: maxRange = 64; break; + case 1: maxRange = 50; break; + case 2: maxRange = 35; break; + case 3: maxRange = 64; break; + case 4: maxRange = 5; break; + case 5: maxRange = 5; break; + case 6: maxRange = 5; break; + case 7: maxRange = 5; break; + case 8: maxRange = 64; break; + case 9: maxRange = 5; break; + case 10: maxRange = 5; break; + case 11: maxRange = 5; break; + + } + + } + public int getIncapTimer() { return incapTimer; } @@ -129,6 +156,9 @@ public class WeaponObject extends SWGObject { String template = getTemplate(); + if(template == null) + return weaponType; + if(template.contains("rifle")) weaponType = 0; if(template.contains("carbine")) weaponType = 1; if(template.contains("pistol")) weaponType = 2; @@ -174,4 +204,12 @@ public class WeaponObject extends SWGObject { return messageBuilder; } + public float getMaxRange() { + return maxRange; + } + + public void setMaxRange(float maxRange) { + this.maxRange = maxRange; + } + } diff --git a/src/services/CharacterService.java b/src/services/CharacterService.java index ace0a2b7..727976f9 100644 --- a/src/services/CharacterService.java +++ b/src/services/CharacterService.java @@ -205,7 +205,7 @@ public class CharacterService implements INetworkDispatch { String sharedRaceTemplate = raceTemplate.replace("player/", "player/shared_"); CreatureObject object = (CreatureObject) core.objectService.createObject(sharedRaceTemplate, core.terrainService.getPlanetList().get(0)); - object.setCustomizationData(clientCreateCharacter.getCustomizationData()); + object.setCustomization(clientCreateCharacter.getCustomizationData()); object.setCustomName(clientCreateCharacter.getName()); object.setHeight(clientCreateCharacter.getScale()); object.setPersistent(true); diff --git a/src/services/SimulationService.java b/src/services/SimulationService.java index 6aa351d7..dd7a3adc 100644 --- a/src/services/SimulationService.java +++ b/src/services/SimulationService.java @@ -65,6 +65,7 @@ import protocol.swg.objectControllerObjects.TargetUpdate; import resources.objects.cell.CellObject; import resources.objects.creature.CreatureObject; import resources.common.*; +import toxi.geom.Line3D; import toxi.geom.Ray3D; import toxi.geom.Vec3D; import toxi.geom.mesh.TriangleMesh; @@ -593,7 +594,6 @@ public class SimulationService implements INetworkDispatch { List inRangeObjects = get(obj1.getPlanet(), position1.x, position1.z, 150); - for(SWGObject object : inRangeObjects) { if(object == obj1 || object == obj2) @@ -641,6 +641,20 @@ public class SimulationService implements INetworkDispatch { if(cell != null) return checkLineOfSightWorldToCell(obj1, obj2, cell); } + + List segments = new ArrayList(); + Line3D.splitIntoSegments(new Vec3D(position1.x, position1.y + 1, position1.z), new Vec3D(position2.x, position2.y + 1, position2.z), (float) 0.5, segments, true); + + for(Vec3D segment : segments) { + float y = segment.y; + + int height = (int) core.terrainService.getHeight(obj1.getPlanetId(), segment.x, segment.z); // round down to int + + if(height > y) { + System.out.println("Collision with terrain"); + return false; + } + } return true; diff --git a/src/services/TerrainService.java b/src/services/TerrainService.java index a7a28a48..492905fd 100644 --- a/src/services/TerrainService.java +++ b/src/services/TerrainService.java @@ -68,7 +68,6 @@ public class TerrainService { return Float.NaN; Planet planet = getPlanetByID(planetId); float height = planet.getTerrainVisitor().getHeight(x, z); - System.out.println("Height: " + height); return height; } diff --git a/src/services/combat/CombatService.java b/src/services/combat/CombatService.java index ba91f070..e8b4349d 100644 --- a/src/services/combat/CombatService.java +++ b/src/services/combat/CombatService.java @@ -21,6 +21,90 @@ ******************************************************************************/ package services.combat; -public class CombatService { +import java.util.Map; + +import resources.objects.creature.CreatureObject; +import resources.objects.tangible.TangibleObject; +import resources.objects.weapon.WeaponObject; +import services.command.CombatCommand; + +import main.NGECore; + +import engine.resources.objects.SWGObject; +import engine.resources.service.INetworkDispatch; +import engine.resources.service.INetworkRemoteEvent; + +public class CombatService implements INetworkDispatch { + + private NGECore core; + + public CombatService(NGECore core) { + this.core = core; + } + + @Override + public void insertOpcodes(Map arg0, Map arg1) { + + } + + @Override + public void shutdown() { + // TODO Auto-generated method stub + + } + + public void doCombat(CreatureObject attacker, TangibleObject target, WeaponObject weapon, CombatCommand command) { + + if(!attemptCombat(attacker, target)) + return; + + if(!applySpecialCost(attacker, weapon, command)) + return; + + } + + private boolean attemptCombat(CreatureObject attacker, TangibleObject target) { + + if(target.getDefendersList().contains(attacker) && attacker.getDefendersList().contains(target)) + return true; + + if(attacker.getStateBitmask() == 0x8000000) + return false; + + if(!target.isAttackableBy(attacker)) + return false; + + target.addDefender(attacker); + attacker.addDefender(target); + + return true; + + } + + private boolean applySpecialCost(CreatureObject attacker, WeaponObject weapon, CombatCommand command) { + + float actionCost = command.getActionCost(); + float healthCost = command.getHealthCost(); + + if(actionCost == 0 && healthCost == 0) + return true; + + float newAction = attacker.getAction() - actionCost; + if(newAction <= 0) + return false; + + float newHealth = attacker.getHealth() - healthCost; + if(newHealth <= 0) + return false; + + if(newAction != attacker.getAction()) + attacker.setAction((int) newAction); + + if(newHealth != attacker.getHealth()) + attacker.setHealth((int) newHealth); + + return true; + + } } diff --git a/src/services/command/CommandService.java b/src/services/command/CommandService.java index 872f7ff2..dcbee5b0 100644 --- a/src/services/command/CommandService.java +++ b/src/services/command/CommandService.java @@ -32,6 +32,7 @@ import org.apache.mina.core.session.IoSession; import engine.clients.Client; import engine.resources.objects.SWGObject; +import engine.resources.scene.Point3D; import engine.resources.service.INetworkDispatch; import engine.resources.service.INetworkRemoteEvent; import resources.common.*; @@ -39,6 +40,8 @@ import resources.common.*; import protocol.swg.objectControllerObjects.CommandEnqueue; import resources.objects.creature.CreatureObject; +import resources.objects.tangible.TangibleObject; +import resources.objects.weapon.WeaponObject; public class CommandService implements INetworkDispatch { @@ -69,17 +72,12 @@ public class CommandService implements INetworkDispatch { CommandEnqueue commandEnqueue = new CommandEnqueue(); commandEnqueue.deserialize(data); - //System.out.println(commandEnqueue.getCommandArguments()); - BaseSWGCommand command = getCommandByCRC(commandEnqueue.getCommandCRC()); if(command == null) return; - //if(command.getCommandCRC() == CRC.StringtoCRC("transferitemmisc")) - //System.out.println(commandEnqueue.getCommandArguments()); - // TODO: command filters for state, posture etc. if(client.getParent() == null) { @@ -91,23 +89,37 @@ public class CommandService implements INetworkDispatch { SWGObject target = core.objectService.getObject(commandEnqueue.getTargetID()); - //if(target == null) - //System.out.println("NULL Target"); - + if(command instanceof CombatCommand) { + processCombatCommand(actor, target, (CombatCommand) command); + return; + } + + core.scriptService.callScript("scripts/commands/", command.getCommandName(), "run", core, actor, target, commandEnqueue.getCommandArguments()); } - - + }); } - public void registerCommand(String name) { + public BaseSWGCommand registerCommand(String name) { BaseSWGCommand command = new BaseSWGCommand(name); commandLookup.add(command); + + return command; + + } + + public CombatCommand registerCombatCommand(String name) { + + CombatCommand command = new CombatCommand(name); + commandLookup.add(command); + + return command; + } public BaseSWGCommand getCommandByCRC(int CRC) { @@ -122,6 +134,51 @@ public class CommandService implements INetworkDispatch { } + private void processCombatCommand(CreatureObject attacker, SWGObject target, CombatCommand command) { + + if(target == null || !(target instanceof TangibleObject) || target == attacker) + return; + + if(attacker.getPosture() == 13 || attacker.getPosture() == 14) + return; + + if(target instanceof CreatureObject) { + if(((CreatureObject) target).getPosture() == 13 || ((CreatureObject) target).getPosture() == 14) + return; + } + + WeaponObject weapon; + + if(attacker.getWeaponId() == 0) + weapon = (WeaponObject) attacker.getSlottedObject("default_weapon"); // use unarmed/default weapon if no weapon is equipped + else + weapon = (WeaponObject) core.objectService.getObject(attacker.getWeaponId()); + + float maxRange = 0; + + if(command.getMaxRange() == 0) + maxRange = weapon.getMaxRange(); + else + maxRange = command.getMaxRange(); + + Point3D attackerPos = attacker.getWorldPosition(); + Point3D defenderPos = attacker.getWorldPosition(); + + if(attackerPos.getDistance(defenderPos) > maxRange && maxRange != 0) + return; + + if(command.getMinRange() > 0) { + if(attackerPos.getDistance(defenderPos) < command.getMinRange()) + return; + } + + if(!core.simulationService.checkLineOfSight(attacker, target)) + return; + + + } + + @Override public void shutdown() { // TODO Auto-generated method stub