- Версия(и) Minecraft
- 1.7.10
В разработке!
Achtung Kotlin!
В этом гайде мы будем делать простые и сложные машины, хранилища... Я постарался сделать как можно больше комментариев, поэтому в тексте их нет, если что-то не понятно, спрашивайте в теме.Achtung Kotlin!
I часть. Главный файл и зависимости.
Для начала нам нужно установить dev версию IC2. Заполним build.gradle.
Gradle (Groovy):
apply plugin: 'forge'
apply plugin: 'kotlin'
apply plugin: 'idea'
buildscript {
repositories {
mavenCentral()
maven {
name = "forge"
url = "https://maven.minecraftforge.net/"
}
maven {
name = "sonatype"
url = "https://oss.sonatype.org/content/repositories/snapshots/"
}
}
dependencies {
classpath ('com.anatawa12.forge:ForgeGradle:1.2-1.0.+') {
changing = true
}
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.5.10"
}
}
repositories {
mavenCentral()
maven {
name = "ic2"
url = "https://maven.ic2.player.to/"
metadataSources {
artifact()
}
}
}
version = "1.0"
archivesBaseName = "modid"
minecraft {
version = "1.7.10-10.13.4.1614-1.7.10"
runDir = "run"
}
dependencies {
implementation 'net.industrial-craft:industrialcraft-2:2.2.828-experimental:dev'
implementation 'org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.5.10'
}
jar {
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
exclude '**/*.kotlin_metadata'
exclude '**/*.kotlin_module'
exclude '**/*.kotlin_builtins'
}
idea {
module {
inheritOutputDirs = false
outputDir = file('build/classes/main/')
}
}
compileJava {
options.encoding = "UTF-8"
sourceCompatibility = targetCompatibility = '1.8'
}
gradle/wrapper/gradle-wrapper.properties
и меняем в distributionUrl
версию на 7.1.1После этого синхронизируем проект. Дальше нам нужен главный файл нашего аддона. Создадим и заполним его.
Kotlin:
import cpw.mods.fml.common.Mod
import cpw.mods.fml.common.event.FMLPreInitializationEvent
@Mod(modid = "ic2addon", name = "IC2 Addon", version = "0.0.1", dependencies = "required-after:IC2;")
class IC2Addon {
@Mod.EventHandler
fun preInit(e: FMLPreInitializationEvent) {
e.modLog.info("IC2 Addon PreInit")
}
}
II часть. Простые машины.
Создавать аддон без контента как-то не очень, поэтому мы добавим простых машин. Создадим файл для них. В IC2 используются блоки с метадатой. 0 - простой механизм, 1 - улучшенный механизм, 2-15 - машины(в случаем с первым уровнем). Наш файл должен наследоваться от BlockMultiID.
Kotlin:
import advancedmachines.TileEntityMy2SlotsMacerator
import cpw.mods.fml.common.registry.GameRegistry
import ic2.core.IC2
import ic2.core.block.BlockMultiID
import ic2.core.init.InternalName
import net.minecraft.block.Block
import net.minecraft.block.material.Material
import net.minecraft.item.ItemStack
import net.minecraft.tileentity.TileEntity
import net.minecraft.world.World
import org.apache.commons.lang3.mutable.MutableObject
import java.util.*
class MyMachine(internalName1: InternalName): BlockMultiID(internalName1, Material.iron, ItemMyMachine::class.java) {
init {
this.setHardness(2.0f) // Прочность
this.setStepSound(Block.soundTypeMetal) // Звук ходьбы
MyIC2Items.myMachine = ItemStack(this, 1, 0) // Инициализируем переменную. 1 параметр - класс, в нашем случае this, 2 параметр - количестно, ставим 1, 3 параметр - метадата, мин. 0, макс. 15
MyIC2Items.myMacerator = ItemStack(this, 1, 1) // Инициализируем переменную. 1 параметр - класс, в нашем случае this, 2 параметр - количестно, ставим 1, 3 параметр - метадата, мин. 0, макс. 15
MyIC2Items.myMacerator = ItemStack(this, 1, 2) // Инициализируем переменную. 1 параметр - класс, в нашем случае this, 2 параметр - количестно, ставим 1, 3 параметр - метадата, мин. 0, макс. 15
GameRegistry.registerTileEntity(TileEntityMyMacerator::class.java, "My Macerator") // Регестрируем тайл
GameRegistry.registerTileEntity(TileEntityMy2SlotsMacerator::class.java, "My 2 Slots Macerator") // Регестрируем тайл
}
public override fun getTextureFolder(id: Int): String = "myMachine" // Имя папки с текстурами. Путь - assets/ic2/textures/blocks/myMachine
override fun damageDropped(meta: Int): Int = when(meta) { // Мета предмета который сломан.
0 -> meta
1, 2 -> 0
else -> 0
}
override fun getTeClass(meta: Int, ctorArgTypes: MutableObject<Array<Class<*>>>?, ctorArgs: MutableObject<Array<Any>>?): Class<out TileEntity>? {
return when(meta) {
1 -> TileEntityMyMacerator::class.java // Возвращаем тайл энтити дробителя
2 -> TileEntityMy2SlotsMacerator::class.java // Возвращаем тайл энтити дробителя с двумя слотами
else -> null
}
}
override fun randomDisplayTick(world: World?, x: Int, y: Int, z: Int, random: Random?) { // Создаем партиклы
if(IC2.platform.isRendering) {
val meta = world!!.getBlockMetadata(x, y, z)
val f2: Float
var fmod: Float
var f1mod: Float
var f2mod: Float
if(meta == 1 && meta == 2 && this.isActive(world, x, y, z)) { // Для дробителя
val f = x.toFloat() + 1.0f
val f1 = y.toFloat() + 1.0f
f2 = z.toFloat() + 1.0f
for(i in 0..3) {
fmod = -0.2f - random!!.nextFloat() * 0.6f
f1mod = -0.1f + random.nextFloat() * 0.2f
f2mod = -0.2f - random.nextFloat() * 0.6f
world.spawnParticle("smoke", (f + fmod).toDouble(), (f1 + f1mod).toDouble(), (f2 + f2mod).toDouble(), 0.0, 0.0, 0.0)
}
}
}
}
// Дальше копипаст из класса индастриала
override fun hasComparatorInputOverride(): Boolean = false
}
Kotlin:
import cpw.mods.fml.relauncher.Side
import cpw.mods.fml.relauncher.SideOnly
import ic2.api.recipe.Recipes
import ic2.core.block.invslot.InvSlotProcessableGeneric
import ic2.core.block.machine.container.ContainerStandardMachine
import ic2.core.block.machine.tileentity.TileEntityStandardMachine
import ic2.core.upgrade.UpgradableProperty
import net.minecraft.client.gui.GuiScreen
import net.minecraft.entity.player.EntityPlayer
import java.util.*
// Ускоряем работу в 3 раза и увеличиваем потребление энергии за тик в 6 раз
class TileEntityMyMacerator: TileEntityStandardMachine(12, 100, 1) {
init {
this.inputSlot = InvSlotProcessableGeneric(this, "input", 0, 1, Recipes.macerator) // Указывай входной слот. Менять ничего не нужно, только Recipes.macerator на другой тип если надо
}
override fun getInventoryName(): String = "Macerator"
@SideOnly(Side.CLIENT)
override fun getGui(entityPlayer: EntityPlayer, isAdmin: Boolean): GuiScreen = GuiMyMacerator(ContainerStandardMachine(entityPlayer, this)) // GUI машины
override fun getStartSoundFile(): String = "Machines/MaceratorOp.ogg" // Звук начала работы
override fun getInterruptSoundFile(): String = "Machines/InterruptOne.ogg" // Звук работы
override fun getWrenchDropRate(): Float = 0.8f // Шанс успешного выпадения машины. Иначе падает механизм. От 0.0 до 1.0. 0.0 - 0%, 1.0 - 100%. За наводку спасибо Merisen
// Улучшения которые можно установить
override fun getUpgradableProperties(): Set<UpgradableProperty> = EnumSet.of(UpgradableProperty.Processing, UpgradableProperty.Transformer, UpgradableProperty.EnergyStorage, UpgradableProperty.ItemConsuming, UpgradableProperty.ItemProducing)
}
Kotlin:
import cpw.mods.fml.relauncher.Side
import cpw.mods.fml.relauncher.SideOnly
import ic2.core.GuiIC2
import ic2.core.IC2
import ic2.core.block.machine.container.ContainerStandardMachine
import net.minecraft.util.ResourceLocation
import net.minecraft.util.StatCollector
@SideOnly(Side.CLIENT)
class GuiMyMacerator(private val container: ContainerStandardMachine<out TileEntityMyMacerator>): GuiIC2(container) {
override fun drawGuiContainerBackgroundLayer(f: Float, x: Int, y: Int) { // Отрисовка прогресса и зарядки
super.drawGuiContainerBackgroundLayer(f, x, y)
val chargeLevel = (14.0f * (this.container.base as TileEntityMyMacerator).chargeLevel).toInt()
val progress = (24.0f * (this.container.base as TileEntityMyMacerator).progress).toInt()
if(chargeLevel > 0)
this.drawTexturedModalRect(this.xoffset + 56, this.yoffset + 36 + 14 - chargeLevel, 176, 14 - chargeLevel, 14, chargeLevel)
if(progress > 0)
this.drawTexturedModalRect(this.xoffset + 79, this.yoffset + 34, 176, 14, progress + 1, 16)
}
override fun getName(): String = StatCollector.translateToLocal("ic2.Macerator.gui.name") // Текст в гуи(название)
override fun getResourceLocation(): ResourceLocation = ResourceLocation(IC2.textureDomain, "textures/gui/GUIMacerator.png") // Путь до текстуры. Использую стандартну.
}
В классе MyMachine есть какой-то ItemMyMachine. Это - предмет для блоков. Создадим его.
Kotlin:
import ic2.core.item.block.ItemBlockIC2
import net.minecraft.block.Block
import net.minecraft.entity.player.EntityPlayer
import net.minecraft.item.ItemStack
import net.minecraft.util.StatCollector
class ItemMyMachine(block: Block): ItemBlockIC2(block) {
init {
this.maxDamage = 0
this.setHasSubtypes(true)
}
override fun getMetadata(i: Int): Int = i
override fun getUnlocalizedName(itemstack: ItemStack): String? { //Нелокализованное имя. ic2 советую оставить
val meta = itemstack.itemDamage
return when(meta) {
0 -> "ic2.blockMyMachine"
1 -> "ic2.blockMyMacerator"
else -> null
}
}
override fun addInformation(itemStack: ItemStack, player: EntityPlayer, info: MutableList<Any?>, b: Boolean) {
val meta = itemStack.itemDamage
when(meta) {
// Добавляем описание.
1 -> info.add(StatCollector.translateToLocal("ic2.item.tooltip.power") + " 3 EU/t, 32 EU/t " + StatCollector.translateToLocal("ic2.item.tooltip.max"))
else -> {
}
}
}
}
Kotlin:
import net.minecraft.item.ItemStack
object MyIC2Items {
lateinit var myMachine: ItemStack //Механизм
lateinit var myMacerator: ItemStack //Дробитель
}
MyMachine(InternalName.blockMachine)
Теперь он выглядит так
Kotlin:
import cpw.mods.fml.common.Mod
import cpw.mods.fml.common.event.FMLPreInitializationEvent
import ic2.core.init.InternalName
@Mod(modid = "ic2addon", name = "IC2 Addon", version = "0.0.1", dependencies = "required-after:IC2;")
class IC2Addon {
@Mod.EventHandler
fun preInit(e: FMLPreInitializationEvent) {
e.modLog.info("IC2 Addon PreInit")
MyMachine(InternalName.blockMachine)
}
}
Результат:
III часть. Сложные машины.
Настанет время, когда TileEntityStandardMachine уже не будет хватать. Например, вы захотите добавить слотов. Для этого нам потребуется создать немного другой механизм. Создадим для него пакет, а в нем тайл.
Kotlin:
package advancedmachines
import cpw.mods.fml.relauncher.Side
import cpw.mods.fml.relauncher.SideOnly
import ic2.api.recipe.Recipes
import ic2.core.ContainerBase
import ic2.core.IC2
import ic2.core.IHasGui
import ic2.core.block.invslot.*
import ic2.core.block.machine.tileentity.TileEntityElectricMachine
import ic2.core.upgrade.IUpgradableBlock
import ic2.core.upgrade.IUpgradeItem
import ic2.core.upgrade.UpgradableProperty
import net.minecraft.client.gui.GuiScreen
import net.minecraft.entity.player.EntityPlayer
import net.minecraft.nbt.NBTTagCompound
import java.util.*
// Аргументы для конструктора TileEntityElectricMachine. 1 - максимальное количество энергии, 2 - уровень машины
class TileEntityMy2SlotsMacerator: TileEntityElectricMachine(256000, 2, 2), IHasGui, IUpgradableBlock {
private var progress: Short = 0
val inputSlotA: InvSlotProcessable
val inputSlotB: InvSlotProcessable
val outputSlotA: InvSlotOutput
val outputSlotB: InvSlotOutput
val upgradeSlot: InvSlotUpgrade
init {
// Если хотите добавить еще слотов, создаете еще переменные, но при инициализации третий аргумент должен быть на один больше предыдущего, это - индекс.
this.inputSlotA = InvSlotProcessableGeneric(this, "inputA", 0, 1, Recipes.macerator) // Первый входной слот
this.inputSlotB = InvSlotProcessableGeneric(this, "inputB", 1, 1, Recipes.macerator) // Второй входной слот
this.outputSlotA = InvSlotOutput(this, "outputA", 3, 1) // Первый выходной слот
this.outputSlotB = InvSlotOutput(this, "outputB", 4, 1) // Второй выходной слот
this.upgradeSlot = InvSlotUpgrade(this, "upgrade", 5, 2) // Слот для улучшения. Обратите внимание на последний аргумент. Это - количество слотов.
}
override fun getInventoryName(): String = if(IC2.platform.isRendering) "My 2 Slots Macerator" else "My2SlotsMacerator" // Имя инвентаря
override fun getWrenchDropRate(): Float = 0.80f // Шанс успешного выбадения машины. Иначе падает механизм. От 0.0 до 1.0. 0.0 - 0%, 1.0 - 100%. За наводку спасибо Merisen
override fun getGuiContainer(entityPlayer: EntityPlayer): ContainerBase<TileEntityMy2SlotsMacerator> = ContainerMy2SlotsMacerator(entityPlayer, this) // Указываем контейнер
@SideOnly(Side.CLIENT)override fun getGui(entityPlayer: EntityPlayer, isAdmin: Boolean): GuiScreen = GuiMy2SlotsMacerator(ContainerMy2SlotsMacerator(entityPlayer, this)) // Указываем GUI
// Чтение прогресса из NBT
override fun readFromNBT(nbttagcompound: NBTTagCompound) {
super.readFromNBT(nbttagcompound)
this.progress = nbttagcompound.getShort("progress")
}
// Запись прогресса в NBT
override fun writeToNBT(nbttagcompound: NBTTagCompound) {
super.writeToNBT(nbttagcompound)
nbttagcompound.setShort("progress", this.progress)
}
fun gaugeProgressScaled(i: Int): Int = i * this.progress / 4000 // Прогресс
// Цикл для работы.
override fun updateEntityServer() {
super.updateEntityServer()
var needsInvUpdate = false
var newActive = this.active
if(this.progress >= 4000) { // 4000 - максимальный прогресс, если хотите сдеалть работу быстрее или медленнее уменьшаете или увеличиваете соответственно.
this.operate()
needsInvUpdate = true
this.progress = 0
newActive = false
}
val canOperate = this.canOperate()
if(this.energy > 0.0 && canOperate) {
--this.energy
newActive = true
}
if(newActive && this.progress.toInt() != 0) {
if(!canOperate || this.energy < 15.0) {
if(!canOperate) {
this.progress = 0
}
newActive = false
}
} else if(canOperate) {
if(this.energy >= 15.0) {
newActive = true
}
} else {
this.progress = 0
}
if(newActive && canOperate) {
this.progress = (this.progress + 300).toShort() // Работа. Если хотите сдеалть работу быстрее или медленнее увеличиваете или уменьшаете соответственно
this.energy -= 256.0 // Потребление энергии за тик
}
if(needsInvUpdate) {
this.markDirty()
}
if(newActive != this.active) {
this.active = newActive
}
for(i in 0 until this.upgradeSlot.size()) {
val stack = this.upgradeSlot.get(i)
if(stack != null && stack.item is IUpgradeItem && (stack.item as IUpgradeItem).onTick(stack, this)) {
super.markDirty()
}
}
}
// Работа со слотами. Забираем из входного, помещаем в выходной
private fun operate() {
this.operate(this.inputSlotA, this.outputSlotA)
this.operate(this.inputSlotB, this.outputSlotB)
}
private fun operate(inputSlot: InvSlotProcessable, outputSlot: InvSlotOutput) {
if(this.canOperate(inputSlot, outputSlot)) {
outputSlot.add(inputSlot.process().items)
inputSlot.consume()
}
}
// Можно ли положить предмет в выходной слот или забрать из входного.
private fun canOperate(): Boolean = this.canOperate(this.inputSlotA, this.outputSlotA) || this.canOperate(this.inputSlotB, this.outputSlotB)
private fun canOperate(inputSlot: InvSlotProcessable, outputSlot: InvSlotOutput): Boolean = if(inputSlot.isEmpty) { false } else { val output = inputSlot.process(); if(output == null) false else outputSlot.canAdd(output.items) }
override fun onGuiClosed(entityPlayer: EntityPlayer) {} // Действие при закрытии GUI. Можно оставить пустым
override fun getEnergy(): Double = this.energy // Получаем энергию в машине
override fun useEnergy(amount: Double): Boolean = if(this.energy >= amount) { this.energy -= amount; true } else { false } // Используем энергию. Если true, то энергии хватает, иначе не хватает
override fun getUpgradableProperties(): Set<UpgradableProperty> = EnumSet.of(UpgradableProperty.RedstoneSensitive, UpgradableProperty.ItemConsuming, UpgradableProperty.ItemProducing) // Улучшения которые можно установить
}
Kotlin:
package advancedmachines
import cpw.mods.fml.relauncher.Side
import cpw.mods.fml.relauncher.SideOnly
import ic2.core.GuiIC2
import ic2.core.IC2
import net.minecraft.util.ResourceLocation
import net.minecraft.util.StatCollector
@SideOnly(Side.CLIENT)
class GuiMy2SlotsMacerator(container1: ContainerMy2SlotsMacerator): GuiIC2(container1) {
override fun drawGuiContainerBackgroundLayer(f: Float, x: Int, y: Int) { // Рисуем зарядку и прогресс
super.drawGuiContainerBackgroundLayer(f, x, y)
val chargeLevel = Math.round((this.container.base as TileEntityMy2SlotsMacerator).chargeLevel * 14.0f)
this.drawTexturedModalRect(this.xoffset + 56, this.yoffset + 36 + 14 - chargeLevel, 176, 14 - chargeLevel, 14, chargeLevel)
val i1 = (this.container.base as TileEntityMy2SlotsMacerator).gaugeProgressScaled(24)
this.drawTexturedModalRect(this.xoffset + 79, this.yoffset + 34, 176, 14, i1 + 1, 16)
}
override fun getName(): String = StatCollector.translateToLocal("myic2addon.My2SlotsMachine.gui.name") // Имя в GUI
override fun getResourceLocation(): ResourceLocation = ResourceLocation(IC2.textureDomain, "textures/gui/GUIInduction.png") // Текстура. Используем индукционку для двух слотов.
}
Kotlin:
package advancedmachines
import ic2.core.block.machine.container.ContainerElectricMachine
import ic2.core.slot.SlotInvSlot
import net.minecraft.entity.player.EntityPlayer
class ContainerMy2SlotsMacerator(entityPlayer: EntityPlayer, tileEntity: TileEntityMy2SlotsMacerator): ContainerElectricMachine<TileEntityMy2SlotsMacerator>(entityPlayer, tileEntity, 166, 56, 53) {
init {
// Добавляем слоты в контейнер
this.addSlotToContainer(SlotInvSlot(tileEntity.inputSlotA, 0, 47, 17))
this.addSlotToContainer(SlotInvSlot(tileEntity.inputSlotB, 0, 63, 17))
this.addSlotToContainer(SlotInvSlot(tileEntity.outputSlotA, 0, 113, 35))
this.addSlotToContainer(SlotInvSlot(tileEntity.outputSlotB, 0, 131, 35))
for(i in 0..1) {
this.addSlotToContainer(SlotInvSlot(tileEntity.upgradeSlot, i, 153, 26 + i * 18))
}
}
// Сетевые переменные. Что бы другие игроки видели прогресс
override fun getNetworkedFields(): List<String> {
val ret = super.getNetworkedFields()
ret.add("progress")
return ret
}
}
Дальше нам осталось добавить его в класс с машинами. Теперь MyMachine выглядит так:
Kotlin:
import advancedmachines.TileEntityMy2SlotsMacerator
import cpw.mods.fml.common.registry.GameRegistry
import ic2.api.item.ITerraformingBP
import ic2.core.IC2
import ic2.core.block.BlockMultiID
import ic2.core.block.TileEntityBlock
import ic2.core.block.machine.tileentity.*
import ic2.core.init.InternalName
import net.minecraft.block.Block
import net.minecraft.block.material.Material
import net.minecraft.entity.player.EntityPlayer
import net.minecraft.item.ItemStack
import net.minecraft.tileentity.TileEntity
import net.minecraft.world.World
import org.apache.commons.lang3.mutable.MutableObject
import java.util.*
class MyMachine(internalName1: InternalName): BlockMultiID(internalName1, Material.iron, ItemMyMachine::class.java) {
init {
this.setHardness(2.0f) // Прочность
this.setStepSound(Block.soundTypeMetal) // Звук ходьбы
MyIC2Items.myMachine = ItemStack(this, 1, 0) // Инициализируем переменную. 1 параметр - класс, в нашем случае this, 2 параметр - количестно, ставим 1, 3 параметр - метадата, мин. 0, макс. 15
MyIC2Items.myMacerator = ItemStack(this, 1, 1) // Инициализируем переменную. 1 параметр - класс, в нашем случае this, 2 параметр - количестно, ставим 1, 3 параметр - метадата, мин. 0, макс. 15
MyIC2Items.myMacerator = ItemStack(this, 1, 2) // Инициализируем переменную. 1 параметр - класс, в нашем случае this, 2 параметр - количестно, ставим 1, 3 параметр - метадата, мин. 0, макс. 15
GameRegistry.registerTileEntity(TileEntityMyMacerator::class.java, "My Macerator") // Регестрируем тайл
GameRegistry.registerTileEntity(TileEntityMy2SlotsMacerator::class.java, "My 2 Slots Macerator") // Регестрируем тайл
}
public override fun getTextureFolder(id: Int): String = "myMachine" // Имя папки с текстурами. Путь - assets/ic2/textures/blocks/myMachine
override fun damageDropped(meta: Int): Int = meta // Мета предмета
override fun getTeClass(meta: Int, ctorArgTypes: MutableObject<Array<Class<*>>>?, ctorArgs: MutableObject<Array<Any>>?): Class<out TileEntity>? {
return when(meta) {
1 -> TileEntityMyMacerator::class.java // Возвращаем тайл энтити
2 -> TileEntityMy2SlotsMacerator::class.java // Возвращаем тайл энтити
else -> null
}
}
override fun randomDisplayTick(world: World?, x: Int, y: Int, z: Int, random: Random?) { // Создаем партиклы
if(IC2.platform.isRendering) {
val meta = world!!.getBlockMetadata(x, y, z)
val f2: Float
var fmod: Float
var f1mod: Float
var f2mod: Float
if(meta == 1 && meta == 2 && this.isActive(world, x, y, z)) { // Для дробителя
val f = x.toFloat() + 1.0f
val f1 = y.toFloat() + 1.0f
f2 = z.toFloat() + 1.0f
for(i in 0..3) {
fmod = -0.2f - random!!.nextFloat() * 0.6f
f1mod = -0.1f + random.nextFloat() * 0.2f
f2mod = -0.2f - random.nextFloat() * 0.6f
world.spawnParticle("smoke", (f + fmod).toDouble(), (f1 + f1mod).toDouble(), (f2 + f2mod).toDouble(), 0.0, 0.0, 0.0)
}
}
}
}
// Дальше копипаст из ванильного класса
override fun hasComparatorInputOverride(): Boolean {
return true
}
override fun getComparatorInputOverride(world: World?, x: Int, y: Int, z: Int, side: Int): Int {
val te = this.getOwnTe(world!!, x, y, z) as TileEntityBlock
return when(te) {
is TileEntityInduction -> Math.floor((te.heat.toFloat() / TileEntityInduction.maxHeat.toFloat() * 15.0f).toDouble()).toInt()
is TileEntityMatter -> Math.floor(te.energy / 1000000.0 * 15.0).toInt()
is TileEntityElectrolyzer -> Math.floor((te.energy.toFloat() / 20000.0f * 15.0f).toDouble()).toInt()
is TileEntityStandardMachine -> Math.floor((te.progress * 15.0f).toDouble()).toInt()
else -> 0
}
}
override fun onBlockActivated(world: World?, x: Int, y: Int, z: Int, player: EntityPlayer, side: Int, hitX: Float, hitY: Float, hitZ: Float): Boolean {
if(world!!.getBlockMetadata(x, y, z) == 15) {
when {
player.isSneaking -> return false
world.isRemote -> return true
else -> {
val te = world.getTileEntity(x, y, z) as TileEntityTerra
return when {
player.inventory.getCurrentItem() == null -> {
te.ejectBlueprint()
true
}
player.inventory.getCurrentItem().item is ITerraformingBP -> {
te.insertBlueprint(player.inventory.getCurrentItem().copy())
--player.inventory.getCurrentItem().stackSize
true
}
else -> false
}
}
}
} else {
return super.onBlockActivated(world, x, y, z, player, side, hitX, hitY, hitZ)
}
}
}
Kotlin:
import ic2.core.item.block.ItemBlockIC2
import net.minecraft.block.Block
import net.minecraft.entity.player.EntityPlayer
import net.minecraft.item.ItemStack
import net.minecraft.util.StatCollector
class ItemMyMachine(block: Block): ItemBlockIC2(block) {
init {
this.maxDamage = 0
this.setHasSubtypes(true)
}
override fun getMetadata(i: Int): Int = i
override fun getUnlocalizedName(itemstack: ItemStack): String? { //Нелокализованное имя. ic2 советую оставить
val meta = itemstack.itemDamage
return when(meta) {
0 -> "ic2.blockMyMachine"
1 -> "ic2.blockMyMacerator"
2 -> "ic2.blockMy2SlotsMacerator"
else -> null
}
}
override fun addInformation(itemStack: ItemStack, player: EntityPlayer, info: MutableList<Any?>, b: Boolean) {
val meta = itemStack.itemDamage
when(meta) {
// Добавляем описание.
1 -> info.add(StatCollector.translateToLocal("ic2.item.tooltip.power") + " 12 EU/t, 32 EU/t " + StatCollector.translateToLocal("ic2.item.tooltip.max"))
2 -> info.add(StatCollector.translateToLocal("ic2.item.tooltip.power") + " 256 EU/t, 32 EU/t " + StatCollector.translateToLocal("ic2.item.tooltip.max"))
else -> {
}
}
}
}
Но что это? У нас стрелка вместо дробителя. Для этого надо немного изменить текстуру и поменять путь в GUI. Сделаем это!
Кладем текстуру по пути
assets/ic2/textures/gui
И теперь все хорошо.
Так же установим текстуру и локализуем.
Вот такая текстура. Кладем текстуру по пути
assets/ic2/textures/blocks/myMachine
Осталось локализовать.
Код:
myic2addon.My2SlotsMachine.gui.name=My 2 slots Macerator
ic2.blockMy2SlotsMacerator=My 2 slots Macerator
assets/modid/lang
Результат:
Вы можете добавить больше 2 слотов. Я максимум я добавлял 4.
IV часть. Свое хранилище энергии.
Для начала создадим файл с хранилищами.
Kotlin:
package wiring
import MyIC2Items
import cpw.mods.fml.common.registry.GameRegistry
import ic2.core.IC2
import ic2.core.Ic2Items
import ic2.core.block.BlockMultiID
import ic2.core.block.TileEntityBlock
import ic2.core.block.wiring.TileEntityElectricBlock
import ic2.core.init.InternalName
import ic2.core.init.MainConfig
import ic2.core.util.ConfigUtil
import ic2.core.util.StackUtil
import ic2.core.util.Util
import net.minecraft.block.Block
import net.minecraft.block.material.Material
import net.minecraft.entity.EntityLivingBase
import net.minecraft.item.Item
import net.minecraft.item.ItemStack
import net.minecraft.tileentity.TileEntity
import net.minecraft.util.MathHelper
import net.minecraft.world.IBlockAccess
import net.minecraft.world.World
import org.apache.commons.lang3.mutable.MutableObject
import java.util.*
class MyBlockElectric(internalName1: InternalName): BlockMultiID(internalName1, Material.iron, MyItemElectricBlock::class.java) {
init {
// Уже знакомая конструкция
this.setHardness(1.5f)
this.setStepSound(Block.soundTypeMetal)
MyIC2Items.smallEnergyStorage = ItemStack(this, 1, 0)
MyIC2Items.bigEnergyStorage = ItemStack(this, 1, 1)
GameRegistry.registerTileEntity(TilEntityElectricSmallEnergyStorage::class.java, "Small Energy Storage")
GameRegistry.registerTileEntity(TilEntityElectricBigEnergyStorage::class.java, "Big Energy Storage")
}
override fun getTextureFolder(id: Int): String = "wiring" // Имя папки с текстурой
override fun getTeClass(meta: Int, ctorArgTypes: MutableObject<Array<Class<*>>>?, ctorArgs: MutableObject<Array<Any>>?): Class<out TileEntity>? {
return when(meta) {
0 -> TilEntityElectricSmallEnergyStorage::class.java
1 -> TilEntityElectricBigEnergyStorage::class.java
else -> null
}
}
// Дальше копипаст из класса индастриала
override fun getItemDropped(meta: Int, random: Random?, fortune: Int): Item {
return if(ConfigUtil.getBool(MainConfig.get(), "balance/ignoreWrenchRequirement")) {
Item.getItemFromBlock(this)
} else {
when(meta) {
0, 3 -> Item.getItemFromBlock(this)
else -> Ic2Items.machine.item
}
}
}
override fun damageDropped(meta: Int): Int {
return if(ConfigUtil.getBool(MainConfig.get(), "balance/ignoreWrenchRequirement")) {
meta
} else {
when(meta) {
0, 3 -> meta
else -> Ic2Items.machine.itemDamage
}
}
}
override fun quantityDropped(random: Random?): Int = 1
override fun isProvidingWeakPower(blockAccess: IBlockAccess?, x: Int, y: Int, z: Int, side: Int): Int {
val te = this.getOwnTe(blockAccess!!, x, y, z) as TileEntityBlock
return if(te !is TileEntityElectricBlock) {
0
} else {
if(te.isEmittingRedstone) 15 else 0
}
}
override fun canProvidePower(): Boolean = true
override fun isNormalCube(world: IBlockAccess?, i: Int, j: Int, k: Int): Boolean = true
override fun isBlockSolid(world: IBlockAccess, x: Int, y: Int, z: Int, side: Int): Boolean = true
override fun onBlockPlacedBy(world: World?, x: Int, y: Int, z: Int, entityliving: EntityLivingBase?, itemStack: ItemStack?) {
if(IC2.platform.isSimulating) {
val te = this.getOwnTe(world!!, x, y, z) as TileEntityBlock
if(te is TileEntityElectricBlock) {
val nbttagcompound = StackUtil.getOrCreateNbtData(itemStack!!)
te.energy = nbttagcompound.getDouble("energy")
}
if(entityliving == null) {
te.facing = 1.toShort()
} else {
val yaw = MathHelper.floor_double((entityliving.rotationYaw * 4.0f / 360.0f).toDouble() + 0.5) and 3
val pitch = Math.round(entityliving.rotationPitch)
when {
pitch >= 65 -> te.facing = 1.toShort()
pitch <= -65 -> te.facing = 0.toShort()
else -> when(yaw) {
0 -> te.facing = 2.toShort()
1 -> te.facing = 5.toShort()
2 -> te.facing = 3.toShort()
3 -> te.facing = 4.toShort()
}
}
}
}
}
override fun hasComparatorInputOverride(): Boolean = true
override fun getComparatorInputOverride(world: World?, x: Int, y: Int, z: Int, side: Int): Int {
val te = this.getOwnTe(world!!, x, y, z) as TileEntityBlock
val teb = te as TileEntityElectricBlock
return Math.round(Util.map(teb.energy, teb.maxStorage.toDouble(), 15.0)).toInt()
}
}
Первый:
Kotlin:
package wiring
import ic2.core.block.wiring.ContainerElectricBlock
import ic2.core.block.wiring.TileEntityElectricBlock
import net.minecraft.client.gui.GuiScreen
import net.minecraft.entity.player.EntityPlayer
// Аргументы TileEntityElectricBlock. 1 - уровень, 2 - выходное напряжение(EU/t), 3 - максимальное количество энергии
class TilEntityElectricSmallEnergyStorage: TileEntityElectricBlock(5, 4096, 1000000000) {
override fun getInventoryName(): String = "SES"
override fun getGui(entityPlayer: EntityPlayer?, isAdmin: Boolean): GuiScreen = GuiMyElectricBlock(ContainerElectricBlock(entityPlayer, this))
}
Kotlin:
package wiring
import ic2.core.block.wiring.ContainerElectricBlock
import ic2.core.block.wiring.TileEntityElectricBlock
import net.minecraft.client.gui.GuiScreen
import net.minecraft.entity.player.EntityPlayer
// Аргументы TileEntityElectricBlock. 1 - уровень, 2 - выходное напряжение(EU/t), 3 - максимальное количество энергии
class TilEntityElectricBigEnergyStorage: TileEntityElectricBlock(6, 8192, 2000000000) {
override fun getInventoryName(): String = "BES"
override fun getGui(entityPlayer: EntityPlayer?, isAdmin: Boolean): GuiScreen = GuiMyElectricBlock(ContainerElectricBlock(entityPlayer, this))
}
Kotlin:
package wiring
import ic2.core.GuiIconButton
import ic2.core.IC2
import ic2.core.block.wiring.ContainerElectricBlock
import ic2.core.block.wiring.TileEntityChargepadBlock
import ic2.core.block.wiring.TileEntityElectricBlock
import ic2.core.network.NetworkManager
import ic2.core.util.GuiTooltipHelper
import net.minecraft.client.gui.GuiButton
import net.minecraft.client.gui.inventory.GuiContainer
import net.minecraft.init.Items
import net.minecraft.item.ItemStack
import net.minecraft.tileentity.TileEntity
import net.minecraft.util.ResourceLocation
import net.minecraft.util.StatCollector
import org.lwjgl.opengl.GL11
class GuiMyElectricBlock(container1: ContainerElectricBlock): GuiContainer(container1) {
private val container: ContainerElectricBlock
private val armorInv: String
private val level: String
private val name: String?
private var background = ResourceLocation(IC2.textureDomain, "textures/gui/GUIElectricBlock.png") // Путь до текстуры
init {
this.ySize = 196
this.container = container1
this.armorInv = StatCollector.translateToLocal("ic2.EUStorage.gui.info.armor")
this.level = StatCollector.translateToLocal("ic2.EUStorage.gui.info.level")
when((container1.base as TileEntityElectricBlock).tier) {
5 -> this.name = StatCollector.translateToLocal("myic2addon.ses.gui.name") // Имя GUI(название)
6 -> this.name = StatCollector.translateToLocal("myic2addon.bes.gui.name") // Имя GUI(название)
else -> this.name = "Untitled"
}
}
// Все что дальше нам не нужно
override fun initGui() {
super.initGui()
this.buttonList.add(GuiIconButton(0, (this.width - this.xSize) / 2 + 152, (this.height - this.ySize) / 2 + 4, 20, 20, ItemStack(Items.redstone), true))
}
override fun drawGuiContainerForegroundLayer(par1: Int, par2: Int) {
this.fontRendererObj.drawString(this.name, (this.xSize - this.fontRendererObj.getStringWidth(this.name)) / 2, 6, 4210752)
this.fontRendererObj.drawString(this.armorInv, 8, this.ySize - 126 + 3, 4210752)
this.fontRendererObj.drawString(this.level, 79, 25, 4210752)
val e = Math.min((this.container.base as TileEntityElectricBlock).energy, (this.container.base as TileEntityElectricBlock).maxStorage.toDouble()).toInt()
this.fontRendererObj.drawString(" $e", 110, 35, 4210752)
this.fontRendererObj.drawString("/" + (this.container.base as TileEntityElectricBlock).maxStorage, 110, 45, 4210752)
val output = StatCollector.translateToLocalFormatted("ic2.EUStorage.gui.info.output", (this.container.base as TileEntityElectricBlock).output)
this.fontRendererObj.drawString(output, 85, 60, 4210752)
GuiTooltipHelper.drawAreaTooltip(par1 - this.guiLeft, par2 - this.guiTop, (this.container.base as TileEntityElectricBlock).getredstoneMode(), 153, 3, 172, 22)
}
override fun drawGuiContainerBackgroundLayer(f: Float, x: Int, y: Int) {
GL11.glColor4f(1.0f, 1.0f, 1.0f, 1.0f)
this.mc.textureManager.bindTexture(background)
val j = (this.width - this.xSize) / 2
val k = (this.height - this.ySize) / 2
this.drawTexturedModalRect(j, k, 0, 0, this.xSize, this.ySize)
if((this.container.base as TileEntityElectricBlock).energy > 0.0) {
val i1 = (24.0f * (this.container.base as TileEntityElectricBlock).chargeLevel).toInt()
this.drawTexturedModalRect(j + 79, k + 34, 176, 14, i1 + 1, 16)
}
}
override fun actionPerformed(guibutton: GuiButton?) {
super.actionPerformed(guibutton)
if(guibutton!!.id == 0) {
(IC2.network.get() as NetworkManager).initiateClientTileEntityEvent(this.container.base as TileEntity, 0)
}
}
}
Kotlin:
package wiring
import MyIC2Items
import cpw.mods.fml.relauncher.Side
import cpw.mods.fml.relauncher.SideOnly
import ic2.core.item.block.ItemBlockIC2
import ic2.core.util.StackUtil
import net.minecraft.block.Block
import net.minecraft.creativetab.CreativeTabs
import net.minecraft.entity.player.EntityPlayer
import net.minecraft.item.Item
import net.minecraft.item.ItemStack
import net.minecraft.util.StatCollector
class MyItemElectricBlock(block: Block): ItemBlockIC2(block) {
init {
this.maxDamage = 0
this.setHasSubtypes(true)
this.setMaxStackSize(1)
}
override fun getMetadata(i: Int): Int = i
override fun getUnlocalizedName(itemstack: ItemStack?): String? {
val meta = itemstack!!.itemDamage
return when(meta) {
0 -> "ic2.blockSES"
1 -> "ic2.blockBES"
else -> null
}
}
// Добавляем описание
override fun addInformation(itemStack: ItemStack?, player: EntityPlayer?, info: MutableList<Any?>, b: Boolean) {
val meta = itemStack!!.itemDamage
when(meta) {
0 -> info.add(StatCollector.translateToLocal("ic2.item.tooltip.Output") + " 4096EU/t " + StatCollector.translateToLocal("ic2.item.tooltip.Capacity") + " 1b EU ")
1 -> info.add(StatCollector.translateToLocal("ic2.item.tooltip.Output") + " 8192EU/t " + StatCollector.translateToLocal("ic2.item.tooltip.Capacity") + " 2b EU")
}
when(meta) {
0, 1 -> {
val nbttagcompound = StackUtil.getOrCreateNbtData(itemStack)
info.add(StatCollector.translateToLocal("ic2.item.tooltip.Store") + " " + nbttagcompound.getInteger("energy") + " EU")
}
}
}
@SideOnly(Side.CLIENT)
override fun getSubItems(item: Item, par2CreativeTabs: CreativeTabs?, itemList: MutableList<Any?>) {
itemList.add(MyIC2Items.smallEnergyStorage) // Добавляем просто хранилища
itemList.add(MyIC2Items.bigEnergyStorage) // Добавляем просто хранилища
// Добавляем заполненые хранилища
var itemStack = ItemStack(MyIC2Items.smallEnergyStorage.item, 1) // Инициализируем айтем стак
itemStack.itemDamage = 0 // Ставим мету
var nbttagcompound = StackUtil.getOrCreateNbtData(itemStack) // Инициализируем НБТ
nbttagcompound.setDouble("energy", 1000000000.0) // Устанавливем энергию
itemList.add(itemStack) // Добавляем
itemStack = ItemStack(MyIC2Items.bigEnergyStorage.item, 1)
itemStack.itemDamage = 1
nbttagcompound = StackUtil.getOrCreateNbtData(itemStack)
nbttagcompound.setDouble("energy", 2000000000.0)
itemList.add(itemStack)
}
}
MyIC2Items:
Kotlin:
lateinit var smallEnergyStorage: ItemStack // Маленькое энергохранилище
lateinit var bigEnergyStorage: ItemStack // Большое энерго хранилище
MyBlockElectric(InternalName.blockElectric)
Устанавливаем текстуру и локализуем. Результат:
На скриншотах только маленькое хранилище на 1ККК энергии. Но большое на 2ККК такое же.
Как насчет добавить хранилище с зарядной пластиной? Давайте сделаем это.
Так же создаем класс с хранилищами.
Kotlin:
package wiring
import MyIC2Items
import cpw.mods.fml.common.registry.GameRegistry
import ic2.core.IC2
import ic2.core.block.BlockMultiID
import ic2.core.block.wiring.TileEntityChargepadBlock
import ic2.core.init.InternalName
import ic2.core.util.StackUtil
import net.minecraft.block.Block
import net.minecraft.block.material.Material
import net.minecraft.entity.Entity
import net.minecraft.entity.EntityLivingBase
import net.minecraft.entity.player.EntityPlayer
import net.minecraft.item.ItemStack
import net.minecraft.tileentity.TileEntity
import net.minecraft.util.MathHelper
import net.minecraft.world.IBlockAccess
import net.minecraft.world.World
import org.apache.commons.lang3.mutable.MutableObject
import java.util.*
class MyBlockChargepad(internalName: InternalName): BlockMultiID(internalName, Material.iron, MyItemChargepadBlock::class.java) {
init {
this.setHardness(1.5f)
this.setStepSound(Block.soundTypeMetal)
this.setBlockBounds(0.0f, 0.0f, 0.0f, 1.0f, 0.95f, 1.0f)
MyIC2Items.chargepadSmallEnergyStorage = ItemStack(this, 1, 0)
MyIC2Items.chargepadBigEnergyStorage = ItemStack(this, 1, 1)
GameRegistry.registerTileEntity(TilEntityChargepadSmallEnergyStorage::class.java, "Chargepad Small Energy Storage")
GameRegistry.registerTileEntity(TilEntityChargepadBigEnergyStorage::class.java, "Chargepad Big Energy Storage")
}
override fun getTextureFolder(id: Int): String = "wiring"
override fun getTeClass(meta: Int, ctorArgTypes: MutableObject<Array<Class<*>>>?, ctorArgs: MutableObject<Array<Any>>?): Class<out TileEntity>? {
return when(meta) {
0 -> TilEntityChargepadSmallEnergyStorage::class.java
1 -> TilEntityChargepadBigEnergyStorage::class.java
else -> null
}
}
// Спавн партиклов при зарядке
override fun randomDisplayTick(world: World?, x: Int, y: Int, z: Int, random: Random?) {
if(IC2.platform.isRendering) {
val te = this.getOwnTe(world!!, x, y, z) as TileEntityChargepadBlock
te.spawnParticles(world, x, y, z, random)
}
}
// Зарядка брони на игроке
override fun onEntityCollidedWithBlock(world: World?, x: Int, y: Int, z: Int, entity: Entity?) {
if(IC2.platform.isSimulating) {
if(entity is EntityPlayer) {
val te = this.getOwnTe(world!!, x, y, z) as TileEntityChargepadBlock
te.playerstandsat(entity)
}
}
}
// Поворот блока при установке
override fun onBlockPlacedBy(world: World?, x: Int, y: Int, z: Int, entity: EntityLivingBase?, stack: ItemStack?) {
if(IC2.platform.isSimulating) {
val te = this.getOwnTe(world!!, x, y, z) as TileEntityChargepadBlock
val nbttagcompound = StackUtil.getOrCreateNbtData(stack!!)
te.energy = nbttagcompound.getDouble("energy")
if(entity == null) {
te.facing = 0.toShort()
} else {
val yaw = MathHelper.floor_double((entity.rotationYaw * 4.0f / 360.0f).toDouble() + 0.5) and 3
val pitch = Math.round(entity.rotationPitch)
if(pitch <= -65) {
te.facing = 0.toShort()
} else {
when(yaw) {
0 -> te.facing = 2.toShort()
1 -> te.facing = 5.toShort()
2 -> te.facing = 3.toShort()
3 -> te.facing = 4.toShort()
}
}
}
}
}
override fun isProvidingWeakPower(blockAccess: IBlockAccess?, x: Int, y: Int, z: Int, side: Int): Int {
val te = this.getOwnTe(blockAccess!!, x, y, z) as TileEntityChargepadBlock
return if(te.isEmittingRedstone) 15 else 0
}
override fun canProvidePower(): Boolean = true
override fun isOpaqueCube(): Boolean = false
override fun isNormalCube(world: IBlockAccess?, i: Int, j: Int, k: Int): Boolean = false
}
Маленькое хранилище:
Kotlin:
package wiring
import ic2.core.block.wiring.ContainerChargepadBlock
import ic2.core.block.wiring.TileEntityChargepadBlock
import net.minecraft.client.gui.GuiScreen
import net.minecraft.entity.player.EntityPlayer
import net.minecraft.item.ItemStack
class TilEntityChargepadSmallEnergyStorage: TileEntityChargepadBlock(5, 32, 1000000000) {
override fun getInventoryName(): String = "Chargepad (SES)"
override fun getGui(entityPlayer: EntityPlayer?, isAdmin: Boolean): GuiScreen = GuiMyChargepadBlock(ContainerChargepadBlock(entityPlayer, this))
override fun getItems(player: EntityPlayer?) {
if(player != null) {
// Зарядка брони
var var2 = player.inventory.armorInventory
var var3 = var2.size
var var4 = 0
var current: ItemStack?
while(var4 < var3) {
current = var2[var4]
if(current != null) {
this.chargeitems(current, 8192) // Второй аргумент - фактор зарядки. Умножаем на тикрейт и получаем EU/t зарядки
}
++var4
}
// Зарядка вещей в инвентаре
var2 = player.inventory.mainInventory
var3 = var2.size
var4 = 0
while(var4 < var3) {
current = var2[var4]
if(current != null) {
this.chargeitems(current, 8192)
}
++var4
}
}
}
}
Kotlin:
package wiring
import ic2.core.block.wiring.ContainerChargepadBlock
import ic2.core.block.wiring.TileEntityChargepadBlock
import net.minecraft.client.gui.GuiScreen
import net.minecraft.entity.player.EntityPlayer
import net.minecraft.item.ItemStack
class TilEntityChargepadBigEnergyStorage: TileEntityChargepadBlock(6, 32, 2000000000) {
override fun getInventoryName(): String = "Chargepad (BES)"
override fun getGui(entityPlayer: EntityPlayer?, isAdmin: Boolean): GuiScreen = GuiMyChargepadBlock(ContainerChargepadBlock(entityPlayer, this))
// Здесь происходит зарядка
override fun getItems(player: EntityPlayer?) {
if(player != null) {
var var2 = player.inventory.armorInventory
var var3 = var2.size
var var4 = 0
var current: ItemStack?
while(var4 < var3) {
current = var2[var4]
if(current != null) {
this.chargeitems(current, 16384)
}
++var4
}
var2 = player.inventory.mainInventory
var3 = var2.size
var4 = 0
while(var4 < var3) {
current = var2[var4]
if(current != null) {
this.chargeitems(current, 16384)
}
++var4
}
}
}
}
Kotlin:
package wiring
import MyIC2Items
import cpw.mods.fml.relauncher.Side
import cpw.mods.fml.relauncher.SideOnly
import ic2.core.item.block.ItemBlockIC2
import ic2.core.util.StackUtil
import net.minecraft.block.Block
import net.minecraft.creativetab.CreativeTabs
import net.minecraft.entity.player.EntityPlayer
import net.minecraft.item.Item
import net.minecraft.item.ItemStack
import net.minecraft.util.StatCollector
class MyItemChargepadBlock(block: Block): ItemBlockIC2(block) {
init {
this.maxDamage = 0
this.setHasSubtypes(true)
this.setMaxStackSize(1)
}
override fun getMetadata(i: Int): Int {
return i
}
override fun getUnlocalizedName(itemstack: ItemStack?): String? {
val meta = itemstack!!.itemDamage
return when(meta) {
0 -> "ic2.blockChargepadSES"
1 -> "ic2.blockChargepadBES"
else -> null
}
}
override fun addInformation(itemStack: ItemStack?, player: EntityPlayer?, info: MutableList<Any?>, b: Boolean) {
val meta = itemStack!!.itemDamage
when(meta) {
0 -> info.add(StatCollector.translateToLocal("ic2.item.tooltip.Output") + " 4096EU/t " + StatCollector.translateToLocal("ic2.item.tooltip.Capacity") + " 1b EU ")
1 -> info.add(StatCollector.translateToLocal("ic2.item.tooltip.Output") + " 8192EU/t " + StatCollector.translateToLocal("ic2.item.tooltip.Capacity") + " 2b EU")
}
when(meta) {
0, 1 -> {
val nbttagcompound = StackUtil.getOrCreateNbtData(itemStack)
info.add(StatCollector.translateToLocal("ic2.item.tooltip.Store") + " " + nbttagcompound.getInteger("energy") + " EU")
}
}
}
@SideOnly(Side.CLIENT)
override fun getSubItems(item: Item, par2CreativeTabs: CreativeTabs?, itemList: MutableList<Any?>) {
itemList.add(MyIC2Items.chargepadBigEnergyStorage)
itemList.add(MyIC2Items.chargepadSmallEnergyStorage)
var itemStack = ItemStack(MyIC2Items.chargepadBigEnergyStorage.item, 1)
itemStack.itemDamage = 0
var nbttagcompound = StackUtil.getOrCreateNbtData(itemStack)
nbttagcompound.setDouble("energy", 1000000000.0)
itemList.add(itemStack)
itemStack = ItemStack(MyIC2Items.chargepadSmallEnergyStorage.item, 1)
itemStack.itemDamage = 1
nbttagcompound = StackUtil.getOrCreateNbtData(itemStack)
nbttagcompound.setDouble("energy", 2000000000.0)
itemList.add(itemStack)
}
}
Kotlin:
package wiring
import ic2.core.GuiIconButton
import ic2.core.IC2
import ic2.core.block.wiring.ContainerChargepadBlock
import ic2.core.block.wiring.TileEntityChargepadBlock
import ic2.core.network.NetworkManager
import ic2.core.util.GuiTooltipHelper
import net.minecraft.client.gui.GuiButton
import net.minecraft.client.gui.inventory.GuiContainer
import net.minecraft.init.Items
import net.minecraft.item.ItemStack
import net.minecraft.tileentity.TileEntity
import net.minecraft.util.ResourceLocation
import net.minecraft.util.StatCollector
import org.lwjgl.opengl.GL11
class GuiMyChargepadBlock(container1: ContainerChargepadBlock): GuiContainer(container1) {
private val container: ContainerChargepadBlock = container1
private val level: String = StatCollector.translateToLocal("ic2.EUStorage.gui.info.level")
private val name: String?
private var background: ResourceLocation = ResourceLocation(IC2.textureDomain, "textures/gui/GUIChargepadBlock.png")
init {
when((container1.base as TileEntityChargepadBlock).tier) {
5 -> this.name = StatCollector.translateToLocal("myic2addon.sesChargepad.gui.name")
6 -> this.name = StatCollector.translateToLocal("myic2addon.besChargepad.gui.name")
else -> this.name = null
}
}
override fun drawGuiContainerForegroundLayer(par1: Int, par2: Int) {
this.fontRendererObj.drawString(this.name, (this.xSize - this.fontRendererObj.getStringWidth(this.name)) / 2, 6, 4210752)
this.fontRendererObj.drawString(this.level, 79, 25, 4210752)
val e = Math.min((this.container.base as TileEntityChargepadBlock).energy, (this.container.base as TileEntityChargepadBlock).maxStorage.toDouble()).toInt()
this.fontRendererObj.drawString(" $e", 110, 35, 4210752)
this.fontRendererObj.drawString("/" + (this.container.base as TileEntityChargepadBlock).maxStorage, 110, 45, 4210752)
GuiTooltipHelper.drawAreaTooltip(par1 - this.guiLeft, par2 - this.guiTop, (this.container.base as TileEntityChargepadBlock).getredstoneMode(), 153, 3, 172, 22)
}
override fun drawGuiContainerBackgroundLayer(f: Float, x: Int, y: Int) {
GL11.glColor4f(1.0f, 1.0f, 1.0f, 1.0f)
this.mc.getTextureManager().bindTexture(background)
val j = (this.width - this.xSize) / 2
val k = (this.height - this.ySize) / 2
this.drawTexturedModalRect(j, k, 0, 0, this.xSize, this.ySize)
if((this.container.base as TileEntityChargepadBlock).energy > 0.0) {
val i1 = (24.0f * (this.container.base as TileEntityChargepadBlock).chargeLevel).toInt()
this.drawTexturedModalRect(j + 79, k + 34, 176, 14, i1 + 1, 16)
}
}
override fun initGui() {
super.initGui()
this.buttonList.add(GuiIconButton(0, (this.width - this.xSize) / 2 + 152, (this.height - this.ySize) / 2 + 4, 20, 20, ItemStack(Items.redstone), true))
}
override fun actionPerformed(guibutton: GuiButton?) {
super.actionPerformed(guibutton)
if(guibutton!!.id == 0) {
(IC2.network.get() as NetworkManager).initiateClientTileEntityEvent(this.container.base as TileEntity, 0)
}
}
}
MyIC2Items
Kotlin:
lateinit var chargepadSmallEnergyStorage: ItemStack // Маленькое энергохранилище
lateinit var chargepadBigEnergyStorage: ItemStack // Большое энерго хранилище
MyBlockChargepad(InternalName.blockChargepad)
Готово! Дальше локализуем и ставим текстуру.
V часть. Предмет на энергии.
Свой меч.
В этом разделе к коду я добавил больше комментариев. И так. Пришло время сделать что-то другое. Давайте сделаем свой меч. Я буду делать электрокатану. Создадим класс и назовем его Свой меч.
Katana
и поместим его в пакет items
.
Kotlin:
package items
import com.google.common.collect.HashMultimap
import com.google.common.collect.Multimap
import cpw.mods.fml.relauncher.Side
import cpw.mods.fml.relauncher.SideOnly
import ic2.api.item.ElectricItem
import ic2.core.IC2
import ic2.core.init.InternalName
import ic2.core.item.armor.ItemArmorNanoSuit
import ic2.core.item.armor.ItemArmorQuantumSuit
import ic2.core.item.tool.ItemElectricTool
import net.minecraft.client.renderer.texture.IIconRegister
import net.minecraft.entity.EntityLivingBase
import net.minecraft.entity.SharedMonsterAttributes
import net.minecraft.entity.ai.attributes.AttributeModifier
import net.minecraft.entity.player.EntityPlayer
import net.minecraft.item.Item
import net.minecraft.item.ItemStack
import net.minecraft.util.DamageSource
import net.minecraft.util.IIcon
class Katana(internalName: InternalName): ItemElectricTool(internalName, 10) {
// Переменные для удобства. Можно и не использовать
private val energyConsumeOnHit = 15000.0 // Сколько будет тратится энергии за удар
private val damage = 40.0 // Сколько будет наносить меч
init {
maxCharge = 500000 // Сколько может хранить зарядки
tier = 4 // Энергоуровень
transferLimit = 10000 // Сколько будет перемещаться в предмет EU/t при зарядке
unlocalizedName = "katana" // Нелокализованное имя. Используется для перевода и текстур
}
@SideOnly(Side.CLIENT) lateinit var texture: IIcon // Переменная для текстуры
@SideOnly(Side.CLIENT) override fun registerIcons(iconRegister: IIconRegister) { texture = iconRegister.registerIcon("${IC2.textureDomain}:katana") } // Регестрируем текстуру
@SideOnly(Side.CLIENT) override fun getIcon(itemStack: ItemStack, pass: Int): IIcon = texture // Устанавливем текстуру
@SideOnly(Side.CLIENT) override fun requiresMultipleRenderPasses(): Boolean = true // Благодаря этому текстуры пременятся на предметы с метадатой. Это нам обязательно нужно
override fun isFull3D(): Boolean = true
override fun hitEntity(stack: ItemStack?, target: EntityLivingBase?, source: EntityLivingBase?): Boolean { // Что происходит при ударе
if(IC2.platform.isSimulating) {
if(target !is EntityPlayer) { // Если цель не игрок
if(ElectricItem.manager.canUse(stack, energyConsumeOnHit)) { // Если мы можем использовать предмет
target?.attackEntityFrom(DamageSource.causePlayerDamage(source as EntityPlayer), damage.toFloat()) // Наносим 40 едениц урона(20 сердец)
ElectricItem.manager.discharge(stack, energyConsumeOnHit, this.tier, true, false, false) // Разряжаем предмет на 15К EU
}
}
else {// Если цель игрок
for(i in 0..3) {
val armor = target.getEquipmentInSlot(i + 1) // Получем броню
var amount = 0.0
if(armor != null) { // Если броня надета
if(armor.item is ItemArmorNanoSuit) amount = 200000.0 // Если броня - нано-костюм, то будем её разряжать на 200К EU. Что бы полностью разрядит броню, потребуется 5 ударов
else if(armor.item is ItemArmorQuantumSuit) amount = 2000000.0 // Если броня - квант, то разряжаем её на 2KK EU. Что бы полностью разрядит броню, потребуется 5 ударов
if(amount > 0.0) ElectricItem.manager.discharge(armor, amount, this.tier, true, false, false); ElectricItem.manager.discharge(stack, energyConsumeOnHit * 1.5, this.tier, true, false, false) // И наконец разряжаем катану и броню противника
}
}
}
}
return true
}
override fun getAttributeModifiers(stack: ItemStack?): Multimap<*, *> {
var dmg = 1.0 // Стандартно урон 1 еденица (0.5 сердца)
if(ElectricItem.manager.canUse(stack, energyConsumeOnHit)) { // Если хватает энергии ставим урон на 40 едениц(20 сердец)
dmg = damage
}
// Дальше записываем атрибут
val ret = HashMultimap.create<String, AttributeModifier>()
ret.put(SharedMonsterAttributes.attackDamage.attributeUnlocalizedName, AttributeModifier(Item.field_111210_e, "Tool modifier", dmg, 0))
return ret
}
}
preInit
.Katana(InternalName.itemNanoSaber)
.Локализуем, ставим иконку и готово!
Результат:
Свой бур.
Создадим класс MyDrill
в пакете items
Kotlin:
package items
import ic2.core.IC2
import ic2.core.init.InternalName
import ic2.core.item.tool.ItemDrill
import net.minecraft.enchantment.Enchantment
import net.minecraft.enchantment.EnchantmentHelper
import net.minecraft.entity.player.EntityPlayer
import net.minecraft.item.ItemStack
import net.minecraft.world.World
import java.util.*
class MyDrill(internalName: InternalName): ItemDrill(internalName, 1000, HarvestLevel.Iridium) {
var mode = 0 // Переменная режима, позже будем её менять
init {
maxCharge = 500000 // Максимальный заряд
transferLimit = 10000 // Сколько будет перемещаться в предмет EU/t при зарядке
tier = 4 // Энергоуровень
efficiencyOnProperMaterial = 50F // Эффективность. Чем выше, тем быстрее копает
unlocalizedName = "myDrill" // Нелокализованное имя
}
override fun getItemStack(charge: Double): ItemStack {
val ret = super.getItemStack(charge)
val enchantmentMap = HashMap<Int, Int>()
enchantmentMap[Enchantment.fortune.effectId] = 5 // Добавляем удачу 5 уровня
EnchantmentHelper.setEnchantments(enchantmentMap, ret)
return ret
}
override fun onItemRightClick(stack: ItemStack, world: World?, player: EntityPlayer?): ItemStack {
if(!IC2.platform.isSimulating) {
return super.onItemRightClick(stack, world, player)
} else {
if(IC2.keyboard.isModeSwitchKeyDown(player)) {
val enchantmentMap = HashMap<Int, Int>()
enchantmentMap[Enchantment.fortune.effectId] = 5 // Так же добавляем удачу
// Дальше будут переключаться режимы.
when(mode) {
0 -> {
enchantmentMap[Enchantment.silkTouch.effectId] = 1 // Добавляем шёлковое касание
IC2.platform.messagePlayer(player, "ic2.tooltip.mode", "ic2.tooltip.mode.silkTouch")
mode += 1
}
1 -> {
efficiencyOnProperMaterial = 25F // Сделаем скорость ломания в 2 раза меньше
IC2.platform.messagePlayer(player, "ic2.tooltip.mode", "ic2.tooltip.mode.accurate")
mode += 1
}
2 -> {
efficiencyOnProperMaterial = 50F // Тут возвращаем скорость обратно
IC2.platform.messagePlayer(player, "ic2.tooltip.mode", "ic2.tooltip.mode.normal")
mode = 0
}
}
EnchantmentHelper.setEnchantments(enchantmentMap, stack) // Запись энчантов в предмет
}
return super.onItemRightClick(stack, world, player)
}
}
override fun onItemUse(stack: ItemStack?, player: EntityPlayer, world: World?, x: Int, y: Int, z: Int, side: Int, xOffset: Float, yOffset: Float, zOffset: Float): Boolean {
return if(IC2.keyboard.isModeSwitchKeyDown(player)) false else super.onItemUse(stack, player, world, x, y, z, side, xOffset, yOffset, zOffset)
}
}
preInit
.MyDrill(InternalName.itemToolDrill)
.Локализуем, ставим иконку и готово!
Результат:
VI часть. Кастомный ядерный реактор.
TODO
TODO