diff --git a/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/lang/English.kt b/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/lang/English.kt index 343421c3c..45477de5c 100644 --- a/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/lang/English.kt +++ b/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/lang/English.kt @@ -853,6 +853,24 @@ private fun androidFeatures(provider: MatteryLanguageProvider) { private fun gui(provider: MatteryLanguageProvider) { with(provider.english) { + gui("black_hole_generator.help0", "Generates energy using angular momentum of Singularities") + gui("black_hole_generator.help1", "The stronger gravity Singularity has, the more power is generated!") + gui("black_hole_generator.help2", "Using Spacetime Normalizers will reduce gravitation strength of Singularity, which will reduce power output.") + gui("black_hole_generator.help3", "This machine is the only 'safe' way of disposing Singularities, by draining them dry by continuously injecting antimatter until Singularity lose all its mass") + + gui("black_hole_generator.injection_rate.mode", "Injection rate") + gui("black_hole_generator.injection_rate.desc", "Amount of MtU injected each tick, from either injectors (or both)") + gui("black_hole_generator.target_mass.mode", "Target mass") + + gui("black_hole_generator.sustain.mode", "Sustain") + gui("black_hole_generator.sustain.desc", "Keep Singularity's mass at target level, injecting matter or antimatter when necessary") + + gui("black_hole_generator.matter_only.mode", "Inject matter only") + gui("black_hole_generator.matter_only.desc", "Only inject matter into singularity. Way less power generated, but mass of Singularity will increase over time, as well as power output") + + gui("black_hole_generator.antimatter_only.mode", "Inject antimatter only") + gui("black_hole_generator.antimatter_only.desc", "Only inject antimatter into singularity. Way more power generated, but mass of Singularity will decrease over time, as well as power output") + gui("draw_multiblock_guide", "Draw building guide") gui("ago", "%s ago") diff --git a/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/lang/Russian.kt b/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/lang/Russian.kt index 91b373a4b..f3eec2081 100644 --- a/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/lang/Russian.kt +++ b/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/lang/Russian.kt @@ -857,6 +857,23 @@ private fun androidFeatures(provider: MatteryLanguageProvider) { private fun gui(provider: MatteryLanguageProvider) { with(provider.russian) { + gui("black_hole_generator.help0", "Генерирует электричество используя угловое ускорение сингулярностей") + gui("black_hole_generator.help1", "Чем сильнее гравитационное поле сингулярности, тем больше генерация!") + gui("black_hole_generator.help2", "Использование стабилизаторов пространства-времени ослабляет гравитационное поле, снижая генерацию") + gui("black_hole_generator.help3", "Данный генератор единственный способ 'безопасно' избавиться от сингулярности, полностью лишив её накопленной массы в режиме подпитки антиматерией") + + gui("black_hole_generator.injection_rate.mode", "Скорость подпитки") + gui("black_hole_generator.target_mass.mode", "Целевая масса") + + gui("black_hole_generator.sustain.mode", "Поддерживать массу") + gui("black_hole_generator.sustain.desc", "Поддерживать массу сингулярности на заданном значении, подпитывая материей или антиматерией по мере необходимости") + + gui("black_hole_generator.matter_only.mode", "Подпитка материей") + gui("black_hole_generator.matter_only.desc", "Подпитывать только материей, существенно снизив генерацию энергии, но увеличивая массу сингулярности, а так же дальнейшую выработку энергии") + + gui("black_hole_generator.antimatter_only.mode", "Подпитка антиматерией") + gui("black_hole_generator.antimatter_only.desc", "Подпитывать только антиматерией, существенно увеличив генерацию энергии, но уменьшая массу сингулярности, а так же дальнейшую выработку энергии") + gui("draw_multiblock_guide", "Отображать помощника постройки") gui("ago", "%s тому назад") diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/blackhole/BlackHoleBlockEntity.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/blackhole/BlackHoleBlockEntity.kt index 20a701545..084c09392 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/blackhole/BlackHoleBlockEntity.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/blackhole/BlackHoleBlockEntity.kt @@ -49,7 +49,7 @@ import kotlin.math.roundToInt import kotlin.math.sqrt class BlackHoleBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : MatteryBlockEntity(MBlockEntities.BLACK_HOLE, p_155229_, p_155230_) { - var mass by syncher.decimal(BASELINE_MASS, setter = setter@{ field, mass -> + var mass by syncher.decimal(ServerConfig.Blackhole.BASELINE_MASS, setter = setter@{ field, mass -> if (level !is ServerLevel) { field.accept(mass) return@setter @@ -118,7 +118,7 @@ class BlackHoleBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : Mattery else -> massForDiv /= 16384 } - gravitationStrength = sqrt(massForDiv.div(BASELINE_MASS).toDouble()).coerceIn(0.2, 40.0) + gravitationStrength = sqrt(massForDiv.div(ServerConfig.Blackhole.BASELINE_MASS).toDouble()).coerceIn(0.2, 40.0) affectedBounds = BoundingBox( (-30 * gravitationStrength).toInt(), (-30 * gravitationStrength).toInt(), @@ -141,7 +141,7 @@ class BlackHoleBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : Mattery override fun loadAdditional(nbt: CompoundTag, registry: HolderLookup.Provider) { super.loadAdditional(nbt, registry) - mass = nbt.map("mass", Decimal::deserializeNBT) ?: BASELINE_MASS + mass = nbt.map("mass", Decimal::deserializeNBT) ?: ServerConfig.Blackhole.BASELINE_MASS spinDirection = nbt.getBoolean("spin_direction") } @@ -307,7 +307,6 @@ class BlackHoleBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : Mattery companion object { const val ITERATIONS = 30_000 - val BASELINE_MASS = Decimal(50_000) val HAWKING_MASS_LOSE_STEP = Decimal(-100) } } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/blackhole/BlackHoleGeneratorBlockEntity.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/blackhole/BlackHoleGeneratorBlockEntity.kt index 84f0520a6..1f303921f 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/blackhole/BlackHoleGeneratorBlockEntity.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/blackhole/BlackHoleGeneratorBlockEntity.kt @@ -1,9 +1,12 @@ package ru.dbotthepony.mc.otm.block.entity.blackhole +import com.mojang.serialization.Codec import it.unimi.dsi.fastutil.objects.ObjectArrayList import it.unimi.dsi.fastutil.objects.ObjectArraySet import it.unimi.dsi.fastutil.objects.ObjectIterators import net.minecraft.core.BlockPos +import net.minecraft.network.chat.Component +import net.minecraft.util.StringRepresentable import net.minecraft.world.entity.player.Inventory import net.minecraft.world.entity.player.Player import net.minecraft.world.inventory.AbstractContainerMenu @@ -22,10 +25,13 @@ import ru.dbotthepony.mc.otm.capability.energy.CombinedProfiledEnergyStorage import ru.dbotthepony.mc.otm.capability.energy.receiveEnergy import ru.dbotthepony.mc.otm.capability.matter.CombinedProfiledMatterStorage import ru.dbotthepony.mc.otm.config.MachinesConfig +import ru.dbotthepony.mc.otm.config.ServerConfig import ru.dbotthepony.mc.otm.core.RandomSource2Generator +import ru.dbotthepony.mc.otm.core.TranslatableComponent import ru.dbotthepony.mc.otm.core.collect.map import ru.dbotthepony.mc.otm.core.multiblock.ShapedMultiblock import ru.dbotthepony.mc.otm.core.getBlockStateNow +import ru.dbotthepony.mc.otm.core.getValue import ru.dbotthepony.mc.otm.core.immutableList import ru.dbotthepony.mc.otm.core.math.Decimal import ru.dbotthepony.mc.otm.core.math.plus @@ -38,6 +44,7 @@ import ru.dbotthepony.mc.otm.registry.MBlockEntities import ru.dbotthepony.mc.otm.registry.MBlockTags import ru.dbotthepony.mc.otm.registry.MBlocks import java.io.Closeable +import kotlin.math.min class BlackHoleGeneratorBlockEntity(blockPos: BlockPos, blockState: BlockState) : MatteryDeviceBlockEntity(MBlockEntities.BLACK_HOLE_GENERATOR, blockPos, blockState) { var multiblock: ShapedMultiblock? = null @@ -74,10 +81,38 @@ class BlackHoleGeneratorBlockEntity(blockPos: BlockPos, blockState: BlockState) { level?.random?.let { RandomSource2Generator(it) } } ) + enum class Mode(val label: Component, val tooltip: Component) { + TARGET_MASS(TranslatableComponent("otm.gui.black_hole_generator.sustain.mode"), TranslatableComponent("otm.gui.black_hole_generator.sustain.desc")), + MATTER_ONLY(TranslatableComponent("otm.gui.black_hole_generator.matter_only.mode"), TranslatableComponent("otm.gui.black_hole_generator.matter_only.desc")), + ANTIMATTER_ONLY(TranslatableComponent("otm.gui.black_hole_generator.antimatter_only.mode"), TranslatableComponent("otm.gui.black_hole_generator.antimatter_only.desc")); + } + + var mode = Mode.TARGET_MASS + set(value) { + field = value + markDirtyFast() + } + + var injectionRate = Decimal.ONE_TENTH + set(value) { + field = maxOf(Decimal.ONE_TENTH, value) + markDirtyFast() + } + + var targetMass = ServerConfig.Blackhole.BASELINE_MASS + set(value) { + field = maxOf(Decimal.ONE, value) + markDirtyFast() + } + init { exposeSideless(MatteryCapability.MATTER_BLOCK, matter) exposeSideless(MatteryCapability.BLOCK_ENERGY, energy) exposeSideless(Capabilities.EnergyStorage.BLOCK, energy) + + savetables.enum(::mode, map = Mode::valueOf) + savetables.decimal(::injectionRate) + savetables.decimal(::targetMass) } private fun findBlackHoleRange(): Int { @@ -109,6 +144,9 @@ class BlackHoleGeneratorBlockEntity(blockPos: BlockPos, blockState: BlockState) energy.tick() matter.tick() + if (redstoneControl.isBlockedByRedstone) + return + val level = level!! if (lastRange == -1) { @@ -123,14 +161,48 @@ class BlackHoleGeneratorBlockEntity(blockPos: BlockPos, blockState: BlockState) } else { val blackHole = multiblock.blockEntities(BLACK_HOLE).first() - if (matter.extractMatter(MachinesConfig.BlackHoleGenerator.MATTER_RATE, true) != MachinesConfig.BlackHoleGenerator.MATTER_RATE) return - val energyToStore = blackHole.mass / MachinesConfig.BlackHoleGenerator.MASS_DIVISOR - if (energy.receiveEnergy(energyToStore, true) != energyToStore) return + val matterExtracted = matter.extractMatter(if (mode == Mode.TARGET_MASS && blackHole.mass != targetMass) minOf(injectionRate, (blackHole.mass - targetMass).absoluteValue) else injectionRate, true) + if (!matterExtracted.isPositive) return - matter.extractMatter(MachinesConfig.BlackHoleGenerator.MATTER_RATE, false) - energy.receiveEnergy(energyToStore, false) + val targetEnergy = when (mode) { + Mode.TARGET_MASS -> { + if (targetMass > blackHole.mass) { + MachinesConfig.BlackHoleGenerator.GENERATION_RATIO_FEED * matterExtracted * blackHole.gravitationStrength + } else if (targetMass < blackHole.mass) { + MachinesConfig.BlackHoleGenerator.GENERATION_RATIO_DRAIN * matterExtracted * blackHole.gravitationStrength + } else { + MachinesConfig.BlackHoleGenerator.GENERATION_RATIO_SUSTAIN * matterExtracted * blackHole.gravitationStrength + } + } - blackHole.mass += MachinesConfig.BlackHoleGenerator.MASS_FEEDING_RATIO * MachinesConfig.BlackHoleGenerator.MATTER_RATE + Mode.MATTER_ONLY -> MachinesConfig.BlackHoleGenerator.GENERATION_RATIO_FEED * matterExtracted + Mode.ANTIMATTER_ONLY -> MachinesConfig.BlackHoleGenerator.GENERATION_RATIO_DRAIN * matterExtracted + } + + val energyInserted = energy.receiveEnergy(targetEnergy, true) + if (!energyInserted.isPositive) return + val actualMatterRatio = energyInserted / targetEnergy * matterExtracted + + matter.extractMatter(actualMatterRatio, false) + energy.receiveEnergy(energyInserted, false) + + when (mode) { + Mode.TARGET_MASS -> { + if (targetMass > blackHole.mass) { + blackHole.mass += actualMatterRatio * MachinesConfig.BlackHoleGenerator.FEEDING_EFFICIENCY + } else if (targetMass < blackHole.mass) { + blackHole.mass -= actualMatterRatio * MachinesConfig.BlackHoleGenerator.DRAINING_EFFICIENCY + } + } + + Mode.MATTER_ONLY -> { + blackHole.mass += actualMatterRatio * MachinesConfig.BlackHoleGenerator.FEEDING_EFFICIENCY + } + + Mode.ANTIMATTER_ONLY -> { + blackHole.mass -= actualMatterRatio * MachinesConfig.BlackHoleGenerator.DRAINING_EFFICIENCY + } + } } } } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/client/render/Widgets15.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/client/render/Widgets15.kt index adad65d22..2910f8abd 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/client/render/Widgets15.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/client/render/Widgets15.kt @@ -16,4 +16,11 @@ object Widgets15 { val BUTTON_PRESSED = misc15.next() val BUTTON_DISABLED_STRETCHABLE = misc15.makeButton(2f) val BUTTON_DISABLED = misc15.next() + + val RADIO_IDLE = misc15.next() + val RADIO_HOVERED = misc15.next() + val RADIO_PRESSED = misc15.next() + val RADIO_DISABLED = misc15.next() + val RADIO_ICON = misc15.next() + val RADIO_ICON_DISABLED = misc15.next() } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/panels/Label.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/panels/Label.kt index 312e90d56..879473336 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/panels/Label.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/panels/Label.kt @@ -7,9 +7,9 @@ import ru.dbotthepony.mc.otm.client.render.RenderGravity import ru.dbotthepony.mc.otm.core.TextComponent import ru.dbotthepony.kommons.math.RGBAColor -open class Label @JvmOverloads constructor( +open class Label( screen: S, - parent: EditablePanel<*>?, + parent: EditablePanel<*>? = null, x: Float = 0f, y: Float = 0f, width: Float = 100f, diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/panels/button/BooleanButtonPanel.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/panels/button/BooleanButtonPanel.kt index 9383a117a..8d7e30b96 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/panels/button/BooleanButtonPanel.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/panels/button/BooleanButtonPanel.kt @@ -23,10 +23,8 @@ abstract class BooleanButtonPanel( y: Float = 0f, width: Float, height: Float, + val isChecked: Delegate, ) : ButtonPanel(screen, parent, x, y, width, height) { - protected abstract fun onChange(newValue: Boolean) - - abstract var isChecked: Boolean abstract val tooltipActive: Component? abstract val tooltipInactive: Component? abstract val iconActive: IGUIRenderable? @@ -36,17 +34,25 @@ abstract class BooleanButtonPanel( open val iconDisabledInactive: IGUIRenderable? get() = iconInactive + override var isDisabled: Boolean + get() { + if (isChecked is IPlayerInputWithFeedback) { + return !isChecked.test(minecraft.player!!) + } else { + return super.isDisabled + } + } + set(value) { super.isDisabled = value } + override val icon: IGUIRenderable? - get() = if (isChecked) { + get() = if (isChecked.get()) { if (isDisabled) iconDisabledActive else iconActive } else { if (isDisabled) iconDisabledInactive else iconInactive } override fun onClick(mouseButton: Int) { - val newValue = !isChecked - isChecked = newValue - onChange(newValue) + isChecked.accept(!isChecked.get()) } override fun innerRenderTooltips(graphics: MGUIGraphics, mouseX: Float, mouseY: Float, partialTick: Float): Boolean { @@ -65,14 +71,14 @@ abstract class BooleanButtonPanel( } if (tooltipActive != null) { - if (isChecked) + if (isChecked.get()) tooltips.add(TranslatableComponent("otm.gui.tooltip.enum.active", tooltipActive.copy().withStyle(ChatFormatting.WHITE))) else tooltips.add(tooltipActive.copy().withStyle(ChatFormatting.GRAY)) } if (tooltipInactive != null) { - if (isChecked) + if (isChecked.get()) tooltips.add(tooltipInactive.copy().withStyle(ChatFormatting.GRAY)) else tooltips.add(TranslatableComponent("otm.gui.tooltip.enum.active", tooltipInactive.copy().withStyle(ChatFormatting.WHITE))) @@ -85,13 +91,41 @@ abstract class BooleanButtonPanel( return super.innerRenderTooltips(graphics, mouseX, mouseY, partialTick) } - open class Checkbox( + open class Radio( screen: S, - parent: EditablePanel<*>?, + parent: EditablePanel<*>? = null, x: Float = 0f, y: Float = 0f, - val prop: Delegate, - ) : BooleanButtonPanel(screen, parent, x, y, 15f, 15f) { + prop: Delegate, + ) : BooleanButtonPanel(screen, parent, x, y, 15f, 15f, prop) { + override val disabledSprite: IGUIRenderable + get() = Widgets15.RADIO_DISABLED + override val pressedSprite: IGUIRenderable + get() = Widgets15.RADIO_PRESSED + override val hoveredSprite: IGUIRenderable + get() = Widgets15.RADIO_HOVERED + override val idleSprite: IGUIRenderable + get() = Widgets15.RADIO_IDLE + + override var tooltipActive: Component? = null + override var tooltipInactive: Component? = null + override val iconActive: IGUIRenderable? + get() = Widgets15.RADIO_ICON + override val iconInactive: IGUIRenderable? + get() = null + override val iconDisabledActive: IGUIRenderable? + get() = Widgets15.RADIO_ICON_DISABLED + override val iconSpaceReservation: SpaceReservation + get() = SpaceReservation.ICON_ONLY + } + + open class Checkbox( + screen: S, + parent: EditablePanel<*>? = null, + x: Float = 0f, + y: Float = 0f, + prop: Delegate, + ) : BooleanButtonPanel(screen, parent, x, y, 15f, 15f, prop) { constructor( screen: S, parent: EditablePanel<*>?, @@ -119,33 +153,13 @@ abstract class BooleanButtonPanel( prop: Delegate, ) : this(screen, parent, 0f, 0f, prop) - override fun onChange(newValue: Boolean) { - // do nothing - } - var displayUncheckedIcon = true override var label: Component? = null - override var isChecked: Boolean - get() = prop.get() - set(value) { prop.accept(value) } override var labelColor: RGBAColor = RGBAColor.WHITE - override val iconWinding: UVWindingOrder - get() = UVWindingOrder.NORMAL - override var iconOnLeft: Boolean = true override val iconSpaceReservation: SpaceReservation = SpaceReservation.ICON_AND_TEXT - override var isDisabled: Boolean - get() { - if (prop is IPlayerInputWithFeedback) { - return !prop.test(minecraft.player!!) - } else { - return super.isDisabled - } - } - set(value) { super.isDisabled = value } - override var tooltipActive: Component? = null override val tooltipInactive: Component? = null override val iconActive: IGUIRenderable @@ -161,41 +175,23 @@ abstract class BooleanButtonPanel( open class Simple( screen: S, - parent: EditablePanel<*>?, + parent: EditablePanel<*>? = null, x: Float = 0f, y: Float = 0f, width: Float, height: Float, - val prop: Delegate, + prop: Delegate, override var iconActive: IGUIRenderable? = null, override var iconInactive: IGUIRenderable? = null, - val onChange: ((newValue: Boolean) -> Unit)? = null, override var tooltipActive: Component? = null, override var tooltipInactive: Component? = null, - ) : BooleanButtonPanel(screen, parent, x, y, width, height) { - override fun onChange(newValue: Boolean) { - // do nothing - } - + ) : BooleanButtonPanel(screen, parent, x, y, width, height, prop) { override var label: Component? = null - override var isChecked: Boolean - get() = prop.get() - set(value) { prop.accept(value) } override var labelColor: RGBAColor = RGBAColor.WHITE override var iconWinding: UVWindingOrder = UVWindingOrder.NORMAL override var iconOnLeft: Boolean = true override val iconSpaceReservation: SpaceReservation = SpaceReservation.DEFAULT - - override var isDisabled: Boolean - get() { - if (prop is IPlayerInputWithFeedback) { - return !prop.test(minecraft.player!!) - } else { - return super.isDisabled - } - } - set(value) { super.isDisabled = value } } companion object { @@ -209,11 +205,10 @@ abstract class BooleanButtonPanel( prop: Delegate, iconActive: IGUIRenderable? = null, iconInactive: IGUIRenderable? = null, - onChange: ((newValue: Boolean) -> Unit)? = null, tooltipActive: Component? = null, tooltipInactive: Component? = null, ): Simple { - return Simple(screen, parent, x, y, 18f, 18f, prop, iconActive, iconInactive, onChange, tooltipActive, tooltipInactive) + return Simple(screen, parent, x, y, 18f, 18f, prop, iconActive, iconInactive, tooltipActive, tooltipInactive) } fun square15( @@ -224,11 +219,10 @@ abstract class BooleanButtonPanel( prop: Delegate, iconActive: IGUIRenderable? = null, iconInactive: IGUIRenderable? = null, - onChange: ((newValue: Boolean) -> Unit)? = null, tooltipActive: Component? = null, tooltipInactive: Component? = null, ): Simple { - return Simple(screen, parent, x, y, 15f, 15f, prop, iconActive, iconInactive, onChange, tooltipActive, tooltipInactive) + return Simple(screen, parent, x, y, 15f, 15f, prop, iconActive, iconInactive, tooltipActive, tooltipInactive) } fun square8( @@ -239,11 +233,10 @@ abstract class BooleanButtonPanel( prop: Delegate, iconActive: IGUIRenderable? = null, iconInactive: IGUIRenderable? = null, - onChange: ((newValue: Boolean) -> Unit)? = null, tooltipActive: Component? = null, tooltipInactive: Component? = null, ): Simple { - return Simple(screen, parent, x, y, 8f, 8f, prop, iconActive, iconInactive, onChange, tooltipActive, tooltipInactive) + return Simple(screen, parent, x, y, 8f, 8f, prop, iconActive, iconInactive, tooltipActive, tooltipInactive) } fun square18( @@ -252,11 +245,10 @@ abstract class BooleanButtonPanel( prop: Delegate, iconActive: IGUIRenderable? = null, iconInactive: IGUIRenderable? = null, - onChange: ((newValue: Boolean) -> Unit)? = null, tooltipActive: Component? = null, tooltipInactive: Component? = null, ): Simple { - return Simple(screen, parent, 0f, 0f, 18f, 18f, prop, iconActive, iconInactive, onChange, tooltipActive, tooltipInactive) + return Simple(screen, parent, 0f, 0f, 18f, 18f, prop, iconActive, iconInactive, tooltipActive, tooltipInactive) } fun square15( @@ -265,11 +257,10 @@ abstract class BooleanButtonPanel( prop: Delegate, iconActive: IGUIRenderable? = null, iconInactive: IGUIRenderable? = null, - onChange: ((newValue: Boolean) -> Unit)? = null, tooltipActive: Component? = null, tooltipInactive: Component? = null, ): Simple { - return Simple(screen, parent, 0f, 0f, 15f, 15f, prop, iconActive, iconInactive, onChange, tooltipActive, tooltipInactive) + return Simple(screen, parent, 0f, 0f, 15f, 15f, prop, iconActive, iconInactive, tooltipActive, tooltipInactive) } fun square8( @@ -278,11 +269,10 @@ abstract class BooleanButtonPanel( prop: Delegate, iconActive: IGUIRenderable? = null, iconInactive: IGUIRenderable? = null, - onChange: ((newValue: Boolean) -> Unit)? = null, tooltipActive: Component? = null, tooltipInactive: Component? = null, ): Simple { - return Simple(screen, parent, 0f, 0f, 8f, 8f, prop, iconActive, iconInactive, onChange, tooltipActive, tooltipInactive) + return Simple(screen, parent, 0f, 0f, 8f, 8f, prop, iconActive, iconInactive, tooltipActive, tooltipInactive) } } } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/panels/input/NumberInputPanel.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/panels/input/NumberInputPanel.kt index 2ac442cb7..b103a7f7c 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/panels/input/NumberInputPanel.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/panels/input/NumberInputPanel.kt @@ -18,7 +18,7 @@ abstract class NumberInputPanel( x: Float = 0f, y: Float = 0f, width: Float = WIDTH, - height: Float = HeightControls.BUTTON_HEIGHT * 2f, + height: Float = HeightControls.BUTTON_HEIGHT * 2f + 1f, var min: N? = null, var max: N? = null, ) : EditablePanel(screen, parent, x, y, width, height) { @@ -92,12 +92,13 @@ abstract class NumberInputPanel( override val disabledSprite get() = if (!isIncrease) Widgets.ARROW_DOWN_BUTTON_DISABLED else Widgets.ARROW_UP_BUTTON_DISABLED init { - dock = Dock.TOP - - if (isIncrease) + if (isIncrease) { tooltips.add(TranslatableComponent("otm.gui.increase")) - else + dock = Dock.TOP + } else { tooltips.add(TranslatableComponent("otm.gui.decrease")) + dock = Dock.BOTTOM + } } override fun test(value: Int): Boolean { @@ -133,7 +134,7 @@ abstract class LNumberInputPanel( x: Float = 0f, y: Float = 0f, width: Float = WIDTH, - height: Float = HeightControls.BUTTON_HEIGHT * 2f, + height: Float = HeightControls.BUTTON_HEIGHT * 2f + 1f, min: N? = null, max: N? = null, val toNumber: (String) -> N?, @@ -189,7 +190,7 @@ open class DecimalInputPanel( x: Float = 0f, y: Float = 0f, width: Float = WIDTH, - height: Float = HeightControls.BUTTON_HEIGHT * 2f, + height: Float = HeightControls.BUTTON_HEIGHT * 2f + 1f, var step: Decimal = Decimal.ONE, min: Decimal? = null, max: Decimal? = null, diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/panels/input/TextInputPanel.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/panels/input/TextInputPanel.kt index fe411fea0..8c66f1ac3 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/panels/input/TextInputPanel.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/panels/input/TextInputPanel.kt @@ -41,7 +41,7 @@ open class TextInputPanel( x: Float = 0f, y: Float = 0f, width: Float = 60f, - height: Float = 11f, + height: Float = 15f, ) : EditablePanel(screen, parent, x, y, width, height) { private data class TextSelection(val cursor: Int, val shift: Int) { val isLeft get() = shift < 0 @@ -159,7 +159,7 @@ open class TextInputPanel( init { scissor = true - dockPadding = DockProperty(2f, 2f, 2f, 2f) + dockPadding = DockProperty(3f, 3f, 3f, 3f) } private var oldText = ArrayList() diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/panels/util/UtilPanels.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/panels/util/UtilPanels.kt new file mode 100644 index 000000000..b223f1441 --- /dev/null +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/panels/util/UtilPanels.kt @@ -0,0 +1,41 @@ +package ru.dbotthepony.mc.otm.client.screen.panels.util + +import net.minecraft.client.gui.screens.Screen +import ru.dbotthepony.mc.otm.client.screen.panels.Dock +import ru.dbotthepony.mc.otm.client.screen.panels.DockProperty +import ru.dbotthepony.mc.otm.client.screen.panels.DockResizeMode +import ru.dbotthepony.mc.otm.client.screen.panels.EditablePanel +import kotlin.math.max + +fun , L : EditablePanel, S : Screen> makeButtonLabel( + screen: S, + parent: EditablePanel<*>?, + button: B, + label: L, + x: Float = 0f, + y: Float = 0f, +): Triple> { + val canvas = EditablePanel(screen, parent, x, y) + + with(canvas) { + width = button.width + label.width + 2f + height = max(button.height, label.height) + + button.parent = this + label.parent = this + + button.childrenOrder = 0 + label.childrenOrder = 1 + + button.dockMargin = DockProperty.EMPTY + label.dockMargin = DockProperty(left = 2f) + + label.dock = Dock.FILL + label.dockResize = DockResizeMode.WIDTH + + button.dock = Dock.LEFT + button.dockResize = DockResizeMode.NONE + } + + return Triple(button, label, canvas) +} diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/tech/BlackHoleGeneratorScreen.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/tech/BlackHoleGeneratorScreen.kt index 45f38334c..df72120ea 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/tech/BlackHoleGeneratorScreen.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/tech/BlackHoleGeneratorScreen.kt @@ -2,32 +2,84 @@ package ru.dbotthepony.mc.otm.client.screen.tech import net.minecraft.network.chat.Component import net.minecraft.world.entity.player.Inventory +import ru.dbotthepony.mc.otm.block.entity.blackhole.BlackHoleGeneratorBlockEntity import ru.dbotthepony.mc.otm.client.screen.MatteryScreen import ru.dbotthepony.mc.otm.client.screen.panels.Dock -import ru.dbotthepony.mc.otm.client.screen.panels.EditablePanel import ru.dbotthepony.mc.otm.client.screen.panels.FramePanel +import ru.dbotthepony.mc.otm.client.screen.panels.Label import ru.dbotthepony.mc.otm.client.screen.panels.button.BooleanButtonPanel +import ru.dbotthepony.mc.otm.client.screen.panels.button.DeviceControls +import ru.dbotthepony.mc.otm.client.screen.panels.input.DecimalInputPanel +import ru.dbotthepony.mc.otm.client.screen.panels.util.makeButtonLabel import ru.dbotthepony.mc.otm.client.screen.widget.ProfiledMatterGaugePanel import ru.dbotthepony.mc.otm.client.screen.widget.ProfiledPowerGaugePanel +import ru.dbotthepony.mc.otm.core.TextComponent import ru.dbotthepony.mc.otm.core.TranslatableComponent +import ru.dbotthepony.mc.otm.core.math.Decimal import ru.dbotthepony.mc.otm.menu.tech.BlackHoleGeneratorMenu class BlackHoleGeneratorScreen(menu: BlackHoleGeneratorMenu, inventory: Inventory, title: Component) : MatteryScreen(menu, inventory, title) { override fun makeMainFrame(): FramePanel> { - val frame = FramePanel.padded(this, 200f, 60f, title) + val frame = FramePanel.padded(this, 240f, 130f, title) + + frame.behaveAsWindow() + frame.onClose { onClose() } + frame.makeHelpButton().also { + it.tooltips.add(TranslatableComponent("otm.gui.black_hole_generator.help0")) + it.tooltips.add(TranslatableComponent("otm.gui.black_hole_generator.help1")) + it.tooltips.add(TranslatableComponent("otm.gui.black_hole_generator.help2")) + it.tooltips.add(TextComponent("")) + it.tooltips.add(TranslatableComponent("otm.gui.black_hole_generator.help3")) + } val energy = ProfiledPowerGaugePanel(this, frame, menu.energy) val matter = ProfiledMatterGaugePanel(this, frame, menu.matter) - matter.dockLeft = 1f + matter.dockLeft = 2f energy.dock = Dock.LEFT matter.dock = Dock.LEFT - matter.dockRight = 4f + matter.dockRight = 5f val drawGuide = BooleanButtonPanel.Checkbox(this, frame, menu.drawBuildingGuide, TranslatableComponent("otm.gui.draw_multiblock_guide")) drawGuide.dock = Dock.TOP - drawGuide.dockBottom = 2f + + Label(this, frame, text = TranslatableComponent("otm.gui.black_hole_generator.injection_rate.mode")).also { + it.dock = Dock.TOP + it.dockTop = 2f + } + + val injectionRate = DecimalInputPanel(this, frame, menu.injectionRate, min = Decimal.ONE_TENTH, step = Decimal.ONE_TENTH) + injectionRate.dock = Dock.TOP + injectionRate.dockTop = 1f + + Label(this, frame, text = TranslatableComponent("otm.gui.black_hole_generator.target_mass.mode")).also { + it.dock = Dock.TOP + it.dockTop = 2f + } + + val targetMass = DecimalInputPanel(this, frame, menu.targetMass, min = Decimal.ONE, step = Decimal(1000)) + targetMass.dock = Dock.TOP + targetMass.dockTop = 1f + targetMass.dockBottom = 4f + + for (mode in BlackHoleGeneratorBlockEntity.Mode.entries) { + val (radio, label, canvas) = makeButtonLabel( + this, + frame, + BooleanButtonPanel.Radio(this, prop = menu.mode.map({ it == mode }, { if (it) mode else BlackHoleGeneratorBlockEntity.Mode.TARGET_MASS })), + Label(this, text = mode.label) + ) + + label.tooltips.add(mode.tooltip) + radio.tooltips.add(mode.tooltip) + canvas.tooltips.add(mode.tooltip) + + canvas.dock = Dock.TOP + canvas.dockTop = 2f + } + + DeviceControls(this, frame, redstoneConfig = menu.redstoneConfig) return frame } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/widget/MatterGaugePanel.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/widget/MatterGaugePanel.kt index 8fbf9b855..889bf0322 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/widget/MatterGaugePanel.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/widget/MatterGaugePanel.kt @@ -155,3 +155,17 @@ open class ProfiledMatterGaugePanel( } } } + +/** + * Shortcut to [ProfiledMatterGaugePanel] with doubled width + */ +@Suppress("FunctionName") +fun WideProfiledMatterGaugePanel( + screen: S, + parent: EditablePanel<*>? = null, + widget: IProfiledLevelGaugeWidget, + x: Float = 0f, + y: Float = 0f, + width: Float = 18f, + height: Float = 48f +) = ProfiledMatterGaugePanel(screen, parent, widget, x, y, width, height) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/config/MachinesConfig.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/config/MachinesConfig.kt index 139e483c0..9075f56ca 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/config/MachinesConfig.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/config/MachinesConfig.kt @@ -201,21 +201,38 @@ object MachinesConfig : AbstractConfig("machines") { val MATTER_HATCH by builder .comment("Internal buffer of matter hatch") - .defineDecimal("MATTER_HATCH", Decimal(200), Decimal.ONE) + .defineDecimal("MATTER_HATCH", Decimal(4_000), Decimal.ONE) object BlackHoleGenerator { init { builder.push("BLACK_HOLE_GENERATOR") } - val MATTER_RATE: Decimal - get() = Decimal("0.25") + val GENERATION_RATIO_SUSTAIN: Decimal by builder + .comment("Baseline energy generation when Singularity has gravitation strength of 1") + .comment("and inject rate of 1 MtU, in 'target mass' generation mode, *when* target mass is achieved.") + .defineDecimal("GENERATION_RATIO_SUSTAIN", Decimal(8_000)) - val MASS_DIVISOR: Decimal - get() = Decimal.TEN + val GENERATION_RATIO_FEED: Decimal by builder + .comment("Baseline energy generation when Singularity has gravitation strength of 1") + .comment("and inject rate of 1 MtU, in 'inject mater only' generation mode.") + .defineDecimal("GENERATION_RATIO_FEED", Decimal(4_000)) - val MASS_FEEDING_RATIO: Decimal - get() = Decimal("0.1") + val GENERATION_RATIO_DRAIN: Decimal by builder + .comment("Baseline energy generation when Singularity has gravitation strength of 1") + .comment("and inject rate of 1 MtU, in 'inject antimatter only' generation mode.") + .defineDecimal("GENERATION_RATIO_DRAIN", Decimal(25_000)) + + val FEEDING_EFFICIENCY: Decimal by builder + .comment("Efficiency at increasing mass of Singularity when injecting mass,") + .comment("when generator is working in either 'inject only' or 'target mass' modes when") + .comment("Singularity mass is lesser than required. 0.6 means 60% of injected mass") + .comment("increases Singularity mass.") + .defineDecimal("FEEDING_EFFICIENCY", Decimal("0.6"), Decimal.ZERO, Decimal.ONE) + + val DRAINING_EFFICIENCY: Decimal by builder + .comment("Same as FEEDING_EFFICIENCY, but for 'draining' Singularity mass (inject antimatter only)") + .defineDecimal("DRAINING_EFFICIENCY", Decimal("1.0"), Decimal.ZERO, Decimal.ONE) init { builder.pop() diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/config/ServerConfig.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/config/ServerConfig.kt index a4d6dc4bf..78c37014b 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/config/ServerConfig.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/config/ServerConfig.kt @@ -1,5 +1,9 @@ package ru.dbotthepony.mc.otm.config +import ru.dbotthepony.kommons.util.getValue +import ru.dbotthepony.mc.otm.core.math.Decimal +import ru.dbotthepony.mc.otm.core.math.defineDecimal + object ServerConfig : AbstractConfig("misc") { val LABORATORY_LAMP_LIGHT_LENGTH: Int by builder.comment("In blocks").defineInRange("LABORATORY_LAMP_LIGHT_LENGTH", 6, 1, 128) val INFINITE_EXOSUIT_UPGRADES: Boolean by builder.comment("Allows to apply the same upgrade over and over again.", "Obviously completely breaks balance.").define("INFINITE_EXOSUIT_UPGRADES", false) @@ -23,11 +27,21 @@ object ServerConfig : AbstractConfig("misc") { init { builder.pop() - builder.push("BLACKHOLES") Blackhole } object Blackhole { + init { + builder.push("BLACK_HOLE") + } + + val BASELINE_MASS by builder + .comment("Mass of Singularity to be considered 'baseline' in regard to all calculations") + .comment("(such as gravitational strength), including the initial mass of Singularity.") + .comment("Changing this value mid-game can result in unwanted side effects,") + .comment("and lowering this value after generating world may result in unforeseen consequences far worse than resonance cascade.") + .defineDecimal("BASELINE_MASS", Decimal(500_000), Decimal.ONE) + val PLAYER_DAMAGE_SCALE: Double by builder .comment("Percentage of damage received by players from Event Horizon of Singularities") .defineInRange("PLAYER_DAMAGE_SCALE", 0.25, 0.0, Float.MAX_VALUE.toDouble()) @@ -53,13 +67,13 @@ object ServerConfig : AbstractConfig("misc") { .defineInRange("BOSS_FORCE_MULTIPLIER", 0.4, 0.0, Float.MAX_VALUE.toDouble()) val DESTROY_BLOCKS: Boolean by builder - .comment("Whenever singularities should destroy blocks") + .comment("Whenever singularities should destroy blocks.") .comment("Keep in mind that mobs behind blocks can cause serious server lag") - .comment("when trying to reach singularity") + .comment("when trying to reach singularity due to considerable pressure on physics engine solver.") .define("DESTROY_BLOCKS", true) - } - init { - builder.pop() + init { + builder.pop() + } } } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/input/DecimalInputWithFeedback.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/input/DecimalInputWithFeedback.kt new file mode 100644 index 000000000..a2aaee415 --- /dev/null +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/input/DecimalInputWithFeedback.kt @@ -0,0 +1,33 @@ +package ru.dbotthepony.mc.otm.menu.input + +import ru.dbotthepony.kommons.util.Delegate +import ru.dbotthepony.mc.otm.core.math.Decimal +import ru.dbotthepony.mc.otm.data.DecimalCodec +import ru.dbotthepony.mc.otm.menu.MatteryMenu +import java.util.function.Supplier +import kotlin.reflect.KMutableProperty0 + +class DecimalInputWithFeedback(menu: MatteryMenu, allowSpectators: Boolean = false) : AbstractPlayerInputWithFeedback() { + override val input = menu.decimalInput(allowSpectators) { consumer?.invoke(it) } + override val field = menu.mSynchronizer.computed(Supplier { supplier?.invoke() ?: Decimal.ZERO }, DecimalCodec.NETWORK) + + constructor(menu: MatteryMenu, allowSpectators: Boolean, state: KMutableProperty0?) : this(menu, allowSpectators) { + if (state != null) + with(state) + } + + constructor(menu: MatteryMenu, allowSpectators: Boolean, state: Delegate?) : this(menu, allowSpectators) { + if (state != null) + with(state) + } + + constructor(menu: MatteryMenu, state: KMutableProperty0?) : this(menu) { + if (state != null) + with(state) + } + + constructor(menu: MatteryMenu, state: Delegate?) : this(menu) { + if (state != null) + with(state) + } +} diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/tech/BlackHoleGeneratorMenu.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/tech/BlackHoleGeneratorMenu.kt index 226776b0c..feddd6a5c 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/tech/BlackHoleGeneratorMenu.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/tech/BlackHoleGeneratorMenu.kt @@ -4,6 +4,8 @@ import net.minecraft.world.entity.player.Inventory import ru.dbotthepony.mc.otm.block.entity.blackhole.BlackHoleGeneratorBlockEntity import ru.dbotthepony.mc.otm.menu.MatteryMenu import ru.dbotthepony.mc.otm.menu.input.BooleanInputWithFeedback +import ru.dbotthepony.mc.otm.menu.input.DecimalInputWithFeedback +import ru.dbotthepony.mc.otm.menu.input.EnumInputWithFeedback import ru.dbotthepony.mc.otm.menu.widget.CombinedProfiledLevelGaugeWidget import ru.dbotthepony.mc.otm.registry.MMenus @@ -15,4 +17,8 @@ class BlackHoleGeneratorMenu( val drawBuildingGuide = BooleanInputWithFeedback(this, tile?.let { it::drawBuildingGuide }) val energy = CombinedProfiledLevelGaugeWidget(this, tile?.energy) val matter = CombinedProfiledLevelGaugeWidget(this, tile?.matter) + val injectionRate = DecimalInputWithFeedback(this, tile?.let { it::injectionRate }) + val targetMass = DecimalInputWithFeedback(this, tile?.let { it::targetMass }) + val mode = EnumInputWithFeedback(this, tile?.let { it::mode }) + val redstoneConfig = EnumInputWithFeedback(this, tile?.let { it.redstoneControl::redstoneSetting }) } diff --git a/src/main/resources/assets/overdrive_that_matters/textures/gui/widgets/radio.png b/src/main/resources/assets/overdrive_that_matters/textures/gui/widgets/radio.png new file mode 100644 index 000000000..831267b7c Binary files /dev/null and b/src/main/resources/assets/overdrive_that_matters/textures/gui/widgets/radio.png differ diff --git a/src/main/resources/assets/overdrive_that_matters/textures/gui/widgets/widget_15.png b/src/main/resources/assets/overdrive_that_matters/textures/gui/widgets/widget_15.png index 95af9fdc1..e28176267 100644 Binary files a/src/main/resources/assets/overdrive_that_matters/textures/gui/widgets/widget_15.png and b/src/main/resources/assets/overdrive_that_matters/textures/gui/widgets/widget_15.png differ diff --git a/src/main/resources/assets/overdrive_that_matters/textures/gui/widgets/widget_15.xcf b/src/main/resources/assets/overdrive_that_matters/textures/gui/widgets/widget_15.xcf index 0e578bf3a..8d47776e7 100644 Binary files a/src/main/resources/assets/overdrive_that_matters/textures/gui/widgets/widget_15.xcf and b/src/main/resources/assets/overdrive_that_matters/textures/gui/widgets/widget_15.xcf differ