From a88c7d5b97bd20c0d372391312c8ba4fc9aeca8d Mon Sep 17 00:00:00 2001 From: Bibi Reden Date: Sat, 27 Jul 2024 20:11:00 -0500 Subject: [PATCH] Implement UI elements for skill info & temp menu --- .../com/bibireden/playerex/PlayerEXClient.kt | 11 +-- .../ui/components/AttributeListComponent.kt | 43 +++++++++++ .../components/AttributeListEntryComponent.kt | 38 ++++++++++ .../playerex/ui/components/MenuComponent.kt | 2 +- .../labels/AttributeLabelComponent.kt | 10 ++- ...butesMenu.kt => PlayerEXAttributesMenu.kt} | 66 ++++++++++------- .../playerex/ui/menus/PlayerEXStatsMenu.kt | 73 +++++++++++++++++++ .../playerex/ui/util/FormattingPredicates.kt | 10 +++ .../assets/playerex/owo_ui/main_ui_model.xml | 2 +- .../api/attribute/DefaultAttributeImpl.kt | 57 ++++++++------- .../resources/assets/playerex/lang/en_us.json | 4 + 11 files changed, 254 insertions(+), 62 deletions(-) create mode 100644 src/client/kotlin/com/bibireden/playerex/ui/components/AttributeListComponent.kt create mode 100644 src/client/kotlin/com/bibireden/playerex/ui/components/AttributeListEntryComponent.kt rename src/client/kotlin/com/bibireden/playerex/ui/menus/{AttributesMenu.kt => PlayerEXAttributesMenu.kt} (58%) create mode 100644 src/client/kotlin/com/bibireden/playerex/ui/menus/PlayerEXStatsMenu.kt create mode 100644 src/client/kotlin/com/bibireden/playerex/ui/util/FormattingPredicates.kt diff --git a/src/client/kotlin/com/bibireden/playerex/PlayerEXClient.kt b/src/client/kotlin/com/bibireden/playerex/PlayerEXClient.kt index 19f2750b..3a468169 100644 --- a/src/client/kotlin/com/bibireden/playerex/PlayerEXClient.kt +++ b/src/client/kotlin/com/bibireden/playerex/PlayerEXClient.kt @@ -10,11 +10,13 @@ import com.bibireden.playerex.networking.registerClientbound import com.bibireden.playerex.networking.types.NotificationType import com.bibireden.playerex.registry.AttributesMenuRegistry import com.bibireden.playerex.ui.PlayerEXScreen -import com.bibireden.playerex.ui.menus.AttributesMenu +import com.bibireden.playerex.ui.menus.PlayerEXAttributesMenu +import com.bibireden.playerex.ui.menus.PlayerEXStatsMenu import net.fabricmc.api.ClientModInitializer import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents import net.fabricmc.fabric.api.client.keybinding.v1.KeyBindingHelper import net.minecraft.client.MinecraftClient +import net.minecraft.client.network.ClientPlayerEntity import net.minecraft.client.option.KeyBinding import net.minecraft.client.util.InputUtil import net.minecraft.entity.player.PlayerEntity @@ -37,9 +39,7 @@ object PlayerEXClient : ClientModInitializer { } EntityAttributeModifiedEvents.MODIFIED.register { attribute, entity, _, _, _ -> - if (entity is PlayerEntity && entity.world.isClient) { - if (entity != MinecraftClient.getInstance().player) return@register - + if (entity is ClientPlayerEntity) { val screen = MinecraftClient.getInstance().currentScreen if (screen is PlayerEXScreen) { if (attribute == PlayerEXAttributes.LEVEL) { @@ -54,7 +54,8 @@ object PlayerEXClient : ClientModInitializer { } } - AttributesMenuRegistry.register(AttributesMenu::class.java) + AttributesMenuRegistry.register(PlayerEXAttributesMenu::class.java) + AttributesMenuRegistry.register(PlayerEXStatsMenu::class.java) ClientTickEvents.END_CLIENT_TICK.register { client -> if (PlayerEX.CONFIG.disableUI) return@register diff --git a/src/client/kotlin/com/bibireden/playerex/ui/components/AttributeListComponent.kt b/src/client/kotlin/com/bibireden/playerex/ui/components/AttributeListComponent.kt new file mode 100644 index 00000000..b6027346 --- /dev/null +++ b/src/client/kotlin/com/bibireden/playerex/ui/components/AttributeListComponent.kt @@ -0,0 +1,43 @@ +package com.bibireden.playerex.ui.components + +import com.bibireden.data_attributes.api.attribute.EntityAttributeSupplier +import com.bibireden.playerex.ui.util.FormattingPredicates +import io.wispforest.owo.ui.component.Components +import io.wispforest.owo.ui.container.Containers +import io.wispforest.owo.ui.container.FlowLayout +import io.wispforest.owo.ui.core.Positioning +import io.wispforest.owo.ui.core.Sizing +import net.minecraft.entity.attribute.EntityAttribute +import net.minecraft.entity.player.PlayerEntity +import net.minecraft.text.Text + +private fun transform(array: List>): List> { + val filtered = mutableListOf>() + for ((attribute, pred) in array) { + if (attribute.get().isPresent) filtered.add(Pair(attribute.get().get(), pred.predicate)) + } + return filtered +} + +class AttributeListComponent(translationKey: String, private val player: PlayerEntity, private val gimmie: List>) : FlowLayout(Sizing.fill(45), Sizing.content(), Algorithm.VERTICAL) { + val entriesSection: FlowLayout + + init { + child( + Components.label(Text.translatable(translationKey)) + .horizontalSizing(Sizing.fill(100)) + ) + entriesSection = Containers.verticalFlow(Sizing.fill(100), Sizing.content()) + .apply { + gap(4) + }.also(::child) + + gap(4) + refresh() + } + + fun refresh() { + entriesSection.children().filterIsInstance().forEach(::removeChild) + entriesSection.children(transform(gimmie).map { AttributeListEntryComponent(it.first, player, it.second) }) + } +} \ No newline at end of file diff --git a/src/client/kotlin/com/bibireden/playerex/ui/components/AttributeListEntryComponent.kt b/src/client/kotlin/com/bibireden/playerex/ui/components/AttributeListEntryComponent.kt new file mode 100644 index 00000000..6744414a --- /dev/null +++ b/src/client/kotlin/com/bibireden/playerex/ui/components/AttributeListEntryComponent.kt @@ -0,0 +1,38 @@ +package com.bibireden.playerex.ui.components + +import com.bibireden.data_attributes.api.DataAttributesAPI +import com.bibireden.playerex.ext.id +import com.bibireden.playerex.ui.util.Colors +import io.wispforest.owo.ui.component.LabelComponent +import io.wispforest.owo.ui.core.HorizontalAlignment +import io.wispforest.owo.ui.core.VerticalAlignment +import net.minecraft.entity.attribute.EntityAttribute +import net.minecraft.entity.player.PlayerEntity +import net.minecraft.text.Text +import net.minecraft.util.Formatting + +typealias FormattingPredicate = (Double) -> String + +class AttributeListEntryComponent( + val attribute: EntityAttribute, + val player: PlayerEntity, + private val formattingPredicate: FormattingPredicate +) : LabelComponent(Text.empty()) { + init { + horizontalTextAlignment(HorizontalAlignment.CENTER) + verticalTextAlignment(VerticalAlignment.CENTER) + + refresh() + } + + fun refresh() { + text( + Text.translatable(attribute.translationKey) + .append(": ") + .append(Text.literal( + DataAttributesAPI.getValue(attribute, player).map { formattingPredicate(it) } + .orElse("N/A")).styled { it.withColor(Colors.GOLD) } + ) + ) + } +} \ No newline at end of file diff --git a/src/client/kotlin/com/bibireden/playerex/ui/components/MenuComponent.kt b/src/client/kotlin/com/bibireden/playerex/ui/components/MenuComponent.kt index da76380f..77ff803d 100644 --- a/src/client/kotlin/com/bibireden/playerex/ui/components/MenuComponent.kt +++ b/src/client/kotlin/com/bibireden/playerex/ui/components/MenuComponent.kt @@ -18,7 +18,7 @@ import org.jetbrains.annotations.ApiStatus * and have the benefits of a unique instance that is attached to the primary mod. */ @ApiStatus.OverrideOnly -abstract class MenuComponent(horizontalSizing: Sizing, verticalSizing: Sizing, algorithm: Algorithm) : FlowLayout(horizontalSizing, verticalSizing, algorithm) { +abstract class MenuComponent(horizontalSizing: Sizing = Sizing.fill(100), verticalSizing: Sizing = Sizing.fill(100), algorithm: Algorithm) : FlowLayout(horizontalSizing, verticalSizing, algorithm) { val onLevelUpdatedEvents = OnLevelUpdated.stream val onAttributeUpdatedEvents = OnAttributeUpdated.stream diff --git a/src/client/kotlin/com/bibireden/playerex/ui/components/labels/AttributeLabelComponent.kt b/src/client/kotlin/com/bibireden/playerex/ui/components/labels/AttributeLabelComponent.kt index 0610fd11..f3974aa0 100644 --- a/src/client/kotlin/com/bibireden/playerex/ui/components/labels/AttributeLabelComponent.kt +++ b/src/client/kotlin/com/bibireden/playerex/ui/components/labels/AttributeLabelComponent.kt @@ -19,12 +19,14 @@ private fun createTextFromAttribute(attribute: EntityAttribute, player: PlayerEn }) .append("/${(attribute as IEntityAttribute).`data_attributes$max`().toInt()})") -class AttributeLabelComponent(private val attribute: EntityAttribute, private val player: PlayerEntity) : LabelComponent(createTextFromAttribute(attribute, player)) { +open class AttributeLabelComponent(private val attribute: EntityAttribute, private val player: PlayerEntity) : LabelComponent(Text.empty()) { init { - horizontalTextAlignment(HorizontalAlignment.CENTER) - verticalTextAlignment(VerticalAlignment.CENTER) + this.horizontalTextAlignment(HorizontalAlignment.CENTER) + this.verticalTextAlignment(VerticalAlignment.CENTER) - id("${attribute.id}:current_level") + this.id("${attribute.id}:current_level") + + this.refresh() } fun refresh(): LabelComponent = text(createTextFromAttribute(attribute, player)) diff --git a/src/client/kotlin/com/bibireden/playerex/ui/menus/AttributesMenu.kt b/src/client/kotlin/com/bibireden/playerex/ui/menus/PlayerEXAttributesMenu.kt similarity index 58% rename from src/client/kotlin/com/bibireden/playerex/ui/menus/AttributesMenu.kt rename to src/client/kotlin/com/bibireden/playerex/ui/menus/PlayerEXAttributesMenu.kt index 8df62bb1..c0bf8e81 100644 --- a/src/client/kotlin/com/bibireden/playerex/ui/menus/AttributesMenu.kt +++ b/src/client/kotlin/com/bibireden/playerex/ui/menus/PlayerEXAttributesMenu.kt @@ -1,39 +1,46 @@ package com.bibireden.playerex.ui.menus import com.bibireden.data_attributes.api.DataAttributesAPI +import com.bibireden.data_attributes.api.attribute.EntityAttributeSupplier import com.bibireden.data_attributes.api.attribute.IEntityAttribute +import com.bibireden.playerex.api.attribute.ModdedAttributes import com.bibireden.playerex.api.attribute.PlayerEXAttributes import com.bibireden.playerex.components.player.IPlayerDataComponent +import com.bibireden.playerex.ext.id import com.bibireden.playerex.ext.level import com.bibireden.playerex.ui.PlayerEXScreen import com.bibireden.playerex.ui.childById -import com.bibireden.playerex.ui.components.MenuComponent -import com.bibireden.playerex.ui.components.AttributeComponent +import com.bibireden.playerex.ui.components.* import com.bibireden.playerex.ui.components.buttons.AttributeButtonComponent import com.bibireden.playerex.ui.components.labels.AttributeLabelComponent -import com.bibireden.playerex.util.PlayerEXUtil +import com.bibireden.playerex.ui.util.FormattingPredicates +import de.dafuqs.additionalentityattributes.AdditionalEntityAttributes import io.wispforest.owo.ui.component.Components +import io.wispforest.owo.ui.component.LabelComponent import io.wispforest.owo.ui.component.TextBoxComponent import io.wispforest.owo.ui.container.Containers import io.wispforest.owo.ui.container.FlowLayout -import io.wispforest.owo.ui.core.Insets -import io.wispforest.owo.ui.core.OwoUIAdapter -import io.wispforest.owo.ui.core.Positioning -import io.wispforest.owo.ui.core.Sizing +import io.wispforest.owo.ui.core.* +import net.fabric_extras.ranged_weapon.api.EntityAttributes_RangedWeapon import net.minecraft.client.network.ClientPlayerEntity +import net.minecraft.entity.attribute.EntityAttributes import net.minecraft.entity.player.PlayerEntity import net.minecraft.registry.Registries import net.minecraft.text.Text +import org.jetbrains.annotations.ApiStatus // todo: cache buttons/certain UI elements -class AttributesMenu : MenuComponent(Sizing.fill(100), Sizing.fill(100), Algorithm.VERTICAL) { +@ApiStatus.Internal +class PlayerEXAttributesMenu : MenuComponent(algorithm = Algorithm.VERTICAL) { + private fun onLevelUpdate(level: Int) {} /** Whenever ANY attribute gets updated. */ private fun onAttributeUpdate() { // refresh all attribute labels this.forEachDescendant { component -> + // todo: use derived interface to check instance if (component is AttributeComponent) { component.refresh() return@forEachDescendant @@ -63,25 +70,32 @@ class AttributesMenu : MenuComponent(Sizing.fill(100), Sizing.fill(100), Algorit } override fun build(player: ClientPlayerEntity, adapter: OwoUIAdapter, component: IPlayerDataComponent) { - child(Containers.verticalFlow(Sizing.fill(35), Sizing.fill(100)).apply { - child(Components.label(Text.translatable("playerex.ui.category.primary_attributes"))) - child( - Components.textBox(Sizing.fixed(27)) - .also { - it.setMaxLength(4) - it.onChanged().subscribe { onInputFieldUpdated(player, component) } - } - .text("1") - .verticalSizing(Sizing.fixed(10)) - .positioning(Positioning.relative(100, 0)) - .id("input") - ) - child(Components.box(Sizing.fill(100), Sizing.fixed(2))) - gap(5) - children(PlayerEXAttributes.PRIMARY_ATTRIBUTE_IDS.mapNotNull(Registries.ATTRIBUTE::get).map { AttributeComponent(it, player, component) }) - }.id("attributes")) + child(Containers.verticalScroll( + Sizing.fill(35), + Sizing.fill(100), + Containers.verticalFlow(Sizing.fill(100), Sizing.content()).apply { + child(Containers.horizontalFlow(Sizing.fill(100), Sizing.content(2)).apply { + child(Components.label(Text.translatable("playerex.ui.category.primary_attributes"))) + child( + Components.textBox(Sizing.fixed(27)) + .also { + it.setMaxLength(4) + it.onChanged().subscribe { onInputFieldUpdated(player, component) } + } + .text("1") + .verticalSizing(Sizing.fixed(10)) + .positioning(Positioning.relative(100, 0)) + .id("input") + ) + }) + child(Components.box(Sizing.fill(100), Sizing.fixed(2))) + verticalAlignment(VerticalAlignment.CENTER) + gap(5) + children(PlayerEXAttributes.PRIMARY_ATTRIBUTE_IDS.mapNotNull(Registries.ATTRIBUTE::get).map { AttributeComponent(it, player, component) }) + }.id("attributes")) + ) - padding(Insets.both(12, 12)) + padding(Insets.both(8, 8)) onLevelUpdate(player.level.toInt()) onAttributeUpdate() diff --git a/src/client/kotlin/com/bibireden/playerex/ui/menus/PlayerEXStatsMenu.kt b/src/client/kotlin/com/bibireden/playerex/ui/menus/PlayerEXStatsMenu.kt new file mode 100644 index 00000000..1df1c7a1 --- /dev/null +++ b/src/client/kotlin/com/bibireden/playerex/ui/menus/PlayerEXStatsMenu.kt @@ -0,0 +1,73 @@ +package com.bibireden.playerex.ui.menus + +import com.bibireden.data_attributes.api.attribute.EntityAttributeSupplier +import com.bibireden.playerex.api.attribute.ModdedAttributes +import com.bibireden.playerex.api.attribute.PlayerEXAttributes +import com.bibireden.playerex.components.player.IPlayerDataComponent +import com.bibireden.playerex.ext.id +import com.bibireden.playerex.ui.components.AttributeListComponent +import com.bibireden.playerex.ui.components.AttributeListEntryComponent +import com.bibireden.playerex.ui.components.MenuComponent +import com.bibireden.playerex.ui.util.FormattingPredicates +import de.dafuqs.additionalentityattributes.AdditionalEntityAttributes +import io.wispforest.owo.ui.component.Components +import io.wispforest.owo.ui.container.Containers +import io.wispforest.owo.ui.container.FlowLayout +import io.wispforest.owo.ui.core.Insets +import io.wispforest.owo.ui.core.OwoUIAdapter +import io.wispforest.owo.ui.core.Positioning +import io.wispforest.owo.ui.core.Sizing +import net.fabric_extras.ranged_weapon.api.EntityAttributes_RangedWeapon +import net.minecraft.client.network.ClientPlayerEntity +import net.minecraft.entity.attribute.EntityAttributes +import net.minecraft.text.Text +import org.jetbrains.annotations.ApiStatus + +@ApiStatus.Internal +class PlayerEXStatsMenu : MenuComponent(algorithm = Algorithm.VERTICAL) { + val MELEE_COMBAT_STATS: List> = listOf( + EntityAttributeSupplier(EntityAttributes.GENERIC_ATTACK_DAMAGE.id) to FormattingPredicates.Normal, + EntityAttributeSupplier(EntityAttributes.GENERIC_ATTACK_SPEED.id) to FormattingPredicates.Normal, + ModdedAttributes.ATTACK_RANGE to FormattingPredicates.Normal, + EntityAttributeSupplier(PlayerEXAttributes.MELEE_CRIT_DAMAGE.id) to FormattingPredicates.PercentageDiv, + EntityAttributeSupplier(PlayerEXAttributes.MELEE_CRIT_CHANCE.id) to FormattingPredicates.PercentageDiv + ) + + val RANGED_COMBAT_STATS: List> = listOf( + EntityAttributeSupplier(PlayerEXAttributes.RANGED_DAMAGE.id) to FormattingPredicates.Normal, + EntityAttributeSupplier(PlayerEXAttributes.RANGED_CRITICAL_DAMAGE.id) to FormattingPredicates.PercentageDiv, + EntityAttributeSupplier(PlayerEXAttributes.RANGED_CRITICAL_CHANCE.id) to FormattingPredicates.PercentageDiv, + EntityAttributeSupplier(EntityAttributes_RangedWeapon.HASTE.id) to FormattingPredicates.Percent, + ) + + val DEFENSE_COMBAT_STATS: List> = listOf( + EntityAttributeSupplier(EntityAttributes.GENERIC_ARMOR.id) to FormattingPredicates.Normal, + EntityAttributeSupplier(AdditionalEntityAttributes.MAGIC_PROTECTION.id) to FormattingPredicates.Normal, + EntityAttributeSupplier(EntityAttributes.GENERIC_ARMOR_TOUGHNESS.id) to FormattingPredicates.Normal, + EntityAttributeSupplier(EntityAttributes.GENERIC_KNOCKBACK_RESISTANCE.id) to FormattingPredicates.PercentageDiv, + EntityAttributeSupplier(PlayerEXAttributes.EVASION.id) to FormattingPredicates.PercentageDiv, + ) + + override fun build(player: ClientPlayerEntity, adapter: OwoUIAdapter, component: IPlayerDataComponent) { + child( + Containers.verticalScroll( + Sizing.fill(100), + Sizing.fill(100), + Containers.verticalFlow(Sizing.fill(100), Sizing.content()).apply { + child(AttributeListComponent("playerex.ui.main.categories.melee_combat", player, MELEE_COMBAT_STATS)) + child(AttributeListComponent("playerex.ui.main.categories.ranged_combat", player, RANGED_COMBAT_STATS)) + child(AttributeListComponent("playerex.ui.main.categories.defense_combat", player, DEFENSE_COMBAT_STATS)) + gap(10) + }.id("combat_stats") + ) + ) + + this.onAttributeUpdated.subscribe { _, _ -> + this.forEachDescendant { + if (it is AttributeListEntryComponent) it.refresh() + } + } + + padding(Insets.both(8, 12)) + } +} \ No newline at end of file diff --git a/src/client/kotlin/com/bibireden/playerex/ui/util/FormattingPredicates.kt b/src/client/kotlin/com/bibireden/playerex/ui/util/FormattingPredicates.kt new file mode 100644 index 00000000..fe7f6802 --- /dev/null +++ b/src/client/kotlin/com/bibireden/playerex/ui/util/FormattingPredicates.kt @@ -0,0 +1,10 @@ +package com.bibireden.playerex.ui.util + +import com.bibireden.playerex.ui.components.FormattingPredicate + +enum class FormattingPredicates(val predicate: FormattingPredicate) { + Normal({ "%.2f".format(it) }), + Percent({ "${it.toInt()}%" }), + PercentageMul({ "${(it * 100.0).toInt()}%" }), + PercentageDiv({ "${(it / 100.0).toInt()}%" }), +} \ No newline at end of file diff --git a/src/client/resources/assets/playerex/owo_ui/main_ui_model.xml b/src/client/resources/assets/playerex/owo_ui/main_ui_model.xml index cdc9c8dd..57580a58 100644 --- a/src/client/resources/assets/playerex/owo_ui/main_ui_model.xml +++ b/src/client/resources/assets/playerex/owo_ui/main_ui_model.xml @@ -88,7 +88,7 @@ 85100 - 0,50 + 0,40 10 center diff --git a/src/main/kotlin/com/bibireden/playerex/api/attribute/DefaultAttributeImpl.kt b/src/main/kotlin/com/bibireden/playerex/api/attribute/DefaultAttributeImpl.kt index 50f7de28..9d7bb662 100644 --- a/src/main/kotlin/com/bibireden/playerex/api/attribute/DefaultAttributeImpl.kt +++ b/src/main/kotlin/com/bibireden/playerex/api/attribute/DefaultAttributeImpl.kt @@ -1,61 +1,68 @@ package com.bibireden.playerex.api.attribute import com.bibireden.data_attributes.api.attribute.StackingBehavior +import com.bibireden.data_attributes.api.attribute.StackingFormula import com.bibireden.data_attributes.config.functions.AttributeFunction +import com.bibireden.data_attributes.config.models.OverridesConfigModel +import com.bibireden.data_attributes.config.models.OverridesConfigModel.AttributeOverride import com.bibireden.data_attributes.data.EntityTypeData -import com.bibireden.playerex.PlayerEX import com.bibireden.playerex.ext.id import de.dafuqs.additionalentityattributes.AdditionalEntityAttributes import net.fabric_extras.ranged_weapon.api.EntityAttributes_RangedWeapon import net.minecraft.entity.attribute.EntityAttributes import net.minecraft.util.Identifier +import net.projectile_damage.api.EntityAttributes_ProjectileDamage object DefaultAttributeImpl { + val OVERRIDES: Map = mapOf( + EntityAttributes.GENERIC_ARMOR.id to AttributeOverride( + max = 1024.0, + formula = StackingFormula.Diminished + ) + ) val FUNCTIONS: Map> = mapOf( PlayerEXAttributes.CONSTITUTION.id to listOf( AttributeFunction(EntityAttributes.GENERIC_MAX_HEALTH.id, StackingBehavior.Add, 0.5), AttributeFunction(EntityAttributes.GENERIC_ARMOR.id, StackingBehavior.Add, 0.25), - AttributeFunction(PlayerEXAttributes.POISON_RESISTANCE.id, StackingBehavior.Add, 0.1), - AttributeFunction(PlayerEXAttributes.FREEZE_RESISTANCE.id, StackingBehavior.Add, 0.1), - AttributeFunction(PlayerEXAttributes.LIGHTNING_RESISTANCE.id, StackingBehavior.Add, 0.1), AttributeFunction(AdditionalEntityAttributes.MAGIC_PROTECTION.id, StackingBehavior.Add, 0.25), - AttributeFunction(AdditionalEntityAttributes.LUNG_CAPACITY.id, StackingBehavior.Add, 0.25) + AttributeFunction(AdditionalEntityAttributes.LUNG_CAPACITY.id, StackingBehavior.Add, 0.01), + AttributeFunction(PlayerEXAttributes.POISON_RESISTANCE.id, StackingBehavior.Add, 0.1), ), PlayerEXAttributes.STRENGTH.id to listOf( - AttributeFunction(EntityAttributes.GENERIC_ATTACK_DAMAGE.id, StackingBehavior.Add, 0.02), + AttributeFunction(EntityAttributes.GENERIC_ATTACK_DAMAGE.id, StackingBehavior.Multiply, 0.02), AttributeFunction(EntityAttributes.GENERIC_KNOCKBACK_RESISTANCE.id, StackingBehavior.Add, 0.1), - AttributeFunction(PlayerEXAttributes.MELEE_CRIT_DAMAGE.id, StackingBehavior.Add, 0.05), + AttributeFunction(PlayerEXAttributes.MELEE_CRIT_DAMAGE.id, StackingBehavior.Multiply, 0.05), AttributeFunction(PlayerEXAttributes.BREAKING_SPEED.id, StackingBehavior.Add, 0.01), ), PlayerEXAttributes.DEXTERITY.id to listOf( - AttributeFunction(EntityAttributes.GENERIC_ATTACK_SPEED.id, StackingBehavior.Add, 0.01), - AttributeFunction(PlayerEXAttributes.RANGED_DAMAGE.id, StackingBehavior.Add, 0.02), - AttributeFunction(PlayerEXAttributes.RANGED_CRITICAL_DAMAGE.id, StackingBehavior.Add, 0.05), - AttributeFunction(EntityAttributes_RangedWeapon.HASTE.id, StackingBehavior.Add, 0.05), - AttributeFunction(PlayerEXAttributes.FIRE_RESISTANCE.id, StackingBehavior.Add, 0.1), + AttributeFunction(EntityAttributes.GENERIC_ATTACK_SPEED.id, StackingBehavior.Multiply, 0.01), + AttributeFunction(PlayerEXAttributes.RANGED_DAMAGE.id, StackingBehavior.Multiply, 0.02), + AttributeFunction(PlayerEXAttributes.RANGED_CRITICAL_DAMAGE.id, StackingBehavior.Multiply, 0.05), + AttributeFunction(EntityAttributes_RangedWeapon.HASTE.id, StackingBehavior.Multiply, 0.02), + AttributeFunction(EntityAttributes_ProjectileDamage.GENERIC_PROJECTILE_DAMAGE.id, StackingBehavior.Multiply, 0.1), ), PlayerEXAttributes.INTELLIGENCE.id to listOf( - AttributeFunction(AdditionalEntityAttributes.DROPPED_EXPERIENCE.id, StackingBehavior.Add, 0.01), + // todo: spell haste? (see wizards/spell power) + AttributeFunction(AdditionalEntityAttributes.DROPPED_EXPERIENCE.id, StackingBehavior.Multiply, 0.01), AttributeFunction(PlayerEXAttributes.WITHER_RESISTANCE.id, StackingBehavior.Add, 0.1), - AttributeFunction(PlayerEXAttributes.HEAL_AMPLIFICATION.id, StackingBehavior.Add, 0.05), + // todo: max mana? (see archon) + // todo: enchanting power? (see zenith) + ), + PlayerEXAttributes.FOCUS.id to listOf( AttributeFunction(PlayerEXAttributes.HEALTH_REGENERATION.id, StackingBehavior.Add, 0.01), + AttributeFunction(PlayerEXAttributes.HEAL_AMPLIFICATION.id, StackingBehavior.Multiply, 0.05), + AttributeFunction(PlayerEXAttributes.FREEZE_RESISTANCE.id, StackingBehavior.Add, 0.1), + AttributeFunction(PlayerEXAttributes.LIGHTNING_RESISTANCE.id, StackingBehavior.Add, 0.1), + AttributeFunction(PlayerEXAttributes.FIRE_RESISTANCE.id, StackingBehavior.Add, 0.1), ), PlayerEXAttributes.LUCKINESS.id to listOf( - AttributeFunction(PlayerEXAttributes.MELEE_CRIT_CHANCE.id, StackingBehavior.Add, 0.02), - AttributeFunction(PlayerEXAttributes.RANGED_CRITICAL_CHANCE.id, StackingBehavior.Add, 0.02), - // cannot find spell crit chance atm, maybe a wizard thing + AttributeFunction(PlayerEXAttributes.MELEE_CRIT_CHANCE.id, StackingBehavior.Multiply, 0.02), + AttributeFunction(PlayerEXAttributes.RANGED_CRITICAL_CHANCE.id, StackingBehavior.Multiply, 0.02), + // todo: spell crit chance (see wizards/spell power) // loot table chance?? wh- - AttributeFunction(PlayerEXAttributes.MELEE_CRIT_CHANCE.id, StackingBehavior.Add, 0.01), AttributeFunction(EntityAttributes.GENERIC_LUCK.id, StackingBehavior.Add, 0.05), AttributeFunction(PlayerEXAttributes.EVASION.id, StackingBehavior.Add, 0.01), ), - PlayerEXAttributes.FOCUS.id to listOf( - AttributeFunction(PlayerEXAttributes.HEALTH_REGENERATION.id, StackingBehavior.Add, 0.01), - AttributeFunction(PlayerEXAttributes.HEAL_AMPLIFICATION.id, StackingBehavior.Add, 0.05), - AttributeFunction(PlayerEXAttributes.FREEZE_RESISTANCE.id, StackingBehavior.Add, 0.1), - AttributeFunction(PlayerEXAttributes.LIGHTNING_RESISTANCE.id, StackingBehavior.Add, 0.1), - AttributeFunction(PlayerEXAttributes.FIRE_RESISTANCE.id, StackingBehavior.Add, 0.1), - ) ) val ENTITY_TYPES: Map = mapOf( Identifier.of("minecraft", "player")!! to EntityTypeData(mapOf( diff --git a/src/main/resources/assets/playerex/lang/en_us.json b/src/main/resources/assets/playerex/lang/en_us.json index 9d8753e7..61736424 100644 --- a/src/main/resources/assets/playerex/lang/en_us.json +++ b/src/main/resources/assets/playerex/lang/en_us.json @@ -34,8 +34,12 @@ {"text": "Current XP: ", "color": "white"}, {"index": 2} ], + "playerex.ui.nameplate.level": "", + "playerex.ui.main.categories.melee_combat": "⚔️ Melee", + "playerex.ui.main.categories.ranged_combat": "🏹 Ranged", + "playerex.ui.main.categories.defense_combat": "🛡️ Defense", "attribute.name.playerex.level": "Level", "attribute.name.playerex.constitution": "Constitution",