diff --git a/scripts/commands/bandflourish.py b/scripts/commands/bandflourish.py index e30daa8f..446ceb72 100644 --- a/scripts/commands/bandflourish.py +++ b/scripts/commands/bandflourish.py @@ -31,15 +31,10 @@ def run(core, actor, target, commandString): if actor.getPerformanceId() <= 0: actor.sendSystemMessage('@performance:flourish_not_performing', 0) return - - animation = 'skill_action_' + str(flourish) - if flourish == 9: - animation = 'mistake' if actor.getAcceptBandflourishes(): actor.sendSystemMessage('@performance:flourish_perform_band_self', 0) - actor.sendSystemMessage('@performance:flourish_perform', 0) - actor.doSkillAnimation(animation) + core.entertainmentService.performFlourish(actor, flourish) group = core.objectService.getObject(actor.getGroupId()) if not group: @@ -50,8 +45,7 @@ def run(core, actor, target, commandString): continue if creature.getAcceptBandflourishes(): creature.sendSystemMessage('@performance:flourish_perform_band_member', 0) - creature.sendSystemMessage('@performance:flourish_perform', 0) - creature.doSkillAnimation(animation) + core.entertainmentService.performFlourish(creature, flourish) return diff --git a/scripts/commands/centerstage.py b/scripts/commands/centerstage.py new file mode 100644 index 00000000..ab85409c --- /dev/null +++ b/scripts/commands/centerstage.py @@ -0,0 +1,14 @@ +import sys + +def setup(): + return + +def run(core, actor, target, commandString): + + if actor.getLevel() < 66: + actor.sendSystemMessage('@performance:effect_lack_skill_self') + return + + if core.entertainmentService.performEffect(actor, 'CenterStage', 'clienteffect/entertainer_center_stage.cef', target) is True: + actor.sendSystemMessage('@performance:effect_perform_center_stage', 0) + return \ No newline at end of file diff --git a/scripts/commands/colorSwirl.py b/scripts/commands/colorSwirl.py new file mode 100644 index 00000000..d437a17c --- /dev/null +++ b/scripts/commands/colorSwirl.py @@ -0,0 +1,14 @@ +import sys + +def setup(): + return + +def run(core, actor, target, commandString): + + if actor.getLevel() < 34: + actor.sendSystemMessage('@performance:effect_lack_skill_self') + return + + if core.entertainmentService.performEffect(actor, 'ColorSwirl', 'clienteffect/entertainer_color_swirl.cef', target) is True: + actor.sendSystemMessage('@performance:effect_perform_color_swirl', 0) + return \ No newline at end of file diff --git a/scripts/commands/colorlights.py b/scripts/commands/colorlights.py new file mode 100644 index 00000000..abaa8dd2 --- /dev/null +++ b/scripts/commands/colorlights.py @@ -0,0 +1,19 @@ +import sys + +def setup(): + return + +def run(core, actor, target, commandString): + + command = 'ColorLights1' + effect = 'entertainer_color_lights_level_1.cef' + + if actor.getLevel() < 4: + actor.sendSystemMessage('@performance:effect_lack_skill_self') + return + + # TODO: Find out levels for other colored light 2 and 3 + + if core.entertainmentService.performEffect(actor, command, effect, target) is True: + actor.sendSystemMessage('@performance:effect_perform_color_lights', 0) + return \ No newline at end of file diff --git a/scripts/commands/dazzle.py b/scripts/commands/dazzle.py new file mode 100644 index 00000000..718c6c5d --- /dev/null +++ b/scripts/commands/dazzle.py @@ -0,0 +1,19 @@ +import sys + +def setup(): + return + +def run(core, actor, target, commandString): + + command = 'Dazzle1' + effect = 'entertainer_dazzle_level_1.cef' + + if actor.getLevel() < 10: + actor.sendSystemMessage('@performance:effect_lack_skill_self') + return + + # TODO: Find out levels for other dazzle 2 and 3 + + if core.entertainmentService.performEffect(actor, command, effect, target) is True: + actor.sendSystemMessage('@performance:effect_perform_dazzle', 0) + return \ No newline at end of file diff --git a/scripts/commands/distract.py b/scripts/commands/distract.py new file mode 100644 index 00000000..6c1eb887 --- /dev/null +++ b/scripts/commands/distract.py @@ -0,0 +1,19 @@ +import sys + +def setup(): + return + +def run(core, actor, target, commandString): + + command = 'Distract1' + effect = 'entertainer_distract_level_1.cef' + + if actor.getLevel() < 18: + actor.sendSystemMessage('@performance:effect_lack_skill_self') + return + + # TODO: Find out levels for other distract 2 and 3 + + if core.entertainmentService.performEffect(actor, command, effect, target) is True: + actor.sendSystemMessage('@performance:effect_perform_distract', 0) + return \ No newline at end of file diff --git a/scripts/commands/featuredSolo.py b/scripts/commands/featuredSolo.py new file mode 100644 index 00000000..7b7f98cf --- /dev/null +++ b/scripts/commands/featuredSolo.py @@ -0,0 +1,14 @@ +import sys + +def setup(): + return + +def run(core, actor, target, commandString): + + if actor.getLevel() < 90: + actor.sendSystemMessage('@performance:effect_lack_skill_self') + return + + if core.entertainmentService.performEffect(actor, 'FeaturedSolo', 'clienteffect/entertainer_featured_solo.cef', target) is True: + actor.sendSystemMessage('@performance:effect_perform_featured_solo', 0) + return \ No newline at end of file diff --git a/scripts/commands/firejet.py b/scripts/commands/firejet.py new file mode 100644 index 00000000..42179337 --- /dev/null +++ b/scripts/commands/firejet.py @@ -0,0 +1,19 @@ +import sys + +def setup(): + return + +def run(core, actor, target, commandString): + + command = 'FireJets1' + effect = 'entertainer_fire_jets_level_1.cef' + + if actor.getLevel() < 26: + actor.sendSystemMessage('@performance:effect_lack_skill_self') + return + + # TODO: Find out levels for other firejets 2 and 3 + + if core.entertainmentService.performEffect(actor, command, effect, target) is True: + actor.sendSystemMessage('@performance:effect_perform_fire_jets', 0) + return \ No newline at end of file diff --git a/scripts/commands/firejet2.py b/scripts/commands/firejet2.py new file mode 100644 index 00000000..820d1db7 --- /dev/null +++ b/scripts/commands/firejet2.py @@ -0,0 +1,14 @@ +import sys + +def setup(): + return + +def run(core, actor, target, commandString): + + if actor.getLevel() < 76: + actor.sendSystemMessage('@performance:effect_lack_skill_self') + return + + if core.entertainmentService.performEffect(actor, 'FireJetsB', 'clienteffect/entertainer_fire_jets2.cef', target) is True: + actor.sendSystemMessage('@performance:effect_perform_fire_jets_2', 0) + return \ No newline at end of file diff --git a/scripts/commands/floorLights.py b/scripts/commands/floorLights.py new file mode 100644 index 00000000..945d273e --- /dev/null +++ b/scripts/commands/floorLights.py @@ -0,0 +1,14 @@ +import sys + +def setup(): + return + +def run(core, actor, target, commandString): + + if actor.getLevel() < 82: + actor.sendSystemMessage('@performance:effect_lack_skill_self') + return + + if core.entertainmentService.performEffect(actor, 'DanceFloor', 'clienteffect/entertainer_dance_floor.cef', target) is True: + actor.sendSystemMessage('@performance:effect_perform_dance_floor', 0) + return \ No newline at end of file diff --git a/scripts/commands/laserShow.py b/scripts/commands/laserShow.py new file mode 100644 index 00000000..8ed7d21d --- /dev/null +++ b/scripts/commands/laserShow.py @@ -0,0 +1,14 @@ +import sys + +def setup(): + return + +def run(core, actor, target, commandString): + + if actor.getLevel() < 42: + actor.sendSystemMessage('@performance:effect_lack_skill_self') + return + + if core.entertainmentService.performEffect(actor, 'LaserShow', 'clienteffect/entertainer_laser_show.cef', target) is True: + actor.sendSystemMessage('@performance:effect_perform_lase_show', 0) + return \ No newline at end of file diff --git a/scripts/commands/smokebomb.py b/scripts/commands/smokebomb.py new file mode 100644 index 00000000..01b2bf52 --- /dev/null +++ b/scripts/commands/smokebomb.py @@ -0,0 +1,19 @@ +import sys + +def setup(): + return + +def run(core, actor, target, commandString): + + command = 'SmokeBomb1' + effect = 'entertainer_smoke_bomb_level_1.cef' + + if actor.getLevel() < 50: + actor.sendSystemMessage('@performance:effect_lack_skill_self') + return + + # TODO: Find out levels for other smoke bomb 2 and 3 + + if core.entertainmentService.performEffect(actor, command, effect, target) is True: + actor.sendSystemMessage('@performance:effect_perform_smoke_bomb', 0) + return \ No newline at end of file diff --git a/scripts/commands/spotlight.py b/scripts/commands/spotlight.py new file mode 100644 index 00000000..25341536 --- /dev/null +++ b/scripts/commands/spotlight.py @@ -0,0 +1,24 @@ +from protocol.swg import PlayClientEffectObjectMessage +import sys + +def setup(): + return + +def run(core, actor, target, commandString): + + command = 'SpotLight1' + effect = 'clienteffect/entertainer_spot_light_level_1.cef' + + # TODO: Figure out what levels the spotlight effects upgraded at. + + if actor.getLevel() >= 80: + command == 'SpotLight3' + effect = 'clienteffect/entertainer_spot_light_level_3.cef' + + elif actor.getLevel() >= 40: + command == 'SpotLight2' + effect = 'clienteffect/entertainer_spot_light_level_2.cef' + + if core.entertainmentService.performEffect(actor, command, effect, None) is True: + actor.sendSystemMessage('@performance:effect_perform_spot_light', 0) + return diff --git a/scripts/commands/ventriloquism.py b/scripts/commands/ventriloquism.py new file mode 100644 index 00000000..198516f4 --- /dev/null +++ b/scripts/commands/ventriloquism.py @@ -0,0 +1,19 @@ +import sys + +def setup(): + return + +def run(core, actor, target, commandString): + + command = 'Ventriloquism1' + effect = 'entertainer_ventriloquism_level_1.cef' + + if actor.getLevel() < 58: + actor.sendSystemMessage('@performance:effect_lack_skill_self') + return + + # TODO: Find out levels for other ventriloquism 2 and 3 + + if core.entertainmentService.performEffect(actor, command, effect, target) is True: + actor.sendSystemMessage('@performance:effect_perform_ventriloquism', 0) + return \ No newline at end of file diff --git a/src/resources/common/Performance.java b/src/resources/common/Performance.java index 9100e2f2..4179f4be 100644 --- a/src/resources/common/Performance.java +++ b/src/resources/common/Performance.java @@ -1,3 +1,24 @@ +/******************************************************************************* + * 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 resources.common; public class Performance { diff --git a/src/resources/common/PerformanceEffect.java b/src/resources/common/PerformanceEffect.java new file mode 100644 index 00000000..09afddd0 --- /dev/null +++ b/src/resources/common/PerformanceEffect.java @@ -0,0 +1,108 @@ +/******************************************************************************* + * 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 resources.common; + +public class PerformanceEffect { + + private int effectActionCost; + private float effectDuration; + private String name; + private String performanceType; + private boolean requiredPerforming; + private int requiredSkillModValue; + private int targetType; + private boolean music; + private boolean dance; + + public PerformanceEffect() { } + + public int getEffectActionCost() { + return effectActionCost; + } + public float getEffectDuration() { + return effectDuration; + } + public String getName() { + return name; + } + public int getRequiredSkillModValue() { + return requiredSkillModValue; + } + public int getTargetType() { + return targetType; + } + public String getPerformanceType() { + return performanceType; + } + public boolean isRequiredPerforming() { + return requiredPerforming; + } + public void setEffectActionCost(int effectActionCost) { + this.effectActionCost = effectActionCost; + } + public void setEffectDuration(float effectDuration) { + this.effectDuration = effectDuration; + } + public void setName(String name) { + this.name = name; + } + public void setPerformanceType(String performanceType) { + this.performanceType = performanceType; + + if (performanceType.contains(",")) { + String[] array = performanceType.split(","); + if(array.length < 2) + return; + + this.dance = true; + this.music = true; + } + else if (performanceType.equals("music")) { this.music = true; } + else if (performanceType.equals("dance")) { this.dance = true; } + } + public void setRequiredPerforming(boolean requiredPerforming) { + this.requiredPerforming = requiredPerforming; + } + public void setRequiredSkillModValue(int requiredSkillModValue) { + this.requiredSkillModValue = requiredSkillModValue; + } + public void setTargetType(int targetType) { + this.targetType = targetType; + } + + public boolean isMusic() { + return music; + } + + public void setMusic(boolean music) { + this.music = music; + } + + public boolean isDance() { + return dance; + } + + public void setDance(boolean dance) { + this.dance = dance; + } + +} diff --git a/src/resources/objects/creature/CreatureObject.java b/src/resources/objects/creature/CreatureObject.java index e02a879e..46d13369 100644 --- a/src/resources/objects/creature/CreatureObject.java +++ b/src/resources/objects/creature/CreatureObject.java @@ -31,6 +31,7 @@ import org.apache.mina.core.buffer.IoBuffer; import protocol.swg.ChatSystemMessage; import protocol.swg.ObjControllerMessage; +import protocol.swg.PlayClientEffectObjectMessage; import protocol.swg.PlayMusicMessage; import protocol.swg.UpdatePostureMessage; import protocol.swg.UpdatePVPStatusMessage; @@ -167,6 +168,9 @@ public class CreatureObject extends TangibleObject implements IPersistent { @NotPersistent private int flourishCount = 0; + @NotPersistent + private boolean performingEffect; + public CreatureObject(long objectID, Planet planet, Point3D position, Quaternion orientation, String Template) { super(objectID, planet, Template, position, orientation); messageBuilder = new CreatureMessageBuilder(this); @@ -1655,4 +1659,16 @@ public class CreatureObject extends TangibleObject implements IPersistent { this.spectatorTask = spectatorTask; } } + + public boolean isPerformingEffect() { + synchronized(objectMutex) { + return performingEffect; + } + } + + public void setPerformingEffect(boolean hasEffect) { + synchronized(objectMutex) { + this.performingEffect = hasEffect; + } + } } diff --git a/src/services/EntertainmentService.java b/src/services/EntertainmentService.java index ad35f3f8..b45b0c8d 100644 --- a/src/services/EntertainmentService.java +++ b/src/services/EntertainmentService.java @@ -18,6 +18,7 @@ import org.apache.mina.core.session.IoSession; import protocol.swg.ObjControllerMessage; import protocol.swg.OkMessage; +import protocol.swg.PlayClientEffectObjectMessage; import protocol.swg.objectControllerObjects.BuffBuilderChangeMessage; import protocol.swg.objectControllerObjects.BuffBuilderEndMessage; import protocol.swg.objectControllerObjects.BuffBuilderStartMessage; @@ -25,11 +26,14 @@ import resources.common.BuffBuilder; import resources.common.Console; import resources.common.ObjControllerOpcodes; import resources.common.Performance; +import resources.common.PerformanceEffect; import resources.common.StringUtilities; +import resources.datatables.Posture; import resources.objects.Buff; import resources.objects.BuffItem; import resources.objects.creature.CreatureObject; import resources.objects.player.PlayerObject; +import resources.objects.tangible.TangibleObject; import engine.clientdata.ClientFileManager; import engine.clientdata.visitors.DatatableVisitor; import engine.clients.Client; @@ -44,14 +48,17 @@ public class EntertainmentService implements INetworkDispatch { private Vector buffBuilderSkills = new Vector(); //FIXME: create a wrapper class for double key lookup maps - private HashMap performances = new HashMap(); - private HashMap performancesByIndex = new HashMap(); - private HashMap danceMap = new HashMap(); + private ConcurrentHashMap performances = new ConcurrentHashMap(); + private ConcurrentHashMap performancesByIndex = new ConcurrentHashMap(); + private ConcurrentHashMap danceMap = new ConcurrentHashMap(); + + private Map performanceEffects = new ConcurrentHashMap(); public EntertainmentService(NGECore core) { this.core = core; populateSkillCaps(); populatePerformanceTable(); + populatePerformanceEffects(); registerCommands(); } @@ -288,7 +295,37 @@ public class EntertainmentService implements INetworkDispatch { e.printStackTrace(); } } + + private void populatePerformanceEffects() { + try { + DatatableVisitor effects = ClientFileManager.loadFile("datatables/performance/perform_effect.iff", DatatableVisitor.class); + for (int r = 0; r < effects.getRowCount(); r++) { + String effectName = ((String) effects.getObject(r, 0)); + String performanceType = ((String) effects.getObject(r, 1)); + int requiredSkillModValue = ((int) effects.getObject(r, 2)); + Boolean requiredPerforming = ((Boolean) effects.getObject(r, 3)); + int targetType = ((int) effects.getObject(r, 4)); + float effectDuration = ((float) effects.getObject(r, 5)); + int effectActionCost = ((int) effects.getObject(r, 6)); + + PerformanceEffect item = new PerformanceEffect(); + item.setEffectActionCost(effectActionCost); + item.setEffectDuration(effectDuration); + item.setName(effectName); + item.setPerformanceType(performanceType); + item.setRequiredPerforming(requiredPerforming); + item.setRequiredSkillModValue(requiredSkillModValue); + item.setTargetType(targetType); + + performanceEffects.put(effectName.toLowerCase(), item); + + } + } catch (InstantiationException | IllegalAccessException e) { + e.printStackTrace(); + } + } + private void registerCommands() { core.commandService.registerCommand("bandflourish"); core.commandService.registerCommand("flourish"); @@ -298,6 +335,23 @@ public class EntertainmentService implements INetworkDispatch { core.commandService.registerCommand("stopdance"); core.commandService.registerCommand("watch"); core.commandService.registerCommand("stopwatching"); + //core.commandService.registerCommand("holoEmote"); + // TODO: Add /bandsolo, /bandpause, /changeBandMusic, /changeDance, /changeGroupDance, /changeMusic + + // Entertainer Effects + core.commandService.registerCommand("centerStage"); + core.commandService.registerCommand("colorSwirl"); + core.commandService.registerCommand("colorlights"); + core.commandService.registerCommand("floorLights"); // referred to also as Dance Floor + core.commandService.registerCommand("dazzle"); + core.commandService.registerCommand("distract"); + core.commandService.registerCommand("featuredSolo"); + core.commandService.registerCommand("firejet"); + core.commandService.registerCommand("firejet2"); + core.commandService.registerCommand("laserShow"); + core.commandService.registerCommand("smokebomb"); + core.commandService.registerCommand("spotlight"); + core.commandService.registerCommand("ventriloquism"); } public void giveInspirationBuff(SWGObject reciever, Vector buffVector) { @@ -383,6 +437,10 @@ public class EntertainmentService implements INetworkDispatch { return performancesByIndex.get(index); } + public Map getPerformanceEffects() { + return performanceEffects; + } + public void startPerformance(CreatureObject actor, int performanceId, int performanceCounter, String skillName, boolean isDance) { actor.setPerformanceId(performanceId, isDance); actor.setPerformanceCounter(performanceCounter); @@ -480,7 +538,59 @@ public class EntertainmentService implements INetworkDispatch { }, (long) performance.getLoopDuration(), TimeUnit.SECONDS); } + + public boolean performEffect(final CreatureObject performer, String command, String effect, TangibleObject target) { + PerformanceEffect pEffect = performanceEffects.get(command.toLowerCase()); + if(pEffect == null) + return false; + + String performance = (performer.getPerformanceType()) ? "dance" : "music"; + + // TODO: Skill Level check + + if(performer.isPerformingEffect()) { + performer.sendSystemMessage("@performance:effect_wait_self", (byte) 0); + return false; + } + + if (performer.getPosture() != Posture.SkillAnimating) { + performer.sendSystemMessage("@performance:effect_not_performing", (byte) 0); + return false; + } + + if(performance.equals("dance") && !pEffect.isDance() || performance.equals("music") && !pEffect.isMusic()) { + performer.sendSystemMessage("@performance:effect_not_performing_correct", (byte) 0); + return false; + } + + if(performer.getAction() < pEffect.getEffectActionCost()) { + performer.sendSystemMessage("@performance:effect_too_tired", (byte) 0); + return false; + } + + performer.setAction(performer.getAction() - pEffect.getEffectActionCost()); + + performer.setPerformingEffect(true); + + if(target != null) + target.playEffectObject(effect, ""); + + else + performer.playEffectObject(effect, ""); + + scheduler.schedule(new Runnable() { + + @Override + public void run() { + performer.setPerformingEffect(false); + } + + }, (long) pEffect.getEffectDuration(), TimeUnit.SECONDS); + + return true; + } + @Override public void shutdown() {