diff --git a/common/src/main/kotlin/org/valkyrienskies/clockwork/ClockworkConfig.kt b/common/src/main/kotlin/org/valkyrienskies/clockwork/ClockworkConfig.kt index 07814181d..8bc3adb3e 100644 --- a/common/src/main/kotlin/org/valkyrienskies/clockwork/ClockworkConfig.kt +++ b/common/src/main/kotlin/org/valkyrienskies/clockwork/ClockworkConfig.kt @@ -35,6 +35,12 @@ object ClockworkConfig { @ConfigEntry(description = "Gas energy display unit") var energyDisplayUnit = DuctUnits.EnergyUnit.JOULE + + @ConfigEntry(description = "Threshold for high temperature warning. 0.9 = 90% of maximum", min = 0.0, max = 1.0) + var maxTemperatureWarning = 0.9 + + @ConfigEntry(description = "Threshold for high pressure warning. 0.9 = 90% of maximum", min = 0.0, max = 1.0) + var maxPressureWarning = 0.9 } class Server { diff --git a/common/src/main/kotlin/org/valkyrienskies/clockwork/content/logistics/gas/IClockworkNodeBE.kt b/common/src/main/kotlin/org/valkyrienskies/clockwork/content/logistics/gas/IClockworkNodeBE.kt index a63f4eeeb..6f90817c4 100644 --- a/common/src/main/kotlin/org/valkyrienskies/clockwork/content/logistics/gas/IClockworkNodeBE.kt +++ b/common/src/main/kotlin/org/valkyrienskies/clockwork/content/logistics/gas/IClockworkNodeBE.kt @@ -5,11 +5,12 @@ import dev.architectury.platform.Platform import net.minecraft.ChatFormatting import net.minecraft.client.Minecraft import net.minecraft.network.chat.Component -import org.valkyrienskies.clockwork.ClockworkGasses +import org.valkyrienskies.clockwork.ClockworkConfig import org.valkyrienskies.clockwork.ClockworkLang import org.valkyrienskies.clockwork.ClockworkMod import org.valkyrienskies.clockwork.ClockworkModClient import org.valkyrienskies.clockwork.util.gui.DuctTextUtil +import org.valkyrienskies.clockwork.util.gui.DuctTextUtil.gasComponent import org.valkyrienskies.clockwork.util.gui.IHaveDuctStats import org.valkyrienskies.kelvin.util.INodeBlockEntity import org.valkyrienskies.kelvin.util.KelvinExtensions.toMinecraft @@ -28,59 +29,71 @@ interface IClockworkNodeBE: INodeBlockEntity, IHaveGoggleInformation { var found = false kelvin.nodeInfo[pos]?.totalVolume?.let { volume -> - found = true ClockworkLang.builder().apply { - add(ClockworkLang.translate("gui.ductInfo.volume").add(ClockworkLang.text(": ")).style(ChatFormatting.GREEN)) - add(DuctTextUtil.translateVolume(ClockworkLang.builder(), volume, true).style(ChatFormatting.GREEN)) - space() + add(ClockworkLang.translate( + "gui.ductInfo.volume", + DuctTextUtil.translateVolume(ClockworkLang.builder(), volume, true) + ).style(ChatFormatting.GREEN)) forGoggles(tooltip, 0) } } kelvin.getTemperatureAt(pos).let { temp -> found = true ClockworkLang.builder().apply { - add(ClockworkLang.translate("gui.ductInfo.temperature").add(ClockworkLang.text(": ")).style(ChatFormatting.GOLD)) - add(DuctTextUtil.translateTemperature(ClockworkLang.builder(), temp, true).style(ChatFormatting.GOLD)) + val max = blockStats?.getMaximumTemperature() + val critical = if (max != null) temp > max * ClockworkConfig.CLIENT.maxTemperatureWarning else false + val indents = if (critical) -2 else 0 + + if (critical) text("!! ") + add(ClockworkLang.translate( + "gui.ductInfo.temperature", + DuctTextUtil.translateTemperature(ClockworkLang.builder(), temp, true) + )) + style(ChatFormatting.GOLD) if (isPlayerSneaking) - blockStats?.getMaximumTemperature()?.let { max -> - add(ClockworkLang.text(" / ") - .add(DuctTextUtil.translateTemperature(ClockworkLang.builder(), max, true)) - .style(ChatFormatting.DARK_GRAY) - ) + if (max != null) { + add(ClockworkLang.translate( + "gui.ductInfo.out_of", + DuctTextUtil.translateTemperature(ClockworkLang.builder(), max, true) + ).style(ChatFormatting.DARK_GRAY)) } - space() - - forGoggles(tooltip, 0) + forGoggles(tooltip, indents) } } kelvin.getPressureAt(pos).takeIf { it > 0.0 }?.let { pressure -> found = true ClockworkLang.builder().apply { - add(ClockworkLang.translate("gui.ductInfo.pressure").add(ClockworkLang.text(": ")).style(ChatFormatting.BLUE)) - add(DuctTextUtil.translatePressure(ClockworkLang.builder(), pressure, true).style(ChatFormatting.BLUE)) + val max = blockStats?.getMaximumPressure() + val critical = if (max != null) pressure > max * ClockworkConfig.CLIENT.maxPressureWarning else false + val indents = if (critical) -2 else 0 + + if (critical) text("!! ") + add(ClockworkLang.translate( + "gui.ductInfo.pressure", + DuctTextUtil.translatePressure(ClockworkLang.builder(), pressure, true) + )) + style(ChatFormatting.BLUE) if (isPlayerSneaking) - blockStats?.getMaximumPressure()?.let { max -> - add(ClockworkLang.text(" / ") - .add(DuctTextUtil.translatePressure(ClockworkLang.builder(), max, true)) - .style(ChatFormatting.DARK_GRAY) - ) + if (max != null) { + add(ClockworkLang.translate( + "gui.ductInfo.out_of", + DuctTextUtil.translatePressure(ClockworkLang.builder(), max, true) + ).style(ChatFormatting.DARK_GRAY)) } - space() - - forGoggles(tooltip, 0) + forGoggles(tooltip, indents) } } if (isPlayerSneaking) kelvin.getHeatEnergy(pos).takeIf { it > 0.0 }?.let { energy -> found = true ClockworkLang.builder().apply { - add(ClockworkLang.translate("gui.ductInfo.energy").add(ClockworkLang.text(": ")).style(ChatFormatting.RED)) - add(DuctTextUtil.translateEnergy(ClockworkLang.builder(), energy, true).style(ChatFormatting.RED)) - space() - + add(ClockworkLang.translate( + "gui.ductInfo.energy", + DuctTextUtil.translateEnergy(ClockworkLang.builder(), energy, true) + ).style(ChatFormatting.RED)) forGoggles(tooltip, 0) } } @@ -94,41 +107,27 @@ interface IClockworkNodeBE: INodeBlockEntity, IHaveGoggleInformation { .mapNotNull { (gas, amount) -> if (amount <= 0.0) return@mapNotNull null totalGasMass += amount - - val component = Component.empty().apply { - append(Component.literal(ClockworkGasses.getDisplayCharacterCode(gas)) - .withStyle { it.withFont(ClockworkGasses.ICON_FONT_LOCATION) }) - if (isPlayerSneaking) { - append(Component.literal(" ${gas.name} ").withStyle(ChatFormatting.GRAY)) - } else { - append(Component.literal(" ")) - } - append(DuctTextUtil.translateMass(ClockworkLang.builder(), amount, true).component()) - } - finishedComponents.add(component) + finishedComponents.add(gasComponent(gas, amount, isPlayerSneaking)) } if (finishedComponents.isEmpty()) return@let ClockworkLang.translate("gui.ductInfo.title.contents").forGoggles(tooltip) - val rows = mutableListOf>() - for (num in finishedComponents.indices step 2) { - if (num + 1 < finishedComponents.size) { - rows.add(Pair(finishedComponents[num], finishedComponents[num + 1])) - } else { - rows.add(Pair(finishedComponents[num], Component.empty())) - } - } - for (row in rows) { - val rowComponent = Component.empty() - .append(row.first) - .append(Component.literal(" ")) - .append(row.second) - ClockworkLang.builder().add(rowComponent).forGoggles(tooltip, 1) + for (row in finishedComponents.chunked(2)) { + ClockworkLang.builder().add( + ClockworkLang.builder().apply { + add(row[0]) + if (row.size > 1) { + text(" ") + add(row[1]) + } + } + ).forGoggles(tooltip, 1) } if (isPlayerSneaking && finishedComponents.size > 1) - ClockworkLang.translate("gui.ductInfo.mass_total").add( + ClockworkLang.translate( + "gui.ductInfo.mass_total", DuctTextUtil.translateMass(ClockworkLang.builder(), totalGasMass, true) ).style(ChatFormatting.GRAY).forGoggles(tooltip, 1) diff --git a/common/src/main/kotlin/org/valkyrienskies/clockwork/content/logistics/gas/generation/compressor/AirCompressorBlockEntity.kt b/common/src/main/kotlin/org/valkyrienskies/clockwork/content/logistics/gas/generation/compressor/AirCompressorBlockEntity.kt index 038c30ce0..2e31e1b6b 100644 --- a/common/src/main/kotlin/org/valkyrienskies/clockwork/content/logistics/gas/generation/compressor/AirCompressorBlockEntity.kt +++ b/common/src/main/kotlin/org/valkyrienskies/clockwork/content/logistics/gas/generation/compressor/AirCompressorBlockEntity.kt @@ -1,23 +1,34 @@ package org.valkyrienskies.clockwork.content.logistics.gas.generation.compressor +import net.minecraft.ChatFormatting import net.minecraft.core.BlockPos import net.minecraft.nbt.CompoundTag +import net.minecraft.network.chat.CommonComponents +import net.minecraft.network.chat.Component import net.minecraft.world.level.block.entity.BlockEntityType import net.minecraft.world.level.block.state.BlockState import org.valkyrienskies.clockwork.ClockworkConfig; +import org.valkyrienskies.clockwork.ClockworkLang import org.valkyrienskies.clockwork.ClockworkMod import org.valkyrienskies.clockwork.util.AerodynamicUtils import org.valkyrienskies.clockwork.util.KNodeKineticBlockEntity +import org.valkyrienskies.clockwork.util.gui.ClockworkTooltipHelper +import org.valkyrienskies.clockwork.util.gui.DuctTextUtil import org.valkyrienskies.kelvin.impl.registry.GasTypeRegistry import org.valkyrienskies.mod.api.dimensionId -import org.valkyrienskies.mod.api.getShipManagingBlock -import org.valkyrienskies.mod.common.util.toJOMLD +import org.valkyrienskies.mod.common.toWorldCoordinates import kotlin.math.abs import kotlin.math.max class AirCompressorBlockEntity(typeIn: BlockEntityType<*>, pos: BlockPos, state: BlockState) : KNodeKineticBlockEntity(typeIn, pos, state) { - var isActivated: Boolean = false - private set + enum class CompressorStatus { + ACTIVE, + INACTIVE, + EXHAUSTED, + OBSTRUCTED + } + var status: CompressorStatus = CompressorStatus.INACTIVE + set(value) { if (field != value) { field = value; sendData() } } var clientParticles: Boolean = false var clientSize: Float = 0.0f @@ -25,18 +36,17 @@ class AirCompressorBlockEntity(typeIn: BlockEntityType<*>, pos: BlockPos, state: private val airGas = GasTypeRegistry.getGasType("kelvin", "air") private val heliumGas = GasTypeRegistry.getGasType("vs_clockwork", "aether") - fun getAirDensity(): Double { - - val ship = level.getShipManagingBlock(blockPos) - val position = ship?.transform?.toWorld?.transformPosition(blockPos.toJOMLD()) ?: blockPos.toJOMLD() + val active get() = status == CompressorStatus.ACTIVE + val exhausted get() = status == CompressorStatus.EXHAUSTED + val obstructed get() = status == CompressorStatus.OBSTRUCTED + fun getAirDensity(): Double { + val position = level.toWorldCoordinates(blockPos) return AerodynamicUtils.getAirDensityForY(position.y, level!!.dimensionId) } fun getAirTemperature(): Double { - val ship = level.getShipManagingBlock(blockPos) - val position = ship?.transform?.toWorld?.transformPosition(blockPos.toJOMLD()) ?: blockPos.toJOMLD() - + val position = level.toWorldCoordinates(blockPos) return AerodynamicUtils.getAirTemperatureForY(position.y, level!!.dimensionId) } @@ -50,25 +60,59 @@ class AirCompressorBlockEntity(typeIn: BlockEntityType<*>, pos: BlockPos, state: val kelvin = ClockworkMod.getKelvin() kelvin.getNodeAt(getDuctNodePosition()) ?: return - val pressure = kelvin.getPressureAt(getDuctNodePosition()) val speed = abs(getSpeed()) + if (level!!.getBlockState(blockPos.above()).isAir) { + if (speed > 0) { + // Should this depend on actual air pressure outside? If we are in vacuum, + // no way this compressor thing will still pump 10 ground atmospheres. + // Maybe something airCompressorMaxPressureFactor instead? + if (kelvin.getPressureAt(getDuctNodePosition()) < ClockworkConfig.SERVER.airCompressorMaxPressure) { + status = CompressorStatus.ACTIVE + // Future: proper API for defining atmospheric composition? + val heliumShare = max( + 0.0, + 1 - getAirDensity() / ClockworkConfig.SERVER.airCompressorHeliumAirDensity + ) + val deltaVolume = ClockworkConfig.SERVER.airCompressorSpeed * speed + kelvin.addGasAtTemperature( + getDuctNodePosition(),airGas, (1 - heliumShare) * deltaVolume, getAirTemperature() + ) + kelvin.addGasAtTemperature( + getDuctNodePosition(),heliumGas, heliumShare * deltaVolume, getAirTemperature() + ) + } else status = CompressorStatus.EXHAUSTED + } else status = CompressorStatus.INACTIVE + } else status = CompressorStatus.OBSTRUCTED + } - if (speed>0 && pressure< ClockworkConfig.SERVER.airCompressorMaxPressure) { - if (!isActivated) { - isActivated = true - sendData() + override fun addToGoggleTooltip(tooltip: List?, isPlayerSneaking: Boolean): Boolean { + if (status != CompressorStatus.INACTIVE) { + ClockworkLang.translate("gui.air_compressor.info.title").forGoggles((tooltip as MutableList)) + when (status) { + CompressorStatus.OBSTRUCTED -> { + ClockworkTooltipHelper.addHint(tooltip, "gui.air_compressor.info.obstructed") + } + CompressorStatus.EXHAUSTED -> { + ClockworkTooltipHelper.addHint(tooltip, "gui.air_compressor.info.exhausted") + } + CompressorStatus.ACTIVE -> { + ClockworkLang + .translate("gui.air_compressor.info.active.title").style(ChatFormatting.GREEN) + .forGoggles(tooltip) + ClockworkLang + .translate( + "gui.air_compressor.info.active", + DuctTextUtil.translateTemperature( + ClockworkLang.builder(), getAirTemperature(), true + ).style(ChatFormatting.GOLD) + ).style(ChatFormatting.GRAY) + .forGoggles(tooltip) + } + else -> {} } - - - val heliumShare = max(0.0, (ClockworkConfig.SERVER.airCompressorHeliumAirDensity - getAirDensity())) / ClockworkConfig.SERVER.airCompressorHeliumAirDensity - val deltaVolume = ClockworkConfig.SERVER.airCompressorSpeed*speed - - kelvin.addGasAtTemperature(getDuctNodePosition(),airGas, (1-heliumShare)*deltaVolume, getAirTemperature()) - kelvin.addGasAtTemperature(getDuctNodePosition(),heliumGas, heliumShare*deltaVolume, getAirTemperature()) - } else if (isActivated) { - isActivated = false; - sendData() + tooltip.add(CommonComponents.EMPTY) } + return super.addToGoggleTooltip(tooltip, isPlayerSneaking) } override fun remove() { @@ -76,12 +120,12 @@ class AirCompressorBlockEntity(typeIn: BlockEntityType<*>, pos: BlockPos, state: } override fun read(tag: CompoundTag, clientPacket: Boolean) { - isActivated = tag.getBoolean("isActivated") + status = CompressorStatus.valueOf(tag.getString("status")) super.read(tag, clientPacket) } override fun write(tag: CompoundTag, clientPacket: Boolean) { - tag.putBoolean("isActivated",isActivated) + tag.putString("status", status.toString()) super.write(tag, clientPacket) } diff --git a/common/src/main/kotlin/org/valkyrienskies/clockwork/content/logistics/gas/generation/compressor/AirCompressorRenderer.kt b/common/src/main/kotlin/org/valkyrienskies/clockwork/content/logistics/gas/generation/compressor/AirCompressorRenderer.kt index d92cc006f..d54c863b2 100644 --- a/common/src/main/kotlin/org/valkyrienskies/clockwork/content/logistics/gas/generation/compressor/AirCompressorRenderer.kt +++ b/common/src/main/kotlin/org/valkyrienskies/clockwork/content/logistics/gas/generation/compressor/AirCompressorRenderer.kt @@ -90,7 +90,7 @@ class AirCompressorRenderer(context: BlockEntityRendererProvider.Context?) : Kin val sizeMultiplier = when { minecraft.isPaused -> 0f // Deflate if particles were spawned OR if the compressor is off - be.clientParticles || !be.isActivated -> -1f + be.clientParticles || !be.active -> -1f else -> 1f } diff --git a/common/src/main/kotlin/org/valkyrienskies/clockwork/content/logistics/gas/heater/GasHeaterBlockEntity.kt b/common/src/main/kotlin/org/valkyrienskies/clockwork/content/logistics/gas/heater/GasHeaterBlockEntity.kt index 7779d6d8d..02a0fa8fc 100644 --- a/common/src/main/kotlin/org/valkyrienskies/clockwork/content/logistics/gas/heater/GasHeaterBlockEntity.kt +++ b/common/src/main/kotlin/org/valkyrienskies/clockwork/content/logistics/gas/heater/GasHeaterBlockEntity.kt @@ -5,13 +5,16 @@ import com.simibubi.create.content.processing.burner.BlazeBurnerBlock.HeatLevel import com.simibubi.create.foundation.blockEntity.behaviour.BlockEntityBehaviour import net.minecraft.ChatFormatting import net.minecraft.core.BlockPos +import net.minecraft.network.chat.CommonComponents import net.minecraft.network.chat.Component import net.minecraft.world.level.block.entity.BlockEntityType import net.minecraft.world.level.block.state.BlockState import org.valkyrienskies.clockwork.ClockworkConfig +import org.valkyrienskies.clockwork.ClockworkLang import org.valkyrienskies.clockwork.ClockworkMod -import org.valkyrienskies.clockwork.ClockworkMod.MOD_ID import org.valkyrienskies.clockwork.util.KNodeBlockEntity +import org.valkyrienskies.clockwork.util.gui.ClockworkTooltipHelper +import org.valkyrienskies.clockwork.util.gui.DuctTextUtil import org.valkyrienskies.kelvin.api.DuctNodePos import org.valkyrienskies.kelvin.util.KelvinExtensions.toDuctNodePos @@ -63,11 +66,43 @@ class GasHeaterBlockEntity(type: BlockEntityType<*>, pos: BlockPos, state: Block } override fun addToGoggleTooltip(tooltip: List?, isPlayerSneaking: Boolean): Boolean { - (tooltip as MutableList).add(Component.translatable("$MOD_ID.gas_heater.heater_info").withStyle(ChatFormatting.GRAY)) - - tooltip.add(Component.translatable("$MOD_ID.gas_heater.heat_level", level!!.getBlockState(blockPos).getValue(HEAT_LEVEL).name).withStyle(ChatFormatting.YELLOW)) - tooltip.add(Component.empty()) - + ClockworkLang.translate("gui.gas_heater.info.title").forGoggles((tooltip as MutableList)) + when (blockState.getValue(HEAT_LEVEL)) { + HeatLevel.SEETHING, HeatLevel.FADING -> { + ClockworkTooltipHelper.addHint(tooltip, "gui.gas_heater.info.heat_level.superheated", ChatFormatting.AQUA) + } + HeatLevel.KINDLED -> { + ClockworkTooltipHelper.addHint(tooltip, "gui.gas_heater.info.heat_level.heated", ChatFormatting.GOLD) + if (isPlayerSneaking) + ClockworkLang.translate("gui.gas_heater.info.heat_level.next", + DuctTextUtil.translateTemperature( + ClockworkLang.builder(), + ClockworkConfig.SERVER.heaterSeethingTemp.toDouble(), true + ) + ).style(ChatFormatting.DARK_GRAY).forGoggles(tooltip) + } + HeatLevel.SMOULDERING -> { + ClockworkTooltipHelper.addHint(tooltip, "gui.gas_heater.info.heat_level.passive", ChatFormatting.RED) + if (isPlayerSneaking) + ClockworkLang.translate("gui.gas_heater.info.heat_level.next", + DuctTextUtil.translateTemperature( + ClockworkLang.builder(), + ClockworkConfig.SERVER.heaterKindledTemp.toDouble(), true + ) + ).style(ChatFormatting.DARK_GRAY).forGoggles(tooltip) + } + else -> { + ClockworkTooltipHelper.addHint(tooltip, "gui.gas_heater.info.heat_level.none", ChatFormatting.GRAY) + if (isPlayerSneaking) + ClockworkLang.translate("gui.gas_heater.info.heat_level.next", + DuctTextUtil.translateTemperature( + ClockworkLang.builder(), + ClockworkConfig.SERVER.heaterSmoulderingTemp.toDouble(), true + ) + ).style(ChatFormatting.DARK_GRAY).forGoggles(tooltip) + } + } + tooltip.add(CommonComponents.EMPTY) return super.addToGoggleTooltip(tooltip, isPlayerSneaking) } } \ No newline at end of file diff --git a/common/src/main/kotlin/org/valkyrienskies/clockwork/content/logistics/gas/pockets/nozzle/GasNozzleBlockEntity.kt b/common/src/main/kotlin/org/valkyrienskies/clockwork/content/logistics/gas/pockets/nozzle/GasNozzleBlockEntity.kt index e42e73015..1fc21957e 100644 --- a/common/src/main/kotlin/org/valkyrienskies/clockwork/content/logistics/gas/pockets/nozzle/GasNozzleBlockEntity.kt +++ b/common/src/main/kotlin/org/valkyrienskies/clockwork/content/logistics/gas/pockets/nozzle/GasNozzleBlockEntity.kt @@ -10,6 +10,7 @@ import net.minecraft.client.multiplayer.ClientLevel import net.minecraft.core.BlockPos import net.minecraft.core.Direction import net.minecraft.nbt.CompoundTag +import net.minecraft.network.chat.CommonComponents import net.minecraft.network.chat.Component import net.minecraft.resources.ResourceLocation import net.minecraft.server.level.ServerLevel @@ -17,27 +18,25 @@ import net.minecraft.util.Mth import net.minecraft.util.RandomSource import net.minecraft.world.level.block.entity.BlockEntityType import net.minecraft.world.level.block.state.BlockState -import net.minecraft.world.level.block.state.properties.BlockStateProperties -import org.joml.Vector3f import org.valkyrienskies.clockwork.ClockworkAugmentations +import org.valkyrienskies.clockwork.ClockworkLang import org.valkyrienskies.clockwork.ClockworkMod import org.valkyrienskies.clockwork.ClockworkModClient import org.valkyrienskies.clockwork.ClockworkSounds import org.valkyrienskies.clockwork.content.forces.BalloonController import org.valkyrienskies.clockwork.content.forces.data.BalloonData -import org.valkyrienskies.clockwork.content.logistics.gas.exhaust.ExhaustBlock -import org.valkyrienskies.clockwork.content.logistics.gas.generation.coal_burner.CoalBurnerBlockEntity.Companion.FUEL_ENERGY_DENSITY -import org.valkyrienskies.clockwork.content.logistics.gas.generation.coal_burner.CoalBurnerBlockEntity.Companion.LOG_BURN_TIME import org.valkyrienskies.kelvin.api.DuctNodePos import org.valkyrienskies.clockwork.util.ClockworkUtils.retrieveGasInfoFromPocket import org.valkyrienskies.clockwork.util.KNodeKineticBlockEntity import org.valkyrienskies.clockwork.util.KelvinParticleHelper -import org.valkyrienskies.core.api.world.connectivity.ConnectionStatus +import org.valkyrienskies.clockwork.util.gui.ClockworkTooltipHelper +import org.valkyrienskies.clockwork.util.gui.DuctTextUtil import org.valkyrienskies.kelvin.KelvinMod import org.valkyrienskies.kelvin.api.GasType import org.valkyrienskies.kelvin.impl.registry.GasTypeRegistry import org.valkyrienskies.kelvin.util.KelvinExtensions.toDuctNodePos import org.valkyrienskies.kelvin.util.KelvinExtensions.toVector3i +import org.valkyrienskies.mod.api.isBlockInShipyard import org.valkyrienskies.mod.common.dimensionId import org.valkyrienskies.mod.common.getLoadedShipManagingPos import org.valkyrienskies.mod.common.shipObjectWorld @@ -411,23 +410,44 @@ class GasNozzleBlockEntity(type: BlockEntityType<*>, pos: BlockPos, state: Block } override fun addToGoggleTooltip(tooltip: List?, isPlayerSneaking: Boolean): Boolean { - val bool = super.addToGoggleTooltip(tooltip, isPlayerSneaking) + ClockworkLang.translate("gui.gas_nozzle.info.title").forGoggles((tooltip as MutableList)) + + if (!level.isBlockInShipyard(blockPos.x, blockPos.y, blockPos.z)) { + ClockworkTooltipHelper.addHint(tooltip, "gui.gas_nozzle.info.no_ship", ChatFormatting.GOLD) + } if (!hasPocket || pocketTemperature.isNaN()) { - (tooltip as MutableList?)?.add(Component.literal("Missing pocket.").withStyle(ChatFormatting.GRAY)) - (tooltip as MutableList?)?.add(Component.literal("[Right-click] to re-scan.").withStyle(ChatFormatting.DARK_GRAY).withStyle(ChatFormatting.ITALIC)) + ClockworkTooltipHelper.addHint( + tooltip, "gui.gas_nozzle.info.no_pocket", ChatFormatting.GOLD, 0, 0, + Minecraft.getInstance().options.keyUse.translatedKeyMessage + ) } else { - (tooltip as MutableList?)?.add(Component.literal("Pocket Volume: ${"%,.2f".format(balloonVolume)} m³").withStyle(ChatFormatting.GREEN)) - (tooltip as MutableList?)?.add(Component.literal("Pocket Temperature: ${pocketTemperature.roundToInt()} K").withStyle(ChatFormatting.GOLD)) + ClockworkLang.translate( + "gui.gas_nozzle.info.volume", + DuctTextUtil.translateVolume(ClockworkLang.builder(), balloonVolume, true) + ).style(ChatFormatting.GREEN).forGoggles(tooltip) + ClockworkLang.translate( + "gui.gas_nozzle.info.temperature", + DuctTextUtil.translateTemperature(ClockworkLang.builder(), pocketTemperature, true) + ).style(ChatFormatting.GOLD).forGoggles(tooltip) + if (isPlayerSneaking) { val targetTemperature = ClockworkModClient.getKelvin().getTemperatureAt(getDuctNodePosition()) * pointer.value.toDouble() - (tooltip as MutableList?)?.add(Component.literal("Target Temperature: ${targetTemperature.roundToInt()} K").withStyle(ChatFormatting.YELLOW).withStyle( - ChatFormatting.ITALIC)) + ClockworkLang.translate( + "gui.gas_nozzle.info.target_temperature", + DuctTextUtil.translateTemperature(ClockworkLang.builder(), targetTemperature, true) + ).style(ChatFormatting.YELLOW).style(ChatFormatting.ITALIC).forGoggles(tooltip) } if (currentIdealOutput.toInt() != 0) { - (tooltip as MutableList?)?.add(Component.literal("!! BALLOON INTEGRITY COMPROMISED !!").withStyle(ChatFormatting.RED)) - (tooltip as MutableList?)?.add(Component.literal("Leaks Detected: ${currentIdealOutput.roundToInt()}").withStyle(ChatFormatting.DARK_RED)) + tooltip.add(CommonComponents.EMPTY) + ClockworkTooltipHelper.addHint(tooltip, "gui.gas_nozzle.info.leak", ChatFormatting.RED, -2) + ClockworkLang + .translate("gui.gas_nozzle.info.leak.count", currentIdealOutput.roundToInt()) + .style(ChatFormatting.RED) + .forGoggles(tooltip) } } - return bool + tooltip.add(CommonComponents.EMPTY) + + return super.addToGoggleTooltip(tooltip, isPlayerSneaking) } } diff --git a/common/src/main/kotlin/org/valkyrienskies/clockwork/util/gui/ClockworkTooltipHelper.kt b/common/src/main/kotlin/org/valkyrienskies/clockwork/util/gui/ClockworkTooltipHelper.kt new file mode 100644 index 000000000..b674386be --- /dev/null +++ b/common/src/main/kotlin/org/valkyrienskies/clockwork/util/gui/ClockworkTooltipHelper.kt @@ -0,0 +1,34 @@ +package org.valkyrienskies.clockwork.util.gui + +import net.createmod.catnip.lang.FontHelper +import net.createmod.catnip.lang.FontHelper.cutTextComponent +import net.minecraft.ChatFormatting +import net.minecraft.network.chat.Component +import org.valkyrienskies.clockwork.ClockworkLang + +object ClockworkTooltipHelper { + fun addOnlyHint( + tooltip: MutableList, hintKey: String, indents: Int = 0, vararg args: Any + ) { + val hint = ClockworkLang.translateDirect(hintKey, *args) + val cutComponent = cutTextComponent(hint, FontHelper.Palette.GRAY_AND_WHITE) + for (c in cutComponent) { + ClockworkLang.builder().add(c).forGoggles(tooltip, indents) + } + } + + fun addTitleAndHint( + tooltip: MutableList, titleKey: String, hintKey: String, + style: ChatFormatting = ChatFormatting.GOLD, titleIndents: Int = 0, contentIndents: Int = 0, vararg args: Any + ) { + ClockworkLang.translate(titleKey).style(style).forGoggles(tooltip, titleIndents) + addOnlyHint(tooltip, hintKey, contentIndents, *args) + } + + fun addHint( + tooltip: MutableList, hintKey: String, + style: ChatFormatting = ChatFormatting.GOLD, titleIndents: Int = 0, contentIndents: Int = 0, vararg args: Any + ) { + addTitleAndHint(tooltip, "$hintKey.title", hintKey, style, titleIndents, contentIndents, *args) + } +} \ No newline at end of file diff --git a/common/src/main/kotlin/org/valkyrienskies/clockwork/util/gui/DuctTextUtil.kt b/common/src/main/kotlin/org/valkyrienskies/clockwork/util/gui/DuctTextUtil.kt index f0392ed8a..1fddd3666 100644 --- a/common/src/main/kotlin/org/valkyrienskies/clockwork/util/gui/DuctTextUtil.kt +++ b/common/src/main/kotlin/org/valkyrienskies/clockwork/util/gui/DuctTextUtil.kt @@ -1,8 +1,13 @@ package org.valkyrienskies.clockwork.util.gui import net.createmod.catnip.lang.LangBuilder +import net.minecraft.ChatFormatting +import net.minecraft.network.chat.Component import org.valkyrienskies.clockwork.ClockworkConfig +import org.valkyrienskies.clockwork.ClockworkGasses +import org.valkyrienskies.clockwork.ClockworkLang import org.valkyrienskies.clockwork.util.gui.DuctUnits.* +import org.valkyrienskies.kelvin.api.GasType object DuctTextUtil { @@ -45,4 +50,18 @@ object DuctTextUtil { fun translateMass(builder: LangBuilder, value: Double, allowSimplify: Boolean, unit: MassUnit? = null): LangBuilder { return translate(builder, value, allowSimplify, MassUnit.BASE, ClockworkConfig.CLIENT.massDisplayUnit) } + + @JvmStatic + fun gasComponent(gasType: GasType, mass: Double, detailed: Boolean = false, unit: MassUnit? = null): Component { + return Component.empty().apply { + append(Component.literal(ClockworkGasses.getDisplayCharacterCode(gasType)) + .withStyle { it.withFont(ClockworkGasses.ICON_FONT_LOCATION) }) + if (detailed) { + append(Component.literal(" ${gasType.name} ").withStyle(ChatFormatting.GRAY)) + } else { + append(Component.literal(" ")) + } + append(DuctTextUtil.translateMass(ClockworkLang.builder(), mass, true).component()) + } + } } \ No newline at end of file diff --git a/common/src/main/resources/assets/vs_clockwork/lang/en_us.json b/common/src/main/resources/assets/vs_clockwork/lang/en_us.json index 76e34b4ba..8e5e27c9a 100644 --- a/common/src/main/resources/assets/vs_clockwork/lang/en_us.json +++ b/common/src/main/resources/assets/vs_clockwork/lang/en_us.json @@ -140,9 +140,6 @@ "propeller.rotation_direction.normal": "Normal", "propeller.rotation_direction.inverted": "Reversed", - "vs_clockwork.gas_heater.heater_info": " Heater Info", - "vs_clockwork.gas_heater.heat_level": "Heat Level: %s", - "vs_clockwork.command.get_air_values": "At y: %d density: %d temperature: %d", "vs_clockwork.subtitle.gravitron_start": "Gravitron Booting Up", @@ -388,6 +385,12 @@ "vs_clockwork.gravitron.tool.destroy.description.2": "ship will snap into place.", "vs_clockwork.gravitron.tool.destroy.description.3": "", + "vs_clockwork.unit.temp": "Temperature", + "vs_clockwork.unit.pressure": "Pressure", + "vs_clockwork.unit.energy": "Energy", + "vs_clockwork.unit.volume": "Volume", + "vs_clockwork.unit.mass": "Mass", + "vs_clockwork.unit.temp.kelvin": "K", "vs_clockwork.unit.temp.celsius": "°C", "vs_clockwork.unit.temp.fahrenheit": "°F", @@ -413,13 +416,45 @@ "vs_clockwork.unit.mass.imperial_ton": "ton", "vs_clockwork.unit.mass.ounce": "oz", + "vs_clockwork.gui.air_compressor.info.title": "Compressor Info:", + "vs_clockwork.gui.air_compressor.info.obstructed.title": "Obstructed", + "vs_clockwork.gui.air_compressor.info.obstructed": "Cannot operate with a solid block directly above.", + "vs_clockwork.gui.air_compressor.info.exhausted.title": "Exhausted", + "vs_clockwork.gui.air_compressor.info.exhausted": "_Pressure_ in the system is _too high_ to keep pumping.", + "vs_clockwork.gui.air_compressor.info.active.title": "Active", + "vs_clockwork.gui.air_compressor.info.active": "Pumping air at %s", + + "vs_clockwork.gui.gas_nozzle.info.title": "Balloon Info:", + "vs_clockwork.gui.gas_nozzle.info.no_pocket.title": "No Balloon", + "vs_clockwork.gui.gas_nozzle.info.no_pocket": "[%s] with an empty hand to scan.", + "vs_clockwork.gui.gas_nozzle.info.no_ship.title": "Not on Ship", + "vs_clockwork.gui.gas_nozzle.info.no_ship": "Balloons can only be assembled on _Ships._", + "vs_clockwork.gui.gas_nozzle.info.volume": "Balloon Volume: %s", + "vs_clockwork.gui.gas_nozzle.info.temperature": "Balloon Temperature: %s", + "vs_clockwork.gui.gas_nozzle.info.target_temperature": "Target Temperature: %s", + "vs_clockwork.gui.gas_nozzle.info.leak.title": "!! Balloon Integrity Compromised !!", + "vs_clockwork.gui.gas_nozzle.info.leak": "Gas is _escaping!_", + "vs_clockwork.gui.gas_nozzle.info.leak.count": "Leaks Detected: %d", + + "vs_clockwork.gui.gas_heater.info.title": "Heater Info:", + "vs_clockwork.gui.gas_heater.info.heat_level.superheated.title": "Superheated!", + "vs_clockwork.gui.gas_heater.info.heat_level.superheated": "Equivalent to a _Blaze Burner_ powered with _Blaze Cakes._ Works with _Boilers_ and _Basins._", + "vs_clockwork.gui.gas_heater.info.heat_level.heated.title": "Heated", + "vs_clockwork.gui.gas_heater.info.heat_level.heated": "Equivalent to a powered _Blaze Burner._ Works with _Boilers_ and _Basins._", + "vs_clockwork.gui.gas_heater.info.heat_level.passive.title": "Passive", + "vs_clockwork.gui.gas_heater.info.heat_level.passive": "Equivalent to a _passive heat source_ like campfires or lava.", + "vs_clockwork.gui.gas_heater.info.heat_level.none.title": "Not Heated", + "vs_clockwork.gui.gas_heater.info.heat_level.none": "Pump hot _gas_ into this machine to heat Create machines.", + "vs_clockwork.gui.gas_heater.info.heat_level.next": "Next Tier: %s", + "vs_clockwork.gui.ductInfo.title": "Duct Info:", - "vs_clockwork.gui.ductInfo.volume": "Volume", - "vs_clockwork.gui.ductInfo.temperature": "Temperature", - "vs_clockwork.gui.ductInfo.pressure": "Pressure", - "vs_clockwork.gui.ductInfo.energy": "Thermal Energy", + "vs_clockwork.gui.ductInfo.volume": "Volume: %s", + "vs_clockwork.gui.ductInfo.temperature": "Temperature: %s", + "vs_clockwork.gui.ductInfo.pressure": "Pressure: %s", + "vs_clockwork.gui.ductInfo.energy": "Thermal Energy: %s", + "vs_clockwork.gui.ductInfo.out_of": " / %s", "vs_clockwork.gui.ductInfo.title.contents": "Duct Contents:", - "vs_clockwork.gui.ductInfo.mass_total": "Total ", + "vs_clockwork.gui.ductInfo.mass_total": "Total %s", "vs_clockwork.ponder.wanderwand.header": "Wanderwand", "vs_clockwork.ponder.wanderwand.text_1": "Place the wand in the Physics Infuser",