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 df3082d0a..9e1a28a10 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 @@ -164,8 +164,12 @@ private fun misc(provider: MatteryLanguageProvider) { misc("needs_no_power", "Requires no power to operate") gui("lock_holo_screen", "Lock contents") + gui("lock_holo_screen.unlocked", "Unlock contents") gui("lock_holo_screen.tip", "Locking and unlocking contents is only possible in creative.\nWhen locked, text boundaries are removed.") + gui("holo_screen.resize_text", "Resize text automatically") + gui("holo_screen.do_not_resize_text", "Do not resize text") + gui("ticks", "Ticks") gui("power_cost_per_use", "Power cost per use: %s") @@ -395,6 +399,7 @@ private fun misc(provider: MatteryLanguageProvider) { misc("android_station.research.low_power", "Android Station is low on power! Can't research!") misc("android_station.research.researched", "Researched!") misc("android_station.research.can_be_researched", "Ready to research!") + misc("android_station.research.can_not_afford", "Missing required items!") misc("android_station.research.can_not_be_researched", "Can't research!") misc("android_station.research.xp_cost", "Experience cost: %s levels") misc("android_station.research.item", "Requires %s x%s") 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 672541b8c..4b2fc7937 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 @@ -176,8 +176,12 @@ private fun misc(provider: MatteryLanguageProvider) { misc("needs_no_power", "Не требует энергии для работы") gui("lock_holo_screen", "Заблокировать содержимое") + gui("lock_holo_screen.unlocked", "Разблокировать содержимое") gui("lock_holo_screen.tip", "Блокировка и разблокировка содержимого возможна только в режиме творчества.\nКогда заблокировано, границы ввода текста отключены.") + gui("holo_screen.resize_text", "Изменять размер текста автоматически") + gui("holo_screen.do_not_resize_text", "Не менять размер текста") + gui("ticks", "Тиков") gui("power_cost_per_use", "Энергии на операцию: %s") @@ -403,6 +407,7 @@ private fun misc(provider: MatteryLanguageProvider) { misc("android_station.research.low_power", "Мало питания у станции андроидов! Исследования недоступны!") misc("android_station.research.researched", "Исследовано!") misc("android_station.research.can_be_researched", "Готово к исследованию!") + misc("android_station.research.can_not_afford", "Не хватает предметов!") misc("android_station.research.can_not_be_researched", "Нельзя исследовать!") misc("android_station.research.xp_cost", "Требуется %s уровней Опыта") misc("android_station.research.item", "Требует %s %s шт.") diff --git a/src/main/java/ru/dbotthepony/mc/otm/OverdriveThatMatters.java b/src/main/java/ru/dbotthepony/mc/otm/OverdriveThatMatters.java index 77e20d762..853a6188d 100644 --- a/src/main/java/ru/dbotthepony/mc/otm/OverdriveThatMatters.java +++ b/src/main/java/ru/dbotthepony/mc/otm/OverdriveThatMatters.java @@ -58,6 +58,7 @@ import ru.dbotthepony.mc.otm.matter.IMatterFunction; import ru.dbotthepony.mc.otm.matter.MatterManager; import ru.dbotthepony.mc.otm.network.*; import ru.dbotthepony.mc.otm.registry.*; +import ru.dbotthepony.mc.otm.server.MCommands; import ru.dbotthepony.mc.otm.storage.StorageStack; import ru.dbotthepony.mc.otm.triggers.KillAsAndroidTrigger; import top.theillusivec4.curios.api.CuriosApi; @@ -127,6 +128,7 @@ public final class OverdriveThatMatters { MArmorMaterials.INSTANCE.register(bus); MCriteriaTriggers.INSTANCE.register(bus); MStats.INSTANCE.register(bus); + CommandArgumentTypes.INSTANCE.register(bus); StorageStack.Companion.register(bus); MatteryChestMenu.Companion.register(bus); @@ -197,7 +199,6 @@ public final class OverdriveThatMatters { EVENT_BUS.addListener(EventPriority.NORMAL, MatteryPlayer.Companion::onPlayerSpawnPhantoms); EVENT_BUS.addListener(EventPriority.NORMAL, MatteryPlayer.Companion::onStartTracking); EVENT_BUS.addListener(EventPriority.NORMAL, MatteryPlayer.Companion::onStopTracking); - EVENT_BUS.addListener(EventPriority.NORMAL, MatteryPlayer.Companion::addCommands); EVENT_BUS.addListener(EventPriority.NORMAL, QuantumBatteryItem.Companion::tick); EVENT_BUS.addListener(EventPriority.LOWEST, PortableCondensationDriveItem.Companion::onPickupEvent); @@ -228,6 +229,8 @@ public final class OverdriveThatMatters { EVENT_BUS.addListener(EventPriority.NORMAL, DevChestBlockEntity.Companion::mappingsChanged); + EVENT_BUS.addListener(EventPriority.NORMAL, MCommands.INSTANCE::register); + if (ModList.get().isLoaded(CuriosApi.MODID)) { EVENT_BUS.addListener(EventPriority.NORMAL, CuriosCompatKt::onCuriosSlotModifiersUpdated); } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/android/AndroidResearch.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/android/AndroidResearch.kt index 003fad620..68ebb9380 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/android/AndroidResearch.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/android/AndroidResearch.kt @@ -171,17 +171,9 @@ class AndroidResearch(val type: AndroidResearchType, val capability: MatteryPlay return true } - val canResearch: Boolean get() { - if (!consumeResearchCost(simulate = true)) { - return false - } - - if (!isPrerequisitesResearched || (!ply.isCreative && isAnyBlockerResearched)) { - return false - } - - return true - } + val canResearch: Boolean get() = !(!isPrerequisitesResearched || (!ply.isCreative && isAnyBlockerResearched)) + val canAfford: Boolean get() = consumeResearchCost(simulate = true) + val readyToResearch: Boolean get() = canResearch && canAfford /** * Determines if this research is already blocked directly by another research. @@ -244,12 +236,12 @@ class AndroidResearch(val type: AndroidResearchType, val capability: MatteryPlay return true } - fun research(force: Boolean = false): Boolean { + fun research(force: Boolean = false, free: Boolean = false): Boolean { if (isResearched) { return false } - if (force || canResearch && consumeResearchCost(false)) { + if (force || canResearch && (free || canAfford && consumeResearchCost(false))) { onResearched() isResearched = true diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/android/feature/NanobotsArmorFeature.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/android/feature/NanobotsArmorFeature.kt index 512117f6b..820b2c566 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/android/feature/NanobotsArmorFeature.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/android/feature/NanobotsArmorFeature.kt @@ -3,6 +3,7 @@ package ru.dbotthepony.mc.otm.android.feature import net.minecraft.core.HolderLookup import net.minecraft.nbt.CompoundTag import net.minecraft.server.level.ServerPlayer +import net.minecraft.tags.DamageTypeTags import net.neoforged.neoforge.event.entity.living.LivingIncomingDamageEvent import ru.dbotthepony.kommons.util.getValue import ru.dbotthepony.kommons.util.setValue @@ -44,6 +45,8 @@ class NanobotsArmorFeature(android: MatteryPlayer) : AndroidFeature(AndroidFeatu } override fun onHurt(event: LivingIncomingDamageEvent) { + if (ply.invulnerableTime > 10 && !event.source.`is`(DamageTypeTags.BYPASSES_COOLDOWN)) return; + ticksPassed = 0 if (!event.source.isBypassArmor && layers > 0) { diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/decorative/HoloSignBlockEntity.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/decorative/HoloSignBlockEntity.kt index 34a356892..5ab2a9764 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/decorative/HoloSignBlockEntity.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/decorative/HoloSignBlockEntity.kt @@ -56,6 +56,11 @@ class HoloSignBlockEntity(blockPos: BlockPos, blockState: BlockState) : MatteryB var textBlue by syncher.float(85f / 255f, setter = ::colorSetter).delegate var textAlpha by syncher.float(1f).delegate + var textAutoScale by syncher.boolean(true, setter = { access, value -> + setChanged() + access.accept(value) + }).delegate + var isLocked = false init { @@ -67,6 +72,8 @@ class HoloSignBlockEntity(blockPos: BlockPos, blockState: BlockState) : MatteryB savetables.float(::textGreen) savetables.float(::textBlue) savetables.float(::textAlpha) + + savetables.bool(::textAutoScale) } override fun createMenu(p_39954_: Int, p_39955_: Inventory, p_39956_: Player): AbstractContainerMenu { diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/capability/MatteryPlayer.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/capability/MatteryPlayer.kt index a33f45d94..af8b509b3 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/capability/MatteryPlayer.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/capability/MatteryPlayer.kt @@ -8,8 +8,6 @@ import it.unimi.dsi.fastutil.objects.Object2ObjectArrayMap import net.minecraft.ChatFormatting import net.minecraft.client.model.PlayerModel import net.minecraft.client.player.AbstractClientPlayer -import net.minecraft.commands.Commands -import net.minecraft.commands.arguments.EntityArgument import net.minecraft.core.HolderLookup import net.minecraft.core.registries.BuiltInRegistries import net.minecraft.nbt.CompoundTag @@ -44,7 +42,6 @@ import net.neoforged.bus.api.Event import net.neoforged.bus.api.ICancellableEvent import net.neoforged.neoforge.common.CommonHooks import net.neoforged.neoforge.common.NeoForge -import net.neoforged.neoforge.event.RegisterCommandsEvent import net.neoforged.neoforge.event.entity.living.LivingDeathEvent import net.neoforged.neoforge.event.entity.living.LivingIncomingDamageEvent import net.neoforged.neoforge.event.entity.living.MobEffectEvent @@ -52,7 +49,6 @@ import net.neoforged.neoforge.event.entity.player.PlayerEvent import net.neoforged.neoforge.event.entity.player.PlayerSpawnPhantomsEvent import net.neoforged.neoforge.event.tick.PlayerTickEvent import net.neoforged.neoforge.network.PacketDistributor -import net.neoforged.neoforge.server.command.EnumArgument import org.apache.logging.log4j.LogManager import org.joml.Vector4f import ru.dbotthepony.kommons.collect.ListenableMap @@ -1409,76 +1405,6 @@ class MatteryPlayer(val ply: Player) { companion object { private val offhandSlotRange = IntSet.of(40) - private fun setExoPack(players: Collection, hasExoPack: Boolean): Int { - for (player in players) { - player.matteryPlayer.hasExopack = hasExoPack - player.matteryPlayer._exoPackMenu = null - } - - return players.size - } - - private fun makeAndroid(players: Collection): Int { - for (player in players) { - player.matteryPlayer.becomeAndroid() - } - - return players.size - } - - private fun makeHuman(players: Collection): Int { - for (player in players) { - player.matteryPlayer.becomeHumane() - } - - return players.size - } - - private fun setUpgrade(players: Collection, type: UpgradeType, state: Boolean): Int { - for (player in players) { - player.matteryPlayer.let { type.prop.set(it, state) } - } - - return players.size - } - - fun addCommands(event: RegisterCommandsEvent) { - event.dispatcher.register( - Commands.literal("exopack") - .requires { it.hasPermission(Commands.LEVEL_GAMEMASTERS) } - .then(Commands.literal("add") - .executes { setExoPack(listOf(it.source.playerOrException), true) } - .then(Commands.argument("targets", EntityArgument.players()).executes { setExoPack(EntityArgument.getPlayers(it, "targets"), true) }) - ) - .then(Commands.literal("remove") - .executes { setExoPack(listOf(it.source.playerOrException), false) } - .then(Commands.argument("targets", EntityArgument.players()).executes { setExoPack(EntityArgument.getPlayers(it, "targets"), false) }) - ) - .then(Commands.literal("upgrade") - .then(Commands.argument("type", EnumArgument.enumArgument(UpgradeType::class.java)) - .then(Commands.literal("add") - .executes { setUpgrade(listOf(it.source.playerOrException), it.getArgument("type", UpgradeType::class.java), true) } - .then(Commands.argument("targets", EntityArgument.players()).executes { setUpgrade(EntityArgument.getPlayers(it, "targets"), it.getArgument("type", UpgradeType::class.java), true) })) - .then(Commands.literal("remove") - .executes { setUpgrade(listOf(it.source.playerOrException), it.getArgument("type", UpgradeType::class.java), false) } - .then(Commands.argument("targets", EntityArgument.players()).executes { setUpgrade(EntityArgument.getPlayers(it, "targets"), it.getArgument("type", UpgradeType::class.java), false) }))) - ) - ) - - event.dispatcher.register( - Commands.literal("android") - .requires { it.hasPermission(Commands.LEVEL_GAMEMASTERS) } - .then(Commands.literal("on") - .executes { makeAndroid(listOf(it.source.playerOrException)) } - .then(Commands.argument("targets", EntityArgument.players()).executes { makeAndroid(EntityArgument.getPlayers(it, "targets")) }) - ) - .then(Commands.literal("off") - .executes { makeHuman(listOf(it.source.playerOrException)) } - .then(Commands.argument("targets", EntityArgument.players()).executes { makeHuman(EntityArgument.getPlayers(it, "targets")) }) - ) - ) - } - init { WitherBoss.TARGETING_CONDITIONS.selector(WitherBoss.TARGETING_CONDITIONS.selector!!.and { it.matteryPlayer?.isAndroid != true }) WitherBoss.LIVING_ENTITY_SELECTOR = WitherBoss.LIVING_ENTITY_SELECTOR.and { it.matteryPlayer?.isAndroid != true } 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 4454efe37..a405fed3d 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 @@ -176,4 +176,11 @@ object Widgets18 { } val UPGRADES = controlsGrid.next() + + val COLOR_PALETTE = controlsGrid.next() + val TEXT_SCALE_DISABLED = controlsGrid.next() + val TEXT_SCALE_ENABLED = controlsGrid.next() + + val LOCK_UNLOCKED = controlsGrid.next() + val LOCK_LOCKED = controlsGrid.next() } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/client/render/blockentity/HoloSignRenderer.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/client/render/blockentity/HoloSignRenderer.kt index 6242b1eee..dc86fa0d6 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/client/render/blockentity/HoloSignRenderer.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/client/render/blockentity/HoloSignRenderer.kt @@ -35,6 +35,13 @@ class HoloSignRenderer(private val context: BlockEntityRendererProvider.Context) val totalHeight = lines.size * font.lineHeight + (lines.size - 1) * 2f var y = -totalHeight / 2f + if (tile.textAutoScale) { + val totalWidth = lines.maxOf { font.width(it) }.toFloat() + val highest = totalWidth.coerceAtLeast(totalHeight) + val mul = if (highest > 96f) 1f / (highest / 96f) else 96f / highest + poseStack.scale(mul, mul, mul) + } + for (line in lines) { font.draw(poseStack = poseStack, buffer = bufferSource, text = line, gravity = RenderGravity.TOP_CENTER, y = y, color = RGBAColor(tile.textRed, tile.textGreen, tile.textBlue, tile.textAlpha)) y += font.lineHeight + 2f 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 726a5eab2..0f775924f 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 @@ -683,7 +683,10 @@ abstract class MatteryScreen(menu: T, inventory: Inventory, tit panelsReversed.any { it.updateCursor1() } RenderSystem.depthFunc(GL11.GL_LESS) + graphics.pose().pushPose() + graphics.pose().translate(guiLeft.toFloat(), guiTop.toFloat(), 0f) NeoForge.EVENT_BUS.post(ContainerScreenEvent.Render.Background(this, graphics, mouseX, mouseY)) + graphics.pose().popPose() RenderSystem.disableDepthTest() // Screen.super.render @@ -693,7 +696,10 @@ abstract class MatteryScreen(menu: T, inventory: Inventory, tit // /Screen.super.render RenderSystem.disableDepthTest() + graphics.pose().pushPose() + graphics.pose().translate(guiLeft.toFloat(), guiTop.toFloat(), 0f) NeoForge.EVENT_BUS.post(ContainerScreenEvent.Render.Foreground(this, graphics, mouseX, mouseY)) + graphics.pose().popPose() var itemstack = if (draggingItem.isEmpty) menu.carried else draggingItem diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/decorative/HoloSignScreen.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/decorative/HoloSignScreen.kt index f291876b3..66294534b 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/decorative/HoloSignScreen.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/decorative/HoloSignScreen.kt @@ -2,21 +2,18 @@ package ru.dbotthepony.mc.otm.client.screen.decorative import net.minecraft.network.chat.Component import net.minecraft.world.entity.player.Inventory -import net.minecraft.world.item.ItemStack -import ru.dbotthepony.mc.otm.client.render.ItemStackIcon import ru.dbotthepony.mc.otm.client.screen.MatteryScreen import ru.dbotthepony.mc.otm.client.screen.panels.ColorPickerPanel 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.FramePanel -import ru.dbotthepony.mc.otm.client.screen.panels.button.CheckBoxLabelInputPanel import ru.dbotthepony.mc.otm.client.screen.panels.button.LargeRectangleButtonPanel import ru.dbotthepony.mc.otm.client.screen.panels.button.makeDeviceControls import ru.dbotthepony.mc.otm.client.screen.panels.input.NetworkedStringInputPanel import ru.dbotthepony.mc.otm.core.TranslatableComponent import ru.dbotthepony.kommons.math.RGBAColor +import ru.dbotthepony.mc.otm.client.render.Widgets18 +import ru.dbotthepony.mc.otm.client.screen.panels.button.LargeBooleanRectangleButtonPanel import ru.dbotthepony.mc.otm.menu.decorative.HoloSignMenu -import ru.dbotthepony.mc.otm.registry.MItems class HoloSignScreen(menu: HoloSignMenu, inventory: Inventory, title: Component) : MatteryScreen(menu, title) { override fun makeMainFrame(): FramePanel> { @@ -24,16 +21,14 @@ class HoloSignScreen(menu: HoloSignMenu, inventory: Inventory, title: Component) frame.makeCloseButton() frame.onClose { onClose() } + frame.makeHelpButton().apply { + tooltips.add(TranslatableComponent("otm.gui.lock_holo_screen.tip")) + } val input = NetworkedStringInputPanel(this, frame, backend = menu.text) input.dock = Dock.FILL input.isMultiLine = true - val lock = CheckBoxLabelInputPanel(this, frame, menu.locked, TranslatableComponent("otm.gui.lock_holo_screen")) - lock.dock = Dock.BOTTOM - lock.dockMargin = DockProperty(2f, 2f, 2f, 2f) - lock.tooltips.add(TranslatableComponent("otm.gui.lock_holo_screen.tip")) - val controls = makeDeviceControls(this, frame, redstoneConfig = menu.redstone) controls.addButton(object : LargeRectangleButtonPanel(this@HoloSignScreen, frame, onPress = { @@ -51,10 +46,30 @@ class HoloSignScreen(menu: HoloSignMenu, inventory: Inventory, title: Component) }) { init { tooltips.add(TranslatableComponent("otm.gui.change_color")) - icon = ItemStackIcon(ItemStack(MItems.PAINTER)).fixed() + icon = Widgets18.COLOR_PALETTE } }) + controls.addButton(LargeBooleanRectangleButtonPanel( + this@HoloSignScreen, + frame, + prop = menu.textAutoScale, + iconActive = Widgets18.TEXT_SCALE_ENABLED, + iconInactive = Widgets18.TEXT_SCALE_DISABLED, + tooltipActive = TranslatableComponent("otm.gui.holo_screen.resize_text"), + tooltipInactive = TranslatableComponent("otm.gui.holo_screen.do_not_resize_text"), + )) + + controls.addButton(LargeBooleanRectangleButtonPanel( + this@HoloSignScreen, + frame, + prop = menu.locked, + iconActive = Widgets18.LOCK_LOCKED, + iconInactive = Widgets18.LOCK_UNLOCKED, + tooltipActive = TranslatableComponent("otm.gui.lock_holo_screen"), + tooltipInactive = TranslatableComponent("otm.gui.lock_holo_screen.unlocked") + )) + return frame } } 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 bd78347a9..2515c8ad9 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 @@ -288,7 +288,7 @@ private class AndroidResearchButton( } override val cursorType: CursorType - get() = if (node.isAnyBlockerResearchedIndirect && !(parent?.screen as AndroidStationScreen).menu.player.isCreative) CursorType.NOT_ALLOWED else if (node.canResearch && !node.isResearched) CursorType.HAND else CursorType.ARROW + get() = if (node.isAnyBlockerResearchedIndirect && !(parent?.screen as AndroidStationScreen).menu.player.isCreative) CursorType.NOT_ALLOWED else if (node.readyToResearch && !node.isResearched) CursorType.HAND else CursorType.ARROW override fun innerRender(graphics: MGUIGraphics, mouseX: Float, mouseY: Float, partialTick: Float) { val hovered = screen.hoveredResearch @@ -303,7 +303,7 @@ private class AndroidResearchButton( AndroidStationScreen.RESEARCHED } else if (node.isAnyBlockerResearchedIndirect) { AndroidStationScreen.ALREADY_BLOCKED - } else if (node.canResearch) { + } else if (node.readyToResearch) { AndroidStationScreen.CAN_BE_RESEARCHED } else { AndroidStationScreen.CAN_NOT_BE_RESEARCHED @@ -388,7 +388,7 @@ private class AndroidResearchButton( override fun mouseClickedInner(x: Double, y: Double, button: Int): Boolean { if (button == InputConstants.MOUSE_BUTTON_LEFT && minecraft.player?.isSpectator != true) { - if (node.canResearch && !node.isResearched && (parent?.screen as AndroidStationScreen).menu.energyWidget.level >= MachinesConfig.AndroidStation.ENERGY_PER_RESEARCH) { + if (node.readyToResearch && !node.isResearched && (parent?.screen as AndroidStationScreen).menu.energyWidget.level >= MachinesConfig.AndroidStation.ENERGY_PER_RESEARCH) { if (node.type.flatBlocking.isNotEmpty()) { queryUser( TranslatableComponent("otm.android_station.research.confirm", node.type.displayName), @@ -420,14 +420,16 @@ private class AndroidResearchButton( if (node.isResearched) { list.add(TranslatableComponent("otm.android_station.research.researched").withStyle(ChatFormatting.DARK_AQUA)) - } else if (node.canResearch) { - list.add(TranslatableComponent("otm.android_station.research.can_be_researched").withStyle(ChatFormatting.DARK_GREEN)) - - if (!enoughPower) { - list.add(TranslatableComponent("otm.android_station.research.low_power").withStyle(ChatFormatting.DARK_RED)) - } } else { - list.add(TranslatableComponent("otm.android_station.research.can_not_be_researched").withStyle(ChatFormatting.DARK_RED)) + if (node.canResearch) { + if (node.canAfford) { + list.add(TranslatableComponent("otm.android_station.research.can_be_researched").withStyle(ChatFormatting.DARK_GREEN)) + } else { + list.add(TranslatableComponent("otm.android_station.research.can_not_afford").withStyle(ChatFormatting.DARK_RED)) + } + } else { + list.add(TranslatableComponent("otm.android_station.research.can_not_be_researched").withStyle(ChatFormatting.DARK_RED)) + } if (!enoughPower) { list.add(TranslatableComponent("otm.android_station.research.low_power").withStyle(ChatFormatting.DARK_RED)) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/item/tool/ExplosiveHammerItem.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/item/tool/ExplosiveHammerItem.kt index 8fcdb6015..72dc1cd38 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/item/tool/ExplosiveHammerItem.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/item/tool/ExplosiveHammerItem.kt @@ -86,17 +86,16 @@ class ExplosiveHammerItem(durability: Int = 512) : Item(Properties().stacksTo(1) val player = CommonHooks.getCraftingPlayer() ?: return itemStack.copy() if (player.level().isClientSide) return itemStack.copy() - if (!isPrimed(itemStack)) { - itemStack.hurtAndBreak(1, player.level() as ServerLevel, player) {} - } else { - val level = player.level() as ServerLevel + val level = player.level() as ServerLevel + itemStack.hurtAndBreak(8, level, player) {} - itemStack.hurtAndBreak(level.random.nextInt(1, 20), player.level() as ServerLevel, player) {} + if (isPrimed(itemStack)) { + itemStack.hurtAndBreak(level.random.nextInt(1, 20), level, player) {} unprime(itemStack) val (ex, ey, ez) = Vector.atCenterOf(player.blockPosition()) - val exp = Explosion(player.level(), player, ex, ey, ez, 1f, false, if (ToolsConfig.ExplosiveHammer.EXPLOSION_DAMAGE_BLOCKS) Explosion.BlockInteraction.DESTROY_WITH_DECAY else Explosion.BlockInteraction.KEEP) + val exp = Explosion(level, player, ex, ey, ez, 1f, false, if (ToolsConfig.ExplosiveHammer.EXPLOSION_DAMAGE_BLOCKS) Explosion.BlockInteraction.DESTROY_WITH_DECAY else Explosion.BlockInteraction.KEEP) exp.explode() exp.finalizeExplosion(true) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/decorative/HoloSignMenu.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/decorative/HoloSignMenu.kt index 87c55378e..2dd7ffa7c 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/decorative/HoloSignMenu.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/decorative/HoloSignMenu.kt @@ -24,6 +24,7 @@ class HoloSignMenu( val textGreen = FloatInputWithFeedback(this) val textBlue = FloatInputWithFeedback(this) val textAlpha = FloatInputWithFeedback(this) + val textAutoScale = BooleanInputWithFeedback(this) init { text.filter { it.isCreative || !locked.value } @@ -35,6 +36,8 @@ class HoloSignMenu( textBlue.filter { it.isCreative || !locked.value } textAlpha.filter { it.isCreative || !locked.value } + textAutoScale.filter { it.isCreative || !locked.value } + if (tile != null) { text.withConsumer { if (tile.isLocked) tile.signText = it else tile.signText = HoloSignBlockEntity.truncate(it) }.withSupplier(tile::signText) textRed.withConsumer { tile.textRed = it.coerceIn(0f, 1f) }.withSupplier(tile::textRed) @@ -43,6 +46,7 @@ class HoloSignMenu( textAlpha.withConsumer { tile.textAlpha = it.coerceIn(0f, 1f) }.withSupplier(tile::textAlpha) locked.with(tile::isLocked) redstone.with(tile.redstoneControl::redstoneSetting) + textAutoScale.with(tile::textAutoScale) } } } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/registry/CommandArgumentTypes.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/registry/CommandArgumentTypes.kt new file mode 100644 index 000000000..5c6e73824 --- /dev/null +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/registry/CommandArgumentTypes.kt @@ -0,0 +1,20 @@ +package ru.dbotthepony.mc.otm.registry + +import net.minecraft.commands.synchronization.ArgumentTypeInfo +import net.minecraft.commands.synchronization.ArgumentTypeInfos +import net.minecraft.commands.synchronization.SingletonArgumentInfo +import net.minecraft.core.registries.Registries +import net.neoforged.bus.api.IEventBus +import ru.dbotthepony.mc.otm.server.command.AndroidResearchArgument + +object CommandArgumentTypes { + private val registry: MDeferredRegister> = MDeferredRegister(Registries.COMMAND_ARGUMENT_TYPE) + + val ANDROID_RESEARCH by registry.register("android_research") { + ArgumentTypeInfos.registerByClass(AndroidResearchArgument::class.java, SingletonArgumentInfo.contextFree(AndroidResearchArgument.Companion::create)) + } + + fun register(bus: IEventBus) { + registry.register(bus) + } +} diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/server/MCommands.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/server/MCommands.kt new file mode 100644 index 000000000..8b911edb9 --- /dev/null +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/server/MCommands.kt @@ -0,0 +1,11 @@ +package ru.dbotthepony.mc.otm.server + +import net.neoforged.neoforge.event.RegisterCommandsEvent +import ru.dbotthepony.mc.otm.server.command.* + +object MCommands { + fun register(event: RegisterCommandsEvent) { + ExopackCommand.register(event) + AndroidCommand.register(event) + } +} diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/server/command/AndroidCommand.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/server/command/AndroidCommand.kt new file mode 100644 index 000000000..44a14eb34 --- /dev/null +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/server/command/AndroidCommand.kt @@ -0,0 +1,125 @@ +package ru.dbotthepony.mc.otm.server.command + +import net.minecraft.commands.Commands +import net.minecraft.commands.arguments.EntityArgument +import net.minecraft.world.entity.player.Player +import net.neoforged.neoforge.event.RegisterCommandsEvent +import ru.dbotthepony.mc.otm.android.AndroidResearchManager +import ru.dbotthepony.mc.otm.android.AndroidResearchType +import ru.dbotthepony.mc.otm.capability.matteryPlayer + +object AndroidCommand { + fun register(event: RegisterCommandsEvent) { + event.dispatcher.register( + Commands.literal("android") + .requires { it.hasPermission(Commands.LEVEL_GAMEMASTERS) } + .then(Commands.literal("on") + .executes { makeAndroid(listOf(it.source.playerOrException)) } + .then(Commands.argument("targets", EntityArgument.players()).executes { makeAndroid(EntityArgument.getPlayers(it, "targets")) }) + ) + .then(Commands.literal("off") + .executes { makeHuman(listOf(it.source.playerOrException)) } + .then(Commands.argument("targets", EntityArgument.players()).executes { makeHuman(EntityArgument.getPlayers(it, "targets")) }) + ) + .then( + Commands.literal("research") + .then( + Commands.literal("grant") + .then( + Commands.argument("targets", EntityArgument.players()) + .then( + Commands.argument("research", AndroidResearchArgument.create()) + .executes { + grantResearch(EntityArgument.getPlayers(it, "targets"), AndroidResearchArgument.getResearchType(it, "research")) + } + .then( + Commands.literal("force") + .executes { + grantResearch(EntityArgument.getPlayers(it, "targets"), AndroidResearchArgument.getResearchType(it, "research"), true) + } + ) + ) + .then( + Commands.literal("*") + .executes { + val players = EntityArgument.getPlayers(it, "targets") + AndroidResearchManager.researchMap.map { a -> a.value }.forEach { a -> + grantResearch(players, a) + } + + players.size + } + .then( + Commands.literal("force") + .executes { + val players = EntityArgument.getPlayers(it, "targets") + AndroidResearchManager.researchMap.map { a -> a.value }.forEach { a -> + grantResearch(players, a, true) + } + + players.size + } + ) + ) + ) + ) + .then( + Commands.literal("revoke") + .then( + Commands.argument("targets", EntityArgument.players()) + .then( + Commands.argument("research", AndroidResearchArgument.create()) + .executes { + revokeResearch(EntityArgument.getPlayers(it, "targets"), AndroidResearchArgument.getResearchType(it, "research")) + } + ) + .then( + Commands.literal("*") + .executes { + val players = EntityArgument.getPlayers(it, "targets") + AndroidResearchManager.researchMap.map { a -> a.value }.forEach { a -> + revokeResearch(players, a) + } + + players.size + } + ) + ) + + ) + ) + ) + } + + private fun grantResearch(players: Collection, type: AndroidResearchType, force: Boolean = false): Int { + for (player in players) { + player.matteryPlayer.getResearch(type).research(force, free = true) + } + + return players.size + } + + private fun revokeResearch(players: Collection, type: AndroidResearchType): Int { + for (player in players) { + player.matteryPlayer.getResearch(type).unResearch() + } + + return players.size + } + + private fun makeAndroid(players: Collection): Int { + for (player in players) { + player.matteryPlayer.becomeAndroid() + } + + return players.size + } + + private fun makeHuman(players: Collection): Int { + for (player in players) { + player.matteryPlayer.becomeHumane() + } + + return players.size + } +} diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/server/command/AndroidResearchArgument.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/server/command/AndroidResearchArgument.kt new file mode 100644 index 000000000..16b9cebde --- /dev/null +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/server/command/AndroidResearchArgument.kt @@ -0,0 +1,31 @@ +package ru.dbotthepony.mc.otm.server.command + +import com.mojang.brigadier.StringReader +import com.mojang.brigadier.arguments.ArgumentType +import com.mojang.brigadier.context.CommandContext +import com.mojang.brigadier.suggestion.Suggestions +import com.mojang.brigadier.suggestion.SuggestionsBuilder +import net.minecraft.commands.CommandSourceStack +import net.minecraft.commands.SharedSuggestionProvider +import net.minecraft.resources.ResourceLocation +import ru.dbotthepony.mc.otm.android.AndroidResearchManager +import ru.dbotthepony.mc.otm.android.AndroidResearchType +import java.util.concurrent.CompletableFuture + +class AndroidResearchArgument : ArgumentType { + override fun parse(reader: StringReader): AndroidResearchType { + return AndroidResearchManager[ResourceLocation.read(reader)] ?: throw NoSuchElementException() + } + + override fun listSuggestions(context: CommandContext, builder: SuggestionsBuilder): CompletableFuture { + return SharedSuggestionProvider.suggest(AndroidResearchManager.researchMap.map { it.key.toString() }, builder) + } + + companion object { + fun create(): AndroidResearchArgument = AndroidResearchArgument() + + fun getResearchType(context: CommandContext, name: String): AndroidResearchType { + return context.getArgument(name, AndroidResearchType::class.java) + } + } +} diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/server/command/ExopackCommand.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/server/command/ExopackCommand.kt new file mode 100644 index 000000000..943283326 --- /dev/null +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/server/command/ExopackCommand.kt @@ -0,0 +1,54 @@ +package ru.dbotthepony.mc.otm.server.command + +import net.minecraft.commands.Commands +import net.minecraft.commands.arguments.EntityArgument +import net.minecraft.world.entity.player.Player +import net.neoforged.neoforge.event.RegisterCommandsEvent +import net.neoforged.neoforge.server.command.EnumArgument +import ru.dbotthepony.mc.otm.capability.MatteryPlayer.UpgradeType +import ru.dbotthepony.mc.otm.capability.matteryPlayer + +object ExopackCommand { + fun register(event: RegisterCommandsEvent) { + event.dispatcher.register( + Commands.literal("exopack") + .requires { it.hasPermission(Commands.LEVEL_GAMEMASTERS) } + .then(Commands.literal("add") + .executes { setExoPack(listOf(it.source.playerOrException), true) } + .then(Commands.argument("targets", EntityArgument.players()).executes { setExoPack(EntityArgument.getPlayers(it, "targets"), true) }) + ) + .then(Commands.literal("remove") + .executes { setExoPack(listOf(it.source.playerOrException), false) } + .then(Commands.argument("targets", EntityArgument.players()).executes { setExoPack(EntityArgument.getPlayers(it, "targets"), false) }) + ) + .then(Commands.literal("upgrade") + .then(Commands.argument("type", EnumArgument.enumArgument(UpgradeType::class.java)) + .then(Commands.literal("add") + .executes { setUpgrade(listOf(it.source.playerOrException), it.getArgument("type", UpgradeType::class.java), true) } + .then(Commands.argument("targets", EntityArgument.players()).executes { setUpgrade( + EntityArgument.getPlayers(it, "targets"), it.getArgument("type", UpgradeType::class.java), true) })) + .then(Commands.literal("remove") + .executes { setUpgrade(listOf(it.source.playerOrException), it.getArgument("type", UpgradeType::class.java), false) } + .then(Commands.argument("targets", EntityArgument.players()).executes { setUpgrade( + EntityArgument.getPlayers(it, "targets"), it.getArgument("type", UpgradeType::class.java), false) }))) + ) + ) + } + + private fun setExoPack(players: Collection, hasExoPack: Boolean): Int { + for (player in players) { + player.matteryPlayer.hasExopack = hasExoPack + // player.matteryPlayer.recreateExoPackMenu() + } + + return players.size + } + + private fun setUpgrade(players: Collection, type: UpgradeType, state: Boolean): Int { + for (player in players) { + player.matteryPlayer.let { type.prop.set(it, state) } + } + + return players.size + } +} 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 41171ed83..f3e0a019d 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 cbd6a7acf..e04e31f4a 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 diff --git a/src/main/resources/data/overdrive_that_matters/structure/field_research_pod.nbt b/src/main/resources/data/overdrive_that_matters/structure/field_research_pod.nbt index 02c59e497..6de764a87 100644 Binary files a/src/main/resources/data/overdrive_that_matters/structure/field_research_pod.nbt and b/src/main/resources/data/overdrive_that_matters/structure/field_research_pod.nbt differ diff --git a/src/main/resources/data/overdrive_that_matters/structure/field_research_pod_ruin.nbt b/src/main/resources/data/overdrive_that_matters/structure/field_research_pod_ruin.nbt index c3c297d99..57947deee 100644 Binary files a/src/main/resources/data/overdrive_that_matters/structure/field_research_pod_ruin.nbt and b/src/main/resources/data/overdrive_that_matters/structure/field_research_pod_ruin.nbt differ diff --git a/src/main/resources/data/overdrive_that_matters/structure/laboratory/main/generator_room_0.nbt b/src/main/resources/data/overdrive_that_matters/structure/laboratory/main/generator_room_0.nbt index be5743718..b8a71e7ab 100644 Binary files a/src/main/resources/data/overdrive_that_matters/structure/laboratory/main/generator_room_0.nbt and b/src/main/resources/data/overdrive_that_matters/structure/laboratory/main/generator_room_0.nbt differ