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 3fce11216..e76ae4983 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 @@ -603,6 +603,18 @@ private fun items(provider: MatteryLanguageProvider) { add(MItems.ZPM_BATTERY, "Zero Point Module") add(MItems.ZPM_BATTERY, "description", "Can be found in hands of those who travel between dimensions, if they ever reached different reality of origin of these constructs...") + + add(MItems.CreativeUpgrades.SPEED, "Creative Speed Upgrade") + add(MItems.CreativeUpgrades.ENERGY_CONSUMPTION, "Creative Energy Consumption Upgrade") + add(MItems.CreativeUpgrades.ENERGY_STORAGE, "Creative Energy Storage Upgrade") + add(MItems.CreativeUpgrades.ENERGY_STORAGE_FLAT, "Creative Energy Storage Upgrade (Flat)") + add(MItems.CreativeUpgrades.ENERGY_STORAGE_FLAT_SMALL, "Creative Energy Storage Upgrade (Flat Small)") + add(MItems.CreativeUpgrades.ENERGY_THROUGHPUT, "Creative Energy Throughput Upgrade") + add(MItems.CreativeUpgrades.ENERGY_THROUGHPUT_FLAT, "Creative Energy Throughput Upgrade (Flat)") + add(MItems.CreativeUpgrades.ENERGY_THROUGHPUT_FLAT_SMALL, "Creative Energy Throughput Upgrade (Flat Small)") + add(MItems.CreativeUpgrades.FAILSAFE, "Creative Failsafe Upgrade") + add(MItems.CreativeUpgrades.FAILURE, "Creative Failure Upgrade") + add(MItems.CreativeUpgrades.PROCESSING_ITEMS, "Creative Item Processing Upgrade") } } @@ -688,6 +700,27 @@ private fun gui(provider: MatteryLanguageProvider) { gui("side_mode.pull", "Pull") gui("side_mode.push", "Push") + gui("upgrades", "Upgrades") + gui("upgrades.current", "Active upgrades:") + gui("upgrade.speed", "Operation speed: %s%%") + gui("upgrade.processing_items", "Items processed per cycle: +%s") + gui("upgrade.energy_storage_flat", "Energy capacity: +%s") + gui("upgrade.energy_storage", "Energy capacity: +%s%%") + gui("upgrade.energy_consumed", "Energy consumption: %s%%") + gui("upgrade.energy_throughput_flat", "Energy throughput: +%s") + gui("upgrade.energy_throughput", "Energy throughput: +%s%%") + gui("upgrade.failsafe", "Failure chance: %s%%") + + gui("upgrade_type.list", "Upgrade classification:") + gui("upgrade_type.allowed", "Allowed upgrades:") + gui("upgrade_type.allowed_none", "No possible upgrades at the moment.") + gui("upgrade_type.speed", "Speed") + gui("upgrade_type.processing", "Processing") + gui("upgrade_type.energy_storage", "Energy Storage") + gui("upgrade_type.energy_consumption", "Energy Consumption") + gui("upgrade_type.energy_throughput", "Energy Throughput") + gui("upgrade_type.failsafe", "Failsafe") + gui("balance_inputs", "Balance input slots") gui("sorting.default", "Default sorting") 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 14b993b9e..291b4ff5a 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 @@ -607,6 +607,18 @@ private fun items(provider: MatteryLanguageProvider) { add(MItems.ZPM_BATTERY, "Модуль нулевой точки") add(MItems.ZPM_BATTERY, "description", "Может быть найден у тех, кто путешествует между измерениями, если, конечно, они смогли достигнуть вселенной, где данные устройства были созиданы...") + + add(MItems.CreativeUpgrades.SPEED, "Творческое улучшение скорости") + add(MItems.CreativeUpgrades.ENERGY_CONSUMPTION, "Творческое улучшение энергоэффективности") + add(MItems.CreativeUpgrades.ENERGY_STORAGE, "Творческое улучшение энергохраналища") + add(MItems.CreativeUpgrades.ENERGY_STORAGE_FLAT, "Творческое улучшение энергохраналища (простое)") + add(MItems.CreativeUpgrades.ENERGY_STORAGE_FLAT_SMALL, "Творческое улучшение энергохраналища (малое простое)") + add(MItems.CreativeUpgrades.ENERGY_THROUGHPUT, "Творческое улучшение энергоканала") + add(MItems.CreativeUpgrades.ENERGY_THROUGHPUT_FLAT, "Творческое улучшение энергоканала (простое)") + add(MItems.CreativeUpgrades.ENERGY_THROUGHPUT_FLAT_SMALL, "Творческое улучшение энергоканала (малое простое)") + add(MItems.CreativeUpgrades.FAILSAFE, "Творческое улучшение отказоустойчивости") + add(MItems.CreativeUpgrades.FAILURE, "Творческое улучшение краха") + add(MItems.CreativeUpgrades.PROCESSING_ITEMS, "Творческое улучшение обработки") } } @@ -692,6 +704,27 @@ private fun gui(provider: MatteryLanguageProvider) { gui("side_mode.pull", "Автоматическое вытягивание") gui("side_mode.push", "Автоматическое выталкивание") + gui("upgrades", "Улучшения") + gui("upgrades.current", "Активные улучшения:") + gui("upgrade.speed", "Скорость работы: %s%%") + gui("upgrade.processing_items", "Работы за цикл: +%s") + gui("upgrade.energy_storage_flat", "Хранилище энергии: +%s") + gui("upgrade.energy_storage", "Хранилище энергии: +%s%%") + gui("upgrade.energy_consumed", "Потребление энергии: %s%%") + gui("upgrade.energy_throughput_flat", "Пропускная способность энергии: +%s") + gui("upgrade.energy_throughput", "Пропускная способность энергии: +%s%%") + gui("upgrade.failsafe", "Шанс неудачи: %s%%") + + gui("upgrade_type.list", "Классификация улучшения:") + gui("upgrade_type.allowed", "Допустимые улучшения:") + gui("upgrade_type.allowed_none", "На данный момент нет допустимых улучшений.") + gui("upgrade_type.speed", "Скорость") + gui("upgrade_type.processing", "Обработка") + gui("upgrade_type.energy_storage", "Энергохранилище") + gui("upgrade_type.energy_consumption", "Энергоэффективность") + gui("upgrade_type.energy_throughput", "Энергоканал") + gui("upgrade_type.failsafe", "Отказоустойчивость") + gui("balance_inputs", "Балансировать входные слоты") gui("sorting.default", "Сортировка по умолчанию") diff --git a/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/tags/Tags.kt b/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/tags/Tags.kt index 9932f8709..b69231e57 100644 --- a/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/tags/Tags.kt +++ b/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/tags/Tags.kt @@ -112,6 +112,8 @@ fun addTags(tagsProvider: TagsProvider) { tagsProvider.items.forge("shears").add(MItems.TRITANIUM_SHEARS) tagsProvider.items.forge("shields").add(MItems.TRITANIUM_SHIELD) + tagsProvider.items.Appender(MItemTags.UPGRADES).add(MItems.CreativeUpgrades.LIST) + tagsProvider.blocks.Appender(BlockTags.STAIRS) .add(MRegistry.FLOOR_TILES_STAIRS.blocks.values) .add(MRegistry.TRITANIUM_STAIRS.allBlocks.values) diff --git a/src/main/java/ru/dbotthepony/mc/otm/capability/MatteryCapability.java b/src/main/java/ru/dbotthepony/mc/otm/capability/MatteryCapability.java index ad3d8aeff..37a8aba97 100644 --- a/src/main/java/ru/dbotthepony/mc/otm/capability/MatteryCapability.java +++ b/src/main/java/ru/dbotthepony/mc/otm/capability/MatteryCapability.java @@ -63,6 +63,10 @@ public class MatteryCapability { @NotNull public static final Capability CURIOS_ITEM = CapabilityManager.get(new CapabilityToken<>() {}); + @Nonnull + @NotNull + public static final Capability UPGRADE = CapabilityManager.get(new CapabilityToken<>() {}); + public static void register(RegisterCapabilitiesEvent event) { event.register(IMatteryEnergyStorage.class); event.register(MatteryPlayerCapability.class); @@ -72,5 +76,6 @@ public class MatteryCapability { event.register(IReplicationTaskProvider.class); event.register(IMatteryDrive.class); event.register(StorageNode.class); + event.register(IMatteryUpgrade.class); } } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/Jobs.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/Jobs.kt index 3ebeaff46..7a595a8cd 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/Jobs.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/Jobs.kt @@ -3,7 +3,9 @@ package ru.dbotthepony.mc.otm.block.entity import net.minecraft.nbt.CompoundTag import net.minecraft.world.item.ItemStack import net.minecraftforge.common.util.INBTSerializable +import ru.dbotthepony.mc.otm.capability.IMatteryUpgrade import ru.dbotthepony.mc.otm.capability.energy.IMatteryEnergyStorage +import ru.dbotthepony.mc.otm.config.MachinesConfig import ru.dbotthepony.mc.otm.core.math.Decimal import ru.dbotthepony.mc.otm.core.math.getDecimal import ru.dbotthepony.mc.otm.core.math.set @@ -153,6 +155,7 @@ abstract class MachineJobEventLoop : INBTSerializable : INBTSerializable : INBTSerializable( blockPos: BlockPos, blockState: BlockState, val jobDeserializer: (tag: CompoundTag) -> JobType?, - maxJobs: Int = 1 + maxJobs: Int = 1, ) : MatteryPoweredBlockEntity(type, blockPos, blockState) { val jobEventLoops: ImmutableList> = immutableList(maxJobs) { id -> object : MachineJobEventLoop() { @@ -38,6 +40,8 @@ abstract class MatteryWorkerBlockEntity( get() = matteryEnergy override val isBlockedByRedstone: Boolean get() = redstoneControl.isBlockedByRedstone + override val upgrades: IMatteryUpgrade? + get() = this@MatteryWorkerBlockEntity.upgrades override fun deserializeJob(nbt: CompoundTag): JobType? { return jobDeserializer.invoke(nbt) @@ -61,6 +65,8 @@ abstract class MatteryWorkerBlockEntity( } } + open val upgrades: IMatteryUpgrade? get() = null + var balanceInputs = false init { diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/PlatePressBlockEntity.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/PlatePressBlockEntity.kt index e88dbb13f..e5737178a 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/PlatePressBlockEntity.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/PlatePressBlockEntity.kt @@ -12,11 +12,14 @@ import ru.dbotthepony.mc.otm.block.entity.JobContainer import ru.dbotthepony.mc.otm.block.entity.JobStatus import ru.dbotthepony.mc.otm.block.entity.MachineItemJob import ru.dbotthepony.mc.otm.block.entity.MatteryWorkerBlockEntity +import ru.dbotthepony.mc.otm.capability.IMatteryUpgrade +import ru.dbotthepony.mc.otm.capability.UpgradeType import ru.dbotthepony.mc.otm.capability.energy.ProfiledEnergyStorage import ru.dbotthepony.mc.otm.capability.energy.WorkerEnergyStorage import ru.dbotthepony.mc.otm.config.MachinesConfig import ru.dbotthepony.mc.otm.container.MatteryContainer import ru.dbotthepony.mc.otm.container.HandlerFilter +import ru.dbotthepony.mc.otm.container.UpgradeContainer import ru.dbotthepony.mc.otm.container.balance import ru.dbotthepony.mc.otm.core.math.Decimal import ru.dbotthepony.mc.otm.menu.tech.PlatePressMenu @@ -29,7 +32,8 @@ class PlatePressBlockEntity( p_155230_: BlockState, val isTwin: Boolean = false, ) : MatteryWorkerBlockEntity(if (isTwin) MBlockEntities.TWIN_PLATE_PRESS else MBlockEntities.PLATE_PRESS, p_155229_, p_155230_, ::MachineItemJob, if (isTwin) 2 else 1) { - val energy = ProfiledEnergyStorage(WorkerEnergyStorage(this::setChangedLight, MachinesConfig.PLATE_PRESS)) + override val upgrades = UpgradeContainer(this::setChangedLight, if (isTwin) 4 else 3, UpgradeType.BASIC) + val energy = ProfiledEnergyStorage(WorkerEnergyStorage(this::setChangedLight, upgrades.transform(MachinesConfig.PLATE_PRESS))) val inputContainer = MatteryContainer(this::itemContainerUpdated, if (isTwin) 2 else 1).also(::addDroppableContainer) val outputContainer = MatteryContainer(this::itemContainerUpdated, if (isTwin) 2 else 1).also(::addDroppableContainer) @@ -55,6 +59,7 @@ class PlatePressBlockEntity( savetable(::inputContainer) savetable(::outputContainer) savetables.double(::experience) + savetables.stateful(::upgrades) } override fun createMenu(containerID: Int, inventory: Inventory, ply: Player): AbstractContainerMenu { diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/capability/Upgrades.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/capability/Upgrades.kt new file mode 100644 index 000000000..67040f3b0 --- /dev/null +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/capability/Upgrades.kt @@ -0,0 +1,200 @@ +package ru.dbotthepony.mc.otm.capability + +import net.minecraft.ChatFormatting +import net.minecraft.network.chat.Component +import ru.dbotthepony.mc.otm.client.ShiftPressedCond +import ru.dbotthepony.mc.otm.config.MachinesConfig +import ru.dbotthepony.mc.otm.core.TextComponent +import ru.dbotthepony.mc.otm.core.TranslatableComponent +import ru.dbotthepony.mc.otm.core.immutableSet +import ru.dbotthepony.mc.otm.core.math.Decimal +import ru.dbotthepony.mc.otm.core.util.formatPower + +/** + * Upgrades merge by sum of their effects + * + * Values which are otherwise not stated to allow negatives or not, Do allow negative values. + */ +interface IMatteryUpgrade { + /** + * Type(s) this upgrade represent + */ + val upgradeTypes: Set get() = setOf() + + /** + * [speedBonus] of `1.0` means that machine doubles the speed (performs twice the amount of + * work ticks per work cycle). + */ + val speedBonus: Double get() = 0.0 + + /** + * **CAN NOT be negative.** + * + * [processingItems] of `4` means machine will accept at most 5 (1 + 4) of items per job. + */ + val processingItems: Int get() = 0 + + /** + * **CAM NOT be negative.** + * + * Added directly over regular energy storage capacity. + */ + val energyStorageFlat: Decimal get() = Decimal.ZERO + + /** + * **CAM NOT be negative.** + */ + val energyStorage: Decimal get() = Decimal.ZERO + + /** + * Value of `1` means power consumption is doubled, `2` is tripled, `-0.5` is halved. + */ + val energyConsumed: Decimal get() = Decimal.ZERO + + /** + * **CAN NOT be negative.** + * + * Added directly over regular throughput + */ + val energyThroughputFlat: Decimal get() = Decimal.ZERO + + /** + * **CAN NOT be negative.** + * + * Value of `1` means power throughput is doubled, `2` is tripled, and so on. + */ + val energyThroughput: Decimal get() = Decimal.ZERO + + /** + * **CAN NOT be negative.** + * + * **Merged by multiplication** + */ + val failureMultiplier: Double get() = 1.0 + + companion object : IMatteryUpgrade +} + +fun IMatteryUpgrade.addUpgradeTooltipLines(tooltips: MutableCollection) { + if (upgradeTypes.isNotEmpty() && ShiftPressedCond.asBoolean) { + tooltips.add(TranslatableComponent("otm.gui.upgrade_type.list").withStyle(ChatFormatting.GRAY)) + + for (upgrade in upgradeTypes) { + tooltips.add(upgrade.component.copy().withStyle(ChatFormatting.GRAY)) + } + + tooltips.add(TextComponent("")) + } + + if (speedBonus >= 0.01) { + tooltips.add(TranslatableComponent("otm.gui.upgrade.speed", TextComponent("+" + (speedBonus.coerceIn(MachinesConfig.Upgrades.MIN_SPEED, MachinesConfig.Upgrades.MAX_SPEED) * 100.0).toInt().toString()).withStyle(ChatFormatting.DARK_GREEN)).withStyle(ChatFormatting.GRAY)) + } else if (speedBonus <= -0.01) { + tooltips.add(TranslatableComponent("otm.gui.upgrade.speed", TextComponent((speedBonus.coerceIn(MachinesConfig.Upgrades.MIN_SPEED, MachinesConfig.Upgrades.MAX_SPEED) * 100.0).toInt().toString()).withStyle(ChatFormatting.DARK_RED)).withStyle(ChatFormatting.GRAY)) + } + + if (processingItems != 0) { + tooltips.add(TranslatableComponent("otm.gui.upgrade.processing_items", TextComponent("+$processingItems").withStyle(ChatFormatting.DARK_GREEN)).withStyle(ChatFormatting.GRAY)) + } + + if (energyStorageFlat != Decimal.ZERO) { + tooltips.add(TranslatableComponent("otm.gui.upgrade.energy_storage_flat", energyStorageFlat.formatPower(formatAsReadable = ShiftPressedCond).copy().withStyle(ChatFormatting.DARK_GREEN)).withStyle(ChatFormatting.GRAY)) + } + + if (energyStorage != Decimal.ZERO) { + tooltips.add(TranslatableComponent("otm.gui.upgrade.energy_storage", TextComponent((energyStorage * 100).toString(0)).withStyle(ChatFormatting.DARK_GREEN)).withStyle(ChatFormatting.GRAY)) + } + + if (energyConsumed > Decimal.ONE) { + tooltips.add(TranslatableComponent("otm.gui.upgrade.energy_consumed", TextComponent("+" + (energyConsumed.coerceIn(MachinesConfig.Upgrades.MIN_ENERGY, MachinesConfig.Upgrades.MAX_ENERGY) * 100).toString(0)).withStyle(ChatFormatting.DARK_RED)).withStyle(ChatFormatting.GRAY)) + } else if (energyConsumed < Decimal.MINUS_ONE) { + tooltips.add(TranslatableComponent("otm.gui.upgrade.energy_consumed", TextComponent((energyConsumed.coerceIn(MachinesConfig.Upgrades.MIN_ENERGY, MachinesConfig.Upgrades.MAX_ENERGY) * 100).toString(0)).withStyle(ChatFormatting.DARK_GREEN)).withStyle(ChatFormatting.GRAY)) + } + + if (energyThroughputFlat != Decimal.ZERO) { + tooltips.add(TranslatableComponent("otm.gui.upgrade.energy_throughput_flat", energyThroughputFlat.formatPower(formatAsReadable = ShiftPressedCond).copy().withStyle(ChatFormatting.DARK_GREEN)).withStyle(ChatFormatting.GRAY)) + } + + if (energyThroughput != Decimal.ZERO) { + tooltips.add(TranslatableComponent("otm.gui.upgrade.energy_throughput", TextComponent((energyThroughput * 100).toString(0)).withStyle(ChatFormatting.DARK_GREEN)).withStyle(ChatFormatting.GRAY)) + } + + if (failureMultiplier >= 1.01) { + tooltips.add(TranslatableComponent("otm.gui.upgrade.failsafe", TextComponent("+" + ((failureMultiplier - 1) * 100).toInt().toString()).withStyle(ChatFormatting.DARK_RED)).withStyle(ChatFormatting.GRAY)) + } else if (failureMultiplier <= 0.99) { + tooltips.add(TranslatableComponent("otm.gui.upgrade.failsafe", TextComponent(((failureMultiplier.coerceAtLeast(0.0) - 1) * 100).toInt().toString()).withStyle(ChatFormatting.DARK_GREEN)).withStyle(ChatFormatting.GRAY)) + } +} + +fun IMatteryUpgrade.getUpgradeTooltipLines(): MutableList { + return ArrayList().also { addUpgradeTooltipLines(it) } +} + +enum class UpgradeType { + SPEED, + PROCESSING, + ENERGY_STORAGE, + ENERGY_CONSUMPTION, + ENERGY_THROUGHPUT, + FAILSAFE; + + val localeId = "otm.gui.upgrade_type.${name.lowercase()}" + val component: Component get() = TranslatableComponent(localeId) + + val flag = 1 shl (ordinal + 1) + fun set() = sets[flag] + + companion object { + private val cached = values() + + private val sets = Array(2 shl cached.size) { + immutableSet { + for (u in values()) if (it.and(u.flag) != 0) accept(u) + } + } + + @JvmField + val ALL = set(*values()) + @JvmField + val BASIC = set(SPEED, ENERGY_STORAGE, ENERGY_CONSUMPTION, ENERGY_THROUGHPUT) + + fun set(vararg types: UpgradeType): Set { + var flags = 0 + for (v in types) flags = flags or v.flag + return sets[flags] + } + + fun set(): Set { + return sets[0] + } + + fun set( + type0: UpgradeType, + ): Set = sets[type0.flag] + + fun set( + type0: UpgradeType, + type1: UpgradeType, + ): Set = sets[type0.flag or type1.flag] + + fun set( + type0: UpgradeType, + type1: UpgradeType, + type2: UpgradeType, + ): Set = sets[type0.flag or type1.flag or type2.flag] + + fun set( + type0: UpgradeType, + type1: UpgradeType, + type2: UpgradeType, + type3: UpgradeType, + ): Set = sets[type0.flag or type1.flag or type2.flag or type3.flag] + + fun set( + type0: UpgradeType, + type1: UpgradeType, + type2: UpgradeType, + type3: UpgradeType, + type4: UpgradeType, + ): Set = sets[type0.flag or type1.flag or type2.flag or type3.flag or type4.flag] + } +} diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/client/render/Widgets18.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/client/render/Widgets18.kt index d347c5feb..71f858864 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/client/render/Widgets18.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/client/render/Widgets18.kt @@ -59,7 +59,7 @@ object Widgets18 { val PATTERN_SLOT_BACKGROUND = slotBgGrid.next() val MATTER_CAPACITOR_SLOT_BACKGROUND = slotBgGrid.next() - private val controlsGrid = WidgetLocation.SIDE_CONTROLS.grid(rows = 7, columns = 9) + private val controlsGrid = WidgetLocation.SIDE_CONTROLS.grid(rows = 8, columns = 9) val BATTERY_ONLY = controlsGrid.next() val ITEMS_CONFIGURATION = controlsGrid.next() @@ -160,4 +160,6 @@ object Widgets18 { put(RelativeSide.FRONT, FRONT_CONTROLS) put(RelativeSide.BACK, BACK_CONTROLS) } + + val UPGRADES = controlsGrid.next() } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/MatteryScreen.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/MatteryScreen.kt index 1d5bd9dd1..468a71ba5 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/MatteryScreen.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/MatteryScreen.kt @@ -319,7 +319,10 @@ abstract class MatteryScreen(menu: T, inventory: Inventory, tit * @return FramePanel created, or null */ protected open fun makeMainFrame(): FramePanel>? { - return FramePanel(this, null, 0f, 0f, DEFAULT_FRAME_WIDTH, DEFAULT_FRAME_HEIGHT, getTitle()) + return FramePanel(this, null, 0f, 0f, DEFAULT_FRAME_WIDTH, DEFAULT_FRAME_HEIGHT, getTitle()).also { + it.onClose { onClose() } + it.makeCloseButton() + } } public override fun recalculateQuickCraftRemaining() { diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/panels/EditablePanel.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/panels/EditablePanel.kt index a0ca9d7c8..c188af33e 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/panels/EditablePanel.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/panels/EditablePanel.kt @@ -1,8 +1,10 @@ package ru.dbotthepony.mc.otm.client.screen.panels import com.google.common.collect.ImmutableList +import com.mojang.blaze3d.platform.InputConstants import com.mojang.blaze3d.systems.RenderSystem import com.mojang.blaze3d.vertex.PoseStack +import it.unimi.dsi.fastutil.ints.IntAVLTreeSet import it.unimi.dsi.fastutil.objects.ReferenceArraySet import net.minecraft.client.gui.ComponentPath import net.minecraft.client.gui.Font @@ -23,6 +25,7 @@ import ru.dbotthepony.mc.otm.client.render.currentScissorRect import ru.dbotthepony.mc.otm.client.render.popScissorRect import ru.dbotthepony.mc.otm.client.render.pushScissorRect import ru.dbotthepony.mc.otm.client.screen.MatteryScreen +import ru.dbotthepony.mc.otm.client.screen.panels.button.AbstractButtonPanel import ru.dbotthepony.mc.otm.client.screen.panels.input.QueryUserPanel import java.util.* import kotlin.collections.ArrayList @@ -417,6 +420,7 @@ open class EditablePanel @JvmOverloads constructor( return field } + field = null return null } @@ -965,7 +969,7 @@ open class EditablePanel @JvmOverloads constructor( return true } - if (isHovered) { + if (isHovered || this is AbstractButtonPanel<*> && isPressed) { val tooltip = tooltip val tooltipList = tooltipList @@ -1186,10 +1190,6 @@ open class EditablePanel @JvmOverloads constructor( this.height = height } - companion object { - private val LOGGER = LogManager.getLogger()!! - } - protected open fun visibilityChanges(new: Boolean, old: Boolean) { } @@ -1589,7 +1589,7 @@ open class EditablePanel @JvmOverloads constructor( fun keyPressed(key: Int, scancode: Int, mods: Int): Boolean { if (!isVisible() || !acceptKeyboardInput) return false if (!isEverFocused()) return false - if (flashAnyBlocker(true)) return true + if (flashAnyBlocker(key !in ignoreFlashKeys)) return true if (isFocusedThis) return keyPressedInternal(key, scancode, mods) for (child in visibleChildrenInternal) { @@ -1737,4 +1737,21 @@ open class EditablePanel @JvmOverloads constructor( fun queryUser(title: Component, text: Collection, onConfirm: Runnable, onCancel: Runnable? = null): QueryUserPanel { return QueryUserPanel(screen, title, text, onConfirm, onCancel).also { blockingWindow = it } } + + companion object { + private val LOGGER = LogManager.getLogger()!! + + private val ignoreFlashKeys = IntAVLTreeSet() + + init { + ignoreFlashKeys.add(InputConstants.KEY_LEFT) + ignoreFlashKeys.add(InputConstants.KEY_RIGHT) + ignoreFlashKeys.add(InputConstants.KEY_UP) + ignoreFlashKeys.add(InputConstants.KEY_DOWN) + ignoreFlashKeys.add(InputConstants.KEY_RCONTROL) + ignoreFlashKeys.add(InputConstants.KEY_LCONTROL) + ignoreFlashKeys.add(InputConstants.KEY_RSHIFT) + ignoreFlashKeys.add(InputConstants.KEY_LSHIFT) + } + } } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/panels/FramePanel.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/panels/FramePanel.kt index d1f9e24cb..ace546c82 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/panels/FramePanel.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/panels/FramePanel.kt @@ -12,6 +12,8 @@ import net.minecraft.network.chat.Component import org.lwjgl.opengl.GL30 import ru.dbotthepony.mc.otm.client.playGuiClickSound import ru.dbotthepony.mc.otm.client.render.* +import ru.dbotthepony.mc.otm.client.screen.panels.button.AbstractButtonPanel +import ru.dbotthepony.mc.otm.client.screen.panels.button.ButtonPanel open class FramePanel( screen: S, @@ -123,6 +125,30 @@ open class FramePanel( } } + inner class CloseButton : AbstractButtonPanel(screen, this@FramePanel, this@FramePanel.width - CLOSE_BUTTON.width, 0f, CLOSE_BUTTON.width, CLOSE_BUTTON.height) { + override fun onClick(mouseButton: Int) { + close() + } + + override fun innerRender(graphics: GuiGraphics, mouseX: Float, mouseY: Float, partialTick: Float) { + if (isPressed) { + CLOSE_BUTTON_PRESSED.render(graphics, 0f, 0f, width, height) + } else if (isHovered) { + CLOSE_BUTTON_HOVERED.render(graphics, 0f, 0f, width, height) + } else { + CLOSE_BUTTON.render(graphics, 0f, 0f, width, height) + } + } + + override fun onRemoved() { + super.onRemoved() + + if (closeButton == this) { + closeButton = null + } + } + } + protected val tabs: java.util.ArrayList = ArrayList() override fun performLayout() { @@ -131,13 +157,29 @@ open class FramePanel( tab.initial = i == 0 } + closeButton?.setPos(width - CLOSE_BUTTON.width, 0f) + super.performLayout() } protected var dragging = false + protected var closeButton: CloseButton? = null var closeOnEscape = false + fun makeCloseButton() { + if (closeButton == null) + closeButton = CloseButton() + } + + /** + * Adds close button and makes panel [close] when user presses ESC with this panel focused + */ + fun behaveAsWindow() { + closeOnEscape = true + makeCloseButton() + } + init { setDockPadding(PADDING, if (title != null) PADDING_TOP else PADDING, PADDING, PADDING) } @@ -187,9 +229,24 @@ open class FramePanel( } + protected val closeCallbacks = ArrayList() + + fun onClose(callback: Runnable) { + closeCallbacks.add(callback) + } + + /** + * Usually just calls [remove] + */ + open fun close() { + if (isRemoved) return + remove() + closeCallbacks.forEach { it.run() } + } + override fun keyPressedInternal(key: Int, scancode: Int, mods: Int): Boolean { if (key == InputConstants.KEY_ESCAPE && closeOnEscape) { - remove() + close() return true } @@ -258,9 +315,13 @@ open class FramePanel( padding = DockProperty(-3f, -3f, -3f, -3f) ) - val TAB_RIGHT_CONNECTION = WidgetLocation.MISC.sprite(x = 30f, y = 0f, width = 3f, height = 5f) - val TAB_LEFT_CONNECTION = WidgetLocation.MISC.sprite(x = 33f, y = 0f, width = 3f, height = 5f) - val TAB_BACKGROUND = WidgetLocation.MISC.sprite(x = 30f, y = 6f, width = 6f, height = 6f) + val TAB_RIGHT_CONNECTION = WidgetLocation.MISC.sprite(x = 30f, y = 0f, width = 3f, height = 5f) + val TAB_LEFT_CONNECTION = WidgetLocation.MISC.sprite(x = 33f, y = 0f, width = 3f, height = 5f) + val TAB_BACKGROUND = WidgetLocation.MISC.sprite(x = 30f, y = 6f, width = 6f, height = 6f) + + val CLOSE_BUTTON = WidgetLocation.MISC.sprite(x = 51f, y = 0f, width = 13f, height = 11f) + val CLOSE_BUTTON_HOVERED = WidgetLocation.MISC.sprite(x = 51f, y = 11f, width = 13f, height = 11f) + val CLOSE_BUTTON_PRESSED = WidgetLocation.MISC.sprite(x = 51f, y = 22f, width = 13f, height = 11f) const val TAB_HEIGHT = 28f const val TAB_WIDTH = 28f diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/panels/button/Buttons.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/panels/button/Buttons.kt index 759e7bdba..31e47b284 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/panels/button/Buttons.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/panels/button/Buttons.kt @@ -3,26 +3,38 @@ package ru.dbotthepony.mc.otm.client.screen.panels.button import com.mojang.blaze3d.platform.InputConstants import net.minecraft.ChatFormatting import net.minecraft.client.gui.GuiGraphics +import net.minecraft.network.chat.Component import ru.dbotthepony.mc.otm.block.entity.MatteryDeviceBlockEntity import ru.dbotthepony.mc.otm.block.entity.RedstoneSetting import ru.dbotthepony.mc.otm.capability.FlowDirection +import ru.dbotthepony.mc.otm.capability.addUpgradeTooltipLines import ru.dbotthepony.mc.otm.client.isCtrlDown import ru.dbotthepony.mc.otm.client.isShiftDown import ru.dbotthepony.mc.otm.client.minecraft import ru.dbotthepony.mc.otm.client.render.AbstractMatterySprite import ru.dbotthepony.mc.otm.client.render.Widgets18 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.DockResizeMode 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.slot.AbstractSlotPanel +import ru.dbotthepony.mc.otm.client.screen.panels.slot.SlotPanel +import ru.dbotthepony.mc.otm.client.screen.panels.util.GridPanel import ru.dbotthepony.mc.otm.core.GetterSetter +import ru.dbotthepony.mc.otm.core.TextComponent import ru.dbotthepony.mc.otm.core.TranslatableComponent import ru.dbotthepony.mc.otm.core.math.RelativeSide +import ru.dbotthepony.mc.otm.core.value +import ru.dbotthepony.mc.otm.menu.UpgradeSlots import ru.dbotthepony.mc.otm.menu.input.BooleanInputWithFeedback import ru.dbotthepony.mc.otm.menu.input.EnergyConfigPlayerInput import ru.dbotthepony.mc.otm.menu.input.FluidConfigPlayerInput import ru.dbotthepony.mc.otm.menu.input.IPlayerInputWithFeedback import ru.dbotthepony.mc.otm.menu.input.ItemConfigPlayerInput import java.util.function.Predicate +import kotlin.math.ceil +import kotlin.math.pow private fun > makeRedstoneSettingButton( screen: S, @@ -212,6 +224,7 @@ private fun > makeItemHandlerControlPanel( moveButtons(front, back, left, right, top, bottom) screen.addPanel(frame) frame.requestFocus() + frame.closeOnEscape = true return frame } @@ -240,6 +253,7 @@ private fun > makeEnergyConfigPanel( moveButtons(front, back, left, right, top, bottom) screen.addPanel(frame) frame.requestFocus() + frame.closeOnEscape = true return frame } @@ -268,6 +282,7 @@ private fun > makeFluidConfigPanel( moveButtons(front, back, left, right, top, bottom) screen.addPanel(frame) frame.requestFocus() + frame.closeOnEscape = true return frame } @@ -281,12 +296,17 @@ class DeviceControls>( val energyConfig: EnergyConfigPlayerInput? = null, val fluidConfig: FluidConfigPlayerInput? = null, val balanceInputs: BooleanInputWithFeedback? = null, + val upgrades: UpgradeSlots? = null, ) : EditablePanel(screen, parent, x = parent.width + 3f, height = 0f, width = 0f) { val itemConfigButton: LargeRectangleButtonPanel? val energyConfigButton: LargeRectangleButtonPanel? val fluidConfigButton: LargeRectangleButtonPanel? val redstoneControlsButton: LargeEnumRectangleButtonPanel? val balanceInputsButton: LargeBooleanRectangleButtonPanel? + val upgradesButton: LargeRectangleButtonPanel? + + private var upgradeWindow: FramePanel? = null + private var nextY = 0f fun

> addButton(button: P): P { @@ -310,6 +330,82 @@ class DeviceControls>( redstoneControlsButton = null } + if (upgrades != null) { + upgradesButton = addButton(object : LargeRectangleButtonPanel( + screen, this@DeviceControls, + skinElement = Widgets18.UPGRADES + ) { + init { + tooltip = TranslatableComponent("otm.gui.upgrades") + } + + override fun tickInner() { + super.tickInner() + + tooltipList = ArrayList().also { + it.add(TranslatableComponent("otm.gui.upgrades")) + it.add(TextComponent("")) + + if (upgrades.allowedTypes.isEmpty()) { + it.add(TranslatableComponent("otm.gui.upgrade_type.allowed_none").withStyle(ChatFormatting.DARK_GRAY)) + } else { + it.add(TranslatableComponent("otm.gui.upgrade_type.allowed").withStyle(ChatFormatting.GRAY)) + + for (upgrade in upgrades.allowedTypes) { + it.add(upgrade.component.copy().withStyle(ChatFormatting.GRAY)) + } + } + + val i = it.size + upgrades.currentStats.addUpgradeTooltipLines(it) + + if (it.size != i) { + it.add(i, TranslatableComponent("otm.gui.upgrades.current").withStyle(ChatFormatting.GRAY)) + it.add(i, TextComponent("")) + } + } + } + + override fun onClick(mouseButton: Int) { + if (mouseButton == InputConstants.MOUSE_BUTTON_LEFT) { + if (upgradeWindow != null && !upgradeWindow!!.isRemoved) { + upgradeWindow!!.toScreenCenter() + upgradeWindow!!.popup() + } else { + val square = ceil(upgrades.slots.size.toDouble().pow(0.5)).toInt() + val size = square * AbstractSlotPanel.SIZE + + upgradeWindow = FramePanel(screen, (size + 40f).coerceAtLeast(120f), 30f + size, TranslatableComponent("otm.gui.upgrades")).also { frame -> + val grid = GridPanel(screen, frame, width = AbstractSlotPanel.SIZE * square, height = AbstractSlotPanel.SIZE * square, columns = square, rows = square) + + for (slot in upgrades.slots) { + SlotPanel(screen, grid, slot) + } + + grid.dock = Dock.FILL + grid.dockResize = DockResizeMode.NONE + + screen.addPanel(frame) + + val parentFrame = this@DeviceControls.parent!! + + frame.behaveAsWindow() + frame.setPos(parentFrame.absoluteX + parentFrame.width / 2f - frame.width / 2f, parentFrame.absoluteY + parentFrame.height / 2f - frame.height / 2f) + frame.popup() + + upgrades.openState.value = true + frame.onClose { upgrades.openState.value = false } + + parentFrame.blockingWindow = frame + } + } + } + } + }) + } else { + upgradesButton = null + } + if (balanceInputs != null) { balanceInputsButton = addButton(LargeBooleanRectangleButtonPanel( screen, this, @@ -396,8 +492,9 @@ fun > makeDeviceControls( energyConfig: EnergyConfigPlayerInput? = null, fluidConfig: FluidConfigPlayerInput? = null, balanceInputs: BooleanInputWithFeedback? = null, + upgrades: UpgradeSlots? = null, ): DeviceControls { return DeviceControls(screen, parent, extra = extra, redstoneConfig = redstoneConfig, itemConfig = itemConfig, energyConfig = energyConfig, fluidConfig = fluidConfig, - balanceInputs = balanceInputs) + balanceInputs = balanceInputs, upgrades = upgrades) } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/panels/input/QueryUserPanel.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/panels/input/QueryUserPanel.kt index 4b7a8ec99..b36deebb1 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/panels/input/QueryUserPanel.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/panels/input/QueryUserPanel.kt @@ -63,6 +63,7 @@ open class QueryUserPanel( this.width = maxWidth.coerceAtLeast(bottom.children.stream().mapToDouble { it.width.toDouble() }.sum().toFloat() + 2f) + PADDING * 2f toScreenCenter() + behaveAsWindow() } override fun keyPressedInternal(key: Int, scancode: Int, mods: Int): Boolean { diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/tech/AndroidStationScreen.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/tech/AndroidStationScreen.kt index 2f3eda8cb..16d955ba2 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/tech/AndroidStationScreen.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/tech/AndroidStationScreen.kt @@ -636,7 +636,7 @@ class AndroidStationScreen constructor(p_97741_: AndroidStationMenu, p_97742_: I researchCanvas.setDockMargin(4f, 4f, 4f, 4f) research!!.toScreenCenter() - research!!.closeOnEscape = true + research!!.behaveAsWindow() addPanel(research!!) research!!.requestFocus() } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/tech/PlatePressScreen.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/tech/PlatePressScreen.kt index d937ce9fd..3a3d28b6e 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/tech/PlatePressScreen.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/tech/PlatePressScreen.kt @@ -8,7 +8,6 @@ import ru.dbotthepony.mc.otm.client.screen.panels.FramePanel import ru.dbotthepony.mc.otm.client.screen.panels.button.makeDeviceControls import ru.dbotthepony.mc.otm.client.screen.panels.slot.SlotPanel import ru.dbotthepony.mc.otm.client.screen.widget.ProgressGaugePanel -import ru.dbotthepony.mc.otm.client.screen.widget.WidePowerGaugePanel import ru.dbotthepony.mc.otm.client.screen.widget.WideProfiledPowerGaugePanel import ru.dbotthepony.mc.otm.menu.tech.PlatePressMenu @@ -24,7 +23,7 @@ class PlatePressScreen(menu: PlatePressMenu, inventory: Inventory, title: Compon ProgressGaugePanel(this, frame, menu.progressGauge, 78f, PROGRESS_ARROW_TOP) SlotPanel(this, frame, menu.outputSlot, 104f, PROGRESS_SLOT_TOP) - makeDeviceControls(this, frame, redstoneConfig = menu.redstoneConfig, energyConfig = menu.energyConfig, itemConfig = menu.itemConfig) + makeDeviceControls(this, frame, redstoneConfig = menu.redstoneConfig, energyConfig = menu.energyConfig, itemConfig = menu.itemConfig, upgrades = menu.upgrades) return frame } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/tech/TwinPlatePressScreen.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/tech/TwinPlatePressScreen.kt index 6a2952f8c..946201340 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/tech/TwinPlatePressScreen.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/tech/TwinPlatePressScreen.kt @@ -27,7 +27,7 @@ class TwinPlatePressScreen(menu: TwinPlatePressMenu, inventory: Inventory, title ProgressGaugePanel(this, frame, menu.progressGauge1, 78f, PROGRESS_ARROW_TOP + 10f) SlotPanel(this, frame, menu.outputSlots[1], 104f, PROGRESS_SLOT_TOP + 10f) - makeDeviceControls(this, frame, redstoneConfig = menu.redstoneConfig, energyConfig = menu.energyConfig, itemConfig = menu.itemConfig, balanceInputs = menu.balanceInputs) + makeDeviceControls(this, frame, redstoneConfig = menu.redstoneConfig, energyConfig = menu.energyConfig, itemConfig = menu.itemConfig, balanceInputs = menu.balanceInputs, upgrades = menu.upgrades) return frame } 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 8fc6c4cef..607a4e858 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/config/MachinesConfig.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/config/MachinesConfig.kt @@ -10,6 +10,7 @@ import ru.dbotthepony.mc.otm.block.entity.tech.AndroidStationBlockEntity import ru.dbotthepony.mc.otm.block.entity.tech.ChemicalGeneratorBlockEntity import ru.dbotthepony.mc.otm.capability.energy.BlockEnergyStorageImpl import ru.dbotthepony.mc.otm.core.math.Decimal +import ru.dbotthepony.mc.otm.core.math.defineDecimal import ru.dbotthepony.mc.otm.registry.MNames object MachinesConfig : AbstractConfig("machines") { @@ -42,4 +43,34 @@ object MachinesConfig : AbstractConfig("machines") { } val ANDROID_CHARGER = BlockEnergyStorageImpl.makeConfigEntry(builder, MNames.ANDROID_CHARGER, capacity = Decimal(400_000), throughput = Decimal(8192)) { AndroidCharger } + + object Upgrades { + init { + builder.push("UPGRADES") + } + + val MIN_SPEED: Double by builder + .comment("Minimal combined upgrade speed percentage (upgrades can't decrease machine speed below this)") + .defineInRange("MIN_SPEED", -0.8, -1.0, Double.MAX_VALUE) + + val MAX_SPEED: Double by builder + .comment("Maximal combined upgrade speed percentage") + .defineInRange("MAX_SPEED", Double.MAX_VALUE, 0.0, Double.MAX_VALUE) + + val MIN_ENERGY by builder + .comment("Minimal combined energy consumption percentage (upgrades can't decrease machine energy consumption below this)") + .defineDecimal("MIN_ENERGY", Decimal(-0.8), Decimal(-1.0)) + + val MAX_ENERGY by builder + .comment("Maximal combined energy consumption percentage") + .defineDecimal("MAX_ENERGY", Decimal.LONG_MAX_VALUE, Decimal.ZERO) + + init { + builder.pop() + } + } + + init { + Upgrades + } } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/container/UpgradeContainer.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/container/UpgradeContainer.kt new file mode 100644 index 000000000..d93c2c282 --- /dev/null +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/container/UpgradeContainer.kt @@ -0,0 +1,54 @@ +package ru.dbotthepony.mc.otm.container + +import ru.dbotthepony.mc.otm.capability.IMatteryUpgrade +import ru.dbotthepony.mc.otm.capability.MatteryCapability +import ru.dbotthepony.mc.otm.capability.UpgradeType +import ru.dbotthepony.mc.otm.config.ConciseBalanceValues +import ru.dbotthepony.mc.otm.config.VerboseBalanceValues +import ru.dbotthepony.mc.otm.core.isNotEmpty +import ru.dbotthepony.mc.otm.core.math.Decimal +import kotlin.math.pow + +open class UpgradeContainer(slotCount: Int, open val allowedUpgrades: Set = UpgradeType.ALL, watcher: Runnable = Runnable {}) : MatteryContainer(watcher, slotCount), IMatteryUpgrade { + constructor(watcher: Runnable, slotCount: Int, allowedUpgrades: Set) : this(slotCount, allowedUpgrades, watcher) + + final override val upgradeTypes: Set + get() = setOf() + + override val speedBonus: Double + get() = stream().filter { it.isNotEmpty }.mapToDouble { it.getCapability(MatteryCapability.UPGRADE).map { it.speedBonus }.orElse(0.0) * it.count }.sum() + override val processingItems: Int + get() = stream().filter { it.isNotEmpty }.mapToInt { it.getCapability(MatteryCapability.UPGRADE).map { it.processingItems }.orElse(0).coerceAtLeast(0) * it.count }.sum() + override val energyStorageFlat: Decimal + get() = stream().filter { it.isNotEmpty }.map { it.getCapability(MatteryCapability.UPGRADE).map { it.energyStorageFlat }.orElse(Decimal.ZERO).moreThanZero() * it.count }.reduce(Decimal.ZERO, Decimal::plus) + override val energyStorage: Decimal + get() = stream().filter { it.isNotEmpty }.map { it.getCapability(MatteryCapability.UPGRADE).map { it.energyStorage }.orElse(Decimal.ZERO).moreThanZero() * it.count }.reduce(Decimal.ZERO, Decimal::plus) + override val energyConsumed: Decimal + get() = stream().filter { it.isNotEmpty }.map { it.getCapability(MatteryCapability.UPGRADE).map { it.energyConsumed }.orElse(Decimal.ZERO) * it.count }.reduce(Decimal.ZERO, Decimal::plus) + override val failureMultiplier: Double + get() = stream().filter { it.isNotEmpty }.mapToDouble { it.getCapability(MatteryCapability.UPGRADE).map { it.failureMultiplier }.orElse(1.0).coerceAtLeast(0.0).pow(it.count.toDouble()) }.reduce(1.0) { a, b -> a * b } + override val energyThroughputFlat: Decimal + get() = stream().filter { it.isNotEmpty }.map { it.getCapability(MatteryCapability.UPGRADE).map { it.energyThroughputFlat }.orElse(Decimal.ZERO).moreThanZero() * it.count }.reduce(Decimal.ZERO, Decimal::plus) + override val energyThroughput: Decimal + get() = stream().filter { it.isNotEmpty }.map { it.getCapability(MatteryCapability.UPGRADE).map { it.energyThroughput }.orElse(Decimal.ZERO).moreThanZero() * it.count }.reduce(Decimal.ZERO, Decimal::plus) + + fun transform(values: ConciseBalanceValues): ConciseBalanceValues { + return object : ConciseBalanceValues { + override val capacity: Decimal + get() = values.capacity * (energyStorage + Decimal.ONE) + energyStorageFlat + override val throughput: Decimal + get() = values.throughput * (energyThroughput + Decimal.ONE) + energyThroughputFlat + } + } + + fun transform(values: VerboseBalanceValues): VerboseBalanceValues { + return object : VerboseBalanceValues { + override val capacity: Decimal + get() = values.capacity * (energyStorage + Decimal.ONE) + energyStorageFlat + override val receive: Decimal + get() = values.receive * (energyThroughput + Decimal.ONE) + energyThroughputFlat + override val extract: Decimal + get() = values.extract * (energyThroughput + Decimal.ONE) + energyThroughputFlat + } + } +} diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/core/Ext.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/core/Ext.kt index efbf72a36..2a1d8b81d 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/core/Ext.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/core/Ext.kt @@ -91,8 +91,8 @@ inline fun LazyOptional.ifPresentK(lambda: (T) -> Unit) { val ItemStack.tagNotNull: CompoundTag get() = orCreateTag -val FluidStack.isNotEmpty get() = !isEmpty -val ItemStack.isNotEmpty get() = !isEmpty +inline val FluidStack.isNotEmpty get() = !isEmpty +inline val ItemStack.isNotEmpty get() = !isEmpty inline var Entity.position: Vec3 get() = position() diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/core/collect/ConditionalEnumSet.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/core/collect/ConditionalEnumSet.kt new file mode 100644 index 000000000..9dbbf12ab --- /dev/null +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/core/collect/ConditionalEnumSet.kt @@ -0,0 +1,41 @@ +package ru.dbotthepony.mc.otm.core.collect + +import java.util.EnumMap +import java.util.function.BooleanSupplier +import java.util.stream.Stream + +class ConditionalEnumSet>private constructor(private val backing: EnumMap, marker: Unit) : Set { + constructor(clazz: Class) : this(EnumMap(clazz), Unit) + constructor(map: Map) : this(EnumMap(map), Unit) + + override val size: Int + get() = backing.values.stream().filter { it.asBoolean }.count().toInt() + + override fun contains(element: T): Boolean { + return backing[element]?.asBoolean ?: false + } + + override fun containsAll(elements: Collection): Boolean { + return elements.all { contains(it) } + } + + override fun isEmpty(): Boolean { + return backing.isEmpty() || backing.values.none { it.asBoolean } + } + + override fun stream(): Stream { + return backing.entries.stream().filter { it.value.asBoolean }.map { it.key } + } + + override fun iterator(): Iterator { + return backing.entries.iterator().filter { it.value.asBoolean }.map { it.key } + } + + fun add(value: T, condition: BooleanSupplier) { + backing[value] = condition + } + + fun remove(value: T): Boolean { + return backing.remove(value) != null + } +} diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/core/collect/ConditionalSet.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/core/collect/ConditionalSet.kt index 781f9ef47..9596f15e9 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/core/collect/ConditionalSet.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/core/collect/ConditionalSet.kt @@ -1,68 +1,57 @@ package ru.dbotthepony.mc.otm.core.collect +import it.unimi.dsi.fastutil.objects.Object2ObjectLinkedOpenHashMap +import java.util.function.BooleanSupplier import java.util.stream.Stream -class ConditionalSet : AbstractSet { - // method without boxing - fun interface Condition { - fun check(): Boolean +class ConditionalSet : Set { + private val backing = Object2ObjectLinkedOpenHashMap() + + override val size: Int + get() = backing.values.stream().filter { it.asBoolean }.count().toInt() + + override fun contains(element: E): Boolean { + return backing[element]?.asBoolean ?: false } - private val getters: Array> - - constructor(vararg getters: Pair) : super() { - this.getters = Array(getters.size) { getters[it] } + override fun containsAll(elements: Collection): Boolean { + return elements.all { contains(it) } } - constructor(getters: List>) : super() { - this.getters = Array(getters.size) { getters[it] } + override fun isEmpty(): Boolean { + return backing.isEmpty() || backing.values.stream().noneMatch { it.asBoolean } } - constructor(getters: Stream>) : super() { - this.getters = getters.toArray { arrayOfNulls>(it) } + override fun stream(): Stream { + return backing.entries.stream().filter { it.value.asBoolean }.map { it.key } } - override val size: Int get() { - var i = 0 - - for (pair in getters) { - if (pair.first.check()) { - i++ - } - } - - return i + override fun iterator(): Iterator { + return backing.entries.iterator().filter { it.value.asBoolean }.map { it.key } } - override fun iterator(): Iterator { - return object : Iterator { - val parent = getters.iterator() - private var pair: Pair? = null + fun add(element: E, condition: BooleanSupplier): Boolean { + if (element in backing) return false + backing[element] = condition + return true + } - private fun search() { - for (pair in parent) { - if (pair.first.check()) { - this.pair = pair - return - } - } + fun addFirst(element: E, condition: BooleanSupplier): Boolean { + if (element in backing) return false + backing.putAndMoveToFirst(element, condition) + return true + } - this.pair = null - } + fun replace(element: E, condition: BooleanSupplier) { + backing[element] = condition + } - init { - search() - } + fun replaceFirst(element: E, condition: BooleanSupplier) { + backing.remove(element) + backing.putAndMoveToFirst(element, condition) + } - override fun hasNext(): Boolean { - return pair != null - } - - override fun next(): T { - val pair = pair ?: throw NoSuchElementException() - search() - return pair.second - } - } + fun remove(element: E): Boolean { + return backing.remove(element) != null } } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/item/SimpleUpgrade.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/item/SimpleUpgrade.kt new file mode 100644 index 000000000..66fdf57bd --- /dev/null +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/item/SimpleUpgrade.kt @@ -0,0 +1,51 @@ +package ru.dbotthepony.mc.otm.item + +import net.minecraft.core.Direction +import net.minecraft.nbt.CompoundTag +import net.minecraft.network.chat.Component +import net.minecraft.world.item.Item +import net.minecraft.world.item.ItemStack +import net.minecraft.world.item.TooltipFlag +import net.minecraft.world.level.Level +import net.minecraftforge.common.capabilities.Capability +import net.minecraftforge.common.capabilities.ICapabilityProvider +import net.minecraftforge.common.util.LazyOptional +import ru.dbotthepony.mc.otm.capability.IMatteryUpgrade +import ru.dbotthepony.mc.otm.capability.MatteryCapability +import ru.dbotthepony.mc.otm.capability.UpgradeType +import ru.dbotthepony.mc.otm.capability.addUpgradeTooltipLines +import ru.dbotthepony.mc.otm.core.TextComponent +import ru.dbotthepony.mc.otm.core.math.Decimal + +class SimpleUpgrade( + properties: Properties, + override val upgradeTypes: Set, + override val speedBonus: Double = 0.0, + override val processingItems: Int = 0, + override val energyStorageFlat: Decimal = Decimal.ZERO, + override val energyStorage: Decimal = Decimal.ZERO, + override val energyConsumed: Decimal = Decimal.ZERO, + override val energyThroughputFlat: Decimal = Decimal.ZERO, + override val energyThroughput: Decimal = Decimal.ZERO, + override val failureMultiplier: Double = 1.0, +) : Item(properties), IMatteryUpgrade, ICapabilityProvider { + private val resolver = LazyOptional.of { this } + + override fun getCapability(cap: Capability, side: Direction?): LazyOptional { + if (cap === MatteryCapability.UPGRADE) { + return resolver.cast() + } + + return LazyOptional.empty() + } + + override fun appendHoverText(p_41421_: ItemStack, p_41422_: Level?, p_41423_: MutableList, p_41424_: TooltipFlag) { + super.appendHoverText(p_41421_, p_41422_, p_41423_, p_41424_) + addUpgradeTooltipLines(p_41423_) + } + + override fun initCapabilities(stack: ItemStack, nbt: CompoundTag?): ICapabilityProvider { + return this + } +} + diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/MatteryMenu.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/MatteryMenu.kt index bc92c1a77..24429784e 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/MatteryMenu.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/MatteryMenu.kt @@ -11,6 +11,7 @@ import net.minecraft.network.FriendlyByteBuf import net.minecraft.resources.ResourceLocation import net.minecraft.server.level.ServerPlayer import net.minecraft.world.Container +import net.minecraft.world.SimpleContainer import net.minecraft.world.entity.player.Inventory import net.minecraft.world.entity.player.Player import net.minecraft.world.inventory.AbstractContainerMenu @@ -23,6 +24,9 @@ import net.minecraft.world.item.enchantment.EnchantmentHelper.hasBindingCurse import net.minecraft.world.level.block.entity.BlockEntity import net.minecraftforge.network.NetworkEvent import net.minecraftforge.network.PacketDistributor +import ru.dbotthepony.mc.otm.capability.IMatteryUpgrade +import ru.dbotthepony.mc.otm.capability.MatteryCapability +import ru.dbotthepony.mc.otm.capability.UpgradeType import ru.dbotthepony.mc.otm.capability.matteryPlayer import ru.dbotthepony.mc.otm.client.minecraft import ru.dbotthepony.mc.otm.compat.cos.cosmeticArmorSlots @@ -31,7 +35,12 @@ import ru.dbotthepony.mc.otm.compat.curios.isCurioSlot import ru.dbotthepony.mc.otm.container.ItemFilter import ru.dbotthepony.mc.otm.container.ItemFilterNetworkSlot import ru.dbotthepony.mc.otm.container.MatteryContainer +import ru.dbotthepony.mc.otm.container.UpgradeContainer import ru.dbotthepony.mc.otm.core.GetterSetter +import ru.dbotthepony.mc.otm.core.collect.ConditionalEnumSet +import ru.dbotthepony.mc.otm.core.collect.ConditionalSet +import ru.dbotthepony.mc.otm.core.immutableList +import ru.dbotthepony.mc.otm.core.math.Decimal import ru.dbotthepony.mc.otm.core.util.BigDecimalValueCodec import ru.dbotthepony.mc.otm.core.util.BinaryStringCodec import ru.dbotthepony.mc.otm.core.util.BooleanValueCodec @@ -49,10 +58,14 @@ import ru.dbotthepony.mc.otm.network.packetHandled import ru.dbotthepony.mc.otm.network.sender import ru.dbotthepony.mc.otm.network.synchronizer.FieldSynchronizer import ru.dbotthepony.mc.otm.network.synchronizer.IField +import ru.dbotthepony.mc.otm.network.synchronizer.IMutableBooleanField import java.io.DataInputStream import java.io.DataOutputStream import java.math.BigDecimal import java.util.* +import java.util.function.BooleanSupplier +import java.util.function.DoubleSupplier +import java.util.function.IntSupplier import java.util.function.Predicate import java.util.function.Supplier @@ -63,6 +76,17 @@ data class EquipmentSlots( val curiosSlots: List> ) +/** + * [openState] **is clientside only**, attempting to use it on server will result + * in classloading exceptions. + */ +data class UpgradeSlots( + val slots: List, + val allowedTypes: Set, + val openState: GetterSetter, + val currentStats: IMatteryUpgrade +) + abstract class MatteryMenu @JvmOverloads protected constructor( menuType: MenuType<*>?, containerId: Int, @@ -382,7 +406,7 @@ abstract class MatteryMenu @JvmOverloads protected constructor( return player.distanceToSqr(pos.x.toDouble() + 0.5, pos.y.toDouble() + 0.5, pos.z.toDouble() + 0.5) <= 64.0 } - private val externalSlots = ArrayList() + private val externalSlots = ConditionalSet() private val quickMoveMapping = Reference2ObjectOpenHashMap>>() override fun addSlot(pSlot: Slot): Slot { @@ -412,11 +436,17 @@ abstract class MatteryMenu @JvmOverloads protected constructor( /** * Adds slot to "storage slots" list (utilized by quick move) and calls [addSlot] + * + * [condition] allows to specify when slot is invisible on GUI (hence being ignored by quick move) */ - protected fun addStorageSlot(slot: T, addMapping: Boolean = true): T { + protected fun addStorageSlot(slot: T, addMapping: Boolean = true, prepend: Boolean = false, condition: BooleanSupplier = BooleanSupplier { true }): T { if (slot !in externalSlots) { addSlot(slot) - externalSlots.add(slot) + + if (prepend) + externalSlots.replaceFirst(slot, condition) + else + externalSlots.replace(slot, condition) if (addMapping) { mapQuickMove(slot, equipmentSlots) @@ -446,8 +476,8 @@ abstract class MatteryMenu @JvmOverloads protected constructor( mapQuickMove(slot, externalSlots, prepend = prepend) } - protected fun mapQuickMove(slot: Slot, target: Collection, prepend: Boolean = false) { - val listing = quickMoveMapping.computeIfAbsent(slot, Reference2ObjectFunction { ReferenceArrayList(1) }) + protected fun mapQuickMove(slot: Slot, target: Collection, prepend: Boolean = false, condition: BooleanSupplier = BooleanSupplier { true }) { + val listing = quickMoveMapping.computeIfAbsent(slot, Reference2ObjectFunction { ReferenceArrayList(1) /* ReferenceArrayList ибо мы используем его в некотором смысле как множество */ }) listing.remove(target) if (prepend) @@ -715,6 +745,56 @@ abstract class MatteryMenu @JvmOverloads protected constructor( ) } + fun makeUpgradeSlots(count: Int, container: UpgradeContainer?): UpgradeSlots { + if (container != null) { + require(count == container.containerSize) { "Upgrade container size ${container.containerSize} does not match with provided size $count" } + } + + val allowedTypes = EnumMap(UpgradeType::class.java) + + for (value in UpgradeType.ALL) { + allowedTypes[value] = mSynchronizer.bool() + + if (container != null) { + allowedTypes[value]!!.boolean = value in container.allowedUpgrades + } + } + + val syncContainer = container ?: SimpleContainer(count) + + var isOpen = false + val input = PlayerInput(BooleanValueCodec, allowSpectators = true, handler = { isOpen = it }) + + return UpgradeSlots( + slots = immutableList(count) { + object : MatterySlot(syncContainer, it) { + init { + mapQuickMoveToInventory(this) + addStorageSlot(this, prepend = true, condition = { isOpen }) + } + + override fun mayPlace(itemStack: ItemStack): Boolean { + return super.mayPlace(itemStack) && itemStack.getCapability(MatteryCapability.UPGRADE).map { it.upgradeTypes.any { allowedTypes[it]!!.boolean } }.orElse(false) + } + } + }, + + allowedTypes = ConditionalEnumSet(allowedTypes), + openState = GetterSetter.of({ isOpen }, { input.input(it); isOpen = it }), + currentStats = object : IMatteryUpgrade { + override val upgradeTypes: Set = setOf() + override val speedBonus: Double by mSynchronizer.computedDouble(DoubleSupplier { container?.speedBonus ?: 0.0 }).property + override val processingItems: Int by mSynchronizer.computedInt(IntSupplier { container?.processingItems ?: 0 }).property + override val energyStorageFlat: Decimal by mSynchronizer.computedDecimal { container?.energyStorageFlat ?: Decimal.ZERO } + override val energyStorage: Decimal by mSynchronizer.computedDecimal { container?.energyStorage ?: Decimal.ZERO } + override val energyConsumed: Decimal by mSynchronizer.computedDecimal { container?.energyConsumed ?: Decimal.ZERO } + override val energyThroughputFlat: Decimal by mSynchronizer.computedDecimal { container?.energyThroughputFlat ?: Decimal.ZERO } + override val energyThroughput: Decimal by mSynchronizer.computedDecimal { container?.energyThroughput ?: Decimal.ZERO } + override val failureMultiplier: Double by mSynchronizer.computedDouble(DoubleSupplier { container?.failureMultiplier ?: 1.0 }).property + } + ) + } + companion object { val TEXTURE_EMPTY_SLOTS: List = ImmutableList.of( InventoryMenu.EMPTY_ARMOR_SLOT_BOOTS, diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/Slots.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/Slots.kt index 68ee7387d..01f2cc395 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/Slots.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/Slots.kt @@ -10,6 +10,7 @@ import ru.dbotthepony.mc.otm.capability.FlowDirection import ru.dbotthepony.mc.otm.capability.MatteryCapability import ru.dbotthepony.mc.otm.capability.energy import ru.dbotthepony.mc.otm.client.minecraft +import ru.dbotthepony.mc.otm.container.UpgradeContainer import ru.dbotthepony.mc.otm.core.GetterSetter import ru.dbotthepony.mc.otm.core.immutableList import ru.dbotthepony.mc.otm.runOnClient diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/tech/PlatePressMenu.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/tech/PlatePressMenu.kt index 0f33d9ed6..935922882 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/tech/PlatePressMenu.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/tech/PlatePressMenu.kt @@ -26,6 +26,8 @@ class PlatePressMenu @JvmOverloads constructor( val energyConfig = EnergyConfigPlayerInput(this, tile?.energyConfig, allowPull = true) val profiledEnergy = ProfiledLevelGaugeWidget(this, tile?.energy, energyWidget) + val upgrades = makeUpgradeSlots(3, tile?.upgrades) + init { addStorageSlot(inputSlot) addStorageSlot(outputSlot) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/tech/TwinPlatePressMenu.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/tech/TwinPlatePressMenu.kt index f6bda5c84..e5168c070 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/tech/TwinPlatePressMenu.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/tech/TwinPlatePressMenu.kt @@ -31,6 +31,8 @@ class TwinPlatePressMenu @JvmOverloads constructor( val balanceInputs = BooleanInputWithFeedback(this) + val upgrades = makeUpgradeSlots(4, tile?.upgrades) + init { if (tile != null) { balanceInputs.with(tile::balanceInputs) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/registry/MCreativeTabs.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/registry/MCreativeTabs.kt index 6434da4ae..44a35bf41 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/registry/MCreativeTabs.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/registry/MCreativeTabs.kt @@ -130,6 +130,7 @@ private fun CreativeModeTab.Output.fluids(value: Item) { private fun addMainCreativeTabItems(consumer: CreativeModeTab.Output) { with(consumer) { accept(MItems.MACHINES) + accept(MItems.CreativeUpgrades.LIST) accept(MRegistry.CARGO_CRATES.item) accept(MItems.HOLO_SIGN) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/registry/MItems.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/registry/MItems.kt index 4577d88c7..ea6697944 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/registry/MItems.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/registry/MItems.kt @@ -4,7 +4,6 @@ package ru.dbotthepony.mc.otm.registry import net.minecraft.ChatFormatting import net.minecraft.network.chat.Component import net.minecraft.resources.ResourceLocation -import net.minecraft.world.entity.EquipmentSlot import net.minecraft.world.food.FoodProperties import net.minecraft.world.item.* import net.minecraft.world.item.crafting.Ingredient @@ -15,9 +14,11 @@ import net.minecraftforge.eventbus.api.IEventBus import net.minecraftforge.registries.DeferredRegister import net.minecraftforge.registries.ForgeRegistries import ru.dbotthepony.mc.otm.OverdriveThatMatters +import ru.dbotthepony.mc.otm.capability.UpgradeType import ru.dbotthepony.mc.otm.config.ItemsConfig import ru.dbotthepony.mc.otm.core.collect.SupplierList import ru.dbotthepony.mc.otm.core.TranslatableComponent +import ru.dbotthepony.mc.otm.core.math.Decimal import ru.dbotthepony.mc.otm.item.* import ru.dbotthepony.mc.otm.item.exopack.ExoPackCraftingUpgradeItem import ru.dbotthepony.mc.otm.item.exopack.ExoPackProbeItem @@ -160,6 +161,38 @@ object MItems { TRITANIUM_ANVIL = SupplierList(props) } + object CreativeUpgrades { + val SPEED: SimpleUpgrade by registry.register("creative_speed_upgrade") { SimpleUpgrade(Item.Properties().rarity(Rarity.EPIC), UpgradeType.SPEED.set(), speedBonus = 1.0) } + val ENERGY_CONSUMPTION: SimpleUpgrade by registry.register("creative_energy_consumption_upgrade") { SimpleUpgrade(Item.Properties().rarity(Rarity.EPIC), UpgradeType.ENERGY_CONSUMPTION.set(), energyConsumed = Decimal.MINUS_ONE) } + val ENERGY_STORAGE: SimpleUpgrade by registry.register("creative_energy_storage_upgrade") { SimpleUpgrade(Item.Properties().rarity(Rarity.EPIC), UpgradeType.ENERGY_STORAGE.set(), energyStorage = Decimal.ONE) } + val ENERGY_STORAGE_FLAT: SimpleUpgrade by registry.register("creative_energy_storage_flat_upgrade") { SimpleUpgrade(Item.Properties().rarity(Rarity.EPIC), UpgradeType.ENERGY_STORAGE.set(), energyStorageFlat = Decimal.LONG_MAX_VALUE) } + val ENERGY_STORAGE_FLAT_SMALL: SimpleUpgrade by registry.register("creative_energy_storage_flat2_upgrade") { SimpleUpgrade(Item.Properties().rarity(Rarity.EPIC), UpgradeType.ENERGY_STORAGE.set(), energyStorageFlat = Decimal.INT_MAX_VALUE) } + val ENERGY_THROUGHPUT: SimpleUpgrade by registry.register("creative_energy_throughput_upgrade") { SimpleUpgrade(Item.Properties().rarity(Rarity.EPIC), UpgradeType.ENERGY_THROUGHPUT.set(), energyThroughput = Decimal.ONE) } + val ENERGY_THROUGHPUT_FLAT: SimpleUpgrade by registry.register("creative_energy_throughput_flat_upgrade") { SimpleUpgrade(Item.Properties().rarity(Rarity.EPIC), UpgradeType.ENERGY_THROUGHPUT.set(), energyThroughputFlat = Decimal.LONG_MAX_VALUE) } + val ENERGY_THROUGHPUT_FLAT_SMALL: SimpleUpgrade by registry.register("creative_energy_throughput_flat2_upgrade") { SimpleUpgrade(Item.Properties().rarity(Rarity.EPIC), UpgradeType.ENERGY_THROUGHPUT.set(), energyThroughputFlat = Decimal.INT_MAX_VALUE) } + val FAILSAFE: SimpleUpgrade by registry.register("creative_failsafe_upgrade") { SimpleUpgrade(Item.Properties().rarity(Rarity.EPIC), UpgradeType.FAILSAFE.set(), failureMultiplier = 0.0) } + val FAILURE: SimpleUpgrade by registry.register("creative_failure_upgrade") { SimpleUpgrade(Item.Properties().rarity(Rarity.EPIC), UpgradeType.FAILSAFE.set(), failureMultiplier = 2.0) } + val PROCESSING_ITEMS: SimpleUpgrade by registry.register("creative_processing_upgrade") { SimpleUpgrade(Item.Properties().rarity(Rarity.EPIC), UpgradeType.PROCESSING.set(), processingItems = 1) } + + val LIST = SupplierList( + ::SPEED, + ::ENERGY_CONSUMPTION, + ::ENERGY_STORAGE, + ::ENERGY_STORAGE_FLAT, + ::ENERGY_STORAGE_FLAT_SMALL, + ::ENERGY_THROUGHPUT, + ::ENERGY_THROUGHPUT_FLAT, + ::ENERGY_THROUGHPUT_FLAT_SMALL, + ::FAILSAFE, + ::FAILURE, + ::PROCESSING_ITEMS, + ) + } + + init { + CreativeUpgrades + } + val MATTER_DUST: Item by registry.register(MNames.MATTER_DUST) { MatterDustItem() } val TRITANIUM_ORE_CLUMP: Item by registry.register(MNames.TRITANIUM_ORE_CLUMP) { Item(DEFAULT_PROPERTIES) } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/registry/Tags.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/registry/Tags.kt index a7d5a8e79..ae77498d5 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/registry/Tags.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/registry/Tags.kt @@ -25,6 +25,7 @@ object MItemTags { val CARGO_CRATES: TagKey = ItemTags.create(ResourceLocation(OverdriveThatMatters.MOD_ID, "cargo_crates")) val MINECART_CARGO_CRATES: TagKey = ItemTags.create(ResourceLocation(OverdriveThatMatters.MOD_ID, "minecart_cargo_crates")) val INDUSTRIAL_GLASS: TagKey = ItemTags.create(ResourceLocation(OverdriveThatMatters.MOD_ID, "industrial_glass")) + val UPGRADES: TagKey = ItemTags.create(ResourceLocation(OverdriveThatMatters.MOD_ID, "upgrades")) val CRAFTING_TABLES: TagKey = ItemTags.create(ResourceLocation("forge", "crafting_tables")) diff --git a/src/main/resources/assets/overdrive_that_matters/textures/gui/widgets/misc.png b/src/main/resources/assets/overdrive_that_matters/textures/gui/widgets/misc.png index 8923a02d7..bc3b614b3 100644 Binary files a/src/main/resources/assets/overdrive_that_matters/textures/gui/widgets/misc.png and b/src/main/resources/assets/overdrive_that_matters/textures/gui/widgets/misc.png differ diff --git a/src/main/resources/assets/overdrive_that_matters/textures/gui/widgets/side_controls.png b/src/main/resources/assets/overdrive_that_matters/textures/gui/widgets/side_controls.png index 2c2c135b4..54effb4a7 100644 Binary files a/src/main/resources/assets/overdrive_that_matters/textures/gui/widgets/side_controls.png and b/src/main/resources/assets/overdrive_that_matters/textures/gui/widgets/side_controls.png differ diff --git a/src/main/resources/assets/overdrive_that_matters/textures/gui/widgets/side_controls.xcf b/src/main/resources/assets/overdrive_that_matters/textures/gui/widgets/side_controls.xcf index 3182f633b..cbb5a84e4 100644 Binary files a/src/main/resources/assets/overdrive_that_matters/textures/gui/widgets/side_controls.xcf and b/src/main/resources/assets/overdrive_that_matters/textures/gui/widgets/side_controls.xcf differ