Added paging to the HUD so abilities don't have to be exclusive

This commit is contained in:
Sollace 2020-10-09 14:37:49 +02:00
parent 4d8c41fa8b
commit cef123e162
5 changed files with 133 additions and 19 deletions

View file

@ -5,6 +5,8 @@ import java.util.EnumMap;
import java.util.Map; import java.util.Map;
import java.util.Optional; import java.util.Optional;
import javax.annotation.Nullable;
import com.minelittlepony.unicopia.Race; import com.minelittlepony.unicopia.Race;
import com.minelittlepony.unicopia.ability.data.Hit; import com.minelittlepony.unicopia.ability.data.Hit;
import com.minelittlepony.unicopia.entity.player.Pony; import com.minelittlepony.unicopia.entity.player.Pony;
@ -22,6 +24,10 @@ public class AbilityDispatcher implements Tickable, NbtSerialisable {
private final Map<AbilitySlot, Stat> stats = new EnumMap<>(AbilitySlot.class); private final Map<AbilitySlot, Stat> stats = new EnumMap<>(AbilitySlot.class);
@Nullable
private Race prevRace;
private long maxPage;
public AbilityDispatcher(Pony player) { public AbilityDispatcher(Pony player) {
this.player = player; this.player = player;
} }
@ -34,10 +40,10 @@ public class AbilityDispatcher implements Tickable, NbtSerialisable {
} }
} }
public void activate(AbilitySlot slot) { public void activate(AbilitySlot slot, long page) {
Stat stat = getStat(slot); Stat stat = getStat(slot);
if (stat.canSwitchStates()) { if (stat.canSwitchStates()) {
stat.getAbility().ifPresent(stat::setActiveAbility); stat.getAbility(page).ifPresent(stat::setActiveAbility);
} }
} }
@ -45,6 +51,14 @@ public class AbilityDispatcher implements Tickable, NbtSerialisable {
return stats.computeIfAbsent(slot, Stat::new); return stats.computeIfAbsent(slot, Stat::new);
} }
public long getMaxPage() {
if (prevRace != player.getSpecies()) {
prevRace = player.getSpecies();
maxPage = Math.max(0, stats.values().stream().mapToLong(Stat::getMaxPage).reduce(0, Math::max) - 1);
}
return maxPage;
}
@Override @Override
public void tick() { public void tick() {
stats.values().forEach(Stat::tick); stats.values().forEach(Stat::tick);
@ -176,14 +190,23 @@ public class AbilityDispatcher implements Tickable, NbtSerialisable {
} }
} }
public Optional<Ability<?>> getAbility() { public Optional<Ability<?>> getAbility(long page) {
Race race = player.getSpecies(); Race race = player.getSpecies();
return Abilities.BY_SLOT.computeIfAbsent(slot, c -> Collections.emptySet()) return Abilities.BY_SLOT.computeIfAbsent(slot, c -> Collections.emptySet())
.stream() .stream()
.filter(a -> a.canUse(race)) .filter(a -> a.canUse(race))
.skip(page)
.findFirst(); .findFirst();
} }
public long getMaxPage() {
Race race = player.getSpecies();
return Abilities.BY_SLOT.computeIfAbsent(slot, c -> Collections.emptySet())
.stream()
.filter(a -> a.canUse(race))
.count();
}
protected synchronized void setActiveAbility(Ability<?> power) { protected synchronized void setActiveAbility(Ability<?> power) {
if (activeAbility.orElse(null) != power) { if (activeAbility.orElse(null) != power) {
triggered = false; triggered = false;

View file

@ -31,7 +31,7 @@ public class EarthPonyGrowAbility implements Ability<Pos> {
@Override @Override
public boolean canUse(Race race) { public boolean canUse(Race race) {
return race == Race.EARTH; return race.canUseEarth();
} }
@Override @Override

View file

@ -7,15 +7,21 @@ import java.util.Set;
import org.lwjgl.glfw.GLFW; import org.lwjgl.glfw.GLFW;
import com.minelittlepony.unicopia.ability.AbilityDispatcher;
import com.minelittlepony.unicopia.ability.AbilitySlot; import com.minelittlepony.unicopia.ability.AbilitySlot;
import com.minelittlepony.unicopia.client.gui.UHud;
import com.minelittlepony.unicopia.entity.player.Pony; import com.minelittlepony.unicopia.entity.player.Pony;
import net.fabricmc.fabric.api.client.keybinding.v1.KeyBindingHelper; import net.fabricmc.fabric.api.client.keybinding.v1.KeyBindingHelper;
import net.minecraft.client.MinecraftClient; import net.minecraft.client.MinecraftClient;
import net.minecraft.client.options.KeyBinding; import net.minecraft.client.options.KeyBinding;
import net.minecraft.client.sound.PositionedSoundInstance;
import net.minecraft.sound.SoundEvents;
import net.minecraft.text.LiteralText;
import net.minecraft.util.math.MathHelper;
public class KeyBindingsHandler { public class KeyBindingsHandler {
private final String KEY_CATEGORY = "unicopia.category.name"; private static final String KEY_CATEGORY = "unicopia.category.name";
public static final KeyBindingsHandler INSTANCE = new KeyBindingsHandler(); public static final KeyBindingsHandler INSTANCE = new KeyBindingsHandler();
@ -24,6 +30,11 @@ public class KeyBindingsHandler {
private final Map<KeyBinding, AbilitySlot> keys = new HashMap<>(); private final Map<KeyBinding, AbilitySlot> keys = new HashMap<>();
private final Map<AbilitySlot, KeyBinding> reverse = new HashMap<>(); private final Map<AbilitySlot, KeyBinding> reverse = new HashMap<>();
private final KeyBinding pageDown = register(GLFW.GLFW_KEY_PAGE_DOWN, "hud_page_dn");
private final KeyBinding pageUp = register(GLFW.GLFW_KEY_PAGE_UP, "hud_page_up");
public long page = 0;
private final Set<KeyBinding> pressed = new HashSet<>(); private final Set<KeyBinding> pressed = new HashSet<>();
public KeyBindingsHandler() { public KeyBindingsHandler() {
@ -37,31 +48,69 @@ public class KeyBindingsHandler {
} }
public void addKeybind(int code, AbilitySlot slot) { public void addKeybind(int code, AbilitySlot slot) {
KeyBinding binding = KeyBindingHelper.registerKeyBinding(new KeyBinding("key.unicopia." + slot.name().toLowerCase(), code, KEY_CATEGORY)); KeyBinding binding = register(code, slot.name().toLowerCase());
reverse.put(slot, binding); reverse.put(slot, binding);
keys.put(binding, slot); keys.put(binding, slot);
} }
static KeyBinding register(int code, String name) {
return KeyBindingHelper.registerKeyBinding(new KeyBinding("key.unicopia." + name, code, KEY_CATEGORY));
}
public void tick(MinecraftClient client) { public void tick(MinecraftClient client) {
if (client.currentScreen != null if (client.currentScreen != null
|| client.player == null) { || client.player == null) {
return; return;
} }
Pony iplayer = Pony.of(client.player); Pony iplayer = Pony.of(client.player);
AbilityDispatcher abilities = iplayer.getAbilities();
long maxPage = abilities.getMaxPage();
for (KeyBinding i : keys.keySet()) { page = MathHelper.clamp(page, 0, maxPage);
AbilitySlot slot = keys.get(i);
if (slot == AbilitySlot.PRIMARY && client.options.keySneak.isPressed()) {
slot = AbilitySlot.PASSIVE;
}
if (i.isPressed()) { if (page > 0 && checkPressed(pageDown) == PressedState.PRESSED) {
if (pressed.add(i)) { changePage(client, maxPage, -1);
iplayer.getAbilities().activate(slot); } else if (page < maxPage && checkPressed(pageUp) == PressedState.PRESSED) {
changePage(client, maxPage, 1);
} else {
for (KeyBinding i : keys.keySet()) {
AbilitySlot slot = keys.get(i);
if (slot == AbilitySlot.PRIMARY && client.options.keySneak.isPressed()) {
slot = AbilitySlot.PASSIVE;
}
PressedState state = checkPressed(i);
if (state != PressedState.UNCHANGED) {
if (state == PressedState.PRESSED) {
abilities.activate(slot, page);
} else {
abilities.clear(slot);
}
} }
} else if (pressed.remove(i)) {
iplayer.getAbilities().clear(slot);
} }
} }
} }
private void changePage(MinecraftClient client, long max, int sigma) {
page += sigma;
client.getSoundManager().play(PositionedSoundInstance.master(SoundEvents.UI_BUTTON_CLICK, 1.75F + (0.25F * sigma)));
UHud.instance.setMessage(new LiteralText(page + " of " + max));
}
private PressedState checkPressed(KeyBinding binding) {
if (binding.isPressed()) {
return pressed.add(binding) ? PressedState.PRESSED : PressedState.UNCHANGED;
} else if (pressed.remove(binding)) {
return PressedState.UNPRESSED;
}
return PressedState.UNCHANGED;
}
enum PressedState {
UNCHANGED,
PRESSED,
UNPRESSED
}
} }

View file

@ -8,6 +8,7 @@ import com.minelittlepony.common.event.ScreenInitCallback.ButtonList;
import com.minelittlepony.unicopia.InteractionManager; import com.minelittlepony.unicopia.InteractionManager;
import com.minelittlepony.unicopia.Race; import com.minelittlepony.unicopia.Race;
import com.minelittlepony.unicopia.Unicopia; import com.minelittlepony.unicopia.Unicopia;
import com.minelittlepony.unicopia.client.gui.UHud;
import com.minelittlepony.unicopia.entity.player.PlayerCamera; import com.minelittlepony.unicopia.entity.player.PlayerCamera;
import com.minelittlepony.unicopia.entity.player.Pony; import com.minelittlepony.unicopia.entity.player.Pony;
@ -62,6 +63,7 @@ public class UnicopiaClient implements ClientModInitializer {
private void onTick(MinecraftClient client) { private void onTick(MinecraftClient client) {
KeyBindingsHandler.INSTANCE.tick(client); KeyBindingsHandler.INSTANCE.tick(client);
UHud.instance.tick();
} }
private void onScreenInit(Screen screen, ButtonList buttons) { private void onScreenInit(Screen screen, ButtonList buttons) {

View file

@ -3,8 +3,11 @@ package com.minelittlepony.unicopia.client.gui;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import javax.annotation.Nullable;
import com.minelittlepony.unicopia.ability.AbilityDispatcher; import com.minelittlepony.unicopia.ability.AbilityDispatcher;
import com.minelittlepony.unicopia.ability.AbilitySlot; import com.minelittlepony.unicopia.ability.AbilitySlot;
import com.minelittlepony.unicopia.client.KeyBindingsHandler;
import com.minelittlepony.unicopia.entity.player.Pony; import com.minelittlepony.unicopia.entity.player.Pony;
import com.mojang.blaze3d.systems.RenderSystem; import com.mojang.blaze3d.systems.RenderSystem;
@ -13,6 +16,7 @@ import net.minecraft.client.font.TextRenderer;
import net.minecraft.client.gui.DrawableHelper; import net.minecraft.client.gui.DrawableHelper;
import net.minecraft.client.gui.hud.InGameHud; import net.minecraft.client.gui.hud.InGameHud;
import net.minecraft.client.util.math.MatrixStack; import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.text.Text;
import net.minecraft.util.Identifier; import net.minecraft.util.Identifier;
import net.minecraft.util.Util; import net.minecraft.util.Util;
@ -32,6 +36,10 @@ public class UHud extends DrawableHelper {
slots.add(new Slot(this, AbilitySlot.TERTIARY, AbilitySlot.TERTIARY, 36, 19, 3, 22, 17, 19).background(80, 105)); slots.add(new Slot(this, AbilitySlot.TERTIARY, AbilitySlot.TERTIARY, 36, 19, 3, 22, 17, 19).background(80, 105));
}); });
@Nullable
private Text message;
private int messageTime;
public void render(InGameHud hud, MatrixStack matrices, float tickDelta) { public void render(InGameHud hud, MatrixStack matrices, float tickDelta) {
if (client.player == null || client.player.isSpectator()) { if (client.player == null || client.player.isSpectator()) {
@ -46,13 +54,17 @@ public class UHud extends DrawableHelper {
matrices.push(); matrices.push();
matrices.translate(104 + (scaledWidth - 50) / 2, 20 + scaledHeight - 70, 0); matrices.translate(104 + (scaledWidth - 50) / 2, 20 + scaledHeight - 70, 0);
AbilityDispatcher abilities = Pony.of(client.player).getAbilities();
if (message != null && messageTime > 0) {
renderMessage(matrices, tickDelta);
}
RenderSystem.enableAlphaTest(); RenderSystem.enableAlphaTest();
RenderSystem.enableBlend(); RenderSystem.enableBlend();
client.getTextureManager().bindTexture(HUD_TEXTURE); client.getTextureManager().bindTexture(HUD_TEXTURE);
AbilityDispatcher abilities = Pony.of(client.player).getAbilities();
boolean swap = client.options.keySneak.isPressed(); boolean swap = client.options.keySneak.isPressed();
slots.forEach(slot -> slot.renderBackground(matrices, abilities, swap, tickDelta)); slots.forEach(slot -> slot.renderBackground(matrices, abilities, swap, tickDelta));
@ -64,8 +76,36 @@ public class UHud extends DrawableHelper {
matrices.pop(); matrices.pop();
} }
private void renderMessage(MatrixStack matrices, float tickDelta) {
float time = messageTime - tickDelta;
int progress = Math.min(255, (int)(time * 255F / 20F));
if (progress > 8) {
int color = 0xFFFFFF;
int alpha = progress << 24 & -16777216;
color |= alpha;
drawCenteredText(matrices, client.textRenderer, message, 25, -15, color);
}
}
public void setMessage(Text message) {
this.message = message;
this.messageTime = 60;
}
public void tick() {
if (messageTime > 0) {
messageTime--;
}
}
void renderAbilityIcon(MatrixStack matrices, AbilityDispatcher.Stat stat, int x, int y, int u, int v, int frameWidth, int frameHeight) { void renderAbilityIcon(MatrixStack matrices, AbilityDispatcher.Stat stat, int x, int y, int u, int v, int frameWidth, int frameHeight) {
stat.getAbility().ifPresent(ability -> { stat.getAbility(KeyBindingsHandler.INSTANCE.page).ifPresent(ability -> {
client.getTextureManager().bindTexture(ability.getIcon(Pony.of(client.player))); client.getTextureManager().bindTexture(ability.getIcon(Pony.of(client.player)));
drawTexture(matrices, x, y, 0, 0, frameWidth, frameHeight, u, v); drawTexture(matrices, x, y, 0, 0, frameWidth, frameHeight, u, v);
client.getTextureManager().bindTexture(HUD_TEXTURE); client.getTextureManager().bindTexture(HUD_TEXTURE);