Reworked durability configs to be dynamically set during inventory tick update whenever a config change is detected. Added unbreakable text to totem tooltip. Fixed server world crashing when reviving player due to closing level (try-with-resources).
This commit is contained in:
@ -0,0 +1,46 @@
|
|||||||
|
package dev.micle.totem_of_reviving.component;
|
||||||
|
|
||||||
|
import com.mojang.serialization.Codec;
|
||||||
|
import com.mojang.serialization.codecs.RecordCodecBuilder;
|
||||||
|
import io.netty.buffer.ByteBuf;
|
||||||
|
import net.minecraft.network.codec.ByteBufCodecs;
|
||||||
|
import net.minecraft.network.codec.StreamCodec;
|
||||||
|
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
public class TotemConfigHashData {
|
||||||
|
public static final Codec<TotemConfigHashData> CODEC = RecordCodecBuilder.create(instance ->
|
||||||
|
instance.group(
|
||||||
|
Codec.INT.fieldOf("configHash").forGetter(TotemConfigHashData::getConfigHash)
|
||||||
|
).apply(instance, TotemConfigHashData::new)
|
||||||
|
);
|
||||||
|
public static final StreamCodec<ByteBuf, TotemConfigHashData> STREAM_CODEC = StreamCodec.composite(
|
||||||
|
ByteBufCodecs.INT, TotemConfigHashData::getConfigHash,
|
||||||
|
TotemConfigHashData::new
|
||||||
|
);
|
||||||
|
|
||||||
|
private final int configHash;
|
||||||
|
|
||||||
|
public TotemConfigHashData(int configHash) {
|
||||||
|
this.configHash = configHash;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getConfigHash() {
|
||||||
|
return this.configHash;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return Objects.hash(this.configHash);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object obj) {
|
||||||
|
if (obj == this) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return obj instanceof TotemConfigHashData tchd
|
||||||
|
&& this.configHash == tchd.configHash;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -7,7 +7,7 @@ import net.minecraft.world.item.Rarity;
|
|||||||
|
|
||||||
public class DiamondTotemItem extends TotemItem {
|
public class DiamondTotemItem extends TotemItem {
|
||||||
public DiamondTotemItem() {
|
public DiamondTotemItem() {
|
||||||
super(createProperties(Rarity.RARE, Config.Server.getDiamondTotemConfig().getDurability(), false));
|
super(createProperties(Rarity.RARE, false));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String getName() {
|
public static String getName() {
|
||||||
|
|||||||
@ -7,7 +7,7 @@ import net.minecraft.world.item.Rarity;
|
|||||||
|
|
||||||
public class IronTotemItem extends TotemItem {
|
public class IronTotemItem extends TotemItem {
|
||||||
public IronTotemItem() {
|
public IronTotemItem() {
|
||||||
super(createProperties(Rarity.COMMON, Config.Server.getIronTotemConfig().getDurability(), false));
|
super(createProperties(Rarity.COMMON, false));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String getName() {
|
public static String getName() {
|
||||||
|
|||||||
@ -7,7 +7,7 @@ import net.minecraft.world.item.Rarity;
|
|||||||
|
|
||||||
public class NetheriteTotemItem extends TotemItem {
|
public class NetheriteTotemItem extends TotemItem {
|
||||||
public NetheriteTotemItem() {
|
public NetheriteTotemItem() {
|
||||||
super(createProperties(Rarity.EPIC, Config.Server.getNetheriteTotemConfig().getDurability(), true));
|
super(createProperties(Rarity.EPIC, true));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String getName() {
|
public static String getName() {
|
||||||
|
|||||||
@ -7,7 +7,7 @@ import net.minecraft.world.item.Rarity;
|
|||||||
|
|
||||||
public class StrawTotemItem extends TotemItem {
|
public class StrawTotemItem extends TotemItem {
|
||||||
public StrawTotemItem() {
|
public StrawTotemItem() {
|
||||||
super(createProperties(Rarity.UNCOMMON, Config.Server.getStrawTotemConfig().getDurability(), false));
|
super(createProperties(Rarity.UNCOMMON, false));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String getName() {
|
public static String getName() {
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
package dev.micle.totem_of_reviving.item.totem;
|
package dev.micle.totem_of_reviving.item.totem;
|
||||||
|
|
||||||
import com.mojang.blaze3d.platform.InputConstants;
|
import com.mojang.blaze3d.platform.InputConstants;
|
||||||
|
import dev.micle.totem_of_reviving.component.TotemConfigHashData;
|
||||||
import dev.micle.totem_of_reviving.component.TotemData;
|
import dev.micle.totem_of_reviving.component.TotemData;
|
||||||
import dev.micle.totem_of_reviving.setup.Config;
|
import dev.micle.totem_of_reviving.setup.Config;
|
||||||
import dev.micle.totem_of_reviving.setup.ModDataComponents;
|
import dev.micle.totem_of_reviving.setup.ModDataComponents;
|
||||||
@ -8,6 +9,7 @@ import dev.micle.totem_of_reviving.util.ComponentHelper;
|
|||||||
import dev.micle.totem_of_reviving.util.LangAsset;
|
import dev.micle.totem_of_reviving.util.LangAsset;
|
||||||
import net.minecraft.ChatFormatting;
|
import net.minecraft.ChatFormatting;
|
||||||
import net.minecraft.client.Minecraft;
|
import net.minecraft.client.Minecraft;
|
||||||
|
import net.minecraft.core.component.DataComponents;
|
||||||
import net.minecraft.network.chat.Component;
|
import net.minecraft.network.chat.Component;
|
||||||
import net.minecraft.server.MinecraftServer;
|
import net.minecraft.server.MinecraftServer;
|
||||||
import net.minecraft.server.level.ServerLevel;
|
import net.minecraft.server.level.ServerLevel;
|
||||||
@ -16,17 +18,18 @@ import net.minecraft.server.players.PlayerList;
|
|||||||
import net.minecraft.stats.Stats;
|
import net.minecraft.stats.Stats;
|
||||||
import net.minecraft.world.InteractionHand;
|
import net.minecraft.world.InteractionHand;
|
||||||
import net.minecraft.world.InteractionResultHolder;
|
import net.minecraft.world.InteractionResultHolder;
|
||||||
|
import net.minecraft.world.entity.Entity;
|
||||||
import net.minecraft.world.entity.EquipmentSlot;
|
import net.minecraft.world.entity.EquipmentSlot;
|
||||||
import net.minecraft.world.entity.player.Player;
|
import net.minecraft.world.entity.player.Player;
|
||||||
import net.minecraft.world.item.Item;
|
import net.minecraft.world.item.Item;
|
||||||
import net.minecraft.world.item.ItemStack;
|
import net.minecraft.world.item.ItemStack;
|
||||||
import net.minecraft.world.item.Rarity;
|
import net.minecraft.world.item.Rarity;
|
||||||
import net.minecraft.world.item.TooltipFlag;
|
import net.minecraft.world.item.TooltipFlag;
|
||||||
|
import net.minecraft.world.item.component.Unbreakable;
|
||||||
import net.minecraft.world.level.Level;
|
import net.minecraft.world.level.Level;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
import javax.annotation.ParametersAreNonnullByDefault;
|
import javax.annotation.ParametersAreNonnullByDefault;
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
@ -36,8 +39,8 @@ public abstract class TotemItem extends Item {
|
|||||||
super(properties);
|
super(properties);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Properties createProperties(Rarity rarity, int durability, boolean isFireResistant) {
|
public static Properties createProperties(Rarity rarity, boolean isFireResistant) {
|
||||||
Properties properties = new Properties().stacksTo(1).rarity(rarity).durability(durability);
|
Properties properties = new Properties().stacksTo(1).rarity(rarity);
|
||||||
|
|
||||||
if (isFireResistant) properties = properties.fireResistant();
|
if (isFireResistant) properties = properties.fireResistant();
|
||||||
|
|
||||||
@ -160,28 +163,18 @@ public abstract class TotemItem extends Item {
|
|||||||
).withStyle(ChatFormatting.GRAY);
|
).withStyle(ChatFormatting.GRAY);
|
||||||
}
|
}
|
||||||
|
|
||||||
try (ServerLevel targetLevel = target.serverLevel()) {
|
if (!target.serverLevel().equals(user.serverLevel()) && !config.getCanReviveAcrossDimensions()) {
|
||||||
if (!targetLevel.equals(user.serverLevel()) && !config.getCanReviveAcrossDimensions()) {
|
|
||||||
return LangAsset.MESSAGE_PLAYER_IS_IN_ANOTHER_DIMENSION.getComponent(
|
return LangAsset.MESSAGE_PLAYER_IS_IN_ANOTHER_DIMENSION.getComponent(
|
||||||
Component.literal(totemData.getTargetName()).withStyle(ChatFormatting.WHITE)
|
Component.literal(totemData.getTargetName()).withStyle(ChatFormatting.WHITE)
|
||||||
).withStyle(ChatFormatting.GRAY);
|
).withStyle(ChatFormatting.GRAY);
|
||||||
}
|
}
|
||||||
} catch (IOException e) {
|
|
||||||
return LangAsset.MESSAGE_UNABLE_TO_GET_PLAYER_WORLD.getComponent(
|
|
||||||
Component.literal(totemData.getTargetName()).withStyle(ChatFormatting.RED)
|
|
||||||
).withStyle(ChatFormatting.DARK_RED);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!totemItem.canAffordTarget(totemData)) {
|
if (!totemItem.canAffordTarget(totemData)) {
|
||||||
return LangAsset.MESSAGE_NOT_ENOUGH_CHARGE.getComponent().withStyle(ChatFormatting.WHITE);
|
return LangAsset.MESSAGE_NOT_ENOUGH_CHARGE.getComponent().withStyle(ChatFormatting.WHITE);
|
||||||
}
|
}
|
||||||
|
|
||||||
try (ServerLevel userLevel = user.serverLevel()) {
|
target.teleportTo(user.serverLevel(), user.position().x, user.position().y, user.position().z, user.getYRot(), user.getXRot());
|
||||||
target.teleportTo(userLevel, user.position().x, user.position().y, user.position().z, user.getYRot(), user.getXRot());
|
target.setGameMode(user.serverLevel().getServer().getDefaultGameType());
|
||||||
target.setGameMode(userLevel.getServer().getDefaultGameType());
|
|
||||||
} catch (IOException e) {
|
|
||||||
return LangAsset.MESSAGE_UNABLE_TO_GET_YOUR_WORLD.getComponent().withStyle(ChatFormatting.RED);
|
|
||||||
}
|
|
||||||
|
|
||||||
totemData = new TotemData(
|
totemData = new TotemData(
|
||||||
totemData.getTargetIndex(),
|
totemData.getTargetIndex(),
|
||||||
@ -234,6 +227,9 @@ public abstract class TotemItem extends Item {
|
|||||||
if (getConfig().getCanReviveAcrossDimensions()) {
|
if (getConfig().getCanReviveAcrossDimensions()) {
|
||||||
tooltipComponents.add(LangAsset.TOOLTIP_TOTEM_CAN_REVIVE_ACROSS_DIMENSIONS.getComponent().withStyle(ChatFormatting.GRAY, ChatFormatting.ITALIC));
|
tooltipComponents.add(LangAsset.TOOLTIP_TOTEM_CAN_REVIVE_ACROSS_DIMENSIONS.getComponent().withStyle(ChatFormatting.GRAY, ChatFormatting.ITALIC));
|
||||||
}
|
}
|
||||||
|
if (!stack.isDamageableItem()) {
|
||||||
|
tooltipComponents.add(LangAsset.TOOLTIP_TOTEM_IS_UNBREAKABLE.getComponent().withStyle(ChatFormatting.GRAY, ChatFormatting.ITALIC));
|
||||||
|
}
|
||||||
|
|
||||||
tooltipComponents.add(Component.empty());
|
tooltipComponents.add(Component.empty());
|
||||||
|
|
||||||
@ -256,6 +252,31 @@ public abstract class TotemItem extends Item {
|
|||||||
super.appendHoverText(stack, context, tooltipComponents, tooltipFlag);
|
super.appendHoverText(stack, context, tooltipComponents, tooltipFlag);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@ParametersAreNonnullByDefault
|
||||||
|
public void inventoryTick(ItemStack stack, Level level, Entity entity, int slotId, boolean isSelected) {
|
||||||
|
if (level.isClientSide) {
|
||||||
|
super.inventoryTick(stack, level, entity, slotId, isSelected);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
TotemConfigHashData totemConfigHashData = stack.get(ModDataComponents.TOTEM_CONFIG_HASH_DATA);
|
||||||
|
if (totemConfigHashData == null || totemConfigHashData.getConfigHash() != getConfig().getConfigHash()) {
|
||||||
|
if (getConfig().getDurability() == 0) {
|
||||||
|
stack.set(DataComponents.UNBREAKABLE, new Unbreakable(false));
|
||||||
|
stack.remove(DataComponents.MAX_DAMAGE);
|
||||||
|
stack.remove(DataComponents.DAMAGE);
|
||||||
|
} else {
|
||||||
|
stack.remove(DataComponents.UNBREAKABLE);
|
||||||
|
stack.set(DataComponents.MAX_DAMAGE, getConfig().getDurability());
|
||||||
|
stack.set(DataComponents.DAMAGE, 0);
|
||||||
|
}
|
||||||
|
stack.set(ModDataComponents.TOTEM_CONFIG_HASH_DATA, new TotemConfigHashData(getConfig().getConfigHash()));
|
||||||
|
}
|
||||||
|
|
||||||
|
super.inventoryTick(stack, level, entity, slotId, isSelected);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ParametersAreNonnullByDefault
|
@ParametersAreNonnullByDefault
|
||||||
public @NotNull InteractionResultHolder<ItemStack> use(Level level, Player player, InteractionHand usedHand) {
|
public @NotNull InteractionResultHolder<ItemStack> use(Level level, Player player, InteractionHand usedHand) {
|
||||||
@ -283,26 +304,4 @@ public abstract class TotemItem extends Item {
|
|||||||
|
|
||||||
return super.use(level, player, usedHand);
|
return super.use(level, player, usedHand);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
@ParametersAreNonnullByDefault
|
|
||||||
public int getMaxDamage(ItemStack stack) {
|
|
||||||
return getConfig().getDurability();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@ParametersAreNonnullByDefault
|
|
||||||
public boolean isDamageable(ItemStack stack) {
|
|
||||||
return getConfig().getDurability() != 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@ParametersAreNonnullByDefault
|
|
||||||
public int getDamage(ItemStack stack) {
|
|
||||||
if (isDamageable(stack) && super.getDamage(stack) >= getMaxDamage(stack)) {
|
|
||||||
stack.setCount(0);
|
|
||||||
return getMaxDamage(stack);
|
|
||||||
}
|
|
||||||
return (isDamageable(stack)) ? super.getDamage(stack) : 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -8,6 +8,8 @@ import net.neoforged.fml.ModContainer;
|
|||||||
import net.neoforged.fml.config.ModConfig;
|
import net.neoforged.fml.config.ModConfig;
|
||||||
import net.neoforged.neoforge.common.ModConfigSpec;
|
import net.neoforged.neoforge.common.ModConfigSpec;
|
||||||
|
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
public final class Config {
|
public final class Config {
|
||||||
public static void init(ModContainer modContainer) {
|
public static void init(ModContainer modContainer) {
|
||||||
modContainer.registerConfig(ModConfig.Type.SERVER, Server.SPEC);
|
modContainer.registerConfig(ModConfig.Type.SERVER, Server.SPEC);
|
||||||
@ -24,8 +26,6 @@ public final class Config {
|
|||||||
static {
|
static {
|
||||||
ModConfigSpec.Builder builder = new ModConfigSpec.Builder();
|
ModConfigSpec.Builder builder = new ModConfigSpec.Builder();
|
||||||
|
|
||||||
builder.comment("WHEN MAKING CHANGES IT IS RECOMMENDED TO NOT BE IN A WORLD.\n" +
|
|
||||||
"CHANGES WILL MOST LIKELY REQUIRE A RESTART FOR EVERYTHING TO WORK PROPERLY.");
|
|
||||||
STRAW_TOTEM_CONFIG = new TotemConfig(builder, StrawTotemItem.getName(), -1, 3,
|
STRAW_TOTEM_CONFIG = new TotemConfig(builder, StrawTotemItem.getName(), -1, 3,
|
||||||
1, false, false, 1);
|
1, false, false, 1);
|
||||||
IRON_TOTEM_CONFIG = new TotemConfig(builder, IronTotemItem.getName(), -1, 5,
|
IRON_TOTEM_CONFIG = new TotemConfig(builder, IronTotemItem.getName(), -1, 5,
|
||||||
@ -85,13 +85,7 @@ public final class Config {
|
|||||||
public double getChargeCostMultiplier() { return CHARGE_COST_MULTIPLIER.get(); }
|
public double getChargeCostMultiplier() { return CHARGE_COST_MULTIPLIER.get(); }
|
||||||
public boolean getCanReviveMoreExpensiveTargets() { return CAN_REVIVE_MORE_EXPENSIVE_TARGETS.get(); }
|
public boolean getCanReviveMoreExpensiveTargets() { return CAN_REVIVE_MORE_EXPENSIVE_TARGETS.get(); }
|
||||||
public boolean getCanReviveAcrossDimensions() { return CAN_REVIVE_ACROSS_DIMENSIONS.get(); }
|
public boolean getCanReviveAcrossDimensions() { return CAN_REVIVE_ACROSS_DIMENSIONS.get(); }
|
||||||
public int getDurability() {
|
public int getDurability() { return DURABILITY.get(); }
|
||||||
try {
|
public int getConfigHash() { return Objects.hash(getDurability()); }
|
||||||
return DURABILITY.get();
|
|
||||||
} catch (IllegalStateException e) {
|
|
||||||
return 10;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,16 +1,24 @@
|
|||||||
package dev.micle.totem_of_reviving.setup;
|
package dev.micle.totem_of_reviving.setup;
|
||||||
|
|
||||||
|
import dev.micle.totem_of_reviving.component.TotemConfigHashData;
|
||||||
import dev.micle.totem_of_reviving.component.TotemData;
|
import dev.micle.totem_of_reviving.component.TotemData;
|
||||||
import net.minecraft.core.component.DataComponentType;
|
import net.minecraft.core.component.DataComponentType;
|
||||||
import net.neoforged.neoforge.registries.DeferredHolder;
|
import net.neoforged.neoforge.registries.DeferredHolder;
|
||||||
|
|
||||||
public class ModDataComponents {
|
public class ModDataComponents {
|
||||||
public static final DeferredHolder<DataComponentType<?>, DataComponentType<TotemData>> TOTEM_DATA = Registration.DATA_COMPONENTS.registerComponentType(
|
public static final DeferredHolder<DataComponentType<?>, DataComponentType<TotemData>> TOTEM_DATA = Registration.DATA_COMPONENTS.registerComponentType(
|
||||||
"basic",
|
"totem_data",
|
||||||
builder -> builder
|
builder -> builder
|
||||||
.persistent(TotemData.CODEC)
|
.persistent(TotemData.CODEC)
|
||||||
.networkSynchronized(TotemData.STREAM_CODEC)
|
.networkSynchronized(TotemData.STREAM_CODEC)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
public static final DeferredHolder<DataComponentType<?>, DataComponentType<TotemConfigHashData>> TOTEM_CONFIG_HASH_DATA = Registration.DATA_COMPONENTS.registerComponentType(
|
||||||
|
"totem_config_hash_data",
|
||||||
|
builder -> builder
|
||||||
|
.persistent(TotemConfigHashData.CODEC)
|
||||||
|
.networkSynchronized(TotemConfigHashData.STREAM_CODEC)
|
||||||
|
);
|
||||||
|
|
||||||
public static void register() {}
|
public static void register() {}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -21,6 +21,7 @@ public enum LangAsset {
|
|||||||
TOOLTIP_TOTEM_DYNAMIC_COST("tooltip", "totem_dynamic_cost"),
|
TOOLTIP_TOTEM_DYNAMIC_COST("tooltip", "totem_dynamic_cost"),
|
||||||
TOOLTIP_TOTEM_CAN_REVIVE_MORE_EXPENSIVE_TARGETS("tooltip", "totem_can_revive_more_expensive_targets"),
|
TOOLTIP_TOTEM_CAN_REVIVE_MORE_EXPENSIVE_TARGETS("tooltip", "totem_can_revive_more_expensive_targets"),
|
||||||
TOOLTIP_TOTEM_CAN_REVIVE_ACROSS_DIMENSIONS("tooltip", "totem_can_revive_across_dimensions"),
|
TOOLTIP_TOTEM_CAN_REVIVE_ACROSS_DIMENSIONS("tooltip", "totem_can_revive_across_dimensions"),
|
||||||
|
TOOLTIP_TOTEM_IS_UNBREAKABLE("tooltip", "totem_is_unbreakable"),
|
||||||
TOOLTIP_TOTEM_REVIVE_INSTRUCTION("tooltip", "totem_revive_instruction"),
|
TOOLTIP_TOTEM_REVIVE_INSTRUCTION("tooltip", "totem_revive_instruction"),
|
||||||
TOOLTIP_TOTEM_CHARGE_INSTRUCTION("tooltip", "totem_charge_instruction"),
|
TOOLTIP_TOTEM_CHARGE_INSTRUCTION("tooltip", "totem_charge_instruction"),
|
||||||
TOOLTIP_TOTEM_CHANGE_TARGET_INSTRUCTION("tooltip", "totem_change_target_instructions"),
|
TOOLTIP_TOTEM_CHANGE_TARGET_INSTRUCTION("tooltip", "totem_change_target_instructions"),
|
||||||
|
|||||||
@ -14,6 +14,7 @@
|
|||||||
"tooltip.totem_of_reviving.totem_dynamic_cost": "Dynamic cost (Multiplier: %s).",
|
"tooltip.totem_of_reviving.totem_dynamic_cost": "Dynamic cost (Multiplier: %s).",
|
||||||
"tooltip.totem_of_reviving.totem_can_revive_more_expensive_targets": "Can revive more expensive targets.",
|
"tooltip.totem_of_reviving.totem_can_revive_more_expensive_targets": "Can revive more expensive targets.",
|
||||||
"tooltip.totem_of_reviving.totem_can_revive_across_dimensions": "Can revive across dimensions.",
|
"tooltip.totem_of_reviving.totem_can_revive_across_dimensions": "Can revive across dimensions.",
|
||||||
|
"tooltip.totem_of_reviving.totem_is_unbreakable": "Unbreakable.",
|
||||||
"tooltip.totem_of_reviving.totem_revive_instruction": "When second hand is empty: revive target.",
|
"tooltip.totem_of_reviving.totem_revive_instruction": "When second hand is empty: revive target.",
|
||||||
"tooltip.totem_of_reviving.totem_charge_instruction": "When second hand has a reviving charge: charge totem.",
|
"tooltip.totem_of_reviving.totem_charge_instruction": "When second hand has a reviving charge: charge totem.",
|
||||||
"tooltip.totem_of_reviving.totem_change_target_instructions": "Change target.",
|
"tooltip.totem_of_reviving.totem_change_target_instructions": "Change target.",
|
||||||
|
|||||||
Reference in New Issue
Block a user