From 654fa6b49fad7614c9110dc9f93c830ef1dcc9e0 Mon Sep 17 00:00:00 2001 From: Light2 Date: Sun, 15 Sep 2013 18:48:13 +0200 Subject: [PATCH] Added delay attacks and effects --- .../swg/PlayClientEffectLocMessage.java | 70 ++++++++++ src/resources/objects/Buff.java | 15 +- .../creature/CreatureMessageBuilder.java | 20 +++ src/services/combat/CombatService.java | 131 +++++++++++++++++- src/services/command/CombatCommand.java | 61 ++++++++ 5 files changed, 288 insertions(+), 9 deletions(-) create mode 100644 src/protocol/swg/PlayClientEffectLocMessage.java diff --git a/src/protocol/swg/PlayClientEffectLocMessage.java b/src/protocol/swg/PlayClientEffectLocMessage.java new file mode 100644 index 00000000..fd71b8a7 --- /dev/null +++ b/src/protocol/swg/PlayClientEffectLocMessage.java @@ -0,0 +1,70 @@ +/******************************************************************************* + * Copyright (c) 2013 + * + * This File is part of NGECore2. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + * + * Using NGEngine to work with NGECore2 is making a combined work based on NGEngine. + * Therefore all terms and conditions of the GNU Lesser General Public License cover the combination. + ******************************************************************************/ +package protocol.swg; + +import java.nio.ByteOrder; + +import org.apache.mina.core.buffer.IoBuffer; + +import engine.resources.scene.Point3D; + +public class PlayClientEffectLocMessage extends SWGMessage { + + private String effectFile; + private String planet; + private Point3D position; + + public PlayClientEffectLocMessage(String effectFile, String planet, Point3D position) { + + this.effectFile = effectFile; + this.planet = planet; + this.position = position; + + } + + @Override + public IoBuffer serialize() { + + IoBuffer result = IoBuffer.allocate(36 + effectFile.length() + planet.length()).order(ByteOrder.LITTLE_ENDIAN); + + result.putShort((short) 9); + result.putInt(0x02949E74); + result.put(getAsciiString(effectFile)); + result.put(getAsciiString(planet)); + result.putFloat(position.x); + result.putFloat(position.y); + result.putFloat(position.z); + result.putLong(0); + result.putInt(0); // unks seem to be always 0 + result.putShort((short) 0); + + return result.flip(); + + } + + @Override + public void deserialize(IoBuffer data) { + // TODO Auto-generated method stub + + } + +} diff --git a/src/resources/objects/Buff.java b/src/resources/objects/Buff.java index 178a49a6..20a2dc73 100644 --- a/src/resources/objects/Buff.java +++ b/src/resources/objects/Buff.java @@ -33,7 +33,7 @@ import engine.clientdata.ClientFileManager; import engine.clientdata.visitors.DatatableVisitor; import engine.resources.common.CRC; -@Persistent(version=4) +@Persistent(version=5) public class Buff implements IListObject { @NotPersistent @@ -56,6 +56,7 @@ public class Buff implements IListObject { private boolean decayOnPvPDeath; private long startTime; private int totalPlayTime; + private byte decayCounter; public Buff(String buffName, long ownerId) { @@ -335,7 +336,9 @@ public class Buff implements IListObject { long currentTime = System.currentTimeMillis(); long timeDiff = (currentTime - startTime) / 1000; int remaining = (int) (duration - timeDiff); - System.out.println("Buff remaining: " + remaining); + for(int i = 0; i < decayCounter; i++) { + remaining /= 2; + } return remaining; } @@ -348,4 +351,12 @@ public class Buff implements IListObject { this.totalPlayTime = totalPlayTime; } + public byte getDecayCounter() { + return decayCounter; + } + + public void incDecayCounter(byte decayCounter) { + this.decayCounter++; + } + } diff --git a/src/resources/objects/creature/CreatureMessageBuilder.java b/src/resources/objects/creature/CreatureMessageBuilder.java index 9826ac71..379882b0 100644 --- a/src/resources/objects/creature/CreatureMessageBuilder.java +++ b/src/resources/objects/creature/CreatureMessageBuilder.java @@ -742,6 +742,26 @@ public class CreatureMessageBuilder extends ObjectMessageBuilder { } + public IoBuffer buildUpdateBuffDelta(Buff buff) { + + CreatureObject creature = (CreatureObject) object; + PlayerObject player = (PlayerObject) creature.getSlottedObject("ghost"); + + IoBuffer buffer = bufferPool.allocate(37, false).order(ByteOrder.LITTLE_ENDIAN); + buffer.putInt(1); + buffer.putInt(creature.getBuffListCounter()); + buff.setTotalPlayTime((int) (player.getTotalPlayTime() + (System.currentTimeMillis() - player.getLastPlayTimeUpdate()) / 1000)); + buffer.put((byte) 2); + buffer.put(buff.getBytes()); + int size = buffer.position(); + buffer.flip(); + buffer = createDelta("CREO", (byte) 6, (short) 1, (short) 0x1A, buffer, size + 4); + + return buffer; + + } + + public IoBuffer buildGroupInviteDelta(long inviteSenderId, long inviteCounter, String leaderName) { IoBuffer buffer = bufferPool.allocate(18 + leaderName.length(), false).order(ByteOrder.LITTLE_ENDIAN); diff --git a/src/services/combat/CombatService.java b/src/services/combat/CombatService.java index d02ce610..34264342 100644 --- a/src/services/combat/CombatService.java +++ b/src/services/combat/CombatService.java @@ -26,24 +26,30 @@ import java.util.Map; import java.util.Random; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ScheduledFuture; import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; import org.apache.mina.core.buffer.IoBuffer; import protocol.swg.ObjControllerMessage; +import protocol.swg.PlayClientEffectLocMessage; import protocol.swg.UpdatePVPStatusMessage; import protocol.swg.objectControllerObjects.CombatAction; import protocol.swg.objectControllerObjects.CombatSpam; import protocol.swg.objectControllerObjects.CommandEnqueueRemove; import protocol.swg.objectControllerObjects.StartTask; import resources.common.FileUtilities; +import resources.objects.cell.CellObject; import resources.objects.creature.CreatureObject; import resources.objects.tangible.TangibleObject; +import resources.objects.waypoint.WaypointObject; import resources.objects.weapon.WeaponObject; import services.command.CombatCommand; import main.NGECore; import engine.resources.common.CRC; import engine.resources.objects.SWGObject; +import engine.resources.scene.Point3D; import engine.resources.service.INetworkDispatch; import engine.resources.service.INetworkRemoteEvent; @@ -68,7 +74,7 @@ public class CombatService implements INetworkDispatch { } - public void doCombat(CreatureObject attacker, TangibleObject target, WeaponObject weapon, CombatCommand command, int actionCounter) { + public void doCombat(final CreatureObject attacker, final TangibleObject target, final WeaponObject weapon, final CombatCommand command, final int actionCounter) { if(!applySpecialCost(attacker, weapon, command)) @@ -77,14 +83,82 @@ public class CombatService implements INetworkDispatch { if((command.getAttackType() == 0 || command.getAttackType() == 1 || command.getAttackType() == 3) && !attemptCombat(attacker, target)) return; - // use preRun for delayed effects like officer orbital strike, grenades etc. + /* // use preRun for delayed effects like officer orbital strike, grenades etc. if(FileUtilities.doesFileExist("scripts/commands/combat" + command.getCommandName() + ".py")) - core.scriptService.callScript("scripts/commands/combat", command.getCommandName(), "preRun", core, attacker, target, command); + core.scriptService.callScript("scripts/commands/combat", command.getCommandName(), "preRun", core, attacker, target, command);*/ + final Point3D targetPos = target.getPosition(); + final SWGObject targetParent = target.getContainer(); - if(command.getAttackType() == 1) - doSingleTargetCombat(attacker, target, weapon, command, actionCounter); - else if(command.getAttackType() == 0 || command.getAttackType() == 2 || command.getAttackType() == 3) - doAreaCombat(attacker, target, weapon, command, actionCounter); + if(command.getDelayAttackParticle().length() > 0 || command.getInitialAttackDelay() > -1) { + + if(command.getInitialAttackDelay() > 0) { + + if(command.getDelayAttackParticle().length() > 0) + target.notifyObservers(new PlayClientEffectLocMessage(command.getDelayAttackParticle(), target.getPlanet().getName(), target.getWorldPosition()), true); + + try { + Thread.sleep((long) command.getInitialAttackDelay()); + } catch (InterruptedException e) { + e.printStackTrace(); + } + + } else if(command.getInitialAttackDelay() <= 0 && command.getDelayAttackInterval() > 0 && command.getDelayAttackLoops() <= 1) { + + try { + Thread.sleep((long) command.getDelayAttackInterval()); + } catch (InterruptedException e) { + e.printStackTrace(); + } + + if(command.getDelayAttackParticle().length() > 0) + target.notifyObservers(new PlayClientEffectLocMessage(command.getDelayAttackParticle(), target.getPlanet().getName(), target.getWorldPosition()), true); + + } + + if(command.getDelayAttackLoops() > 1) { + final ScheduledFuture task = scheduler.scheduleAtFixedRate(new Runnable() { + + @Override + public void run() { + + if(command.getDelayAttackParticle().length() > 0) + target.notifyObservers(new PlayClientEffectLocMessage(command.getDelayAttackParticle(), target.getPlanet().getName(), target.getWorldPosition()), true); + + if(command.getAttackType() == 1) + doSingleTargetCombat(attacker, target, weapon, command, actionCounter); + else if(command.getAttackType() == 0 || command.getAttackType() == 2 || command.getAttackType() == 3) + doAreaCombat(attacker, targetPos, weapon, command, actionCounter, targetParent); + + } + + }, 0, (long) (command.getDelayAttackInterval() * 1000), TimeUnit.MILLISECONDS); + + scheduler.schedule(new Runnable() { + + @Override + public void run() { + task.cancel(true); + } + + }, (long) ((command.getDelayAttackInterval() * 1000) * command.getDelayAttackLoops()), TimeUnit.MILLISECONDS); + + return; + + } else { + if(command.getAttackType() == 1) + doSingleTargetCombat(attacker, target, weapon, command, actionCounter); + else if(command.getAttackType() == 0 || command.getAttackType() == 2 || command.getAttackType() == 3) + doAreaCombat(attacker, targetPos, weapon, command, actionCounter, targetParent); + } + + } else { + + if(command.getAttackType() == 1) + doSingleTargetCombat(attacker, target, weapon, command, actionCounter); + else if(command.getAttackType() == 0 || command.getAttackType() == 2 || command.getAttackType() == 3) + doAreaCombat(attacker, target, weapon, command, actionCounter); + + } } @@ -94,6 +168,49 @@ public class CombatService implements INetworkDispatch { return; } } + + private void doAreaCombat(CreatureObject attacker, Point3D targetPos, WeaponObject weapon, CombatCommand command, int actionCounter, SWGObject targetCell) { + + float x = attacker.getWorldPosition().x; + float z = attacker.getWorldPosition().z; + + SWGObject fakeTargetObject = new WaypointObject(0, attacker.getPlanet(), targetPos); + + if(targetCell != null) + targetCell._add(fakeTargetObject); + + float dirX = fakeTargetObject.getWorldPosition().x - x; + float dirZ = fakeTargetObject.getWorldPosition().z - z; + + float range = command.getConeLength(); + + List inRangeObjects = core.simulationService.get(attacker.getPlanet(), fakeTargetObject.getWorldPosition().x, fakeTargetObject.getWorldPosition().z, (int) range); + + + for(SWGObject obj : inRangeObjects) { + + if(!(obj instanceof TangibleObject) || obj == attacker) + continue; + + if(obj instanceof CreatureObject && (((CreatureObject) obj).getPosture() == 13 || ((CreatureObject) obj).getPosture() == 14)) + continue; + + if(command.getAttackType() == 0 && !isInConeAngle(attacker, obj, (int) command.getConeLength(), (int) command.getConeWidth(), dirX, dirZ)) + continue; + + if(!core.simulationService.checkLineOfSight(fakeTargetObject, obj)) + continue; + + if(!attemptCombat(attacker, (TangibleObject) obj)) + continue; + + doSingleTargetCombat(attacker, (TangibleObject) obj, weapon, command, actionCounter); + + } + + + } + private void doSingleTargetCombat(CreatureObject attacker, TangibleObject target, WeaponObject weapon, CombatCommand command, int actionCounter) { if(target instanceof CreatureObject) { diff --git a/src/services/command/CombatCommand.java b/src/services/command/CombatCommand.java index cd77a79d..dd838491 100644 --- a/src/services/command/CombatCommand.java +++ b/src/services/command/CombatCommand.java @@ -68,6 +68,13 @@ public class CombatCommand extends BaseSWGCommand { private String performanceSpam; private byte hitSpam; private float cooldown; + private String delayAttackEggTemplate; + private String delayAttackParticle; + private float initialAttackDelay; + private float delayAttackInterval; + private int delayAttackLoops; + private int delayAttackEggPosition; + public CombatCommand(String commandName) { super(commandName); @@ -81,6 +88,12 @@ public class CombatCommand extends BaseSWGCommand { validTargetType = ((Integer) visitor.getObject(i, 5)).byteValue(); hitType = ((Integer) visitor.getObject(i, 6)).byteValue(); healType = ((Integer) visitor.getObject(i, 7)).byteValue(); + delayAttackEggTemplate = (String) visitor.getObject(i, 12); + delayAttackParticle = (String) visitor.getObject(i, 13); + initialAttackDelay = (Float) visitor.getObject(i, 14); + delayAttackInterval = (Float) visitor.getObject(i, 15); + delayAttackLoops = (Integer) visitor.getObject(i, 16); + delayAttackEggPosition = (Integer) visitor.getObject(i, 17); String defaultAnims = (String) visitor.getObject(i, 21); setDefaultAnimations(defaultAnims.split(",")); String unarmedAnims = (String) visitor.getObject(i, 22); @@ -593,6 +606,54 @@ public class CombatCommand extends BaseSWGCommand { public void setCooldown(float cooldown) { this.cooldown = cooldown; } + + public String getDelayAttackEggTemplate() { + return delayAttackEggTemplate; + } + + public void setDelayAttackEggTemplate(String delayAttackEggTemplate) { + this.delayAttackEggTemplate = delayAttackEggTemplate; + } + + public String getDelayAttackParticle() { + return delayAttackParticle; + } + + public void setDelayAttackParticle(String delayAttackParticle) { + this.delayAttackParticle = delayAttackParticle; + } + + public float getInitialAttackDelay() { + return initialAttackDelay; + } + + public void setInitialAttackDelay(float initialAttackDelay) { + this.initialAttackDelay = initialAttackDelay; + } + + public float getDelayAttackInterval() { + return delayAttackInterval; + } + + public void setDelayAttackInterval(float delayAttackInterval) { + this.delayAttackInterval = delayAttackInterval; + } + + public int getDelayAttackEggPosition() { + return delayAttackEggPosition; + } + + public void setDelayAttackEggPosition(int delayAttackEggPosition) { + this.delayAttackEggPosition = delayAttackEggPosition; + } + + public int getDelayAttackLoops() { + return delayAttackLoops; + } + + public void setDelayAttackLoops(int delayAttackLoops) { + this.delayAttackLoops = delayAttackLoops; + }