160 lines
6.2 KiB
Java
160 lines
6.2 KiB
Java
package tc.oc.pgm.score;
|
|
|
|
import java.util.Map;
|
|
|
|
import com.google.common.base.Preconditions;
|
|
import com.google.common.collect.ImmutableMap;
|
|
import net.md_5.bungee.api.ChatColor;
|
|
import net.md_5.bungee.api.chat.TranslatableComponent;
|
|
import org.bukkit.Sound;
|
|
import org.bukkit.event.EventHandler;
|
|
import org.bukkit.event.EventPriority;
|
|
import org.bukkit.event.Listener;
|
|
import org.bukkit.inventory.ItemStack;
|
|
import org.bukkit.inventory.PlayerInventory;
|
|
import tc.oc.commons.bukkit.chat.NameStyle;
|
|
import tc.oc.commons.bukkit.inventory.Slot;
|
|
import tc.oc.commons.bukkit.item.ItemUtils;
|
|
import tc.oc.commons.core.chat.Component;
|
|
import tc.oc.pgm.events.ListenerScope;
|
|
import tc.oc.pgm.events.PlayerItemTransferEvent;
|
|
import tc.oc.pgm.features.FeatureDefinition;
|
|
import tc.oc.pgm.filters.Filter;
|
|
import tc.oc.pgm.filters.FilterMatchModule;
|
|
import tc.oc.pgm.match.Match;
|
|
import tc.oc.pgm.match.MatchPlayer;
|
|
import tc.oc.pgm.match.MatchScope;
|
|
import tc.oc.pgm.teams.Team;
|
|
import tc.oc.pgm.utils.MaterialPattern;
|
|
|
|
import static com.google.common.base.Preconditions.checkNotNull;
|
|
import static com.google.common.base.Preconditions.checkState;
|
|
|
|
public interface ScoreBoxFactory extends FeatureDefinition {}
|
|
|
|
class ScoreBoxFactoryImpl extends FeatureDefinition.Impl implements ScoreBoxFactory {
|
|
private final Filter trigger;
|
|
private final int score;
|
|
private final Filter filter;
|
|
private final boolean silent;
|
|
private final ImmutableMap<MaterialPattern, Double> redeemables;
|
|
|
|
public ScoreBoxFactoryImpl(Filter trigger, int score, Filter filter, boolean silent, ImmutableMap<MaterialPattern, Double> redeemables) {
|
|
Preconditions.checkNotNull(trigger, "region");
|
|
Preconditions.checkNotNull(filter, "filter");
|
|
|
|
this.trigger = trigger;
|
|
this.score = score;
|
|
this.filter = filter;
|
|
this.silent = silent;
|
|
this.redeemables = redeemables;
|
|
}
|
|
|
|
@Override
|
|
public void load(Match match) {
|
|
new ScoreBox(match);
|
|
}
|
|
|
|
@ListenerScope(MatchScope.RUNNING)
|
|
public class ScoreBox implements Listener {
|
|
|
|
private final Match match;
|
|
private final ScoreMatchModule smm;
|
|
|
|
public ScoreBox(Match match) {
|
|
this.match = checkNotNull(match);
|
|
this.smm = match.needMatchModule(ScoreMatchModule.class);
|
|
|
|
match.registerEvents(this);
|
|
match.needMatchModule(FilterMatchModule.class)
|
|
.onRise(MatchPlayer.class, trigger, player -> {
|
|
if(canScore(player)) {
|
|
score(player, score + redeemItems(player));
|
|
}
|
|
});
|
|
}
|
|
|
|
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
|
|
public void onPlayerAcquireItem(final PlayerItemTransferEvent event) {
|
|
match.interactor(event.getPlayer()).ifPresent(player -> {
|
|
if(event.isAcquiring() &&
|
|
canScore(player) &&
|
|
trigger.query(player).isAllowed()) {
|
|
|
|
score(player, redeemItems(player));
|
|
}
|
|
});
|
|
}
|
|
|
|
private boolean canScore(MatchPlayer player) {
|
|
return player.canInteract() &&
|
|
filter.query(player).isAllowed();
|
|
}
|
|
|
|
/**
|
|
* If given item is redeemed, change its amount and return the points awarded (which may be 0 or negative)
|
|
*
|
|
* Return NaN if the item is not redeemed.
|
|
*/
|
|
private double redeemItem(ItemStack stack) {
|
|
if(stack != null) {
|
|
for(Map.Entry<MaterialPattern, Double> entry : ((Map<MaterialPattern, Double>) redeemables).entrySet()) {
|
|
if(entry.getKey().matches(stack.getData())) {
|
|
final double points = entry.getValue() * stack.getAmount();
|
|
stack.setAmount(0);
|
|
return points;
|
|
}
|
|
}
|
|
}
|
|
return Double.NaN;
|
|
}
|
|
|
|
private double redeemItems(MatchPlayer player) {
|
|
if(redeemables.isEmpty()) return 0;
|
|
|
|
final PlayerInventory inventory = player.getInventory();
|
|
return Slot.Player.player()
|
|
.map(slot -> {
|
|
final ItemStack item = slot.getItem(inventory);
|
|
final double points = redeemItem(item);
|
|
if(Double.isNaN(points)) {
|
|
return 0D;
|
|
} else {
|
|
// Note that redeeming a zero-amount stack will remove the item, but give no points
|
|
slot.putItem(inventory, ItemUtils.something(item).orElse(null));
|
|
return points;
|
|
}
|
|
})
|
|
.reduce(0D, (a, b) -> a + b);
|
|
}
|
|
|
|
private void score(MatchPlayer player, double points) {
|
|
checkState(player.isParticipating());
|
|
|
|
if(points == 0) return;
|
|
|
|
final int integerPoints = (int) points; // can be negative
|
|
if(!silent && integerPoints != 0) {
|
|
player.playSound(Sound.ENTITY_PLAYER_LEVELUP, 1, 1);
|
|
player.getMatch().sendMessage(
|
|
new Component(
|
|
new TranslatableComponent(
|
|
player.getCompetitor() instanceof Team ? "match.score.scorebox.team"
|
|
: "match.score.scorebox.individual",
|
|
player.getStyledName(NameStyle.VERBOSE),
|
|
new TranslatableComponent(
|
|
integerPoints == 1 ? "points.singularCompound"
|
|
: "points.pluralCompound",
|
|
new Component(integerPoints, ChatColor.DARK_AQUA)
|
|
),
|
|
new Component(player.getParty().getComponentName())
|
|
), ChatColor.GRAY
|
|
)
|
|
);
|
|
}
|
|
|
|
smm.incrementScore(player.getCompetitor(), points);
|
|
}
|
|
}
|
|
}
|