diff --git a/Plugins/Mineplex.Core.Common/src/mineplex/core/common/util/UtilText.java b/Plugins/Mineplex.Core.Common/src/mineplex/core/common/util/UtilText.java index 4372b6fba..2095bc1fe 100644 --- a/Plugins/Mineplex.Core.Common/src/mineplex/core/common/util/UtilText.java +++ b/Plugins/Mineplex.Core.Common/src/mineplex/core/common/util/UtilText.java @@ -95,4 +95,22 @@ public class UtilText { public static String[] wrap(String text, int lineLength, boolean wrapLongerWords) { return WordUtils.wrap(text, lineLength, "\00D0", wrapLongerWords).split("\00D0"); } + + public static String repeat(String txt, int times) + { + return new String(new byte[times]).replace("\0", txt); + } + + public static String insertEvery(String txt, String insert, int chars) + { + StringBuilder builder = new StringBuilder(insert + txt); + if (txt.length() > chars) + { + for (int i = 0; i < txt.length() / chars; i++) + { + builder.insert(chars * i, insert); + } + } + return builder.toString(); + } } diff --git a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/ClansManager.java b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/ClansManager.java index 1c9244a7b..113209bd4 100644 --- a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/ClansManager.java +++ b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/ClansManager.java @@ -53,6 +53,7 @@ import mineplex.core.npc.NpcManager; import mineplex.core.packethandler.PacketHandler; import mineplex.core.projectile.ProjectileManager; import mineplex.core.stats.StatsManager; +import mineplex.core.task.TaskManager; import mineplex.core.teleport.Teleport; import mineplex.game.clans.clans.ClansUtility.ClanRelation; import mineplex.game.clans.clans.commands.ClanManagementCommand; @@ -89,6 +90,7 @@ import mineplex.game.clans.gameplay.safelog.LoggingManager; import mineplex.game.clans.gameplay.safelog.npc.NPCManager; import mineplex.game.clans.items.GearManager; import mineplex.game.clans.spawn.Spawn; +import mineplex.game.clans.tutorials.TutorialManager; import mineplex.minecraft.game.classcombat.Class.ClassManager; import mineplex.minecraft.game.classcombat.Class.ClientClass; import mineplex.minecraft.game.classcombat.Class.IPvpClass; @@ -197,6 +199,8 @@ public class ClansManager extends MiniClientPlugin implements IRelat _scoreboard = new ClansScoreboardManager(plugin, this, _warManager, _worldEvent, clientManager, donationManager); new MurderManager(plugin, this); + + new TutorialManager(plugin, _goldManager, donationManager, new TaskManager(plugin, _clientManager, webServerAddress)); _clanAdmin = new ClansAdmin(this); _clanBlocks = new ClansBlocks(); @@ -239,7 +243,7 @@ public class ClansManager extends MiniClientPlugin implements IRelat skillManager.removeSkill("Whirlwind Axe"); skillManager.removeSkill("Shield Smash"); _classManager = new ClassManager(plugin, _clientManager, donationManager, skillManager, itemFactory, webServerAddress); - + // Register redis based server commands ServerCommandManager.getInstance().registerCommandType(ClanDeleteCommand.class, new ClanDeleteCommandHandler()); ServerCommandManager.getInstance().registerCommandType(ClanLoadCommand.class, new ClanLoadCommandHandler()); diff --git a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/tutorials/Consumer.java b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/tutorials/Consumer.java new file mode 100644 index 000000000..6f6b625a0 --- /dev/null +++ b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/tutorials/Consumer.java @@ -0,0 +1,6 @@ +package mineplex.game.clans.tutorials; + +public interface Consumer +{ + public void consume(final T t); +} diff --git a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/tutorials/PlayerTutorial.java b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/tutorials/PlayerTutorial.java new file mode 100644 index 000000000..4d3ea0d02 --- /dev/null +++ b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/tutorials/PlayerTutorial.java @@ -0,0 +1,71 @@ +package mineplex.game.clans.tutorials; + +import org.bukkit.entity.Player; + +import mineplex.core.task.TaskManager; + +public class PlayerTutorial +{ + private final TaskManager _taskManager; + private final Tutorial _tutorial; + private final Player _player; + + private int _currentPart=1; + + public PlayerTutorial(final Player player, final TaskManager taskManager, final Tutorial tutorial) + { + _player = player; + _taskManager = taskManager; + _tutorial = tutorial; + } + + public static PlayerTutorial create(final Player player, final TaskManager taskManager, final Tutorial tutorial) + { + PlayerTutorial user = new PlayerTutorial(player, taskManager, tutorial); + + for (int i : tutorial.getParts().keySet()) + { + if (taskManager.hasCompletedTask(player, tutorial.getType().getId() + tutorial.getPart(i).getId())) + { + user._currentPart = i; + } + } + + tutorial.getPart(user._currentPart).sendDescriptionTo(player); + + return user; + } + + public int getCurrentPart() + { + return _currentPart; + } + + public Tutorial getTutorial() + { + return _tutorial; + } + + public Player getPlayer() + { + return _player; + } + + public TaskManager getTaskManager() + { + return _taskManager; + } + + public void finishedPart(final int partID) + { + if (_currentPart == partID - 1) + { + ++_currentPart; + } + else + { + System.err.println("[CLANS TUTORIALS] FATAL ERROR, PARTS OUT OF SYNC FOR PLAYER " + _player.getName() + "!!!"); + } + } + +} diff --git a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/tutorials/Tutorial.java b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/tutorials/Tutorial.java new file mode 100644 index 000000000..6c7143f6c --- /dev/null +++ b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/tutorials/Tutorial.java @@ -0,0 +1,146 @@ +package mineplex.game.clans.tutorials; + +import java.util.HashMap; + +import org.bukkit.Sound; +import org.bukkit.entity.Player; + +import mineplex.core.common.Pair; +import mineplex.core.common.util.Callback; +import mineplex.core.common.util.F; +import mineplex.core.common.util.UtilPlayer; +import mineplex.core.task.TaskManager; +import mineplex.game.clans.economy.GoldManager; + +/** + * + * I call this a tutorial, even though it is more accurately, "a set of + * achievements or goals, that are in some-what of a tutorial fashion." But that + * would be too long of a class name, so I'll stick with "Tutorial" for now. + * + */ +public abstract class Tutorial +{ + protected final TutorialManager _manager; + private final TaskManager _taskManager; + private final GoldManager _goldManager; + + private final int _rewardAmount; + + private final HashMap>> _parts; + private final HashMap _inTutorial; + private final TutorialType _type; + + public Tutorial(final int rewardAmount, final GoldManager goldManager, final TaskManager taskManager, final TutorialManager manager, final TutorialType type) + { + _goldManager = goldManager; + _taskManager = taskManager; + _rewardAmount = rewardAmount; + _manager = manager; + _type = type; + _parts = new HashMap<>(); + _inTutorial = new HashMap<>(); + } + + protected Consumer addPart(final String name, final String description) + { + final Consumer consumer = new Consumer() + { + public void consume(Player player) + { + finishPart(player, _parts.size() + 1); + } + }; + + _parts.put(_parts.size() + 1, Pair.create(new TutorialPart(_parts.size() + 1, name, description), consumer)); + + return consumer; + } + + private void finishPart(final Player player, final int partID) + { + final Pair> part = _parts.get(partID); + + _inTutorial.get(player.getName()).finishedPart(partID); + + if (!_taskManager.hasCompletedTask(player, _type.getId() + part.getLeft().getId())) + { + _taskManager.completedTask(new Callback() + { + public void run(Boolean completed) + { + UtilPlayer.message(player, F.main("Tutorials", "You have completed part " + F.elem(partID + " (" + part.getLeft().getName() + ")") + ".")); + + player.playSound(player.getLocation(), Sound.LEVEL_UP, 2f, 1.5f); + } + }, player, _type.getId() + part.getLeft().getId()); + } + + if (partID == _parts.size()) + { + finishFor(player); + } + else + { + _parts.get(partID).getLeft().sendDescriptionTo(player); + } + } + + public TutorialPart getPart(final int partID) + { + return _parts.get(partID).getLeft(); + } + + public TutorialType getType() + { + return _type; + } + + private void finishFor(final Player player) + { + _inTutorial.remove(player.getName()); + + UtilPlayer.message(player, F.main("Tutorials", "You have completed the " + F.elem(_type.getFriendlyName() + " Tutorial") + ".")); + if (!_taskManager.hasCompletedTask(player, _type.getId())) + { + _taskManager.completedTask(new Callback() + { + public void run(Boolean completed) + { + _goldManager.addGold(player, _rewardAmount); + } + }, player, _type.getId()); + } + } + + public void startFor(final Player player) + { + _inTutorial.put(player.getName(), PlayerTutorial.create(player, _taskManager, this)); + } + + public void cancelTutorial(final Player player) + { + _inTutorial.remove(player.getName()); + } + + public boolean isInTutorial(final Player player) + { + return _inTutorial.containsKey(player.getName()); + } + + protected HashMap>> getParts() + { + return _parts; + } + + public boolean hasFinished(Player player) + { + return _taskManager.hasCompletedTask(player, _type.getId()); + } + + public PlayerTutorial getPlayer(Player player) + { + return _inTutorial.get(player.getName()); + } + +} diff --git a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/tutorials/TutorialGettingStarted.java b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/tutorials/TutorialGettingStarted.java new file mode 100644 index 000000000..be32e7ae2 --- /dev/null +++ b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/tutorials/TutorialGettingStarted.java @@ -0,0 +1,26 @@ +package mineplex.game.clans.tutorials; + +import mineplex.core.donation.DonationManager; +import mineplex.core.task.TaskManager; +import mineplex.game.clans.economy.GoldManager; + +public class TutorialGettingStarted extends Tutorial +{ + public TutorialGettingStarted(final TutorialManager manager, final GoldManager goldManager, final DonationManager donationManager, final TaskManager taskManager) + { + super(50, goldManager, taskManager, manager, TutorialType.GETTING_STARTED); + addPart("Welcome", "Welcome to Clans! Before you start playing Clans, you should be familiar with the various commands. Type /c help now to view all of the commands for Clans!"); + addPart("Create A Clan", "To create your own clan, type /c create [name]. Don’t worry about being though, you can always disband this clan and join another later if you need to!"); + addPart("Viewing Clan Info", "Now you can view information about your clan. To do this type /c [name]! You can also use any clans name to get some information about them as well."); + addPart("Leave Spawn", "Now you can leave the Spawn Island. Don't worry, you won’t get hurt from the fall! Once you jump off though, PvP is enabled! Be careful!"); + addPart("Go To The Wilderness", "Access your map with /map and head out into the wilderness! You’ll see various other locations marked on your map later."); + addPart("Claiming Territory", "In order to claim a chunk of land for your clan you type /c claim! Notice though, your clan runs on energy! You can buy energy from the shops!"); + addPart("Visit The Shops", "At the shops you can buy most things you need! Once a day you can transfer 1000 gems to 5000 clans gold here as well!"); + addPart("Buy Armor", "Head to the PvP Gear villager and purchase a set of armor! Make sure to buy a matching set to access your class skills!"); + addPart("Equip Armor", "In order to equip a kit, you must put on the full armor set of that kit! Put on the armor set you just bought and you will have selected your kit!"); + addPart("Use An Ability", "In order to use abilities you need a sword or axe. To use your sword ability, right click with your sword! To use your axe ability, right click with your axe!"); + addPart("Class Customization", "To customize your class, right click an enchantment table! There you will find the GUI for all the skills in that class! Customize it to your liking!"); + addPart("Clan Home", "In order to set a clan home, type /c sethome. You can only use this /c home from the spawn island every 5 minutes to return home!"); + } + +} diff --git a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/tutorials/TutorialManager.java b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/tutorials/TutorialManager.java new file mode 100644 index 000000000..e1ececfba --- /dev/null +++ b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/tutorials/TutorialManager.java @@ -0,0 +1,69 @@ +package mineplex.game.clans.tutorials; + +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.player.PlayerJoinEvent; +import org.bukkit.plugin.java.JavaPlugin; + +import mineplex.core.MiniPlugin; +import mineplex.core.common.util.F; +import mineplex.core.common.util.UtilPlayer; +import mineplex.core.donation.DonationManager; +import mineplex.core.task.TaskManager; +import mineplex.game.clans.economy.GoldManager; + +public class TutorialManager extends MiniPlugin +{ + private final Tutorial _gettingStarted; + + public TutorialManager(final JavaPlugin plugin, final GoldManager goldManager, final DonationManager donationManager, final TaskManager taskManager) + { + super("Tutorials", plugin); + + _gettingStarted = new TutorialGettingStarted(this, goldManager, donationManager, taskManager); + } + + public void startTutorial(final TutorialType type, final Player player) + { + switch (type) + { + case GETTING_STARTED: + _gettingStarted.startFor(player); + } + } + + @EventHandler + public void onPlayerJoin(PlayerJoinEvent evt) + { + if (!_gettingStarted.hasFinished(evt.getPlayer())) + { + _gettingStarted.startFor(evt.getPlayer()); + } + } + + public boolean isInTutorial(Player player) + { + return _gettingStarted.isInTutorial(player); + } + + public void cancelTutorial(Player player) + { + if (_gettingStarted.isInTutorial(player)) + { + _gettingStarted.cancelTutorial(player); + + UtilPlayer.message(player, F.main("Tutorials", "You have cancelled the " + F.elem(_gettingStarted.getType().getFriendlyName() + "Tutorial") + ".")); + } + } + + public Tutorial getTutorial(Player player) + { + if (_gettingStarted.isInTutorial(player)) + { + return _gettingStarted; + } + + return null; + } + +} diff --git a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/tutorials/TutorialPart.java b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/tutorials/TutorialPart.java new file mode 100644 index 000000000..4c41f378e --- /dev/null +++ b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/tutorials/TutorialPart.java @@ -0,0 +1,49 @@ +package mineplex.game.clans.tutorials; + +import org.bukkit.entity.Player; + +import mineplex.core.common.util.C; +import mineplex.core.common.util.UtilPlayer; +import mineplex.core.common.util.UtilText; + +public class TutorialPart +{ + private final String _name; + private final String _description; + private final int _id; + + public TutorialPart(final int id, final String name, final String description) + { + _id = id; + _name = name; + _description = description; + } + + public int getID() + { + return _id; + } + + public String getName() + { + return _name; + } + + public String getDescription() + { + return _description; + } + + public String getId() + { + return _name.replace(" ", ""); + } + + public void sendDescriptionTo(Player player) + { + UtilPlayer.message(player, C.cGreen + "=== Pt." + _id + ": " + _name + " ==="); + UtilPlayer.message(player, UtilText.insertEvery(_description, C.cYellow, 15)); + UtilPlayer.message(player, C.cGreen + "=== " + UtilText.repeat("=", _name.length() + ("Pt." + _id + ":").length()) + " ==="); + } + +} diff --git a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/tutorials/TutorialType.java b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/tutorials/TutorialType.java new file mode 100644 index 000000000..021aa0167 --- /dev/null +++ b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/tutorials/TutorialType.java @@ -0,0 +1,32 @@ +package mineplex.game.clans.tutorials; + +public enum TutorialType +{ + GETTING_STARTED(TutorialGettingStarted.class, "Getting Started", "GettingStartedTutorial"); + + private final Class _clazz; + private final String _uniqueId; + private final String _friendlyName; + + TutorialType(final Class clazz, final String friendlyName, final String uniqueId) + { + _clazz = clazz; + _uniqueId = uniqueId; + _friendlyName = friendlyName; + } + + public Class getClazz() + { + return _clazz; + } + + public String getId() + { + return _uniqueId; + } + + public String getFriendlyName() + { + return _friendlyName; + } +} diff --git a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/tutorials/commands/EndTutorialCommand.java b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/tutorials/commands/EndTutorialCommand.java new file mode 100644 index 000000000..08fbe2852 --- /dev/null +++ b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/tutorials/commands/EndTutorialCommand.java @@ -0,0 +1,31 @@ +package mineplex.game.clans.tutorials.commands; + +import org.bukkit.entity.Player; + +import mineplex.core.command.CommandBase; +import mineplex.core.common.Rank; +import mineplex.core.common.util.F; +import mineplex.core.common.util.UtilPlayer; +import mineplex.game.clans.tutorials.TutorialManager; + +public class EndTutorialCommand extends CommandBase +{ + public EndTutorialCommand(TutorialManager plugin) + { + super(plugin, Rank.ALL, "endtutorial", "endtut", "et"); + } + + @Override + public void Execute(Player caller, String[] args) + { + if (Plugin.isInTutorial(caller)) + { + Plugin.cancelTutorial(caller); + } + else + { + UtilPlayer.message(caller, F.main("Tutorials", "You are not currently in a tutorial.")); + } + } + +} diff --git a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/tutorials/commands/TaskInfoCommand.java b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/tutorials/commands/TaskInfoCommand.java new file mode 100644 index 000000000..3fcc5b320 --- /dev/null +++ b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/tutorials/commands/TaskInfoCommand.java @@ -0,0 +1,31 @@ +package mineplex.game.clans.tutorials.commands; + +import org.bukkit.entity.Player; + +import mineplex.core.command.CommandBase; +import mineplex.core.common.Rank; +import mineplex.core.common.util.F; +import mineplex.core.common.util.UtilPlayer; +import mineplex.game.clans.tutorials.TutorialManager; + +public class TaskInfoCommand extends CommandBase +{ + public TaskInfoCommand(TutorialManager plugin) + { + super(plugin, Rank.ALL, "partinfo", "pi"); + } + + @Override + public void Execute(Player caller, String[] args) + { + if (Plugin.isInTutorial(caller)) + { + Plugin.getTutorial(caller).getPart(Plugin.getTutorial(caller).getPlayer(caller).getCurrentPart()).sendDescriptionTo(caller); + } + else + { + UtilPlayer.message(caller, F.main("Tutorials", "You are not currently in a tutorial.")); + } + } + +}