2019-02-19 18:58:06 +01:00
|
|
|
package world.bentobox.challenges.tasks;
|
2018-12-30 14:31:26 +01:00
|
|
|
|
|
|
|
|
2019-05-06 11:10:02 +02:00
|
|
|
|
2021-08-14 18:25:04 +02:00
|
|
|
import com.google.common.collect.UnmodifiableIterator;
|
2021-09-24 15:03:02 +02:00
|
|
|
import java.time.*;
|
2019-10-10 07:35:25 +02:00
|
|
|
import java.util.Arrays;
|
|
|
|
import java.util.Collections;
|
|
|
|
import java.util.EnumMap;
|
|
|
|
import java.util.HashMap;
|
|
|
|
import java.util.List;
|
|
|
|
import java.util.Map;
|
|
|
|
import java.util.Objects;
|
|
|
|
import java.util.PriorityQueue;
|
|
|
|
import java.util.Queue;
|
2021-08-14 18:25:04 +02:00
|
|
|
import java.util.UUID;
|
2019-10-10 07:35:25 +02:00
|
|
|
import java.util.stream.Collectors;
|
|
|
|
|
2019-10-30 07:44:26 +01:00
|
|
|
import org.bukkit.Bukkit;
|
2019-10-10 07:35:25 +02:00
|
|
|
import org.bukkit.ChatColor;
|
|
|
|
import org.bukkit.GameMode;
|
|
|
|
import org.bukkit.Material;
|
|
|
|
import org.bukkit.World;
|
2019-01-24 22:29:56 +01:00
|
|
|
import org.bukkit.block.Block;
|
2019-04-23 18:54:39 +02:00
|
|
|
import org.bukkit.block.BlockFace;
|
2019-05-06 11:10:02 +02:00
|
|
|
import org.bukkit.entity.Entity;
|
2018-12-30 14:31:26 +01:00
|
|
|
import org.bukkit.entity.EntityType;
|
|
|
|
import org.bukkit.entity.Player;
|
|
|
|
import org.bukkit.inventory.ItemStack;
|
2019-04-23 18:54:39 +02:00
|
|
|
import org.bukkit.util.BoundingBox;
|
2018-12-30 14:31:26 +01:00
|
|
|
|
2019-01-24 22:29:56 +01:00
|
|
|
import world.bentobox.bentobox.api.localization.TextVariables;
|
|
|
|
import world.bentobox.bentobox.api.user.User;
|
2019-04-23 18:54:39 +02:00
|
|
|
import world.bentobox.bentobox.database.objects.Island;
|
2019-01-24 22:29:56 +01:00
|
|
|
import world.bentobox.bentobox.util.Util;
|
2018-12-30 14:31:26 +01:00
|
|
|
import world.bentobox.challenges.ChallengesAddon;
|
2021-08-14 20:43:42 +02:00
|
|
|
import world.bentobox.challenges.managers.ChallengesManager;
|
2019-01-23 15:09:38 +01:00
|
|
|
import world.bentobox.challenges.database.object.Challenge;
|
|
|
|
import world.bentobox.challenges.database.object.Challenge.ChallengeType;
|
2019-01-24 23:54:21 +01:00
|
|
|
import world.bentobox.challenges.database.object.ChallengeLevel;
|
2019-09-08 19:03:46 +02:00
|
|
|
import world.bentobox.challenges.database.object.requirements.InventoryRequirements;
|
|
|
|
import world.bentobox.challenges.database.object.requirements.IslandRequirements;
|
|
|
|
import world.bentobox.challenges.database.object.requirements.OtherRequirements;
|
2021-08-14 18:25:04 +02:00
|
|
|
import world.bentobox.challenges.database.object.requirements.StatisticRequirements;
|
2021-09-19 20:04:09 +02:00
|
|
|
import world.bentobox.challenges.utils.Constants;
|
2019-06-16 14:57:05 +02:00
|
|
|
import world.bentobox.challenges.utils.Utils;
|
2019-01-24 22:29:56 +01:00
|
|
|
|
2018-12-30 14:31:26 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Run when a user tries to complete a challenge
|
|
|
|
* @author tastybento
|
|
|
|
*
|
|
|
|
*/
|
2019-01-24 22:29:56 +01:00
|
|
|
public class TryToComplete
|
|
|
|
{
|
2019-11-03 23:12:09 +01:00
|
|
|
// ---------------------------------------------------------------------
|
|
|
|
// Section: Variables
|
|
|
|
// ---------------------------------------------------------------------
|
2018-12-30 14:31:26 +01:00
|
|
|
|
2019-01-24 22:29:56 +01:00
|
|
|
/**
|
|
|
|
* Challenges addon variable.
|
|
|
|
*/
|
2021-12-01 10:30:02 +01:00
|
|
|
private final ChallengesAddon addon;
|
2019-01-24 22:29:56 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Challenges manager for addon.
|
|
|
|
*/
|
|
|
|
private ChallengesManager manager;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* World where all checks are necessary.
|
|
|
|
*/
|
2018-12-30 14:31:26 +01:00
|
|
|
private World world;
|
2019-01-24 22:29:56 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
* User who is completing challenge.
|
|
|
|
*/
|
2018-12-30 14:31:26 +01:00
|
|
|
private User user;
|
2019-01-24 22:29:56 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Permission prefix string.
|
|
|
|
*/
|
|
|
|
private String permissionPrefix;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Challenge that should be completed.
|
|
|
|
*/
|
2019-01-23 15:09:38 +01:00
|
|
|
private Challenge challenge;
|
2018-12-30 14:31:26 +01:00
|
|
|
|
2019-01-24 23:28:12 +01:00
|
|
|
/**
|
|
|
|
* Variable that will be used to avoid multiple empty object generation.
|
|
|
|
*/
|
|
|
|
private final ChallengeResult EMPTY_RESULT = new ChallengeResult();
|
2019-01-24 22:29:56 +01:00
|
|
|
|
2019-11-03 23:12:09 +01:00
|
|
|
// ---------------------------------------------------------------------
|
|
|
|
// Section: Builder
|
|
|
|
// ---------------------------------------------------------------------
|
2019-01-24 22:29:56 +01:00
|
|
|
|
|
|
|
|
|
|
|
@Deprecated
|
|
|
|
public TryToComplete user(User user)
|
|
|
|
{
|
2018-12-30 14:31:26 +01:00
|
|
|
this.user = user;
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
2019-01-24 22:29:56 +01:00
|
|
|
|
|
|
|
@Deprecated
|
|
|
|
public TryToComplete(ChallengesAddon addon)
|
|
|
|
{
|
2018-12-30 14:31:26 +01:00
|
|
|
this.addon = addon;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2019-11-03 23:12:09 +01:00
|
|
|
// ---------------------------------------------------------------------
|
|
|
|
// Section: Constructor
|
|
|
|
// ---------------------------------------------------------------------
|
2018-12-30 14:31:26 +01:00
|
|
|
|
|
|
|
|
|
|
|
/**
|
2019-01-24 22:29:56 +01:00
|
|
|
* @param addon - Challenges Addon.
|
|
|
|
* @param user - User who performs challenge.
|
|
|
|
* @param challenge - Challenge that should be completed.
|
|
|
|
* @param world - World where completion may occur.
|
|
|
|
* @param topLabel - Label of the top command.
|
|
|
|
* @param permissionPrefix - Permission prefix for GameMode addon.
|
2018-12-30 14:31:26 +01:00
|
|
|
*/
|
2019-01-24 22:29:56 +01:00
|
|
|
public TryToComplete(ChallengesAddon addon,
|
2019-11-03 23:12:09 +01:00
|
|
|
User user,
|
|
|
|
Challenge challenge,
|
|
|
|
World world,
|
|
|
|
String topLabel,
|
|
|
|
String permissionPrefix)
|
2019-01-24 22:29:56 +01:00
|
|
|
{
|
2018-12-30 14:31:26 +01:00
|
|
|
this.addon = addon;
|
|
|
|
this.world = world;
|
2019-01-24 22:29:56 +01:00
|
|
|
this.permissionPrefix = permissionPrefix;
|
2018-12-30 14:31:26 +01:00
|
|
|
this.user = user;
|
2019-01-24 22:29:56 +01:00
|
|
|
this.manager = addon.getChallengesManager();
|
2019-10-30 07:44:26 +01:00
|
|
|
// To avoid any modifications that may occur to challenges in current completion
|
2019-05-16 09:30:01 +02:00
|
|
|
// just clone it.
|
|
|
|
this.challenge = challenge.clone();
|
2019-01-28 20:01:26 +01:00
|
|
|
}
|
|
|
|
|
2018-12-30 14:31:26 +01:00
|
|
|
|
2019-01-28 20:01:26 +01:00
|
|
|
/**
|
|
|
|
* This static method allows complete challenge and get result about completion.
|
|
|
|
* @param addon - Challenges Addon.
|
|
|
|
* @param user - User who performs challenge.
|
|
|
|
* @param challenge - Challenge that should be completed.
|
|
|
|
* @param world - World where completion may occur.
|
|
|
|
* @param topLabel - Label of the top command.
|
|
|
|
* @param permissionPrefix - Permission prefix for GameMode addon.
|
|
|
|
* @return true, if challenge is completed, otherwise false.
|
|
|
|
*/
|
|
|
|
public static boolean complete(ChallengesAddon addon,
|
2019-11-03 23:12:09 +01:00
|
|
|
User user,
|
|
|
|
Challenge challenge,
|
|
|
|
World world,
|
|
|
|
String topLabel,
|
|
|
|
String permissionPrefix)
|
2019-05-06 11:10:02 +02:00
|
|
|
{
|
|
|
|
return TryToComplete.complete(addon, user, challenge, world, topLabel, permissionPrefix, 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* This static method allows complete challenge and get result about completion.
|
|
|
|
* @param addon - Challenges Addon.
|
|
|
|
* @param user - User who performs challenge.
|
|
|
|
* @param challenge - Challenge that should be completed.
|
|
|
|
* @param world - World where completion may occur.
|
|
|
|
* @param topLabel - Label of the top command.
|
|
|
|
* @param permissionPrefix - Permission prefix for GameMode addon.
|
|
|
|
* @param maxTimes - Integer that represents how many times user wants to complete challenges.
|
|
|
|
* @return true, if challenge is completed, otherwise false.
|
|
|
|
*/
|
|
|
|
public static boolean complete(ChallengesAddon addon,
|
2019-11-03 23:12:09 +01:00
|
|
|
User user,
|
|
|
|
Challenge challenge,
|
|
|
|
World world,
|
|
|
|
String topLabel,
|
|
|
|
String permissionPrefix,
|
|
|
|
int maxTimes)
|
2019-01-28 20:01:26 +01:00
|
|
|
{
|
|
|
|
return new TryToComplete(addon, user, challenge, world, topLabel, permissionPrefix).
|
2021-09-24 15:03:02 +02:00
|
|
|
build(maxTimes).
|
|
|
|
meetsRequirements;
|
2019-01-24 22:29:56 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2019-11-03 23:12:09 +01:00
|
|
|
// ---------------------------------------------------------------------
|
|
|
|
// Section: Methods
|
|
|
|
// ---------------------------------------------------------------------
|
2019-01-24 22:29:56 +01:00
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* This method checks if challenge can be done, and complete it, if it is possible.
|
|
|
|
* @return ChallengeResult object, that contains completion status.
|
|
|
|
*/
|
2019-10-30 07:44:26 +01:00
|
|
|
ChallengeResult build(int maxTimes)
|
2019-01-24 22:29:56 +01:00
|
|
|
{
|
2018-12-30 14:31:26 +01:00
|
|
|
// Check if can complete challenge
|
2019-05-06 11:10:02 +02:00
|
|
|
ChallengeResult result = this.checkIfCanCompleteChallenge(maxTimes);
|
2019-01-24 22:29:56 +01:00
|
|
|
|
2019-05-06 11:10:02 +02:00
|
|
|
if (!result.isMeetsRequirements())
|
2019-01-24 22:29:56 +01:00
|
|
|
{
|
|
|
|
return result;
|
2018-12-30 14:31:26 +01:00
|
|
|
}
|
2019-01-24 22:29:56 +01:00
|
|
|
|
2021-12-01 10:30:02 +01:00
|
|
|
if (this.user.getLocation() == null || this.user.getInventory() == null)
|
|
|
|
{
|
|
|
|
// This is just a cleaning check. There is no situations where location or inventory
|
|
|
|
// could be null at this point of code.
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2019-05-06 11:10:02 +02:00
|
|
|
this.fullFillRequirements(result);
|
|
|
|
|
|
|
|
// Validation to avoid rewarding if something goes wrong in removing requirements.
|
|
|
|
|
|
|
|
if (!result.isMeetsRequirements())
|
|
|
|
{
|
|
|
|
if (result.removedItems != null)
|
|
|
|
{
|
|
|
|
result.removedItems.forEach((item, amount) ->
|
|
|
|
{
|
|
|
|
ItemStack returnItem = item.clone();
|
|
|
|
returnItem.setAmount(amount);
|
|
|
|
|
|
|
|
this.user.getInventory().addItem(returnItem).forEach((k, v) ->
|
2019-11-03 23:12:09 +01:00
|
|
|
this.user.getWorld().dropItem(this.user.getLocation(), v));
|
2019-05-06 11:10:02 +02:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
// Entities and blocks will not be restored.
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
// If challenge was not completed then reward items for completing it first time.
|
|
|
|
if (!result.wasCompleted())
|
2019-01-24 22:29:56 +01:00
|
|
|
{
|
|
|
|
// Item rewards
|
|
|
|
for (ItemStack reward : this.challenge.getRewardItems())
|
|
|
|
{
|
2019-02-14 13:20:08 +01:00
|
|
|
// Clone is necessary because otherwise it will chane reward itemstack
|
|
|
|
// amount.
|
|
|
|
this.user.getInventory().addItem(reward.clone()).forEach((k, v) ->
|
2019-11-03 23:12:09 +01:00
|
|
|
this.user.getWorld().dropItem(this.user.getLocation(), v));
|
2018-12-30 14:31:26 +01:00
|
|
|
}
|
|
|
|
|
2019-01-24 22:29:56 +01:00
|
|
|
// Money Reward
|
|
|
|
if (this.addon.isEconomyProvided())
|
|
|
|
{
|
|
|
|
this.addon.getEconomyProvider().deposit(this.user, this.challenge.getRewardMoney());
|
|
|
|
}
|
|
|
|
|
|
|
|
// Experience Reward
|
|
|
|
this.user.getPlayer().giveExp(this.challenge.getRewardExperience());
|
2018-12-30 14:31:26 +01:00
|
|
|
|
|
|
|
// Run commands
|
2019-01-24 22:29:56 +01:00
|
|
|
this.runCommands(this.challenge.getRewardCommands());
|
|
|
|
|
2019-05-06 11:10:02 +02:00
|
|
|
// Send message about first completion only if it is completed only once.
|
|
|
|
if (result.getFactor() == 1)
|
|
|
|
{
|
2021-09-19 14:36:52 +02:00
|
|
|
Utils.sendMessage(this.user, this.user.getTranslation("challenges.messages.you-completed-challenge",
|
|
|
|
"[value]", this.challenge.getFriendlyName()));
|
2019-05-06 11:10:02 +02:00
|
|
|
}
|
2019-01-24 22:29:56 +01:00
|
|
|
|
|
|
|
if (this.addon.getChallengesSettings().isBroadcastMessages())
|
|
|
|
{
|
2021-09-19 14:36:52 +02:00
|
|
|
Bukkit.getOnlinePlayers().stream().
|
|
|
|
map(User::getInstance).
|
2021-12-01 10:30:02 +01:00
|
|
|
forEach(user -> Utils.sendMessage(user, user.getTranslation(
|
|
|
|
"challenges.messages.name-has-completed-challenge",
|
|
|
|
Constants.PARAMETER_NAME, this.user.getName(),
|
|
|
|
"[value]", this.challenge.getFriendlyName())));
|
2018-12-30 14:31:26 +01:00
|
|
|
}
|
2019-05-01 21:57:24 +02:00
|
|
|
|
|
|
|
// sends title to player on challenge completion
|
|
|
|
if (this.addon.getChallengesSettings().isShowCompletionTitle())
|
|
|
|
{
|
|
|
|
this.user.getPlayer().sendTitle(
|
2021-12-01 10:30:02 +01:00
|
|
|
this.parseChallenge(this.user.getTranslation("challenges.titles.challenge-title"), this.challenge),
|
|
|
|
this.parseChallenge(this.user.getTranslation("challenges.titles.challenge-subtitle"), this.challenge),
|
|
|
|
10,
|
|
|
|
this.addon.getChallengesSettings().getTitleShowtime(),
|
|
|
|
20);
|
2019-05-01 21:57:24 +02:00
|
|
|
}
|
2019-01-24 22:29:56 +01:00
|
|
|
}
|
2019-05-06 11:10:02 +02:00
|
|
|
|
|
|
|
if (result.wasCompleted() || result.getFactor() > 1)
|
2019-01-24 22:29:56 +01:00
|
|
|
{
|
2019-05-06 11:10:02 +02:00
|
|
|
int rewardFactor = result.getFactor() - (result.wasCompleted() ? 0 : 1);
|
|
|
|
|
2019-01-24 22:29:56 +01:00
|
|
|
// Item Repeat Rewards
|
|
|
|
for (ItemStack reward : this.challenge.getRepeatItemReward())
|
|
|
|
{
|
2019-02-14 13:20:08 +01:00
|
|
|
// Clone is necessary because otherwise it will chane reward itemstack
|
|
|
|
// amount.
|
2019-05-06 11:10:02 +02:00
|
|
|
|
|
|
|
for (int i = 0; i < rewardFactor; i++)
|
|
|
|
{
|
|
|
|
this.user.getInventory().addItem(reward.clone()).forEach((k, v) ->
|
2019-11-03 23:12:09 +01:00
|
|
|
this.user.getWorld().dropItem(this.user.getLocation(), v));
|
2019-05-06 11:10:02 +02:00
|
|
|
}
|
2018-12-30 14:31:26 +01:00
|
|
|
}
|
|
|
|
|
2019-01-24 22:29:56 +01:00
|
|
|
// Money Repeat Reward
|
|
|
|
if (this.addon.isEconomyProvided())
|
|
|
|
{
|
2019-05-06 11:10:02 +02:00
|
|
|
this.addon.getEconomyProvider().deposit(this.user,
|
2021-12-01 10:30:02 +01:00
|
|
|
this.challenge.getRepeatMoneyReward() * rewardFactor);
|
2019-01-24 22:29:56 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// Experience Repeat Reward
|
2019-05-06 11:10:02 +02:00
|
|
|
this.user.getPlayer().giveExp(
|
2019-11-03 23:12:09 +01:00
|
|
|
this.challenge.getRepeatExperienceReward() * rewardFactor);
|
2018-12-30 14:31:26 +01:00
|
|
|
|
|
|
|
// Run commands
|
2019-05-06 11:10:02 +02:00
|
|
|
for (int i = 0; i < rewardFactor; i++)
|
|
|
|
{
|
|
|
|
this.runCommands(this.challenge.getRepeatRewardCommands());
|
|
|
|
}
|
2019-01-24 22:29:56 +01:00
|
|
|
|
2019-05-06 11:10:02 +02:00
|
|
|
if (result.getFactor() > 1)
|
|
|
|
{
|
2021-09-19 14:36:52 +02:00
|
|
|
Utils.sendMessage(this.user, this.user.getTranslation("challenges.messages.you-repeated-challenge-multiple",
|
|
|
|
"[value]", this.challenge.getFriendlyName(),
|
|
|
|
"[count]", Integer.toString(result.getFactor())));
|
2019-05-06 11:10:02 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2021-09-19 14:36:52 +02:00
|
|
|
Utils.sendMessage(this.user, this.user.getTranslation("challenges.messages.you-repeated-challenge",
|
|
|
|
"[value]", this.challenge.getFriendlyName()));
|
2019-05-06 11:10:02 +02:00
|
|
|
}
|
2018-12-30 14:31:26 +01:00
|
|
|
}
|
2019-01-24 22:29:56 +01:00
|
|
|
|
2018-12-30 14:31:26 +01:00
|
|
|
// Mark as complete
|
2019-05-06 11:10:02 +02:00
|
|
|
this.manager.setChallengeComplete(this.user, this.world, this.challenge, result.getFactor());
|
2019-01-24 22:29:56 +01:00
|
|
|
|
2019-05-09 10:22:01 +02:00
|
|
|
// Check level completion for non-free challenges
|
|
|
|
if (!result.wasCompleted() &&
|
2019-11-03 23:12:09 +01:00
|
|
|
!this.challenge.getLevel().equals(ChallengesManager.FREE))
|
2019-01-24 23:54:21 +01:00
|
|
|
{
|
|
|
|
ChallengeLevel level = this.manager.getLevel(this.challenge);
|
|
|
|
|
2019-05-09 10:22:01 +02:00
|
|
|
if (level != null && !this.manager.isLevelCompleted(this.user, this.world, level))
|
2019-01-24 23:54:21 +01:00
|
|
|
{
|
2019-02-18 00:29:42 +01:00
|
|
|
if (this.manager.validateLevelCompletion(this.user, this.world, level))
|
2019-01-24 23:54:21 +01:00
|
|
|
{
|
|
|
|
// Item rewards
|
|
|
|
for (ItemStack reward : level.getRewardItems())
|
|
|
|
{
|
2019-02-14 13:20:08 +01:00
|
|
|
// Clone is necessary because otherwise it will chane reward itemstack
|
|
|
|
// amount.
|
|
|
|
this.user.getInventory().addItem(reward.clone()).forEach((k, v) ->
|
2019-11-03 23:12:09 +01:00
|
|
|
this.user.getWorld().dropItem(this.user.getLocation(), v));
|
2019-01-24 23:54:21 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// Money Reward
|
|
|
|
if (this.addon.isEconomyProvided())
|
|
|
|
{
|
|
|
|
this.addon.getEconomyProvider().deposit(this.user, level.getRewardMoney());
|
|
|
|
}
|
|
|
|
|
|
|
|
// Experience Reward
|
|
|
|
this.user.getPlayer().giveExp(level.getRewardExperience());
|
|
|
|
|
|
|
|
// Run commands
|
|
|
|
this.runCommands(level.getRewardCommands());
|
|
|
|
|
2021-09-19 14:36:52 +02:00
|
|
|
Utils.sendMessage(this.user, this.user.getTranslation("challenges.messages.you-completed-level",
|
|
|
|
"[value]", level.getFriendlyName()));
|
2019-01-24 23:54:21 +01:00
|
|
|
|
|
|
|
if (this.addon.getChallengesSettings().isBroadcastMessages())
|
|
|
|
{
|
2021-09-19 14:36:52 +02:00
|
|
|
Bukkit.getOnlinePlayers().stream().
|
|
|
|
map(User::getInstance).
|
2021-12-01 10:30:02 +01:00
|
|
|
forEach(user -> Utils.sendMessage(user, user.getTranslation(
|
|
|
|
"challenges.messages.name-has-completed-level",
|
|
|
|
Constants.PARAMETER_NAME, this.user.getName(),
|
|
|
|
"[value]", level.getFriendlyName())));
|
2019-01-24 23:54:21 +01:00
|
|
|
}
|
|
|
|
|
2019-02-18 00:29:42 +01:00
|
|
|
this.manager.setLevelComplete(this.user, this.world, level);
|
2019-05-01 21:57:24 +02:00
|
|
|
|
|
|
|
// sends title to player on level completion
|
|
|
|
if (this.addon.getChallengesSettings().isShowCompletionTitle())
|
|
|
|
{
|
|
|
|
this.user.getPlayer().sendTitle(
|
2021-09-19 14:36:52 +02:00
|
|
|
this.parseLevel(this.user.getTranslation("challenges.titles.level-title"), level),
|
|
|
|
this.parseLevel(this.user.getTranslation("challenges.titles.level-subtitle"), level),
|
|
|
|
10,
|
|
|
|
this.addon.getChallengesSettings().getTitleShowtime(),
|
|
|
|
20);
|
2019-05-01 21:57:24 +02:00
|
|
|
}
|
2019-01-24 23:54:21 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-01-24 22:29:56 +01:00
|
|
|
return result;
|
2018-12-30 14:31:26 +01:00
|
|
|
}
|
|
|
|
|
2019-01-24 22:29:56 +01:00
|
|
|
|
2019-05-06 11:10:02 +02:00
|
|
|
/**
|
2021-12-01 10:30:02 +01:00
|
|
|
* This method fulfills all challenge type requirements, that is not fulfilled yet.
|
2019-05-06 11:10:02 +02:00
|
|
|
* @param result Challenge Results
|
|
|
|
*/
|
|
|
|
private void fullFillRequirements(ChallengeResult result)
|
|
|
|
{
|
2021-08-14 18:25:04 +02:00
|
|
|
switch (this.challenge.getChallengeType())
|
2019-05-06 11:10:02 +02:00
|
|
|
{
|
2021-09-18 12:01:35 +02:00
|
|
|
case ISLAND_TYPE -> {
|
2021-08-14 18:25:04 +02:00
|
|
|
IslandRequirements requirements = this.challenge.getRequirements();
|
2019-09-08 19:03:46 +02:00
|
|
|
|
2021-08-14 18:25:04 +02:00
|
|
|
if (result.meetsRequirements &&
|
2019-11-03 23:12:09 +01:00
|
|
|
requirements.isRemoveEntities() &&
|
|
|
|
!requirements.getRequiredEntities().isEmpty())
|
2021-08-14 18:25:04 +02:00
|
|
|
{
|
|
|
|
this.removeEntities(result.entities, result.getFactor());
|
|
|
|
}
|
2019-05-06 11:10:02 +02:00
|
|
|
|
2021-08-14 18:25:04 +02:00
|
|
|
if (result.meetsRequirements &&
|
2019-11-03 23:12:09 +01:00
|
|
|
requirements.isRemoveBlocks() &&
|
|
|
|
!requirements.getRequiredBlocks().isEmpty())
|
2021-08-14 18:25:04 +02:00
|
|
|
{
|
|
|
|
this.removeBlocks(result.blocks, result.getFactor());
|
|
|
|
}
|
2019-05-06 11:10:02 +02:00
|
|
|
}
|
2021-09-18 12:01:35 +02:00
|
|
|
case INVENTORY_TYPE -> {
|
2021-08-14 18:25:04 +02:00
|
|
|
// If remove items, then remove them
|
|
|
|
if (this.getInventoryRequirements().isTakeItems())
|
|
|
|
{
|
|
|
|
int sumEverything = result.requiredItems.stream().
|
2019-11-03 23:12:09 +01:00
|
|
|
mapToInt(itemStack -> itemStack.getAmount() * result.getFactor()).
|
|
|
|
sum();
|
2019-05-06 11:10:02 +02:00
|
|
|
|
2021-08-14 18:25:04 +02:00
|
|
|
Map<ItemStack, Integer> removedItems =
|
2019-11-03 23:12:09 +01:00
|
|
|
this.removeItems(result.requiredItems, result.getFactor());
|
2019-05-06 11:10:02 +02:00
|
|
|
|
2021-08-14 18:25:04 +02:00
|
|
|
int removedAmount = removedItems.values().stream().mapToInt(num -> num).sum();
|
2019-05-06 11:10:02 +02:00
|
|
|
|
2021-08-14 18:25:04 +02:00
|
|
|
// Something is not removed.
|
|
|
|
if (sumEverything != removedAmount)
|
|
|
|
{
|
2021-09-19 14:36:52 +02:00
|
|
|
Utils.sendMessage(this.user,
|
|
|
|
this.user.getTranslation("challenges.errors.cannot-remove-items"));
|
2019-05-06 11:10:02 +02:00
|
|
|
|
2021-08-14 18:25:04 +02:00
|
|
|
result.removedItems = removedItems;
|
|
|
|
result.meetsRequirements = false;
|
|
|
|
}
|
2019-05-06 11:10:02 +02:00
|
|
|
}
|
|
|
|
}
|
2021-09-18 12:01:35 +02:00
|
|
|
case OTHER_TYPE -> {
|
2021-08-14 18:25:04 +02:00
|
|
|
OtherRequirements requirements = this.challenge.getRequirements();
|
2019-09-08 19:03:46 +02:00
|
|
|
|
2021-08-14 18:25:04 +02:00
|
|
|
if (this.addon.isEconomyProvided() && requirements.isTakeMoney())
|
|
|
|
{
|
|
|
|
this.addon.getEconomyProvider().withdraw(this.user, requirements.getRequiredMoney());
|
|
|
|
}
|
2019-05-06 11:10:02 +02:00
|
|
|
|
2021-08-14 18:25:04 +02:00
|
|
|
if (requirements.isTakeExperience() &&
|
2019-11-03 23:12:09 +01:00
|
|
|
this.user.getPlayer().getGameMode() != GameMode.CREATIVE)
|
2021-08-14 18:25:04 +02:00
|
|
|
{
|
|
|
|
// Cannot take anything from creative game mode.
|
|
|
|
this.user.getPlayer().setTotalExperience(
|
2019-11-03 23:12:09 +01:00
|
|
|
this.user.getPlayer().getTotalExperience() - requirements.getRequiredExperience());
|
2021-08-14 18:25:04 +02:00
|
|
|
}
|
|
|
|
}
|
2021-09-18 12:01:35 +02:00
|
|
|
case STATISTIC_TYPE -> {
|
2021-08-14 18:25:04 +02:00
|
|
|
StatisticRequirements requirements = this.challenge.getRequirements();
|
|
|
|
|
2021-12-01 10:30:02 +01:00
|
|
|
if (requirements.isReduceStatistic() && requirements.getStatistic() != null)
|
2021-08-14 18:25:04 +02:00
|
|
|
{
|
|
|
|
int removeAmount = result.getFactor() * requirements.getAmount();
|
|
|
|
|
|
|
|
// Start to remove from player who called the completion.
|
|
|
|
switch (requirements.getStatistic().getType())
|
|
|
|
{
|
|
|
|
case UNTYPED -> {
|
|
|
|
int statistic = this.user.getPlayer().getStatistic(requirements.getStatistic());
|
|
|
|
|
|
|
|
if (removeAmount >= statistic)
|
|
|
|
{
|
|
|
|
this.user.getPlayer().setStatistic(requirements.getStatistic(), 0);
|
|
|
|
removeAmount -= statistic;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
this.user.getPlayer().setStatistic(requirements.getStatistic(), statistic - removeAmount);
|
|
|
|
removeAmount = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
case ITEM, BLOCK -> {
|
|
|
|
int statistic = this.user.getPlayer().getStatistic(requirements.getStatistic());
|
|
|
|
|
2021-12-01 10:30:02 +01:00
|
|
|
if (requirements.getMaterial() == null)
|
|
|
|
{
|
|
|
|
// Just a sanity check. Material cannot be null at this point of code.
|
|
|
|
removeAmount = 0;
|
|
|
|
}
|
|
|
|
else if (removeAmount >= statistic)
|
2021-08-14 18:25:04 +02:00
|
|
|
{
|
|
|
|
this.user.getPlayer().setStatistic(requirements.getStatistic(), requirements.getMaterial(), 0);
|
|
|
|
removeAmount -= statistic;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
this.user.getPlayer().setStatistic(requirements.getStatistic(),
|
|
|
|
requirements.getMaterial(),
|
|
|
|
statistic - removeAmount);
|
|
|
|
removeAmount = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
case ENTITY -> {
|
|
|
|
int statistic = this.user.getPlayer().getStatistic(requirements.getStatistic());
|
|
|
|
|
2021-12-01 10:30:02 +01:00
|
|
|
if (requirements.getEntity() == null)
|
|
|
|
{
|
|
|
|
// Just a sanity check. Entity cannot be null at this point of code.
|
|
|
|
removeAmount = 0;
|
|
|
|
}
|
|
|
|
else if (removeAmount >= statistic)
|
2021-08-14 18:25:04 +02:00
|
|
|
{
|
|
|
|
this.user.getPlayer().setStatistic(requirements.getStatistic(), requirements.getEntity(), 0);
|
|
|
|
removeAmount -= statistic;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
this.user.getPlayer().setStatistic(requirements.getStatistic(),
|
|
|
|
requirements.getEntity(),
|
|
|
|
statistic - removeAmount);
|
|
|
|
removeAmount = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// If challenges are in sync with all island members, then punish others too.
|
|
|
|
if (this.addon.getChallengesSettings().isStoreAsIslandData())
|
|
|
|
{
|
|
|
|
Island island = this.addon.getIslands().getIsland(this.world, this.user);
|
|
|
|
|
|
|
|
if (island == null)
|
|
|
|
{
|
|
|
|
// hmm
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (UnmodifiableIterator<UUID> iterator = island.getMemberSet().iterator();
|
|
|
|
iterator.hasNext() && removeAmount > 0; )
|
|
|
|
{
|
|
|
|
Player player = Bukkit.getPlayer(iterator.next());
|
|
|
|
|
|
|
|
if (player == null || player == this.user.getPlayer())
|
|
|
|
{
|
|
|
|
// cannot punish null or player who already was punished.
|
|
|
|
continue;
|
|
|
|
}
|
2022-04-17 00:27:35 +02:00
|
|
|
|
|
|
|
switch (Objects.requireNonNull(requirements.getStatistic()).getType())
|
2021-08-14 18:25:04 +02:00
|
|
|
{
|
|
|
|
case UNTYPED -> {
|
|
|
|
int statistic = player.getStatistic(requirements.getStatistic());
|
|
|
|
|
|
|
|
if (removeAmount >= statistic)
|
|
|
|
{
|
|
|
|
removeAmount -= statistic;
|
|
|
|
player.setStatistic(requirements.getStatistic(), 0);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
player.setStatistic(requirements.getStatistic(), statistic - removeAmount);
|
|
|
|
removeAmount = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
case ITEM, BLOCK -> {
|
|
|
|
int statistic = player.getStatistic(requirements.getStatistic());
|
|
|
|
|
2021-12-01 10:30:02 +01:00
|
|
|
if (requirements.getMaterial() == null)
|
|
|
|
{
|
|
|
|
// Just a sanity check. Entity cannot be null at this point of code.
|
|
|
|
removeAmount = 0;
|
|
|
|
}
|
|
|
|
else if (removeAmount >= statistic)
|
2021-08-14 18:25:04 +02:00
|
|
|
{
|
|
|
|
removeAmount -= statistic;
|
|
|
|
player.setStatistic(requirements.getStatistic(), requirements.getMaterial(), 0);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
player.setStatistic(requirements.getStatistic(),
|
|
|
|
requirements.getMaterial(),
|
|
|
|
statistic - removeAmount);
|
|
|
|
removeAmount = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
case ENTITY -> {
|
|
|
|
int statistic = player.getStatistic(requirements.getStatistic());
|
|
|
|
|
2021-12-01 10:30:02 +01:00
|
|
|
if (requirements.getEntity() == null)
|
|
|
|
{
|
|
|
|
// Just a sanity check. Entity cannot be null at this point of code.
|
|
|
|
removeAmount = 0;
|
|
|
|
}
|
|
|
|
else if (removeAmount >= statistic)
|
2021-08-14 18:25:04 +02:00
|
|
|
{
|
|
|
|
removeAmount -= statistic;
|
|
|
|
player.setStatistic(requirements.getStatistic(), requirements.getEntity(), 0);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
player.setStatistic(requirements.getStatistic(),
|
|
|
|
requirements.getEntity(),
|
|
|
|
statistic - removeAmount);
|
|
|
|
removeAmount = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2019-05-06 11:10:02 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-12-30 14:31:26 +01:00
|
|
|
/**
|
|
|
|
* Checks if a challenge can be completed or not
|
2019-01-24 22:29:56 +01:00
|
|
|
* It returns ChallengeResult.
|
2019-05-06 11:10:02 +02:00
|
|
|
* @param maxTimes - times that user wanted to complete
|
2018-12-30 14:31:26 +01:00
|
|
|
*/
|
2019-05-06 11:10:02 +02:00
|
|
|
private ChallengeResult checkIfCanCompleteChallenge(int maxTimes)
|
2019-01-24 22:29:56 +01:00
|
|
|
{
|
2019-01-24 23:28:12 +01:00
|
|
|
ChallengeResult result;
|
2022-04-17 00:03:11 +02:00
|
|
|
|
2019-01-24 22:29:56 +01:00
|
|
|
ChallengeType type = this.challenge.getChallengeType();
|
2018-12-30 14:31:26 +01:00
|
|
|
// Check the world
|
2019-01-26 12:58:00 +01:00
|
|
|
if (!this.challenge.isDeployed())
|
|
|
|
{
|
2021-09-19 14:36:52 +02:00
|
|
|
Utils.sendMessage(this.user, this.user.getTranslation("challenges.errors.not-deployed"));
|
2019-01-26 12:58:00 +01:00
|
|
|
result = EMPTY_RESULT;
|
|
|
|
}
|
2019-06-16 19:46:12 +02:00
|
|
|
else if (maxTimes < 1)
|
|
|
|
{
|
2021-09-19 14:36:52 +02:00
|
|
|
Utils.sendMessage(this.user, this.user.getTranslation("challenges.errors.not-valid-integer"));
|
2019-06-16 19:46:12 +02:00
|
|
|
result = EMPTY_RESULT;
|
|
|
|
}
|
2019-01-26 12:58:00 +01:00
|
|
|
else if (Util.getWorld(this.world) != Util.getWorld(this.user.getWorld()) ||
|
2021-12-01 10:30:02 +01:00
|
|
|
!this.challenge.matchGameMode(Utils.getGameMode(this.world)))
|
2019-01-24 22:29:56 +01:00
|
|
|
{
|
2021-09-19 14:36:52 +02:00
|
|
|
Utils.sendMessage(this.user, this.user.getTranslation("general.errors.wrong-world"));
|
2019-01-24 23:28:12 +01:00
|
|
|
result = EMPTY_RESULT;
|
2018-12-30 14:31:26 +01:00
|
|
|
}
|
2019-01-26 12:47:56 +01:00
|
|
|
// Player is not on island
|
2021-12-01 10:30:02 +01:00
|
|
|
else if (this.user.getLocation() == null ||
|
|
|
|
ChallengesAddon.CHALLENGES_WORLD_PROTECTION.isSetForWorld(this.world) &&
|
2019-11-03 23:12:09 +01:00
|
|
|
!this.addon.getIslands().locationIsOnIsland(this.user.getPlayer(), this.user.getLocation()))
|
2019-01-26 12:47:56 +01:00
|
|
|
{
|
2021-09-19 14:36:52 +02:00
|
|
|
Utils.sendMessage(this.user, this.user.getTranslation("challenges.errors.not-on-island"));
|
2019-01-26 12:47:56 +01:00
|
|
|
result = EMPTY_RESULT;
|
|
|
|
}
|
2019-02-19 16:53:03 +01:00
|
|
|
// Check player permission
|
|
|
|
else if (!this.addon.getIslands().getIslandAt(this.user.getLocation()).
|
2021-12-01 10:30:02 +01:00
|
|
|
map(i -> i.isAllowed(this.user, ChallengesAddon.CHALLENGES_ISLAND_PROTECTION)).
|
|
|
|
orElse(false))
|
2019-02-19 16:53:03 +01:00
|
|
|
{
|
2021-09-19 14:36:52 +02:00
|
|
|
Utils.sendMessage(this.user, this.user.getTranslation("challenges.errors.no-rank"));
|
2019-02-19 16:53:03 +01:00
|
|
|
result = EMPTY_RESULT;
|
|
|
|
}
|
2019-01-24 22:29:56 +01:00
|
|
|
// Check if user has unlocked challenges level.
|
|
|
|
else if (!this.challenge.getLevel().equals(ChallengesManager.FREE) &&
|
2021-12-01 10:30:02 +01:00
|
|
|
!this.manager.isLevelUnlocked(this.user, this.world, this.manager.getLevel(this.challenge.getLevel())))
|
2019-01-24 22:29:56 +01:00
|
|
|
{
|
2021-09-19 14:36:52 +02:00
|
|
|
Utils.sendMessage(this.user, this.user.getTranslation("challenges.errors.challenge-level-not-available"));
|
2019-01-24 23:28:12 +01:00
|
|
|
result = EMPTY_RESULT;
|
2018-12-30 14:31:26 +01:00
|
|
|
}
|
|
|
|
// Check max times
|
2019-01-24 22:29:56 +01:00
|
|
|
else if (this.challenge.isRepeatable() && this.challenge.getMaxTimes() > 0 &&
|
2021-12-01 10:30:02 +01:00
|
|
|
this.manager.getChallengeTimes(this.user, this.world, this.challenge) >= this.challenge.getMaxTimes())
|
2019-01-24 22:29:56 +01:00
|
|
|
{
|
2021-09-19 14:36:52 +02:00
|
|
|
Utils.sendMessage(this.user, this.user.getTranslation("challenges.errors.not-repeatable"));
|
2019-01-24 23:28:12 +01:00
|
|
|
result = EMPTY_RESULT;
|
2018-12-30 14:31:26 +01:00
|
|
|
}
|
|
|
|
// Check repeatability
|
2019-02-18 00:29:42 +01:00
|
|
|
else if (!this.challenge.isRepeatable() && this.manager.isChallengeComplete(this.user, this.world, this.challenge))
|
2019-01-24 22:29:56 +01:00
|
|
|
{
|
2021-09-19 14:36:52 +02:00
|
|
|
Utils.sendMessage(this.user, this.user.getTranslation("challenges.errors.not-repeatable"));
|
2019-01-24 23:28:12 +01:00
|
|
|
result = EMPTY_RESULT;
|
2018-12-30 14:31:26 +01:00
|
|
|
}
|
2021-09-24 15:03:02 +02:00
|
|
|
// Check if timeout is not broken
|
|
|
|
else if (this.manager.isBreachingTimeOut(this.user, this.world, this.challenge))
|
|
|
|
{
|
|
|
|
long missing = this.manager.getLastCompletionDate(this.user, this.world, challenge) +
|
|
|
|
this.challenge.getTimeout() - System.currentTimeMillis();
|
|
|
|
|
|
|
|
Utils.sendMessage(this.user, this.user.getTranslation("challenges.errors.timeout",
|
|
|
|
"[timeout]", Utils.parseDuration(Duration.ofMillis(this.challenge.getTimeout()), this.user),
|
|
|
|
"[wait-time]", Utils.parseDuration(Duration.ofMillis(missing), this.user)));
|
|
|
|
result = EMPTY_RESULT;
|
|
|
|
}
|
2019-01-24 22:57:50 +01:00
|
|
|
// Check environment
|
|
|
|
else if (!this.challenge.getEnvironment().isEmpty() &&
|
2021-12-01 10:30:02 +01:00
|
|
|
!this.challenge.getEnvironment().contains(this.user.getWorld().getEnvironment()))
|
2019-01-24 22:57:50 +01:00
|
|
|
{
|
2021-09-19 14:36:52 +02:00
|
|
|
Utils.sendMessage(this.user, this.user.getTranslation("challenges.errors.wrong-environment"));
|
2019-01-24 23:28:12 +01:00
|
|
|
result = EMPTY_RESULT;
|
2019-01-24 23:20:33 +01:00
|
|
|
}
|
|
|
|
// Check permission
|
|
|
|
else if (!this.checkPermissions())
|
|
|
|
{
|
2021-09-19 14:36:52 +02:00
|
|
|
Utils.sendMessage(this.user, this.user.getTranslation("general.errors.no-permission"));
|
2019-01-24 23:28:12 +01:00
|
|
|
result = EMPTY_RESULT;
|
2019-01-24 22:57:50 +01:00
|
|
|
}
|
2021-09-18 12:01:35 +02:00
|
|
|
else if (type.equals(ChallengeType.INVENTORY_TYPE))
|
2018-12-30 14:31:26 +01:00
|
|
|
{
|
2019-05-06 11:10:02 +02:00
|
|
|
result = this.checkInventory(this.getAvailableCompletionTimes(maxTimes));
|
2018-12-30 14:31:26 +01:00
|
|
|
}
|
2021-09-18 12:01:35 +02:00
|
|
|
else if (type.equals(ChallengeType.ISLAND_TYPE))
|
2018-12-30 14:31:26 +01:00
|
|
|
{
|
2019-05-06 11:10:02 +02:00
|
|
|
result = this.checkSurrounding(this.getAvailableCompletionTimes(maxTimes));
|
2018-12-30 14:31:26 +01:00
|
|
|
}
|
2021-09-18 12:01:35 +02:00
|
|
|
else if (type.equals(ChallengeType.OTHER_TYPE))
|
2019-01-24 22:29:56 +01:00
|
|
|
{
|
2019-05-06 11:10:02 +02:00
|
|
|
result = this.checkOthers(this.getAvailableCompletionTimes(maxTimes));
|
2019-01-24 23:28:12 +01:00
|
|
|
}
|
2021-09-18 12:01:35 +02:00
|
|
|
else if (type.equals(ChallengeType.STATISTIC_TYPE))
|
2021-08-14 18:25:04 +02:00
|
|
|
{
|
|
|
|
result = this.checkStatistic(this.getAvailableCompletionTimes(maxTimes));
|
|
|
|
}
|
2019-01-24 23:28:12 +01:00
|
|
|
else
|
|
|
|
{
|
|
|
|
result = EMPTY_RESULT;
|
2018-12-30 14:31:26 +01:00
|
|
|
}
|
2019-01-24 22:29:56 +01:00
|
|
|
|
2019-05-06 11:10:02 +02:00
|
|
|
// Mark if challenge is completed.
|
|
|
|
if (result.isMeetsRequirements())
|
|
|
|
{
|
|
|
|
result.setCompleted(this.manager.isChallengeComplete(this.user, this.world, this.challenge));
|
|
|
|
}
|
2019-01-24 22:29:56 +01:00
|
|
|
// Everything fails till this point.
|
2019-01-24 23:28:12 +01:00
|
|
|
return result;
|
2018-12-30 14:31:26 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2019-01-24 23:20:33 +01:00
|
|
|
/**
|
|
|
|
* This method checks if user has all required permissions.
|
|
|
|
* @return true if user has all required permissions, otherwise false.
|
|
|
|
*/
|
|
|
|
private boolean checkPermissions()
|
|
|
|
{
|
2019-09-08 19:03:46 +02:00
|
|
|
return this.challenge.getRequirements().getRequiredPermissions().isEmpty() ||
|
2021-09-19 14:36:52 +02:00
|
|
|
this.challenge.getRequirements().getRequiredPermissions().stream().allMatch(s -> this.user.hasPermission(s));
|
2019-01-24 23:20:33 +01:00
|
|
|
}
|
|
|
|
|
2019-05-06 11:10:02 +02:00
|
|
|
|
|
|
|
/**
|
|
|
|
* This method checks if it is possible to complete maxTimes current challenge by
|
|
|
|
* challenge constraints and already completed times.
|
|
|
|
* @param vantedTimes How many times user wants to complete challenge
|
|
|
|
* @return how many times user is able complete challenge by its constraints.
|
|
|
|
*/
|
|
|
|
private int getAvailableCompletionTimes(int vantedTimes)
|
|
|
|
{
|
2021-09-24 15:03:02 +02:00
|
|
|
if (!this.challenge.isRepeatable() || this.challenge.getTimeout() > 0)
|
2019-05-06 11:10:02 +02:00
|
|
|
{
|
|
|
|
// Challenge is not repeatable
|
|
|
|
vantedTimes = 1;
|
|
|
|
}
|
2022-03-22 11:41:27 +01:00
|
|
|
else if (this.challenge.getMaxTimes() > 0)
|
2019-05-06 11:10:02 +02:00
|
|
|
{
|
|
|
|
// Challenge has limitations
|
|
|
|
long availableTimes = this.challenge.getMaxTimes() - this.manager.getChallengeTimes(this.user, this.world, this.challenge);
|
|
|
|
|
|
|
|
if (availableTimes < vantedTimes)
|
|
|
|
{
|
|
|
|
vantedTimes = (int) availableTimes;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return vantedTimes;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2019-01-24 22:29:56 +01:00
|
|
|
/**
|
|
|
|
* This method runs all commands from command list.
|
|
|
|
* @param commands List of commands that must be performed.
|
|
|
|
*/
|
|
|
|
private void runCommands(List<String> commands)
|
|
|
|
{
|
|
|
|
// Ignore commands with this perm
|
|
|
|
if (user.hasPermission(this.permissionPrefix + "command.challengeexempt") && !user.isOp())
|
|
|
|
{
|
|
|
|
return;
|
2018-12-30 14:31:26 +01:00
|
|
|
}
|
2019-01-24 22:29:56 +01:00
|
|
|
for (String cmd : commands)
|
|
|
|
{
|
|
|
|
if (cmd.startsWith("[SELF]"))
|
|
|
|
{
|
|
|
|
String alert = "Running command '" + cmd + "' as " + this.user.getName();
|
|
|
|
this.addon.getLogger().info(alert);
|
2021-12-01 10:30:02 +01:00
|
|
|
cmd = cmd.substring(6).replace(Constants.PARAMETER_PLAYER, this.user.getName()).trim();
|
2019-01-24 22:29:56 +01:00
|
|
|
try
|
|
|
|
{
|
|
|
|
if (!user.performCommand(cmd))
|
|
|
|
{
|
|
|
|
this.showError(cmd);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
catch (Exception e)
|
|
|
|
{
|
|
|
|
this.showError(cmd);
|
|
|
|
}
|
2018-12-30 14:31:26 +01:00
|
|
|
|
2019-01-24 22:29:56 +01:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
// Substitute in any references to player
|
|
|
|
try
|
|
|
|
{
|
|
|
|
if (!this.addon.getServer().dispatchCommand(this.addon.getServer().getConsoleSender(),
|
2021-09-19 20:04:09 +02:00
|
|
|
cmd.replace(Constants.PARAMETER_PLAYER, this.user.getName())))
|
2019-01-24 22:29:56 +01:00
|
|
|
{
|
|
|
|
this.showError(cmd);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
catch (Exception e)
|
|
|
|
{
|
|
|
|
this.showError(cmd);
|
|
|
|
}
|
2018-12-30 14:31:26 +01:00
|
|
|
}
|
2019-01-24 22:29:56 +01:00
|
|
|
}
|
2018-12-30 14:31:26 +01:00
|
|
|
|
|
|
|
|
2019-01-24 22:29:56 +01:00
|
|
|
/**
|
|
|
|
* Throws error message.
|
|
|
|
* @param cmd Error message that appear after failing some command.
|
|
|
|
*/
|
|
|
|
private void showError(final String cmd)
|
|
|
|
{
|
|
|
|
this.addon.getLogger().severe("Problem executing command executed by player - skipping!");
|
|
|
|
this.addon.getLogger().severe(() -> "Command was : " + cmd);
|
2018-12-30 14:31:26 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2019-11-03 23:12:09 +01:00
|
|
|
// ---------------------------------------------------------------------
|
|
|
|
// Section: Inventory Challenge
|
|
|
|
// ---------------------------------------------------------------------
|
2019-01-24 22:29:56 +01:00
|
|
|
|
|
|
|
|
2018-12-30 14:31:26 +01:00
|
|
|
/**
|
2019-01-24 22:29:56 +01:00
|
|
|
* Checks if a inventory challenge can be completed or not
|
|
|
|
* It returns ChallengeResult.
|
2019-05-06 11:10:02 +02:00
|
|
|
* @param maxTimes - times that user wanted to complete
|
2019-01-24 22:29:56 +01:00
|
|
|
*/
|
2019-05-06 11:10:02 +02:00
|
|
|
private ChallengeResult checkInventory(int maxTimes)
|
2018-12-30 14:31:26 +01:00
|
|
|
{
|
2022-03-22 11:41:27 +01:00
|
|
|
if (maxTimes <= 0)
|
|
|
|
{
|
|
|
|
return EMPTY_RESULT;
|
|
|
|
}
|
|
|
|
|
2019-01-24 22:29:56 +01:00
|
|
|
// Run through inventory
|
2019-06-16 14:57:05 +02:00
|
|
|
List<ItemStack> requiredItems;
|
2019-02-14 09:28:06 +01:00
|
|
|
|
|
|
|
// Players in creative game mode has got all items. No point to search for them.
|
|
|
|
if (this.user.getPlayer().getGameMode() != GameMode.CREATIVE)
|
2019-01-24 22:29:56 +01:00
|
|
|
{
|
2021-09-24 16:16:33 +02:00
|
|
|
requiredItems = Utils.groupEqualItems(this.getInventoryRequirements().getRequiredItems(),
|
|
|
|
this.getInventoryRequirements().getIgnoreMetaData());
|
2019-01-24 22:29:56 +01:00
|
|
|
|
2019-04-01 09:14:31 +02:00
|
|
|
// Check if all required items are in players inventory.
|
|
|
|
for (ItemStack required : requiredItems)
|
|
|
|
{
|
2019-05-06 11:10:02 +02:00
|
|
|
int numInInventory;
|
|
|
|
|
2022-04-17 00:27:35 +02:00
|
|
|
if (this.getInventoryRequirements().getIgnoreMetaData().contains(required.getType()))
|
2019-04-01 09:14:31 +02:00
|
|
|
{
|
2021-09-24 16:16:33 +02:00
|
|
|
numInInventory = Arrays.stream(this.user.getInventory().getContents()).
|
|
|
|
filter(Objects::nonNull).
|
|
|
|
filter(i -> i.getType().equals(required.getType())).
|
|
|
|
mapToInt(ItemStack::getAmount).
|
|
|
|
sum();
|
2019-04-01 09:14:31 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2021-09-24 16:16:33 +02:00
|
|
|
numInInventory = Arrays.stream(this.user.getInventory().getContents()).
|
|
|
|
filter(Objects::nonNull).
|
|
|
|
filter(i -> i.isSimilar(required)).
|
|
|
|
mapToInt(ItemStack::getAmount).
|
|
|
|
sum();
|
2019-04-01 09:14:31 +02:00
|
|
|
}
|
|
|
|
|
2019-05-06 11:10:02 +02:00
|
|
|
if (numInInventory < required.getAmount())
|
2019-04-01 09:14:31 +02:00
|
|
|
{
|
2021-09-19 14:36:52 +02:00
|
|
|
Utils.sendMessage(this.user, this.user.getTranslation("challenges.errors.not-enough-items",
|
|
|
|
"[items]",
|
|
|
|
Utils.prettifyObject(required, this.user)));
|
2019-04-01 09:14:31 +02:00
|
|
|
return EMPTY_RESULT;
|
|
|
|
}
|
2019-05-06 11:10:02 +02:00
|
|
|
|
|
|
|
maxTimes = Math.min(maxTimes, numInInventory / required.getAmount());
|
2019-02-14 09:28:06 +01:00
|
|
|
}
|
2018-12-30 14:31:26 +01:00
|
|
|
}
|
2019-06-16 14:57:05 +02:00
|
|
|
else
|
|
|
|
{
|
|
|
|
requiredItems = Collections.emptyList();
|
|
|
|
}
|
2019-01-24 22:29:56 +01:00
|
|
|
|
|
|
|
// Return the result
|
2019-05-06 11:10:02 +02:00
|
|
|
return new ChallengeResult().
|
2019-11-03 23:12:09 +01:00
|
|
|
setMeetsRequirements().
|
|
|
|
setCompleteFactor(maxTimes).
|
|
|
|
setRequiredItems(requiredItems);
|
2018-12-30 14:31:26 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Removes items from a user's inventory
|
2019-04-01 09:14:31 +02:00
|
|
|
* @param requiredItemList - a list of item stacks to be removed
|
2019-05-06 11:10:02 +02:00
|
|
|
* @param factor - factor for required items.
|
2018-12-30 14:31:26 +01:00
|
|
|
*/
|
2019-05-06 11:10:02 +02:00
|
|
|
Map<ItemStack, Integer> removeItems(List<ItemStack> requiredItemList, int factor)
|
2019-01-24 22:29:56 +01:00
|
|
|
{
|
2019-05-06 11:10:02 +02:00
|
|
|
Map<ItemStack, Integer> removed = new HashMap<>();
|
2019-01-24 22:29:56 +01:00
|
|
|
|
2019-04-01 09:14:31 +02:00
|
|
|
for (ItemStack required : requiredItemList)
|
2019-01-24 22:29:56 +01:00
|
|
|
{
|
2019-05-06 11:10:02 +02:00
|
|
|
int amountToBeRemoved = required.getAmount() * factor;
|
2019-04-01 09:14:31 +02:00
|
|
|
List<ItemStack> itemsInInventory;
|
2019-01-24 22:29:56 +01:00
|
|
|
|
2021-12-01 10:30:02 +01:00
|
|
|
if (this.user.getInventory() == null)
|
|
|
|
{
|
|
|
|
// Sanity check. User always has inventory at this point of code.
|
|
|
|
itemsInInventory = Collections.emptyList();
|
|
|
|
}
|
|
|
|
else if (this.getInventoryRequirements().getIgnoreMetaData().contains(required.getType()))
|
2019-04-01 09:14:31 +02:00
|
|
|
{
|
|
|
|
// Use collecting method that ignores item meta.
|
|
|
|
itemsInInventory = Arrays.stream(user.getInventory().getContents()).
|
2021-09-24 16:16:33 +02:00
|
|
|
filter(Objects::nonNull).
|
|
|
|
filter(i -> i.getType().equals(required.getType())).
|
|
|
|
collect(Collectors.toList());
|
2019-04-01 09:14:31 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// Use collecting method that compares item meta.
|
|
|
|
itemsInInventory = Arrays.stream(user.getInventory().getContents()).
|
2021-09-24 16:16:33 +02:00
|
|
|
filter(Objects::nonNull).
|
|
|
|
filter(i -> i.isSimilar(required)).
|
|
|
|
collect(Collectors.toList());
|
2019-04-01 09:14:31 +02:00
|
|
|
}
|
2021-09-24 16:16:33 +02:00
|
|
|
|
2019-05-06 11:10:02 +02:00
|
|
|
for (ItemStack itemStack : itemsInInventory)
|
2019-01-24 22:29:56 +01:00
|
|
|
{
|
|
|
|
if (amountToBeRemoved > 0)
|
|
|
|
{
|
2019-05-06 11:10:02 +02:00
|
|
|
ItemStack dummy = itemStack.clone();
|
|
|
|
dummy.setAmount(1);
|
|
|
|
|
2018-12-30 14:31:26 +01:00
|
|
|
// Remove either the full amount or the remaining amount
|
2019-05-06 11:10:02 +02:00
|
|
|
if (itemStack.getAmount() >= amountToBeRemoved)
|
2019-01-24 22:29:56 +01:00
|
|
|
{
|
2019-05-06 11:10:02 +02:00
|
|
|
itemStack.setAmount(itemStack.getAmount() - amountToBeRemoved);
|
|
|
|
removed.merge(dummy, amountToBeRemoved, Integer::sum);
|
2018-12-30 14:31:26 +01:00
|
|
|
amountToBeRemoved = 0;
|
2019-01-24 22:29:56 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2019-05-06 11:10:02 +02:00
|
|
|
removed.merge(dummy, itemStack.getAmount(), Integer::sum);
|
|
|
|
amountToBeRemoved -= itemStack.getAmount();
|
|
|
|
itemStack.setAmount(0);
|
2018-12-30 14:31:26 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2019-01-24 22:29:56 +01:00
|
|
|
|
|
|
|
if (amountToBeRemoved > 0)
|
|
|
|
{
|
2019-04-01 09:14:31 +02:00
|
|
|
this.addon.logError("Could not remove " + amountToBeRemoved + " of " + required.getType() +
|
2019-11-03 23:12:09 +01:00
|
|
|
" from player's inventory!");
|
2018-12-30 14:31:26 +01:00
|
|
|
}
|
|
|
|
}
|
2019-01-24 22:29:56 +01:00
|
|
|
|
2018-12-30 14:31:26 +01:00
|
|
|
return removed;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2019-11-03 23:12:09 +01:00
|
|
|
// ---------------------------------------------------------------------
|
|
|
|
// Section: Island Challenge
|
|
|
|
// ---------------------------------------------------------------------
|
2019-01-24 22:29:56 +01:00
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Checks if a island challenge can be completed or not
|
|
|
|
* It returns ChallengeResult.
|
2019-05-06 11:10:02 +02:00
|
|
|
* @param factor - times that user wanted to complete
|
2019-01-24 22:29:56 +01:00
|
|
|
*/
|
2019-05-06 11:10:02 +02:00
|
|
|
private ChallengeResult checkSurrounding(int factor)
|
2019-01-24 22:29:56 +01:00
|
|
|
{
|
2022-03-22 11:41:27 +01:00
|
|
|
if (factor <= 0)
|
|
|
|
{
|
|
|
|
return EMPTY_RESULT;
|
|
|
|
}
|
|
|
|
|
2019-04-23 18:54:39 +02:00
|
|
|
// Init location in player position.
|
2019-04-24 06:03:09 +02:00
|
|
|
BoundingBox boundingBox = this.user.getPlayer().getBoundingBox().clone();
|
2019-04-23 18:54:39 +02:00
|
|
|
|
2019-08-28 23:07:08 +02:00
|
|
|
// Expand position with search radius. Unless someone sets search radius larger than island
|
|
|
|
// range. In this situation use island range.
|
|
|
|
int distance = this.addon.getPlugin().getIWM().getIslandDistance(this.world);
|
|
|
|
|
2019-09-08 19:03:46 +02:00
|
|
|
IslandRequirements requirements = this.challenge.getRequirements();
|
|
|
|
|
|
|
|
if (requirements.getSearchRadius() < distance + 1)
|
2019-08-28 23:07:08 +02:00
|
|
|
{
|
2019-09-08 19:03:46 +02:00
|
|
|
distance = requirements.getSearchRadius();
|
2019-08-28 23:07:08 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
boundingBox.expand(distance);
|
2019-04-23 18:54:39 +02:00
|
|
|
|
|
|
|
if (ChallengesAddon.CHALLENGES_WORLD_PROTECTION.isSetForWorld(this.world))
|
2018-12-30 14:31:26 +01:00
|
|
|
{
|
2019-04-23 18:54:39 +02:00
|
|
|
// Players should not be able to complete challenge if they stay near island with required blocks.
|
|
|
|
|
|
|
|
Island island = this.addon.getIslands().getIsland(this.world, this.user);
|
2019-11-03 23:12:09 +01:00
|
|
|
|
2019-10-30 07:44:26 +01:00
|
|
|
if (island == null) {
|
|
|
|
// Just in case. Should never hit because there is a check if the player is on this island further up
|
|
|
|
return EMPTY_RESULT;
|
|
|
|
}
|
2019-01-24 22:29:56 +01:00
|
|
|
|
2019-04-23 18:54:39 +02:00
|
|
|
if (boundingBox.getMinX() < island.getMinX())
|
|
|
|
{
|
|
|
|
boundingBox.expand(BlockFace.EAST, Math.abs(island.getMinX() - boundingBox.getMinX()));
|
|
|
|
}
|
2019-01-24 22:29:56 +01:00
|
|
|
|
2019-04-23 18:54:39 +02:00
|
|
|
if (boundingBox.getMinZ() < island.getMinZ())
|
2019-01-24 22:29:56 +01:00
|
|
|
{
|
2019-04-23 18:54:39 +02:00
|
|
|
boundingBox.expand(BlockFace.NORTH, Math.abs(island.getMinZ() - boundingBox.getMinZ()));
|
2019-01-24 22:29:56 +01:00
|
|
|
}
|
|
|
|
|
2019-04-23 18:54:39 +02:00
|
|
|
int range = island.getRange();
|
|
|
|
|
2019-08-28 23:07:08 +02:00
|
|
|
if (boundingBox.getMaxX() > island.getMaxX())
|
|
|
|
{
|
|
|
|
boundingBox.expand(BlockFace.WEST, Math.abs(boundingBox.getMaxX() - island.getMaxX()));
|
|
|
|
}
|
2019-04-23 18:54:39 +02:00
|
|
|
|
2019-08-30 16:15:36 +02:00
|
|
|
if (boundingBox.getMaxZ() > island.getMaxZ())
|
2019-01-24 22:29:56 +01:00
|
|
|
{
|
2019-08-30 16:15:36 +02:00
|
|
|
boundingBox.expand(BlockFace.SOUTH, Math.abs(boundingBox.getMaxZ() - island.getMaxZ()));
|
2019-01-24 22:29:56 +01:00
|
|
|
}
|
|
|
|
|
2019-08-28 23:07:08 +02:00
|
|
|
// Protection code. Do not allow to select too large region for completing challenge.
|
|
|
|
if (boundingBox.getWidthX() > distance * 2 + 3 ||
|
2021-12-01 10:30:02 +01:00
|
|
|
boundingBox.getWidthZ() > distance * 2 + 3 ||
|
|
|
|
boundingBox.getHeight() > distance * 2 + 3)
|
2019-01-24 22:29:56 +01:00
|
|
|
{
|
2019-08-28 23:07:08 +02:00
|
|
|
this.addon.logError("BoundingBox is larger than SearchRadius. " +
|
2021-12-01 10:30:02 +01:00
|
|
|
" | BoundingBox: " + boundingBox +
|
2019-11-03 23:12:09 +01:00
|
|
|
" | Search Distance: " + requirements.getSearchRadius() +
|
2021-12-01 10:30:02 +01:00
|
|
|
" | Location: " + this.user.getLocation() +
|
|
|
|
" | Center: " + island.getCenter() +
|
2019-11-03 23:12:09 +01:00
|
|
|
" | Range: " + range);
|
2019-08-28 23:07:08 +02:00
|
|
|
|
|
|
|
return EMPTY_RESULT;
|
2019-01-24 22:29:56 +01:00
|
|
|
}
|
2019-04-23 18:54:39 +02:00
|
|
|
}
|
2019-03-05 09:30:58 +01:00
|
|
|
|
2019-09-08 19:03:46 +02:00
|
|
|
ChallengeResult result = this.searchForEntities(requirements.getRequiredEntities(), factor, boundingBox);
|
2019-04-23 18:54:39 +02:00
|
|
|
|
2019-09-08 19:03:46 +02:00
|
|
|
if (result.isMeetsRequirements() && !requirements.getRequiredBlocks().isEmpty())
|
2019-04-23 18:54:39 +02:00
|
|
|
{
|
|
|
|
// Search for items only if entities found
|
2019-09-08 19:03:46 +02:00
|
|
|
result = this.searchForBlocks(requirements.getRequiredBlocks(), result.getFactor(), boundingBox);
|
2019-04-23 18:54:39 +02:00
|
|
|
}
|
|
|
|
|
2018-12-30 14:31:26 +01:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2019-01-24 22:29:56 +01:00
|
|
|
|
|
|
|
/**
|
2019-04-23 18:54:39 +02:00
|
|
|
* This method search required blocks in given challenge boundingBox.
|
2019-05-06 11:10:02 +02:00
|
|
|
* @param requiredMap RequiredBlock Map.
|
|
|
|
* @param factor - requirement multilayer.
|
2019-04-23 18:54:39 +02:00
|
|
|
* @param boundingBox Bounding box of island challenge
|
2019-01-24 22:29:56 +01:00
|
|
|
* @return ChallengeResult
|
|
|
|
*/
|
2019-05-06 11:10:02 +02:00
|
|
|
private ChallengeResult searchForBlocks(Map<Material, Integer> requiredMap, int factor, BoundingBox boundingBox)
|
2019-01-24 22:29:56 +01:00
|
|
|
{
|
2019-05-06 11:10:02 +02:00
|
|
|
if (requiredMap.isEmpty())
|
2019-04-23 18:54:39 +02:00
|
|
|
{
|
2019-05-06 11:10:02 +02:00
|
|
|
return new ChallengeResult().setMeetsRequirements().setCompleteFactor(factor);
|
2019-04-23 18:54:39 +02:00
|
|
|
}
|
|
|
|
|
2019-05-06 11:10:02 +02:00
|
|
|
Map<Material, Integer> blocks = new EnumMap<>(requiredMap);
|
|
|
|
Map<Material, Integer> blocksFound = new HashMap<>(requiredMap.size());
|
|
|
|
|
|
|
|
// This queue will contain only blocks whit required type ordered by distance till player.
|
|
|
|
Queue<Block> blockFromWorld = new PriorityQueue<>((o1, o2) -> {
|
2021-12-01 10:30:02 +01:00
|
|
|
if (o1.getType().equals(o2.getType()) && this.user.getLocation() != null)
|
2019-11-03 23:12:09 +01:00
|
|
|
{
|
|
|
|
return Double.compare(o1.getLocation().distance(this.user.getLocation()),
|
2021-12-01 10:30:02 +01:00
|
|
|
o2.getLocation().distance(this.user.getLocation()));
|
2019-11-03 23:12:09 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return o1.getType().compareTo(o2.getType());
|
|
|
|
}
|
2019-05-06 11:10:02 +02:00
|
|
|
});
|
|
|
|
|
2019-04-23 18:54:39 +02:00
|
|
|
for (int x = (int) boundingBox.getMinX(); x <= boundingBox.getMaxX(); x++)
|
2019-01-24 22:29:56 +01:00
|
|
|
{
|
2019-04-23 18:54:39 +02:00
|
|
|
for (int y = (int) boundingBox.getMinY(); y <= boundingBox.getMaxY(); y++)
|
2019-01-24 22:29:56 +01:00
|
|
|
{
|
2019-04-23 18:54:39 +02:00
|
|
|
for (int z = (int) boundingBox.getMinZ(); z <= boundingBox.getMaxZ(); z++)
|
2019-01-24 22:29:56 +01:00
|
|
|
{
|
2019-05-06 11:10:02 +02:00
|
|
|
Block block = this.user.getWorld().getBlockAt(x, y, z);
|
2019-04-23 18:54:39 +02:00
|
|
|
|
2019-05-06 11:10:02 +02:00
|
|
|
if (requiredMap.containsKey(block.getType()))
|
2019-04-23 18:54:39 +02:00
|
|
|
{
|
2019-05-06 11:10:02 +02:00
|
|
|
blockFromWorld.add(block);
|
|
|
|
|
|
|
|
blocksFound.putIfAbsent(block.getType(), 1);
|
|
|
|
blocksFound.computeIfPresent(block.getType(), (reqEntity, amount) -> amount + 1);
|
|
|
|
|
|
|
|
// Remove one
|
|
|
|
blocks.computeIfPresent(block.getType(), (b, amount) -> amount - 1);
|
|
|
|
// Remove any that have an amount of 0
|
|
|
|
blocks.entrySet().removeIf(en -> en.getValue() <= 0);
|
|
|
|
|
|
|
|
if (blocks.isEmpty() && factor == 1)
|
|
|
|
{
|
|
|
|
// Return as soon as it s empty as no point to search more.
|
|
|
|
return new ChallengeResult().setMeetsRequirements().setCompleteFactor(factor).setBlockQueue(blockFromWorld);
|
|
|
|
}
|
2019-04-23 18:54:39 +02:00
|
|
|
}
|
2018-12-30 14:31:26 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2019-01-24 22:29:56 +01:00
|
|
|
|
|
|
|
if (blocks.isEmpty())
|
|
|
|
{
|
2019-05-06 11:10:02 +02:00
|
|
|
if (factor > 1)
|
|
|
|
{
|
|
|
|
// Calculate minimal completion count.
|
|
|
|
|
|
|
|
for (Map.Entry<Material, Integer> entry : blocksFound.entrySet())
|
|
|
|
{
|
|
|
|
factor = Math.min(factor,
|
2019-11-03 23:12:09 +01:00
|
|
|
entry.getValue() / requiredMap.get(entry.getKey()));
|
2019-05-06 11:10:02 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// kick garbage collector
|
|
|
|
blocksFound.clear();
|
|
|
|
|
|
|
|
return new ChallengeResult().setMeetsRequirements().setCompleteFactor(factor).setBlockQueue(blockFromWorld);
|
2018-12-30 14:31:26 +01:00
|
|
|
}
|
2019-01-24 22:29:56 +01:00
|
|
|
|
2021-09-19 14:36:52 +02:00
|
|
|
Utils.sendMessage(this.user, this.user.getTranslation("challenges.errors.not-close-enough",
|
|
|
|
"[number]", String.valueOf(this.getIslandRequirements().getSearchRadius())));
|
2019-01-24 22:29:56 +01:00
|
|
|
|
2021-09-19 14:36:52 +02:00
|
|
|
blocks.forEach((k, v) -> Utils.sendMessage(this.user,
|
|
|
|
this.user.getTranslation("challenges.errors.you-still-need",
|
2019-11-03 23:12:09 +01:00
|
|
|
"[amount]", String.valueOf(v),
|
2021-09-19 14:36:52 +02:00
|
|
|
"[item]", Utils.prettifyObject(k, this.user))));
|
2018-12-30 14:31:26 +01:00
|
|
|
|
2019-05-06 11:10:02 +02:00
|
|
|
|
|
|
|
// kick garbage collector
|
|
|
|
blocks.clear();
|
|
|
|
blocksFound.clear();
|
2019-05-16 09:30:01 +02:00
|
|
|
blockFromWorld.clear();
|
2019-05-06 11:10:02 +02:00
|
|
|
|
2019-01-24 23:28:12 +01:00
|
|
|
return EMPTY_RESULT;
|
2018-12-30 14:31:26 +01:00
|
|
|
}
|
|
|
|
|
2019-01-24 22:29:56 +01:00
|
|
|
|
|
|
|
/**
|
2019-04-23 18:54:39 +02:00
|
|
|
* This method search required entities in given radius from user position and entity is inside boundingBox.
|
2019-05-06 11:10:02 +02:00
|
|
|
* @param requiredMap RequiredEntities Map.
|
|
|
|
* @param factor - requirements multiplier.
|
2019-04-23 18:54:39 +02:00
|
|
|
* @param boundingBox Bounding box of island challenge
|
2019-01-24 22:29:56 +01:00
|
|
|
* @return ChallengeResult
|
|
|
|
*/
|
2019-05-06 11:10:02 +02:00
|
|
|
private ChallengeResult searchForEntities(Map<EntityType, Integer> requiredMap,
|
2019-11-03 23:12:09 +01:00
|
|
|
int factor,
|
|
|
|
BoundingBox boundingBox)
|
2019-01-24 22:29:56 +01:00
|
|
|
{
|
2019-05-06 11:10:02 +02:00
|
|
|
if (requiredMap.isEmpty())
|
2019-04-23 18:54:39 +02:00
|
|
|
{
|
2019-05-06 11:10:02 +02:00
|
|
|
return new ChallengeResult().setMeetsRequirements().setCompleteFactor(factor);
|
2019-04-23 18:54:39 +02:00
|
|
|
}
|
|
|
|
|
2019-05-06 11:10:02 +02:00
|
|
|
// Collect all entities that could be removed.
|
|
|
|
Map<EntityType, Integer> entitiesFound = new HashMap<>();
|
|
|
|
Map<EntityType, Integer> minimalRequirements = new EnumMap<>(requiredMap);
|
|
|
|
|
|
|
|
// Create queue that contains all required entities ordered by distance till player.
|
|
|
|
Queue<Entity> entityQueue = new PriorityQueue<>((o1, o2) -> {
|
2021-12-01 10:30:02 +01:00
|
|
|
if (o1.getType().equals(o2.getType()) && this.user.getLocation() != null)
|
2019-05-06 11:10:02 +02:00
|
|
|
{
|
|
|
|
return Double.compare(o1.getLocation().distance(this.user.getLocation()),
|
2021-12-01 10:30:02 +01:00
|
|
|
o2.getLocation().distance(this.user.getLocation()));
|
2019-05-06 11:10:02 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return o1.getType().compareTo(o2.getType());
|
|
|
|
}
|
|
|
|
});
|
2019-04-23 18:54:39 +02:00
|
|
|
|
2020-03-09 10:39:59 +01:00
|
|
|
user.getWorld().getNearbyEntities(boundingBox).forEach(entity -> {
|
2019-04-23 18:54:39 +02:00
|
|
|
// Check if entity is inside challenge bounding box
|
2019-05-06 11:10:02 +02:00
|
|
|
if (requiredMap.containsKey(entity.getType()))
|
2019-04-23 18:54:39 +02:00
|
|
|
{
|
2019-11-03 23:12:09 +01:00
|
|
|
entityQueue.add(entity);
|
2019-05-14 08:55:34 +02:00
|
|
|
|
2019-05-06 11:10:02 +02:00
|
|
|
entitiesFound.putIfAbsent(entity.getType(), 1);
|
|
|
|
entitiesFound.computeIfPresent(entity.getType(), (reqEntity, amount) -> amount + 1);
|
|
|
|
|
2019-04-23 18:54:39 +02:00
|
|
|
// Look through all the nearby Entities, filtering by type
|
2019-05-06 11:10:02 +02:00
|
|
|
minimalRequirements.computeIfPresent(entity.getType(), (reqEntity, amount) -> amount - 1);
|
|
|
|
minimalRequirements.entrySet().removeIf(e -> e.getValue() == 0);
|
2019-04-23 18:54:39 +02:00
|
|
|
}
|
2018-12-30 14:31:26 +01:00
|
|
|
});
|
2019-01-24 22:29:56 +01:00
|
|
|
|
2019-05-06 11:10:02 +02:00
|
|
|
if (minimalRequirements.isEmpty())
|
2019-01-24 22:29:56 +01:00
|
|
|
{
|
2019-05-06 11:10:02 +02:00
|
|
|
if (factor > 1)
|
|
|
|
{
|
|
|
|
// Calculate minimal completion count.
|
|
|
|
|
|
|
|
for (Map.Entry<EntityType, Integer> entry : entitiesFound.entrySet())
|
|
|
|
{
|
|
|
|
factor = Math.min(factor,
|
2019-11-03 23:12:09 +01:00
|
|
|
entry.getValue() / requiredMap.get(entry.getKey()));
|
2019-05-06 11:10:02 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Kick garbage collector
|
|
|
|
entitiesFound.clear();
|
|
|
|
|
|
|
|
return new ChallengeResult().setMeetsRequirements().setCompleteFactor(factor).setEntityQueue(entityQueue);
|
2019-01-24 22:29:56 +01:00
|
|
|
}
|
|
|
|
|
2021-09-19 14:36:52 +02:00
|
|
|
minimalRequirements.forEach((reqEnt, amount) ->
|
|
|
|
Utils.sendMessage(this.user, this.user.getTranslation("challenges.errors.you-still-need",
|
2019-11-03 23:12:09 +01:00
|
|
|
"[amount]", String.valueOf(amount),
|
2021-09-19 14:36:52 +02:00
|
|
|
"[item]", Utils.prettifyObject(reqEnt, this.user))));
|
2019-01-24 22:29:56 +01:00
|
|
|
|
2019-05-06 11:10:02 +02:00
|
|
|
// Kick garbage collector
|
|
|
|
entitiesFound.clear();
|
|
|
|
minimalRequirements.clear();
|
|
|
|
entityQueue.clear();
|
|
|
|
|
2019-01-24 23:28:12 +01:00
|
|
|
return EMPTY_RESULT;
|
2019-01-24 22:29:56 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* This method removes required block and set air instead of it.
|
2019-05-06 11:10:02 +02:00
|
|
|
* @param blockQueue Queue with blocks that could be removed
|
|
|
|
* @param factor requirement factor for each block type.
|
2019-01-24 22:29:56 +01:00
|
|
|
*/
|
2019-05-06 11:10:02 +02:00
|
|
|
private void removeBlocks(Queue<Block> blockQueue, int factor)
|
2019-01-24 22:29:56 +01:00
|
|
|
{
|
2019-09-08 19:03:46 +02:00
|
|
|
Map<Material, Integer> blocks = new EnumMap<>(this.getIslandRequirements().getRequiredBlocks());
|
2019-01-24 22:29:56 +01:00
|
|
|
|
2019-05-06 11:10:02 +02:00
|
|
|
// Increase required blocks by factor.
|
|
|
|
blocks.entrySet().forEach(entry -> entry.setValue(entry.getValue() * factor));
|
2019-01-24 22:29:56 +01:00
|
|
|
|
2019-05-06 11:10:02 +02:00
|
|
|
blockQueue.forEach(block -> {
|
|
|
|
if (blocks.containsKey(block.getType()))
|
|
|
|
{
|
|
|
|
blocks.computeIfPresent(block.getType(), (b, amount) -> amount - 1);
|
|
|
|
blocks.entrySet().removeIf(en -> en.getValue() <= 0);
|
2019-01-24 22:29:56 +01:00
|
|
|
|
2019-05-06 11:10:02 +02:00
|
|
|
block.setType(Material.AIR);
|
2019-01-24 22:29:56 +01:00
|
|
|
}
|
2019-05-06 11:10:02 +02:00
|
|
|
});
|
2019-01-24 22:29:56 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* This method removes required entities.
|
2019-05-06 11:10:02 +02:00
|
|
|
* @param entityQueue Queue with entities that could be removed
|
|
|
|
* @param factor requirement factor for each entity type.
|
2019-01-24 22:29:56 +01:00
|
|
|
*/
|
2019-05-06 11:10:02 +02:00
|
|
|
private void removeEntities(Queue<Entity> entityQueue, int factor)
|
2019-01-24 22:29:56 +01:00
|
|
|
{
|
2019-09-08 19:03:46 +02:00
|
|
|
Map<EntityType, Integer> entities = this.getIslandRequirements().getRequiredEntities().isEmpty() ?
|
2019-11-03 23:12:09 +01:00
|
|
|
new EnumMap<>(EntityType.class) : new EnumMap<>(this.getIslandRequirements().getRequiredEntities());
|
2019-01-24 22:29:56 +01:00
|
|
|
|
2019-11-03 23:12:09 +01:00
|
|
|
// Increase required entities by factor.
|
|
|
|
entities.entrySet().forEach(entry -> entry.setValue(entry.getValue() * factor));
|
2019-01-24 22:29:56 +01:00
|
|
|
|
2019-11-03 23:12:09 +01:00
|
|
|
// Go through entity queue and remove entities that are requried.
|
|
|
|
entityQueue.forEach(entity -> {
|
|
|
|
if (entities.containsKey(entity.getType()))
|
|
|
|
{
|
|
|
|
entities.computeIfPresent(entity.getType(), (reqEntity, amount) -> amount - 1);
|
|
|
|
entities.entrySet().removeIf(e -> e.getValue() == 0);
|
|
|
|
entity.remove();
|
|
|
|
}
|
|
|
|
});
|
2019-01-24 22:29:56 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2019-11-03 23:12:09 +01:00
|
|
|
// ---------------------------------------------------------------------
|
|
|
|
// Section: Other challenge
|
|
|
|
// ---------------------------------------------------------------------
|
2019-01-24 22:29:56 +01:00
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Checks if a other challenge can be completed or not
|
|
|
|
* It returns ChallengeResult.
|
2019-05-06 11:10:02 +02:00
|
|
|
* @param factor - times that user wanted to complete
|
2019-01-24 22:29:56 +01:00
|
|
|
*/
|
2019-05-06 11:10:02 +02:00
|
|
|
private ChallengeResult checkOthers(int factor)
|
2019-01-24 22:29:56 +01:00
|
|
|
{
|
2022-03-22 11:41:27 +01:00
|
|
|
if (factor <= 0)
|
|
|
|
{
|
|
|
|
return EMPTY_RESULT;
|
|
|
|
}
|
|
|
|
|
2019-09-08 19:03:46 +02:00
|
|
|
OtherRequirements requirements = this.getOtherRequirements();
|
|
|
|
|
2021-09-19 14:36:52 +02:00
|
|
|
if (!this.addon.isLevelProvided() && requirements.getRequiredIslandLevel() != 0)
|
2019-11-03 23:12:09 +01:00
|
|
|
{
|
2021-09-19 14:36:52 +02:00
|
|
|
Utils.sendMessage(this.user, this.user.getTranslation("challenges.errors.missing-addon"));
|
2019-11-03 23:12:09 +01:00
|
|
|
}
|
|
|
|
else if (!this.addon.isEconomyProvided() &&
|
|
|
|
requirements.getRequiredMoney() != 0)
|
|
|
|
{
|
2021-09-19 14:36:52 +02:00
|
|
|
Utils.sendMessage(this.user, this.user.getTranslation("challenges.errors.missing-addon"));
|
2019-11-03 23:12:09 +01:00
|
|
|
}
|
|
|
|
else if (this.addon.isEconomyProvided() && requirements.getRequiredMoney() < 0)
|
|
|
|
{
|
2021-09-19 14:36:52 +02:00
|
|
|
Utils.sendMessage(this.user, this.user.getTranslation("challenges.errors.incorrect"));
|
2019-11-03 23:12:09 +01:00
|
|
|
}
|
|
|
|
else if (this.addon.isEconomyProvided() &&
|
2021-09-19 14:36:52 +02:00
|
|
|
!this.addon.getEconomyProvider().has(this.user, requirements.getRequiredMoney()))
|
2019-01-24 22:29:56 +01:00
|
|
|
{
|
2021-09-19 14:36:52 +02:00
|
|
|
Utils.sendMessage(this.user, this.user.getTranslation("challenges.errors.not-enough-money",
|
|
|
|
"[value]",
|
|
|
|
Double.toString(requirements.getRequiredMoney())));
|
2019-11-03 23:12:09 +01:00
|
|
|
}
|
|
|
|
else if (requirements.getRequiredExperience() < 0)
|
|
|
|
{
|
2021-09-19 14:36:52 +02:00
|
|
|
Utils.sendMessage(this.user, this.user.getTranslation("challenges.errors.incorrect"));
|
2019-01-24 22:29:56 +01:00
|
|
|
}
|
2019-09-08 19:03:46 +02:00
|
|
|
else if (this.user.getPlayer().getTotalExperience() < requirements.getRequiredExperience() &&
|
2021-09-19 14:36:52 +02:00
|
|
|
this.user.getPlayer().getGameMode() != GameMode.CREATIVE)
|
2019-01-24 22:29:56 +01:00
|
|
|
{
|
2019-02-14 09:28:06 +01:00
|
|
|
// Players in creative gamemode has infinite amount of EXP.
|
2021-09-19 14:36:52 +02:00
|
|
|
Utils.sendMessage(this.user, this.user.getTranslation("challenges.errors.not-enough-experience",
|
|
|
|
"[value]",
|
|
|
|
Integer.toString(requirements.getRequiredExperience())));
|
2019-01-24 22:29:56 +01:00
|
|
|
}
|
2019-11-03 23:12:09 +01:00
|
|
|
else if (this.addon.isLevelProvided() &&
|
|
|
|
this.addon.getLevelAddon().getIslandLevel(this.world, this.user.getUniqueId()) < requirements.getRequiredIslandLevel())
|
2019-01-24 22:29:56 +01:00
|
|
|
{
|
2021-09-19 14:36:52 +02:00
|
|
|
Utils.sendMessage(this.user, this.user.getTranslation("challenges.errors.island-level",
|
|
|
|
TextVariables.NUMBER,
|
|
|
|
String.valueOf(requirements.getRequiredIslandLevel())));
|
2019-01-24 22:29:56 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2019-11-03 23:12:09 +01:00
|
|
|
// calculate factor
|
2019-01-24 22:29:56 +01:00
|
|
|
|
2019-11-03 23:12:09 +01:00
|
|
|
if (this.addon.isEconomyProvided() && requirements.isTakeMoney())
|
|
|
|
{
|
|
|
|
factor = Math.min(factor, (int) (this.addon.getEconomyProvider().getBalance(this.user) / requirements.getRequiredMoney()));
|
|
|
|
}
|
2019-01-24 22:29:56 +01:00
|
|
|
|
2019-11-03 23:12:09 +01:00
|
|
|
if (requirements.getRequiredExperience() > 0 && requirements.isTakeExperience())
|
|
|
|
{
|
|
|
|
factor = Math.min(factor, this.user.getPlayer().getTotalExperience() / requirements.getRequiredExperience());
|
|
|
|
}
|
2019-05-06 11:10:02 +02:00
|
|
|
|
|
|
|
return new ChallengeResult().setMeetsRequirements().setCompleteFactor(factor);
|
2018-12-30 14:31:26 +01:00
|
|
|
}
|
2019-01-24 22:29:56 +01:00
|
|
|
|
2021-08-14 18:25:04 +02:00
|
|
|
return EMPTY_RESULT;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ---------------------------------------------------------------------
|
|
|
|
// Section: Statistic Challenge
|
|
|
|
// ---------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Checks if a statistic challenge can be completed or not
|
|
|
|
* It returns ChallengeResult.
|
|
|
|
* @param factor - times that user wanted to complete
|
|
|
|
*/
|
|
|
|
private ChallengeResult checkStatistic(int factor)
|
|
|
|
{
|
2022-03-22 11:41:27 +01:00
|
|
|
if (factor <= 0)
|
|
|
|
{
|
|
|
|
return EMPTY_RESULT;
|
|
|
|
}
|
|
|
|
|
2021-08-14 18:25:04 +02:00
|
|
|
StatisticRequirements requirements = this.challenge.getRequirements();
|
|
|
|
|
|
|
|
int currentValue;
|
|
|
|
|
2021-12-01 10:30:02 +01:00
|
|
|
if (requirements.getStatistic() == null)
|
|
|
|
{
|
|
|
|
// Sanity check.
|
|
|
|
return EMPTY_RESULT;
|
|
|
|
}
|
|
|
|
|
2022-04-17 00:27:35 +02:00
|
|
|
switch (Objects.requireNonNull(requirements.getStatistic()).getType())
|
2021-08-14 18:25:04 +02:00
|
|
|
{
|
|
|
|
case UNTYPED -> currentValue =
|
|
|
|
this.manager.getStatisticData(this.user, this.world, requirements.getStatistic());
|
|
|
|
case ITEM, BLOCK -> currentValue =
|
|
|
|
this.manager.getStatisticData(this.user, this.world, requirements.getStatistic(), requirements.getMaterial());
|
|
|
|
case ENTITY -> currentValue =
|
|
|
|
this.manager.getStatisticData(this.user, this.world, requirements.getStatistic(), requirements.getEntity());
|
|
|
|
default -> currentValue = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (currentValue < requirements.getAmount())
|
|
|
|
{
|
2021-09-19 14:36:52 +02:00
|
|
|
Utils.sendMessage(this.user, this.user.getTranslation("challenges.errors.requirement-not-met",
|
2021-08-14 18:25:04 +02:00
|
|
|
TextVariables.NUMBER, String.valueOf(requirements.getAmount()),
|
2021-09-19 14:36:52 +02:00
|
|
|
"[value]", String.valueOf(currentValue)));
|
2021-08-14 18:25:04 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
factor = requirements.getAmount() == 0 ? factor : Math.min(factor, currentValue / requirements.getAmount());
|
|
|
|
|
|
|
|
return new ChallengeResult().setMeetsRequirements().setCompleteFactor(factor);
|
|
|
|
}
|
|
|
|
|
2019-01-24 23:28:12 +01:00
|
|
|
return EMPTY_RESULT;
|
2018-12-30 14:31:26 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2019-11-03 23:12:09 +01:00
|
|
|
// ---------------------------------------------------------------------
|
|
|
|
// Section: Title parsings
|
|
|
|
// ---------------------------------------------------------------------
|
2019-05-01 21:57:24 +02:00
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* This method pareses input message by replacing all challenge variables in [] with their values.
|
|
|
|
* @param inputMessage inputMessage string
|
|
|
|
* @param challenge Challenge from which these values should be taken
|
|
|
|
* @return new String that replaces [VALUE] with correct value from challenge.
|
|
|
|
*/
|
|
|
|
private String parseChallenge(String inputMessage, Challenge challenge)
|
|
|
|
{
|
|
|
|
String outputMessage = inputMessage;
|
|
|
|
|
|
|
|
if (inputMessage.contains("[") && inputMessage.contains("]"))
|
|
|
|
{
|
|
|
|
outputMessage = outputMessage.replace("[friendlyName]", challenge.getFriendlyName());
|
2021-12-01 10:30:02 +01:00
|
|
|
|
|
|
|
ChallengeLevel level = challenge.getLevel().isEmpty() ? null : this.manager.getLevel(challenge.getLevel());
|
|
|
|
outputMessage = outputMessage.replace("[level]", level == null ? "" : level.getFriendlyName());
|
|
|
|
|
2019-05-01 21:57:24 +02:00
|
|
|
outputMessage = outputMessage.replace("[rewardText]", challenge.getRewardText());
|
|
|
|
}
|
|
|
|
|
2019-05-04 10:16:41 +02:00
|
|
|
return ChatColor.translateAlternateColorCodes('&', outputMessage);
|
2019-05-01 21:57:24 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* This method pareses input message by replacing all level variables in [] with their values.
|
|
|
|
* @param inputMessage inputMessage string
|
|
|
|
* @param level level from which these values should be taken
|
|
|
|
* @return new String that replaces [VALUE] with correct value from level.
|
|
|
|
*/
|
|
|
|
private String parseLevel(String inputMessage, ChallengeLevel level)
|
|
|
|
{
|
|
|
|
String outputMessage = inputMessage;
|
|
|
|
|
|
|
|
if (inputMessage.contains("[") && inputMessage.contains("]"))
|
|
|
|
{
|
|
|
|
outputMessage = outputMessage.replace("[friendlyName]", level.getFriendlyName());
|
|
|
|
outputMessage = outputMessage.replace("[rewardText]", level.getRewardText());
|
|
|
|
}
|
|
|
|
|
2019-05-04 10:16:41 +02:00
|
|
|
return ChatColor.translateAlternateColorCodes('&', outputMessage);
|
2019-05-01 21:57:24 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2019-11-03 23:12:09 +01:00
|
|
|
// ---------------------------------------------------------------------
|
|
|
|
// Section: Simple getter methods
|
|
|
|
// ---------------------------------------------------------------------
|
2019-09-08 19:03:46 +02:00
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* This is simple cast method. Easier access to IslandRequirements.
|
|
|
|
* @return Island Requirements
|
|
|
|
*/
|
|
|
|
private IslandRequirements getIslandRequirements()
|
|
|
|
{
|
|
|
|
return this.challenge.getRequirements();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* This is simple cast method. Easier access to InventoryRequirements.
|
|
|
|
* @return Inventory Requirements
|
|
|
|
*/
|
|
|
|
private InventoryRequirements getInventoryRequirements()
|
|
|
|
{
|
|
|
|
return this.challenge.getRequirements();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* This is simple cast method. Easier access to OtherRequirements.
|
|
|
|
* @return Other Requirements
|
|
|
|
*/
|
|
|
|
private OtherRequirements getOtherRequirements()
|
|
|
|
{
|
|
|
|
return this.challenge.getRequirements();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2019-11-03 23:12:09 +01:00
|
|
|
// ---------------------------------------------------------------------
|
|
|
|
// Section: Result classes
|
|
|
|
// ---------------------------------------------------------------------
|
2019-01-24 22:29:56 +01:00
|
|
|
|
|
|
|
|
2018-12-30 14:31:26 +01:00
|
|
|
/**
|
|
|
|
* Contains flags on completion of challenge
|
|
|
|
*
|
2019-01-24 22:29:56 +01:00
|
|
|
* @author tastybento
|
2018-12-30 14:31:26 +01:00
|
|
|
*/
|
2021-09-24 15:03:02 +02:00
|
|
|
static class ChallengeResult
|
2019-01-24 22:29:56 +01:00
|
|
|
{
|
2019-05-06 11:10:02 +02:00
|
|
|
/**
|
|
|
|
* This method sets that challenge meets all requirements at least once.
|
|
|
|
* @return Current object.
|
|
|
|
*/
|
|
|
|
ChallengeResult setMeetsRequirements()
|
|
|
|
{
|
|
|
|
this.meetsRequirements = true;
|
|
|
|
return this;
|
|
|
|
}
|
2019-01-24 22:29:56 +01:00
|
|
|
|
2019-05-06 11:10:02 +02:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Method sets that challenge is completed once already
|
|
|
|
* @param completed boolean that indicate that challenge has been already completed.
|
|
|
|
* @return Current object.
|
|
|
|
*/
|
|
|
|
ChallengeResult setCompleted(boolean completed)
|
|
|
|
{
|
|
|
|
this.completed = completed;
|
|
|
|
return this;
|
|
|
|
}
|
2019-01-24 22:29:56 +01:00
|
|
|
|
|
|
|
|
2019-01-05 11:17:03 +01:00
|
|
|
/**
|
2019-05-06 11:10:02 +02:00
|
|
|
* Method sets how many times challenge can be completed.
|
|
|
|
* @param factor Integer that represents completion count.
|
|
|
|
* @return Current object.
|
2019-01-05 11:17:03 +01:00
|
|
|
*/
|
2019-05-06 11:10:02 +02:00
|
|
|
ChallengeResult setCompleteFactor(int factor)
|
2019-01-24 22:29:56 +01:00
|
|
|
{
|
2019-05-06 11:10:02 +02:00
|
|
|
this.factor = factor;
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ---------------------------------------------------------------------
|
|
|
|
// Section: Requirement memory
|
|
|
|
// ---------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Method sets requiredItems for inventory challenge.
|
|
|
|
* @param requiredItems items that are required by inventory challenge.
|
|
|
|
* @return Current object.
|
|
|
|
*/
|
|
|
|
ChallengeResult setRequiredItems(List<ItemStack> requiredItems)
|
|
|
|
{
|
|
|
|
this.requiredItems = requiredItems;
|
2018-12-30 14:31:26 +01:00
|
|
|
return this;
|
|
|
|
}
|
2019-01-24 22:29:56 +01:00
|
|
|
|
|
|
|
|
2018-12-30 14:31:26 +01:00
|
|
|
/**
|
2019-05-06 11:10:02 +02:00
|
|
|
* Method sets queue that contains all blocks with required material type.
|
|
|
|
* @param blocks queue that contains required materials from world.
|
|
|
|
* @return Current object.
|
2018-12-30 14:31:26 +01:00
|
|
|
*/
|
2019-05-06 11:10:02 +02:00
|
|
|
ChallengeResult setBlockQueue(Queue<Block> blocks)
|
2019-01-24 22:29:56 +01:00
|
|
|
{
|
2019-05-06 11:10:02 +02:00
|
|
|
this.blocks = blocks;
|
2018-12-30 14:31:26 +01:00
|
|
|
return this;
|
|
|
|
}
|
2019-05-06 11:10:02 +02:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Method sets queue that contains all entities with required entity type.
|
|
|
|
* @param entities queue that contains required entities from world.
|
|
|
|
* @return Current object.
|
|
|
|
*/
|
|
|
|
ChallengeResult setEntityQueue(Queue<Entity> entities)
|
|
|
|
{
|
|
|
|
this.entities = entities;
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ---------------------------------------------------------------------
|
|
|
|
// Section: Getters
|
|
|
|
// ---------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns value of was completed variable.
|
|
|
|
* @return value of completed variable
|
|
|
|
*/
|
|
|
|
boolean wasCompleted()
|
|
|
|
{
|
|
|
|
return this.completed;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* This method returns how many times challenge can be completed.
|
|
|
|
* @return completion count.
|
|
|
|
*/
|
|
|
|
int getFactor()
|
|
|
|
{
|
|
|
|
return this.factor;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* This method returns if challenge requirements has been met at least once.
|
|
|
|
* @return value of meets requirements variable.
|
|
|
|
*/
|
|
|
|
boolean isMeetsRequirements()
|
|
|
|
{
|
|
|
|
return this.meetsRequirements;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ---------------------------------------------------------------------
|
|
|
|
// Section: Variables
|
|
|
|
// ---------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Boolean that indicate that challenge has already bean completed once before.
|
|
|
|
*/
|
|
|
|
private boolean completed;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Indicates that challenge can be completed.
|
|
|
|
*/
|
|
|
|
private boolean meetsRequirements;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Integer that represents how many times challenge is completed
|
|
|
|
*/
|
|
|
|
private int factor;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* List that contains required items for Inventory Challenge
|
|
|
|
* Necessary as it contains grouped items by type or similarity, not by limit 64.
|
|
|
|
*/
|
|
|
|
private List<ItemStack> requiredItems;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Map that contains removed items and their removed count.
|
|
|
|
*/
|
|
|
|
private Map<ItemStack, Integer> removedItems = null;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Queue of blocks that contains all blocks with the same type as requiredBlock from
|
|
|
|
* challenge requirements.
|
|
|
|
*/
|
|
|
|
private Queue<Block> blocks;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Queue of entities that contains all entities with the same type as requiredEntities from
|
|
|
|
* challenge requirements.
|
|
|
|
*/
|
|
|
|
private Queue<Entity> entities;
|
2019-11-03 23:12:09 +01:00
|
|
|
|
|
|
|
/* (non-Javadoc)
|
|
|
|
* @see java.lang.Object#toString()
|
|
|
|
*/
|
|
|
|
@Override
|
|
|
|
public String toString() {
|
|
|
|
return "ChallengeResult [completed=" + completed + ", meetsRequirements=" + meetsRequirements + ", factor="
|
|
|
|
+ factor + ", requiredItems=" + requiredItems + ", removedItems=" + removedItems + ", blocks="
|
|
|
|
+ blocks + ", entities=" + entities + "]";
|
|
|
|
}
|
2018-12-30 14:31:26 +01:00
|
|
|
}
|
|
|
|
}
|