Compare commits

...

9 commits
v1.4 ... main

18 changed files with 1095 additions and 161 deletions

View file

@ -38,7 +38,7 @@ mod_name=VHat Can I Roll?
# The license of the mod. Review your options at https://choosealicense.com/. All Rights Reserved is the default.
mod_license=GNU LGPL 3.0
# The mod version. See https://semver.org/
mod_version=1.4
mod_version=1.5
# The group ID for the mod. It is only important when publishing as an artifact to a Maven repository.
# This should match the base package used for the mod sources.
# See https://maven.apache.org/guides/mini/guide-naming-conventions.html

View file

@ -11,10 +11,12 @@ public class Config {
public static final ForgeConfigSpec.IntValue BUTTON_X;
public static final ForgeConfigSpec.IntValue BUTTON_Y;
public static final ForgeConfigSpec.IntValue MAX_LEVEL_OVERRIDE;
public static final ForgeConfigSpec.BooleanValue SHOW_ABILITY_ENHANCEMENTS;
public static final ForgeConfigSpec.BooleanValue SHOW_ABILITY_ENHANCEMENTS;
public static final ForgeConfigSpec.BooleanValue SHOW_WEIGHT;
public static final ForgeConfigSpec.BooleanValue SHOW_CHANCE;
public static final ForgeConfigSpec.BooleanValue QOL_HUNTERS_CONFLICT_RESOLUTION;
public static final ForgeConfigSpec.BooleanValue SHOW_UNOBTAINABLE_CRAFTED;
public static final ForgeConfigSpec.BooleanValue DEBUG_UNIQUE_GEAR;
// string instead of enum, because forge would remove enum values that are not present in the enum
// (this could cause problems if mods are extending the enum - like wold's)
public static final ForgeConfigSpec.ConfigValue<List<String>> AFFIX_TAG_GROUP_CHANCE_BLACKLIST;
@ -40,11 +42,16 @@ public class Config {
QOL_HUNTERS_CONFLICT_RESOLUTION = builder
.comment("QOL Hunters conflict resolution (shouldn't be disabled unless it causes issues)")
.define("QOLHuntersConflictResolution", true);
builder.pop();
AFFIX_TAG_GROUP_CHANCE_BLACKLIST = builder
.comment("vhcir won't show chance/weight for affixes in these groups")
.define("affixTagGroupBlacklist", List.of(VaultGearTierConfig.ModifierAffixTagGroup.CRAFTED_PREFIX.name(), VaultGearTierConfig.ModifierAffixTagGroup.CRAFTED_SUFFIX.name()));
MAX_LEVEL_OVERRIDE = builder
.comment("override max level")
.defineInRange("maxLevelOverride", -1, -1, Integer.MAX_VALUE);
DEBUG_UNIQUE_GEAR = builder
.comment("debug unique gear")
.define("debugUniqueGear", false);
builder.pop();
SHOW_ABILITY_ENHANCEMENTS = builder
.comment("show ability enhancements")
@ -58,10 +65,9 @@ public class Config {
.comment("show chance")
.define("showChance", true);
AFFIX_TAG_GROUP_CHANCE_BLACKLIST = builder
.comment("vhcir won't show chance/weight for affixes in these groups")
.define("affixTagGroupBlacklist", List.of(VaultGearTierConfig.ModifierAffixTagGroup.CRAFTED_PREFIX.name(), VaultGearTierConfig.ModifierAffixTagGroup.CRAFTED_SUFFIX.name()));
SHOW_UNOBTAINABLE_CRAFTED = builder
.comment("show unobtainable crafted modifiers (above current lvl)")
.define("showUnobtainableCrafted", false);
SPEC = builder.build();
}
}

View file

@ -22,8 +22,8 @@ public class QOLHuntersCompat {
if (qolConfigButton == null) {
// use reflection to avoid a million dependencies
try {
var cl = Class.forName("io.iridium.qolhunters.config.QOLHuntersClientConfigs");
var qolButton = cl.getField("SHOW_CONFIG_BUTTON").get(null);
Class<?> cl = Class.forName("io.iridium.qolhunters.config.QOLHuntersClientConfigs");
Object qolButton = cl.getField("SHOW_CONFIG_BUTTON").get(null);
qolConfigButton = (ForgeConfigSpec.BooleanValue) qolButton;
} catch (NoSuchFieldException | ClassNotFoundException | IllegalAccessException e) {
qolHuntersLoaded = false;

View file

@ -1,8 +1,14 @@
package com.radimous.vhatcaniroll.logic;
import iskallia.vault.gear.VaultGearState;
import iskallia.vault.gear.data.VaultGearData;
import iskallia.vault.init.ModGearAttributes;
import iskallia.vault.init.ModItems;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.ItemStack;
import org.apache.commons.lang3.tuple.Pair;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
@ -23,35 +29,36 @@ public class Items {
public static List<ItemStack> getVHGearItems() {
return List.of(
new ItemStack(ModItems.SWORD),
new ItemStack(ModItems.AXE),
new ItemStack(ModItems.HELMET),
new ItemStack(ModItems.CHESTPLATE),
new ItemStack(ModItems.LEGGINGS),
new ItemStack(ModItems.BOOTS),
new ItemStack(ModItems.FOCUS),
new ItemStack(ModItems.SHIELD),
new ItemStack(ModItems.WAND),
new ItemStack(ModItems.MAGNET),
new ItemStack(ModItems.JEWEL)
);
withTransmog(new ItemStack(ModItems.SWORD), new ResourceLocation("the_vault:gear/sword/sword_0")),
withTransmog(new ItemStack(ModItems.AXE), new ResourceLocation("the_vault:gear/axe/axe_0")),
withTransmog(new ItemStack(ModItems.HELMET), new ResourceLocation("the_vault:gear/armor/gladiator_dark/helmet")),
withTransmog(new ItemStack(ModItems.CHESTPLATE), new ResourceLocation("the_vault:gear/armor/magmatic/chestplate")),
withTransmog(new ItemStack(ModItems.LEGGINGS), new ResourceLocation("the_vault:gear/armor/reinforced_platemail_dark/leggings")),
withTransmog(new ItemStack(ModItems.BOOTS), new ResourceLocation("the_vault:gear/armor/gladiator_dark/boots")),
withTransmog(new ItemStack(ModItems.FOCUS), new ResourceLocation("the_vault:gear/focus/tatteredtome")),
withTransmog(new ItemStack(ModItems.SHIELD), new ResourceLocation("the_vault:gear/shield/gold_plated")),
withTransmog(new ItemStack(ModItems.WAND), new ResourceLocation("the_vault:gear/wand/lunar")),
withTransmog(new ItemStack(ModItems.MAGNET), new ResourceLocation("the_vault:magnets/magnet_1")),
withTransmog(new ItemStack(ModItems.JEWEL), new ResourceLocation("the_vault:gear/jewel/sword_0"))
);
}
public static List<ItemStack> getWoldGearItems() {
List<ItemStack> woldItems = new ArrayList<>();
List<String> woldItemFields = Arrays.asList(
"BATTLESTAFF",
"TRIDENT",
"PLUSHIE",
"LOOT_SACK",
"RANG"
List<Pair<String, String>> woldItemFields = Arrays.asList(
Pair.of("BATTLESTAFF", "the_vault:gear/battlestaff/battlestaff_redstone"),
Pair.of("TRIDENT", "the_vault:gear/trident/orange"),
Pair.of("PLUSHIE", "the_vault:gear/plushie/hrry"),
Pair.of("LOOT_SACK", "the_vault:gear/loot_sack/bundle"),
Pair.of("RANG", "the_vault:gear/rang/wooden")
);
try{
Class<?> woldItemClass = Class.forName("xyz.iwolfking.woldsvaults.init.ModItems");
for (String woldFieldName : woldItemFields) {
for (Pair<String, String> woldFieldTransmogs : woldItemFields) {
try {
String woldFieldName = woldFieldTransmogs.getLeft();
Item item = (Item) woldItemClass.getField(woldFieldName).get(null);
woldItems.add(new ItemStack(item));
woldItems.add(withTransmog(new ItemStack(item), new ResourceLocation(woldFieldTransmogs.getRight())));
} catch (IllegalArgumentException | SecurityException | NoSuchFieldException |
IllegalAccessException ignored) {
// no-op
@ -61,6 +68,20 @@ public class Items {
// no-op
}
return woldItems;
}
/**
* Creates copy of the given stack with the transmog applied
* @param stack the stack to apply the transmog to
* @param transmog the transmog to apply
* @return the stack with the transmog applied
*/
public static ItemStack withTransmog(ItemStack stack, ResourceLocation transmog){
ItemStack displayStack = stack.copy();
VaultGearData gearData = VaultGearData.read(displayStack);
gearData.setState(VaultGearState.IDENTIFIED);
gearData.createOrReplaceAttributeValue(ModGearAttributes.GEAR_MODEL, transmog);
gearData.write(displayStack);
return displayStack;
}
}

View file

@ -1,30 +1,54 @@
package com.radimous.vhatcaniroll.logic;
import com.radimous.vhatcaniroll.Config;
import com.radimous.vhatcaniroll.mixin.AbilityFloatValueAttributeReaderInvoker;
import com.radimous.vhatcaniroll.mixin.EffectConfigAccessor;
import com.radimous.vhatcaniroll.mixin.VaultGearTierConfigAccessor;
import iskallia.vault.config.UniqueGearConfig;
import iskallia.vault.config.gear.VaultGearTierConfig;
import iskallia.vault.gear.attribute.VaultGearAttribute;
import iskallia.vault.gear.attribute.VaultGearAttributeRegistry;
import iskallia.vault.gear.attribute.VaultGearModifier;
import iskallia.vault.gear.attribute.ability.AbilityAreaOfEffectPercentAttribute;
import iskallia.vault.gear.attribute.ability.AbilityLevelAttribute;
import iskallia.vault.gear.attribute.ability.special.EntropyPoisonModification;
import iskallia.vault.gear.attribute.ability.special.FrostNovaVulnerabilityModification;
import iskallia.vault.gear.attribute.ability.special.base.SpecialAbilityConfig;
import iskallia.vault.gear.attribute.ability.special.base.SpecialAbilityGearAttribute;
import iskallia.vault.gear.attribute.ability.special.base.SpecialAbilityModification;
import iskallia.vault.gear.attribute.ability.special.base.template.FloatRangeModification;
import iskallia.vault.gear.attribute.ability.special.base.template.IntRangeModification;
import iskallia.vault.gear.attribute.ability.special.base.template.config.FloatRangeConfig;
import iskallia.vault.gear.attribute.ability.special.base.template.config.IntRangeConfig;
import iskallia.vault.gear.attribute.ability.special.base.template.value.FloatValue;
import iskallia.vault.gear.attribute.ability.special.base.template.value.IntValue;
import iskallia.vault.gear.attribute.config.BooleanFlagGenerator;
import iskallia.vault.gear.attribute.config.ConfigurableAttributeGenerator;
import iskallia.vault.gear.attribute.custom.effect.EffectGearAttribute;
import iskallia.vault.gear.attribute.custom.loot.LootTriggerAttribute;
import iskallia.vault.gear.attribute.custom.loot.ManaPerLootAttribute;
import iskallia.vault.gear.reader.VaultGearModifierReader;
import iskallia.vault.init.ModConfigs;
import iskallia.vault.skill.ability.component.AbilityLabelFormatters;
import iskallia.vault.skill.base.Skill;
import net.minecraft.ChatFormatting;
import net.minecraft.network.chat.Component;
import net.minecraft.network.chat.MutableComponent;
import net.minecraft.network.chat.Style;
import net.minecraft.network.chat.TextColor;
import net.minecraft.network.chat.TextComponent;
import net.minecraft.resources.ResourceLocation;
import net.minecraftforge.fml.LogicalSide;
import org.jetbrains.annotations.NotNull;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
@ -37,22 +61,33 @@ public class Modifiers {
ChatFormatting.LIGHT_PURPLE, ChatFormatting.AQUA, ChatFormatting.WHITE};
private static final Pattern CLOUD_PATTERN = Pattern.compile("^(?<effect>.*?) ?(?<lvl>I|II|III|IV|V|VI|VII|VIII|IX|X)? (?<suffix>Cloud.*)$");
private static final DecimalFormat DECIMAL_FORMAT = new DecimalFormat("0.##");
public static List<Component> getModifierList(int lvl, VaultGearTierConfig cfg, ModifierCategory modifierCategory) {
Map<VaultGearTierConfig.ModifierAffixTagGroup, VaultGearTierConfig.AttributeGroup> modifierGroup = ((VaultGearTierConfigAccessor) cfg).getModifierGroup();
ArrayList<Component> modList = new ArrayList<>();
for (VaultGearTierConfig.ModifierAffixTagGroup affixTagGroup : modifierGroup.keySet()) {
modList.addAll(getAffixGroupComponents(lvl, affixTagGroup, modifierGroup, modifierCategory));
modList.addAll(getAffixGroupComponents(lvl, affixTagGroup, modifierGroup.get(affixTagGroup), modifierCategory));
}
return modList;
}
private static List<Component> getAffixGroupComponents(int lvl, VaultGearTierConfig.ModifierAffixTagGroup affixTagGroup,
Map<VaultGearTierConfig.ModifierAffixTagGroup, VaultGearTierConfig.AttributeGroup> modifierGroup,
ModifierCategory modifierCategory) {
public static List<Component> getUniqueModifierList(int lvl, ModifierCategory modifierCategory, Map<UniqueGearConfig.AffixTargetType, List<ResourceLocation>> modifierIdentifiers) {
ArrayList<Component> modList = new ArrayList<>();
for (Map.Entry<UniqueGearConfig.AffixTargetType, List<ResourceLocation>> modifierIdentifier : modifierIdentifiers.entrySet()) {
modList.addAll(getUniqueAffixComponents(lvl, modifierIdentifier, modifierCategory));
}
return modList;
}
public static List<Component> getAffixGroupComponents(int lvl, VaultGearTierConfig.ModifierAffixTagGroup affixTagGroup,
VaultGearTierConfig.AttributeGroup modifierGroups,
ModifierCategory modifierCategory) {
ArrayList<Component> componentList = new ArrayList<>();
if (!Config.SHOW_ABILITY_ENHANCEMENTS.get() && affixTagGroup.equals(VaultGearTierConfig.ModifierAffixTagGroup.ABILITY_ENHANCEMENT)) {
@ -60,14 +95,14 @@ public class Modifiers {
}
Map<String, Integer> groupCounts = countGroups(lvl, affixTagGroup, modifierGroup, modifierCategory);
Map<String, Integer> groupCounts = countGroups(lvl, modifierGroups, modifierCategory);
AtomicBoolean noWeightAttr = new AtomicBoolean(false);
int totalWeight = modifierGroup.get(affixTagGroup).stream()
int totalWeight = modifierGroups.stream()
.mapToInt(modTierGroup -> getModifierTiers(lvl, modTierGroup, modifierCategory).stream().mapToInt(
tier -> {
if ((affixTagGroup == VaultGearTierConfig.ModifierAffixTagGroup.IMPLICIT
|| affixTagGroup == VaultGearTierConfig.ModifierAffixTagGroup.BASE_ATTRIBUTES) && groupCounts.get(modTierGroup.getModifierGroup()) == 1) {
|| affixTagGroup == VaultGearTierConfig.ModifierAffixTagGroup.BASE_ATTRIBUTES) && groupCounts.get(modTierGroup.getModifierGroup()) == 1) {
noWeightAttr.set(true);
return 0;
}
@ -88,10 +123,8 @@ public class Modifiers {
componentList.add(new TextComponent("Total Weight: " + totalWeight).withStyle(ChatFormatting.BOLD));
}
Map<String, List<Component>> groupedModifiers = new HashMap<>();
for (VaultGearTierConfig.ModifierTierGroup modifierTierGroup : modifierGroup.get(affixTagGroup)) {
for (VaultGearTierConfig.ModifierTierGroup modifierTierGroup :modifierGroups) {
ArrayList<VaultGearTierConfig.ModifierTier<?>> mTierList;
mTierList = getModifierTiers(lvl, modifierTierGroup, modifierCategory);
@ -99,11 +132,10 @@ public class Modifiers {
continue;
}
String modGr = modifierTierGroup.getModifierGroup();
MutableComponent modComp = getModifierComponent(VaultGearAttributeRegistry.getAttribute(modifierTierGroup.getAttribute()),mTierList);
// //if (implicit||base) && groupCounts == 0
if (!(
(affixTagGroup == VaultGearTierConfig.ModifierAffixTagGroup.BASE_ATTRIBUTES
|| affixTagGroup == VaultGearTierConfig.ModifierAffixTagGroup.IMPLICIT
@ -114,7 +146,7 @@ public class Modifiers {
modComp.append(new TextComponent(" w"+weight).withStyle(ChatFormatting.GRAY));
}
if (Config.SHOW_CHANCE.get() && shouldShowWeight(modifierCategory, affixTagGroup)) {
if (Config.SHOW_CHANCE.get() && shouldShowWeight(modifierCategory, affixTagGroup) && totalWeight > 0) {
modComp.append(new TextComponent(String.format(" %.2f%%", ((double) weight * 100 / totalWeight))).withStyle(ChatFormatting.GRAY));
}
}
@ -135,23 +167,56 @@ public class Modifiers {
// more than 7 groups is a bit crazy, but just in case
boolean useNums = groupedModifiers.size() > COLORS.length;
int i = 0;
for (var modGr: groupedModifiers.values()) {
for (var mod: modGr) {
MutableComponent full = new TextComponent(useNums ? i + " " : "").withStyle(COLORS[i % COLORS.length]);
full.append(mod);
componentList.add(full);
}
i++;
for (List<Component> modGr: groupedModifiers.values()) {
for (Component mod: modGr) {
MutableComponent full = new TextComponent(useNums ? i + " " : "").withStyle(COLORS[i % COLORS.length]);
full.append(mod);
componentList.add(full);
}
i++;
}
componentList.add(TextComponent.EMPTY);
return componentList;
}
private static Map<String, Integer> countGroups(int lvl, VaultGearTierConfig.ModifierAffixTagGroup affixTagGroup,
Map<VaultGearTierConfig.ModifierAffixTagGroup, VaultGearTierConfig.AttributeGroup> modifierGroup,
ModifierCategory modifierCategory) {
/**
* Same as getAffixGroupComponents, but for unique gear without chances and groups
*/
public static List<Component> getUniqueAffixComponents(int lvl,Map.Entry<UniqueGearConfig.AffixTargetType, List<ResourceLocation>> modifierIdentifier, ModifierCategory modifierCategory) {
ArrayList<Component> componentList = new ArrayList<>();
if (modifierIdentifier.getValue().isEmpty()) {
return componentList; // no affix for this type
}
UniqueGearConfig.AffixTargetType affixTagGroup = modifierIdentifier.getKey();
componentList.add(new TextComponent(affixTagGroup.toString().replace("_", " ")).withStyle(ChatFormatting.BOLD));
for (ResourceLocation modifier : modifierIdentifier.getValue()) {
VaultGearTierConfig.ModifierTierGroup modifierTierGroup = ModConfigs.VAULT_GEAR_CONFIG.get(VaultGearTierConfig.UNIQUE_ITEM).getTierGroup(modifier);
if (modifierTierGroup == null) {
continue;
}
ArrayList<VaultGearTierConfig.ModifierTier<?>> mTierList;
mTierList = getModifierTiers(lvl, modifierTierGroup, modifierCategory);
if (mTierList.isEmpty()) {
continue;
}
MutableComponent modComp = getModifierComponent(VaultGearAttributeRegistry.getAttribute(modifierTierGroup.getAttribute()),mTierList);
MutableComponent full = new TextComponent(" ");
full.append(modComp);
componentList.add(full);
}
if (componentList.size() == 1) { // only header
return new ArrayList<>(); // no affixes for this type (all tiers are unobtainable)
}
componentList.add(TextComponent.EMPTY);
return componentList;
}
private static Map<String, Integer> countGroups(int lvl, VaultGearTierConfig.AttributeGroup modifierTierGroups, ModifierCategory modifierCategory) {
Map<String, Integer> groupCounts = new HashMap<>();
for (VaultGearTierConfig.ModifierTierGroup modifierTierGroup : modifierGroup.get(affixTagGroup)) {
for (VaultGearTierConfig.ModifierTierGroup modifierTierGroup : modifierTierGroups) {
ArrayList<VaultGearTierConfig.ModifierTier<?>> mTierList;
mTierList = getModifierTiers(lvl, modifierTierGroup, modifierCategory);
if (mTierList.isEmpty()) {
@ -163,15 +228,14 @@ public class Modifiers {
return groupCounts;
}
private static ArrayList<VaultGearTierConfig.ModifierTier<?>> getModifierTiers(int lvl,
VaultGearTierConfig.ModifierTierGroup modifierTierGroup, ModifierCategory modifierCategory) {
public static ArrayList<VaultGearTierConfig.ModifierTier<?>> getModifierTiers(int lvl, VaultGearTierConfig.ModifierTierGroup modifierTierGroup, ModifierCategory modifierCategory) {
if (modifierCategory == ModifierCategory.NORMAL) {
return getNormalModifierTiers(lvl, modifierTierGroup);
}
var res = new ArrayList<VaultGearTierConfig.ModifierTier<?>>();
var highest = modifierTierGroup.getHighestForLevel(lvl);
ArrayList<VaultGearTierConfig.ModifierTier<?>> res = new ArrayList<>();
VaultGearTierConfig.ModifierTier<?> highest = modifierTierGroup.getHighestForLevel(lvl);
if (highest == null) {
return res; // empty
}
@ -179,7 +243,7 @@ public class Modifiers {
return res; // empty
}
int index = Math.min(highest.getModifierTier() + modifierCategory.getTierIncrease(), modifierTierGroup.size() - 1);
var legendTier = modifierTierGroup.get(index);
VaultGearTierConfig.ModifierTier<?> legendTier = modifierTierGroup.get(index);
if (legendTier == null || legendTier.getWeight() == 0){
return res; // empty
}
@ -200,7 +264,7 @@ public class Modifiers {
}
@SuppressWarnings("unchecked") // I don't think proper generics are possible, VaultGearTierConfig#getModifiersForLevel returns List<ModifierTier<?>>
private static <T, C> MutableComponent getModifierComponent(VaultGearAttribute<T> atr,
public static <T, C> MutableComponent getModifierComponent(VaultGearAttribute<T> atr,
ArrayList<VaultGearTierConfig.ModifierTier<?>> modifierTiers) {
if (modifierTiers.isEmpty()) {
return new TextComponent("ERR - EMPTY MODIFIER TIERS");
@ -222,8 +286,12 @@ public class Modifiers {
}
String atrName = atrRegName.toString();
var minConfigDisplay = atrGenerator.getConfigDisplay(atr.getReader(), minConfig);
MutableComponent minConfigDisplay = atrGenerator.getConfigDisplay(atr.getReader(), minConfig);
if (minConfig instanceof SpecialAbilityGearAttribute.SpecialAbilityTierConfig<?,?,?> minConfigSpecial) {
return getSpecialAbilityAttributeComponent(modifierTiers, minConfigSpecial);
}
MutableComponent res = null;
if (modifierTiers.size() > 1) {
res = rangeComponent(atrName, atr, atrGenerator, minConfig, maxConfig);
@ -240,11 +308,71 @@ public class Modifiers {
if (minConfig instanceof EffectGearAttribute.Config ) {
return minConfigDisplay;
}
if (minConfig instanceof AbilityAreaOfEffectPercentAttribute.Config minConfigA) {
return getAbilityAoePercentageComponent(atr, minConfigA, minConfigA);
}
if (minConfig instanceof ManaPerLootAttribute.Config maxManaPerLootConfig) {
return getManaPerLootComponent(maxManaPerLootConfig, maxManaPerLootConfig);
}
return res;
}
return new TextComponent("ERR - NULL DISPLAY " + atrName);
}
@SuppressWarnings("unchecked") // this thing is insane
private static @NotNull MutableComponent getSpecialAbilityAttributeComponent(
ArrayList<VaultGearTierConfig.ModifierTier<?>> modifierTiers,
SpecialAbilityGearAttribute.SpecialAbilityTierConfig<?, ?, ?> minConfigSpecial) {
SpecialAbilityModification<? extends SpecialAbilityConfig<?>, ?> modification = minConfigSpecial.getModification();
if (modification instanceof IntRangeModification intRangeModification){
var minValue = intRangeModification.getMinimumValue(getIntTiers(modifierTiers));
var maxValue = intRangeModification.getMaximumValue(getIntTiers(modifierTiers));
String minValueDisplay = minValue.map(x -> String.valueOf(x.getValue().getValue())).orElse("NULL");
String maxValueDisplay = maxValue.map(x -> String.valueOf(x.getValue().getValue())).orElse("NULL");
MutableComponent minToMaxComponent = new TextComponent(minValueDisplay + "-" + maxValueDisplay).withStyle(ChatFormatting.UNDERLINE).withStyle(Style.EMPTY.withColor(TextColor.fromRgb(6082075)));
if (intRangeModification instanceof FrostNovaVulnerabilityModification) {
return (new TextComponent("Frost Nova also applies Level ").append(minToMaxComponent).append(" Vulnerability")).withStyle(Style.EMPTY.withColor(TextColor.fromRgb(14076214)));
}
if (intRangeModification instanceof EntropyPoisonModification) {
return new TextComponent("Entropic Bind also applies Poison ").withStyle(Style.EMPTY.withColor(TextColor.fromRgb(14076214))).append(minToMaxComponent);
}
if (intRangeModification.getKey().toString().equals("the_vault:glacial_blast_hypothermia")){
return (new TextComponent("Glacial Blast is ").append(minToMaxComponent).append("X more likely to shatter")).withStyle(Style.EMPTY.withColor(TextColor.fromRgb(14076214)));
}
}
if (modification instanceof FloatRangeModification floatRangeModification) {
var minValue = floatRangeModification.getMinimumValue(getFloatTiers(modifierTiers));
var maxValue = floatRangeModification.getMaximumValue(getFloatTiers(modifierTiers));
float minValueDisplay = minValue.map(x -> x.getValue().getValue()).orElse(0f);
float maxValueDisplay = maxValue.map(x -> x.getValue().getValue()).orElse(0f);
MutableComponent minToMaxComponent = new TextComponent(DECIMAL_FORMAT.format(minValueDisplay*100) + "%-" + DECIMAL_FORMAT.format(maxValueDisplay*100)+"%").withStyle(ChatFormatting.UNDERLINE).withStyle(Style.EMPTY.withColor(TextColor.fromRgb(6082075)));
if (floatRangeModification.getKey().toString().equals("the_vault:fireball_special_modification")){
return (new TextComponent("Fireball has ").append(minToMaxComponent).append(" chance to fire twice")).withStyle(Style.EMPTY.withColor(TextColor.fromRgb(14076214)));
}
}
String abilityKey = minConfigSpecial.getAbilityKey();
return ModConfigs.ABILITIES.getAbilityById(abilityKey).filter(skill -> skill.getName() != null).map(skill -> {
String name = skill.getName();
return new TextComponent("Special " + name + " modification");
}).orElseGet(() -> (TextComponent) new TextComponent(abilityKey).withStyle(Style.EMPTY.withColor(14076214)));
}
@SuppressWarnings("unchecked")
private static List<SpecialAbilityGearAttribute.SpecialAbilityTierConfig<SpecialAbilityModification<IntRangeConfig, IntValue>, IntRangeConfig, IntValue>> getIntTiers(List<VaultGearTierConfig.ModifierTier<?>> modifierTiers) {
return modifierTiers.stream().map(x -> (SpecialAbilityGearAttribute.SpecialAbilityTierConfig<SpecialAbilityModification<IntRangeConfig, IntValue>, IntRangeConfig, IntValue>) x.getModifierConfiguration()).toList();
}
@SuppressWarnings("unchecked")
private static List<SpecialAbilityGearAttribute.SpecialAbilityTierConfig<SpecialAbilityModification<FloatRangeConfig, FloatValue>, FloatRangeConfig, FloatValue>> getFloatTiers(List<VaultGearTierConfig.ModifierTier<?>> modifierTiers) {
return modifierTiers.stream().map(x -> (SpecialAbilityGearAttribute.SpecialAbilityTierConfig<SpecialAbilityModification<FloatRangeConfig, FloatValue>, FloatRangeConfig, FloatValue>) x.getModifierConfiguration()).toList();
}
/**
* This method handles combining multiple configs into a single component
* VH doesn't have method for this, so we need to do it manually
@ -252,65 +380,121 @@ public class Modifiers {
* and combining it with normal display for single component (that has name and color)
*/
private static <T, C> MutableComponent rangeComponent(String atrName, VaultGearAttribute<T> atr,
ConfigurableAttributeGenerator<T, C> atrGenerator, C minConfig, C maxConfig) {
MutableComponent res = atrGenerator.getConfigRangeDisplay(atr.getReader(), minConfig, maxConfig);
var minConfigDisplay = atrGenerator.getConfigDisplay(atr.getReader(), minConfig);
var maxConfigDisplay = atrGenerator.getConfigDisplay(atr.getReader(), maxConfig);
ConfigurableAttributeGenerator<T, C> atrGenerator, C minConfig, C maxConfig) {
MutableComponent res = atrGenerator.getConfigRangeDisplay(atr.getReader(), minConfig, maxConfig);
MutableComponent minConfigDisplay = atrGenerator.getConfigDisplay(atr.getReader(), minConfig);
MutableComponent maxConfigDisplay = atrGenerator.getConfigDisplay(atr.getReader(), maxConfig);
if (res != null && minConfig instanceof AbilityLevelAttribute.Config minConfigAbility) {
return abilityLvlComponent(res, atr, minConfigAbility);
}
if ((atrName.equals("the_vault:effect_avoidance") || atrName.equals("the_vault:effect_list_avoidance")) && minConfigDisplay != null) {
// res -> "30% - 50%"
// single -> "30% Poison Avoidance"
// minRange -> "30%"
var single = minConfigDisplay.withStyle(atr.getReader().getColoredTextStyle());
var minRange = atrGenerator.getConfigRangeDisplay(atr.getReader(), minConfig, minConfig);
if (minRange != null && res != null) {
res.append(single.getString().replace(minRange.getString(), ""));
// res -> "30% - 50% Poison Avoidance"
}
}
if (minConfigDisplay != null && maxConfigDisplay != null && (atrName.equals("the_vault:effect_cloud") || atrName.equals("the_vault:effect_cloud_when_hit"))) {
return getCloudRangeComponent(minConfigDisplay, maxConfigDisplay, atr);
}
if (res != null && minConfig instanceof AbilityLevelAttribute.Config minConfigAbility) {
return abilityLvlComponent(res, atr, minConfigAbility);
}
if (minConfig instanceof EffectGearAttribute.Config minEffectConfig
&& maxConfig instanceof EffectGearAttribute.Config
&& maxConfigDisplay != null) {
var effectStr = ((EffectConfigAccessor)minEffectConfig).getAmplifier() + "-" +
maxConfigDisplay.getString();
return new TextComponent(effectStr).withStyle(atr.getReader().getColoredTextStyle());
if ((atrName.equals("the_vault:effect_avoidance") || atrName.equals("the_vault:effect_list_avoidance")) && minConfigDisplay != null) {
// res -> "30% - 50%"
// single -> "30% Poison Avoidance"
// minRange -> "30%"
MutableComponent single = minConfigDisplay.withStyle(atr.getReader().getColoredTextStyle());
MutableComponent minRange = atrGenerator.getConfigRangeDisplay(atr.getReader(), minConfig, minConfig);
if (minRange != null && res != null) {
res.append(single.getString().replace(minRange.getString(), ""));
// res -> "30% - 50% Poison Avoidance"
}
}
if (minConfigDisplay != null && maxConfigDisplay != null && (atrName.equals("the_vault:effect_cloud") || atrName.equals("the_vault:effect_cloud_when_hit"))) {
return getCloudRangeComponent(minConfigDisplay, maxConfigDisplay, atr);
}
}
if (res != null) {
return atr.getReader().formatConfigDisplay(LogicalSide.CLIENT, res);
}
return res;
if ((minConfig instanceof AbilityAreaOfEffectPercentAttribute.Config minConfigA) && (maxConfig instanceof AbilityAreaOfEffectPercentAttribute.Config maxConfigA)) {
return getAbilityAoePercentageComponent(atr, minConfigA, maxConfigA);
}
if (minConfig instanceof EffectGearAttribute.Config minEffectConfig
&& maxConfig instanceof EffectGearAttribute.Config
&& maxConfigDisplay != null) {
String effectStr = ((EffectConfigAccessor)minEffectConfig).getAmplifier() + "-" +
maxConfigDisplay.getString();
return new TextComponent(effectStr).withStyle(atr.getReader().getColoredTextStyle());
}
if (minConfig instanceof ManaPerLootAttribute.Config minManaPerLootConfig && maxConfig instanceof ManaPerLootAttribute.Config maxManaPerLootConfig) {
return getManaPerLootComponent(minManaPerLootConfig, maxManaPerLootConfig);
}
if (atrName.equals("the_vault:effect_cloud")){
return new TextComponent("Special ability modification");
}
if (res != null) {
return atr.getReader().formatConfigDisplay(LogicalSide.CLIENT, res);
}
return res;
}
private static @NotNull MutableComponent getManaPerLootComponent(ManaPerLootAttribute.Config minManaPerLootConfig,
ManaPerLootAttribute.Config maxManaPerLootConfig) {
int minGenerated = minManaPerLootConfig.getManaGenerated().getMin();
int maxGenerated = maxManaPerLootConfig.getManaGenerated().getMax();
float minGenChance = minManaPerLootConfig.getManaGenerationChance().getMin();
float maxGenChance = maxManaPerLootConfig.getManaGenerationChance().getMax();
var minToMax = new TextComponent(DECIMAL_FORMAT.format(minGenChance*100) + "%-" + DECIMAL_FORMAT.format(maxGenChance*100) + "%").withStyle(Style.EMPTY.withColor(20479));
var generated = new TextComponent(minGenerated + "-" + maxGenerated).withStyle(Style.EMPTY.withColor(20479));
var loot = new TextComponent(maxManaPerLootConfig.getDisplayName()).withStyle(Style.EMPTY.withColor(20479));
return new TextComponent("").withStyle(Style.EMPTY.withColor(65535)).append(minToMax).append(new TextComponent(" chance to generate ")).append(generated).append(" Mana per ").append(loot).append(" looted");
}
private static <T> @NotNull MutableComponent getAbilityAoePercentageComponent(VaultGearAttribute<T> atr,
AbilityAreaOfEffectPercentAttribute.Config minConfigA,
AbilityAreaOfEffectPercentAttribute.Config maxConfigA) {
float min = minConfigA.getMin();
float max = maxConfigA.generateMaximumValue();
VaultGearModifierReader<T> reader = atr.getReader();
MutableComponent minValueDisplay = new TextComponent(new DecimalFormat("0.#").format(Math.abs(min * 100.0F)) + "%");
MutableComponent maxValueDisplay = new TextComponent(new DecimalFormat("0.#").format(Math.abs(max * 100.0F)) + "%");
boolean positive = min > 0;
MutableComponent areaCmp = new TextComponent("Area Of Effect").withStyle(Style.EMPTY.withColor(ModConfigs.COLORS.getColor("areaOfEffect")));
String cdInfo;
if (positive) {
cdInfo = " more ";
} else {
cdInfo = " less ";
}
return new TextComponent("")
.append(VaultGearModifier.AffixType.IMPLICIT.getAffixPrefixComponent(true)
.withStyle(Style.EMPTY.withColor(6082075)))
.append(minValueDisplay.withStyle(Style.EMPTY.withColor(6082075)))
.append(new TextComponent("-").withStyle(Style.EMPTY.withColor(6082075)))
.append(maxValueDisplay.withStyle(Style.EMPTY.withColor(6082075)))
.append(cdInfo)
.append(areaCmp)
.append(" of ")
.append(
((AbilityFloatValueAttributeReaderInvoker) reader).invokeFormatAbilityName(minConfigA.getAbilityKey()))
.setStyle(reader.getColoredTextStyle());
}
private static MutableComponent getCloudRangeComponent(MutableComponent minConfigDisplay, MutableComponent maxConfigDisplay, VaultGearAttribute<?> atr) {
// <Effect> [<LVL>] Cloud [when Hit]
// Poison Cloud
// Poison III Cloud
var minString = minConfigDisplay.getString();
var maxString = maxConfigDisplay.getString();
String minString = minConfigDisplay.getString();
String maxString = maxConfigDisplay.getString();
var minLvl = getCloudLvl(minString);
var maxLvl = getCloudLvl(maxString);
String minLvl = getCloudLvl(minString);
String maxLvl = getCloudLvl(maxString);
if (minLvl.equals(maxLvl)) {
return minConfigDisplay.withStyle(atr.getReader().getColoredTextStyle());
}
var cloudRange = makeCloudLvlRange(minString, minLvl, maxLvl);
String cloudRange = makeCloudLvlRange(minString, minLvl, maxLvl);
return new TextComponent(cloudRange).withStyle(atr.getReader().getColoredTextStyle());
}
private static String getCloudLvl(String displayString){
var matcher = CLOUD_PATTERN.matcher(displayString);
Matcher matcher = CLOUD_PATTERN.matcher(displayString);
if (matcher.find()) {
if (matcher.group("lvl") != null) {
return matcher.group("lvl");
@ -321,7 +505,7 @@ public class Modifiers {
}
private static String makeCloudLvlRange(String displayString, String minLvl, String maxLvl){
var matcher = CLOUD_PATTERN.matcher(displayString);
Matcher matcher = CLOUD_PATTERN.matcher(displayString);
if (matcher.find()) {
return matcher.group("effect") + " " + minLvl + "-" + maxLvl + " " + matcher.group("suffix");
}
@ -331,15 +515,15 @@ public class Modifiers {
private static MutableComponent abilityLvlComponent(MutableComponent prev, VaultGearAttribute<?> atr,
AbilityLevelAttribute.Config minConfig) {
var abComp = new TextComponent("+").withStyle(atr.getReader().getColoredTextStyle());
var optSkill = ModConfigs.ABILITIES.getAbilityById(minConfig.getAbilityKey());
MutableComponent abComp = new TextComponent("+").withStyle(atr.getReader().getColoredTextStyle());
Optional<Skill> optSkill = ModConfigs.ABILITIES.getAbilityById(minConfig.getAbilityKey());
if (optSkill.isEmpty()) {
return prev.append(" added ability levels").withStyle(atr.getReader().getColoredTextStyle());
}
var abName = optSkill.get().getName();
var parts = prev.getString().split("-");
String abName = optSkill.get().getName();
String[] parts = prev.getString().split("-");
var res = new TextComponent("").withStyle(prev.getStyle());
MutableComponent res = new TextComponent("").withStyle(prev.getStyle());
if (parts.length == 2) {
if (parts[0].equals(parts[1])) {
res.append(parts[0]);
@ -356,7 +540,7 @@ public class Modifiers {
abComp.append(new TextComponent(abName).withStyle(Style.EMPTY.withColor(14076214)));
return abComp;
}
private static int modTierListWeight(List<VaultGearTierConfig.ModifierTier<?>> val) {
if (val == null || val.isEmpty()) {
return 0;

View file

@ -0,0 +1,12 @@
package com.radimous.vhatcaniroll.mixin;
import iskallia.vault.gear.attribute.ability.AbilityFloatValueAttribute;
import net.minecraft.network.chat.MutableComponent;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Invoker;
@Mixin(value = AbilityFloatValueAttribute.Reader.class, remap = false)
public interface AbilityFloatValueAttributeReaderInvoker {
@Invoker
MutableComponent invokeFormatAbilityName(String abilityKey);
}

View file

@ -59,7 +59,7 @@ public class StatisticsElementContainerScreenMixin extends AbstractSkillTabEleme
})
);
// add chestplate icon to it
var chestplateStack = new ItemStack(ModItems.CHESTPLATE);
ItemStack chestplateStack = new ItemStack(ModItems.CHESTPLATE);
this.addElement(
new FakeItemSlotElement<>(Spatials.positionXY(-3, 3), () -> chestplateStack, () -> false, ScreenTextures.EMPTY, ScreenTextures.EMPTY
).layout(

View file

@ -0,0 +1,18 @@
package com.radimous.vhatcaniroll.mixin;
import iskallia.vault.config.UniqueGearConfig;
import iskallia.vault.core.util.WeightedList;
import net.minecraft.resources.ResourceLocation;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Accessor;
import java.util.Map;
@Mixin(value = UniqueGearConfig.class, remap = false)
public interface UniqueGearConfigAccessor {
@Accessor
Map<ResourceLocation, UniqueGearConfig.Entry> getRegistry();
@Accessor
Map<ResourceLocation, WeightedList<ResourceLocation>> getPools();
}

View file

@ -0,0 +1,250 @@
package com.radimous.vhatcaniroll.ui;
import com.mojang.blaze3d.systems.RenderSystem;
import com.mojang.blaze3d.vertex.PoseStack;
import com.radimous.vhatcaniroll.Config;
import com.radimous.vhatcaniroll.logic.ModifierCategory;
import iskallia.vault.client.atlas.TextureAtlasRegion;
import iskallia.vault.client.gui.framework.ScreenTextures;
import iskallia.vault.client.gui.framework.element.ButtonElement;
import iskallia.vault.client.gui.framework.element.DynamicLabelElement;
import iskallia.vault.client.gui.framework.element.FakeItemSlotElement;
import iskallia.vault.client.gui.framework.element.LabelElement;
import iskallia.vault.client.gui.framework.element.NineSliceButtonElement;
import iskallia.vault.client.gui.framework.element.VerticalScrollClipContainer;
import iskallia.vault.client.gui.framework.render.spi.IElementRenderer;
import iskallia.vault.client.gui.framework.screen.layout.ScreenLayout;
import iskallia.vault.client.gui.framework.spatial.Spatials;
import iskallia.vault.client.gui.framework.spatial.spi.IPosition;
import iskallia.vault.client.gui.framework.spatial.spi.ISpatial;
import iskallia.vault.client.gui.framework.text.LabelTextStyle;
import iskallia.vault.config.gear.VaultGearWorkbenchConfig;
import iskallia.vault.gear.VaultGearState;
import iskallia.vault.gear.attribute.VaultGearModifier;
import iskallia.vault.gear.data.VaultGearData;
import iskallia.vault.init.ModGearAttributes;
import net.minecraft.ChatFormatting;
import net.minecraft.client.Minecraft;
import net.minecraft.client.player.LocalPlayer;
import net.minecraft.network.chat.MutableComponent;
import net.minecraft.network.chat.Style;
import net.minecraft.network.chat.TextColor;
import net.minecraft.network.chat.TextComponent;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.Items;
import org.jetbrains.annotations.NotNull;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Supplier;
import static iskallia.vault.client.gui.framework.ScreenTextures.BUTTON_EMPTY;
import static iskallia.vault.client.gui.framework.ScreenTextures.BUTTON_EMPTY_16_48_TEXTURES;
import static iskallia.vault.client.gui.framework.ScreenTextures.BUTTON_EMPTY_DISABLED;
public class CraftedModifiersListContainer extends VerticalScrollClipContainer<CraftedModifiersListContainer>
implements InnerGearScreen {
public CraftedModifiersListContainer(ISpatial spatial, int lvl, ModifierCategory modifierCategory,
ItemStack gearPiece) {
super(spatial);
int labelX = 9;
int labelY = 0;
LocalPlayer player = Minecraft.getInstance().player;
if (player == null) {
return;
}
ItemStack stackCopy = gearPiece.copy();
VaultGearData gearData = VaultGearData.read(stackCopy);
gearData.setItemLevel(lvl);
gearData.setState(VaultGearState.IDENTIFIED);
gearData.createOrReplaceAttributeValue(ModGearAttributes.PREFIXES, 1);
gearData.createOrReplaceAttributeValue(ModGearAttributes.SUFFIXES, 1);
gearData.write(stackCopy);
List<VaultGearWorkbenchConfig.CraftableModifierConfig> crMods = VaultGearWorkbenchConfig.getConfig(gearPiece.getItem())
.map(VaultGearWorkbenchConfig::getAllCraftableModifiers).orElse(null);
if (crMods == null) {
cookieDialog();
return;
}
for (VaultGearWorkbenchConfig.CraftableModifierConfig mod : crMods) {
boolean disabled = false;
// is unlocked?
MutableComponent fullCmp = new TextComponent("");
VaultGearModifier<?> mm = mod.createModifier().orElse(null);
if (mm == null) {
continue;
}
Optional<MutableComponent> oCfgDisplay = mm.getConfigDisplay(gearPiece);
oCfgDisplay.ifPresent(fullCmp::append);
MutableComponent restriction = new TextComponent("");
int minLevel = mod.getMinLevel();
if (mod.getUnlockCategory() == VaultGearWorkbenchConfig.UnlockCategory.LEVEL && lvl < minLevel) {
if (!Config.SHOW_UNOBTAINABLE_CRAFTED.get()){
continue;
}
restriction.append(new TextComponent(" LVL " + minLevel + "+").withStyle(ChatFormatting.DARK_RED));
disabled = true;
}
if (mod.getUnlockCategory() == VaultGearWorkbenchConfig.UnlockCategory.VAULT_DISCOVERY && !mod.hasPrerequisites(player)) {
if (minLevel > lvl) {
if (!Config.SHOW_UNOBTAINABLE_CRAFTED.get()){
continue;
}
restriction.append(new TextComponent(" ARCHIVE").withStyle(ChatFormatting.DARK_RED));
} else {
restriction.append(new TextComponent(" ARCHIVE").withStyle(Style.EMPTY.withColor(TextColor.parseColor("#ff6f00"))));
}
disabled = true;
}
LabelElement<?> labelelement = new LabelElement<>(
Spatials.positionXY(8, labelY + 5).width(this.innerHeight() - labelX), fullCmp,
LabelTextStyle.defaultStyle().shadow() // WHY DOESN'T SHADOW WORK?
);
NineSliceButtonElement<?> btn = new NineSliceButtonElement<>(Spatials.positionXY(0, labelY ).width(innerWidth()).height(18),
new NineSliceButtonElement.NineSliceButtonTextures(BUTTON_EMPTY, BUTTON_EMPTY, BUTTON_EMPTY, BUTTON_EMPTY_DISABLED), () -> {});
//align right
LabelElement<?> restrictionLabel = new LabelElement<>(
Spatials.positionXY(btn.right() - 70, labelY + 5).width(this.innerHeight() - labelX).height(14), restriction,
LabelTextStyle.defaultStyle().border4()
);
btn.setDisabled(disabled);
this.addElement(btn);
this.addElement(labelelement);
this.addElement(restrictionLabel);
labelY += 18;
}
}
public float getScroll() {
return 0;
}
public void setScroll(float scroll) {
}
@Override
public InnerGearScreen create(ISpatial spatial, int lvl, ModifierCategory modifierCategory, ItemStack gearPiece) {
return new CraftedModifiersListContainer(spatial, lvl, modifierCategory, gearPiece);
}
// :)
private void cookieDialog(){
var noModifiers = new LabelElement<>(Spatials.positionXY(innerWidth()/2 - 60, 20).width(18).height(18), new TextComponent("No crafted modifiers found."), LabelTextStyle.defaultStyle().border4().center());
var wantCookie = new LabelElement<>(Spatials.positionXY(innerWidth()/2 - 50, 80).width(18).height(18), new TextComponent("Would you like a cookie?"), LabelTextStyle.defaultStyle().border4().center());
var yesBtn = new ButtonElement<>(Spatials.positionXY(innerWidth()/2 - 20, 100).width(100).height(20), BUTTON_EMPTY_16_48_TEXTURES, () -> {});
var noBtn = new ButtonElement<>(Spatials.positionXY(innerWidth()/2 - 20, 120).width(100).height(20), BUTTON_EMPTY_16_48_TEXTURES, () -> { /* sad cookie monster noises */});
var yesLabel = new LabelElement<>(Spatials.positionXY(innerWidth()/2 - 6, 105).width(18).height(18), new TextComponent("Yes"), LabelTextStyle.defaultStyle().border4().center());
var noLabel = new LabelElement<>(Spatials.positionXY(innerWidth()/2 - 3, 125).width(18).height(18), new TextComponent("No"), LabelTextStyle.defaultStyle().border4().center());
var sadCookie = new LabelElement<>(Spatials.positionXY(innerWidth()/2 - 65, 145).width(18).height(18), new TextComponent("*Sad cookie monster noises*").withStyle(ChatFormatting.GRAY), LabelTextStyle.defaultStyle().center());
yesBtn.setOnClick(() -> {
this.removeElement(noModifiers);
this.removeElement(wantCookie);
this.removeElement(yesBtn);
this.removeElement(noBtn);
this.removeElement(yesLabel);
this.removeElement(noLabel);
this.removeElement(sadCookie);
ScreenLayout.requestLayout();
cookie();
});
noBtn.setOnClick(() -> {
this.addElement(sadCookie);
noBtn.setDisabled(true);
ScreenLayout.requestLayout();
});
this.addElement(noModifiers);
this.addElement(wantCookie);
this.addElement(yesLabel);
this.addElement(noLabel);
this.addElement(noBtn);
this.addElement(yesBtn);
}
private void cookie(){
AtomicInteger counter = new AtomicInteger(0);
var slot = new ScaledFakeItemSlotElement<>(Spatials.positionXY(innerWidth()/2, innerHeight()/2), () -> new ItemStack(Items.COOKIE), () -> false, ScreenTextures.EMPTY, ScreenTextures.EMPTY,8*16,8*16, 8f);
slot.whenClicked(counter::getAndIncrement);
this.addElement(slot);
this.addElement(new CookieLabelElement(Spatials.positionXY(innerWidth()/2, innerHeight()/2 - 70).width(18).height(18), counter::get, LabelTextStyle.defaultStyle().border4().center()));
}
private class CookieLabelElement extends DynamicLabelElement<Integer, CookieLabelElement>{
public CookieLabelElement(IPosition position,
Supplier<Integer> valueSupplier, LabelTextStyle.Builder labelTextStyle) {
super(position, valueSupplier, labelTextStyle);
}
@Override protected void onValueChanged(Integer count) {
this.set(new TextComponent(count.toString()));
}
@Override public void render(IElementRenderer renderer, @NotNull PoseStack poseStack, int mouseX, int mouseY,
float partialTick) {
if (this.valueSupplier.get() == 0) {
return;
}
PoseStack viewStack = RenderSystem.getModelViewStack();
viewStack.pushPose();
float scale = 2f;
viewStack.scale(scale, scale, scale);
viewStack.translate(-getWorldSpatial().x() * (1 - 1/scale), -getWorldSpatial().y() * (1 - 1/scale), 0);
RenderSystem.applyModelViewMatrix();
super.render(renderer, poseStack, mouseX, mouseY, partialTick);
viewStack.popPose();
}
}
private static class ScaledFakeItemSlotElement <E extends ScaledFakeItemSlotElement<E>> extends FakeItemSlotElement<E> {
private float scale;
private long lastClicked = 0;
public ScaledFakeItemSlotElement(ISpatial spatial, Supplier<ItemStack> itemStack, Supplier<Boolean> disabled, TextureAtlasRegion slotTexture, TextureAtlasRegion disabledSlotTexture, int width, int height, float scale) {
super(Spatials.positionX((int) (spatial.x() - (scale * 9))).positionY((int) (spatial.y() - (scale * 9))), itemStack, disabled, slotTexture, disabledSlotTexture, width, height);
this.scale = scale;
}
@Override public void render(IElementRenderer renderer, @NotNull PoseStack poseStack, int mouseX, int mouseY, float partialTick) {
float originalScale = scale;
long msDiff = System.currentTimeMillis() - lastClicked;
if (msDiff < 150) {
scale *= 1 + msDiff * 0.001f;
} else if (msDiff < 300) {
scale *= 1 + (300 - msDiff) * 0.001f;
}
PoseStack viewStack = RenderSystem.getModelViewStack();
viewStack.pushPose();
viewStack.translate(- (scale - originalScale) * originalScale, - (scale - originalScale) * originalScale, 0);
viewStack.scale(scale, scale, 1);
viewStack.translate(-getWorldSpatial().x() * (1 - 1/scale), -getWorldSpatial().y() * (1 - 1/scale), 0);
RenderSystem.applyModelViewMatrix();
super.render(renderer, poseStack, mouseX, mouseY, partialTick);
viewStack.popPose();
scale = originalScale;
}
@Override public boolean mouseClicked(double mouseX, double mouseY, int buttonIndex) {
if (this.isEnabled() && this.containsMouse(mouseX, mouseY) && buttonIndex == 0)
lastClicked = System.currentTimeMillis();
return super.mouseClicked(mouseX, mouseY, buttonIndex);
}
}
}

View file

@ -17,6 +17,8 @@ import iskallia.vault.client.gui.framework.element.NineSliceButtonElement;
import iskallia.vault.client.gui.framework.element.NineSliceElement;
import iskallia.vault.client.gui.framework.element.TabElement;
import iskallia.vault.client.gui.framework.element.TextureAtlasElement;
import iskallia.vault.client.gui.framework.element.VerticalScrollClipContainer;
import iskallia.vault.client.gui.framework.element.spi.ILayoutElement;
import iskallia.vault.client.gui.framework.element.spi.ILayoutStrategy;
import iskallia.vault.client.gui.framework.render.ScreenTooltipRenderer;
import iskallia.vault.client.gui.framework.render.TooltipDirection;
@ -27,10 +29,16 @@ import iskallia.vault.client.gui.framework.spatial.Spatials;
import iskallia.vault.client.gui.framework.spatial.spi.IPosition;
import iskallia.vault.client.gui.framework.spatial.spi.ISpatial;
import iskallia.vault.client.gui.framework.text.LabelTextStyle;
import iskallia.vault.gear.VaultGearState;
import iskallia.vault.gear.data.VaultGearData;
import iskallia.vault.init.ModBlocks;
import iskallia.vault.init.ModGearAttributes;
import iskallia.vault.init.ModItems;
import net.minecraft.ChatFormatting;
import net.minecraft.client.Minecraft;
import net.minecraft.network.chat.TextComponent;
import net.minecraft.network.chat.TranslatableComponent;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.item.ItemStack;
import net.minecraftforge.fml.config.ModConfig;
@ -39,19 +47,23 @@ import java.util.List;
public class GearModifierScreen extends AbstractElementScreen {
//TODO: remove magic numbers
private ModifierListContainer modifierList;
private InnerGearScreen innerScreen;
private NineSliceButtonElement<?> minusButton;
private NineSliceButtonElement<?> plusButton;
private LabelElement<?> minusLabel;
private LabelElement<?> plusLabel;
private final ScrollableLvlInputElement lvlInput;
private ModifierCategory modifierCategory = ModifierCategory.NORMAL;
private LabelElement<?> modifierCategoryLabel;
private HelpContainer helpContainer;
private NineSliceButtonElement<?> modifierCategoryButton;
private final HelpContainer helpContainer;
private final LabelElement<?> windowNameLabel;
private int currIndex = 0;
private final List<TabElement<?>> tabs = new ArrayList<>();
public GearModifierScreen() {
super(new TranslatableComponent("vhatcaniroll.screen.title"), ScreenRenderers.getBuffered(), ScreenTooltipRenderer::create);
super(new TextComponent("VHat can I roll?"), ScreenRenderers.getBuffered(), ScreenTooltipRenderer::create);
// make screen size 95% of the window height and width that looks good
this.setGuiSize(Spatials.size(340, 300).height((int) (
(Minecraft.getInstance().getWindow().getHeight() / Minecraft.getInstance().getWindow().getGuiScale()) *
@ -66,10 +78,10 @@ public class GearModifierScreen extends AbstractElementScreen {
// window title
LabelElement<?> windowName = new LabelElement<>(
Spatials.positionXY(7, 38).size(this.getGuiSpatial().width() / 2 - 7, 20),
this.title.copy().withStyle(ChatFormatting.BLACK),
new TranslatableComponent("vhatcaniroll.screen.title.random").withStyle(ChatFormatting.BLACK),
LabelTextStyle.defaultStyle()
).layout(this.translateWorldSpatial());
this.windowNameLabel = windowName;
this.addElement(background);
this.addElement(windowName);
@ -84,13 +96,18 @@ public class GearModifierScreen extends AbstractElementScreen {
// inner black window
ISpatial modListSpatial = Spatials.positionXY(7, 50).size(this.getGuiSpatial().width() - 14, this.getGuiSpatial().height() - 57);
this.modifierList = new ModifierListContainer(modListSpatial, lvlInput.getValue(), modifierCategory, getCurrGear()).layout(this.translateWorldSpatial());
this.addElement(this.modifierList);
this.innerScreen = new ModifierListContainer(modListSpatial, lvlInput.getValue(), modifierCategory, getCurrGear()).layout(this.translateWorldSpatial());
this.addElement(this.innerScreen);
// help container will overlay the modifier list
this.helpContainer = new HelpContainer(Spatials.positionXY(0, 0).size(0, 0));
createHelpButton(helpContainer);
this.addElement(helpContainer);
createModifierButton();
createTransmogButton();
createCraftedModsButton();
createUniqueGearButton();
}
// helper methods
@ -104,21 +121,103 @@ public class GearModifierScreen extends AbstractElementScreen {
* @param keepScroll whether to keep the current scroll position
*/
private void updateModifierList(boolean keepScroll) {
var oldScroll = this.modifierList.getScroll();
this.removeElement(this.modifierList);
float oldScroll = this.innerScreen.getScroll();
this.removeElement(this.innerScreen);
ISpatial modListSpatial = Spatials.positionXY(7, 50).size(this.getGuiSpatial().width() - 14, this.getGuiSpatial().height() - 57);
this.modifierList = new ModifierListContainer(modListSpatial, lvlInput.getValue(), modifierCategory, getCurrGear()).layout(this.translateWorldSpatial());
if (keepScroll) {
this.modifierList.setScroll(oldScroll);
this.innerScreen = this.innerScreen.create(modListSpatial, lvlInput.getValue(), modifierCategory, getCurrGear());
if (this.innerScreen instanceof ILayoutElement<?> layoutElement) {
layoutElement.layout(this.translateWorldSpatial());
}
this.addElement(this.modifierList);
if (keepScroll) {
this.innerScreen.setScroll(oldScroll);
}
this.addElement(this.innerScreen);
ScreenLayout.requestLayout();
}
private void switchToTransmog(){
this.removeElement(this.innerScreen);
this.modifierCategory = ModifierCategory.NORMAL;
updateModifierCategoryButtonLabel();
ISpatial modListSpatial = Spatials.positionXY(7, 50).size(this.getGuiSpatial().width() - 14, this.getGuiSpatial().height() - 57);
this.innerScreen = new TransmogListContainer(modListSpatial, getCurrGear()).layout(this.translateWorldSpatial());
this.disableCategoryButtons();
this.disableLvlButtons();
this.windowNameLabel.set(new TranslatableComponent("vhatcaniroll.screen.title.transmogs").withStyle(ChatFormatting.BLACK));
this.addElement(this.innerScreen);
ScreenLayout.requestLayout();
}
private void switchToModifiers(){
this.removeElement(this.innerScreen);
ISpatial modListSpatial = Spatials.positionXY(7, 50).size(this.getGuiSpatial().width() - 14, this.getGuiSpatial().height() - 57);
this.innerScreen = new ModifierListContainer(modListSpatial, lvlInput.getValue(), modifierCategory, getCurrGear()).layout(this.translateWorldSpatial());
this.enableCategoryButtons();
this.enableLvlButtons();
this.windowNameLabel.set(new TranslatableComponent("vhatcaniroll.screen.title.random").withStyle(ChatFormatting.BLACK));
this.addElement(this.innerScreen);
ScreenLayout.requestLayout();
}
private void switchToCrafted(){
this.removeElement(this.innerScreen);
this.modifierCategory = ModifierCategory.NORMAL;
updateModifierCategoryButtonLabel();
ISpatial modListSpatial = Spatials.positionXY(7, 50).size(this.getGuiSpatial().width() - 14, this.getGuiSpatial().height() - 57);
this.innerScreen = new CraftedModifiersListContainer(modListSpatial, lvlInput.getValue(), modifierCategory, getCurrGear()).layout(this.translateWorldSpatial());
this.enableLvlButtons();
this.disableCategoryButtons();
this.windowNameLabel.set(new TranslatableComponent("vhatcaniroll.screen.title.crafted").withStyle(ChatFormatting.BLACK));
this.addElement(this.innerScreen);
ScreenLayout.requestLayout();
}
private void switchToUnique(){
this.removeElement(this.innerScreen);
this.modifierCategory = ModifierCategory.NORMAL;
updateModifierCategoryButtonLabel();
ISpatial modListSpatial = Spatials.positionXY(7, 50).size(this.getGuiSpatial().width() - 14, this.getGuiSpatial().height() - 57);
this.innerScreen = new UniqueGearListContainer(modListSpatial, lvlInput.getValue(), modifierCategory, getCurrGear()).layout(this.translateWorldSpatial());
this.enableLvlButtons();
this.disableCategoryButtons();
this.windowNameLabel.set(new TranslatableComponent("vhatcaniroll.screen.title.unique").withStyle(ChatFormatting.BLACK));
this.addElement(this.innerScreen);
ScreenLayout.requestLayout();
}
private void enableCategoryButtons(){
this.modifierCategoryLabel.setVisible(true);
this.modifierCategoryButton.setVisible(true);
this.modifierCategoryButton.setDisabled(false);
}
private void disableCategoryButtons(){
this.modifierCategoryLabel.setVisible(false);
this.modifierCategoryButton.setVisible(false);
this.modifierCategoryButton.setDisabled(true);
}
private void enableLvlButtons(){
this.lvlInput.setVisible(true);
this.minusButton.setVisible(true);
this.minusLabel.setVisible(true);
this.plusButton.setVisible(true);
this.plusLabel.setVisible(true);
}
private void disableLvlButtons(){
this.lvlInput.setVisible(false);
this.minusButton.setVisible(false);
this.minusLabel.setVisible(false);
this.plusButton.setVisible(false);
this.plusLabel.setVisible(false);
}
// pulled from QuestOverviewElementScreen
private ILayoutStrategy translateWorldSpatial() {
return (screen, gui, parent, world) -> world.translateXY(this.getGuiSpatial());
@ -209,7 +308,6 @@ public class GearModifierScreen extends AbstractElementScreen {
Minecraft.getInstance().font)
.layout(this.translateWorldSpatial())
);
inputElement.onTextChanged(s -> updateModifierList(true));
return inputElement;
}
@ -229,19 +327,21 @@ public class GearModifierScreen extends AbstractElementScreen {
NineSliceButtonElement<?> btnPlus =
new NineSliceButtonElement<>(Spatials.positionXY(this.getGuiSpatial().width() - 25 - 13, 35).size(15, 14),
ScreenTextures.BUTTON_EMPTY_TEXTURES, lvlInput::increment).layout(this.translateWorldSpatial());
this.addElement(btnMinus);
this.addElement(minusLabel);
this.addElement(plusLabel);
this.addElement(btnPlus);
this.minusButton = this.addElement(btnMinus);
this.minusLabel = this.addElement(minusLabel);
this.plusLabel = this.addElement(plusLabel);
this.plusButton = this.addElement(btnPlus);
}
private void nextModifierCategory() {
if (!(this.innerScreen instanceof ModifierListContainer)) return;
this.modifierCategory = modifierCategory.next();
updateModifierCategoryButtonLabel();
updateModifierList(true);
}
private void previousModifierCategory() {
if (!(this.innerScreen instanceof ModifierListContainer)) return;
this.modifierCategory = modifierCategory.previous();
updateModifierCategoryButtonLabel();
updateModifierList(true);
@ -269,6 +369,7 @@ public class GearModifierScreen extends AbstractElementScreen {
}
}).layout(this.translateWorldSpatial());
this.addElement(btnLegend);
this.modifierCategoryButton = btnLegend;
}
private void createConfigButton(){
@ -294,6 +395,78 @@ public class GearModifierScreen extends AbstractElementScreen {
);
}
private void createModifierButton() {
this.addElement(new ButtonElement<>(Spatials.positionXY(-3, 3), ScreenTextures.BUTTON_EMPTY_16_TEXTURES, () -> {
if (!(this.innerScreen instanceof ModifierListContainer))
switchToModifiers();
})).layout((screen, gui, parent, world) -> {
world.width(21).height(21).translateX(gui.left() - 16).translateY(this.getGuiSpatial().top() + 50);
}).tooltip(
Tooltips.single(TooltipDirection.LEFT, () -> new TranslatableComponent("vhatcaniroll.screen.title.random"))
);
ItemStack chestplateStack = new ItemStack(ModItems.CHESTPLATE);
this.addElement(
new FakeItemSlotElement<>(Spatials.positionXY(-3, 3), () -> chestplateStack, () -> false, ScreenTextures.EMPTY, ScreenTextures.EMPTY)
.layout((screen, gui, parent, world) -> world.width(21).height(21).translateX(gui.left() - 16).translateY(this.getGuiSpatial().top() + 50))
);
}
private void createUniqueGearButton() {
this.addElement(new ButtonElement<>(Spatials.positionXY(-3, 3), ScreenTextures.BUTTON_EMPTY_16_TEXTURES, () -> {
if (!(this.innerScreen instanceof UniqueGearListContainer))
switchToUnique();
})).layout((screen, gui, parent, world) -> {
world.width(21).height(21).translateX(gui.left() - 16).translateY(this.getGuiSpatial().top() + 70);
}).tooltip(
Tooltips.single(TooltipDirection.LEFT, () -> new TranslatableComponent("vhatcaniroll.screen.title.unique"))
);
ItemStack chestplateStack = new ItemStack(ModItems.CHESTPLATE);
VaultGearData gearData = VaultGearData.read(chestplateStack);
gearData.createOrReplaceAttributeValue(ModGearAttributes.GEAR_ROLL_TYPE, "Unique");
gearData.write(chestplateStack);
this.addElement(
new FakeItemSlotElement<>(Spatials.positionXY(-3, 3), () -> chestplateStack, () -> false, ScreenTextures.EMPTY, ScreenTextures.EMPTY)
.layout((screen, gui, parent, world) -> world.width(21).height(21).translateX(gui.left() - 16).translateY(this.getGuiSpatial().top() + 70))
);
}
private void createTransmogButton() {
this.addElement(new ButtonElement<>(Spatials.positionXY(-3, 3), ScreenTextures.BUTTON_EMPTY_16_TEXTURES, () -> {
if (!(this.innerScreen instanceof TransmogListContainer))
switchToTransmog();
})).layout((screen, gui, parent, world) -> {
world.width(21).height(21).translateX(gui.left() - 16).translateY(this.getGuiSpatial().top() + 90);
}).tooltip(
Tooltips.single(TooltipDirection.LEFT, () -> new TranslatableComponent("vhatcaniroll.screen.title.transmogs"))
);
ItemStack chestplateStack = new ItemStack(ModItems.CHESTPLATE);
VaultGearData gearData = VaultGearData.read(chestplateStack);
gearData.setState(VaultGearState.IDENTIFIED);
gearData.createOrReplaceAttributeValue(ModGearAttributes.GEAR_MODEL, new ResourceLocation("the_vault:gear/armor/flamingo/chestplate"));
gearData.write(chestplateStack);
this.addElement(
new FakeItemSlotElement<>(Spatials.positionXY(-3, 3), () -> chestplateStack, () -> false, ScreenTextures.EMPTY, ScreenTextures.EMPTY)
.layout((screen, gui, parent, world) -> world.width(21).height(21).translateX(gui.left() - 16).translateY(this.getGuiSpatial().top() + 90))
);
}
private void createCraftedModsButton() {
this.addElement(new ButtonElement<>(Spatials.positionXY(-3, 3), ScreenTextures.BUTTON_EMPTY_16_TEXTURES, () -> {
if (!(this.innerScreen instanceof CraftedModifiersListContainer))
switchToCrafted();
})).layout((screen, gui, parent, world) -> {
world.width(21).height(21).translateX(gui.left() - 16).translateY(this.getGuiSpatial().top() + 110);
}).tooltip(
Tooltips.single(TooltipDirection.LEFT, () -> new TranslatableComponent("vhatcaniroll.screen.title.crafted"))
);
ItemStack workbenchStack = new ItemStack(ModBlocks.MODIFIER_WORKBENCH);
this.addElement(
new FakeItemSlotElement<>(Spatials.positionXY(-3, 3), () -> workbenchStack, () -> false, ScreenTextures.EMPTY, ScreenTextures.EMPTY)
.layout((screen, gui, parent, world) -> world.width(21).height(21).translateX(gui.left() - 16).translateY(this.getGuiSpatial().top() + 110))
);
}
@Override
public boolean keyPressed(int keyCode, int scanCode, int modifiers) {
// left/right to increase/decrease lvl
@ -305,10 +478,14 @@ public class GearModifierScreen extends AbstractElementScreen {
}
// up/down to scroll up/down
if (keyCode == InputConstants.KEY_K || keyCode == InputConstants.KEY_UP) {
this.modifierList.onMouseScrolled(0, 0, 1);
if (this.innerScreen instanceof VerticalScrollClipContainer<?> vsc){
vsc.onMouseScrolled(0,0,1);
}
}
if (keyCode == InputConstants.KEY_J || keyCode == InputConstants.KEY_DOWN) {
this.modifierList.onMouseScrolled(0, 0, -1);
if (this.innerScreen instanceof VerticalScrollClipContainer<?> vsc){
vsc.onMouseScrolled(0,0,-1);
}
}
// tab to next gear item
if (keyCode == InputConstants.KEY_TAB && !hasShiftDown()) {

View file

@ -15,21 +15,21 @@ public class HelpContainer extends ContainerElement<HelpContainer> {
super(spatial);
this.setVisible(false); // Hide by default
var tabLabel = new LabelElement<>(
LabelElement<?> tabLabel = new LabelElement<>(
Spatials.positionXY(336, 16).width(16).height(16),
new TextComponent("TAB").withStyle(ChatFormatting.GOLD),
LabelTextStyle.shadow()
).layout(this.translateWorldSpatial());
this.addElement(tabLabel);
var shiftTabLabel = new LabelElement<>(
LabelElement<?> shiftTabLabel = new LabelElement<>(
Spatials.positionXY(-60, 16).width(16).height(16),
new TextComponent("SHIFT + TAB").withStyle(ChatFormatting.GOLD),
LabelTextStyle.shadow()
).layout(this.translateWorldSpatial());
this.addElement(shiftTabLabel);
var arrows = new LabelElement<>(
LabelElement<?> arrows = new LabelElement<>(
Spatials.positionXY(260, 54).width(16).height(16),
new TextComponent("").withStyle(ChatFormatting.GOLD)
.append(new TextComponent("scroll").withStyle(ChatFormatting.BLUE))
@ -38,7 +38,7 @@ public class HelpContainer extends ContainerElement<HelpContainer> {
).layout(this.translateWorldSpatial());
this.addElement(arrows);
var vimArrows = new LabelElement<>(
LabelElement<?> vimArrows = new LabelElement<>(
Spatials.positionXY(262, 64).width(16).height(16),
new TextComponent("h ").withStyle(ChatFormatting.GOLD)
.append(new TextComponent("wheel").withStyle(ChatFormatting.BLUE))
@ -47,42 +47,42 @@ public class HelpContainer extends ContainerElement<HelpContainer> {
).layout(this.translateWorldSpatial());
this.addElement(vimArrows);
var ctrlLabel = new LabelElement<>(
Spatials.positionXY(340, 38).width(16).height(16),
LabelElement<?> ctrlLabel = new LabelElement<>(
Spatials.positionXY(365, 38).width(16).height(16),
new TextComponent("CTRL").withStyle(ChatFormatting.GOLD),
LabelTextStyle.shadow()
).layout(this.translateWorldSpatial());
this.addElement(ctrlLabel);
var categoryLabelNormal = new LabelElement<>(
Spatials.positionXY(350, 52).width(16).height(16),
LabelElement<?> categoryLabelNormal = new LabelElement<>(
Spatials.positionXY(375, 52).width(16).height(16),
new TextComponent(ModifierCategory.NORMAL.name()).withStyle(ModifierCategory.NORMAL.getStyle()),
LabelTextStyle.shadow()
).layout(this.translateWorldSpatial());
this.addElement(categoryLabelNormal);
var categoryLabelGreater = new LabelElement<>(
Spatials.positionXY(350, 62).width(16).height(16),
LabelElement<?> categoryLabelGreater = new LabelElement<>(
Spatials.positionXY(375, 62).width(16).height(16),
new TextComponent(ModifierCategory.GREATER.name()).withStyle(ModifierCategory.GREATER.getStyle()),
LabelTextStyle.shadow()
).layout(this.translateWorldSpatial());
this.addElement(categoryLabelGreater);
var categoryLabelLegendary = new LabelElement<>(
Spatials.positionXY(350, 72).width(16).height(16),
LabelElement<?> categoryLabelLegendary = new LabelElement<>(
Spatials.positionXY(375, 72).width(16).height(16),
new TextComponent(ModifierCategory.LEGENDARY.name()).withStyle(ModifierCategory.LEGENDARY.getStyle()),
LabelTextStyle.shadow()
).layout(this.translateWorldSpatial());
this.addElement(categoryLabelLegendary);
var upLabel = new LabelElement<>(
Spatials.positionXY(340, 150).width(16).height(16),
LabelElement<?> upLabel = new LabelElement<>(
Spatials.positionXY(340, 190).width(16).height(16),
new TextComponent("↑ k").withStyle(ChatFormatting.GOLD),
LabelTextStyle.shadow()
).layout(this.translateWorldSpatial());
this.addElement(upLabel);
var downLabel = new LabelElement<>(
Spatials.positionXY(340, 164).width(16).height(16),
LabelElement<?> downLabel = new LabelElement<>(
Spatials.positionXY(340, 204).width(16).height(16),
new TextComponent("↓ j").withStyle(ChatFormatting.GOLD),
LabelTextStyle.shadow()
).layout(this.translateWorldSpatial());
@ -100,10 +100,10 @@ public class HelpContainer extends ContainerElement<HelpContainer> {
rolled together.
""";
var array = text.split("\n");
String[] array = text.split("\n");
int labelY = 120;
for (String s : array) {
var textLabel = new LabelElement<>(
LabelElement<?> textLabel = new LabelElement<>(
Spatials.positionXY(-100, labelY).width(20).height(15),
new TextComponent(s).withStyle(ChatFormatting.GOLD), LabelTextStyle.shadow()
).layout(this.translateWorldSpatial());

View file

@ -0,0 +1,12 @@
package com.radimous.vhatcaniroll.ui;
import com.radimous.vhatcaniroll.logic.ModifierCategory;
import iskallia.vault.client.gui.framework.element.spi.IElement;
import iskallia.vault.client.gui.framework.spatial.spi.ISpatial;
import net.minecraft.world.item.ItemStack;
public interface InnerGearScreen extends IElement {
float getScroll();
void setScroll(float scroll);
InnerGearScreen create(ISpatial spatial, int lvl, ModifierCategory modifierCategory, ItemStack gearPiece);
}

View file

@ -10,6 +10,7 @@ import iskallia.vault.client.gui.framework.spatial.spi.ISpatial;
import iskallia.vault.client.gui.framework.text.LabelTextStyle;
import iskallia.vault.config.gear.VaultGearTierConfig;
import net.minecraft.ChatFormatting;
import net.minecraft.network.chat.Component;
import net.minecraft.network.chat.TextComponent;
import net.minecraft.world.item.ItemStack;
@ -17,15 +18,13 @@ import java.util.Optional;
import com.radimous.vhatcaniroll.logic.Modifiers;
public class ModifierListContainer extends VerticalScrollClipContainer<ModifierListContainer> {
public class ModifierListContainer extends VerticalScrollClipContainer<ModifierListContainer> implements InnerGearScreen {
public ModifierListContainer(ISpatial spatial, int lvl, ModifierCategory modifierCategory, ItemStack gearPiece) {
super(spatial, Padding.ZERO, ScreenTextures.INSET_BLACK_BACKGROUND);
int labelX = 9;
int labelY = 20;
Optional<VaultGearTierConfig> optCfg = VaultGearTierConfig.getConfig(gearPiece);
// Label for the item name and level (GOLD if legendary, AQUA if greater, WHITE if common)
LabelElement<?> itemName = new LabelElement<>(
Spatials.positionXY(labelX, 5).width(this.innerWidth() - labelX).height(15), new TextComponent(
@ -34,10 +33,10 @@ public class ModifierListContainer extends VerticalScrollClipContainer<ModifierL
);
this.addElement(itemName);
Optional<VaultGearTierConfig> optCfg = VaultGearTierConfig.getConfig(gearPiece);
if (optCfg.isPresent()) {
VaultGearTierConfig cfg = optCfg.get();
for (var modifier : Modifiers.getModifierList(lvl, cfg, modifierCategory)) {
for (Component modifier : Modifiers.getModifierList(lvl, cfg, modifierCategory)) {
LabelElement<?> labelelement = new LabelElement<>(
Spatials.positionXY(labelX, labelY).width(this.innerWidth() - labelX).height(15), modifier, LabelTextStyle.defaultStyle()
);
@ -69,4 +68,9 @@ public class ModifierListContainer extends VerticalScrollClipContainer<ModifierL
public void setScroll(float scroll) {
this.verticalScrollBarElement.setValue(scroll);
}
@Override
public InnerGearScreen create(ISpatial spatial, int lvl, ModifierCategory modifierCategory, ItemStack gearPiece) {
return new ModifierListContainer(spatial, lvl, modifierCategory, gearPiece);
}
}

View file

@ -30,6 +30,22 @@ public class ScrollableLvlInputElement extends TextInputElement<ScrollableLvlInp
return super.onMouseScrolled(mouseX, mouseY, delta);
}
@Override public boolean onMouseClicked(double mouseX, double mouseY, int buttonIndex) {
if (buttonIndex == 1) { // right
this.setInput("");
}
if (buttonIndex == 2){ // middle
this.setValue(VaultBarOverlay.vaultLevel);
}
return super.onMouseClicked(mouseX, mouseY, buttonIndex);
}
@Override public boolean charTyped(char charTyped, int keyCode) {
if (!Character.isDigit(charTyped)) {
return false;
}
return super.charTyped(charTyped, keyCode);
}
public int getValue() {
return parseInt(this.getInput());

View file

@ -0,0 +1,93 @@
package com.radimous.vhatcaniroll.ui;
import com.radimous.vhatcaniroll.logic.ModifierCategory;
import iskallia.vault.block.TransmogTableBlock;
import iskallia.vault.client.ClientDiscoveredEntriesData;
import iskallia.vault.client.gui.framework.ScreenTextures;
import iskallia.vault.client.gui.framework.element.DiscoveredModelSelectElement;
import iskallia.vault.client.gui.framework.element.FakeItemSlotElement;
import iskallia.vault.client.gui.framework.element.LabelElement;
import iskallia.vault.client.gui.framework.element.NineSliceButtonElement;
import iskallia.vault.client.gui.framework.element.VerticalScrollClipContainer;
import iskallia.vault.client.gui.framework.spatial.Padding;
import iskallia.vault.client.gui.framework.spatial.Spatials;
import iskallia.vault.client.gui.framework.spatial.spi.ISpatial;
import iskallia.vault.client.gui.framework.text.LabelTextStyle;
import iskallia.vault.gear.VaultGearRarity;
import iskallia.vault.gear.VaultGearState;
import iskallia.vault.gear.data.VaultGearData;
import iskallia.vault.init.ModConfigs;
import iskallia.vault.init.ModDynamicModels;
import iskallia.vault.init.ModGearAttributes;
import iskallia.vault.util.SideOnlyFixer;
import iskallia.vault.util.function.ObservableSupplier;
import net.minecraft.client.Minecraft;
import net.minecraft.client.player.LocalPlayer;
import net.minecraft.network.chat.Style;
import net.minecraft.network.chat.TextComponent;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.item.ItemStack;
import java.util.List;
import java.util.Set;
import static iskallia.vault.client.gui.framework.ScreenTextures.BUTTON_EMPTY;
import static iskallia.vault.client.gui.framework.ScreenTextures.BUTTON_EMPTY_DISABLED;
public class TransmogListContainer extends VerticalScrollClipContainer<TransmogListContainer> implements InnerGearScreen {
public TransmogListContainer(ISpatial spatial, ItemStack gearPiece) {
super(spatial, Padding.ZERO, ScreenTextures.INSET_BLACK_BACKGROUND);
int labelX = 9;
int labelY = 0;
LocalPlayer player = Minecraft.getInstance().player;
if (player == null) {
return;
}
Set<ResourceLocation> discoveredModelIds = ClientDiscoveredEntriesData.Models.getDiscoveredModels();
ObservableSupplier<Set<ResourceLocation>> discoveredModelObserverIds = ClientDiscoveredEntriesData.Models.getObserverModels();
DiscoveredModelSelectElement.DiscoveredModelSelectorModel model = new DiscoveredModelSelectElement.DiscoveredModelSelectorModel(
ObservableSupplier.of(() -> gearPiece, SideOnlyFixer::stackEqualExact), discoveredModelObserverIds, x -> {});
List<DiscoveredModelSelectElement.TransmogModelEntry> mEntries = model.getEntries();
for (DiscoveredModelSelectElement.TransmogModelEntry x : mEntries) {
ItemStack displayStack = new ItemStack(gearPiece.getItem());
VaultGearData gearData = VaultGearData.read(displayStack);
gearData.setState(VaultGearState.IDENTIFIED);
gearData.createOrReplaceAttributeValue(ModGearAttributes.GEAR_MODEL, x.getModelId());
gearData.write(displayStack);
this.addElement(new FakeItemSlotElement<>(Spatials.positionXY(labelX, labelY).width(16).height(16), () -> displayStack, () -> false, ScreenTextures.EMPTY, ScreenTextures.EMPTY));
var oMod = ModDynamicModels.REGISTRIES.getModel(gearPiece.getItem(), x.getModelId());
if (oMod.isPresent()) {
var mod = oMod.get();
VaultGearRarity rollRarity = ModConfigs.GEAR_MODEL_ROLL_RARITIES.getRarityOf(gearPiece, mod.getId());
this.addElement(new LabelElement<>(
Spatials.positionXY(labelX + 20, labelY + 6).width(this.innerWidth() - labelX).height(15),
new TextComponent(mod.getDisplayName()).withStyle(Style.EMPTY.withColor(rollRarity.getColor().getValue())), LabelTextStyle.defaultStyle()));
NineSliceButtonElement<?> btn = new NineSliceButtonElement<>(Spatials.positionXY(0, labelY ).width(innerWidth()).height(18),
new NineSliceButtonElement.NineSliceButtonTextures(BUTTON_EMPTY, BUTTON_EMPTY, BUTTON_EMPTY, BUTTON_EMPTY_DISABLED), () -> {});
boolean canTransmog = TransmogTableBlock.canTransmogModel(player, discoveredModelIds, x.getModelId());
btn.setDisabled(!canTransmog);
this.addElement(btn);
}
labelY += 18;
}
}
public float getScroll() {
return this.verticalScrollBarElement.getValue();
}
public void setScroll(float scroll) {
this.verticalScrollBarElement.setValue(scroll);
}
@Override
public InnerGearScreen create(ISpatial spatial, int lvl, ModifierCategory modifierCategory, ItemStack gearPiece) {
return new TransmogListContainer(spatial, gearPiece);
}
}

View file

@ -0,0 +1,136 @@
package com.radimous.vhatcaniroll.ui;
import com.radimous.vhatcaniroll.Config;
import com.radimous.vhatcaniroll.logic.ModifierCategory;
import com.radimous.vhatcaniroll.logic.Modifiers;
import com.radimous.vhatcaniroll.mixin.UniqueGearConfigAccessor;
import com.radimous.vhatcaniroll.mixin.VaultGearTierConfigAccessor;
import iskallia.vault.client.gui.framework.ScreenTextures;
import iskallia.vault.client.gui.framework.element.FakeItemSlotElement;
import iskallia.vault.client.gui.framework.element.LabelElement;
import iskallia.vault.client.gui.framework.element.NineSliceElement;
import iskallia.vault.client.gui.framework.element.VerticalScrollClipContainer;
import iskallia.vault.client.gui.framework.spatial.Padding;
import iskallia.vault.client.gui.framework.spatial.Spatials;
import iskallia.vault.client.gui.framework.spatial.spi.ISpatial;
import iskallia.vault.client.gui.framework.text.LabelTextStyle;
import iskallia.vault.config.UniqueGearConfig;
import iskallia.vault.config.gear.VaultGearTierConfig;
import iskallia.vault.gear.VaultGearState;
import iskallia.vault.gear.data.VaultGearData;
import iskallia.vault.init.ModConfigs;
import iskallia.vault.init.ModGearAttributes;
import net.minecraft.ChatFormatting;
import net.minecraft.network.chat.Component;
import net.minecraft.network.chat.TextComponent;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.item.ItemStack;
import java.util.List;
import java.util.Map;
public class UniqueGearListContainer extends VerticalScrollClipContainer<UniqueGearListContainer> implements InnerGearScreen {
public UniqueGearListContainer(ISpatial spatial, int lvl, ModifierCategory modifierCategory, ItemStack gearPiece) {
super(spatial, Padding.ZERO, ScreenTextures.INSET_BLACK_BACKGROUND);
int labelX = 9;
int labelY = 9;
Map<ResourceLocation, UniqueGearConfig.Entry> uniqueRegistry = ((UniqueGearConfigAccessor) ModConfigs.UNIQUE_GEAR).getRegistry();
ResourceLocation regName = gearPiece.getItem().getRegistryName();
if (regName == null) {
return;
}
String regPath = regName.getPath();
var goodEntries = uniqueRegistry.entrySet().stream().filter(entry -> entry.getValue().getModel() != null && entry.getValue().getModel().toString().contains(regPath)).toList();
VaultGearTierConfigAccessor uniqueConfig1 = (VaultGearTierConfigAccessor) ModConfigs.VAULT_GEAR_CONFIG.get(VaultGearTierConfig.UNIQUE_ITEM);
if (uniqueConfig1 == null) {
return;
}
for (Map.Entry<ResourceLocation, UniqueGearConfig.Entry> entry : goodEntries) {
UniqueGearConfig.Entry value = entry.getValue();
String name = value.getName();
if (name == null) {
continue;
}
ResourceLocation model = value.getModel();
if (model == null) {
continue;
}
Map<UniqueGearConfig.AffixTargetType, List<ResourceLocation>> modifierIdentifiers = value.getModifierIdentifiers();
if (modifierIdentifiers == null) {
continue;
}
int iconHeight = labelY;
labelY += 5;
LabelElement<?> nameLabel = new LabelElement<>(
Spatials.positionXY(labelX + 20, labelY).width(this.innerWidth() - labelX).height(15),
new TextComponent(name), LabelTextStyle.defaultStyle()
);
this.addElement(nameLabel);
labelY += 20;
ItemStack displayStack = new ItemStack(gearPiece.getItem());
VaultGearData gearData = VaultGearData.read(displayStack);
gearData.setState(VaultGearState.IDENTIFIED);
gearData.createOrReplaceAttributeValue(ModGearAttributes.GEAR_MODEL, model);
gearData.write(displayStack);
this.addElement(new FakeItemSlotElement<>(Spatials.positionXY(labelX - 4, iconHeight).width(16).height(16), () -> displayStack, () -> false, ScreenTextures.EMPTY, ScreenTextures.EMPTY));
List<Component> mlist = Modifiers.getUniqueModifierList(lvl, modifierCategory, modifierIdentifiers);
for (Component mc : mlist) {
LabelElement<?> mcl = new LabelElement<>(
Spatials.positionXY(labelX, labelY).width(this.innerWidth() - labelX).height(15),
mc, LabelTextStyle.defaultStyle());
this.addElement(mcl);
labelY += 10;
}
this.addElement(new NineSliceElement<>(
Spatials.positionXY(0, labelY).width(this.innerWidth()).height(3),
ScreenTextures.BUTTON_EMPTY));
labelY += 10;
}
if (Config.DEBUG_UNIQUE_GEAR.get()) {
var badEntries = uniqueRegistry.entrySet().stream().filter(entry -> entry.getValue().getModel() == null || !entry.getValue().getModel().toString().contains(regPath)).toList();
this.addElement(new LabelElement<>(
Spatials.positionXY(labelX, labelY).width(this.innerWidth() - labelX).height(15),
new TextComponent("[DEBUG] BAD ENTRIES:").withStyle(ChatFormatting.RED), LabelTextStyle.defaultStyle()));
labelY += 10;
for (Map.Entry<ResourceLocation, UniqueGearConfig.Entry> entry : badEntries) {
this.addElement(new LabelElement<>(
Spatials.positionXY(labelX, labelY).width(this.innerWidth() - labelX).height(15),
new TextComponent("ID: " + entry.getKey().toString()).withStyle(ChatFormatting.RED),
LabelTextStyle.defaultStyle()));
labelY += 10;
UniqueGearConfig.Entry value = entry.getValue();
if (value == null) {
continue;
}
this.addElement(new LabelElement<>(
Spatials.positionXY(labelX, labelY).width(this.innerWidth() - labelX).height(15),
new TextComponent("Model: " + value.getModel()).withStyle(ChatFormatting.RED),
LabelTextStyle.defaultStyle()));
labelY += 16;
}
}
}
public float getScroll() {
return this.verticalScrollBarElement.getValue();
}
public void setScroll(float scroll) {
this.verticalScrollBarElement.setValue(scroll);
}
@Override
public InnerGearScreen create(ISpatial spatial, int lvl, ModifierCategory modifierCategory, ItemStack gearPiece) {
return new UniqueGearListContainer(spatial, lvl, modifierCategory, gearPiece);
}
}

View file

@ -1,5 +1,8 @@
{
"vhatcaniroll.screen.title": "Gear Modifiers",
"vhatcaniroll.screen.title.random": "Random Modifiers",
"vhatcaniroll.screen.title.crafted": "Crafted Modifiers",
"vhatcaniroll.screen.title.unique": "Unique Gear",
"vhatcaniroll.screen.title.transmogs": "Transmogs",
"vhatcaniroll.openmodscreen": "Open VHat can I roll? screen",
"key.categories.vhatcaniroll": "VHat can I roll?"
}

View file

@ -5,11 +5,13 @@
"compatibilityLevel": "JAVA_8",
"refmap": "vhatcaniroll.refmap.json",
"mixins": [
"EffectConfigAccessor"
],
"client": [
"EffectConfigAccessor",
"StatisticsElementContainerScreenMixin",
"VaultGearTierConfigAccessor"
"UniqueGearConfigAccessor",
"VaultGearTierConfigAccessor",
"AbilityFloatValueAttributeReaderInvoker"
],
"injectors": {
"defaultRequire": 1