Essence storage, servo, capsules
This commit is contained in:
parent
5748908ac2
commit
40da26033d
@ -362,6 +362,7 @@ private fun blocks(provider: MatteryLanguageProvider) {
|
||||
add(MBlocks.DRIVE_VIEWER, "Drive Viewer")
|
||||
add(MBlocks.BLACK_HOLE, "Local Anomalous Singular Gravitation Field")
|
||||
add(MBlocks.COBBLESTONE_GENERATOR, "Cobblestone Generator")
|
||||
add(MBlocks.ESSENCE_STORAGE, "Essence Storage")
|
||||
|
||||
add(MBlocks.ENGINE, "Ship Engine")
|
||||
add(MBlocks.HOLO_SIGN, "Holo Sign")
|
||||
@ -445,6 +446,12 @@ private fun items(provider: MatteryLanguageProvider) {
|
||||
add(MItems.ExopackUpgrades.INVENTORY_UPGRADE_PROCEDURAL, "Indescribable Exopack Inventory Upgrade")
|
||||
add(MItems.ExopackUpgrades.INVENTORY_UPGRADE_PROCEDURAL, "description", "They normally generate in dungeons with appropriate NBT tag attached")
|
||||
|
||||
add(MItems.ESSENCE_CAPSULE, "Essence Capsule")
|
||||
add(MItems.ESSENCE_DRIVE, "Essence Memory Drive")
|
||||
add(MItems.ESSENCE_SERVO, "Essence Servo")
|
||||
add(MItems.ESSENCE_SERVO, "desc", "Allows to 'pump' essence involving fleshy humanoids")
|
||||
add(MItems.ESSENCE_SERVO, "desc2", "Can be used standalone, or as tool inside Essence Servo")
|
||||
|
||||
add(MItems.NUTRIENT_PASTE, "Nutrient Paste")
|
||||
|
||||
add(MItems.BLACK_HOLE_SCANNER, "Singularity Scanner")
|
||||
@ -657,6 +664,18 @@ private fun gui(provider: MatteryLanguageProvider) {
|
||||
gui("matter_panel.matter_stored", "Matter stored: %s")
|
||||
gui("matter_panel.matter_required", "Matter required: %s")
|
||||
gui("matter_panel.complexity", "Total complexity: %s")
|
||||
|
||||
gui("experience", "%s experience points")
|
||||
gui("experience_levels", "%s experience levels")
|
||||
|
||||
gui("experience.store", "Store %s experience levels")
|
||||
gui("experience.store_all", "Store all experience levels")
|
||||
gui("experience.dispense", "Dispense %s experience levels")
|
||||
gui("experience.dispense_all", "Dispense all experience levels")
|
||||
gui("experience.set_exact", "Set your experience level to %s")
|
||||
|
||||
gui("essence_capsule", "(Almost) Everything you ever knew is within")
|
||||
gui("essence_capsule2", "This item can be recycled at Essence Servo")
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -369,6 +369,7 @@ private fun blocks(provider: MatteryLanguageProvider) {
|
||||
add(MBlocks.DRIVE_VIEWER, "Просмотрщик дисков конденсации")
|
||||
add(MBlocks.BLACK_HOLE, "Локализированное аномальное сингулярное гравитационное поле")
|
||||
add(MBlocks.COBBLESTONE_GENERATOR, "Генератор булыжника")
|
||||
add(MBlocks.ESSENCE_STORAGE, "Хранилище эссенции")
|
||||
|
||||
add(MBlocks.ENGINE, "Двигатель корабля")
|
||||
add(MBlocks.HOLO_SIGN, "Голографическая табличка")
|
||||
@ -450,6 +451,12 @@ private fun items(provider: MatteryLanguageProvider) {
|
||||
add(MItems.ExopackUpgrades.INVENTORY_UPGRADE_PROCEDURAL, "Неописуемое обновление инвентаря экзопака")
|
||||
add(MItems.ExopackUpgrades.INVENTORY_UPGRADE_PROCEDURAL, "description", "В нормальных условиях, они появляются в сундуках")
|
||||
|
||||
add(MItems.ESSENCE_CAPSULE, "Капсула эссенции")
|
||||
add(MItems.ESSENCE_DRIVE, "Диск эссенции")
|
||||
add(MItems.ESSENCE_SERVO, "Помпа эссенции")
|
||||
add(MItems.ESSENCE_SERVO, "desc", "Позволяет 'перекачивать' эссенцию гуманоидов из плоти")
|
||||
add(MItems.ESSENCE_SERVO, "desc2", "Может быть использовано напрямую, или как инструмент внутри хранилища эссенции")
|
||||
|
||||
add(MItems.NUTRIENT_PASTE, "Питательная паста")
|
||||
|
||||
add(MItems.BLACK_HOLE_SCANNER, "Сканер сингулярностей")
|
||||
@ -659,6 +666,18 @@ private fun gui(provider: MatteryLanguageProvider) {
|
||||
gui("matter_panel.matter_stored", "Материи хранится: %s")
|
||||
gui("matter_panel.matter_required", "Материи требуется: %s")
|
||||
gui("matter_panel.complexity", "Общая сложность: %s")
|
||||
|
||||
gui("experience", "%s очков опыта")
|
||||
gui("experience_levels", "%s уровней опыта")
|
||||
|
||||
gui("experience.store", "Передать %s уровней опыта")
|
||||
gui("experience.store_all", "Передать все уровни опыта")
|
||||
gui("experience.dispense", "Вывести %s уровней опыта")
|
||||
gui("experience.dispense_all", "Вывести все уровни опыта")
|
||||
gui("experience.set_exact", "Установить уровень опыта в %s")
|
||||
|
||||
gui("essence_capsule", "(Почти) Всё, что вы знали, хранится внутри")
|
||||
gui("essence_capsule2", "Данный предмет может быть переработан внутри хранилища эссенции")
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -225,7 +225,7 @@ abstract class MatteryBlock @JvmOverloads constructor(
|
||||
}
|
||||
|
||||
companion object {
|
||||
val DEFAULT_PROPERTIES: Properties = Properties.of(Material.STONE, MaterialColor.METAL).requiresCorrectToolForDrops().strength(1.5f, 25.0f)
|
||||
val DEFAULT_PROPERTIES: Properties = Properties.of(Material.STONE, MaterialColor.METAL).requiresCorrectToolForDrops().destroyTime(1.5f).explosionResistance(25.0f)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,56 @@
|
||||
package ru.dbotthepony.mc.otm.block.entity.tech
|
||||
|
||||
import net.minecraft.core.BlockPos
|
||||
import net.minecraft.server.level.ServerPlayer
|
||||
import net.minecraft.world.entity.player.Inventory
|
||||
import net.minecraft.world.entity.player.Player
|
||||
import net.minecraft.world.inventory.AbstractContainerMenu
|
||||
import net.minecraft.world.item.ItemStack
|
||||
import net.minecraft.world.level.block.state.BlockState
|
||||
import ru.dbotthepony.mc.otm.block.entity.MatteryDeviceBlockEntity
|
||||
import ru.dbotthepony.mc.otm.container.HandlerFilter
|
||||
import ru.dbotthepony.mc.otm.container.MatteryContainer
|
||||
import ru.dbotthepony.mc.otm.item.EssenceCapsuleItem
|
||||
import ru.dbotthepony.mc.otm.menu.tech.EssenceStorageMenu
|
||||
import ru.dbotthepony.mc.otm.registry.MBlockEntities
|
||||
|
||||
class EssenceStorageBlockEntity(blockPos: BlockPos, blockState: BlockState) : MatteryDeviceBlockEntity(MBlockEntities.ESSENCE_STORAGE, blockPos, blockState) {
|
||||
var experienceStored = 0L
|
||||
set(value) {
|
||||
require(value >= 0L) { "Negative experience: $value" }
|
||||
field = value
|
||||
setChangedLight()
|
||||
}
|
||||
|
||||
val capsuleContainer = MatteryContainer(::setChangedLight, 1)
|
||||
val servoContainer = MatteryContainer(::setChangedLight, 1)
|
||||
|
||||
init {
|
||||
savetables.long(::experienceStored)
|
||||
savetables.stateful(::capsuleContainer)
|
||||
savetables.stateful(::servoContainer)
|
||||
}
|
||||
|
||||
override fun createMenu(containerID: Int, inventory: Inventory, ply: Player): AbstractContainerMenu {
|
||||
return EssenceStorageMenu(containerID, inventory, this)
|
||||
}
|
||||
|
||||
val itemConfig = ConfigurableItemHandler(
|
||||
input = capsuleContainer.handler(HandlerFilter.OnlyIn.and(object : HandlerFilter {
|
||||
override fun canInsert(slot: Int, stack: ItemStack): Boolean {
|
||||
return stack.item is EssenceCapsuleItem
|
||||
}
|
||||
}))
|
||||
)
|
||||
|
||||
override fun tick() {
|
||||
super.tick()
|
||||
|
||||
val capsule = capsuleContainer[0]
|
||||
|
||||
if (!capsule.isEmpty && capsule.item is EssenceCapsuleItem) {
|
||||
experienceStored += EssenceCapsuleItem.experienceStored(capsule)
|
||||
capsuleContainer.clearContent()
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,39 @@
|
||||
package ru.dbotthepony.mc.otm.block.tech
|
||||
|
||||
import net.minecraft.core.BlockPos
|
||||
import net.minecraft.world.InteractionHand
|
||||
import net.minecraft.world.InteractionResult
|
||||
import net.minecraft.world.entity.player.Player
|
||||
import net.minecraft.world.level.Level
|
||||
import net.minecraft.world.level.block.EntityBlock
|
||||
import net.minecraft.world.level.block.entity.BlockEntity
|
||||
import net.minecraft.world.level.block.entity.BlockEntityTicker
|
||||
import net.minecraft.world.level.block.entity.BlockEntityType
|
||||
import net.minecraft.world.level.block.state.BlockState
|
||||
import net.minecraft.world.phys.BlockHitResult
|
||||
import ru.dbotthepony.mc.otm.block.RotatableMatteryBlock
|
||||
import ru.dbotthepony.mc.otm.block.entity.tech.EssenceStorageBlockEntity
|
||||
import ru.dbotthepony.mc.otm.registry.MItems
|
||||
|
||||
class EssenceStorageBlock : RotatableMatteryBlock(), EntityBlock {
|
||||
override fun newBlockEntity(pPos: BlockPos, pState: BlockState): BlockEntity {
|
||||
return EssenceStorageBlockEntity(pPos, pState)
|
||||
}
|
||||
|
||||
override fun <T : BlockEntity?> getTicker(pLevel: Level, pState: BlockState, pBlockEntityType: BlockEntityType<T>): BlockEntityTicker<T>? {
|
||||
if (!pLevel.isClientSide) {
|
||||
return BlockEntityTicker { _, _, _, pBlockEntity -> if (pBlockEntity is EssenceStorageBlockEntity) pBlockEntity.tick() }
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
@Suppress("OVERRIDE_DEPRECATION")
|
||||
override fun use(blockState: BlockState, level: Level, blockPos: BlockPos, ply: Player, hand: InteractionHand, blockHitResult: BlockHitResult): InteractionResult {
|
||||
if (ply.getItemInHand(hand).item == MItems.ESSENCE_SERVO) {
|
||||
return MItems.ESSENCE_SERVO.useServo(ply, blockPos)
|
||||
}
|
||||
|
||||
return super.use(blockState, level, blockPos, ply, hand, blockHitResult)
|
||||
}
|
||||
}
|
@ -3,6 +3,8 @@ package ru.dbotthepony.mc.otm.client.screen.panels
|
||||
import com.mojang.blaze3d.vertex.PoseStack
|
||||
import net.minecraft.client.gui.screens.Screen
|
||||
import net.minecraft.network.chat.Component
|
||||
import ru.dbotthepony.mc.otm.client.render.TextAlign
|
||||
import ru.dbotthepony.mc.otm.client.render.drawAligned
|
||||
import ru.dbotthepony.mc.otm.core.TextComponent
|
||||
import ru.dbotthepony.mc.otm.core.math.RGBAColor
|
||||
|
||||
@ -27,6 +29,7 @@ open class Label<out S : Screen> @JvmOverloads constructor(
|
||||
}
|
||||
|
||||
var color = RGBAColor.SLATE_GRAY
|
||||
var align = TextAlign.TOP_RIGHT
|
||||
|
||||
override fun innerRender(stack: PoseStack, mouseX: Float, mouseY: Float, partialTick: Float) {
|
||||
clearDepth(stack)
|
||||
@ -35,7 +38,17 @@ open class Label<out S : Screen> @JvmOverloads constructor(
|
||||
font.draw(stack, text, shadowX, shadowY, shadowColor.toInt())
|
||||
}
|
||||
|
||||
font.draw(stack, text, 0f, 0f, color.toInt())
|
||||
when (align) {
|
||||
TextAlign.TOP_LEFT -> font.drawAligned(stack, text, align, 0f, 0f, color.toInt())
|
||||
TextAlign.TOP_CENTER -> font.drawAligned(stack, text, align, width / 2f, 0f, color.toInt())
|
||||
TextAlign.TOP_RIGHT -> font.drawAligned(stack, text, align, width, 0f, color.toInt())
|
||||
TextAlign.CENTER_LEFT -> font.drawAligned(stack, text, align, 0f, height / 2f, color.toInt())
|
||||
TextAlign.CENTER_CENTER -> font.drawAligned(stack, text, align, width / 2f, height / 2f, color.toInt())
|
||||
TextAlign.CENTER_RIGHT -> font.drawAligned(stack, text, align, width, height / 2f, color.toInt())
|
||||
TextAlign.BOTTOM_LEFT -> font.drawAligned(stack, text, align, 0f, height, color.toInt())
|
||||
TextAlign.BOTTOM_CENTER -> font.drawAligned(stack, text, align, width / 2f, height, color.toInt())
|
||||
TextAlign.BOTTOM_RIGHT -> font.drawAligned(stack, text, align, width, height, color.toInt())
|
||||
}
|
||||
}
|
||||
|
||||
override fun sizeToContents() {
|
||||
|
@ -0,0 +1,52 @@
|
||||
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.EditablePanel
|
||||
import kotlin.math.roundToInt
|
||||
|
||||
class HorizontalStripPanel<out S : Screen>(
|
||||
screen: S,
|
||||
parent: EditablePanel<*>?,
|
||||
x: Float = 0f,
|
||||
y: Float = 0f,
|
||||
width: Float = 0f,
|
||||
height: Float = 0f,
|
||||
) : EditablePanel<S>(screen, parent, x, y, width, height) {
|
||||
override fun sizeToContents() {
|
||||
var w = 0f
|
||||
var h = 0f
|
||||
|
||||
for (child in children) {
|
||||
if (child.dock == Dock.NONE) {
|
||||
w += child.width + child.dockMargin.left + child.dockMargin.right
|
||||
h = h.coerceAtLeast(child.height)
|
||||
}
|
||||
}
|
||||
|
||||
width = w
|
||||
height = h
|
||||
}
|
||||
|
||||
override fun performLayout() {
|
||||
super.performLayout()
|
||||
|
||||
var w = 0f
|
||||
|
||||
for (child in children) {
|
||||
if (child.dock == Dock.NONE) {
|
||||
w += child.width + child.dockMargin.left + child.dockMargin.right
|
||||
}
|
||||
}
|
||||
|
||||
w = width / 2f - w / 2f
|
||||
|
||||
for (child in children) {
|
||||
if (child.dock == Dock.NONE) {
|
||||
child.y = (height / 2f - child.height / 2f).roundToInt().toFloat()
|
||||
child.x = (w + child.dockMargin.left).roundToInt().toFloat()
|
||||
w += child.dockMargin.left + child.width + child.dockMargin.right
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,269 @@
|
||||
package ru.dbotthepony.mc.otm.client.screen.tech
|
||||
|
||||
import com.mojang.blaze3d.vertex.PoseStack
|
||||
import net.minecraft.ChatFormatting
|
||||
import net.minecraft.network.chat.Component
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
import net.minecraft.world.entity.player.Inventory
|
||||
import ru.dbotthepony.mc.otm.OverdriveThatMatters
|
||||
import ru.dbotthepony.mc.otm.client.isShiftDown
|
||||
import ru.dbotthepony.mc.otm.client.render.MatteryAtlas
|
||||
import ru.dbotthepony.mc.otm.client.render.TextAlign
|
||||
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.DockProperty
|
||||
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.Label
|
||||
import ru.dbotthepony.mc.otm.client.screen.panels.button.LargeRectangleButtonPanel
|
||||
import ru.dbotthepony.mc.otm.client.screen.panels.input.TextInputPanel
|
||||
import ru.dbotthepony.mc.otm.client.screen.panels.slot.SlotPanel
|
||||
import ru.dbotthepony.mc.otm.client.screen.panels.util.HorizontalStripPanel
|
||||
import ru.dbotthepony.mc.otm.core.TextComponent
|
||||
import ru.dbotthepony.mc.otm.core.TranslatableComponent
|
||||
import ru.dbotthepony.mc.otm.core.util.getLevelFromXp
|
||||
import ru.dbotthepony.mc.otm.core.util.getTotalXpRequiredForLevel
|
||||
import ru.dbotthepony.mc.otm.core.util.getXpRequiredForLevelUp
|
||||
import ru.dbotthepony.mc.otm.menu.tech.EssenceStorageMenu
|
||||
import ru.dbotthepony.mc.otm.registry.MItems
|
||||
|
||||
class EssenceStorageScreen(menu: EssenceStorageMenu, inventory: Inventory, title: Component) : MatteryScreen<EssenceStorageMenu>(menu, title) {
|
||||
override fun makeMainFrame(): FramePanel<MatteryScreen<*>> {
|
||||
val frame = FramePanel.padded(this, width = DEFAULT_FRAME_WIDTH, height = 18f * 2f + 36f + 25f, title)
|
||||
|
||||
val inputs = HorizontalStripPanel(this, frame, height = 18f)
|
||||
inputs.dock = Dock.TOP
|
||||
inputs.dockMargin = DockProperty(bottom = 3f, top = 3f)
|
||||
|
||||
SlotPanel(this, inputs, menu.capsuleSlot).also {
|
||||
it.dock = Dock.RIGHT
|
||||
it.tooltip = MItems.ESSENCE_CAPSULE.description.copy().withStyle(ChatFormatting.GRAY)
|
||||
}
|
||||
|
||||
HorizontalStripPanel(this, frame, height = 18f).also {
|
||||
it.dock = Dock.TOP
|
||||
it.dockMargin = DockProperty(bottom = 3f)
|
||||
|
||||
object : EditablePanel<EssenceStorageScreen>(this@EssenceStorageScreen, it, width = 108f, height = 15f) {
|
||||
init {
|
||||
dockResize = DockResizeMode.NONE
|
||||
dockMargin = DockProperty(bottom = 3f)
|
||||
}
|
||||
|
||||
override fun innerRender(stack: PoseStack, mouseX: Float, mouseY: Float, partialTick: Float) {
|
||||
BAR_BACKGROUND.render(stack, width = width, height = height)
|
||||
val level = getLevelFromXp(menu.experienceStored)
|
||||
val progress = (menu.experienceStored - getTotalXpRequiredForLevel(level)).toDouble() / getXpRequiredForLevelUp(level).toDouble()
|
||||
BAR_FOREGROUND.renderPartial(stack, width = width * progress.toFloat(), height = height)
|
||||
}
|
||||
}
|
||||
|
||||
SlotPanel(this, it, menu.servoSlot).also {
|
||||
it.dock = Dock.RIGHT
|
||||
it.tooltip = MItems.ESSENCE_SERVO.description.copy().withStyle(ChatFormatting.GRAY)
|
||||
}
|
||||
}
|
||||
|
||||
object : Label<EssenceStorageScreen>(this@EssenceStorageScreen, frame, text = TextComponent("")) {
|
||||
init {
|
||||
dock = Dock.TOP
|
||||
dockMargin = DockProperty(bottom = 3f)
|
||||
align = TextAlign.TOP_CENTER
|
||||
}
|
||||
|
||||
override fun tickInner() {
|
||||
super.tickInner()
|
||||
|
||||
if (minecraft?.window?.isShiftDown == true) {
|
||||
text = TranslatableComponent("otm.gui.experience", menu.experienceStored)
|
||||
} else {
|
||||
text = TranslatableComponent("otm.gui.experience_levels", getLevelFromXp(menu.experienceStored))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val outputs = HorizontalStripPanel(this, frame, width = 18f * 3 + 3f * 3, height = 18f)
|
||||
outputs.dock = Dock.TOP
|
||||
outputs.dockResize = DockResizeMode.NONE
|
||||
outputs.dockMargin = DockProperty(bottom = 3f)
|
||||
|
||||
object : LargeRectangleButtonPanel<EssenceStorageScreen>(this@EssenceStorageScreen, inputs, skinElement = STORE_1) {
|
||||
init {
|
||||
dockRight = 3f
|
||||
tooltip = TranslatableComponent("otm.gui.experience.store", 1)
|
||||
}
|
||||
|
||||
override fun onClick(mouseButton: Int) {
|
||||
menu.storeLevels.input(1)
|
||||
}
|
||||
|
||||
override var isDisabled: Boolean
|
||||
get() = !menu.storeLevels.test(minecraft?.player)
|
||||
set(value) {}
|
||||
}
|
||||
|
||||
object : LargeRectangleButtonPanel<EssenceStorageScreen>(this@EssenceStorageScreen, inputs, skinElement = STORE_10) {
|
||||
init {
|
||||
dockRight = 3f
|
||||
tooltip = TranslatableComponent("otm.gui.experience.store", 10)
|
||||
}
|
||||
|
||||
override fun onClick(mouseButton: Int) {
|
||||
menu.storeLevels.input(10)
|
||||
}
|
||||
|
||||
override var isDisabled: Boolean
|
||||
get() = !menu.storeLevels.test(minecraft?.player)
|
||||
set(value) {}
|
||||
}
|
||||
|
||||
object : LargeRectangleButtonPanel<EssenceStorageScreen>(this@EssenceStorageScreen, inputs, skinElement = STORE_ALL) {
|
||||
init {
|
||||
dockRight = 3f
|
||||
tooltip = TranslatableComponent("otm.gui.experience.store_all")
|
||||
}
|
||||
|
||||
override fun onClick(mouseButton: Int) {
|
||||
menu.storeLevels.input(minecraft?.player?.experienceLevel ?: 0)
|
||||
}
|
||||
|
||||
override var isDisabled: Boolean
|
||||
get() = !menu.storeLevels.test(minecraft?.player)
|
||||
set(value) {}
|
||||
}
|
||||
|
||||
object : LargeRectangleButtonPanel<EssenceStorageScreen>(this@EssenceStorageScreen, outputs, skinElement = DISPENSE_1) {
|
||||
init {
|
||||
dockRight = 3f
|
||||
tooltip = TranslatableComponent("otm.gui.experience.dispense", 1)
|
||||
}
|
||||
|
||||
override fun onClick(mouseButton: Int) {
|
||||
menu.dispenseLevels.input(1)
|
||||
}
|
||||
|
||||
override var isDisabled: Boolean
|
||||
get() = !menu.dispenseLevels.test(minecraft?.player)
|
||||
set(value) {}
|
||||
}
|
||||
|
||||
object : LargeRectangleButtonPanel<EssenceStorageScreen>(this@EssenceStorageScreen, outputs, skinElement = DISPENSE_10) {
|
||||
init {
|
||||
dockRight = 3f
|
||||
tooltip = TranslatableComponent("otm.gui.experience.dispense", 10)
|
||||
}
|
||||
|
||||
override fun onClick(mouseButton: Int) {
|
||||
menu.dispenseLevels.input(10)
|
||||
}
|
||||
|
||||
override var isDisabled: Boolean
|
||||
get() = !menu.dispenseLevels.test(minecraft?.player)
|
||||
set(value) {}
|
||||
}
|
||||
|
||||
object : LargeRectangleButtonPanel<EssenceStorageScreen>(this@EssenceStorageScreen, outputs, skinElement = DISPENSE_ALL) {
|
||||
init {
|
||||
dockRight = 3f
|
||||
tooltip = TranslatableComponent("otm.gui.experience.dispense_all")
|
||||
}
|
||||
|
||||
override fun onClick(mouseButton: Int) {
|
||||
menu.dispenseLevels.input(getLevelFromXp(menu.experienceStored) + 1)
|
||||
}
|
||||
|
||||
override var isDisabled: Boolean
|
||||
get() = !menu.dispenseLevels.test(minecraft?.player)
|
||||
set(value) {}
|
||||
}
|
||||
|
||||
val customBar = HorizontalStripPanel(this, frame, height = 18f)
|
||||
customBar.dock = Dock.TOP
|
||||
|
||||
object : LargeRectangleButtonPanel<EssenceStorageScreen>(this@EssenceStorageScreen, customBar, skinElement = STORE_CUSTOM) {
|
||||
init {
|
||||
tooltip = TranslatableComponent("otm.gui.experience.store", customDispense)
|
||||
}
|
||||
|
||||
override fun onClick(mouseButton: Int) {
|
||||
menu.storeLevels.input(customDispense)
|
||||
}
|
||||
|
||||
override var isDisabled: Boolean
|
||||
get() = !menu.storeLevels.test(minecraft?.player)
|
||||
set(value) {}
|
||||
}
|
||||
|
||||
object : TextInputPanel<EssenceStorageScreen>(this@EssenceStorageScreen, customBar, width = 60f) {
|
||||
init {
|
||||
dockMargin = DockProperty(left = 3f, right = 3f)
|
||||
text = customDispense.toString()
|
||||
}
|
||||
|
||||
override fun onTextChanged(old: String, new: String) {
|
||||
customDispense = (new.toIntOrNull() ?: 30).coerceAtLeast(1)
|
||||
}
|
||||
}
|
||||
|
||||
object : LargeRectangleButtonPanel<EssenceStorageScreen>(this@EssenceStorageScreen, customBar, skinElement = DISPENSE_CUSTOM) {
|
||||
init {
|
||||
tooltip = TranslatableComponent("otm.gui.experience.dispense", customDispense)
|
||||
}
|
||||
|
||||
override fun onClick(mouseButton: Int) {
|
||||
menu.dispenseLevels.input(customDispense)
|
||||
}
|
||||
|
||||
override var isDisabled: Boolean
|
||||
get() = !menu.dispenseLevels.test(minecraft?.player)
|
||||
set(value) {}
|
||||
}
|
||||
|
||||
object : LargeRectangleButtonPanel<EssenceStorageScreen>(this@EssenceStorageScreen, customBar, skinElement = SET_EXACT) {
|
||||
init {
|
||||
tooltip = TranslatableComponent("otm.gui.experience.set_exact", customDispense)
|
||||
dock = Dock.RIGHT
|
||||
dockMargin = DockProperty(right = 4f)
|
||||
}
|
||||
|
||||
override fun onClick(mouseButton: Int) {
|
||||
val player = minecraft?.player ?: return
|
||||
|
||||
if (player.experienceLevel == customDispense) {
|
||||
if (player.experienceProgress > 0f) {
|
||||
menu.storeLevels.input(1)
|
||||
}
|
||||
} else if (player.experienceLevel > customDispense) {
|
||||
menu.storeLevels.input(player.experienceLevel - customDispense)
|
||||
} else {
|
||||
menu.dispenseLevels.input(customDispense - player.experienceLevel)
|
||||
}
|
||||
}
|
||||
|
||||
override var isDisabled: Boolean
|
||||
get() = !menu.dispenseLevels.test(minecraft?.player) && !menu.storeLevels.test(minecraft?.player)
|
||||
set(value) {}
|
||||
}
|
||||
|
||||
return frame
|
||||
}
|
||||
|
||||
companion object {
|
||||
private var customDispense = 30
|
||||
|
||||
val ATLAS = MatteryAtlas(ResourceLocation(OverdriveThatMatters.MOD_ID, "textures/gui/essence_storage.png"), 108f, 66f)
|
||||
val STORE_1 = ATLAS.sprite(width = 18f, height = 18f)
|
||||
val STORE_10 = ATLAS.sprite(x = 18f, width = 18f, height = 18f)
|
||||
val STORE_ALL = ATLAS.sprite(x = 18f * 2, width = 18f, height = 18f)
|
||||
val DISPENSE_1 = ATLAS.sprite(x = 18f * 3, width = 18f, height = 18f)
|
||||
val DISPENSE_10 = ATLAS.sprite(x = 18f * 4, width = 18f, height = 18f)
|
||||
val DISPENSE_ALL = ATLAS.sprite(x = 18f * 5, width = 18f, height = 18f)
|
||||
val BAR_BACKGROUND = ATLAS.sprite(y = 18f, height = 15f)
|
||||
val BAR_FOREGROUND = ATLAS.sprite(y = 18f + 15f, height = 15f)
|
||||
|
||||
val STORE_CUSTOM = ATLAS.sprite(width = 18f, height = 18f, y = 48f)
|
||||
val DISPENSE_CUSTOM = ATLAS.sprite(width = 18f, height = 18f, y = 48f, x = 18f)
|
||||
val SET_EXACT = ATLAS.sprite(width = 18f, height = 18f, y = 48f, x = 18f * 2f)
|
||||
}
|
||||
}
|
@ -0,0 +1,97 @@
|
||||
package ru.dbotthepony.mc.otm.core.util
|
||||
|
||||
import it.unimi.dsi.fastutil.longs.LongArrayList
|
||||
import net.minecraft.world.entity.player.Player
|
||||
|
||||
private val levelsTable = LongArrayList()
|
||||
private val totalLevelsTable = LongArrayList().also { it.add(0L) }
|
||||
|
||||
private fun calculate(level: Int): Long {
|
||||
return if (level >= 30) {
|
||||
112L + (level - 30) * 9L
|
||||
} else {
|
||||
if (level >= 15) 37L + (level - 15) * 5L else 7L + level * 2L
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Experience points required for leveling **up from** specified [level].
|
||||
*
|
||||
* Works exactly like [Player.getXpNeededForNextLevel],
|
||||
* meaning that to achieve `level + 1` player need to acquire [getXpRequiredForLevelUp] experience points
|
||||
*/
|
||||
fun getXpRequiredForLevelUp(level: Int): Long {
|
||||
require(level >= 0) { "Negative level: $level" }
|
||||
|
||||
if (levelsTable.size <= level) {
|
||||
synchronized(levelsTable) {
|
||||
while (levelsTable.size <= level) {
|
||||
levelsTable.add(calculate(levelsTable.size))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return levelsTable.getLong(level)
|
||||
}
|
||||
|
||||
/**
|
||||
* Experience points required for achieving **exact** [level] specified.
|
||||
*
|
||||
* Example:
|
||||
* * 0 level -> 0 points (because player starts at level 0)
|
||||
* * 1 level -> [getXpRequiredForLevelUp]`(0)`
|
||||
* * 2 level -> [getXpRequiredForLevelUp]`(0)` + [getXpRequiredForLevelUp]`(1)`
|
||||
* * and so on
|
||||
*/
|
||||
fun getTotalXpRequiredForLevel(level: Int): Long {
|
||||
require(level >= 0) { "Negative level: $level" }
|
||||
|
||||
if (totalLevelsTable.size <= level) {
|
||||
synchronized(totalLevelsTable) {
|
||||
while (totalLevelsTable.size <= level) {
|
||||
totalLevelsTable.add(totalLevelsTable.getLong(totalLevelsTable.size - 1) + getXpRequiredForLevelUp(totalLevelsTable.size - 1))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return totalLevelsTable.getLong(level)
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines current level from [experience] points provided
|
||||
*/
|
||||
fun getLevelFromXp(experience: Long): Int {
|
||||
require(experience >= 0L) { "Negative experience: $experience" }
|
||||
|
||||
if (totalLevelsTable.getLong(totalLevelsTable.size - 1) < experience) {
|
||||
synchronized(totalLevelsTable) {
|
||||
while (totalLevelsTable.getLong(totalLevelsTable.size - 1) < experience) {
|
||||
totalLevelsTable.add(totalLevelsTable.getLong(totalLevelsTable.size - 1) + getXpRequiredForLevelUp(totalLevelsTable.size - 1))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var bottom = 0
|
||||
var top = totalLevelsTable.size - 1
|
||||
|
||||
while (top - bottom > 4) {
|
||||
val middle = bottom + (top - bottom) / 2
|
||||
val middleValue = totalLevelsTable.getLong(middle)
|
||||
|
||||
if (middleValue == experience) {
|
||||
return middle
|
||||
} else if (middleValue > experience) {
|
||||
top = middle - 1
|
||||
} else {
|
||||
bottom = middle + 1
|
||||
}
|
||||
}
|
||||
|
||||
for (i in bottom + 1 .. top) {
|
||||
if (totalLevelsTable.getLong(i) > experience) {
|
||||
return i - 1
|
||||
}
|
||||
}
|
||||
|
||||
return top
|
||||
}
|
@ -6,6 +6,7 @@ import net.minecraft.nbt.DoubleTag
|
||||
import net.minecraft.nbt.FloatTag
|
||||
import net.minecraft.nbt.IntTag
|
||||
import net.minecraft.nbt.ListTag
|
||||
import net.minecraft.nbt.LongTag
|
||||
import net.minecraft.nbt.NumericTag
|
||||
import net.minecraft.nbt.StringTag
|
||||
import net.minecraft.nbt.Tag
|
||||
@ -126,6 +127,18 @@ class Savetables : INBTSerializable<CompoundTag?> {
|
||||
.withDeserializer { it.asInt }
|
||||
}
|
||||
|
||||
fun long(prop: GetterSetter<Long>, name: String): Stateless<Long, NumericTag> {
|
||||
return Stateless(prop, name, NumericTag::class.java)
|
||||
.withSerializer { LongTag.valueOf(it) }
|
||||
.withDeserializer { it.asLong }
|
||||
}
|
||||
|
||||
fun long(prop: KMutableProperty0<Long>, name: String = prop.name): Stateless<Long, NumericTag> {
|
||||
return Stateless(prop, name, NumericTag::class.java)
|
||||
.withSerializer { LongTag.valueOf(it) }
|
||||
.withDeserializer { it.asLong }
|
||||
}
|
||||
|
||||
fun bool(prop: GetterSetter<Boolean>, name: String): Stateless<Boolean, NumericTag> {
|
||||
return Stateless(prop, name, NumericTag::class.java)
|
||||
.withSerializer { ByteTag.valueOf(it) }
|
||||
|
@ -0,0 +1,48 @@
|
||||
package ru.dbotthepony.mc.otm.item
|
||||
|
||||
import net.minecraft.ChatFormatting
|
||||
import net.minecraft.network.chat.Component
|
||||
import net.minecraft.world.item.Item
|
||||
import net.minecraft.world.item.ItemStack
|
||||
import net.minecraft.world.item.Rarity
|
||||
import net.minecraft.world.item.TooltipFlag
|
||||
import net.minecraft.world.level.Level
|
||||
import ru.dbotthepony.mc.otm.client.isShiftDown
|
||||
import ru.dbotthepony.mc.otm.client.minecraft
|
||||
import ru.dbotthepony.mc.otm.core.TranslatableComponent
|
||||
import ru.dbotthepony.mc.otm.core.nbt.set
|
||||
import ru.dbotthepony.mc.otm.core.tagNotNull
|
||||
import ru.dbotthepony.mc.otm.core.util.getLevelFromXp
|
||||
import ru.dbotthepony.mc.otm.runIfClient
|
||||
|
||||
class EssenceCapsuleItem : Item(Properties().stacksTo(1).rarity(Rarity.UNCOMMON)) {
|
||||
override fun appendHoverText(pStack: ItemStack, pLevel: Level?, pTooltipComponents: MutableList<Component>, pIsAdvanced: TooltipFlag) {
|
||||
super.appendHoverText(pStack, pLevel, pTooltipComponents, pIsAdvanced)
|
||||
pTooltipComponents.add(TranslatableComponent("otm.gui.essence_capsule").withStyle(ChatFormatting.GRAY))
|
||||
pTooltipComponents.add(TranslatableComponent("otm.gui.essence_capsule2").withStyle(ChatFormatting.GRAY))
|
||||
|
||||
if (runIfClient(false) { minecraft.window.isShiftDown }) {
|
||||
pTooltipComponents.add(TranslatableComponent("otm.gui.experience", experienceStored(pStack)).withStyle(ChatFormatting.GRAY))
|
||||
} else {
|
||||
pTooltipComponents.add(TranslatableComponent("otm.gui.experience_levels", getLevelFromXp(experienceStored(pStack))).withStyle(ChatFormatting.GRAY))
|
||||
}
|
||||
}
|
||||
|
||||
fun make(experience: Long): ItemStack {
|
||||
return ItemStack(this, 1).also {
|
||||
setExperience(it, experience)
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
@JvmStatic
|
||||
fun setExperience(itemStack: ItemStack, experience: Long) {
|
||||
itemStack.tagNotNull["experience"] = experience
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun experienceStored(itemStack: ItemStack): Long {
|
||||
return (itemStack.tag?.getLong("experience") ?: 0L) * itemStack.count
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,80 @@
|
||||
package ru.dbotthepony.mc.otm.item
|
||||
|
||||
import net.minecraft.ChatFormatting
|
||||
import net.minecraft.core.BlockPos
|
||||
import net.minecraft.network.chat.Component
|
||||
import net.minecraft.server.level.ServerPlayer
|
||||
import net.minecraft.world.InteractionResult
|
||||
import net.minecraft.world.entity.player.Player
|
||||
import net.minecraft.world.item.Item
|
||||
import net.minecraft.world.item.ItemStack
|
||||
import net.minecraft.world.item.TooltipFlag
|
||||
import net.minecraft.world.item.context.UseOnContext
|
||||
import net.minecraft.world.level.Level
|
||||
import ru.dbotthepony.mc.otm.block.entity.tech.EssenceStorageBlockEntity
|
||||
import ru.dbotthepony.mc.otm.core.TranslatableComponent
|
||||
|
||||
class EssenceServoItem : Item(Properties().stacksTo(64)) {
|
||||
override fun appendHoverText(pStack: ItemStack, pLevel: Level?, pTooltipComponents: MutableList<Component>, pIsAdvanced: TooltipFlag) {
|
||||
super.appendHoverText(pStack, pLevel, pTooltipComponents, pIsAdvanced)
|
||||
pTooltipComponents.add(TranslatableComponent("$descriptionId.desc2").withStyle(ChatFormatting.GRAY))
|
||||
pTooltipComponents.add(TranslatableComponent("$descriptionId.desc").withStyle(ChatFormatting.DARK_GRAY))
|
||||
}
|
||||
|
||||
fun useServo(player: Player, pos: BlockPos): InteractionResult {
|
||||
val block = player.level.getBlockEntity(pos) ?: return InteractionResult.FAIL
|
||||
|
||||
// TODO: опыт как жидкость
|
||||
if (block is EssenceStorageBlockEntity) {
|
||||
if (player.level.isClientSide) return InteractionResult.SUCCESS
|
||||
if (player !is ServerPlayer) return InteractionResult.FAIL
|
||||
|
||||
if (player.isCrouching) { // выгружаем в блок
|
||||
storeLevel(player, block)
|
||||
} else { // выгружаем из блока
|
||||
dispenseLevel(player, block)
|
||||
}
|
||||
|
||||
return InteractionResult.SUCCESS
|
||||
}
|
||||
|
||||
return InteractionResult.FAIL
|
||||
}
|
||||
|
||||
override fun useOn(pContext: UseOnContext): InteractionResult {
|
||||
val player = pContext.player ?: return InteractionResult.FAIL
|
||||
return useServo(player, pContext.clickedPos)
|
||||
}
|
||||
|
||||
companion object {
|
||||
@JvmStatic
|
||||
fun storeLevel(player: ServerPlayer, block: EssenceStorageBlockEntity) {
|
||||
val fpoints = (player.experienceProgress * player.xpNeededForNextLevel).toInt()
|
||||
|
||||
if (fpoints > 0) {
|
||||
block.experienceStored += fpoints
|
||||
player.setExperiencePoints(0)
|
||||
} else if (player.experienceLevel > 0) {
|
||||
player.setExperienceLevels(player.experienceLevel - 1)
|
||||
block.experienceStored += player.xpNeededForNextLevel
|
||||
player.setExperiencePoints(0) // для надёжности
|
||||
}
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun dispenseLevel(player: ServerPlayer, block: EssenceStorageBlockEntity) {
|
||||
val fpoints = (player.experienceProgress * player.xpNeededForNextLevel).toInt()
|
||||
val missingPoints = player.xpNeededForNextLevel - fpoints
|
||||
val diff = block.experienceStored.coerceAtMost(missingPoints.toLong()).toInt()
|
||||
|
||||
if (diff == missingPoints) {
|
||||
player.setExperienceLevels(player.experienceLevel + 1)
|
||||
player.setExperiencePoints(0)
|
||||
} else {
|
||||
player.setExperiencePoints(fpoints + diff)
|
||||
}
|
||||
|
||||
block.experienceStored -= diff
|
||||
}
|
||||
}
|
||||
}
|
@ -31,6 +31,7 @@ import ru.dbotthepony.mc.otm.core.util.BinaryStringCodec
|
||||
import ru.dbotthepony.mc.otm.core.util.BooleanValueCodec
|
||||
import ru.dbotthepony.mc.otm.core.util.IStreamCodec
|
||||
import ru.dbotthepony.mc.otm.core.util.NullValueCodec
|
||||
import ru.dbotthepony.mc.otm.core.util.VarIntValueCodec
|
||||
import ru.dbotthepony.mc.otm.menu.widget.AbstractWidget
|
||||
import ru.dbotthepony.mc.otm.network.FieldSynchronizer
|
||||
import ru.dbotthepony.mc.otm.network.MatteryPacket
|
||||
@ -92,7 +93,7 @@ abstract class MatteryMenu @JvmOverloads protected constructor(
|
||||
|
||||
context.enqueueWork {
|
||||
val menu = context.sender?.containerMenu as? MatteryMenu ?: return@enqueueWork
|
||||
if (menu.containerId != containerId) return@enqueueWork
|
||||
if (menu.containerId != containerId || !menu.stillValid(context.sender!!)) return@enqueueWork
|
||||
val input = menu.playerInputs.getOrNull(inputId) ?: return@enqueueWork
|
||||
if (!input.test(context.sender)) return@enqueueWork
|
||||
input.invoke(input.codec.read(DataInputStream(FastByteArrayInputStream(payload))))
|
||||
@ -149,6 +150,7 @@ abstract class MatteryMenu @JvmOverloads protected constructor(
|
||||
fun bigDecimalInput(allowSpectators: Boolean = false, handler: (BigDecimal) -> Unit) = PlayerInput(BigDecimalValueCodec, allowSpectators, handler)
|
||||
fun booleanInput(allowSpectators: Boolean = false, handler: (Boolean) -> Unit) = PlayerInput(BooleanValueCodec, allowSpectators, handler)
|
||||
fun stringInput(allowSpectators: Boolean = false, handler: (String) -> Unit) = PlayerInput(BinaryStringCodec, allowSpectators, handler)
|
||||
fun intInput(allowSpectators: Boolean = false, handler: (Int) -> Unit) = PlayerInput(VarIntValueCodec, allowSpectators, handler)
|
||||
|
||||
/**
|
||||
* inventory + exosuit + hotbar (in this order)
|
||||
|
@ -0,0 +1,93 @@
|
||||
package ru.dbotthepony.mc.otm.menu.tech
|
||||
|
||||
import net.minecraft.server.level.ServerPlayer
|
||||
import net.minecraft.world.SimpleContainer
|
||||
import net.minecraft.world.entity.player.Inventory
|
||||
import net.minecraft.world.item.ItemStack
|
||||
import ru.dbotthepony.mc.otm.block.entity.tech.EssenceStorageBlockEntity
|
||||
import ru.dbotthepony.mc.otm.capability.itemsStream
|
||||
import ru.dbotthepony.mc.otm.capability.matteryPlayer
|
||||
import ru.dbotthepony.mc.otm.core.util.LongValueCodec
|
||||
import ru.dbotthepony.mc.otm.core.util.getTotalXpRequiredForLevel
|
||||
import ru.dbotthepony.mc.otm.item.EssenceCapsuleItem
|
||||
import ru.dbotthepony.mc.otm.item.EssenceServoItem
|
||||
import ru.dbotthepony.mc.otm.menu.MatteryMenu
|
||||
import ru.dbotthepony.mc.otm.menu.MatterySlot
|
||||
import ru.dbotthepony.mc.otm.registry.MItems
|
||||
import ru.dbotthepony.mc.otm.registry.MMenus
|
||||
|
||||
class EssenceStorageMenu @JvmOverloads constructor(
|
||||
containerID: Int,
|
||||
inventory: Inventory,
|
||||
tile: EssenceStorageBlockEntity? = null
|
||||
) : MatteryMenu(MMenus.ESSENCE_STORAGE, containerID, inventory, tile) {
|
||||
val experienceStored by mSynchronizer.ComputedField(getter = { tile?.experienceStored ?: 0L }, LongValueCodec)
|
||||
|
||||
val capsuleSlot = object : MatterySlot(tile?.capsuleContainer ?: SimpleContainer(1), 0) {
|
||||
override fun mayPlace(itemStack: ItemStack): Boolean {
|
||||
return itemStack.item is EssenceCapsuleItem && super.mayPlace(itemStack)
|
||||
}
|
||||
}
|
||||
|
||||
val servoSlot = object : MatterySlot(tile?.servoContainer ?: SimpleContainer(1), 0) {
|
||||
override fun mayPlace(itemStack: ItemStack): Boolean {
|
||||
return itemStack.item == MItems.ESSENCE_SERVO && super.mayPlace(itemStack)
|
||||
}
|
||||
}
|
||||
|
||||
val storeLevels = intInput {
|
||||
if (it > 0) {
|
||||
val ply = ply as ServerPlayer
|
||||
tile!!
|
||||
|
||||
if (it == 1) {
|
||||
EssenceServoItem.storeLevel(ply, tile)
|
||||
} else {
|
||||
if (ply.experienceProgress > 0f) {
|
||||
EssenceServoItem.storeLevel(ply, tile)
|
||||
}
|
||||
|
||||
if (ply.experienceLevel > 0) {
|
||||
val old = ply.experienceLevel
|
||||
val new = (old - it).coerceAtLeast(0)
|
||||
|
||||
tile.experienceStored += getTotalXpRequiredForLevel(old) - getTotalXpRequiredForLevel(new)
|
||||
ply.setExperienceLevels(new)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val dispenseLevels = intInput {
|
||||
if (it > 0) {
|
||||
val ply = ply as ServerPlayer
|
||||
tile!!
|
||||
|
||||
if (it == 1) {
|
||||
EssenceServoItem.dispenseLevel(ply, tile)
|
||||
} else {
|
||||
var i = 0
|
||||
|
||||
while (i++ < it && tile.experienceStored > 0L) {
|
||||
EssenceServoItem.dispenseLevel(ply, tile)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
init {
|
||||
storeLevels.filter {
|
||||
it.isCreative || it.matteryPlayer?.isAndroid == true || servoSlot.item.item == MItems.ESSENCE_SERVO //|| it.itemsStream(true).anyMatch { it.item == MItems.ESSENCE_SERVO }
|
||||
}
|
||||
|
||||
dispenseLevels.filter {
|
||||
it.isCreative || it.matteryPlayer?.isAndroid == true || servoSlot.item.item == MItems.ESSENCE_SERVO //|| it.itemsStream(true).anyMatch { it.item == MItems.ESSENCE_SERVO }
|
||||
}
|
||||
|
||||
dispenseLevels.filter { (tile?.experienceStored ?: experienceStored) > 0L }
|
||||
|
||||
addStorageSlot(capsuleSlot)
|
||||
addStorageSlot(servoSlot)
|
||||
addInventorySlots()
|
||||
}
|
||||
}
|
@ -132,6 +132,8 @@ internal fun addMainCreativeTabItems(consumer: CreativeModeTab.Output) {
|
||||
accept(MItems.BLACK_HOLE)
|
||||
accept(MItems.GRAVITATIONAL_DISRUPTOR)
|
||||
|
||||
accept(MItems.ESSENCE_SERVO)
|
||||
|
||||
energized(MItems.ALL_BATTERIES)
|
||||
mattery(MItems.MATTER_CAPACITORS)
|
||||
accept(MItems.PATTERN_DRIVE_NORMAL)
|
||||
|
@ -56,6 +56,7 @@ object MBlockEntities {
|
||||
val MATTER_RECYCLER: BlockEntityType<MatterRecyclerBlockEntity> by registry.register(MNames.MATTER_RECYCLER) { BlockEntityType.Builder.of(::MatterRecyclerBlockEntity, MBlocks.MATTER_RECYCLER).build(null) }
|
||||
val ENERGY_SERVO: BlockEntityType<EnergyServoBlockEntity> by registry.register(MNames.ENERGY_SERVO) { BlockEntityType.Builder.of(::EnergyServoBlockEntity, MBlocks.ENERGY_SERVO).build(null) }
|
||||
val COBBLESTONE_GENERATOR: BlockEntityType<CobblerBlockEntity> by registry.register(MNames.COBBLESTONE_GENERATOR) { BlockEntityType.Builder.of(::CobblerBlockEntity, MBlocks.COBBLESTONE_GENERATOR).build(null) }
|
||||
val ESSENCE_STORAGE: BlockEntityType<EssenceStorageBlockEntity> by registry.register(MNames.ESSENCE_STORAGE) { BlockEntityType.Builder.of(::EssenceStorageBlockEntity, MBlocks.ESSENCE_STORAGE).build(null) }
|
||||
|
||||
val STORAGE_BUS: BlockEntityType<StorageBusBlockEntity> by registry.register(MNames.STORAGE_BUS) { BlockEntityType.Builder.of(::StorageBusBlockEntity, MBlocks.STORAGE_BUS).build(null) }
|
||||
val STORAGE_IMPORTER: BlockEntityType<StorageImporterBlockEntity> by registry.register(MNames.STORAGE_IMPORTER) { BlockEntityType.Builder.of(::StorageImporterBlockEntity, MBlocks.STORAGE_IMPORTER).build(null) }
|
||||
|
@ -64,6 +64,7 @@ import ru.dbotthepony.mc.otm.block.storage.StorageExporterBlock
|
||||
import ru.dbotthepony.mc.otm.block.storage.StorageImporterBlock
|
||||
import ru.dbotthepony.mc.otm.block.storage.StoragePowerSupplierBlock
|
||||
import ru.dbotthepony.mc.otm.block.tech.CobblerBlock
|
||||
import ru.dbotthepony.mc.otm.block.tech.EssenceStorageBlock
|
||||
import ru.dbotthepony.mc.otm.core.TranslatableComponent
|
||||
import ru.dbotthepony.mc.otm.core.collect.SupplierList
|
||||
import java.util.function.Supplier
|
||||
@ -91,6 +92,7 @@ object MBlocks {
|
||||
val MATTER_RECYCLER: Block by registry.register(MNames.MATTER_RECYCLER) { MatterRecyclerBlock() }
|
||||
val ENERGY_SERVO: Block by registry.register(MNames.ENERGY_SERVO) { EnergyServoBlock() }
|
||||
val COBBLESTONE_GENERATOR: Block by registry.register(MNames.COBBLESTONE_GENERATOR) { CobblerBlock() }
|
||||
val ESSENCE_STORAGE: EssenceStorageBlock by registry.register(MNames.ESSENCE_STORAGE) { EssenceStorageBlock() }
|
||||
|
||||
val STORAGE_BUS: Block by registry.register(MNames.STORAGE_BUS) { StorageBusBlock() }
|
||||
val STORAGE_IMPORTER: Block by registry.register(MNames.STORAGE_IMPORTER) { StorageImporterBlock() }
|
||||
|
@ -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.tags.BlockTags
|
||||
import net.minecraft.world.entity.EquipmentSlot
|
||||
import net.minecraft.world.food.FoodProperties
|
||||
import net.minecraft.world.item.*
|
||||
@ -101,13 +100,22 @@ object MItems {
|
||||
}
|
||||
}
|
||||
|
||||
val ESSENCE_STORAGE: BlockItem by registry.register(MNames.ESSENCE_STORAGE) {
|
||||
object : BlockItem(MBlocks.ESSENCE_STORAGE, DEFAULT_PROPERTIES) {
|
||||
override fun appendHoverText(p_40572_: ItemStack, p_40573_: Level?, p_40574_: MutableList<Component>, p_40575_: TooltipFlag) {
|
||||
super.appendHoverText(p_40572_, p_40573_, p_40574_, p_40575_)
|
||||
p_40574_.add(TranslatableComponent("$descriptionId.desc").withStyle(ChatFormatting.GRAY))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val MACHINES = SupplierList(
|
||||
::ANDROID_STATION, ::BATTERY_BANK, ::MATTER_DECOMPOSER, ::MATTER_CAPACITOR_BANK, ::MATTER_CABLE, ::PATTERN_STORAGE,
|
||||
::MATTER_SCANNER, ::MATTER_PANEL, ::MATTER_REPLICATOR, ::MATTER_BOTTLER, ::ENERGY_COUNTER, ::CHEMICAL_GENERATOR,
|
||||
::PLATE_PRESS, ::MATTER_RECYCLER, ::STORAGE_BUS, ::STORAGE_IMPORTER, ::STORAGE_EXPORTER, ::DRIVE_VIEWER,
|
||||
::DRIVE_RACK, ::ITEM_MONITOR, ::STORAGE_CABLE, ::STORAGE_POWER_SUPPLIER, ::ENERGY_SERVO,
|
||||
::PHANTOM_ATTRACTOR,
|
||||
::GRAVITATION_STABILIZER, ::COBBLESTONE_GENERATOR
|
||||
::GRAVITATION_STABILIZER, ::COBBLESTONE_GENERATOR, ::ESSENCE_STORAGE
|
||||
)
|
||||
|
||||
val DEBUG_EXPLOSION_SMALL: Item by registry.register(MNames.DEBUG_EXPLOSION_SMALL) { BlockItem(MBlocks.DEBUG_EXPLOSION_SMALL, Item.Properties().stacksTo(64)) }
|
||||
@ -134,6 +142,10 @@ object MItems {
|
||||
val TRITANIUM_INGOT_BLOCK: BlockItem by registry.register(MNames.TRITANIUM_INGOT_BLOCK) { BlockItem(MBlocks.TRITANIUM_INGOT_BLOCK, DEFAULT_PROPERTIES) }
|
||||
val TRITANIUM_BARS: BlockItem by registry.register(MNames.TRITANIUM_BARS) { BlockItem(MBlocks.TRITANIUM_BARS, DEFAULT_PROPERTIES) }
|
||||
|
||||
val ESSENCE_SERVO: EssenceServoItem by registry.register("essence_servo") { EssenceServoItem() }
|
||||
val ESSENCE_CAPSULE: EssenceCapsuleItem by registry.register("essence_capsule") { EssenceCapsuleItem() }
|
||||
val ESSENCE_DRIVE: EssenceCapsuleItem by registry.register("essence_drive") { EssenceCapsuleItem() }
|
||||
|
||||
val TRITANIUM_COMPONENT: ForgeTier = ForgeTier(
|
||||
Tiers.IRON.level,
|
||||
3072,
|
||||
|
@ -31,6 +31,7 @@ import ru.dbotthepony.mc.otm.client.screen.tech.ChemicalGeneratorScreen
|
||||
import ru.dbotthepony.mc.otm.client.screen.tech.CobblerScreen
|
||||
import ru.dbotthepony.mc.otm.client.screen.tech.EnergyCounterScreen
|
||||
import ru.dbotthepony.mc.otm.client.screen.tech.EnergyServoScreen
|
||||
import ru.dbotthepony.mc.otm.client.screen.tech.EssenceStorageScreen
|
||||
import ru.dbotthepony.mc.otm.client.screen.tech.PlatePressScreen
|
||||
import ru.dbotthepony.mc.otm.menu.decorative.CargoCrateMenu
|
||||
import ru.dbotthepony.mc.otm.menu.decorative.HoloSignMenu
|
||||
@ -56,6 +57,7 @@ import ru.dbotthepony.mc.otm.menu.tech.ChemicalGeneratorMenu
|
||||
import ru.dbotthepony.mc.otm.menu.tech.CobblerMenu
|
||||
import ru.dbotthepony.mc.otm.menu.tech.EnergyCounterMenu
|
||||
import ru.dbotthepony.mc.otm.menu.tech.EnergyServoMenu
|
||||
import ru.dbotthepony.mc.otm.menu.tech.EssenceStorageMenu
|
||||
import ru.dbotthepony.mc.otm.menu.tech.PlatePressMenu
|
||||
|
||||
object MMenus {
|
||||
@ -82,6 +84,7 @@ object MMenus {
|
||||
val ENERGY_SERVO: MenuType<*> by registry.register(MNames.ENERGY_SERVO) { MenuType(::EnergyServoMenu) }
|
||||
val HOLO_SIGN: MenuType<HoloSignMenu> by registry.register(MNames.HOLO_SIGN) { MenuType(::HoloSignMenu) }
|
||||
val COBBLESTONE_GENERATOR: MenuType<CobblerMenu> by registry.register(MNames.COBBLESTONE_GENERATOR) { MenuType(::CobblerMenu) }
|
||||
val ESSENCE_STORAGE: MenuType<EssenceStorageMenu> by registry.register(MNames.ESSENCE_STORAGE) { MenuType(::EssenceStorageMenu) }
|
||||
|
||||
val STORAGE_BUS: MenuType<*> by registry.register(MNames.STORAGE_BUS) { MenuType(::StorageBusMenu) }
|
||||
val STORAGE_EXPORTER: MenuType<*> by registry.register(MNames.STORAGE_EXPORTER) { MenuType(::StorageExporterMenu) }
|
||||
@ -121,6 +124,7 @@ object MMenus {
|
||||
MenuScreens.register(ENERGY_SERVO as MenuType<EnergyServoMenu>, ::EnergyServoScreen)
|
||||
MenuScreens.register(HOLO_SIGN, ::HoloSignScreen)
|
||||
MenuScreens.register(COBBLESTONE_GENERATOR, ::CobblerScreen)
|
||||
MenuScreens.register(ESSENCE_STORAGE, ::EssenceStorageScreen)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -32,6 +32,7 @@ object MNames {
|
||||
const val MATTER_RECYCLER = "matter_recycler"
|
||||
const val ENERGY_SERVO = "energy_servo"
|
||||
const val COBBLESTONE_GENERATOR = "cobblestone_generator"
|
||||
const val ESSENCE_STORAGE = "essence_storage"
|
||||
const val TRITANIUM_ANVIL = "tritanium_anvil"
|
||||
|
||||
const val STORAGE_CABLE = "storage_cable" // нужен рецепт
|
||||
|
Binary file not shown.
After Width: | Height: | Size: 1.0 KiB |
Binary file not shown.
@ -0,0 +1,124 @@
|
||||
package ru.dbotthepony.mc.otm.tests
|
||||
|
||||
import org.junit.jupiter.api.Assertions.assertEquals
|
||||
import org.junit.jupiter.api.DisplayName
|
||||
import org.junit.jupiter.api.Test
|
||||
import ru.dbotthepony.mc.otm.core.util.getLevelFromXp
|
||||
import ru.dbotthepony.mc.otm.core.util.getTotalXpRequiredForLevel
|
||||
import ru.dbotthepony.mc.otm.core.util.getXpRequiredForLevelUp
|
||||
|
||||
object ExperienceUtilsTest {
|
||||
@Test
|
||||
@DisplayName("Experience utils xp required for level up")
|
||||
fun levelUp() {
|
||||
var i = 0
|
||||
assertEquals(7L, getXpRequiredForLevelUp(i++))
|
||||
assertEquals(9L, getXpRequiredForLevelUp(i++))
|
||||
assertEquals(11L, getXpRequiredForLevelUp(i++))
|
||||
assertEquals(13L, getXpRequiredForLevelUp(i++))
|
||||
assertEquals(15L, getXpRequiredForLevelUp(i++))
|
||||
assertEquals(17L, getXpRequiredForLevelUp(i++))
|
||||
assertEquals(19L, getXpRequiredForLevelUp(i++))
|
||||
assertEquals(21L, getXpRequiredForLevelUp(i++))
|
||||
assertEquals(23L, getXpRequiredForLevelUp(i++))
|
||||
assertEquals(25L, getXpRequiredForLevelUp(i++))
|
||||
assertEquals(27L, getXpRequiredForLevelUp(i++))
|
||||
assertEquals(29L, getXpRequiredForLevelUp(i++))
|
||||
assertEquals(31L, getXpRequiredForLevelUp(i++))
|
||||
assertEquals(33L, getXpRequiredForLevelUp(i++))
|
||||
assertEquals(35L, getXpRequiredForLevelUp(i++))
|
||||
assertEquals(37L, getXpRequiredForLevelUp(i++))
|
||||
assertEquals(42L, getXpRequiredForLevelUp(i++))
|
||||
assertEquals(47L, getXpRequiredForLevelUp(i++))
|
||||
assertEquals(52L, getXpRequiredForLevelUp(i++))
|
||||
assertEquals(57L, getXpRequiredForLevelUp(i++))
|
||||
assertEquals(62L, getXpRequiredForLevelUp(i++))
|
||||
assertEquals(67L, getXpRequiredForLevelUp(i++))
|
||||
assertEquals(72L, getXpRequiredForLevelUp(i++))
|
||||
assertEquals(77L, getXpRequiredForLevelUp(i++))
|
||||
assertEquals(82L, getXpRequiredForLevelUp(i++))
|
||||
assertEquals(87L, getXpRequiredForLevelUp(i++))
|
||||
assertEquals(92L, getXpRequiredForLevelUp(i++))
|
||||
assertEquals(97L, getXpRequiredForLevelUp(i++))
|
||||
assertEquals(102L, getXpRequiredForLevelUp(i++))
|
||||
assertEquals(107L, getXpRequiredForLevelUp(i++))
|
||||
assertEquals(112L, getXpRequiredForLevelUp(i++))
|
||||
assertEquals(121L, getXpRequiredForLevelUp(i++))
|
||||
assertEquals(130L, getXpRequiredForLevelUp(i++))
|
||||
assertEquals(139L, getXpRequiredForLevelUp(i++))
|
||||
assertEquals(148L, getXpRequiredForLevelUp(i++))
|
||||
assertEquals(157L, getXpRequiredForLevelUp(i++))
|
||||
assertEquals(166L, getXpRequiredForLevelUp(i++))
|
||||
assertEquals(175L, getXpRequiredForLevelUp(i++))
|
||||
assertEquals(184L, getXpRequiredForLevelUp(i++))
|
||||
assertEquals(193L, getXpRequiredForLevelUp(i++))
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("Experience utils total xp required for level")
|
||||
fun totalXp() {
|
||||
var i = 1
|
||||
assertEquals(7L, getTotalXpRequiredForLevel(i++)) // 1
|
||||
assertEquals(16L, getTotalXpRequiredForLevel(i++)) // 2
|
||||
assertEquals(27L, getTotalXpRequiredForLevel(i++)) // 3
|
||||
assertEquals(40L, getTotalXpRequiredForLevel(i++)) // 4
|
||||
assertEquals(55L, getTotalXpRequiredForLevel(i++)) // 5
|
||||
assertEquals(72L, getTotalXpRequiredForLevel(i++)) // 6
|
||||
assertEquals(91L, getTotalXpRequiredForLevel(i++)) // 7
|
||||
assertEquals(112L, getTotalXpRequiredForLevel(i++)) // 8
|
||||
assertEquals(135L, getTotalXpRequiredForLevel(i++)) // 9
|
||||
assertEquals(160L, getTotalXpRequiredForLevel(i++)) // 10
|
||||
assertEquals(187L, getTotalXpRequiredForLevel(i++)) // 11
|
||||
assertEquals(216L, getTotalXpRequiredForLevel(i++)) // 12
|
||||
assertEquals(247L, getTotalXpRequiredForLevel(i++)) // 13
|
||||
assertEquals(280L, getTotalXpRequiredForLevel(i++)) // 14
|
||||
assertEquals(315L, getTotalXpRequiredForLevel(i++)) // 15
|
||||
assertEquals(352L, getTotalXpRequiredForLevel(i++)) // 16
|
||||
assertEquals(394L, getTotalXpRequiredForLevel(i++)) // 17
|
||||
assertEquals(441L, getTotalXpRequiredForLevel(i++)) // 18
|
||||
assertEquals(493L, getTotalXpRequiredForLevel(i++)) // 19
|
||||
assertEquals(550L, getTotalXpRequiredForLevel(i++)) // 20
|
||||
assertEquals(612L, getTotalXpRequiredForLevel(i++)) // 21
|
||||
assertEquals(679L, getTotalXpRequiredForLevel(i++)) // 22
|
||||
assertEquals(751L, getTotalXpRequiredForLevel(i++)) // 23
|
||||
assertEquals(828L, getTotalXpRequiredForLevel(i++)) // 24
|
||||
assertEquals(910L, getTotalXpRequiredForLevel(i++)) // 25
|
||||
assertEquals(997L, getTotalXpRequiredForLevel(i++)) // 26
|
||||
assertEquals(1089L, getTotalXpRequiredForLevel(i++)) // 27
|
||||
assertEquals(1186L, getTotalXpRequiredForLevel(i++)) // 28
|
||||
assertEquals(1288L, getTotalXpRequiredForLevel(i++)) // 29
|
||||
assertEquals(1395L, getTotalXpRequiredForLevel(i++)) // 30
|
||||
assertEquals(1507L, getTotalXpRequiredForLevel(i++)) // 31
|
||||
assertEquals(1628L, getTotalXpRequiredForLevel(i++)) // 32
|
||||
assertEquals(1758L, getTotalXpRequiredForLevel(i++)) // 33
|
||||
assertEquals(1897L, getTotalXpRequiredForLevel(i++)) // 34
|
||||
assertEquals(2045L, getTotalXpRequiredForLevel(i++)) // 35
|
||||
assertEquals(2202L, getTotalXpRequiredForLevel(i++)) // 36
|
||||
assertEquals(2368L, getTotalXpRequiredForLevel(i++)) // 37
|
||||
assertEquals(2543L, getTotalXpRequiredForLevel(i++)) // 38
|
||||
assertEquals(2727L, getTotalXpRequiredForLevel(i++)) // 39
|
||||
assertEquals(2920L, getTotalXpRequiredForLevel(i++)) // 40
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("Experience utils reverse search xp -> level")
|
||||
fun reverseSearch() {
|
||||
assertEquals(0, getLevelFromXp(4L))
|
||||
assertEquals(0, getLevelFromXp(6L))
|
||||
assertEquals(1, getLevelFromXp(7L))
|
||||
assertEquals(1, getLevelFromXp(8L))
|
||||
|
||||
assertEquals(19, getLevelFromXp(540L))
|
||||
assertEquals(19, getLevelFromXp(545L))
|
||||
assertEquals(20, getLevelFromXp(550L))
|
||||
assertEquals(21, getLevelFromXp(551L))
|
||||
assertEquals(21, getLevelFromXp(554L))
|
||||
assertEquals(21, getLevelFromXp(556L))
|
||||
|
||||
for (i in 50 .. 100) {
|
||||
assertEquals(i, getLevelFromXp(getTotalXpRequiredForLevel(i)))
|
||||
assertEquals(i - 1, getLevelFromXp(getTotalXpRequiredForLevel(i) - 1L))
|
||||
assertEquals(i, getLevelFromXp(getTotalXpRequiredForLevel(i) + 1L))
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user