diff --git a/TestServer/plugins/TF_PrisonEscape/config.yml b/TestServer/plugins/TF_PrisonEscape/config.yml index 876f8ff..4a4243e 100644 --- a/TestServer/plugins/TF_PrisonEscape/config.yml +++ b/TestServer/plugins/TF_PrisonEscape/config.yml @@ -39,6 +39,7 @@ TradeRequestTimeout: 15 MissionsPerDay: 3 MissionMoneyReward: 10 DifferencesAmount: 3 +SequenceSize: 5 AvailableLanguages: - "english" DefaultLanguage: "english" diff --git a/TestServer/plugins/TF_PrisonEscape/languages/english.yml b/TestServer/plugins/TF_PrisonEscape/languages/english.yml index 88c2c41..265bb77 100644 --- a/TestServer/plugins/TF_PrisonEscape/languages/english.yml +++ b/TestServer/plugins/TF_PrisonEscape/languages/english.yml @@ -200,6 +200,8 @@ Inventory: Title: "Spot the differences {CURRENT}/{TOTAL}" Sort: Title: "Sort the flowers. Correct: {CORRECT}" + Sequence: + Title: "Remember the sequence" Messages: GeneralMessage: "&8[GENERAL] <{PLAYER}> &f{MESSAGE}" PoliceTeamMessage: "&9[TEAM] <{PLAYER}> &f{MESSAGE}" diff --git a/src/main/java/net/tiagofar78/prisonescape/managers/ConfigManager.java b/src/main/java/net/tiagofar78/prisonescape/managers/ConfigManager.java index 34de26d..a877d81 100644 --- a/src/main/java/net/tiagofar78/prisonescape/managers/ConfigManager.java +++ b/src/main/java/net/tiagofar78/prisonescape/managers/ConfigManager.java @@ -66,6 +66,7 @@ public static ConfigManager getInstance() { private int _missionsPerDay; private int _missionMoneyReward; private int _differencesAmount; + private int _sequenceSize; private List _availableLanguages; private String _defaultLanguage; @@ -158,6 +159,7 @@ public ConfigManager() { _missionsPerDay = config.getInt("MissionsPerDay"); _missionMoneyReward = config.getInt("MissionMoneyReward"); _differencesAmount = config.getInt("DifferencesAmount"); + _sequenceSize = config.getInt("SequenceSize"); _availableLanguages = config.getStringList("AvailableLanguages"); _defaultLanguage = config.getString("DefaultLanguage"); @@ -524,6 +526,10 @@ public int getDifferencesAmount() { return _differencesAmount; } + public int getSequenceSize() { + return _sequenceSize; + } + public List getAvailableLanguages() { return new ArrayList<>(_availableLanguages); } diff --git a/src/main/java/net/tiagofar78/prisonescape/managers/MessageLanguageManager.java b/src/main/java/net/tiagofar78/prisonescape/managers/MessageLanguageManager.java index cf1fba1..2862df0 100644 --- a/src/main/java/net/tiagofar78/prisonescape/managers/MessageLanguageManager.java +++ b/src/main/java/net/tiagofar78/prisonescape/managers/MessageLanguageManager.java @@ -122,6 +122,7 @@ private static String getPlayerLanguage(String playerName) { private String _ricochetDownItemName; private String _differencesTitle; private String _sortTitle; + private String _sequenceTitle; // ######################################## // # Chat # @@ -320,6 +321,7 @@ private MessageLanguageManager(String language) { _ricochetDownItemName = createMessage(messages.getString("Inventory.Ricochet.DownItem.Name")); _differencesTitle = createMessage(messages.getString("Inventory.Differences.Title")); _sortTitle = createMessage(messages.getString("Inventory.Sort.Title")); + _sequenceTitle = createMessage(messages.getString("Inventory.Sequence.Title")); String messagePath = "Messages."; _generalMessage = createMessage(messages.getString(messagePath + "GeneralMessage")); @@ -648,6 +650,10 @@ public String getSortTitle(String correct) { return _sortTitle.replace("{CORRECT}", correct); } + public String getSequenceTitle() { + return _sequenceTitle; + } + // ######################################## // # Chat # // ######################################## diff --git a/src/main/java/net/tiagofar78/prisonescape/missions/Mission.java b/src/main/java/net/tiagofar78/prisonescape/missions/Mission.java index b2e658f..cfc5b39 100644 --- a/src/main/java/net/tiagofar78/prisonescape/missions/Mission.java +++ b/src/main/java/net/tiagofar78/prisonescape/missions/Mission.java @@ -14,7 +14,8 @@ public static Mission getRandomMission(String regionName) { new ColorConnectMission(regionName), new RicochetMission(regionName), new DifferencesMission(regionName), - new SortMission(regionName)}; + new SortMission(regionName), + new SequenceMission(regionName)}; Random random = new Random(); return missions[random.nextInt(missions.length)]; diff --git a/src/main/java/net/tiagofar78/prisonescape/missions/SequenceMission.java b/src/main/java/net/tiagofar78/prisonescape/missions/SequenceMission.java new file mode 100644 index 0000000..6b286ac --- /dev/null +++ b/src/main/java/net/tiagofar78/prisonescape/missions/SequenceMission.java @@ -0,0 +1,292 @@ +package net.tiagofar78.prisonescape.missions; + +import net.tiagofar78.prisonescape.PrisonEscape; +import net.tiagofar78.prisonescape.game.Guard; +import net.tiagofar78.prisonescape.game.PEPlayer; +import net.tiagofar78.prisonescape.managers.ConfigManager; +import net.tiagofar78.prisonescape.managers.MessageLanguageManager; +import net.tiagofar78.prisonescape.menus.ClickReturnAction; +import net.tiagofar78.prisonescape.menus.Clickable; + +import org.bukkit.Bukkit; +import org.bukkit.Material; +import org.bukkit.event.inventory.ClickType; +import org.bukkit.inventory.Inventory; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.ItemMeta; + +import java.util.ArrayList; +import java.util.List; +import java.util.Random; + +public class SequenceMission extends Mission implements Clickable { + + private final static int[] BUTTONS_SLOTS = { + 9 * 1 + 3, + 9 * 1 + 4, + 9 * 1 + 5, + 9 * 2 + 3, + 9 * 2 + 4, + 9 * 2 + 5, + 9 * 3 + 3, + 9 * 3 + 4, + 9 * 3 + 5}; + private final static Material BUTTON_MATERIAL = Material.GRAY_STAINED_GLASS_PANE; + private final static Material HIGHLIGHT_MATERIAL = Material.BLUE_STAINED_GLASS_PANE; + private final static Material FAIL_MATERIAL = Material.RED_STAINED_GLASS_PANE; + private final static int ANIMATION_TICKS = 20; + + private Guard _guard; + private int _missionIndex; + + private SequenceGame _game; + private int _currentSequenceIndex; + private int _reachedSequenceIndex; + private boolean _isClickingEnabled; + private AnimationFunction _animation; + + public SequenceMission(String regionName) { + super(regionName); + } + + @Override + public void start(Guard guard, int missionIndex) { + _guard = guard; + _missionIndex = missionIndex; + + int sequenceSize = ConfigManager.getInstance().getSequenceSize(); + _game = new SequenceGame(sequenceSize); + _currentSequenceIndex = 0; + _reachedSequenceIndex = 0; + _isClickingEnabled = false; + + _guard.openMenu(this); + + _guard.updateInventory(); + } + + @Override + public Inventory toInventory(MessageLanguageManager messages) { + String title = messages.getSequenceTitle(); + int lines = 5; + Inventory inv = Bukkit.createInventory(null, lines * 9, title); + + buildBaseInventory(inv, lines); + + runShowFullSequeceAnimation(inv); + + return inv; + } + + private void buildBaseInventory(Inventory inv, int lines) { + ItemStack item = createNamelessItem(Material.BLACK_STAINED_GLASS_PANE); + for (int i = 0; i < lines * 9; i++) { + inv.setItem(i, item); + } + + item = createNamelessItem(BUTTON_MATERIAL); + for (int i = 0; i < BUTTONS_SLOTS.length; i++) { + inv.setItem(BUTTONS_SLOTS[i], item); + } + } + + private ItemStack createNamelessItem(Material material) { + ItemStack item = new ItemStack(material); + ItemMeta meta = item.getItemMeta(); + meta.setDisplayName(" "); + item.setItemMeta(meta); + + return item; + } + + @Override + public ClickReturnAction click(PEPlayer player, int slot, boolean isPlayerInv, ClickType type) { + if (!_isClickingEnabled || isPlayerInv) { + return ClickReturnAction.NOTHING; + } + + int value = getValue(slot); + if (value == -1) { + return ClickReturnAction.NOTHING; + } + + if (_game.match(_currentSequenceIndex, value)) { + if (_currentSequenceIndex == _game.getSequenceSize() - 1) { + player.closeMenu(true); + complete(_guard, _missionIndex); + return ClickReturnAction.NOTHING; + } + + _animation = (inv) -> executeSuccessClick(inv); + } else { + _animation = (inv) -> executeFailedClick(inv); + } + + player.updateView(); + return ClickReturnAction.NOTHING; + } + + public void updateInventory(Inventory inv, PEPlayer player) { + _animation.animate(inv); + } + + private void executeSuccessClick(Inventory inv) { + if (_currentSequenceIndex == _reachedSequenceIndex) { + runSuccessAnimation(inv, _currentSequenceIndex, true); + _reachedSequenceIndex++; + _currentSequenceIndex = 0; + return; + } + + runSuccessAnimation(inv, _currentSequenceIndex, false); + _currentSequenceIndex++; + } + + private void executeFailedClick(Inventory inv) { + runFailAnimation(inv); + _currentSequenceIndex = 0; + _reachedSequenceIndex = 0; + } + + private int getValue(int slot) { + for (int i = 0; i < BUTTONS_SLOTS.length; i++) { + if (slot == BUTTONS_SLOTS[i]) { + return i; + } + } + + return -1; + } + + private void runShowFullSequeceAnimation(Inventory inv) { + Bukkit.getScheduler().runTaskLater(PrisonEscape.getPrisonEscape(), new Runnable() { + + @Override + public void run() { + _isClickingEnabled = false; + runShowSequenceAnimationAux(inv, 0, _reachedSequenceIndex); + } + + }, ANIMATION_TICKS / 2); + } + + private void runShowSequenceAnimationAux(Inventory inv, int currentIndex, int reachedIndex) { + int slot = BUTTONS_SLOTS[_game.getValue(currentIndex)]; + inv.setItem(slot, createNamelessItem(HIGHLIGHT_MATERIAL)); + + Bukkit.getScheduler().runTaskLater(PrisonEscape.getPrisonEscape(), new Runnable() { + + @Override + public void run() { + clearHighlight(inv, slot); + + if (currentIndex == reachedIndex) { + _isClickingEnabled = true; + return; + } + + Bukkit.getScheduler().runTaskLater(PrisonEscape.getPrisonEscape(), new Runnable() { + + @Override + public void run() { + runShowSequenceAnimationAux(inv, currentIndex + 1, reachedIndex); + } + + }, ANIMATION_TICKS / 2); + } + + }, ANIMATION_TICKS); + } + + private void runSuccessAnimation(Inventory inv, int index, boolean showFullSequenceAfter) { + _isClickingEnabled = false; + int slot = BUTTONS_SLOTS[_game.getValue(index)]; + inv.setItem(slot, createNamelessItem(HIGHLIGHT_MATERIAL)); + + Bukkit.getScheduler().runTaskLater(PrisonEscape.getPrisonEscape(), new Runnable() { + + @Override + public void run() { + clearHighlight(inv, slot); + + if (showFullSequenceAfter) { + runShowFullSequeceAnimation(inv); + } else { + _isClickingEnabled = true; + } + } + + }, ANIMATION_TICKS); + } + + private void runFailAnimation(Inventory inv) { + _isClickingEnabled = false; + ItemStack item = createNamelessItem(FAIL_MATERIAL); + int[] slots = new int[BUTTONS_SLOTS.length]; + for (int i = 0; i < BUTTONS_SLOTS.length; i++) { + int slot = BUTTONS_SLOTS[i]; + inv.setItem(slot, item); + slots[i] = slot; + } + + Bukkit.getScheduler().runTaskLater(PrisonEscape.getPrisonEscape(), new Runnable() { + + @Override + public void run() { + _isClickingEnabled = true; + clearHighlight(inv, slots); + + runShowFullSequeceAnimation(inv); + } + + }, ANIMATION_TICKS); + } + + private void clearHighlight(Inventory inv, int... slotsToClear) { + for (int i : slotsToClear) { + inv.setItem(i, createNamelessItem(BUTTON_MATERIAL)); + } + } + + private class SequenceGame { + + private int[] _order; + + private SequenceGame(int sequenceSize) { + List elements = new ArrayList<>(); + for (int i = 0; i < BUTTONS_SLOTS.length; i++) { + elements.add(i); + } + + _order = new int[sequenceSize]; + + Random random = new Random(); + for (int i = 0; i < sequenceSize; i++) { + int randomElement = random.nextInt(elements.size()); + _order[i] = elements.get(randomElement); + + elements.remove(randomElement); + } + } + + private int getSequenceSize() { + return _order.length; + } + + private int getValue(int index) { + return _order[index]; + } + + private boolean match(int index, int value) { + return _order[index] == value; + } + + } + + private interface AnimationFunction { + + void animate(Inventory inv); + + } + +} diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index 3308fe2..8a8f749 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -41,6 +41,7 @@ TradeRequestTimeout: 15 MissionsPerDay: 3 MissionMoneyReward: 10 DifferencesAmount: 3 +SequenceSize: 5 AvailableLanguages: - "english" DefaultLanguage: "english" diff --git a/src/main/resources/languages/english.yml b/src/main/resources/languages/english.yml index 88c2c41..265bb77 100644 --- a/src/main/resources/languages/english.yml +++ b/src/main/resources/languages/english.yml @@ -200,6 +200,8 @@ Inventory: Title: "Spot the differences {CURRENT}/{TOTAL}" Sort: Title: "Sort the flowers. Correct: {CORRECT}" + Sequence: + Title: "Remember the sequence" Messages: GeneralMessage: "&8[GENERAL] <{PLAYER}> &f{MESSAGE}" PoliceTeamMessage: "&9[TEAM] <{PLAYER}> &f{MESSAGE}"