diff --git a/src/resources/objects/creature/CreatureObject.java b/src/resources/objects/creature/CreatureObject.java index f7138711a..6b660bb3f 100644 --- a/src/resources/objects/creature/CreatureObject.java +++ b/src/resources/objects/creature/CreatureObject.java @@ -38,6 +38,7 @@ import network.packets.swg.zone.object_controller.PostureUpdate; import resources.HologramColour; import resources.Posture; import resources.PvpFlag; +import resources.PvpStatus; import resources.Race; import resources.collections.SWGList; import resources.collections.SWGSet; @@ -66,7 +67,6 @@ public class CreatureObject extends TangibleObject { private int cashBalance = 0; private int bankBalance = 0; private long reserveBalance = 0; // Galactic Reserve - capped at 3 billion - private WeaponObject defaultWeapon = null; private byte factionRank = 0; private long ownerId = 0; private int battleFatigue = 0; @@ -88,9 +88,6 @@ public class CreatureObject extends TangibleObject { super.addObject(obj); if (obj.getSlotArrangement() != -1 && !(obj instanceof PlayerObject)) { addEquipment(obj); - if (obj instanceof WeaponObject && defaultWeapon != null && !obj.equals(defaultWeapon)) { - removeObject(defaultWeapon); - } } } @@ -98,9 +95,6 @@ public class CreatureObject extends TangibleObject { public void removeObject(SWGObject obj) { super.removeObject(obj); removeEquipment(obj); - if (obj instanceof WeaponObject && defaultWeapon != null && !obj.equals(defaultWeapon)) { - addObject(defaultWeapon); - } } protected void handleSlotReplacement(SWGObject oldParent, SWGObject obj, int arrangement) { @@ -455,18 +449,17 @@ public class CreatureObject extends TangibleObject { } public void setEquippedWeapon(WeaponObject weapon) { - creo6.setEquippedWeapon(weapon); - sendDelta(6, 12, weapon.getObjectId()); + WeaponObject equippedWeapon; + + if(weapon == null) + equippedWeapon = (WeaponObject) getSlottedObject("default_weapon"); + else + equippedWeapon = weapon; + + creo6.setEquippedWeapon(equippedWeapon); + sendDelta(6, 12, equippedWeapon.getObjectId()); } - public WeaponObject getDefaultWeapon() { - return defaultWeapon; - } - - public void setDefaultWeapon(WeaponObject defaultWeapon) { - this.defaultWeapon = defaultWeapon; - } - public byte getMoodId() { return creo6.getMoodId(); } @@ -773,6 +766,31 @@ public class CreatureObject extends TangibleObject { } return items; } + + @Override + public boolean isEnemy(TangibleObject otherObject) { + boolean enemy = super.isEnemy(otherObject); + + if(enemy) { + // If these are both creatures, there's a chance both of them are players! + if (this instanceof CreatureObject && otherObject instanceof CreatureObject) { + CreatureObject thisCreature = (CreatureObject) this; + CreatureObject otherCreature = (CreatureObject) otherObject; + + // If they're both players, both of them might be special force + if (thisCreature.isPlayer() && otherCreature.isPlayer()) { + // They are enemies if they're both players and members of the special force! + if (getPvpStatus() == PvpStatus.SPECIALFORCES && otherObject.getPvpStatus() == PvpStatus.SPECIALFORCES) { + return true; + } else { // Two players where at least one isn't SF does not make them enemies + return false; + } + } + } + } + + return enemy; + } @Override public boolean equals(Object obj) { @@ -893,7 +911,7 @@ public class CreatureObject extends TangibleObject { @Override public void save(NetBufferStream stream) { super.save(stream); - stream.addByte(0); + stream.addByte(1); creo4.save(stream); creo6.save(stream); stream.addAscii(posture.name()); @@ -906,9 +924,6 @@ public class CreatureObject extends TangibleObject { stream.addLong(ownerId); stream.addLong(statesBitmask); stream.addByte(factionRank); - stream.addBoolean(defaultWeapon != null); - if (defaultWeapon != null) - SWGObjectFactory.save(defaultWeapon, stream); synchronized (skills) { stream.addList(skills, (s) -> stream.addAscii(s)); } @@ -920,7 +935,35 @@ public class CreatureObject extends TangibleObject { @Override public void read(NetBufferStream stream) { super.read(stream); - stream.getByte(); + switch(stream.getByte()) { + case 0: readVersion0(stream); break; + case 1: readVersion1(stream); break; + } + + } + + private void readVersion0(NetBufferStream stream) { + creo4.read(stream); + creo6.read(stream); + posture = Posture.valueOf(stream.getAscii()); + race = Race.valueOf(stream.getAscii()); + height = stream.getFloat(); + battleFatigue = stream.getInt(); + cashBalance = stream.getInt(); + bankBalance = stream.getInt(); + reserveBalance = stream.getLong(); + ownerId = stream.getLong(); + statesBitmask = stream.getLong(); + factionRank = stream.getByte(); + if (stream.getBoolean()) { + SWGObject defaultWeapon = (WeaponObject) SWGObjectFactory.create(stream); + defaultWeapon.moveToContainer(this); // The weapon will be moved into the default_weapon slot + } + stream.getList((i) -> skills.add(stream.getAscii())); + stream.getList((i) -> baseAttributes.set(i, stream.getInt())); + } + + private void readVersion1(NetBufferStream stream) { creo4.read(stream); creo6.read(stream); posture = Posture.valueOf(stream.getAscii()); @@ -933,8 +976,6 @@ public class CreatureObject extends TangibleObject { ownerId = stream.getLong(); statesBitmask = stream.getLong(); factionRank = stream.getByte(); - if (stream.getBoolean()) - defaultWeapon = (WeaponObject) SWGObjectFactory.create(stream); stream.getList((i) -> skills.add(stream.getAscii())); stream.getList((i) -> baseAttributes.set(i, stream.getInt())); } diff --git a/src/resources/objects/tangible/TangibleObject.java b/src/resources/objects/tangible/TangibleObject.java index 764e2cc2f..458b5f542 100644 --- a/src/resources/objects/tangible/TangibleObject.java +++ b/src/resources/objects/tangible/TangibleObject.java @@ -237,6 +237,20 @@ public class TangibleObject extends SWGObject { defenders.sendDeltaMessage(this); } + public boolean isEnemy(TangibleObject otherObject) { + // They CAN be enemies if they're not from the same faction and neither of them are neutral + PvpFaction otherFaction = otherObject.getPvpFaction(); + + if (otherFaction != PvpFaction.NEUTRAL && getPvpFaction() != otherFaction) { + if (getPvpStatus() != PvpStatus.ONLEAVE && otherObject.getPvpStatus() != PvpStatus.ONLEAVE) { + // Both objects are not players. In this case, both just need to be combatants. + return true; + } + } + + return false; + } + @Override public boolean equals(Object o) { return super.equals(o); diff --git a/src/services/combat/CombatService.java b/src/services/combat/CombatService.java index 18387290c..e7b9f658b 100644 --- a/src/services/combat/CombatService.java +++ b/src/services/combat/CombatService.java @@ -40,6 +40,7 @@ import network.packets.swg.zone.object_controller.ShowFlyText; import network.packets.swg.zone.object_controller.ShowFlyText.Scale; import network.packets.swg.zone.object_controller.combat.CombatAction; import intents.chat.ChatCommandIntent; +import resources.PvpFaction; import resources.PvpFlag; import resources.combat.AttackInfoLight; import resources.combat.AttackType; @@ -53,6 +54,7 @@ import resources.control.Intent; import resources.control.Service; import resources.objects.SWGObject; import resources.objects.creature.CreatureObject; +import resources.objects.creature.CreatureState; import resources.objects.tangible.TangibleObject; import resources.objects.weapon.WeaponObject; import resources.server_info.Log; @@ -221,8 +223,14 @@ public class CombatService extends Service { return CombatStatus.NO_WEAPON; if (!(target instanceof TangibleObject)) return CombatStatus.INVALID_TARGET; - if ((((TangibleObject) target).getPvpFlags() & PvpFlag.ATTACKABLE.getBitmask()) == 0) + TangibleObject tangibleTarget = (TangibleObject) target; + if(tangibleTarget.getPvpFaction() != PvpFaction.NEUTRAL) { + if(!tangibleTarget.isEnemy(source)) { + return CombatStatus.INVALID_TARGET; + } + } else if ((tangibleTarget.getPvpFlags() & PvpFlag.ATTACKABLE.getBitmask()) == 0) return CombatStatus.INVALID_TARGET; + CombatStatus status; switch (c.getAttackType()) { case AREA: diff --git a/src/services/faction/FactionService.java b/src/services/faction/FactionService.java index f0a558e60..49addcaff 100644 --- a/src/services/faction/FactionService.java +++ b/src/services/faction/FactionService.java @@ -36,6 +36,7 @@ import network.packets.swg.zone.UpdatePvpStatusMessage; import network.packets.swg.zone.chat.ChatSystemMessage; import network.packets.swg.zone.chat.ChatSystemMessage.SystemChatType; import intents.FactionIntent; +import intents.PlayerEventIntent; import resources.PvpFaction; import resources.PvpFlag; import resources.PvpStatus; @@ -62,20 +63,8 @@ public final class FactionService extends Service { @Override public void onIntentReceived(Intent i) { - if(i instanceof FactionIntent) { - FactionIntent fi = (FactionIntent) i; - - switch(fi.getUpdateType()) { - case FACTIONUPDATE: - handleTypeChange(fi); - break; - case STATUSUPDATE: - handleStatusChange(fi); - break; - case FLAGUPDATE: - handleFlagChange(fi.getTarget()); - break; - } + switch(i.getType()) { + case FactionIntent.TYPE: handleFactionIntent((FactionIntent) i); break; } } @@ -94,6 +83,20 @@ public final class FactionService extends Service { return super.terminate() && success; } + private void handleFactionIntent(FactionIntent i) { + switch (i.getUpdateType()) { + case FACTIONUPDATE: + handleTypeChange(i); + break; + case STATUSUPDATE: + handleStatusChange(i); + break; + case FLAGUPDATE: + handleFlagChange(i.getTarget()); + break; + } + } + private void sendSystemMessage(TangibleObject target, String message) { target.getOwner().sendPacket(new ChatSystemMessage(SystemChatType.SCREEN_AND_CHAT, message)); } @@ -218,11 +221,8 @@ public final class FactionService extends Service { private int getPvpBitmask(TangibleObject object1, TangibleObject object2) { int pvpBitmask = 0; - // They CAN be enemies if they're not from the same faction and neither of them are neutral - if (object1.getPvpFaction() != object2.getPvpFaction() && object2.getPvpFaction() != PvpFaction.NEUTRAL) { - if (object1.getPvpStatus() == PvpStatus.SPECIALFORCES && object2.getPvpStatus() == PvpStatus.SPECIALFORCES) { - pvpBitmask |= PvpFlag.AGGRESSIVE.getBitmask() | PvpFlag.ATTACKABLE.getBitmask(); - } + if(object1.isEnemy(object2)) { + pvpBitmask |= PvpFlag.AGGRESSIVE.getBitmask() | PvpFlag.ATTACKABLE.getBitmask(); } return pvpBitmask;