From 5a27faeb354ba9ee662f54e17b162e6fa10de0fe Mon Sep 17 00:00:00 2001 From: Ziggy Date: Sat, 28 Mar 2020 16:08:56 +0100 Subject: [PATCH] Jedi can tune lightsaber crystals #191 --- .../gameplay/jedi/TuneCrystalIntent.java | 54 +++++++++ .../support/objects/radial/RadialHandler.java | 1 + .../radial/object/TuneCrystalRadial.java | 71 ++++++++++++ .../TerminalCharacterBuilderRadial.java | 12 +- .../support/objects/swg/ServerAttribute.java | 5 +- .../services/gameplay/GameplayManager.java | 2 + .../services/gameplay/jedi/JediManager.java | 37 +++++++ .../jedi/LightsaberCrystalService.java | 103 ++++++++++++++++++ .../radial/object/TestTuneCrystalRadial.java | 81 ++++++++++++++ 9 files changed, 363 insertions(+), 3 deletions(-) create mode 100644 src/main/java/com/projectswg/holocore/intents/gameplay/jedi/TuneCrystalIntent.java create mode 100644 src/main/java/com/projectswg/holocore/resources/support/objects/radial/object/TuneCrystalRadial.java create mode 100644 src/main/java/com/projectswg/holocore/services/gameplay/jedi/JediManager.java create mode 100644 src/main/java/com/projectswg/holocore/services/gameplay/jedi/LightsaberCrystalService.java create mode 100644 src/test/java/com/projectswg/holocore/resources/support/objects/radial/object/TestTuneCrystalRadial.java diff --git a/src/main/java/com/projectswg/holocore/intents/gameplay/jedi/TuneCrystalIntent.java b/src/main/java/com/projectswg/holocore/intents/gameplay/jedi/TuneCrystalIntent.java new file mode 100644 index 000000000..ad4a85f5c --- /dev/null +++ b/src/main/java/com/projectswg/holocore/intents/gameplay/jedi/TuneCrystalIntent.java @@ -0,0 +1,54 @@ +/*********************************************************************************** + * Copyright (c) 2018 /// Project SWG /// www.projectswg.com * + * * + * ProjectSWG is the first NGE emulator for Star Wars Galaxies founded on * + * July 7th, 2011 after SOE announced the official shutdown of Star Wars Galaxies. * + * Our goal is to create an emulator which will provide a server for players to * + * continue playing a game similar to the one they used to play. We are basing * + * it on the final publish of the game prior to end-game events. * + * * + * This file is part of Holocore. * + * * + * --------------------------------------------------------------------------------* + * * + * Holocore is free software: you can redistribute it and/or modify * + * it under the terms of the GNU Affero General Public License as * + * published by the Free Software Foundation, either version 3 of the * + * License, or (at your option) any later version. * + * * + * Holocore 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 Affero General Public License for more details. * + * * + * You should have received a copy of the GNU Affero General Public License * + * along with Holocore. If not, see . * + ***********************************************************************************/ +package com.projectswg.holocore.intents.gameplay.jedi; + +import com.projectswg.holocore.resources.support.objects.swg.SWGObject; +import com.projectswg.holocore.resources.support.objects.swg.creature.CreatureObject; +import me.joshlarson.jlcommon.control.Intent; +import org.jetbrains.annotations.NotNull; + +public class TuneCrystalIntent extends Intent { + private final CreatureObject tuner; + private final SWGObject crystal; + + private TuneCrystalIntent(@NotNull CreatureObject tuner, @NotNull SWGObject crystal) { + this.tuner = tuner; + this.crystal = crystal; + } + + public @NotNull CreatureObject getTuner() { + return tuner; + } + + public @NotNull SWGObject getCrystal() { + return crystal; + } + + public static void broadcast(@NotNull CreatureObject tuner, @NotNull SWGObject crystal) { + new TuneCrystalIntent(tuner, crystal).broadcast(); + } +} diff --git a/src/main/java/com/projectswg/holocore/resources/support/objects/radial/RadialHandler.java b/src/main/java/com/projectswg/holocore/resources/support/objects/radial/RadialHandler.java index b808440a2..13f0e6f0d 100644 --- a/src/main/java/com/projectswg/holocore/resources/support/objects/radial/RadialHandler.java +++ b/src/main/java/com/projectswg/holocore/resources/support/objects/radial/RadialHandler.java @@ -111,6 +111,7 @@ public enum RadialHandler { registerHandler(RareLootService.RARE_CHEST, new RareLootRadial()); registerHandler(RareLootService.EXCEPTIONAL_CHEST, new RareLootRadial()); registerHandler(RareLootService.LEGENDARY_CHEST, new RareLootRadial()); + registerHandler(GameObjectType.GOT_COMPONENT_SABER_CRYSTAL, new TuneCrystalRadial()); } private void initializeContainerRadials() { diff --git a/src/main/java/com/projectswg/holocore/resources/support/objects/radial/object/TuneCrystalRadial.java b/src/main/java/com/projectswg/holocore/resources/support/objects/radial/object/TuneCrystalRadial.java new file mode 100644 index 000000000..c499f66ad --- /dev/null +++ b/src/main/java/com/projectswg/holocore/resources/support/objects/radial/object/TuneCrystalRadial.java @@ -0,0 +1,71 @@ +/*********************************************************************************** + * Copyright (c) 2018 /// Project SWG /// www.projectswg.com * + * * + * ProjectSWG is the first NGE emulator for Star Wars Galaxies founded on * + * July 7th, 2011 after SOE announced the official shutdown of Star Wars Galaxies. * + * Our goal is to create an emulator which will provide a server for players to * + * continue playing a game similar to the one they used to play. We are basing * + * it on the final publish of the game prior to end-game events. * + * * + * This file is part of Holocore. * + * * + * --------------------------------------------------------------------------------* + * * + * Holocore is free software: you can redistribute it and/or modify * + * it under the terms of the GNU Affero General Public License as * + * published by the Free Software Foundation, either version 3 of the * + * License, or (at your option) any later version. * + * * + * Holocore 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 Affero General Public License for more details. * + * * + * You should have received a copy of the GNU Affero General Public License * + * along with Holocore. If not, see . * + ***********************************************************************************/ +package com.projectswg.holocore.resources.support.objects.radial.object; + +import com.projectswg.common.data.objects.GameObjectType; +import com.projectswg.common.data.radial.RadialItem; +import com.projectswg.common.data.radial.RadialOption; +import com.projectswg.holocore.intents.gameplay.jedi.TuneCrystalIntent; +import com.projectswg.holocore.resources.support.global.player.Player; +import com.projectswg.holocore.resources.support.objects.swg.SWGObject; +import com.projectswg.holocore.resources.support.objects.swg.player.Profession; + +import java.util.Collection; + +public class TuneCrystalRadial extends SWGObjectRadial { + + private static final String CRYSTAL_OWNER = "@obj_attr_n:crystal_owner"; + private static final String UNTUNED = "\\#D1F56F UNTUNED \\#FFFFFF "; + + @Override + public void getOptions(Collection options, Player player, SWGObject target) { + if (isOptionVisible(player, target)) { + options.add(RadialOption.create(RadialItem.SERVER_MENU19, "@jedi_spam:tune_crystal")); + } + } + + @Override + public void handleSelection(Player player, SWGObject target, RadialItem selection) { + if (isOptionVisible(player, target)) { + TuneCrystalIntent.broadcast(player.getCreatureObject(), target); // Shows the confirmation window + } + } + + private final boolean isOptionVisible(Player player, SWGObject crystal) { + Profession profession = player.getPlayerObject().getProfession(); + + return !isTuned(crystal) && GameObjectType.GOT_COMPONENT_SABER_CRYSTAL == crystal.getGameObjectType() && profession == Profession.FORCE_SENSITIVE; + } + + private final boolean isTuned(SWGObject crystal) { + if (!crystal.hasAttribute(CRYSTAL_OWNER)) { + return false; + } + + return !UNTUNED.equals(crystal.getAttribute(CRYSTAL_OWNER)); + } +} diff --git a/src/main/java/com/projectswg/holocore/resources/support/objects/radial/terminal/TerminalCharacterBuilderRadial.java b/src/main/java/com/projectswg/holocore/resources/support/objects/radial/terminal/TerminalCharacterBuilderRadial.java index ea84233ea..37f0a98b6 100644 --- a/src/main/java/com/projectswg/holocore/resources/support/objects/radial/terminal/TerminalCharacterBuilderRadial.java +++ b/src/main/java/com/projectswg/holocore/resources/support/objects/radial/terminal/TerminalCharacterBuilderRadial.java @@ -531,7 +531,17 @@ public class TerminalCharacterBuilderRadial implements RadialHandlerInterface { "weapon_mandalorian_lightsaber_04_01", "weapon_npe_lightsaber_02_01", "weapon_npe_lightsaber_02_02", - "weapon_roadmap_lightsaber_02_02" + "weapon_roadmap_lightsaber_02_02", + "item_color_crystal_02_16", // Bane's Heart + "item_color_crystal_02_19", // B'nar's Sacrifice + "item_color_crystal_02_20", // Windu's Guile + "item_color_crystal_02_28", // Kenobi's Legacy + "item_color_crystal_02_29", // Sunrider's Destiny + "item_power_crystal_04_01", // Power crystal + "item_power_crystal_04_04", // Power crystal + "item_power_crystal_04_07", // Power crystal + "item_power_crystal_04_09", // Power crystal + "item_power_crystal_04_20" // Power crystal ); } diff --git a/src/main/java/com/projectswg/holocore/resources/support/objects/swg/ServerAttribute.java b/src/main/java/com/projectswg/holocore/resources/support/objects/swg/ServerAttribute.java index 8b467be42..6a1f3f51a 100644 --- a/src/main/java/com/projectswg/holocore/resources/support/objects/swg/ServerAttribute.java +++ b/src/main/java/com/projectswg/holocore/resources/support/objects/swg/ServerAttribute.java @@ -34,10 +34,11 @@ import java.util.function.Function; public enum ServerAttribute { PCD_PET_TEMPLATE ("pcd.pet.template", PredefinedDataType.STRING), - EGG_SPAWNER ("egg.spawner", Spawner.class, s -> null, s -> null), + EGG_SPAWNER ("egg.spawner", Spawner.class, s -> null, s -> null), GALACTIC_RESOURCE_ID("resources.galactic_resource_id", PredefinedDataType.LONG), SURVEY_TOOL_RANGE ("survey_tool.range", PredefinedDataType.INT), - SET_BONUS_ID ("set_bonus.id", PredefinedDataType.INT); + SET_BONUS_ID ("set_bonus.id", PredefinedDataType.INT), + LINK_OBJECT_ID ("link.object.id", PredefinedDataType.LONG); private static final EnumLookup KEY_LOOKUP = new EnumLookup<>(ServerAttribute.class, ServerAttribute::getKey); diff --git a/src/main/java/com/projectswg/holocore/services/gameplay/GameplayManager.java b/src/main/java/com/projectswg/holocore/services/gameplay/GameplayManager.java index da5bcce50..326f855a7 100644 --- a/src/main/java/com/projectswg/holocore/services/gameplay/GameplayManager.java +++ b/src/main/java/com/projectswg/holocore/services/gameplay/GameplayManager.java @@ -5,6 +5,7 @@ import com.projectswg.holocore.services.gameplay.crafting.CraftingManager; import com.projectswg.holocore.services.gameplay.entertainment.EntertainmentManager; import com.projectswg.holocore.services.gameplay.faction.FactionManager; import com.projectswg.holocore.services.gameplay.gcw.GalacticCivilWarManager; +import com.projectswg.holocore.services.gameplay.jedi.JediManager; import com.projectswg.holocore.services.gameplay.player.PlayerManager; import com.projectswg.holocore.services.gameplay.structures.StructuresManager; import com.projectswg.holocore.services.gameplay.world.WorldManager; @@ -17,6 +18,7 @@ import me.joshlarson.jlcommon.control.ManagerStructure; EntertainmentManager.class, FactionManager.class, GalacticCivilWarManager.class, + JediManager.class, PlayerManager.class, StructuresManager.class, WorldManager.class diff --git a/src/main/java/com/projectswg/holocore/services/gameplay/jedi/JediManager.java b/src/main/java/com/projectswg/holocore/services/gameplay/jedi/JediManager.java new file mode 100644 index 000000000..7a98c364e --- /dev/null +++ b/src/main/java/com/projectswg/holocore/services/gameplay/jedi/JediManager.java @@ -0,0 +1,37 @@ +/*********************************************************************************** + * Copyright (c) 2018 /// Project SWG /// www.projectswg.com * + * * + * ProjectSWG is the first NGE emulator for Star Wars Galaxies founded on * + * July 7th, 2011 after SOE announced the official shutdown of Star Wars Galaxies. * + * Our goal is to create an emulator which will provide a server for players to * + * continue playing a game similar to the one they used to play. We are basing * + * it on the final publish of the game prior to end-game events. * + * * + * This file is part of Holocore. * + * * + * --------------------------------------------------------------------------------* + * * + * Holocore is free software: you can redistribute it and/or modify * + * it under the terms of the GNU Affero General Public License as * + * published by the Free Software Foundation, either version 3 of the * + * License, or (at your option) any later version. * + * * + * Holocore 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 Affero General Public License for more details. * + * * + * You should have received a copy of the GNU Affero General Public License * + * along with Holocore. If not, see . * + ***********************************************************************************/ +package com.projectswg.holocore.services.gameplay.jedi; + +import me.joshlarson.jlcommon.control.Manager; +import me.joshlarson.jlcommon.control.ManagerStructure; + +@ManagerStructure(children = { + LightsaberCrystalService.class, +}) +public class JediManager extends Manager { + +} diff --git a/src/main/java/com/projectswg/holocore/services/gameplay/jedi/LightsaberCrystalService.java b/src/main/java/com/projectswg/holocore/services/gameplay/jedi/LightsaberCrystalService.java new file mode 100644 index 000000000..c727c8d65 --- /dev/null +++ b/src/main/java/com/projectswg/holocore/services/gameplay/jedi/LightsaberCrystalService.java @@ -0,0 +1,103 @@ +/*********************************************************************************** + * Copyright (c) 2018 /// Project SWG /// www.projectswg.com * + * * + * ProjectSWG is the first NGE emulator for Star Wars Galaxies founded on * + * July 7th, 2011 after SOE announced the official shutdown of Star Wars Galaxies. * + * Our goal is to create an emulator which will provide a server for players to * + * continue playing a game similar to the one they used to play. We are basing * + * it on the final publish of the game prior to end-game events. * + * * + * This file is part of Holocore. * + * * + * --------------------------------------------------------------------------------* + * * + * Holocore is free software: you can redistribute it and/or modify * + * it under the terms of the GNU Affero General Public License as * + * published by the Free Software Foundation, either version 3 of the * + * License, or (at your option) any later version. * + * * + * Holocore 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 Affero General Public License for more details. * + * * + * You should have received a copy of the GNU Affero General Public License * + * along with Holocore. If not, see . * + ***********************************************************************************/ +package com.projectswg.holocore.services.gameplay.jedi; + +import com.projectswg.common.data.objects.GameObjectType; +import com.projectswg.holocore.intents.gameplay.jedi.TuneCrystalIntent; +import com.projectswg.holocore.intents.support.global.chat.SystemMessageIntent; +import com.projectswg.holocore.intents.support.objects.swg.ObjectCreatedIntent; +import com.projectswg.holocore.resources.support.global.player.Player; +import com.projectswg.holocore.resources.support.global.zone.sui.SuiButtons; +import com.projectswg.holocore.resources.support.global.zone.sui.SuiMessageBox; +import com.projectswg.holocore.resources.support.objects.swg.SWGObject; +import com.projectswg.holocore.resources.support.objects.swg.ServerAttribute; +import com.projectswg.holocore.resources.support.objects.swg.creature.CreatureObject; +import me.joshlarson.jlcommon.control.IntentHandler; +import me.joshlarson.jlcommon.control.Service; + +/** + *

Responsibilities

+ *
    + *
  • Lightsaber crystal tuning
  • + *
  • Applying the owner attribute to crystals that are created and don't already have it
  • + *
+ */ +public class LightsaberCrystalService extends Service { + + private static final String CRYSTAL_OWNER = "@obj_attr_n:crystal_owner"; + private static final String UNTUNED = "\\#D1F56F UNTUNED \\#FFFFFF "; + + @IntentHandler + private void handleTuneCrystalIntent(TuneCrystalIntent intent) { + CreatureObject tuner = intent.getTuner(); + SWGObject crystal = intent.getCrystal(); + + if (isTuned(crystal)) { + return; + } + + Player owner = tuner.getOwner(); + + if (owner == null) { + return; + } + + SuiMessageBox suiMessageBox = new SuiMessageBox(SuiButtons.YES_NO, "@jedi_spam:confirm_tune_title", "@jedi_spam:confirm_tune_prompt"); + + suiMessageBox.addOkButtonCallback("tune", ((event, parameters) -> { + crystal.setServerAttribute(ServerAttribute.LINK_OBJECT_ID, tuner.getObjectId()); // In case the name of the character ever changes + crystal.addAttribute(CRYSTAL_OWNER, tuner.getObjectName()); + crystal.setObjectName( "\\#00FF00" + crystal.getObjectName() + " (tuned)"); + + // TODO if power crystal or pearl (look for Quality? attribute on object), then apply randomized(?) min/max attributes as well + + SystemMessageIntent.broadcastPersonal(owner, "@jedi_spam:crystal_tune_success"); + })); + + suiMessageBox.display(owner); + } + + @IntentHandler + private void handleObjectCreated(ObjectCreatedIntent intent) { + SWGObject object = intent.getObject(); + + if (object.getGameObjectType() != GameObjectType.GOT_COMPONENT_SABER_CRYSTAL || isTuned(object)) { + // We don't apply the untuned attribute to something that's not a lightsaber crystal or already has the attribute + return; + } + + object.addAttribute(CRYSTAL_OWNER, UNTUNED); + } + + private final boolean isTuned(SWGObject crystal) { + if (!crystal.hasAttribute(CRYSTAL_OWNER)) { + return false; + } + + return !UNTUNED.equals(crystal.getAttribute(CRYSTAL_OWNER)); + } +} diff --git a/src/test/java/com/projectswg/holocore/resources/support/objects/radial/object/TestTuneCrystalRadial.java b/src/test/java/com/projectswg/holocore/resources/support/objects/radial/object/TestTuneCrystalRadial.java new file mode 100644 index 000000000..e5e529587 --- /dev/null +++ b/src/test/java/com/projectswg/holocore/resources/support/objects/radial/object/TestTuneCrystalRadial.java @@ -0,0 +1,81 @@ +package com.projectswg.holocore.resources.support.objects.radial.object; + +import com.projectswg.common.data.objects.GameObjectType; +import com.projectswg.common.data.radial.RadialOption; +import com.projectswg.holocore.resources.support.objects.swg.SWGObject; +import com.projectswg.holocore.resources.support.objects.swg.creature.CreatureObject; +import com.projectswg.holocore.resources.support.objects.swg.player.PlayerObject; +import com.projectswg.holocore.resources.support.objects.swg.player.Profession; +import com.projectswg.holocore.test.resources.GenericCreatureObject; +import com.projectswg.holocore.test.resources.GenericPlayer; +import com.projectswg.holocore.test.resources.GenericTangibleObject; +import org.junit.Before; +import org.junit.Test; + +import java.util.ArrayList; +import java.util.List; + +import static org.junit.Assert.*; + +public class TestTuneCrystalRadial { + + private TuneCrystalRadial radial; + private GenericPlayer player; + private SWGObject crystal; + + @Before + public void setup() { + radial = new TuneCrystalRadial(); + player = new GenericPlayer(); + CreatureObject creatureObject = new GenericCreatureObject(1, "Some Player", true); + creatureObject.getPlayerObject().setProfession(Profession.FORCE_SENSITIVE); // Only Jedi can tune crystals + player.setCreatureObject(creatureObject); + + crystal = new GenericTangibleObject(3); + crystal.setGameObjectType(GameObjectType.GOT_COMPONENT_SABER_CRYSTAL); + crystal.addAttribute("@obj_attr_n:crystal_owner", "\\#D1F56F UNTUNED \\#FFFFFF "); + } + + @Test + public void testNotCrystal() { + List options = new ArrayList<>(); + crystal.setGameObjectType(GameObjectType.GOT_CLOTHING_JACKET); // Let's change the object type to something different + + radial.getOptions(options, player, crystal); + + assertTrue("You should not be able to tune objects that are not lightsaber crystals", options.isEmpty()); + } + + @Test + public void testCrystalUntuned() { + List options = new ArrayList<>(); + radial.getOptions(options, player, crystal); + + assertEquals("Untuned crystals should have one radial option", 1, options.size()); + + RadialOption radialOption = options.get(0); + assertEquals("Untuned crystals should present the option of tuning them", "@jedi_spam:tune_crystal", radialOption.getLabel()); + } + + @Test + public void testCrystalAlreadyTuned() { + List options = new ArrayList<>(); + + // Let's tune the crystal + crystal.addAttribute("@obj_attr_n:crystal_owner", "Some Player"); + + radial.getOptions(options, player, crystal); + + assertTrue("Tuned crystals should have no options", options.isEmpty()); + } + + @Test + public void testNotJedi() { + List options = new ArrayList<>(); + player.getPlayerObject().setProfession(Profession.MEDIC); // Something that's not Jedi - doesn't really matter what + + radial.getOptions(options, player, crystal); + + assertTrue("Only Jedi should be able to tune crystals", options.isEmpty()); + } +}