Compare commits

...
Author SHA1 Message Date
Lily 4faae33d43 mod station groundwork 2024-03-06 15:47:16 -05:00
Lily bd8f761ddb Merge branch 'tm-machine' into mod_station
# Conflicts:
#	common/src/main/kotlin/com/cobblemon/mod/common/CobblemonItems.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/CobblemonClient.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/command/TestCommand.kt
#	common/src/main/resources/assets/cobblemon/lang/en_us.json
2024-03-06 15:07:52 -05:00
Licious d5af099120 Merge branch 'main' into tm-machine 2024-02-21 20:34:34 +00:00
Lily 825e1ee110 Merge branch 'type_gem' into tm-machine
# Conflicts:
#	common/src/main/kotlin/com/cobblemon/mod/common/client/CobblemonClient.kt
#	common/src/main/resources/assets/cobblemon/lang/en_us.json
2024-02-20 17:54:13 -05:00
Lily ee0dc24207 temporarily removed type gems 2024-02-19 20:52:26 -05:00
Lily e5d702bb5a added new type gem sprites 2024-02-19 20:41:41 -05:00
Lily c6e514216c added new obtain methods 2024-02-16 11:26:36 -05:00
Lily f80a2850bb template type gem block 2024-02-05 19:42:36 -05:00
Lily 64fe6cefde Merge branch 'crystal_block' into tm-machine 2024-02-05 19:24:12 -05:00
Lily 26f337c0fd unlock tms when the player obtains them 2024-02-05 16:48:44 -05:00
jeffw773 9fc81c1b33 - Amethyst Shards now only feed into the correct slot 2024-02-01 09:04:02 -08:00
JazzMcNade 5c599dbb9a TM machine monitor switches on and off with player interaction. 2024-02-01 01:08:34 -06:00
jeffw773 d5a94ff784 - Changes to Blockstate when being used by player
- Plays sound when crafted with automation (might not be wanted later idk)
2024-01-31 16:16:52 -08:00
jeffw773 024f299486 - Comparator output from TMM now updates with respect to actions done by TM Machine 2024-01-31 12:06:23 -08:00
jeffw773 9a2b588568 - TM Machine can now Hopper out created TMs and spit out TMs and craft with Redstone signals if wanted 2024-01-31 10:53:26 -08:00
JazzMcNade b6fb5e8776 manual crafting 2024-01-31 03:00:40 -06:00
jeffw773 987b9bb275 - Sync fixes for TMM Inventory and UI slots 2024-01-30 14:35:33 -08:00
apion b04ab8b95b Took some stuff out of CobblemonClient and put it in TMIten (clean up) 2024-01-30 16:52:22 -05:00
Lily dab0623d61 Merge remote-tracking branch 'origin/tm-machine' into tm-machine 2024-01-30 14:16:21 -05:00
Lily cb5b6ec68b advancement obtain method 2024-01-30 14:16:11 -05:00
JazzMcNade ea57c9dc5d Fix for removeStack 2024-01-30 01:56:35 -06:00
jeffw773 9abab091d9 - Materials feed into correct slots on TMM from hoppers 2024-01-28 13:01:49 -08:00
JazzMcNade e2e50d2f1b tm block now has a persistent inventory 2024-01-27 20:37:13 -06:00
jeffw773 4ac88ba192 - fixes to TM instances and isReadyToCraft conditional 2024-01-27 13:00:34 -08:00
jeffw773 37eccce8b1 - tweaks to tms 2024-01-27 12:14:13 -08:00
jeffw773 e44db7c380 - Filter Disc renders properly with client 2024-01-27 11:05:21 -08:00
JazzMcNade d57bb42720 Fix for shift click not always applying the filter 2024-01-27 05:13:19 -06:00
jeffw773 f0c44f040f Merge remote-tracking branch 'origin/tm-machine' into tm-machine 2024-01-26 21:52:45 -08:00
jeffw773 2d6e2f87ed - Hoppers and comparators are working for making TMs and Blank TMs 2024-01-26 21:52:27 -08:00
apion 8b4193a5db Fixed rotations 2024-01-26 22:54:33 -05:00
apion 667dfe32e3 More fun stuff 2024-01-26 22:27:13 -05:00
apion 218253765e Merge branch 'main' into tm-machine 2024-01-26 18:50:37 -05:00
apion ff082adf67 Start working on rendering different color disks in the render machine 2024-01-26 17:27:49 -05:00
apion 66959816ef Merge branch 'main' into tm-machine
# Conflicts:
#	common/src/main/kotlin/com/cobblemon/mod/common/CobblemonNetwork.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/CobblemonSounds.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/api/storage/player/PlayerData.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/CobblemonClient.kt
#	common/src/main/resources/assets/cobblemon/lang/en_us.json
#	common/src/main/resources/assets/cobblemon/sounds.json
#	common/src/main/resources/cobblemon-common.accesswidener
2024-01-26 15:52:23 -05:00
jeffw773 0e85835a87 Merge remote-tracking branch 'origin/tm-machine' into tm-machine 2024-01-26 12:44:35 -08:00
jeffw773 e165d4958d - TM Machine Inventory Disc 2024-01-26 12:44:18 -08:00
JazzMcNade e0736e1988 TM Block is no longer treated as 2 blocks tall for placement. 2024-01-26 02:04:24 -06:00
jeffw773 724ff86a21 - TM Machine Inventory Test 2024-01-25 23:03:38 -08:00
jeffw773 97427fa58b - TM Machine Entity functioning 2024-01-25 17:04:38 -08:00
jeffw773 c9d47a3e21 - More TM Mechanics 2024-01-24 22:30:56 -08:00
jeffw773 c5c884ca2e - Testing New TM Functionality 2024-01-24 15:58:42 -08:00
jeffw773 f086c32b95 - TM Machine Testing 2024-01-24 14:25:49 -08:00
jeffw773 ecea176300 - Added placeholder Type Gem sprites for TM Materials 2024-01-23 16:11:39 -08:00
jeffw773 c00413bb32 - Added Back buttons to TM Machine 2024-01-23 14:28:57 -08:00
jeffw773 be78012ce6 - TM Machine can now scroll through TMs
- Fixed how Scroll List and TM entries are handled so they can be interacted with properly
2024-01-23 11:01:05 -08:00
jeffw773 3844dd6314 - Added mouseClicked, mouseScrolled, mouseDragged to TMScrollingList (but still no work) 2024-01-11 12:34:14 -08:00
Lily 080077189f tm machine ui 2024-01-10 19:45:04 -05:00
jeffw773 4fa86c7742 - Added Eiko's new TM Machine Textures and fixed inventory slot locations 2024-01-04 13:11:00 -08:00
jeffw773 3c9cff5027 - Tweaked position of TM Machine GUI slightly as well as tooltips and inventory slots 2024-01-03 23:02:07 -08:00
Lily a1047e05d4 psychic trim update + updated type icons 2024-01-03 20:19:38 -05:00
Lily b7c1157c5c slight changes to the TM UI 2024-01-03 13:47:41 -05:00
apion cc8a51abcd TM Menu actually rendering now 2024-01-03 06:45:25 -05:00
apion 38174155bf Improved registry process for HandledScreens 2024-01-03 03:05:58 -05:00
Lily 2698006f93 filterTms function for when the UI is implemented 2024-01-03 00:30:50 -05:00
Lily aa38674fc8 TMM sounds and subtitles 2024-01-02 22:40:04 -05:00
apion 9ca0742386 Added fixed TMM model, added system to register HandledScreens 2024-01-02 21:53:50 -05:00
Lily 32d291890e TM colors and type gem items 2024-01-02 18:36:04 -05:00
Lily 381fd1d5e2 tm machine visuals 2024-01-02 12:42:32 -05:00
Lily a2fbe16ede textures partially 2024-01-02 12:20:32 -05:00
Lily 0b478ebd5a working coloring for tm items based on two ints given in the tm json file 2024-01-02 11:40:27 -05:00
Lily b0b07e8edd functional obtain methods for tms, with an option to passively check them 2024-01-01 15:40:07 -05:00
Lily 824773150a more tm item stuff 2023-12-15 16:54:28 -05:00
Lily 3dc285cc70 tm item?!?!?! what the flip?!? 2023-12-11 19:48:36 -05:00
apion e12d0bea66 Added TMBlock (lol) 2023-12-01 01:19:28 -05:00
apion 5bc4994091 Added learned tms to PlayerData, added a way to obtain TMs 2023-11-22 05:01:09 -05:00
apion 2b992dfd51 Setup TM registry 2023-11-22 03:22:36 -05:00
118 changed files with 4556 additions and 40 deletions
@@ -0,0 +1,20 @@
package com.cobblemon.mod.common.mixin.invoker;
import net.minecraft.block.AbstractBlock;
import net.minecraft.block.BlockSetType;
import net.minecraft.block.PressurePlateBlock;
import net.minecraft.resource.featuretoggle.FeatureSet;
import net.minecraft.screen.ScreenHandler;
import net.minecraft.screen.ScreenHandlerType;
import net.minecraft.screen.ScreenHandlerType.Factory;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.gen.Invoker;
@Mixin(ScreenHandlerType.class)
public interface ScreenHandlerTypeInvoker {
@Invoker("<init>")
static <T extends ScreenHandler> ScreenHandlerType<T> cobblemon$create(Factory<T> factory, FeatureSet requiredFeatures) {
throw new UnsupportedOperationException();
}
}
@@ -45,6 +45,8 @@ object CobblemonBlockEntities : PlatformRegistry<Registry<BlockEntityType<*>>, R
val SIGN: BlockEntityType<CobblemonSignBlockEntity> = this.create("sign", BlockEntityType.Builder.create(::CobblemonSignBlockEntity, CobblemonBlocks.APRICORN_SIGN, CobblemonBlocks.APRICORN_WALL_SIGN).build(null))
@JvmField
val HANGING_SIGN: BlockEntityType<CobblemonHangingSignBlockEntity> = this.create("hanging_sign", BlockEntityType.Builder.create(::CobblemonHangingSignBlockEntity, CobblemonBlocks.APRICORN_HANGING_SIGN, CobblemonBlocks.APRICORN_WALL_HANGING_SIGN).build(null))
@JvmField
val TM_BLOCK: BlockEntityType<TMBlockEntity> = this.create("tm_block", BlockEntityType.Builder.create(::TMBlockEntity, CobblemonBlocks.TM_MACHINE).build(null))
@JvmField
val GILDED_CHEST: BlockEntityType<GildedChestBlockEntity> = this.create("chest", BlockEntityType.Builder.create(::GildedChestBlockEntity,
@@ -385,6 +385,17 @@ object CobblemonBlocks : PlatformRegistry<Registry<Block>, RegistryKey<Registry<
.luminance { if ((it.get(PCBlock.ON) as Boolean) && (it.get(PCBlock.PART) == PCBlock.PCPart.TOP)) 10 else 0 }
)
)
val TM_MACHINE = create(
"tm_machine",
TMBlock(
AbstractBlock.Settings.create()
.mapColor(MapColor.GREEN)
.sounds(BlockSoundGroup.METAL)
.pistonBehavior(PistonBehavior.BLOCK)
.nonOpaque()
.luminance { if (it.get(TMBlock.ON) as Boolean) 10 else 0 }
)
)
@JvmField
val DISPLAY_CASE = create(
@@ -399,6 +410,19 @@ object CobblemonBlocks : PlatformRegistry<Registry<Block>, RegistryKey<Registry<
)
)
@JvmField
val MODIFICATION_STATION = create(
"modification_station",
ModStationBlock(
AbstractBlock.Settings.create()
.sounds(BlockSoundGroup.WOOD)
.nonOpaque()
.pistonBehavior(PistonBehavior.BLOCK)
.mapColor(MapColor.BROWN)
.strength(0.3f)
)
)
val RED_MINT = create("red_mint", MintBlock(MintType.RED, AbstractBlock.Settings.create().mapColor(MapColor.RED).noCollision().ticksRandomly().breakInstantly().sounds(CobblemonSounds.MINT_SOUNDS)))
@JvmField
val BLUE_MINT = create("blue_mint", MintBlock(MintType.BLUE, AbstractBlock.Settings.create().mapColor(MapColor.BLUE).noCollision().ticksRandomly().breakInstantly().sounds(CobblemonSounds.MINT_SOUNDS)))
@@ -432,6 +456,67 @@ object CobblemonBlocks : PlatformRegistry<Registry<Block>, RegistryKey<Registry<
@JvmField
val POTTED_PEP_UP_FLOWER = this.create("potted_pep_up_flower", BlocksInvoker.createFlowerPotBlock(PEP_UP_FLOWER))
@JvmField
val NORMAL_TYPE_GEM_BLOCK = this.create("normal_type_gem_block", Block(AbstractBlock.Settings.copy(Blocks.AMETHYST_BLOCK)))
@JvmField
val NORMAL_TYPE_GEM = typeGem(
"normal_type_gem",
GrowableStoneBlock.STAGE_3,
7,
3,
null,
NORMAL_TYPE_GEM_BLOCK
)
@JvmField
val LARGE_BUDDING_NORMAL_TYPE_GEM = typeGem(
"large_budding_normal_type_gem",
GrowableStoneBlock.STAGE_2,
5,
3,
NORMAL_TYPE_GEM,
NORMAL_TYPE_GEM_BLOCK
)
@JvmField
val MEDIUM_BUDDING_NORMAL_TYPE_GEM = typeGem(
"medium_budding_normal_type_gem",
GrowableStoneBlock.STAGE_1,
4,
3,
LARGE_BUDDING_NORMAL_TYPE_GEM,
NORMAL_TYPE_GEM_BLOCK
)
@JvmField
val SMALL_BUDDING_NORMAL_TYPE_GEM = typeGem(
"small_budding_normal_type_gem",
GrowableStoneBlock.STAGE_0,
3,
4,
MEDIUM_BUDDING_NORMAL_TYPE_GEM,
NORMAL_TYPE_GEM_BLOCK
)
private fun typeGem(
name: String,
stage: Int,
height: Int,
xzOffset: Int,
nextStage: Block?,
baseBlock: Block
): TypeGemBlock {
return this.create(name, TypeGemBlock(
settings = AbstractBlock.Settings.create()
.pistonBehavior(PistonBehavior.DESTROY)
.nonOpaque()
.strength(1.5F)
.sounds(CobblemonSounds.TYPE_GEM_SOUNDS),
stage = stage,
height = height,
xzOffset = xzOffset,
nextStage = nextStage,
baseBlock = baseBlock
))
}
/**
* Returns a map of all the blocks that can be stripped with an axe in the format of input - output.
*
@@ -442,8 +527,6 @@ object CobblemonBlocks : PlatformRegistry<Registry<Block>, RegistryKey<Registry<
APRICORN_LOG to STRIPPED_APRICORN_LOG
)
private fun apricornBlock(name: String, apricorn: Apricorn): ApricornBlock = this.create(name, ApricornBlock(AbstractBlock.Settings.create().mapColor(apricorn.mapColor()).ticksRandomly().strength(Blocks.OAK_LOG.hardness, Blocks.OAK_LOG.blastResistance).sounds(BlockSoundGroup.WOOD).nonOpaque(), apricorn))
private fun tumblestoneBlock(name: String, stage: Int, height: Int, xzOffset: Int, nextStage: Block?) : Block {
@@ -26,6 +26,7 @@ import net.minecraft.registry.tag.TagKey
import net.minecraft.resource.ResourceManager
import net.minecraft.resource.ResourceReloader
import net.minecraft.resource.ResourceType
import net.minecraft.screen.ScreenHandlerType
import net.minecraft.server.MinecraftServer
import net.minecraft.server.network.ServerPlayerEntity
import net.minecraft.text.Text
@@ -158,6 +159,8 @@ interface CobblemonImplementation {
*/
fun registerResourceReloader(identifier: Identifier, reloader: ResourceReloader, type: ResourceType, dependencies: Collection<Identifier>)
fun registerScreenHandlerType(identifier: Identifier, screenHandlerType: ScreenHandlerType<*>)
/**
* TODO
*
@@ -258,10 +258,13 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, RegistryKey<Registry<It
val HEALING_MACHINE = blockItem("healing_machine", CobblemonBlocks.HEALING_MACHINE)
@JvmField
val PC = blockItem("pc", CobblemonBlocks.PC)
val TM_MACHINE = blockItem("tm_machine", CobblemonBlocks.TM_MACHINE)
@JvmField
val PASTURE = blockItem("pasture", CobblemonBlocks.PASTURE)
@JvmField
val DISPLAY_CASE = blockItem("display_case", CobblemonBlocks.DISPLAY_CASE)
@JvmField
val MOD_STATION = blockItem("modification_station", CobblemonBlocks.MODIFICATION_STATION)
// Evolution items
@JvmField val LINK_CABLE = create("link_cable", LinkCableItem())
@@ -867,6 +870,10 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, RegistryKey<Registry<It
val RELIC_COIN_POUCH = blockItem("relic_coin_pouch", CobblemonBlocks.RELIC_COIN_POUCH)
@JvmField
val RELIC_COIN_SACK = blockItem("relic_coin_sack", CobblemonBlocks.RELIC_COIN_SACK)
@JvmField
val TECHNICAL_MACHINE = this.create("technical_machine", TechnicalMachineItem(Item.Settings()))
@JvmField
val BLANK_TM = this.create("blank_tm", CobblemonItem(Item.Settings()))
// Type Gems
@JvmField
@@ -43,6 +43,8 @@ import com.cobblemon.mod.common.client.net.dialogue.DialogueClosedHandler
import com.cobblemon.mod.common.client.net.dialogue.DialogueOpenedHandler
import com.cobblemon.mod.common.client.net.effect.SpawnSnowstormEntityParticleHandler
import com.cobblemon.mod.common.client.net.effect.SpawnSnowstormParticleHandler
import com.cobblemon.mod.common.client.net.gui.CraftBlankTMPacketHandler
import com.cobblemon.mod.common.client.net.gui.CraftTMPacketHandler
import com.cobblemon.mod.common.client.net.gui.InteractPokemonUIPacketHandler
import com.cobblemon.mod.common.client.net.gui.SummaryUIPacketHandler
import com.cobblemon.mod.common.client.net.pasture.ClosePastureHandler
@@ -131,6 +133,8 @@ import com.cobblemon.mod.common.net.messages.client.trade.TradeOfferExpiredPacke
import com.cobblemon.mod.common.net.messages.client.trade.TradeOfferNotificationPacket
import com.cobblemon.mod.common.net.messages.client.trade.TradeStartedPacket
import com.cobblemon.mod.common.net.messages.client.trade.TradeUpdatedPacket
import com.cobblemon.mod.common.net.messages.client.ui.CraftBlankTMPacket
import com.cobblemon.mod.common.net.messages.client.ui.CraftTMPacket
import com.cobblemon.mod.common.net.messages.client.ui.InteractPokemonUIPacket
import com.cobblemon.mod.common.net.messages.client.ui.SummaryUIPacket
import com.cobblemon.mod.common.net.messages.server.*
@@ -432,6 +436,10 @@ object CobblemonNetwork : NetworkManager {
this.createServerBound(PartyPokemonMoveSelectedPacket.ID, PartyPokemonMoveSelectedPacket::decode, PartyPokemonMoveSelectedHandler)
this.createServerBound(PartyMoveSelectCancelledPacket.ID, PartyMoveSelectCancelledPacket::decode, PartyMoveSelectCancelledHandler)
// TM Machine packets
this.createServerBound(CraftTMPacket.ID, CraftTMPacket::decode, CraftTMPacketHandler)
this.createServerBound(CraftBlankTMPacket.ID, CraftBlankTMPacket::decode, CraftBlankTMPacketHandler)
// Dialogue packets
this.createServerBound(EscapeDialoguePacket.ID, EscapeDialoguePacket::decode, EscapeDialogueHandler)
this.createServerBound(InputToDialoguePacket.ID, InputToDialoguePacket::decode, InputToDialogueHandler)
@@ -240,6 +240,19 @@ object CobblemonSounds : PlatformRegistry<Registry<SoundEvent>, RegistryKey<Regi
TUMBLESTONE_HIT,
TUMBLESTONE_STEP
)
@JvmField
val TM_USE = this.create("tm.use")
@JvmField
val TMM_CRAFT = this.create("tmm.craft")
@JvmField
val TMM_CRAFT_BLANK = this.create("tmm.craft_blank")
@JvmField
val TMM_OFF = this.create("tmm.off")
@JvmField
val TMM_ON = this.create("tmm.on")
@JvmField
val TYPE_GEM_SOUNDS = TUMBLESTONE_BLOCK_SOUNDS
@JvmField
val BERRY_BUSH_SOUNDS = BlockSoundGroup(1f, 1f,
@@ -8,6 +8,7 @@
package com.cobblemon.mod.common.api.pokemon.moves
import com.cobblemon.mod.common.Cobblemon
import com.cobblemon.mod.common.api.data.ClientDataSynchronizer
import com.cobblemon.mod.common.api.moves.MoveTemplate
import com.cobblemon.mod.common.api.moves.Moves
@@ -93,6 +94,20 @@ open class Learnset : ClientDataSynchronizer<Learnset> {
.flatMap { it.value }
.toSet()
fun tmLearnableMoves(): MutableList<MoveTemplate> {
val moves = mutableListOf<MoveTemplate>()
moves.addAll(tmMoves)
moves.addAll(tutorMoves)
moves.addAll(eggMoves)
moves.addAll(getLevelUpMovesUpTo(Cobblemon.config.maxPokemonLevel))
moves.addAll(evolutionMoves)
moves.addAll(formChangeMoves)
return moves
}
// We only sync level up moves atm
override fun shouldSynchronize(other: Learnset) = other.levelUpMoves != this.levelUpMoves
@@ -10,6 +10,7 @@ package com.cobblemon.mod.common.api.storage.player
import com.cobblemon.mod.common.Cobblemon
import com.cobblemon.mod.common.CobblemonNetwork.sendPacket
import com.cobblemon.mod.common.api.tms.TechnicalMachine
import com.cobblemon.mod.common.CobblemonSounds
import com.cobblemon.mod.common.net.messages.client.starter.SetClientPlayerDataPacket
import java.util.UUID
@@ -23,6 +24,7 @@ data class PlayerData(
var starterSelected: Boolean,
var starterUUID: UUID?,
var keyItems: MutableSet<Identifier>,
var tmSet: MutableSet<Identifier>,
var battleTheme: Identifier?,
val extraData: MutableMap<String, PlayerDataExtension>,
) {
@@ -42,6 +44,7 @@ data class PlayerData(
starterUUID = null,
keyItems = mutableSetOf(),
battleTheme = CobblemonSounds.PVP_BATTLE.id,
tmSet = mutableSetOf(),
extraData = mutableMapOf()
)
}
@@ -10,6 +10,8 @@ package com.cobblemon.mod.common.api.storage.player.adapter
import com.cobblemon.mod.common.api.storage.player.PlayerData
import com.cobblemon.mod.common.api.storage.player.PlayerDataExtension
import com.cobblemon.mod.common.api.tms.ObtainMethod
import com.cobblemon.mod.common.util.adapters.CobblemonObtainMethodAdapter
import com.cobblemon.mod.common.util.adapters.IdentifierAdapter
import com.cobblemon.mod.common.util.fromJson
import com.google.gson.GsonBuilder
@@ -31,6 +33,7 @@ class JsonPlayerData: PlayerDataStoreAdapter {
.setPrettyPrinting()
.disableHtmlEscaping()
.registerTypeAdapter(PlayerDataExtension::class.java, PlayerDataExtensionAdapter)
.registerTypeAdapter(ObtainMethod::class.java, CobblemonObtainMethodAdapter)
.registerTypeAdapter(Identifier::class.java, IdentifierAdapter)
.create()
}
@@ -0,0 +1,26 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.api.tms
import net.minecraft.server.network.ServerPlayerEntity
interface ObtainMethod {
/**
* Whether to check this [ObtainMethod] once every second.
*/
val passive: Boolean
/**
* Checks if the [ObtainMethod] condition is true.
*
* @param player The player to use when checking.
* @return Whether the check succeeded.
*/
fun matches(player: ServerPlayerEntity): Boolean
}
@@ -0,0 +1,23 @@
package com.cobblemon.mod.common.api.tms
import com.google.gson.JsonDeserializer
import com.google.gson.JsonSerializer
import net.minecraft.util.Identifier
import kotlin.reflect.KClass
/**
* A type adapter for [ObtainMethod]s.
* For the default implementation see [CobblemonObtainMethodAdapter].
*
* @author Apion
* @since November 22nd, 2023
*/
interface ObtainMethodAdapter : JsonDeserializer<ObtainMethod>, JsonSerializer<ObtainMethod> {
/**
* Register a [ObtainMethod] to be used by this adapter.
*
* @param type The [KClass] of the [ObtainMethod].
* @param identifier The expected [Identifier] in the parsed JSON.
*/
fun register(type: KClass<out ObtainMethod>, identifier: Identifier)
}
@@ -0,0 +1,119 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.api.tms
import com.cobblemon.mod.common.Cobblemon
import com.cobblemon.mod.common.api.moves.Moves
import com.cobblemon.mod.common.api.types.ElementalType
import com.cobblemon.mod.common.api.types.ElementalTypes
import com.cobblemon.mod.common.pokemon.Pokemon
import com.cobblemon.mod.common.tms.obtain.NoneObtainMethod
import com.cobblemon.mod.common.util.lang
import net.minecraft.item.Item
import net.minecraft.item.Items
import net.minecraft.registry.Registries
import net.minecraft.server.network.ServerPlayerEntity
import net.minecraft.text.MutableText
import net.minecraft.text.Text
import net.minecraft.util.Identifier
class TechnicalMachine(
val moveName: String,
val recipe: TechnicalMachineRecipe?,
val obtainMethods: List<ObtainMethod> = emptyList(),
val type: String,
val primaryColor: Int?,
val secondaryColor: Int?
) {
companion object {
/**
* Filters all available [TechnicalMachines] based on three optional arguments
*
* @param search A [String] to check against move names
* @param type An [ElementalType] to check for
* @param pokemon A [Pokemon] to check the [Learnset] of
* @return A [MutableSet] of [TechnicalMachine] that passed the filter
* @author whatsy
*/
fun filterTms(search: String?, type: ElementalType?, pokemon: Pokemon?): MutableSet<TechnicalMachine> {
val tms = TechnicalMachines.tmMap.values.toMutableSet()
type?.let {
val iterator = tms.iterator()
while (iterator.hasNext()) {
val tm = iterator.next()
if (ElementalTypes.get(tm.type) != type) {
iterator.remove()
}
}
}
pokemon?.let {
val iterator = tms.iterator()
while (iterator.hasNext()) {
val tm = iterator.next()
val move = Moves.getByName(tm.moveName)
if (!pokemon.species.moves.tmLearnableMoves().contains(move)) {
iterator.remove()
}
}
}
search?.let {
val iterator = tms.iterator()
while (iterator.hasNext()) {
val tm = iterator.next()
if (!tm.translatedMoveName().toString().contains(search, true)) {
iterator.remove()
}
}
}
return tms
}
}
/**
* Gets the [Identifier] of this [TechnicalMachine]
*
* @return The [Identifier] of this [TechnicalMachine] (or null if not found)
* @author whatsy
*/
fun id(): Identifier? {
TechnicalMachines.tmMap.forEach {
if (TechnicalMachines.tmMap[it.key] == this) return it.key
}
return null
}
/**
* Unlocks this [TechnicalMachine] for the player.
*
* @param player The [ServerPlayerEntity] to give this [TechnicalMachine] to.
* @return Whether the player was successfully granted the [TechnicalMachine]
* @author whatsy
*/
fun unlock(player: ServerPlayerEntity): Boolean {
if (id() == null) return false
Cobblemon.playerData.get(player).tmSet.add(id()!!)
if (!obtainMethods.any { it is NoneObtainMethod }) player.sendMessage(lang("tms.unlock_tm", lang("move.$moveName")))
return true
}
/**
* Returns a [MutableText] of the translated move name of this [TechnicalMachine]
*
* @return This [TechnicalMachine]'s move name, translated
* @author whatsy
*/
fun translatedMoveName(): MutableText {
return lang("move." + this.moveName)
}
}
@@ -0,0 +1,19 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.api.tms
import net.minecraft.util.Identifier
/**
* Represents the ingredients necessary to craft a [TechnicalMachine] in the [TMBlock]
*/
data class TechnicalMachineRecipe(
val item: Identifier,
val count: Int
)
@@ -0,0 +1,76 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.api.tms
import com.cobblemon.mod.common.Cobblemon
import com.cobblemon.mod.common.CobblemonItems
import com.cobblemon.mod.common.api.data.JsonDataRegistry
import com.cobblemon.mod.common.api.reactive.SimpleObservable
import com.cobblemon.mod.common.item.CobblemonItem
import com.cobblemon.mod.common.item.TechnicalMachineItem
import com.cobblemon.mod.common.registry.ItemTagCondition
import com.cobblemon.mod.common.util.adapters.CobblemonObtainMethodAdapter
import com.cobblemon.mod.common.util.adapters.IdentifierAdapter
import com.cobblemon.mod.common.util.cobblemonResource
import com.google.gson.GsonBuilder
import com.google.gson.reflect.TypeToken
import net.minecraft.item.ItemStack
import net.minecraft.registry.Registries
import net.minecraft.resource.ResourceType
import net.minecraft.server.network.ServerPlayerEntity
import net.minecraft.util.Identifier
object TechnicalMachines : JsonDataRegistry<TechnicalMachine> {
override val gson = GsonBuilder()
.registerTypeAdapter(Identifier::class.java, IdentifierAdapter)
.registerTypeAdapter(ObtainMethod::class.java, CobblemonObtainMethodAdapter)
.create()
override val typeToken = TypeToken.get(TechnicalMachine::class.java)
override val resourcePath = "tms"
override val id = cobblemonResource("technical_machines")
override val type = ResourceType.SERVER_DATA
override val observable = SimpleObservable<TechnicalMachines>()
val tmMap = mutableMapOf<Identifier, TechnicalMachine>()
val tagMap = mutableMapOf<ItemTagCondition, TechnicalMachine>()
val passiveTms = mutableMapOf<Identifier, TechnicalMachine>()
override fun reload(data: Map<Identifier, TechnicalMachine>) {
data.forEach {id, tm ->
tmMap[id] = tm
if (tm.obtainMethods.any { it.passive }) passiveTms.put(id, tm)
}
}
override fun sync(player: ServerPlayerEntity) { }
fun getTechnicalMachineFromStack(item: ItemStack?): TechnicalMachine? {
if (item == null) {
return null
}
return TechnicalMachineItem.getMoveNbt(item)
}
fun getStackFromTechnicalMachine(tm: TechnicalMachine): ItemStack {
val tmItem = CobblemonItems.TECHNICAL_MACHINE.defaultStack
return CobblemonItems.TECHNICAL_MACHINE.setNbt(tmItem,tm.id().toString())
}
fun isTechnicalMachine(item: ItemStack): Boolean {
return item.item is TechnicalMachineItem
}
fun checkPassives(player: ServerPlayerEntity) {
val playerTms = Cobblemon.playerData.get(player).tmSet
passiveTms.forEach { (id, tm) ->
if (tm.obtainMethods.all { it.matches(player) } && !playerTms.contains(id)) tm.unlock(player)
}
}
}
@@ -13,17 +13,23 @@ import net.minecraft.text.MutableText
import net.minecraft.util.Identifier
/**
* Class representing a type of a Pokemon or Move
* Class representing a type of Pokémon or Move
*
* @param name: The English name used to load / find it (spaces -> _)
* @param displayName: A Component used to display the name, normally a TranslatableText
* @param textureXMultiplier: The multiplier by which the TypeWidget shall move the display
* @param resourceLocation: The location of the resource used in the TypeWidget
* @param primaryColor: The primary color of this type used to color [TechnicalMachineItem].
* @param secondaryColor: The secondary color of this type used to color [TechnicalMachineItem]
* @param typeGem: The Type Gem item used to craft a [TechnicalMachineItem] of this type.
*/
class ElementalType(
val name: String,
val displayName: MutableText,
val hue: Int,
val textureXMultiplier: Int,
val resourceLocation: Identifier = Identifier(Cobblemon.MODID, "ui/types.png")
val resourceLocation: Identifier = Identifier(Cobblemon.MODID, "ui/types.png"),
val primaryColor: Int,
val secondaryColor: Int,
val typeGem: Identifier
)
@@ -8,6 +8,7 @@
package com.cobblemon.mod.common.api.types
import com.cobblemon.mod.common.util.cobblemonResource
import net.minecraft.text.MutableText
import net.minecraft.text.Text
@@ -22,134 +23,180 @@ object ElementalTypes {
name = "normal",
displayName = Text.translatable("cobblemon.type.normal"),
hue = 0xDDDDCF,
textureXMultiplier = 0
textureXMultiplier = 0,
primaryColor = 0xCCCCC1,
secondaryColor = 0xF9FFFC
)
val FIRE = register(
name = "fire",
displayName = Text.translatable("cobblemon.type.fire"),
hue = 0xE55C32,
textureXMultiplier = 1
textureXMultiplier = 1,
primaryColor = 0xFF8766,
secondaryColor = 0xFFD9A5
)
val WATER = register(
name = "water",
displayName = Text.translatable("cobblemon.type.water"),
hue = 0x4A9BE8,
textureXMultiplier = 2
textureXMultiplier = 2,
primaryColor = 0x7F9DFF,
secondaryColor = 0xA5EEFF
)
val GRASS = register(
name = "grass",
displayName = Text.translatable("cobblemon.type.grass"),
hue = 0x4DBC3C,
textureXMultiplier = 3
textureXMultiplier = 3,
primaryColor = 0x66CC99,
secondaryColor = 0xD6FFA5
)
val ELECTRIC = register(
name = "electric",
displayName = Text.translatable("cobblemon.type.electric"),
hue = 0xEFD128,
textureXMultiplier = 4
textureXMultiplier = 4,
primaryColor = 0xFFCF3F,
secondaryColor = 0xFFFFBF
)
val ICE = register(
name = "ice",
displayName = Text.translatable("cobblemon.type.ice"),
hue = 0x6BC3EF,
textureXMultiplier = 5
textureXMultiplier = 5,
primaryColor = 0x8CC7FF,
secondaryColor = 0xD6FFFF
)
val FIGHTING = register(
name = "fighting",
displayName = Text.translatable("cobblemon.type.fighting"),
hue = 0xC44C5C,
textureXMultiplier = 6
textureXMultiplier = 6,
primaryColor = 0xCC6673,
secondaryColor = 0xFFADA5
)
val POISON = register(
name = "poison",
displayName = Text.translatable("cobblemon.type.poison"),
hue = 0xA24BD8,
textureXMultiplier = 7
textureXMultiplier = 7,
primaryColor = 0x8D66CC,
secondaryColor = 0xEDA5FF
)
val GROUND = register(
name = "ground",
displayName = Text.translatable("cobblemon.type.ground"),
hue = 0xD89950,
textureXMultiplier = 8
textureXMultiplier = 8,
primaryColor = 0xE5A27E,
secondaryColor = 0xFFE1A5
)
val FLYING = register(
name = "flying",
displayName = Text.translatable("cobblemon.type.flying"),
hue = 0xBCC1FF,
textureXMultiplier = 9
textureXMultiplier = 9,
primaryColor = 0x8CB6FF,
secondaryColor = 0xE8DDFF
)
val PSYCHIC = register(
name = "psychic",
displayName = Text.translatable("cobblemon.type.psychic"),
hue = 0xD86AD6,
textureXMultiplier = 10
textureXMultiplier = 10,
primaryColor = 0xE48CFF,
secondaryColor = 0xFFCCF6
)
val BUG = register(
name = "bug",
displayName = Text.translatable("cobblemon.type.bug"),
hue = 0xA2C831,
textureXMultiplier = 11
textureXMultiplier = 11,
primaryColor = 0xAFCC66,
secondaryColor = 0xF6FFBF
)
val ROCK = register(
name = "rock",
displayName = Text.translatable("cobblemon.type.rock"),
hue = 0xAA9666,
textureXMultiplier = 12
textureXMultiplier = 12,
primaryColor = 0x997F4C,
secondaryColor = 0xDBC6A4
)
val GHOST = register(
name = "ghost",
displayName = Text.translatable("cobblemon.type.ghost"),
hue = 0x9572E5,
textureXMultiplier = 13
textureXMultiplier = 13,
primaryColor = 0x8E8CFF,
secondaryColor = 0xE8A5FF
)
val DRAGON = register(
name = "dragon",
displayName = Text.translatable("cobblemon.type.dragon"),
hue = 0x535DE8,
textureXMultiplier = 14
textureXMultiplier = 14,
primaryColor = 0xBA8CFF,
secondaryColor = 0xA5E5FF
)
val DARK = register(
name = "dark",
displayName = Text.translatable("cobblemon.type.dark"),
hue = 0x5C6CB2,
textureXMultiplier = 15
textureXMultiplier = 15,
primaryColor = 0x5966B2,
secondaryColor = 0xA5B1FF
)
val STEEL = register(
name = "steel",
displayName = Text.translatable("cobblemon.type.steel"),
hue = 0xC3CCE0,
textureXMultiplier = 16
textureXMultiplier = 16,
primaryColor = 0x858EB2,
secondaryColor = 0xF4FFFD
)
val FAIRY = register(
name = "fairy",
displayName = Text.translatable("cobblemon.type.fairy"),
hue = 0xEA727E,
textureXMultiplier = 17
textureXMultiplier = 17,
primaryColor = 0xFF8CB6,
secondaryColor = 0xFFD0CC
)
fun register(name: String, displayName: MutableText, hue: Int, textureXMultiplier: Int): ElementalType {
fun register(
name: String,
displayName: MutableText,
hue: Int,
textureXMultiplier: Int,
primaryColor: Int,
secondaryColor: Int
): ElementalType {
return ElementalType(
name = name,
displayName = displayName,
hue = hue,
textureXMultiplier = textureXMultiplier
textureXMultiplier = textureXMultiplier,
primaryColor = primaryColor,
secondaryColor = secondaryColor,
typeGem = cobblemonResource("${name}_gem")
).also {
allTypes.add(it)
}
@@ -0,0 +1,128 @@
package com.cobblemon.mod.common.block
import net.minecraft.block.AbstractBlock.Settings
import net.minecraft.block.Block
import net.minecraft.block.BlockState
import net.minecraft.block.Blocks
import net.minecraft.block.HorizontalFacingBlock
import net.minecraft.entity.LivingEntity
import net.minecraft.entity.ai.pathing.NavigationType
import net.minecraft.entity.player.PlayerEntity
import net.minecraft.fluid.Fluids
import net.minecraft.item.ItemPlacementContext
import net.minecraft.item.ItemStack
import net.minecraft.screen.NamedScreenHandlerFactory
import net.minecraft.state.StateManager
import net.minecraft.state.property.EnumProperty
import net.minecraft.util.*
import net.minecraft.util.hit.BlockHitResult
import net.minecraft.util.math.BlockPos
import net.minecraft.util.math.Direction
import net.minecraft.world.BlockView
import net.minecraft.world.World
import net.minecraft.world.WorldAccess
import net.minecraft.world.WorldView
class ModStationBlock(settings: Settings) : Block(settings) {
companion object {
val PART = EnumProperty.of("part", ModStationPart::class.java)
}
enum class ModStationPart(private val label: String) : StringIdentifiable {
TOP("top"),
BOTTOM("bottom");
override fun asString() = label
}
init {
defaultState = this.stateManager.defaultState.with(
HorizontalFacingBlock.FACING, Direction.SOUTH
).with(PART, ModStationPart.BOTTOM)
}
override fun onPlaced(
world: World,
pos: BlockPos,
state: BlockState,
placer: LivingEntity?,
itemStack: ItemStack
) {
world.setBlockState(pos.up(), state
.with(PART, ModStationPart.TOP)
)
world.updateNeighbors(pos, Blocks.AIR)
state.updateNeighbors(world, pos, 3)
}
override fun getPlacementState(blockPlaceContext: ItemPlacementContext): BlockState? {
val abovePosition = blockPlaceContext.blockPos.up()
val world = blockPlaceContext.world
if (world.getBlockState(abovePosition).canReplace(blockPlaceContext) && !world.isOutOfHeightLimit(abovePosition)) {
return defaultState
.with(HorizontalFacingBlock.FACING, blockPlaceContext.horizontalPlayerFacing)
.with(PART, ModStationPart.BOTTOM)
}
return null
}
override fun canPlaceAt(state: BlockState, world: WorldView, pos: BlockPos): Boolean {
val blockPos = pos.down()
val blockState = world.getBlockState(blockPos)
return if (state.get(PART) == ModStationPart.BOTTOM) blockState.isSideSolidFullSquare(world, blockPos, Direction.UP) else blockState.isOf(this)
}
override fun canPathfindThrough(
state: BlockState?,
world: BlockView?,
pos: BlockPos?,
type: NavigationType?
) = false
override fun appendProperties(builder: StateManager.Builder<Block, BlockState>) {
builder.add(HorizontalFacingBlock.FACING)
builder.add(PART)
}
override fun rotate(blockState: BlockState, rotation: BlockRotation) = blockState.with(HorizontalFacingBlock.FACING, rotation.rotate(blockState.get(HorizontalFacingBlock.FACING)))
override fun mirror(blockState: BlockState, mirror: BlockMirror): BlockState {
return blockState.rotate(mirror.getRotation(blockState.get(HorizontalFacingBlock.FACING)))
}
override fun onStateReplaced(state: BlockState, world: World, pos: BlockPos?, newState: BlockState, moved: Boolean) {
if (!state.isOf(newState.block)) super.onStateReplaced(state, world, pos, newState, moved)
}
override fun getStateForNeighborUpdate(
state: BlockState,
direction: Direction,
neighborState: BlockState,
world: WorldAccess,
pos: BlockPos,
neighborPos: BlockPos
): BlockState {
val isStation = neighborState.isOf(this)
val part = state.get(PART)
if (!isStation && part == ModStationPart.TOP && neighborPos == pos.down()) {
return Blocks.AIR.defaultState
} else if (!isStation && part == ModStationPart.BOTTOM && neighborPos == pos.up()) {
return Blocks.AIR.defaultState
}
return state
}
override fun onUse(
state: BlockState,
world: World,
pos: BlockPos,
player: PlayerEntity,
hand: Hand,
hit: BlockHitResult
): ActionResult {
player.openHandledScreen(state.createScreenHandlerFactory(world, pos))
return ActionResult.CONSUME
}
}
@@ -0,0 +1,547 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.block
import com.cobblemon.mod.common.CobblemonItems
import com.cobblemon.mod.common.CobblemonSounds
import com.cobblemon.mod.common.api.tms.TechnicalMachine
import com.cobblemon.mod.common.api.tms.TechnicalMachines
import com.cobblemon.mod.common.api.types.ElementalTypes
import com.cobblemon.mod.common.block.entity.TMBlockEntity
import com.cobblemon.mod.common.gui.TMMScreenHandler
import com.cobblemon.mod.common.util.playSoundServer
import com.cobblemon.mod.common.util.toVec3d
import net.minecraft.block.*
import net.minecraft.block.entity.BlockEntity
import net.minecraft.block.entity.BrewingStandBlockEntity
import net.minecraft.entity.ItemEntity
import net.minecraft.entity.ai.pathing.NavigationType
import net.minecraft.entity.player.PlayerEntity
import net.minecraft.fluid.FluidState
import net.minecraft.fluid.Fluids
import net.minecraft.inventory.SidedInventory
import net.minecraft.item.ItemPlacementContext
import net.minecraft.item.ItemStack
import net.minecraft.item.Items
import net.minecraft.registry.Registries
import net.minecraft.screen.NamedScreenHandlerFactory
import net.minecraft.screen.SimpleNamedScreenHandlerFactory
import net.minecraft.server.network.ServerPlayerEntity
import net.minecraft.server.world.ServerWorld
import net.minecraft.sound.SoundCategory
import net.minecraft.stat.Stats
import net.minecraft.state.StateManager
import net.minecraft.state.property.BooleanProperty
import net.minecraft.state.property.Properties
import net.minecraft.text.Text
import net.minecraft.util.ActionResult
import net.minecraft.util.BlockMirror
import net.minecraft.util.BlockRotation
import net.minecraft.util.Hand
import net.minecraft.util.hit.BlockHitResult
import net.minecraft.util.math.BlockPos
import net.minecraft.util.math.Direction
import net.minecraft.util.shape.VoxelShape
import net.minecraft.util.shape.VoxelShapes
import net.minecraft.world.BlockView
import net.minecraft.world.World
import net.minecraft.world.WorldAccess
class TMBlock(properties: Settings): BlockWithEntity(properties), Waterloggable, InventoryProvider {
/*val FACING = Properties.FACING
val TRIGGERED = Properties.TRIGGERED
val WATERLOGGED = Properties.WATERLOGGED*/
//var filterTM: TechnicalMachine? = null
//var previousFilterTM: TechnicalMachine? = null
var loadedMaterials: MutableList<ItemStack> = mutableListOf()
//val inv = TMBlockInventory(this)
/*class TMBlockInventory(val tmBlock: TMBlock) : SidedInventory {
override fun clear() {
TODO("Not yet implemented")
}
override fun size(): Int {
TODO("Not yet implemented")
}
override fun isEmpty(): Boolean {
return false
}
override fun getStack(slot: Int): ItemStack {
return ItemStack.EMPTY
}
override fun removeStack(slot: Int, amount: Int): ItemStack {
return ItemStack.EMPTY
}
override fun removeStack(slot: Int): ItemStack {
TODO("Not yet implemented")
}
override fun setStack(slot: Int, stack: ItemStack?) {
TODO("Not yet implemented")
}
override fun markDirty() {
TODO("Not yet implemented")
}
override fun canPlayerUse(player: PlayerEntity?): Boolean {
return false
}
override fun getAvailableSlots(side: Direction?): IntArray {
return IntArray(1)
}
override fun canInsert(slot: Int, stack: ItemStack?, dir: Direction?): Boolean {
// todo only allow for hopper to insert materials if it has a filterTM in it
if (tmBlock.filterTM != null && stack != null) {
// if material is needed then load it
if (tmBlock.materialNeeded(tmBlock.filterTM!!, stack)) {
tmBlock.loadMaterial(stack)
return true
}
else
return false
}
return false
}
override fun canExtract(slot: Int, stack: ItemStack?, dir: Direction?): Boolean {
return false
}
}*/
companion object {
//val WATERLOGGED = BooleanProperty.of("waterlogged")
val ON = BooleanProperty.of("on")
val FACING = Properties.FACING
val TRIGGERED = Properties.TRIGGERED
val WATERLOGGED = Properties.WATERLOGGED
private var NORTH_OUTLINE = VoxelShapes.union(
VoxelShapes.cuboid(0.0, 0.0, 0.0, 1.0, 0.3125, 0.9375),
VoxelShapes.cuboid(0.0, 0.3125, 0.75, 1.0, 0.9375, 0.9375),
VoxelShapes.cuboid(0.0625, 0.3125, 0.0625, 0.9375, 0.875, 0.9375)
)
private var SOUTH_OUTLINE = VoxelShapes.union(
VoxelShapes.cuboid(0.0, 0.0, 0.0625, 1.0, 0.3125, 1.0),
VoxelShapes.cuboid(0.0, 0.3125, 0.0625, 1.0, 0.9375, 0.25),
VoxelShapes.cuboid(0.0625, 0.3125, 0.0625, 0.9375, 0.875, 0.9375)
)
private var WEST_OUTLINE = VoxelShapes.union(
VoxelShapes.cuboid(0.0, 0.0, 0.0, 0.9375, 0.3125, 1.0),
VoxelShapes.cuboid(0.75, 0.3125, 0.0, 0.9375, 0.9375, 1.0),
VoxelShapes.cuboid(0.0625, 0.3125, 0.0625, 0.9375, 0.875, 0.9375)
)
private var EAST_OUTLINE = VoxelShapes.union(
VoxelShapes.cuboid(0.0625, 0.0, 0.0, 1.0, 0.3125, 1.0),
VoxelShapes.cuboid(0.0625, 0.3125, 0.0, 0.25, 0.9375, 1.0),
VoxelShapes.cuboid(0.0625, 0.3125, 0.0625, 0.9375, 0.875, 0.9375)
)
}
init {
defaultState = this.stateManager.defaultState.with(FACING, Direction.NORTH)
.with(WATERLOGGED, false)
.with(ON, false)
.with(TRIGGERED, false)
}
override fun getPlacementState(blockPlaceContext: ItemPlacementContext): BlockState? {
return defaultState
.with(FACING, blockPlaceContext.horizontalPlayerFacing)
.with(WATERLOGGED, blockPlaceContext.world.getFluidState(blockPlaceContext.blockPos).fluid == Fluids.WATER)
.with(ON, false)
}
override fun onBreak(world: World, pos: BlockPos, state: BlockState, player: PlayerEntity?) {
super.onBreak(world, pos, state, player)
// todo dump materials and filterTM on the ground
}
@Deprecated("Deprecated in Java")
override fun neighborUpdate(state: BlockState, world: World, pos: BlockPos, sourceBlock: Block?, sourcePos: BlockPos?, notify: Boolean) {
val bl = world.isReceivingRedstonePower(pos) || world.isReceivingRedstonePower(pos.up())
val bl2 = state.get(TRIGGERED)
if (bl && !bl2) {
world.scheduleBlockTick(pos, this, 4)
world.setBlockState(pos, state.with(TRIGGERED, true) as BlockState, NO_REDRAW)
} else if (!bl && bl2) {
world.setBlockState(pos, state.with(TRIGGERED, false) as BlockState, NO_REDRAW)
}
}
@Deprecated("Deprecated in Java")
override fun scheduledTick(state: BlockState?, world: ServerWorld?, pos: BlockPos?, random: net.minecraft.util.math.random.Random?) {
val inventory = (world!!.getBlockEntity(pos) as TMBlockEntity).tmmInventory
val tmEntity = (world.getBlockEntity(pos) as TMBlockEntity)
if(world == null || pos == null) {
return
}
//val tankEntity = world.getBlockEntity(pos) as MultiblockEntity
if (tmEntity.blockState.get(ON)) {
//print("TMM is in use so scheduled Tick is disabled")
return
}
//this.onTriggerEvent(state, world, pos, random)
// todo if the output slot is empty then try to craft a TM to that slot
if (ItemStack.areItemsEqual(inventory.items!!.get(3), ItemStack.EMPTY)) {
if (state?.let { getInventory(it, world, pos) } != null) {
val itemStack: ItemStack
itemStack = if (inventory.filterTM != null)
inventory.filterTM!!.copy()
else
ItemStack(CobblemonItems.BLANK_TM, 1)
val tm = TechnicalMachines.getTechnicalMachineFromStack(itemStack)
// todo use isReadyToCraftTM to finalize the creation
if (((inventory.filterTM != null && tm != null) && isReadyToCraftTM(state, world, pos, tm)) || isReadyToCraftBlankTM(state, world, pos)) {
// create TM item to the output slot
inventory.items!!.set(3, itemStack)
tmEntity.markDirty()
// Play sound for TM creation
world.playSoundServer(tmEntity.blockPos.toVec3d(), CobblemonSounds.TMM_CRAFT, SoundCategory.BLOCKS)
}
}
}
// todo if there is an item in the output slot then spit it out
else {
if (state?.let { getInventory(it, world, pos) } != null) {
val itemStack = inventory.items!!.get(3)
// Get the direction the block is facing
val facingDirection = state.get(Properties.FACING)?.opposite ?: return
// Calculate the center position of the block
val frontOffset = 0.5 // Half block offset to the front
val spawnX = pos.x + 0.5 + facingDirection.offsetX * frontOffset
val spawnY = pos.y + 0.3 + facingDirection.offsetY * frontOffset
val spawnZ = pos.z + 0.5 + facingDirection.offsetZ * frontOffset
// Create the ItemEntity at the center of the block
val itemEntity = ItemEntity(world, spawnX, spawnY, spawnZ, itemStack).copy()
// Create the ItemEntity
itemEntity.setVelocity(0.0, 0.0, 0.0)
// Add the ItemEntity to the world
world.spawnEntity(itemEntity)
//clear inventory of SidedInventory
inventory.items?.clear()
tmEntity.markDirty()
//getInventory(state, world, pos).clear()
}
}
/*if (state?.let { getInventory(it, world, pos) } != null) {
val itemStack: ItemStack
itemStack = if (inventory.filterTM != null)
inventory.filterTM!!
else
ItemStack(CobblemonItems.BLANK_TM, 1)
val tm = TechnicalMachines.getTechnicalMachineFromStack(itemStack)
// todo use isReadyToCraftTM to finalize the creation
if ((inventory.filterTM != null && isReadyToCraftTM(state, world, pos, tm!!)) || isReadyToCraftBlankTM(state, world, pos)) {
// Get the direction the block is facing
val facingDirection = state.get(Properties.FACING)?.opposite ?: return
// Calculate the center position of the block
val frontOffset = 0.5 // Half block offset to the front
val spawnX = pos.x + 0.5 + facingDirection.offsetX * frontOffset
val spawnY = pos.y + 0.3 + facingDirection.offsetY * frontOffset
val spawnZ = pos.z + 0.5 + facingDirection.offsetZ * frontOffset
// Create the ItemEntity at the center of the block
val itemEntity = ItemEntity(world, spawnX, spawnY, spawnZ, itemStack).copy()
// Create the ItemEntity
itemEntity.setVelocity(0.0, 0.0, 0.0)
// Add the ItemEntity to the world
world.spawnEntity(itemEntity)
//clear inventory of SidedInventory
inventory.items?.clear()
//getInventory(state, world, pos).clear()
}
}*/
}
/*val currentTm = filterTM ?: return sendPacketToServer(CraftBlankTMPacket(handler.input.getStack(2)))
sendPacketToServer(
CraftTMPacket(
currentTm,
handler.input.getStack(0),
handler.input.getStack(1),
handler.input.getStack(2)
)
)*/
@Deprecated("Deprecated in Java")
override fun canPathfindThrough(blockState: BlockState, blockGetter: BlockView, blockPos: BlockPos, pathComputationType: NavigationType) = false
@Deprecated("Deprecated in Java")
override fun hasComparatorOutput(state: BlockState?): Boolean {
return true
}
@Deprecated("Deprecated in Java")
override fun getComparatorOutput(state: BlockState, world: World?, pos: BlockPos?): Int {
if(world == null || pos == null) {
return 0
}
val tmBlockEntity = world.getBlockEntity(pos) as TMBlockEntity
val tm = TechnicalMachines.getTechnicalMachineFromStack(tmBlockEntity.tmmInventory.filterTM)
// if TMM has already crafted something and something is in the output slot do not send signal out
if (!ItemStack.areItemsEqual(tmBlockEntity.tmmInventory.items?.get(3), ItemStack.EMPTY))
return 0
// if the TMM is ready to craft send signal of 15 out
if ((tm != null && isReadyToCraftTM(state, world, pos, tm)) || isReadyToCraftBlankTM(state, world, pos))
return 15
/*if (tmBlockEntity.automationDelay > 0)
tmBlockEntity.automationDelay--
if ((tmBlockEntity.tmmInventory.filterTM != null && isReadyToCraftTM(state, world, pos, tmBlockEntity.tmmInventory.filterTM!!)) || isReadyToCraftBlankTM(state, world, pos)) {
if (tmBlockEntity.automationDelay == 0) {
tmBlockEntity.resetAutomationDelay()
return 15
}
else
return 0
}*/
return 0
}
override fun getInventory(
state: BlockState,
world: WorldAccess,
pos: BlockPos
): SidedInventory {
val tmBlockEntity = world.getBlockEntity(pos) as TMBlockEntity
return tmBlockEntity.tmmInventory
}
override fun appendProperties(builder: StateManager.Builder<Block, BlockState>) {
builder.add(FACING)
builder.add(WATERLOGGED)
builder.add(ON)
builder.add(TRIGGERED)
}
override fun createBlockEntity(pos: BlockPos, state: BlockState): BlockEntity {
return TMBlockEntity(pos, state)
}
@Deprecated("Deprecated in Java")
override fun rotate(blockState: BlockState, rotation: BlockRotation) =
blockState.with(FACING, rotation.rotate(blockState.get(FACING)))
@Deprecated("Deprecated in Java")
override fun mirror(blockState: BlockState, mirror: BlockMirror): BlockState {
return blockState.rotate(mirror.getRotation(blockState.get(FACING)))
}
@Deprecated("Deprecated in Java")
override fun onStateReplaced(state: BlockState, world: World, pos: BlockPos?, newState: BlockState, moved: Boolean) {
if (!state.isOf(newState.block)) super.onStateReplaced(state, world, pos, newState, moved)
}
@Deprecated("Deprecated in Java")
override fun onUse(
blockState: BlockState,
world: World,
pos: BlockPos,
player: PlayerEntity,
interactionHand: Hand,
blockHitResult: BlockHitResult
): ActionResult {
// clear filter TM on client
if (world.isClient) {
val tmBlockEntity = world.getBlockEntity(pos)
val inventory = (tmBlockEntity as TMBlockEntity).tmmInventory
inventory.filterTM = null
return ActionResult.SUCCESS
}
val tmBlockEntity = world.getBlockEntity(pos)
if (tmBlockEntity is TMBlockEntity) {
// Set the block state to ON when the block is used
tmBlockEntity.stateManager.openContainer(player, world, pos, blockState)
player.openHandledScreen(tmBlockEntity as TMBlockEntity?)
}
val inventory = (tmBlockEntity as TMBlockEntity).tmmInventory // (world.getBlockEntity(pos) as TMBlockEntity).tmmInventory
// remove all machine from machine upon use
// inventory.items?.forEach {
// // Get the direction the block is facing
// val facingDirection = blockState.get(Properties.FACING).opposite
//
// // Calculate the center position of the block
// val frontOffset = 0.5 // Half block offset to the front
// val spawnX = pos.x + 0.5 + facingDirection.offsetX * frontOffset
// val spawnY = pos.y + 0.3 + facingDirection.offsetY * frontOffset
// val spawnZ = pos.z + 0.5 + facingDirection.offsetZ * frontOffset
//
// // Create the ItemEntity at the center of the block
// val itemEntity = ItemEntity(world, spawnX, spawnY, spawnZ, it)
//
// // Create the ItemEntity
// itemEntity.setVelocity(0.0, 0.0, 0.0)
//
// // Add the ItemEntity to the world
// world.spawnEntity(itemEntity)
// }
//
// inventory.items?.clear()
// spit out any disc filters
if (inventory.filterTM != null) {
// spit out the filter TM and set filterTM to null
val filterTMStack = inventory.filterTM!!
// Get the direction the block is facing
val facingDirection = blockState.get(Properties.FACING).opposite
// Calculate the center position of the block
val frontOffset = 0.5 // Half block offset to the front
val spawnX = pos.x + 0.5 + facingDirection.offsetX * frontOffset
val spawnY = pos.y + 0.3 + facingDirection.offsetY * frontOffset
val spawnZ = pos.z + 0.5 + facingDirection.offsetZ * frontOffset
// Create the ItemEntity at the center of the block
val itemEntity = ItemEntity(world, spawnX, spawnY, spawnZ, filterTMStack).copy()
// Create the ItemEntity
itemEntity.setVelocity(0.0, 0.0, 0.0)
// Add the ItemEntity to the world
world.spawnEntity(itemEntity)
inventory.filterTM = null
}
val blockEntity = world.getBlockEntity(pos)
if (blockEntity is TMBlockEntity) {
//player.openHandledScreen(blockEntity as TMBlockEntity?)
player.playSound(CobblemonSounds.TMM_ON, SoundCategory.BLOCKS, 1.0f, 1.0f)
// todo maybe uncomment this
//val serverPlayer = player as ServerPlayerEntity
//serverPlayer.openHandledScreen(blockState.createScreenHandlerFactory(world, pos))
}
return ActionResult.CONSUME
}
// override fun createScreenHandlerFactory(
// state: BlockState?,
// world: World?,
// pos: BlockPos?
// ): NamedScreenHandlerFactory {
// return SimpleNamedScreenHandlerFactory(::TMMScreenHandler, Text.of("TM Machine"))
// }
/*fun loadMaterial(itemStack: ItemStack) {
loadedMaterials.add(itemStack)
}*/
fun isReadyToCraftTM(state: BlockState?, world: WorldAccess, pos: BlockPos, tm: TechnicalMachine): Boolean {
val typeGem = Registries.ITEM.get(tm.let { ElementalTypes.get(it.type)?.typeGem }).defaultStack
val recipeItem = Registries.ITEM.get(tm.recipe?.item)
val inventory = state?.let { getInventory(it, world, pos) }
return (inventory!!.count(CobblemonItems.BLANK_TM) == 1
&& inventory.count(typeGem.item) == 1
&& ((inventory.count(recipeItem) == tm.recipe?.count) || (ItemStack.areItemsEqual(recipeItem.defaultStack, ItemStack.EMPTY))))
}
fun isReadyToCraftBlankTM(state: BlockState?, world: WorldAccess, pos: BlockPos): Boolean {
val inventory = state?.let { getInventory(it, world, pos) }
return (inventory!!.count(Items.AMETHYST_SHARD) == 1)
}
/*fun materialNeeded(tm: TechnicalMachine, itemStack: ItemStack): Boolean {
val typeGem = Registries.ITEM.get(ElementalTypes.get(tm.type)?.typeGem).defaultStack
val recipeItem = Registries.ITEM.get(tm.recipe?.item)
// if blank TM is needed still
if ((itemStack !in loadedMaterials && itemStack == CobblemonItems.BLANK_TM.defaultStack))
return true // load in blank TM
// if type gem is needed still
else if ((itemStack !in loadedMaterials && itemStack == typeGem))
return true // load in Type Gem
// if the itemStack is listed as needed in the recipe and the count is not currently met
else if (itemStack.item == recipeItem && loadedMaterials.count { it == itemStack } < tm.recipe?.count!!)
return true
else
return false
}*/
/*fun clearLoadedMaterials() {
loadedMaterials.clear()
}*/
@Deprecated("Deprecated in Java")
override fun getRenderType(blockState: BlockState): BlockRenderType {
return BlockRenderType.MODEL
}
override fun getFluidState(state: BlockState): FluidState? {
return if (state.get(WATERLOGGED)) {
Fluids.WATER.getStill(false)
} else super.getFluidState(state)
}
override fun getOutlineShape(
state: BlockState,
world: BlockView,
pos: BlockPos,
context: ShapeContext
): VoxelShape {
return when (state.get(FACING)) {
Direction.NORTH -> NORTH_OUTLINE
Direction.SOUTH -> SOUTH_OUTLINE
Direction.WEST -> WEST_OUTLINE
else -> EAST_OUTLINE
}
}
}
@@ -0,0 +1,20 @@
package com.cobblemon.mod.common.block
import net.minecraft.block.*
import net.minecraft.util.math.BlockPos
import net.minecraft.world.BlockView
class TypeGemBlock(
settings: Settings,
stage: Int,
height: Int,
xzOffset: Int,
nextStage: Block?,
val baseBlock: Block
) : GrowableStoneBlock(settings, stage, height, xzOffset, nextStage) {
override fun canGrow(pos: BlockPos, world: BlockView): Boolean {
val state = world.getBlockState(pos)
val dir = state.get(FACING).opposite
return (world.getBlockState(pos.offset(dir)).block == baseBlock)
}
}
@@ -0,0 +1,349 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.block.entity
import com.cobblemon.mod.common.CobblemonBlockEntities
import com.cobblemon.mod.common.CobblemonItems
import com.cobblemon.mod.common.api.tms.TechnicalMachine
import com.cobblemon.mod.common.api.tms.TechnicalMachines
import com.cobblemon.mod.common.api.types.ElementalTypes
import com.cobblemon.mod.common.block.TMBlock
import com.cobblemon.mod.common.gui.TMMScreenHandler
import net.minecraft.block.Block
import net.minecraft.block.BlockState
import net.minecraft.block.entity.LockableContainerBlockEntity
import net.minecraft.block.entity.ViewerCountManager
import net.minecraft.entity.player.PlayerEntity
import net.minecraft.entity.player.PlayerInventory
import net.minecraft.inventory.Inventories
import net.minecraft.inventory.Inventory
import net.minecraft.inventory.SidedInventory
import net.minecraft.item.ItemStack
import net.minecraft.item.Items
import net.minecraft.nbt.NbtCompound
import net.minecraft.network.listener.ClientPlayPacketListener
import net.minecraft.network.packet.Packet
import net.minecraft.network.packet.s2c.play.BlockEntityUpdateS2CPacket
import net.minecraft.registry.Registries
import net.minecraft.screen.ScreenHandler
import net.minecraft.text.Text
import net.minecraft.util.collection.DefaultedList
import net.minecraft.util.math.BlockPos
import net.minecraft.util.math.Direction
import net.minecraft.world.World
class TMBlockEntity(
val blockPos: BlockPos,
val blockState: BlockState
) : LockableContainerBlockEntity(CobblemonBlockEntities.TM_BLOCK, blockPos, blockState) {
var tmmInventory = TMBlockInventory(this)
var automationDelay: Int = AUTOMATION_DELAY
var partialTicks = 0.0f
val stateManager: ViewerCountManager = object : ViewerCountManager() {
override fun onContainerOpen(world: World, pos: BlockPos, state: BlockState) {
this@TMBlockEntity.setOpen(state, true)
}
override fun onContainerClose(world: World, pos: BlockPos, state: BlockState) {
this@TMBlockEntity.setOpen(state, false)
}
override fun onViewerCountUpdate(world: World, pos: BlockPos, state: BlockState, oldViewerCount: Int, newViewerCount: Int) {}
override fun isPlayerViewing(player: PlayerEntity): Boolean {
if (player.currentScreenHandler is TMMScreenHandler) {
val inventory = (player.currentScreenHandler as TMMScreenHandler).inventory
return inventory === this@TMBlockEntity
}
return false
}
}
companion object {
const val AUTOMATION_DELAY = 4
const val FILTER_TM_NBT = "FilterTM"
}
fun setOpen(state: BlockState, open: Boolean) {
world!!.setBlockState(getPos(), state.with(TMBlock.ON, open), Block.NOTIFY_ALL)
}
fun tick() {
if (!removed) {
stateManager.updateViewerCount(getWorld(), getPos(), cachedState)
}
}
//var filterTM: TechnicalMachine? = null
//private var inventory: DefaultedList<ItemStack> = DefaultedList.ofSize(size(), ItemStack.EMPTY)
/*override fun size(): Int { return 3 }
override fun getContainerName(): Text {
return Text.translatable("container.tmblock")
}
override fun getInvStackList(): DefaultedList<ItemStack> {
return inventory
}
override fun setInvStackList(list: DefaultedList<ItemStack>?) {
if (list != null) {
this.inventory = list
}
}*/
fun resetAutomationDelay() {
automationDelay = AUTOMATION_DELAY
}
fun materialNeeded(tm: TechnicalMachine?, slot: Int, itemStack: ItemStack): Boolean {
val typeGem = Registries.ITEM.get(tm?.type?.let { ElementalTypes.get(it)?.typeGem }).defaultStack
val recipeItem = Registries.ITEM.get(tm?.recipe?.item)
//val inventory = tmmInventory.inventory
val inventory = tmmInventory.items
//inventory.count { it.value == CobblemonItems.BLANK_TM.defaultStack }
//ItemStack.areEqual()
if (inventory != null) {
if (tmmInventory.filterTM != null) {
// if blank TM is needed still
if (slot == 0 && (inventory.none { it?.count == 1 && it.item == CobblemonItems.BLANK_TM }) && ItemStack.areEqual(itemStack, ItemStack(CobblemonItems.BLANK_TM, 1)))
return true // load in blank TM
// if type gem is needed still
else if (slot == 1 && inventory.none { ItemStack.areEqual(it, typeGem) } && ItemStack.areEqual(itemStack, typeGem))
return true // load in Type Gem
// if the itemStack is listed as needed in the recipe and the count is not currently met
else if (slot == 2 && inventory.none { it?.count == tm?.recipe?.count && ItemStack.areItemsEqual(it, ItemStack(recipeItem, 1)) } && ItemStack.areEqual(itemStack, ItemStack(recipeItem, 1)))
return true
else
return false
}
else if (tmmInventory.filterTM == null && ItemStack.areItemsEqual(itemStack,Items.AMETHYST_SHARD.defaultStack)) {
return (slot == 2 && inventory.none { it?.count == 1 && ItemStack.areItemsEqual(it, Items.AMETHYST_SHARD.defaultStack) })
}
}
return false
}
override fun toInitialChunkDataNbt(): NbtCompound {
val res = NbtCompound()
writeNbt(res)
return res
}
override fun clear() {
tmmInventory.clear()
}
override fun size(): Int {
return this.tmmInventory.size()
}
override fun isEmpty(): Boolean {
return this.tmmInventory.isEmpty()
}
override fun getStack(slot: Int): ItemStack {
return this.tmmInventory.getStack(slot)
}
override fun removeStack(slot: Int, amount: Int): ItemStack {
return this.tmmInventory.removeStack(slot, amount)
}
override fun removeStack(slot: Int): ItemStack {
return this.tmmInventory.removeStack(slot)
}
override fun setStack(slot: Int, stack: ItemStack?) {
return this.tmmInventory.setStack(slot, stack)
}
override fun canPlayerUse(player: PlayerEntity?): Boolean {
return this.tmmInventory.canPlayerUse(player)
}
override fun getContainerName(): Text {
return Text.translatable("container.brewing")
}
override fun createScreenHandler(syncId: Int, playerInventory: PlayerInventory?): ScreenHandler {
return TMMScreenHandler(syncId, playerInventory!!, this.tmmInventory, this)
}
override fun toUpdatePacket(): Packet<ClientPlayPacketListener>? {
return BlockEntityUpdateS2CPacket.create(this)
}
override fun writeNbt(nbt: NbtCompound) {
super.writeNbt(nbt)
Inventories.writeNbt(nbt, tmmInventory.items)
val filterTmCompound = tmmInventory.filterTM?.writeNbt(NbtCompound())
if (filterTmCompound != null)
nbt.put(FILTER_TM_NBT, filterTmCompound)
}
override fun readNbt(nbt: NbtCompound) {
super.readNbt(nbt)
Inventories.readNbt(nbt, tmmInventory.items)
if (nbt.contains(FILTER_TM_NBT)) {
val itemStack = CobblemonItems.TECHNICAL_MACHINE.defaultStack
tmmInventory.filterTM = ItemStack.fromNbt(nbt.getCompound(FILTER_TM_NBT))
val test = 2
}
}
override fun markDirty() {
super.markDirty()
if (this.world != null && !this.world!!.isClient) {
val currentState = world!!.getBlockState(pos)
world!!.setBlockState(pos, currentState, 3) // Flags: 2 | 1 = Block update | Render update
this.world!!.updateNeighborsAlways(this.pos, this.cachedState.block)
}
}
class TMBlockInventory(val tmBlockEntity: TMBlockEntity) : SidedInventory {
private val BLANK_DISC_SLOT_INDEX = 0
private val GEM_SLOT_INDEX = 1
private val MISC_SLOT_INDEX = 2
private val OUTPUT_SLOT_INDEX = 3
private val INPUT_SLOTS = intArrayOf(0, 1, 2, 3)
val entityPos = this.tmBlockEntity.blockPos
val entityState = this.tmBlockEntity.blockState
val entityWorld = this.tmBlockEntity.world
var filterTM: ItemStack? = null
//var inventory: MutableMap<Int, ItemStack?> = mutableMapOf(0 to ItemStack.EMPTY, 1 to ItemStack.EMPTY, 2 to ItemStack.EMPTY)
var items: DefaultedList<ItemStack?>? = DefaultedList.ofSize(4, ItemStack.EMPTY)
fun hasFilterTM(): Boolean {
return filterTM != null
}
override fun clear() {
tmBlockEntity.markDirty()
this.items?.clear()
}
override fun size(): Int {
return this.items?.size ?: 0;
}
/*fun getInvSize(): Int {
return size()
}*/
fun getInvStack(slot: Int): ItemStack {
return items?.get(slot) ?: ItemStack.EMPTY
}
override fun isEmpty(): Boolean {
for (i in 0 until size()) {
val stack: ItemStack = getInvStack(i)
if (!stack.isEmpty) {
return false
}
}
return true
}
/*override fun isEmpty(): Boolean {
return !inventory.any { it.value != ItemStack.EMPTY }
}*/
override fun getStack(slot: Int): ItemStack {
return items?.get(slot) ?: ItemStack.EMPTY
}
override fun getAvailableSlots(side: Direction?): IntArray? {
return if (side == Direction.DOWN) {
return listOf(this.OUTPUT_SLOT_INDEX).toIntArray()
}
else this.INPUT_SLOTS
// val result = this.items?.size?.let { IntArray(it) }
// if (result != null) {
// for (i in result.indices) {
// result[i] = i
// }
// }
// return result
}
override fun removeStack(slot: Int, amount: Int): ItemStack {
tmBlockEntity.markDirty()
return Inventories.splitStack(items, slot, amount)
}
override fun removeStack(slot: Int): ItemStack {
val slotStack = items?.get(slot)
items?.set(slot, ItemStack.EMPTY)
tmBlockEntity.markDirty()
return slotStack ?: ItemStack.EMPTY
}
override fun setStack(slot: Int, stack: ItemStack?) {
items?.set(slot, stack)
tmBlockEntity.markDirty()
}
override fun markDirty() {
if (tmBlockEntity.world != null)
tmBlockEntity.markDirty()
}
override fun canPlayerUse(player: PlayerEntity?): Boolean {
return Inventory.canPlayerUse(this.tmBlockEntity, player)
}
/*override fun getAvailableSlots(side: Direction?): IntArray {
return IntArray(3)
}*/
override fun canInsert(slot: Int, stack: ItemStack?, dir: Direction?): Boolean {
if (this.entityState.get(TMBlock.ON)) {
// print("TMM is in use so canInsert is disabled")
return false
}
if (stack != null && slot < this.INPUT_SLOTS.size) {
val tm = TechnicalMachines.getTechnicalMachineFromStack(tmBlockEntity.tmmInventory.filterTM)
// if material is needed then load it
if (tmBlockEntity.materialNeeded(tm, slot, stack) && (ItemStack.areEqual(items?.get(slot) ?: ItemStack.EMPTY, ItemStack.EMPTY) || ItemStack.areItemsEqual(items?.get(slot) ?: ItemStack.EMPTY, stack))) {
//tmBlockEntity.loadMaterial(stack)
return true
}
else
return false
}
return false
}
override fun canExtract(slot: Int, stack: ItemStack?, dir: Direction?): Boolean {
if (this.entityState.get(TMBlock.ON)) {
//print("TMM is in use so canExtract is disabled")
return false
}
return dir == Direction.DOWN && slot == this.OUTPUT_SLOT_INDEX
}
}
}
@@ -62,6 +62,7 @@ object CobblemonBakingOverrides {
cobblemonModel("restoration_tank_connector", "none")
)
fun registerOverride(modelLocation: Identifier, modelIdentifier: ModelIdentifier): BakingOverride {
val result = BakingOverride(modelLocation, modelIdentifier)
models.add(result)
@@ -18,9 +18,12 @@ import com.cobblemon.mod.common.CobblemonEntities
import com.cobblemon.mod.common.CobblemonItems
import com.cobblemon.mod.common.api.scheduling.ClientTaskTracker
import com.cobblemon.mod.common.api.text.gray
import com.cobblemon.mod.common.api.types.ElementalTypes
import com.cobblemon.mod.common.client.battle.ClientBattle
import com.cobblemon.mod.common.client.gui.PartyOverlay
import com.cobblemon.mod.common.client.gui.battle.BattleOverlay
import com.cobblemon.mod.common.client.gui.modstation.ModStationHandledScreen
import com.cobblemon.mod.common.client.gui.tm.TMMHandledScreen
import com.cobblemon.mod.common.client.particle.BedrockParticleEffectRepository
import com.cobblemon.mod.common.client.render.block.BerryBlockRenderer
import com.cobblemon.mod.common.client.render.block.FossilAnalyzerRenderer
@@ -28,6 +31,7 @@ import com.cobblemon.mod.common.client.render.block.RestorationTankRenderer
import com.cobblemon.mod.common.client.render.block.GildedChestBlockRenderer
import com.cobblemon.mod.common.client.render.block.HealingMachineRenderer
import com.cobblemon.mod.common.client.render.block.*
import com.cobblemon.mod.common.client.render.block.TMBlockRenderer
import com.cobblemon.mod.common.client.render.boat.CobblemonBoatRenderer
import com.cobblemon.mod.common.client.render.generic.GenericBedrockRenderer
import com.cobblemon.mod.common.client.render.item.CobblemonBuiltinItemRendererRegistry
@@ -46,14 +50,19 @@ import com.cobblemon.mod.common.client.storage.ClientStorageManager
import com.cobblemon.mod.common.client.trade.ClientTrade
import com.cobblemon.mod.common.data.CobblemonDataProvider
import com.cobblemon.mod.common.entity.boat.CobblemonBoatType
import com.cobblemon.mod.common.gui.CobblemonScreenHandlers
import com.cobblemon.mod.common.item.PokeBallItem
import com.cobblemon.mod.common.item.TechnicalMachineItem
import com.cobblemon.mod.common.client.render.models.blockbench.repository.FossilModelRepository
import com.cobblemon.mod.common.client.render.models.blockbench.repository.GenericBedrockEntityModelRepository
import com.cobblemon.mod.common.client.render.models.blockbench.repository.MiscModelRepository
import com.cobblemon.mod.common.platform.events.PlatformEvents
import com.cobblemon.mod.common.util.DataKeys
import com.cobblemon.mod.common.util.asTranslated
import net.minecraft.client.color.block.BlockColorProvider
import net.minecraft.client.color.item.ItemColorProvider
import net.minecraft.client.gui.DrawContext
import net.minecraft.client.gui.screen.ingame.HandledScreens
import net.minecraft.client.render.RenderLayer
import net.minecraft.client.render.block.entity.HangingSignBlockEntityRenderer
import net.minecraft.client.render.block.entity.SignBlockEntityRenderer
@@ -107,9 +116,10 @@ object CobblemonClient {
this.registerBlockEntityRenderers()
registerBlockRenderTypes()
//registerColors()
registerColors()
registerFlywheelRenderers()
this.registerEntityRenderers()
registerHandledScreens()
Berries.observable.subscribe {
BerryModelRepository.patchModels()
}
@@ -149,21 +159,24 @@ object CobblemonClient {
// .apply()
}
/*
fun registerColors() {
this.implementation.registerBlockColors(BlockColorProvider { _, _, _, _ ->
return@BlockColorProvider 0xE0A33A
}, CobblemonBlocks.APRICORN_LEAVES)
this.implementation.registerItemColors(ItemColorProvider { _, _ ->
this.implementation.registerItemColors(ItemColorProvider { stack, tint ->
return@ItemColorProvider 0xE0A33A
}, CobblemonItems.APRICORN_LEAVES)
}, CobblemonItems.TECHNICAL_MACHINE)
this.implementation.registerItemColors(TechnicalMachineItem::getItemColor, CobblemonItems.TECHNICAL_MACHINE)
}
*/
private fun registerBlockRenderTypes() {
this.implementation.registerBlockRenderType(RenderLayer.getCutoutMipped(), CobblemonBlocks.APRICORN_LEAVES)
this.implementation.registerBlockRenderType(RenderLayer.getTranslucent(), CobblemonBlocks.TM_MACHINE)
this.implementation.registerBlockRenderType(
RenderLayer.getCutout(),
CobblemonBlocks.GILDED_CHEST,
@@ -251,6 +264,7 @@ object CobblemonClient {
this.implementation.registerBlockEntityRenderer(CobblemonBlockEntities.HANGING_SIGN, ::HangingSignBlockEntityRenderer)
this.implementation.registerBlockEntityRenderer(CobblemonBlockEntities.FOSSIL_ANALYZER, ::FossilAnalyzerRenderer)
this.implementation.registerBlockEntityRenderer(CobblemonBlockEntities.RESTORATION_TANK, ::RestorationTankRenderer)
this.implementation.registerBlockEntityRenderer(CobblemonBlockEntities.TM_BLOCK, ::TMBlockRenderer)
this.implementation.registerBlockEntityRenderer(CobblemonBlockEntities.GILDED_CHEST, ::GildedChestBlockRenderer)
this.implementation.registerBlockEntityRenderer(CobblemonBlockEntities.DISPLAY_CASE, ::DisplayCaseRenderer)
}
@@ -306,4 +320,15 @@ object CobblemonClient {
}
}
private fun registerHandledScreens() {
HandledScreens.register(
CobblemonScreenHandlers.TMM_SCREEN,
::TMMHandledScreen
)
HandledScreens.register(
CobblemonScreenHandlers.MOD_STATION_SCREEN,
::ModStationHandledScreen
)
}
}
@@ -0,0 +1,48 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.client.gui
import com.cobblemon.mod.common.api.gui.blitk
import com.cobblemon.mod.common.api.types.ElementalType
import com.cobblemon.mod.common.util.cobblemonResource
import net.minecraft.client.gui.DrawContext
import net.minecraft.client.util.math.MatrixStack
class TypeReturnIcon(
val x: Number,
val y: Number,
val centeredX: Boolean = false,
val small: Boolean = false,
val secondaryOffset: Float = 15F,
val doubleCenteredOffset: Float = 7.5F,
val opacity: Float = 1F
) {
companion object {
private const val TYPE_ICON_DIAMETER = 36
private const val SCALE = 0.5F
private val typeReturnResource = cobblemonResource("textures/gui/type_return.png")
private val smallTypeReturnResource = cobblemonResource("textures/gui/type_return_small.png")
}
fun render(context: DrawContext) {
val diameter = if (small) (TYPE_ICON_DIAMETER / 2) else TYPE_ICON_DIAMETER
blitk(
matrixStack = context.matrices,
texture = if (small) smallTypeReturnResource else typeReturnResource,
x = (x.toFloat()) / SCALE - 9,
y = y.toFloat() / SCALE,
height = diameter,
width = diameter,
alpha = opacity,
scale = SCALE
)
}
}
@@ -0,0 +1,28 @@
package com.cobblemon.mod.common.client.gui.modstation
import com.cobblemon.mod.common.gui.ModStationScreenHandler
import net.minecraft.client.gui.DrawContext
import net.minecraft.client.gui.screen.ingame.HandledScreen
import net.minecraft.entity.player.PlayerInventory
import net.minecraft.item.ItemStack
import net.minecraft.screen.ScreenHandler
import net.minecraft.screen.ScreenHandlerListener
import net.minecraft.text.Text
class ModStationHandledScreen(
val handler: ModStationScreenHandler,
val inventory: PlayerInventory,
title: Text?
) : HandledScreen<ModStationScreenHandler>(handler, inventory, title), ScreenHandlerListener {
override fun drawBackground(context: DrawContext?, delta: Float, mouseX: Int, mouseY: Int) {
}
override fun onSlotUpdate(handler: ScreenHandler?, slotId: Int, stack: ItemStack?) {
}
override fun onPropertyUpdate(handler: ScreenHandler?, property: Int, value: Int) {
}
}
@@ -0,0 +1,37 @@
package com.cobblemon.mod.common.client.gui.tm
import com.cobblemon.mod.common.api.gui.blitk
import com.cobblemon.mod.common.util.cobblemonResource
import net.minecraft.client.gui.DrawContext
import net.minecraft.client.gui.widget.ButtonWidget
import net.minecraft.client.sound.SoundManager
import net.minecraft.text.Text
class DiscButton(
pX: Int, pY: Int,
onPress: PressAction,
): ButtonWidget(pX, pY, WIDTH.toInt(), HEIGHT.toInt(), Text.literal("All Types"), onPress, DEFAULT_NARRATION_SUPPLIER) {
companion object {
private const val WIDTH = 53F
private const val HEIGHT = 53F
val DISC_BUTTON = cobblemonResource("textures/gui/tm/disc_button.png")
}
override fun renderButton(context: DrawContext, pMouseX: Int, pMouseY: Int, pPartialTicks: Float) {
blitk(
matrixStack = context.matrices,
texture = DISC_BUTTON,
x = x,
y = y,
width = WIDTH,
height = HEIGHT,
vOffset = if (isHovered(pMouseX.toDouble(), pMouseY.toDouble())) HEIGHT else 0,
textureHeight = HEIGHT * 2
)
}
override fun playDownSound(soundManager: SoundManager) {}
fun isHovered(mouseX: Double, mouseY: Double) = mouseX.toFloat() in (x.toFloat()..(x.toFloat() + WIDTH)) && mouseY.toFloat() in (y.toFloat()..(y.toFloat() + HEIGHT))
}
@@ -0,0 +1,54 @@
package com.cobblemon.mod.common.client.gui.tm
import com.cobblemon.mod.common.api.gui.blitk
import com.cobblemon.mod.common.util.cobblemonResource
import net.minecraft.client.gui.DrawContext
import net.minecraft.client.gui.widget.ButtonWidget
import net.minecraft.client.sound.SoundManager
import net.minecraft.text.Text
class EjectButton(
pX: Int, pY: Int,
val small: Boolean = false,
onPress: PressAction
): ButtonWidget(
pX,
pY,
if (small) SMALL_WIDTH.toInt() else LARGE_WIDTH.toInt(),
if (small) SMALL_HEIGHT.toInt() else LARGE_HEIGHT.toInt(),
Text.literal("Eject"),
onPress,
DEFAULT_NARRATION_SUPPLIER
) {
companion object {
private const val LARGE_WIDTH = 54F
private const val LARGE_HEIGHT = 14F
private const val SMALL_WIDTH = 14F
private const val SMALL_HEIGHT = 14F
val SMALL_BUTTON = cobblemonResource("textures/gui/tm/eject_button_small.png")
val LARGE_BUTTON = cobblemonResource("textures/gui/tm/eject_button_large.png")
}
val height = if (small) SMALL_HEIGHT else LARGE_HEIGHT
val width = if (small) SMALL_WIDTH else LARGE_WIDTH
val texture = if (small) SMALL_BUTTON else LARGE_BUTTON
override fun renderButton(context: DrawContext, pMouseX: Int, pMouseY: Int, pPartialTicks: Float) {
blitk(
matrixStack = context.matrices,
texture = texture,
x = x,
y = y,
width = width,
height = height,
vOffset = if (isHovered(pMouseX.toDouble(), pMouseY.toDouble())) height else 0,
textureHeight = height * 2
)
}
override fun playDownSound(soundManager: SoundManager) {}
fun isHovered(mouseX: Double, mouseY: Double) = mouseX.toFloat() in (x.toFloat()..(x.toFloat() + width)) && mouseY.toFloat() in (y.toFloat()..(y.toFloat() + height))
}
@@ -0,0 +1,59 @@
package com.cobblemon.mod.common.client.gui.tm
import com.cobblemon.mod.common.CobblemonItems
import com.cobblemon.mod.common.api.gui.blitk
import com.cobblemon.mod.common.api.tms.TechnicalMachine
import com.cobblemon.mod.common.client.render.drawScaledText
import com.cobblemon.mod.common.client.render.renderScaledGuiItemIcon
import com.cobblemon.mod.common.util.cobblemonResource
import net.minecraft.client.gui.DrawContext
import net.minecraft.client.gui.widget.ButtonWidget
import net.minecraft.client.sound.SoundManager
import net.minecraft.text.Text
class TMListingButton(
pX: Int, pY: Int,
onPress: PressAction,
val tm: TechnicalMachine
): ButtonWidget(pX, pY, WIDTH.toInt(), HEIGHT.toInt(), Text.literal("All Types"), onPress, DEFAULT_NARRATION_SUPPLIER) {
companion object {
private const val HEIGHT = 20F
private const val WIDTH = 140F
val TM_LISTING_BUTTON = cobblemonResource("textures/gui/tm/tm_selection_listing.png")
}
override fun renderButton(context: DrawContext, pMouseX: Int, pMouseY: Int, pPartialTicks: Float) {
blitk(
matrixStack = context.matrices,
texture = TM_LISTING_BUTTON,
x = x,
y = y,
width = WIDTH,
height = HEIGHT,
vOffset = if (isHovered(pMouseX.toDouble(), pMouseY.toDouble())) HEIGHT else 0,
textureHeight = HEIGHT * 2
)
val item = CobblemonItems.TECHNICAL_MACHINE
renderScaledGuiItemIcon(
itemStack = item.setNbt(item.defaultStack, tm.id().toString()),
x = x.toDouble() + 2,
y = y.toDouble() + 2
)
drawScaledText(
context = context,
text = tm.translatedMoveName(),
x = x + 25,
y = y + 7.5,
scale = 0.75f
)
}
override fun playDownSound(soundManager: SoundManager) {}
fun isHovered(mouseX: Double, mouseY: Double) = mouseX.toFloat() in (x.toFloat()..(x.toFloat() + WIDTH)) && mouseY.toFloat() in (y.toFloat()..(y.toFloat() + HEIGHT))
}
@@ -0,0 +1,611 @@
package com.cobblemon.mod.common.client.gui.tm
import com.cobblemon.mod.common.CobblemonItems
import com.cobblemon.mod.common.CobblemonNetwork.sendPacketToServer
import com.cobblemon.mod.common.CobblemonSounds
import com.cobblemon.mod.common.api.gui.ColourLibrary
import com.cobblemon.mod.common.api.gui.MultiLineLabelK
import com.cobblemon.mod.common.api.gui.blitk
import com.cobblemon.mod.common.api.moves.Moves
import com.cobblemon.mod.common.api.reactive.SettableObservable
import com.cobblemon.mod.common.api.text.bold
import com.cobblemon.mod.common.api.tms.TechnicalMachine
import com.cobblemon.mod.common.api.tms.TechnicalMachineRecipe
import com.cobblemon.mod.common.api.types.ElementalType
import com.cobblemon.mod.common.api.types.ElementalTypes
import com.cobblemon.mod.common.block.TMBlock
import com.cobblemon.mod.common.block.entity.TMBlockEntity
import com.cobblemon.mod.common.client.CobblemonClient
import com.cobblemon.mod.common.client.gui.ExitButton
import com.cobblemon.mod.common.client.gui.MoveCategoryIcon
import com.cobblemon.mod.common.client.gui.TypeIcon
import com.cobblemon.mod.common.client.render.drawScaledText
import com.cobblemon.mod.common.client.render.renderScaledGuiItemIcon
import com.cobblemon.mod.common.gui.TMMScreenHandler
import com.cobblemon.mod.common.net.messages.client.ui.CraftBlankTMPacket
import com.cobblemon.mod.common.net.messages.client.ui.CraftTMPacket
import com.cobblemon.mod.common.pokemon.Pokemon
import com.cobblemon.mod.common.pokemon.activestate.PokemonState
import com.cobblemon.mod.common.util.cobblemonResource
import com.cobblemon.mod.common.util.lang
import net.minecraft.client.gui.DrawContext
import net.minecraft.client.gui.Drawable
import net.minecraft.client.gui.Element
import net.minecraft.client.gui.Selectable
import net.minecraft.client.gui.screen.ingame.HandledScreen
import net.minecraft.entity.player.PlayerInventory
import net.minecraft.item.ItemStack
import net.minecraft.item.Items
import net.minecraft.registry.Registries
import net.minecraft.screen.ScreenHandler
import net.minecraft.screen.ScreenHandlerListener
import net.minecraft.text.Text
import net.minecraft.util.Identifier
class TMMHandledScreen(
val handler: TMMScreenHandler,
val inventory: PlayerInventory,
title: Text?
) : HandledScreen<TMMScreenHandler>(handler, inventory, title), ScreenHandlerListener {
companion object {
val TEXTURE_HEIGHT = 222
val TEXTURE_WIDTH = 254
val TYPE_MENU_MODE = 1
val TM_BROWSING_MODE = 2
val TYPE_SELECTION_BASE = cobblemonResource("textures/gui/tm/type_selection_base.png")
val TM_SELECTION_BASE = cobblemonResource("textures/gui/tm/tm_selection_base.png")
val TM_SELECTION_BORDER = cobblemonResource("textures/gui/tm/tm_selection_border.png")
val TM_SELECTION_LISTING = cobblemonResource("textures/gui/tm/tm_selection_listing.png")
val EJECT_BUTTON_SMALL = cobblemonResource("textures/gui/tm/eject_button_small.png")
val EJECT_BUTTON_LARGE = cobblemonResource("textures/gui/tm/eject_button_large.png")
val PARTY_SLOT = cobblemonResource("textures/gui/tm/party_slot.png")
val TEACH_BUTTON = cobblemonResource("textures/gui/tm/teach_button.png")
}
// val selectedTM: TechnicalMachine? = TechnicalMachines.tmMap[cobblemonResource("thunderbolt")]!!
var selectedTM: TechnicalMachine? = null
var tmList: SettableObservable<MutableList<TechnicalMachine>> = SettableObservable(mutableListOf())
var output: ItemStack? = null
val children: MutableMap<String, Element> = mutableMapOf()
var mode: Int = TYPE_MENU_MODE
var sortType: ElementalType? = null
var selectedPokemon: Pokemon? = null
var scroll: TMScrollingList? = null
init {
scroll = TMScrollingList(
x = x + 132,
y = y + 45,
parent = this
)
}
// val selectedTM = TechnicalMachine("stompingtantrum", null, emptyList(), "ground", null, null)
/**
* Used instead of `addDrawableChild()` to avoid re-drawing children.
*/
private fun <T> addChild(drawableElement: T, identifier: String) where T : Element, T : Drawable, T : Selectable {
if (children.contains(identifier)) return
addDrawableChild(drawableElement)
children[identifier] = drawableElement
}
override fun mouseClicked(mouseX: Double, mouseY: Double, button: Int): Boolean {
if (scroll?.isHovered(mouseX, mouseY) == true) {
scroll!!.mouseClicked(mouseX, mouseY, button)
}
return super.mouseClicked(mouseX, mouseY, button)
}
override fun mouseScrolled(mouseX: Double, mouseY: Double, amount: Double): Boolean {
if (scroll?.isHovered(mouseX, mouseY) == true) {
scroll!!.mouseScrolled(mouseX, mouseY, amount)
return true
}
return false
}
override fun mouseDragged(mouseX: Double, mouseY: Double, button: Int, deltaX: Double, deltaY: Double): Boolean {
if (mode != TYPE_MENU_MODE) scroll?.mouseDragged(
mouseX,
mouseY,
button,
deltaX,
deltaY
)
return super.mouseDragged(mouseX, mouseY, button, deltaX, deltaY)
}
fun drawBlankCraftingRecipe(context: DrawContext) {
val x = (width - TEXTURE_WIDTH) / 2
val y = (height - TEXTURE_HEIGHT) / 2
// ingredient
renderScaledGuiItemIcon(
itemStack = Items.AMETHYST_SHARD.defaultStack,
x = (x + 197 + 36).toDouble(),
y = (y + 127).toDouble(),
zTranslation = 1f
)
drawScaledText(
context = context,
text = lang("ui.tms.material_cost"),
x = (x + 223),
y = (y + 117.5),
scale = 0.5f,
centered = true
)
drawScaledText(
context = context,
text = Text.translatable(CobblemonItems.BLANK_TM.translationKey).bold(),
x = (x + 223),
y = (y + 12),
scale = 0.5f,
centered = true
)
drawScaledText(
context = context,
text = lang("ui.power"),
x = (x + 199),
y = (y + 25),
scale = 0.5f
)
drawScaledText(
context = context,
text = Text.literal("-"),
x = (x + 241),
y = (y + 25),
scale = 0.5f,
centered = true
)
drawScaledText(
context = context,
text = lang("ui.accuracy_short"),
x = (x + 199),
y = (y + 35),
scale = 0.5f
)
drawScaledText(
context = context,
text = Text.literal("-"),
x = (x + 241),
y = (y + 35),
scale = 0.5f,
centered = true
)
drawScaledText(
context = context,
text = lang("ui.pp"),
x = (x + 199),
y = (y + 45),
scale = 0.5f
)
drawScaledText(
context = context,
text = Text.literal("-"),
x = (x + 241),
y = (y + 45),
scale = 0.5f,
centered = true
)
drawScaledText(
context = context,
text = lang("ui.summary.title"),
x = (x + 199),
y = (y + 54.5),
scale = 0.5f
)
val scale = 0.5f
context.matrices.push()
context.matrices.scale(scale, scale, 1f)
MultiLineLabelK.create(
component = lang("ui.tms.blank_tm_desc"),
width = 49 / scale,
maxLines = 7
).renderLeftAligned(
context = context,
x = (x + 199) / scale,
y = (y + 62) / scale,
ySpacing = 5.5 / scale,
colour = ColourLibrary.WHITE,
shadow = true
)
context.matrices.pop()
}
fun drawMoveInfo(context: DrawContext, delta: Float, mouseX: Int, mouseY: Int) {
val currentTm = selectedTM
if (currentTm == null) {
return drawBlankCraftingRecipe(context)
}
val x = (width - TEXTURE_WIDTH) / 2
val y = (height - TEXTURE_HEIGHT) / 2
val move = Moves.getByNameOrDummy(currentTm.moveName)
// blank tm
renderScaledGuiItemIcon(
itemStack = CobblemonItems.BLANK_TM.defaultStack,
x = (x + 197).toDouble(),
y = (y + 127).toDouble(),
)
val typeGem = Registries.ITEM.get(ElementalTypes.get(currentTm.type)?.typeGem).defaultStack
// type gem
renderScaledGuiItemIcon(
itemStack = typeGem ?: ItemStack.EMPTY,
x = (x + 197 + 18).toDouble(),
y = (y + 127).toDouble(),
)
val recipe = currentTm.recipe ?: TechnicalMachineRecipe(Identifier.of("minecraft", "air")!!, 1)
// ingredient
renderScaledGuiItemIcon(
itemStack = Registries.ITEM.get(recipe.item).defaultStack,
x = (x + 197 + 36).toDouble(),
y = (y + 127).toDouble(),
zTranslation = 1f
)
context.matrices.push()
context.matrices.translate(0f, 0f, 2f)
if (recipe.count > 1) {
val xIncrease = if (recipe.count < 10) 47 else 41
drawScaledText(
context = context,
text = Text.literal(recipe.count.toString()),
x = (x + 197 + xIncrease).toDouble(),
y = (y + 136).toDouble(),
shadow = true
)
}
context.matrices.pop()
drawScaledText(
context = context,
text = lang("ui.tms.material_cost"),
x = (x + 223),
y = (y + 117.5),
scale = 0.5f,
centered = true
)
drawScaledText(
context = context,
text = currentTm.translatedMoveName().bold(),
x = (x + 223),
y = (y + 12),
scale = 0.5f,
centered = true
)
MoveCategoryIcon(
x = (x + 237.5),
y = (y + 52.5),
category = Moves.getByNameOrDummy(currentTm.moveName).damageCategory
).render(context)
drawScaledText(
context = context,
text = lang("ui.power"),
x = (x + 199),
y = (y + 25),
scale = 0.5f
)
drawScaledText(
context = context,
text = Text.literal(move.power.toInt().toString()),
x = (x + 241),
y = (y + 25),
scale = 0.5f,
centered = true
)
drawScaledText(
context = context,
text = lang("ui.accuracy_short"),
x = (x + 199),
y = (y + 35),
scale = 0.5f
)
drawScaledText(
context = context,
text = Text.literal(move.accuracy.toInt().toString() + "%"),
x = (x + 241),
y = (y + 35),
scale = 0.5f,
centered = true
)
drawScaledText(
context = context,
text = lang("ui.pp"),
x = (x + 199),
y = (y + 45),
scale = 0.5f
)
drawScaledText(
context = context,
text = Text.literal(move.pp.toString()),
x = (x + 241),
y = (y + 45),
scale = 0.5f,
centered = true
)
drawScaledText(
context = context,
text = lang("ui.summary.title"),
x = (x + 199),
y = (y + 54.5),
scale = 0.5f
)
val scale = 0.5f
context.matrices.push()
context.matrices.scale(scale, scale, 1f)
MultiLineLabelK.create(
component = lang("move.${currentTm.moveName}.desc"),
width = 49 / scale,
maxLines = 7
).renderLeftAligned(
context = context,
x = (x + 199) / scale,
y = (y + 62) / scale,
ySpacing = 5.5 / scale,
colour = ColourLibrary.WHITE,
shadow = true
)
context.matrices.pop()
}
fun drawTypeMenu(context: DrawContext, delta: Float, mouseX: Int, mouseY: Int) {
val x = (width - TEXTURE_WIDTH) / 2
val y = (height - TEXTURE_HEIGHT) / 2
blitk(
matrixStack = context.matrices,
texture = TYPE_SELECTION_BASE,
x = x, // horizontal placement of GUI
y = y, // vertical placement of GUI
width = TEXTURE_WIDTH, // scale of the GUI width
height = TEXTURE_HEIGHT // scale of the GUI height
)
fun drawTypeRow(drawX: Int, drawY: Int, types: List<ElementalType>) {
var xOffset = 0
for (type in types) {
addChild(TypeButton(
pX = drawX + 32 + xOffset,
pY = drawY + 16,
type = type,
onPress = {
inventory.player.playSound(CobblemonSounds.GUI_CLICK, 1f, 1f)
tmList.set(TechnicalMachine.filterTms(null, type, null).toMutableList())
sortType = type
mode = TM_BROWSING_MODE
clearGUI()
scroll?.scrollAmount = 0.0
}
), "${type.name}type")
xOffset += 24
}
}
drawTypeRow(x, y, listOf(
ElementalTypes.NORMAL,
ElementalTypes.FIRE,
ElementalTypes.WATER,
ElementalTypes.GRASS,
ElementalTypes.ELECTRIC,
ElementalTypes.ICE
))
drawTypeRow(x + 12, y + 24, listOf(
ElementalTypes.FIGHTING,
ElementalTypes.POISON,
ElementalTypes.GROUND,
ElementalTypes.FLYING,
))
drawTypeRow(x, y + 48, listOf(
ElementalTypes.PSYCHIC,
ElementalTypes.BUG,
ElementalTypes.ROCK,
ElementalTypes.GHOST,
))
drawTypeRow(x + 12, y + 72, listOf(
ElementalTypes.DRAGON,
ElementalTypes.DARK,
ElementalTypes.STEEL,
ElementalTypes.FAIRY,
))
addChild(
DiscButton(
pX = x + 134,
pY = y + 50,
onPress = {
inventory.player.playSound(CobblemonSounds.GUI_CLICK, 1f, 1f)
tmList.set(TechnicalMachine.filterTms(null, null, null).toMutableList())
mode = TM_BROWSING_MODE
sortType = null
scroll?.scrollAmount = 0.0
clearGUI()
}
), "disc"
)
}
fun drawTmSelectMenu(context: DrawContext, delta: Float, mouseX: Int, mouseY: Int) {
val x = (width - TEXTURE_WIDTH) / 2
val y = (height - TEXTURE_HEIGHT) / 2
blitk(
matrixStack = context.matrices,
texture = TM_SELECTION_BASE,
x = x, // horizontal placement of GUI
y = y, // vertical placement of GUI
width = TEXTURE_WIDTH, // scale of the GUI width
height = TEXTURE_HEIGHT // scale of the GUI height
)
blitk(
matrixStack = context.matrices,
texture = TM_SELECTION_BORDER,
x = x + 31, // horizontal placement of GUI
y = y + 14, // vertical placement of GUI
width = 157,
height = 101
)
val displayType = sortType
addChild(
TypeButton(
pX = x + 31,
pY = y + 16,
type = displayType,
onPress = {
mode = TYPE_MENU_MODE
inventory.player.playSound(CobblemonSounds.GUI_CLICK, 1f, 1f)
clearGUI()
}
), "returnTypeMenu"
)
scroll?.render(context, mouseX, mouseY, delta)
}
fun clearGUI() {
val iterator = children.iterator()
while (iterator.hasNext()) {
val (id, _) = iterator.next()
iterator.remove()
children.remove(id)
}
clearChildren()
}
override fun drawBackground(context: DrawContext, delta: Float, mouseX: Int, mouseY: Int) {
super.renderBackground(context)
val x = (width - TEXTURE_WIDTH) / 2
val y = (height - TEXTURE_HEIGHT) / 2
blitk(
matrixStack = context.matrices,
texture = TYPE_SELECTION_BASE,
x = x, // horizontal placement of GUI
y = y, // vertical placement of GUI
width = TEXTURE_WIDTH, // scale of the GUI width
height = TEXTURE_HEIGHT // scale of the GUI height
)
when (mode) {
TYPE_MENU_MODE -> drawTypeMenu(context, delta, mouseX, mouseY)
else -> drawTmSelectMenu(context, delta, mouseX, mouseY)
}
drawMoveInfo(context, delta, mouseX, mouseY)
inventory.markDirty()
addChild(
EjectButton(
pX = x + 196,
pY = y + 168,
small = false,
onPress = {
inventory.player.playSound(CobblemonSounds.GUI_CLICK, 1f, 1f)
val currentTm = selectedTM ?: return@EjectButton sendPacketToServer(CraftBlankTMPacket(handler.input.getStack(2)))
sendPacketToServer(
CraftTMPacket(
currentTm,
handler.input.getStack(0),
handler.input.getStack(1),
handler.input.getStack(2)
)
)
this.handler.syncState()
}
), "eject"
)
addChild(
ExitButton(
pX = x + 228,
pY = y + 185,
onPress = {
this.close()
}
), "exit"
)
val startY = y + 13
val offset = 28
var iterations = 0
CobblemonClient.storage.myParty.forEach { pokemon ->
if (pokemon != null) {
addChild(TMPartySlotWidget(
pX = x - 23,
pY = startY + (offset * iterations),
pokemon = pokemon,
onPress = {
selectedPokemon = if (selectedPokemon == pokemon) null else pokemon
}
), "partyslot_${pokemon.uuid}")
}
iterations++
}
}
override fun drawForeground(context: DrawContext?, mouseX: Int, mouseY: Int) {
//Text is usually drawn here, we dont want that
this.drawMouseoverTooltip(context, mouseX - 158, mouseY - 28)
//this.renderWithTooltip(context, mouseX, mouseY, 1F)
}
override fun onSlotUpdate(handler: ScreenHandler?, slotId: Int, stack: ItemStack?) {
}
override fun close() {
super.close()
val inventory = handler.inventory
if (inventory is TMBlockEntity.TMBlockInventory) {
inventory.tmBlockEntity.blockState.with(TMBlock.ON,false)
}
}
override fun onPropertyUpdate(handler: ScreenHandler?, property: Int, value: Int) {
}
}
@@ -0,0 +1,20 @@
package com.cobblemon.mod.common.client.gui.tm
import com.cobblemon.mod.common.gui.TMMScreenHandler
import com.cobblemon.mod.common.util.giveOrDropItemStack
import net.minecraft.entity.player.PlayerEntity
import net.minecraft.inventory.Inventory
import net.minecraft.item.ItemStack
import net.minecraft.item.Items
import net.minecraft.screen.slot.Slot
class TMMOutputSlot(val screen: TMMScreenHandler, index: Int, x: Int, y: Int) : Slot(screen.playerInventory, index, x, y) {
override fun canInsert(stack: ItemStack?) = false
override fun onTakeItem(player: PlayerEntity, stack: ItemStack) {
player.giveOrDropItemStack(stack, false)
this.stack = Items.AIR.defaultStack
}
}
@@ -0,0 +1,106 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.client.gui.tm
import com.cobblemon.mod.common.api.gui.blitk
import com.cobblemon.mod.common.api.text.text
import com.cobblemon.mod.common.client.gui.drawProfilePokemon
import com.cobblemon.mod.common.client.render.drawScaledText
import com.cobblemon.mod.common.pokemon.Pokemon
import com.cobblemon.mod.common.util.cobblemonResource
import com.cobblemon.mod.common.util.math.fromEulerXYZDegrees
import net.minecraft.client.gui.DrawContext
import net.minecraft.client.gui.widget.ButtonWidget
import net.minecraft.text.Text
import org.joml.Quaternionf
import org.joml.Vector3f
class TMPartySlotWidget(
pX: Number,
pY: Number,
val pokemon: Pokemon?,
onPress: PressAction
) : ButtonWidget(pX.toInt(), pY.toInt(), WIDTH, HEIGHT, Text.literal("PartyMember"), onPress, NarrationSupplier { "".text() }) {
companion object {
const val WIDTH = 46
const val HEIGHT = 27
private const val PORTRAIT_DIAMETER = 25
private val slotResource = cobblemonResource("textures/gui/tm/party_slot.png")
val genderIconMale = cobblemonResource("textures/gui/party/party_gender_male.png")
val genderIconFemale = cobblemonResource("textures/gui/party/party_gender_female.png")
}
private fun getSlotVOffset(pokemon: Pokemon?, isHovered: Boolean, isSelected: Boolean): Int {
if (isHovered || isSelected) {
if (pokemon == null) {
return 0
}
return height
}
return 0
}
override fun renderButton(context: DrawContext, mouseX: Int, mouseY: Int, delta: Float) {
hovered = mouseX >= x && mouseY >= y && mouseX < x + width && mouseY < y + height;
val matrices = context.matrices
blitk(
matrixStack = matrices,
texture = slotResource,
x = x,
y = y,
width = width,
height = height,
vOffset = getSlotVOffset(pokemon, isHovered, isSelected),
textureHeight = height * 2,
)
if (pokemon != null) {
val halfScale = 0.5F
// Render Pokémon
matrices.push()
matrices.translate(x + (PORTRAIT_DIAMETER / 2.0) + 10, y - 1.0, 0.0)
matrices.scale(2.5F, 2.5F, 1F)
drawProfilePokemon(
species = pokemon.species.resourceIdentifier,
aspects = pokemon.aspects.toSet(),
matrixStack = matrices,
rotation = Quaternionf().fromEulerXYZDegrees(Vector3f(13F, 35F, 0F)),
state = null,
scale = 4.5F,
partialTicks = delta
)
matrices.pop()
// Draw Name
drawScaledText(
context = context,
text = pokemon.getDisplayName(),
x = x + 16,
y = y + 21.5,
scale = halfScale
)
val ballIcon = cobblemonResource("textures/gui/ball/" + pokemon.caughtBall.name.path + ".png")
val ballHeight = 22
blitk(
matrixStack = matrices,
texture = ballIcon,
x = (x - 2) / halfScale,
y = (y - 3) / halfScale,
height = ballHeight,
width = 18,
textureHeight = ballHeight * 2,
scale = halfScale
)
}
}
}
@@ -0,0 +1,158 @@
package com.cobblemon.mod.common.client.gui.tm
import com.cobblemon.mod.common.CobblemonSounds
import com.cobblemon.mod.common.api.tms.TechnicalMachine
import net.minecraft.client.MinecraftClient
import net.minecraft.client.gui.DrawContext
import net.minecraft.client.gui.widget.AlwaysSelectedEntryListWidget
import net.minecraft.text.Text
class TMScrollingList(
val x: Int,
val y: Int,
val parent: TMMHandledScreen
) : AlwaysSelectedEntryListWidget<TMScrollingList.TMScrollingListEntry> (
MinecraftClient.getInstance(),
WIDTH, // width
HEIGHT, // height
0, // top
HEIGHT, // bottom
SLOT_HEIGHT// + SLOT_SPACING
) {
companion object {
const val WIDTH = 140
const val HEIGHT = 78
const val SLOT_WIDTH = 140
const val SLOT_HEIGHT = 20
const val SLOT_SPACING = 3
const val SCALE = 0.5f
}
private var scrolling = false
override fun getRowWidth() = SLOT_WIDTH
init {
correctSize()
setRenderHorizontalShadows(false)
setRenderBackground(false)
setRenderSelection(false)
parent.tmList.subscribeIncludingCurrent { tmList ->
val currentEntries = children()
val newTMs = tmList.filter { tm -> currentEntries.none { it.tm.id() == tm.id() } }
val removedTMs = currentEntries.filter { entry -> tmList.none { it.id() == entry.tm.id() } }
removedTMs.forEach(this::removeEntry)
newTMs.forEach { tm -> addEntry(TMScrollingListEntry(tm, parent)) }
}
}
override fun getScrollbarPositionX() = left + width - 3
private fun correctSize() {
updateSize(
WIDTH,
HEIGHT, y - 2, (y + 2) + (HEIGHT - 2))
setLeftPos(x)
}
public override fun addEntry(entry: TMScrollingListEntry) = super.addEntry(entry)
public override fun removeEntry(entry: TMScrollingListEntry) = super.removeEntry(entry)
override fun render(context: DrawContext, mouseX: Int, mouseY: Int, delta: Float) {
correctSize()
context.enableScissor(
left,
top + 5,
left + width,
top + 1 + height
)
super.render(context, mouseX, mouseY, delta)
context.disableScissor()
}
fun isHovered(mouseX: Double, mouseY: Double): Boolean {
println(mouseX.toFloat() in (x.toFloat()..(x.toFloat() + WIDTH)) && mouseY.toFloat() in (y.toFloat()..(y.toFloat() + HEIGHT)))
return mouseX.toFloat() in (x.toFloat()..(x.toFloat() + WIDTH)) && mouseY.toFloat() in (y.toFloat()..(y.toFloat() + HEIGHT))
}
override fun mouseClicked(mouseX: Double, mouseY: Double, button: Int): Boolean {
updateScrollingState(mouseX, mouseY)
if (scrolling) {
focused = getEntryAtPosition(mouseX, mouseY)
isDragging = true
}
return super.mouseClicked(mouseX, mouseY, button)
}
override fun mouseDragged(mouseX: Double, mouseY: Double, button: Int, deltaX: Double, deltaY: Double): Boolean {
if (scrolling) {
if (mouseY < top) {
scrollAmount = 0.0
} else if (mouseY > bottom) {
scrollAmount = maxScroll.toDouble()
} else {
scrollAmount += deltaY
}
}
return super.mouseDragged(mouseX, mouseY, button, deltaX, deltaY)
}
private fun updateScrollingState(mouseX: Double, mouseY: Double) {
scrolling = mouseX >= this.scrollbarPositionX.toDouble()
&& mouseX < (this.scrollbarPositionX + 3).toDouble()
&& mouseY >= top
&& mouseY < bottom
}
class TMScrollingListEntry(val tm: TechnicalMachine, private val parent: TMMHandledScreen) : Entry<TMScrollingListEntry>() {
private val tmButton: TMListingButton = TMListingButton(
pX = 0,
pY = 0,
onPress = {
parent.selectedTM = tm
parent.inventory.player.playSound(CobblemonSounds.GUI_CLICK, 1f, 1f)
},
tm = tm
)
override fun render(
context: DrawContext,
index: Int,
rowTop: Int,
rowLeft: Int,
rowWidth: Int,
rowHeight: Int,
mouseX: Int,
mouseY: Int,
isHovered: Boolean,
tickDelta: Float
) {
val x = rowLeft
val y = rowTop
val matrixStack = context.matrices
// Render just this TMListingButton
tmButton.setPosition(x + 1, y)
tmButton.render(context, mouseX, mouseY, tickDelta)
}
override fun mouseClicked(mouseX: Double, mouseY: Double, delta: Int): Boolean {
if (tmButton.isHovered(mouseX, mouseY)) {
tmButton.onPress()
return true
}
return false
}
override fun getNarration(): Text {
TODO("Not yet implemented")
}
}
}
@@ -0,0 +1,69 @@
package com.cobblemon.mod.common.client.gui.tm
import com.cobblemon.mod.common.CobblemonSounds
import com.cobblemon.mod.common.api.gui.blitk
import com.cobblemon.mod.common.api.types.ElementalType
import com.cobblemon.mod.common.client.gui.TypeIcon
import com.cobblemon.mod.common.client.gui.TypeReturnIcon
import com.cobblemon.mod.common.util.cobblemonResource
import net.minecraft.client.gui.DrawContext
import net.minecraft.client.gui.widget.ButtonWidget
import net.minecraft.client.sound.SoundInstance
import net.minecraft.client.sound.SoundManager
class TypeButton(
pX: Int, pY: Int,
onPress: PressAction,
val type: ElementalType?
): ButtonWidget(pX, pY, WIDTH.toInt(), HEIGHT.toInt(), type?.displayName, onPress, DEFAULT_NARRATION_SUPPLIER) {
companion object {
private const val WIDTH = 24F
private const val HEIGHT = 24F
val TYPE_BUTTON = cobblemonResource("textures/gui/tm/type_button.png")
}
override fun renderButton(context: DrawContext, pMouseX: Int, pMouseY: Int, pPartialTicks: Float) {
blitk(
matrixStack = context.matrices,
texture = TYPE_BUTTON,
x = x,
y = y,
width = WIDTH,
height = HEIGHT,
vOffset = if (isHovered(pMouseX.toDouble(), pMouseY.toDouble())) HEIGHT else 0,
textureHeight = HEIGHT * 2
)
context.matrices.push()
context.matrices.scale(2f, 2f, 2f)
if (type != null) {
TypeIcon(
x = (x + 12.125) / 2,
y = (y + 3) / 2,
type = type,
centeredX = true,
small = true
).render(context)
}
else {
TypeReturnIcon(
x = (x + 12.125) / 2,
y = (y + 3) / 2,
centeredX = true,
small = true
).render(context)
}
context.matrices.pop()
}
override fun playDownSound(soundManager: SoundManager) {
}
fun isHovered(mouseX: Double, mouseY: Double) = mouseX.toFloat() in (x.toFloat()..(x.toFloat() + WIDTH)) && mouseY.toFloat() in (y.toFloat()..(y.toFloat() + HEIGHT))
}
@@ -0,0 +1,30 @@
package com.cobblemon.mod.common.client.net.gui
import com.cobblemon.mod.common.CobblemonItems
import com.cobblemon.mod.common.CobblemonSounds
import com.cobblemon.mod.common.api.net.ServerNetworkPacketHandler
import com.cobblemon.mod.common.gui.TMMScreenHandler
import com.cobblemon.mod.common.net.messages.client.ui.CraftBlankTMPacket
import com.cobblemon.mod.common.util.playSoundServer
import net.minecraft.item.Items
import net.minecraft.server.MinecraftServer
import net.minecraft.server.network.ServerPlayerEntity
import net.minecraft.sound.SoundCategory
object CraftBlankTMPacketHandler : ServerNetworkPacketHandler<CraftBlankTMPacket> {
override fun handle(packet: CraftBlankTMPacket, server: MinecraftServer, player: ServerPlayerEntity) {
val screen = player.currentScreenHandler as TMMScreenHandler
val ingredientSlot = screen.input.getStack(2)
if (ingredientSlot.isOf(Items.AMETHYST_SHARD) && ingredientSlot.count >= 1) {
screen.input.removeStack(2, 1)
screen.result.setStack(0, CobblemonItems.BLANK_TM.defaultStack)
screen.input.markDirty()
screen.result.markDirty()
player.currentScreenHandler.syncState()
player.world.playSoundServer(player.pos, CobblemonSounds.TMM_CRAFT_BLANK, SoundCategory.BLOCKS)
}
}
}
@@ -0,0 +1,60 @@
package com.cobblemon.mod.common.client.net.gui
import com.cobblemon.mod.common.CobblemonItems
import com.cobblemon.mod.common.CobblemonSounds
import com.cobblemon.mod.common.api.net.ServerNetworkPacketHandler
import com.cobblemon.mod.common.api.types.ElementalTypes
import com.cobblemon.mod.common.gui.TMMScreenHandler
import com.cobblemon.mod.common.item.TechnicalMachineItem
import com.cobblemon.mod.common.net.messages.client.ui.CraftTMPacket
import com.cobblemon.mod.common.util.playSoundServer
import net.minecraft.item.Items
import net.minecraft.registry.Registries
import net.minecraft.server.MinecraftServer
import net.minecraft.server.network.ServerPlayerEntity
import net.minecraft.sound.SoundCategory
object CraftTMPacketHandler : ServerNetworkPacketHandler<CraftTMPacket> {
override fun handle(packet: CraftTMPacket, server: MinecraftServer, player: ServerPlayerEntity) {
val screen = player.currentScreenHandler as TMMScreenHandler
val discSlot = screen.inventory?.getStack(0)
val gemSlot = screen.inventory?.getStack(1)
val ingredientSlot = screen.inventory?.getStack(2)
val outputSlot = screen.result.getStack(0)
val typeGem = Registries.ITEM.get(ElementalTypes.get(packet.tm.type)?.typeGem)
print("test")
if (!outputSlot.isEmpty) return
if (discSlot != null) {
if (!discSlot.isOf(CobblemonItems.BLANK_TM)) return
}
if (gemSlot != null) {
if (!gemSlot.isOf(typeGem)) return
}
if (packet.tm.recipe != null) {
if (ingredientSlot != null) {
if (!ingredientSlot.isOf(Registries.ITEM.get(packet.tm.recipe.item))) return
}
if (ingredientSlot != null) {
if (ingredientSlot.count < packet.tm.recipe.count) return
}
}
val item = CobblemonItems.TECHNICAL_MACHINE.defaultStack
item.getOrCreateNbt().putString(TechnicalMachineItem.STORED_MOVE_KEY, packet.tm.id().toString())
screen.result.setStack(0, item)
screen.inventory?.removeStack(0, 1)
screen.inventory?.removeStack(1, 1)
if (packet.tm.recipe != null) {
screen.inventory?.removeStack(2, packet.tm.recipe.count)
}
screen.input.markDirty()
screen.result.markDirty()
player.currentScreenHandler.syncState()
player.world.playSoundServer(player.pos, CobblemonSounds.TMM_CRAFT, SoundCategory.BLOCKS)
}
}
@@ -0,0 +1,13 @@
package com.cobblemon.mod.common.client.net.gui
import com.cobblemon.mod.common.api.net.ClientNetworkPacketHandler
import com.cobblemon.mod.common.net.messages.client.ui.InteractPokemonUIPacket
import com.cobblemon.mod.common.net.messages.client.ui.OpenTMMPacket
import net.minecraft.client.MinecraftClient
object OpenTMMPacketHandler : ClientNetworkPacketHandler<OpenTMMPacket>
{
override fun handle(packet: OpenTMMPacket, client: MinecraftClient) {
//client.setScreen()
}
}
@@ -0,0 +1,78 @@
package com.cobblemon.mod.common.client.render.block
import com.cobblemon.mod.common.api.text.blue
import com.cobblemon.mod.common.api.text.green
import com.cobblemon.mod.common.api.text.red
import com.cobblemon.mod.common.api.tms.TechnicalMachines
import com.cobblemon.mod.common.api.types.ElementalTypes
import com.cobblemon.mod.common.block.TMBlock
import com.cobblemon.mod.common.block.entity.TMBlockEntity
import com.cobblemon.mod.common.client.CobblemonBakingOverrides
import com.cobblemon.mod.common.client.render.layer.CobblemonRenderLayers
import com.cobblemon.mod.common.client.render.models.blockbench.repository.MiscModelRepository
import com.cobblemon.mod.common.client.render.models.blockbench.setRotation
import com.cobblemon.mod.common.util.cobblemonResource
import com.cobblemon.mod.common.util.math.geometry.Axis
import net.minecraft.client.MinecraftClient
import net.minecraft.client.render.LightmapTextureManager
import net.minecraft.client.render.OverlayTexture
import net.minecraft.client.render.RenderLayer
import net.minecraft.client.render.VertexConsumerProvider
import net.minecraft.client.render.block.entity.BlockEntityRenderer
import net.minecraft.client.render.block.entity.BlockEntityRendererFactory
import net.minecraft.client.util.math.MatrixStack
import net.minecraft.util.math.Direction
import net.minecraft.util.math.RotationAxis
import java.awt.Color
import kotlin.math.sin
class TMBlockRenderer(context: BlockEntityRendererFactory.Context) : BlockEntityRenderer<TMBlockEntity> {
//TODO Do the render optimizations that we do for berries and fossils
override fun render(
entity: TMBlockEntity,
tickDelta: Float,
matrices: MatrixStack,
vertexConsumers: VertexConsumerProvider,
light: Int,
overlay: Int
) {
val diskModel = MiscModelRepository.modelOf(MODEL_ID)
matrices.push()
val tm = entity.tmmInventory.filterTM?.let {
TechnicalMachines.getTechnicalMachineFromStack(
it
)
}
entity.partialTicks += tickDelta
val color = tm?.let { Color(ElementalTypes.get(it.type)!!.hue) } ?: Color.WHITE
when (entity.cachedState.get(TMBlock.FACING)) {
Direction.SOUTH -> matrices.translate(15F / 16F, 5.5F / 16F, 1F / 16F)
Direction.WEST -> matrices.translate(14F / 16F, 5.5F / 16F, 0F)
Direction.EAST -> matrices.translate(1F, 5.5F / 16F, 0F)
else -> matrices.translate(15F / 16F, 5.5F / 16F, -1F / 16F)
}
matrices.translate(-7.0/16f, 0.0, 8.0/16f)
matrices.multiply(RotationAxis.POSITIVE_Y.rotationDegrees( entity.partialTicks / 0.5f))
matrices.translate(7.0/16f, 0.0, -8.0/16f)
val renderLayer = RenderLayer.getEntityCutout(cobblemonResource("textures/block/tm_machine.png"))
diskModel?.render(
matrices,
vertexConsumers.getBuffer(renderLayer),
light,
overlay,
color.red.toFloat() / 255F,
color.green.toFloat() / 255F,
color.blue.toFloat() / 255F,
1.0F
)
matrices.pop()
}
companion object {
val MODEL_ID = cobblemonResource("tm_disk.geo")
}
}
@@ -40,6 +40,27 @@ object CobblemonRenderLayers {
multiPhaseParameters
)
}
val TM_BLOCK_LAYER = run {
val multiPhaseParameters = RenderLayer.MultiPhaseParameters.builder()
.lightmap(ENABLE_LIGHTMAP)
.program(CUTOUT_PROGRAM)
.texture(Texture(
cobblemonResource("textures/misc/tm_machine"),
false,
true
))
.cull(DISABLE_CULLING)
.build(true)
RenderLayer.of(
"tm_block",
VertexFormats.POSITION_COLOR_TEXTURE_LIGHT_NORMAL,
VertexFormat.DrawMode.QUADS,
512,
true,
false,
multiPhaseParameters
)
}
val ENTITY_TRANSLUCENT: BiFunction<Identifier, Boolean, RenderLayer> = Util.memoize { texture: Identifier, affectsOutline: kotlin.Boolean ->
var multiPhaseParameters: RenderLayer.MultiPhaseParameters =
@@ -19,6 +19,9 @@ import com.cobblemon.mod.common.api.scheduling.ServerTaskTracker
import com.cobblemon.mod.common.api.scheduling.taskBuilder
import com.cobblemon.mod.common.api.text.green
import com.cobblemon.mod.common.api.text.red
import com.cobblemon.mod.common.api.text.text
import com.cobblemon.mod.common.api.tms.TechnicalMachine
import com.cobblemon.mod.common.api.tms.TechnicalMachines
import com.cobblemon.mod.common.battles.BattleFormat
import com.cobblemon.mod.common.battles.BattleRegistry
import com.cobblemon.mod.common.battles.BattleSide
@@ -60,7 +63,12 @@ object TestCommand {
return Command.SINGLE_SUCCESS
}
for (id in Cobblemon.playerData.get(context.source.playerOrThrow).tmSet) {
context.source.player?.sendMessage(TechnicalMachines.tmMap[id]?.translatedMoveName())
}
try {
filter(context)
// readBerryDataFromCSV()
// this.testClosestBattle(context)
@@ -108,6 +116,12 @@ object TestCommand {
var trade: ActiveTrade? = null
var lastDebugId = 0
private fun filter(context: CommandContext<ServerCommandSource>) {
val tms = TechnicalMachine.filterTms("fire", null, null)
println(context.source.playerOrThrow.party().get(1)?.getDisplayName())
tms.forEach { context.source.playerOrThrow.sendMessage(it.moveName.text()) }
}
private fun testClosestBattle(context: CommandContext<ServerCommandSource>) {
val player = context.source.playerOrThrow
val cloneTeam = player.party().toBattleTeam(true)
@@ -29,6 +29,7 @@ import com.cobblemon.mod.common.api.pokemon.feature.SpeciesFeatures
import com.cobblemon.mod.common.api.spawning.CobblemonSpawnPools
import com.cobblemon.mod.common.api.spawning.CobblemonSpawnRules
import com.cobblemon.mod.common.api.spawning.SpawnDetailPresets
import com.cobblemon.mod.common.api.tms.TechnicalMachines
import com.cobblemon.mod.common.battles.BagItems
import com.cobblemon.mod.common.net.messages.client.data.UnlockReloadPacket
import com.cobblemon.mod.common.platform.events.PlatformEvents
@@ -75,6 +76,7 @@ object CobblemonDataProvider : DataProvider {
CobblemonSpawnPools.load()
this.register(Berries)
this.register(TechnicalMachines)
PlatformEvents.SERVER_PLAYER_LOGOUT.subscribe {
synchronizedPlayerIds.remove(it.player.uuid)
@@ -9,7 +9,9 @@
package com.cobblemon.mod.common.events
import com.cobblemon.mod.common.Cobblemon
import com.cobblemon.mod.common.api.tms.TechnicalMachines
import com.cobblemon.mod.common.battles.BattleRegistry
import com.cobblemon.mod.common.item.TechnicalMachineItem
import com.cobblemon.mod.common.util.party
import net.minecraft.server.MinecraftServer
@@ -25,9 +27,21 @@ object ServerTickHandler {
if (secondsTick == 20) {
secondsTick = 0
// Party tick
// Code to run every in-game second
for (player in server.playerManager.playerList) {
player.party().onSecondPassed(player)
TechnicalMachines.checkPassives(player)
// Give player tm unlocks for tms they don't already have
repeat(player.inventory.size()) {
val stack = player.inventory.getStack(it)
if (stack.item is TechnicalMachineItem) {
val tm = TechnicalMachineItem.getMoveNbt(stack) ?: return@repeat
if (!Cobblemon.playerData.get(player).tmSet.contains(tm.id())) {
tm.unlock(player)
}
}
}
}
}
}
@@ -0,0 +1,25 @@
package com.cobblemon.mod.common.gui
import com.cobblemon.mod.common.Cobblemon
import com.cobblemon.mod.common.mixin.invoker.ScreenHandlerTypeInvoker
import com.cobblemon.mod.common.util.cobblemonResource
import net.minecraft.registry.Registries
import net.minecraft.resource.featuretoggle.FeatureFlags
import net.minecraft.screen.ScreenHandlerType.Factory
import net.minecraft.resource.featuretoggle.FeatureSet
import net.minecraft.screen.ScreenHandler
import net.minecraft.screen.ScreenHandlerType
import net.minecraft.util.Identifier
object CobblemonScreenHandlers {
val TMM_SCREEN = register(cobblemonResource("tmm_screen"), ::TMMScreenHandler)
val MOD_STATION_SCREEN = register(cobblemonResource("mod_station_screen"), ::ModStationScreenHandler)
fun <T : ScreenHandler> register(identifier: Identifier, factory: Factory<T>): ScreenHandlerType<T> {
val result = ScreenHandlerTypeInvoker.`cobblemon$create`(factory, FeatureFlags.VANILLA_FEATURES)
Cobblemon.implementation.registerScreenHandlerType(identifier, result)
return result
}
}
@@ -0,0 +1,60 @@
package com.cobblemon.mod.common.gui
import net.minecraft.entity.player.PlayerEntity
import net.minecraft.entity.player.PlayerInventory
import net.minecraft.inventory.*
import net.minecraft.item.ItemStack
import net.minecraft.screen.ScreenHandler
import net.minecraft.screen.slot.CraftingResultSlot
import net.minecraft.screen.slot.Slot
class ModStationScreenHandler(syncId: Int) : ScreenHandler(CobblemonScreenHandlers.MOD_STATION_SCREEN, syncId) {
var playerInventory: PlayerInventory? = null
var input: RecipeInputInventory = CraftingInventory(this, 2, 1)
val result: CraftingResultInventory = CraftingResultInventory()
var inventory: Inventory? = null
constructor(syncId: Int, playerInventory: PlayerInventory) : this(syncId, playerInventory, SimpleInventory(3))
constructor(syncId: Int, playerInventory: PlayerInventory, inventory: Inventory) : this(syncId) {
val startX = 0 - 9
val startY = 112
val xLen = 18 // 18 is standard
val yLen = 18 // 18 is standard
this.playerInventory = playerInventory
this.inventory = inventory
for (row in 0..2) {
for (column in 0..8) {
this.addSlot(Slot(playerInventory, 9 + (row * 9) + column, startX + (xLen * column), startY + (yLen * row)))
}
}
for (column in 0..8) {
this.addSlot(Slot(playerInventory, column, startX + (xLen * column), startY + 58))
}
addSlot(CraftingResultSlot(
playerInventory.player,
input,
result,
0,
startX,
startY
))
this.addSlot(Slot(this.inventory, 0, startX, startY - 20))
this.addSlot(Slot(this.inventory, 1, startX, startY - 40))
}
override fun quickMove(player: PlayerEntity?, slot: Int): ItemStack {
TODO("Not yet implemented")
}
override fun canUse(player: PlayerEntity?): Boolean {
return inventory?.canPlayerUse(player) ?: false
}
override fun syncState() {
super.syncState()
}
}
@@ -0,0 +1,139 @@
package com.cobblemon.mod.common.gui
import com.cobblemon.mod.common.CobblemonItems
import com.cobblemon.mod.common.block.entity.TMBlockEntity
import net.minecraft.block.BlockState
import net.minecraft.entity.player.PlayerEntity
import net.minecraft.entity.player.PlayerInventory
import net.minecraft.inventory.*
import net.minecraft.item.ItemStack
import net.minecraft.screen.ScreenHandler
import net.minecraft.screen.slot.CraftingResultSlot
import net.minecraft.screen.slot.Slot
import net.minecraft.screen.slot.SlotActionType
import net.minecraft.util.math.BlockPos
import net.minecraft.world.World
class TMMScreenHandler(syncId: Int) : ScreenHandler(CobblemonScreenHandlers.TMM_SCREEN, syncId) {
var playerInventory: PlayerInventory? = null
var input: RecipeInputInventory = CraftingInventory(this, 3, 1)
val result: CraftingResultInventory = CraftingResultInventory()
var tmmEntity: TMBlockEntity? = null
var inventory: Inventory? = null
constructor(syncId: Int, playerInventory: PlayerInventory) : this(syncId, playerInventory, SimpleInventory(4), null) {
}
constructor(syncId: Int, playerInventory: PlayerInventory, inventory: Inventory, blockEntity: TMBlockEntity?) : this(syncId) {
val startX = 0 - 9
val startY = 112
val xLen = 18 // 18 is standard
val yLen = 18 // 18 is standard
this.playerInventory = playerInventory
this.inventory = inventory // as TMBlockEntity.TMBlockInventory) // this does grab the right inventory slots
tmmEntity = blockEntity
if (inventory is TMBlockEntity.TMBlockInventory) {
//inventory.tmBlockEntity
this.syncState()
/*this.inventory = inventory
this.tmmEntity = (inventory as TMBlockEntity.TMBlockInventory).tmBlockEntity
// sync the input slots with the TMM slots
input.setStack(0, inventory.items!!.get(0))
input.setStack(1, inventory.items!!.get(1))
input.setStack(2, inventory.items!!.get(2))
//inventory.items!![3] = result.getStack(0) // sync output of TMM with the crafted TM
result.setStack(0, inventory.items!!.get(3))*/
}
for (row in 0..2) {
for (column in 0..8) {
this.addSlot(Slot(playerInventory, 9 + (row * 9) + column, startX + (xLen * column), startY + (yLen * row)))
}
}
for (column in 0..8) {
this.addSlot(Slot(playerInventory, column, startX + (xLen * column), startY + 58))
}
this.addSlot(CraftingResultSlot(
playerInventory.player,
input,
result,
0,
startX + 123,
startY - 22
))
this.addSlot(Slot(this.inventory, 0, startX + 167, startY + 9)) // material input slot 1
this.addSlot(Slot(this.inventory, 1, startX + 185, startY + 9)) // material input slot 2
this.addSlot(Slot(this.inventory, 2, startX + 203, startY + 9)) // material input slot 3
}
override fun quickMove(player: PlayerEntity, slot: Int): ItemStack {
return if (insertItem(getSlot(slot).stack, 0, SLOT_COUNT, true)) getSlot(slot).stack else ItemStack.EMPTY
}
override fun canUse(player: PlayerEntity?): Boolean {
return inventory?.canPlayerUse(player) ?: false
}
// override fun onClosed(player: PlayerEntity) {
//// for (i in 0..2) {
//// if (!slots[i].stack.isEmpty) player.giveOrDropItemStack(slots[i].stack, false)
//// }
// super.onClosed(player)
// }
override fun onSlotClick(slotIndex: Int, button: Int, actionType: SlotActionType?, player: PlayerEntity) {
val type = if (actionType == SlotActionType.THROW) SlotActionType.PICKUP else actionType // todo issue might be inventory is not being clicked, but it is index 36 still
// if slot is the output slot then clear the TMM output slot
if (slotIndex == 36) {
this.inventory?.setStack(3, ItemStack.EMPTY)
}
super.onSlotClick(slotIndex, button, type, player)
}
override fun onClosed(player: PlayerEntity?) {
super.onClosed(player)
tmmEntity?.stateManager?.closeContainer(player, tmmEntity!!.world, tmmEntity!!.blockPos, tmmEntity!!.blockState)
}
override fun syncState() {
if (inventory is TMBlockEntity.TMBlockInventory) {
//inventory.tmBlockEntity
// sync the input slots with the TMM slots
input.setStack(0, (inventory as TMBlockEntity.TMBlockInventory).items!!.get(0))
input.setStack(1, (inventory as TMBlockEntity.TMBlockInventory).items!!.get(1))
input.setStack(2, (inventory as TMBlockEntity.TMBlockInventory).items!!.get(2))
//inventory.items!![3] = result.getStack(0) // sync output of TMM with the crafted TM
// if there is something in the output slot of this.inventory then sync that with result
if ((inventory as TMBlockEntity.TMBlockInventory).items?.get(3) != ItemStack.EMPTY) {
if (ItemStack.areItemsEqual((inventory as TMBlockEntity.TMBlockInventory).items?.get(3), ItemStack(CobblemonItems.TECHNICAL_MACHINE, 1))
|| ItemStack.areItemsEqual((inventory as TMBlockEntity.TMBlockInventory).items?.get(3), ItemStack(CobblemonItems.BLANK_TM, 1)))
result.setStack(0, (inventory as TMBlockEntity.TMBlockInventory).items!!.get(3))
}
// if inventory is empty in the output slot then sync it to result
else
(inventory as TMBlockEntity.TMBlockInventory).items?.set(3, result.getStack(0))
}
super.syncState()
}
companion object {
val SLOT_COUNT = 3
}
}
@@ -0,0 +1,175 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.item
import com.cobblemon.mod.common.CobblemonSounds
import com.cobblemon.mod.common.api.moves.BenchedMove
import com.cobblemon.mod.common.api.moves.Moves
import com.cobblemon.mod.common.api.text.gray
import com.cobblemon.mod.common.api.text.green
import com.cobblemon.mod.common.api.tms.TechnicalMachine
import com.cobblemon.mod.common.api.tms.TechnicalMachines
import com.cobblemon.mod.common.api.types.ElementalTypes
import com.cobblemon.mod.common.block.entity.TMBlockEntity
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
import com.cobblemon.mod.common.util.lang
import com.cobblemon.mod.common.util.toBlockPos
import net.minecraft.block.Block
import net.minecraft.client.item.TooltipContext
import net.minecraft.entity.LivingEntity
import net.minecraft.entity.player.PlayerEntity
import net.minecraft.item.ItemStack
import net.minecraft.item.ItemUsageContext
import net.minecraft.nbt.NbtString
import net.minecraft.sound.SoundCategory
import net.minecraft.text.MutableText
import net.minecraft.text.Text
import net.minecraft.util.ActionResult
import net.minecraft.util.Hand
import net.minecraft.util.Identifier
import net.minecraft.world.World
class TechnicalMachineItem(settings: Settings): CobblemonItem(settings) {
companion object {
val STORED_MOVE_KEY = "StoredMove"
fun getMoveNbt(stack: ItemStack): TechnicalMachine? {
val nbtCompound = stack.nbt ?: return null
return TechnicalMachines.tmMap[Identifier.tryParse(nbtCompound.getString(STORED_MOVE_KEY))]
}
fun getItemColor(stack: ItemStack, tint: Int): Int {
val nbt = getMoveNbt(stack) ?: return ElementalTypes.NORMAL.primaryColor
if (nbt.primaryColor != null && tint == 0) return nbt.primaryColor
if (nbt.secondaryColor != null && tint != 0) return nbt.secondaryColor
val type = ElementalTypes.getOrException(nbt.type)
if (tint == 0) return type.primaryColor
return type.secondaryColor
}
}
override fun hasGlint(stack: ItemStack?) = false
fun setNbt(stack: ItemStack, id: String): ItemStack {
stack.getOrCreateNbt().put(STORED_MOVE_KEY, NbtString.of(id))
return stack
}
override fun appendTooltip(
stack: ItemStack,
world: World?,
tooltip: MutableList<Text>,
context: TooltipContext?
) {
val nbt = getMoveNbt(stack)
val text: MutableText = if (nbt != null) {
lang("move." + nbt.moveName)
} else {
lang("tms.unknown_move")
}
tooltip.add(text.gray())
}
override fun useOnEntity(stack: ItemStack, user: PlayerEntity, entity: LivingEntity, hand: Hand): ActionResult {
if (user.world.isClient) return ActionResult.FAIL
if (entity !is PokemonEntity) return ActionResult.FAIL
val tm = getMoveNbt(stack) ?: return ActionResult.FAIL
val move = Moves.getByName(tm.moveName) ?: return ActionResult.FAIL
val pokemon = entity.pokemon
val tmLearnableMoves = pokemon.species.moves.tmLearnableMoves()
if (!tmLearnableMoves.contains(move)) {
user.sendMessage(lang("tms.cannot_learn", pokemon.getDisplayName(), tm.translatedMoveName()))
return ActionResult.FAIL
}
if (pokemon.allAccessibleMoves.contains(move)) {
user.sendMessage(lang("tms.already_known", pokemon.getDisplayName(), tm.translatedMoveName()))
return ActionResult.FAIL
}
if (!user.isCreative) stack.decrement(1)
if (pokemon.moveSet.hasSpace()) { pokemon.moveSet.add(move.create()) }
else { pokemon.benchedMoves.add(BenchedMove(move, 0)) }
user.sendMessage(lang("tms.teach_move", pokemon.getDisplayName(), tm.translatedMoveName()).green())
user.playSound(CobblemonSounds.TM_USE, SoundCategory.PLAYERS, 1.0f, 1.0f)
entity.cry()
return ActionResult.CONSUME
}
override fun useOnBlock(context: ItemUsageContext): ActionResult {
if (context.world.isClient) {
context.player?.swingHand(context.hand)
return ActionResult.FAIL
}
//val TMM = context.world.getBlockState(context.hitPos.toBlockPos()).block
val TMM = context.world.getBlockEntity(context.hitPos.toBlockPos())
if (TMM is TMBlockEntity
&& (TMM.tmmInventory.filterTM == null
|| TMM.tmmInventory.filterTM!!.nbt?.get("StoredMove") != context.stack.nbt?.get("StoredMove"))) {
context.player?.playSound(CobblemonSounds.TMM_ON, SoundCategory.BLOCKS, 1.0f, 1.0f)
context.player?.swingHand(context.hand)
if (TMM.tmmInventory.filterTM != null) {
if (!context.player?.isCreative!!) {
context.player!!.giveItemStack(TMM.tmmInventory.filterTM!!)
}
}
// set filterTM equal to the item it corresponds to
TMM.tmmInventory.filterTM = TechnicalMachines.getTechnicalMachineFromStack(context.stack)?.let { TechnicalMachines.getStackFromTechnicalMachine(it) }
/*// if materials are in the machine already
if (TMM.tmmInventory.items?.isNotEmpty() == true) {
TMM.tmmInventory.items?.forEach {
// Get the direction the block is facing
val facingDirection = TMM.blockState.get(Properties.FACING).opposite
// Calculate the center position of the block
val frontOffset = 0.5 // Half block offset to the front
val spawnX = TMM.blockPos.x + 0.5 + facingDirection.offsetX * frontOffset
val spawnY = TMM.blockPos.y + 0.3 + facingDirection.offsetY * frontOffset
val spawnZ = TMM.blockPos.z + 0.5 + facingDirection.offsetZ * frontOffset
// Create the ItemEntity at the center of the block
val itemEntity = ItemEntity( context.world, spawnX, spawnY, spawnZ, it)
// Create the ItemEntity
itemEntity.setVelocity(0.0, 0.0, 0.0)
// Add the ItemEntity to the world
context.world.spawnEntity(itemEntity)
}
TMM.tmmInventory.items?.clear()
}*/
// todo change the color of the disk in the TMM
// todo remove 1 from the stack in the player's hand if not in creative
if (!context.player?.isCreative!!) {
context.player?.getStackInHand(context.hand)?.decrement(1)
}
TMM.markDirty()
TMM.world?.updateListeners(TMM.blockPos, TMM.cachedState, TMM.cachedState, Block.NOTIFY_LISTENERS)
}
/*val type = ElementalTypes.getOrException(getMoveNbt(context.stack)!!.type)
context.player!!.giveItemStack(Registries.ITEM.get(type.typeGem).defaultStack)*/
return super.useOnBlock(context)
}
}
@@ -9,6 +9,7 @@
package com.cobblemon.mod.common.item.group
import com.cobblemon.mod.common.CobblemonItems
import com.cobblemon.mod.common.api.tms.TechnicalMachines
import com.cobblemon.mod.common.util.cobblemonResource
import net.minecraft.item.ItemConvertible
import net.minecraft.item.ItemGroup
@@ -35,6 +36,7 @@ object CobblemonItemGroups {
@JvmStatic val CONSUMABLES_KEY = this.create("consumables", this::consumableEntries) { ItemStack(CobblemonItems.ROASTED_LEEK) }
@JvmStatic val HELD_ITEMS_KEY = this.create("held_item", this::heldItemEntries) { ItemStack(CobblemonItems.EXP_SHARE) }
@JvmStatic val EVOLUTION_ITEMS_KEY = this.create("evolution_item", this::evolutionItemEntries) { ItemStack(CobblemonItems.BLACK_AUGURITE) }
@JvmStatic val TECHNICAL_MACHINES_KEY = this.create("technical_machines", this::technicalMachineEntries) { ItemStack(CobblemonItems.BLANK_TM) }
@JvmStatic val BLOCKS get() = Registries.ITEM_GROUP.get(BLOCKS_KEY)
@JvmStatic val POKEBALLS get() = Registries.ITEM_GROUP.get(POKEBALLS_KEY)
@@ -43,6 +45,7 @@ object CobblemonItemGroups {
@JvmStatic val CONSUMABLES get() = Registries.ITEM_GROUP.get(CONSUMABLES_KEY)
@JvmStatic val HELD_ITEMS get() = Registries.ITEM_GROUP.get(HELD_ITEMS_KEY)
@JvmStatic val EVOLUTION_ITEMS get() = Registries.ITEM_GROUP.get(EVOLUTION_ITEMS_KEY)
@JvmStatic val TECHNICAL_MACHINES get() = Registries.ITEM_GROUP.get(TECHNICAL_MACHINES_KEY)
@JvmStatic val FOOD_INJECTIONS = this.inject(RegistryKey.of(Registries.ITEM_GROUP.key, Identifier("food_and_drinks")), this::foodInjections)
@JvmStatic val TOOLS_AND_UTILITIES_INJECTIONS = this.inject(RegistryKey.of(Registries.ITEM_GROUP.key, Identifier("tools_and_utilities")), this::toolsAndUtilitiesInjections)
@@ -76,6 +79,16 @@ object CobblemonItemGroups {
return consumer
}
private fun technicalMachineEntries(displayContext: DisplayContext, entries: Entries) {
entries.add(CobblemonItems.BLANK_TM)
for (tm in TechnicalMachines.tmMap) {
val item = CobblemonItems.TECHNICAL_MACHINE.setNbt(
CobblemonItems.TECHNICAL_MACHINE.defaultStack,
tm.key.toString())
entries.add(item)
}
}
private fun agricultureEntries(displayContext: DisplayContext, entries: Entries) {
entries.add(CobblemonItems.MEDICINAL_LEEK)
entries.add(CobblemonItems.BIG_ROOT)
@@ -217,8 +230,10 @@ object CobblemonItemGroups {
entries.add(CobblemonItems.FOSSIL_ANALYZER)
entries.add(CobblemonItems.MONITOR)
entries.add(CobblemonItems.PC)
entries.add(CobblemonItems.TM_MACHINE)
entries.add(CobblemonItems.HEALING_MACHINE)
entries.add(CobblemonItems.PASTURE)
entries.add(CobblemonItems.MOD_STATION)
entries.add(CobblemonItems.GILDED_CHEST)
entries.add(CobblemonItems.YELLOW_GILDED_CHEST)
@@ -0,0 +1,35 @@
package com.cobblemon.mod.common.net.messages.client.ui
import com.cobblemon.mod.common.api.net.NetworkPacket
import com.cobblemon.mod.common.api.tms.TechnicalMachine
import com.cobblemon.mod.common.api.tms.TechnicalMachines
import com.cobblemon.mod.common.util.cobblemonResource
import net.minecraft.item.ItemStack
import net.minecraft.network.PacketByteBuf
import java.util.UUID
/**
* Tells the server to attempt crafting a Blank TM using the [TMBlock]
*
* Handled by [CraftBlankTMPacketHandler]
*
* @author whatsy
*/
class CraftBlankTMPacket(
val ingredient: ItemStack
): NetworkPacket<CraftBlankTMPacket> {
override val id = ID
override fun encode(buffer: PacketByteBuf) {
buffer.writeItemStack(ingredient)
}
companion object {
val ID = cobblemonResource("craft_blank_tm")
fun decode(buffer: PacketByteBuf) = CraftBlankTMPacket(
buffer.readItemStack()
)
}
}
@@ -0,0 +1,42 @@
package com.cobblemon.mod.common.net.messages.client.ui
import com.cobblemon.mod.common.api.net.NetworkPacket
import com.cobblemon.mod.common.api.tms.TechnicalMachine
import com.cobblemon.mod.common.api.tms.TechnicalMachines
import com.cobblemon.mod.common.util.cobblemonResource
import net.minecraft.item.ItemStack
import net.minecraft.network.PacketByteBuf
import java.util.UUID
/**
* Tells the server to attempt crafting a [TechnicalMachineItem] using the [TMBlock]
*
* Handled by [CraftTMPacketHandler]
*
* @author whatsy
*/
class CraftTMPacket(
val tm: TechnicalMachine,
val disc: ItemStack,
val gem: ItemStack,
val ingredient: ItemStack
): NetworkPacket<CraftTMPacket> {
override val id = ID
override fun encode(buffer: PacketByteBuf) {
buffer.writeIdentifier(tm.id())
buffer.writeItemStack(disc)
buffer.writeItemStack(gem)
buffer.writeItemStack(ingredient)
}
companion object {
val ID = cobblemonResource("craft_tm")
fun decode(buffer: PacketByteBuf) = CraftTMPacket(
TechnicalMachines.tmMap[buffer.readIdentifier()]!!,
buffer.readItemStack(), buffer.readItemStack(), buffer.readItemStack()
)
}
}
@@ -0,0 +1,15 @@
package com.cobblemon.mod.common.net.messages.client.ui
import com.cobblemon.mod.common.api.net.NetworkPacket
import com.cobblemon.mod.common.util.cobblemonResource
import net.minecraft.network.PacketByteBuf
import net.minecraft.util.Identifier
class OpenTMMPacket: NetworkPacket<OpenTMMPacket> {
override val id = cobblemonResource("open_tm")
override fun encode(buffer: PacketByteBuf) {
}
}
@@ -1398,11 +1398,18 @@ open class Pokemon : ShowdownIdentifiable {
val newLevelUpMoves = form.moves.getLevelUpMovesUpTo(newLevel)
val differences = (newLevelUpMoves - previousLevelUpMoves).filter { this.moveSet.none { move -> move.template == it } }.toMutableSet()
differences.forEach {
if (moveSet.hasSpace()) {
moveSet.add(it.create())
}
}
// differences.forEach {
// TechnicalMachines.tmsToCheckOnLevelUp.entries.filter { entry ->
// entry.value.moveName == it.name
// }.forEach { entry ->
// val player = this.getOwnerPlayer() as PlayerEntity
// Cobblemon.playerData.get(player).tmSet.add(entry.key)
// player.sendMessage(lang("tms.unlock_tm", lang("move." + entry.value.moveName)))
// }
// if (moveSet.hasSpace()) {
// moveSet.add(it.create())
// }
// }
CobblemonEvents.EXPERIENCE_GAINED_EVENT_POST.post(
ExperienceGainedPostEvent(this, source, appliedXP, oldLevel, newLevel, differences),
@@ -0,0 +1,22 @@
package com.cobblemon.mod.common.tms.obtain
import com.cobblemon.mod.common.api.tms.ObtainMethod
import com.cobblemon.mod.common.util.cobblemonResource
import net.minecraft.server.network.ServerPlayerEntity
/**
* An [ObtainMethod] that never triggers.
* Useful since the obtainMethods field in TM JSONs cannot be blank.
*
* @author whatsy
*/
class ImpossibleObtainMethod : ObtainMethod {
override val passive = false
companion object {
val ID = cobblemonResource("impossible")
}
override fun matches(player: ServerPlayerEntity) = false
}
@@ -0,0 +1,24 @@
package com.cobblemon.mod.common.tms.obtain
import com.cobblemon.mod.common.api.tms.ObtainMethod
import com.cobblemon.mod.common.util.cobblemonResource
import net.minecraft.server.network.ServerPlayerEntity
/**
* An [ObtainMethod] that unlocks immediately.
* Used for TMs that aren't unlocked and are available immediately.
* TMs with this [ObtainMethod] will not display an unlock text.
*
* @author whatsy
*/
class NoneObtainMethod : ObtainMethod {
override val passive = true
override fun matches(player: ServerPlayerEntity) = true
companion object {
val ID = cobblemonResource("none")
}
}
@@ -0,0 +1,29 @@
package com.cobblemon.mod.common.tms.obtain
import com.cobblemon.mod.common.api.tms.ObtainMethod
import com.cobblemon.mod.common.util.cobblemonResource
import net.minecraft.server.network.ServerPlayerEntity
import net.minecraft.util.Identifier
/**
* An [ObtainMethod] that triggers when the player has an advancement.
*/
class PlayerHasAdvancementObtainMethod : ObtainMethod {
companion object {
val ID = cobblemonResource("advancement")
}
override val passive = true
val advancement: Identifier? = null
override fun matches(player: ServerPlayerEntity): Boolean {
if (advancement == null) return false
for (entry in player.advancementTracker.progress) {
if (entry.key.id == advancement && entry.value.isDone) return true
}
return false
}
}
@@ -0,0 +1,30 @@
package com.cobblemon.mod.common.tms.obtain
import com.cobblemon.mod.common.api.tms.ObtainMethod
import com.cobblemon.mod.common.util.cobblemonResource
import net.minecraft.server.network.ServerPlayerEntity
/**
* An [ObtainMethod] that checks the player's Y level.
*
* @param yLevel The Y level to check for.
* @param operator The operator to use. Can be "equals", "less", or "greater".
* @author whatsy
*/
class PlayerYObtainMethod(val yLevel: Int, val operator: String) : ObtainMethod {
override val passive = true
override fun matches(player: ServerPlayerEntity): Boolean {
when (operator) {
"equals" -> return (player.y.toInt() == yLevel)
"less" -> return (yLevel < player.y)
"greater" -> return (yLevel > player.y)
}
return false
}
companion object {
val ID = cobblemonResource("y_level")
}
}
@@ -0,0 +1,42 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.tms.obtain
import com.cobblemon.mod.common.api.moves.Moves
import com.cobblemon.mod.common.api.tms.ObtainMethod
import com.cobblemon.mod.common.util.cobblemonResource
import com.cobblemon.mod.common.util.party
import com.google.gson.annotations.SerializedName
import net.minecraft.server.network.ServerPlayerEntity
/**
* An [ObtainMethod] that triggers when a [Pokemon] in the player's party knows a certain [Move]
*
* @author whatsy
*/
class PokemonHasMoveObtainMethod : ObtainMethod {
companion object {
val ID = cobblemonResource("pokemon_knows")
}
@SerializedName("move")
val moveId: String = "splash"
override val passive = true
override fun matches(player: ServerPlayerEntity): Boolean {
player.party().forEach {
it.allAccessibleMoves.forEach {
if (it.equals(Moves.getByName(moveId))) return true
}
}
return false
}
}
@@ -0,0 +1,46 @@
package com.cobblemon.mod.common.util.adapters
import com.cobblemon.mod.common.Cobblemon
import com.cobblemon.mod.common.api.tms.ObtainMethod
import com.cobblemon.mod.common.api.tms.ObtainMethodAdapter
import com.cobblemon.mod.common.tms.obtain.*
import com.google.gson.JsonDeserializationContext
import com.google.gson.JsonElement
import com.google.gson.JsonSerializationContext
import net.minecraft.util.Identifier
import java.lang.reflect.Type
import kotlin.reflect.KClass
object CobblemonObtainMethodAdapter : ObtainMethodAdapter {
private const val VARIANT = "variant"
private val types = hashMapOf<String, KClass<out ObtainMethod>>()
init {
this.register(PokemonHasMoveObtainMethod::class, PokemonHasMoveObtainMethod.ID)
this.register(ImpossibleObtainMethod::class, ImpossibleObtainMethod.ID)
this.register(PlayerHasAdvancementObtainMethod::class, PlayerHasAdvancementObtainMethod.ID)
this.register(NoneObtainMethod::class, NoneObtainMethod.ID)
this.register(PlayerYObtainMethod::class, PlayerYObtainMethod.ID)
}
override fun register(type: KClass<out ObtainMethod>, identifier: Identifier) {
val existing = this.types.put(identifier.toString(), type)
if (existing != null) {
Cobblemon.LOGGER.debug("Replaced {} under ID {} with {} in the {}", existing::class.qualifiedName, identifier.toString(), type.qualifiedName, this::class.qualifiedName)
}
}
override fun deserialize(jElement: JsonElement, type: Type, context: JsonDeserializationContext): ObtainMethod {
val json = jElement.asJsonObject
val variant = json.get(VARIANT).asString.lowercase()
val registeredType = this.types[variant] ?: throw IllegalArgumentException("Cannot resolve type for variant $variant")
return context.deserialize(json, registeredType.java)
}
override fun serialize(method: ObtainMethod, type: Type, context: JsonSerializationContext): JsonElement {
val json = context.serialize(method).asJsonObject
val variant = this.types.entries.find { it.value == method::class }?.key ?: throw IllegalArgumentException("Cannot resolve variant for type ${method::class.qualifiedName}")
json.addProperty(VARIANT, variant)
return json
}
}
@@ -0,0 +1,24 @@
{
"format_version": "1.12.0",
"minecraft:geometry": [
{
"description": {
"identifier": "geometry.unknown",
"texture_width": 64,
"texture_height": 64,
"visible_bounds_width": 3,
"visible_bounds_height": 1.5,
"visible_bounds_offset": [0, 0.25, 0]
},
"bones": [
{
"name": "bb_main",
"pivot": [0, 0, 0],
"cubes": [
{"origin": [-11, 0, 4], "size": [8, 0, 8], "uv": [37, 55]}
]
}
]
}
]
}
@@ -0,0 +1,34 @@
{
"variants": {
"facing=south,on=false": {
"model": "cobblemon:block/tm_machine"
},
"facing=west,on=false": {
"model": "cobblemon:block/tm_machine",
"y": 90
},
"facing=north,on=false": {
"model": "cobblemon:block/tm_machine",
"y": 180
},
"facing=east,on=false": {
"model": "cobblemon:block/tm_machine",
"y": 270
},
"facing=south,on=true": {
"model": "cobblemon:block/tm_machine_on"
},
"facing=west,on=true": {
"model": "cobblemon:block/tm_machine_on",
"y": 90
},
"facing=north,on=true": {
"model": "cobblemon:block/tm_machine_on",
"y": 180
},
"facing=east,on=true": {
"model": "cobblemon:block/tm_machine_on",
"y": 270
}
}
}
@@ -109,6 +109,8 @@
"item.cobblemon.sun_stone": "Sun Stone",
"item.cobblemon.thunder_stone": "Thunder Stone",
"item.cobblemon.water_stone": "Water Stone",
"item.cobblemon.technical_machine": "Technical Machine",
"item.cobblemon.blank_tm": "Blank TM",
"item.cobblemon.rare_candy": "Rare Candy",
"item.cobblemon.exp_candy_xs": "Exp. Candy XS",
@@ -402,11 +404,12 @@
"cobblemon.fossilmachine.protected": "This fossil belongs to %s!",
"itemGroup.cobblemon.blocks": "Blocks",
"itemGroup.cobblemon.pokeball": "Poké Balls",
"itemGroup.cobblemon.pokeball": "Tools",
"itemGroup.cobblemon.agriculture": "Agriculture",
"itemGroup.cobblemon.consumables": "Consumables",
"itemGroup.cobblemon.held_item": "Held Items",
"itemGroup.cobblemon.evolution_item": "Evolution Items",
"itemGroup.cobblemon.technical_machines": "Technical Machines",
"itemGroup.cobblemon.archaeology": "Archaeology",
"block.cobblemon.apricorn_log": "Apricorn Log",
@@ -458,6 +461,7 @@
"block.cobblemon.green_gilded_chest": "Green Gilded Chest",
"block.cobblemon.white_gilded_chest": "White Gilded Chest",
"block.cobblemon.display_case": "Display Case",
"block.cobblemon.tm_machine": "TM Machine",
"block.cobblemon.small_budding_tumblestone": "Small Tumblestone Bud",
"block.cobblemon.medium_budding_tumblestone": "Medium Tumblestone Bud",
@@ -505,6 +509,15 @@
"cobblemon.ui.moves.switch": "Switch Move",
"cobblemon.ui.moves.pp": "%1$sPP",
"cobblemon.tms.unknown_move": "Unknown Move",
"cobblemon.tms.already_known": "%1$s already knows %2$s!",
"cobblemon.tms.teach_move": "%1$s learned %2$s!",
"cobblemon.tms.cannot_learn": "%1$s cannot learn %2$s!",
"cobblemon.tms.unlock_tm": "You unlocked the %1$s TM!",
"cobblemon.ui.tms.material_cost": "Material Cost",
"cobblemon.ui.tms.blank_tm_desc": "A blank disc used for crafting Technical Machines.",
"cobblemon.ui.stats": "Stats",
"cobblemon.ui.stats.stat": "Stat",
"cobblemon.ui.stats.base": "Base",
@@ -542,6 +555,8 @@
"cobblemon.ui.party": "Party",
"cobblemon.ui.power": "Power",
"cobblemon.ui.accuracy": "Accuracy",
"cobblemon.ui.accuracy_short": "Acc.",
"cobblemon.ui.pp": "PP",
"cobblemon.ui.effect": "Effect",
"cobblemon.ui.pokemon": "Pokémon",
"cobblemon.ui.exit": "Exit",
@@ -567,6 +582,13 @@
"key.cobblemon.summary": "Open Summary",
"key.cobblemon.categories.cobblemon": "Cobblemon",
"cobblemon.subtitle.capture_succeeded": "Capture Succeeded!",
"cobblemon.subtitle.tm.use": "Technical Machine used",
"cobblemon.subtitle.tmm.craft": "TM Machine prints TM",
"cobblemon.subtitle.tmm.craft_blank": "TM Machine crafts blank TM",
"cobblemon.subtitle.tmm.off": "TM Machine deactivates",
"cobblemon.subtitle.tmm.on": "TM Machine activates",
"cobblemon.subtitle.poke_ball.capture_succeeded": "Poké Ball capture succeeds",
"cobblemon.subtitle.fossilmachine.activate": "Restoration Machine activates",
"cobblemon.subtitle.fossilmachine.active_loop": "Restoration Machine hums",
@@ -0,0 +1,199 @@
{
"credit": "Made with Blockbench",
"texture_size": [64, 64],
"textures": {
"0": "cobblemon:block/tm_machine",
"particle": "cobblemon:block/tm_machine"
},
"elements": [
{
"from": [0, 0, 1],
"to": [16, 5, 16],
"rotation": {"angle": 0, "axis": "y", "origin": [8, 0, 8]},
"faces": {
"north": {"uv": [3.5, 7.75, 7.5, 9], "texture": "#0"},
"east": {"uv": [7.5, 9.5, 11.25, 10.75], "texture": "#0"},
"south": {"uv": [3.5, 9, 7.5, 10.25], "texture": "#0"},
"west": {"uv": [10, 0, 13.75, 1.25], "texture": "#0"},
"up": {"uv": [4, 3.75, 0, 0], "texture": "#0"},
"down": {"uv": [4, 3.75, 0, 7.5], "texture": "#0"}
}
},
{
"from": [6, 5, 2],
"to": [14, 13, 4],
"rotation": {"angle": 0, "axis": "y", "origin": [8, 0, 8]},
"faces": {
"north": {"uv": [0, 9.75, 2, 11.75], "texture": "#0"},
"east": {"uv": [10.5, 10.75, 11, 12.75], "texture": "#0"},
"south": {"uv": [10, 1.25, 12, 3.25], "texture": "#0"},
"west": {"uv": [11, 10.75, 11.5, 12.75], "texture": "#0"},
"up": {"uv": [13.25, 9.75, 11.25, 9.25], "texture": "#0"},
"down": {"uv": [13.25, 9.75, 11.25, 10.25], "texture": "#0"}
}
},
{
"from": [14, 5, 1],
"to": [16, 15, 4],
"rotation": {"angle": 0, "axis": "y", "origin": [8, 0, 8]},
"faces": {
"north": {"uv": [6.5, 10.25, 7, 12.75], "texture": "#0"},
"east": {"uv": [3.5, 10.25, 4.25, 12.75], "texture": "#0"},
"south": {"uv": [7, 10.25, 7.5, 12.75], "texture": "#0"},
"west": {"uv": [4.25, 10.25, 5, 12.75], "texture": "#0"},
"up": {"uv": [12.25, 5.75, 11.75, 5], "texture": "#0"},
"down": {"uv": [12.5, 1.25, 12, 2], "texture": "#0"}
}
},
{
"from": [6, 13, 1],
"to": [14, 15, 4],
"rotation": {"angle": 0, "axis": "y", "origin": [8, 0, 8]},
"faces": {
"north": {"uv": [11.25, 10.25, 13.25, 10.75], "texture": "#0"},
"east": {"uv": [12, 2, 12.75, 2.5], "texture": "#0"},
"south": {"uv": [7.5, 11.5, 9.5, 12], "texture": "#0"},
"west": {"uv": [12, 2.5, 12.75, 3], "texture": "#0"},
"up": {"uv": [12.25, 6.5, 10.25, 5.75], "texture": "#0"},
"down": {"uv": [12.25, 6.5, 10.25, 7.25], "texture": "#0"}
}
},
{
"from": [0, 5, 1],
"to": [6, 15, 4],
"rotation": {"angle": 0, "axis": "y", "origin": [8, 0, 8]},
"faces": {
"north": {"uv": [2, 9.75, 3.5, 12.25], "texture": "#0"},
"east": {"uv": [5, 10.25, 5.75, 12.75], "texture": "#0"},
"south": {"uv": [10.25, 3.25, 11.75, 5.75], "texture": "#0"},
"west": {"uv": [5.75, 10.25, 6.5, 12.75], "texture": "#0"},
"up": {"uv": [9, 11.5, 7.5, 10.75], "texture": "#0"},
"down": {"uv": [10.5, 10.75, 9, 11.5], "texture": "#0"}
}
},
{
"from": [1, 5, 4],
"to": [15, 14, 15],
"rotation": {"angle": 0, "axis": "y", "origin": [8, 14.25, 4]},
"faces": {
"north": {"uv": [4, 5.5, 7.5, 7.75], "texture": "#0"},
"east": {"uv": [7.5, 5, 10.25, 7.25], "texture": "#0"},
"south": {"uv": [0, 7.5, 3.5, 9.75], "texture": "#0"},
"west": {"uv": [7.5, 7.25, 10.25, 9.5], "texture": "#0"},
"up": {"uv": [7.5, 2.75, 4, 0], "texture": "#0"},
"down": {"uv": [7.5, 2.75, 4, 5.5], "texture": "#0"}
}
},
{
"from": [14, 0, 6],
"to": [14, 7, 8],
"shade": false,
"rotation": {"angle": 0, "axis": "y", "origin": [8, -5, 6]},
"faces": {
"north": {"uv": [0, 0, 0, 1.75], "texture": "#0"},
"east": {"uv": [9.5, 11.5, 10, 13.25], "texture": "#0"},
"south": {"uv": [0, 0, 0, 1.75], "texture": "#0"},
"west": {"uv": [10, 11.5, 10.5, 13.25], "texture": "#0"},
"up": {"uv": [0, 0.5, 0, 0], "texture": "#0"},
"down": {"uv": [0, 0, 0, 0.5], "texture": "#0"}
}
},
{
"from": [2, 0, 6],
"to": [2, 7, 8],
"shade": false,
"rotation": {"angle": 0, "axis": "y", "origin": [8, -5, 6]},
"faces": {
"north": {"uv": [0, 0, 0, 1.75], "texture": "#0"},
"east": {"uv": [11.5, 10.75, 12, 12.5], "texture": "#0"},
"south": {"uv": [0, 0, 0, 1.75], "texture": "#0"},
"west": {"uv": [0, 11.75, 0.5, 13.5], "texture": "#0"},
"up": {"uv": [0, 0.5, 0, 0], "texture": "#0"},
"down": {"uv": [0, 0, 0, 0.5], "texture": "#0"}
}
},
{
"from": [2, 7, 6],
"to": [14, 7, 8],
"shade": false,
"rotation": {"angle": 0, "axis": "y", "origin": [8, -5, 6]},
"faces": {
"north": {"uv": [0, 0, 3, 0], "texture": "#0"},
"east": {"uv": [0, 0, 0.5, 0], "texture": "#0"},
"south": {"uv": [0, 0, 3, 0], "texture": "#0"},
"west": {"uv": [0, 0, 0.5, 0], "texture": "#0"},
"up": {"uv": [13.25, 7.75, 10.25, 7.25], "texture": "#0"},
"down": {"uv": [13.25, 7.75, 10.25, 8.25], "texture": "#0"}
}
},
{
"from": [14, 0, 10],
"to": [14, 7, 12],
"shade": false,
"rotation": {"angle": 0, "axis": "y", "origin": [8, -5, 10]},
"faces": {
"north": {"uv": [0, 0, 0, 1.75], "texture": "#0"},
"east": {"uv": [0.5, 11.75, 1, 13.5], "texture": "#0"},
"south": {"uv": [0, 0, 0, 1.75], "texture": "#0"},
"west": {"uv": [1, 11.75, 1.5, 13.5], "texture": "#0"},
"up": {"uv": [0, 0.5, 0, 0], "texture": "#0"},
"down": {"uv": [0, 0, 0, 0.5], "texture": "#0"}
}
},
{
"from": [2, 0, 10],
"to": [2, 7, 12],
"shade": false,
"rotation": {"angle": 0, "axis": "y", "origin": [8, -5, 10]},
"faces": {
"north": {"uv": [0, 0, 0, 1.75], "texture": "#0"},
"east": {"uv": [1.5, 11.75, 2, 13.5], "texture": "#0"},
"south": {"uv": [0, 0, 0, 1.75], "texture": "#0"},
"west": {"uv": [11.75, 3.25, 12.25, 5], "texture": "#0"},
"up": {"uv": [0, 0.5, 0, 0], "texture": "#0"},
"down": {"uv": [0, 0, 0, 0.5], "texture": "#0"}
}
},
{
"from": [2, 7, 10],
"to": [14, 7, 12],
"shade": false,
"rotation": {"angle": 0, "axis": "y", "origin": [8, -5, 10]},
"faces": {
"north": {"uv": [0, 0, 3, 0], "texture": "#0"},
"east": {"uv": [0, 0, 0.5, 0], "texture": "#0"},
"south": {"uv": [0, 0, 3, 0], "texture": "#0"},
"west": {"uv": [0, 0, 0.5, 0], "texture": "#0"},
"up": {"uv": [13.25, 8.75, 10.25, 8.25], "texture": "#0"},
"down": {"uv": [13.25, 8.75, 10.25, 9.25], "texture": "#0"}
}
}
],
"groups": [
{
"name": "tm_machine",
"origin": [8, 8, 8],
"color": 0,
"children": [
{
"name": "machine",
"origin": [8, 0, 8],
"color": 0,
"children": [0, 1, 2, 3, 4, 5]
},
{
"name": "arm1",
"origin": [8, -5, 8],
"color": 0,
"children": [6, 7, 8]
},
{
"name": "arm2",
"origin": [8, -5, 8],
"color": 0,
"children": [9, 10, 11]
}
]
}
]
}
@@ -0,0 +1,199 @@
{
"credit": "Made with Blockbench",
"texture_size": [64, 64],
"textures": {
"0": "cobblemon:block/tm_machine_on",
"particle": "cobblemon:block/tm_machine_on"
},
"elements": [
{
"from": [0, 0, 1],
"to": [16, 5, 16],
"rotation": {"angle": 0, "axis": "y", "origin": [8, 0, 8]},
"faces": {
"north": {"uv": [3.5, 7.75, 7.5, 9], "texture": "#0"},
"east": {"uv": [7.5, 9.5, 11.25, 10.75], "texture": "#0"},
"south": {"uv": [3.5, 9, 7.5, 10.25], "texture": "#0"},
"west": {"uv": [10, 0, 13.75, 1.25], "texture": "#0"},
"up": {"uv": [4, 3.75, 0, 0], "texture": "#0"},
"down": {"uv": [4, 3.75, 0, 7.5], "texture": "#0"}
}
},
{
"from": [6, 5, 2],
"to": [14, 13, 4],
"rotation": {"angle": 0, "axis": "y", "origin": [8, 0, 8]},
"faces": {
"north": {"uv": [0, 9.75, 2, 11.75], "texture": "#0"},
"east": {"uv": [10.5, 10.75, 11, 12.75], "texture": "#0"},
"south": {"uv": [10, 1.25, 12, 3.25], "texture": "#0"},
"west": {"uv": [11, 10.75, 11.5, 12.75], "texture": "#0"},
"up": {"uv": [13.25, 9.75, 11.25, 9.25], "texture": "#0"},
"down": {"uv": [13.25, 9.75, 11.25, 10.25], "texture": "#0"}
}
},
{
"from": [14, 5, 1],
"to": [16, 15, 4],
"rotation": {"angle": 0, "axis": "y", "origin": [8, 0, 8]},
"faces": {
"north": {"uv": [6.5, 10.25, 7, 12.75], "texture": "#0"},
"east": {"uv": [3.5, 10.25, 4.25, 12.75], "texture": "#0"},
"south": {"uv": [7, 10.25, 7.5, 12.75], "texture": "#0"},
"west": {"uv": [4.25, 10.25, 5, 12.75], "texture": "#0"},
"up": {"uv": [12.25, 5.75, 11.75, 5], "texture": "#0"},
"down": {"uv": [12.5, 1.25, 12, 2], "texture": "#0"}
}
},
{
"from": [6, 13, 1],
"to": [14, 15, 4],
"rotation": {"angle": 0, "axis": "y", "origin": [8, 0, 8]},
"faces": {
"north": {"uv": [11.25, 10.25, 13.25, 10.75], "texture": "#0"},
"east": {"uv": [12, 2, 12.75, 2.5], "texture": "#0"},
"south": {"uv": [7.5, 11.5, 9.5, 12], "texture": "#0"},
"west": {"uv": [12, 2.5, 12.75, 3], "texture": "#0"},
"up": {"uv": [12.25, 6.5, 10.25, 5.75], "texture": "#0"},
"down": {"uv": [12.25, 6.5, 10.25, 7.25], "texture": "#0"}
}
},
{
"from": [0, 5, 1],
"to": [6, 15, 4],
"rotation": {"angle": 0, "axis": "y", "origin": [8, 0, 8]},
"faces": {
"north": {"uv": [2, 9.75, 3.5, 12.25], "texture": "#0"},
"east": {"uv": [5, 10.25, 5.75, 12.75], "texture": "#0"},
"south": {"uv": [10.25, 3.25, 11.75, 5.75], "texture": "#0"},
"west": {"uv": [5.75, 10.25, 6.5, 12.75], "texture": "#0"},
"up": {"uv": [9, 11.5, 7.5, 10.75], "texture": "#0"},
"down": {"uv": [10.5, 10.75, 9, 11.5], "texture": "#0"}
}
},
{
"from": [1, 5, 4],
"to": [15, 14, 15],
"rotation": {"angle": 0, "axis": "y", "origin": [8, 14.25, 4]},
"faces": {
"north": {"uv": [4, 5.5, 7.5, 7.75], "texture": "#0"},
"east": {"uv": [7.5, 5, 10.25, 7.25], "texture": "#0"},
"south": {"uv": [0, 7.5, 3.5, 9.75], "texture": "#0"},
"west": {"uv": [7.5, 7.25, 10.25, 9.5], "texture": "#0"},
"up": {"uv": [7.5, 2.75, 4, 0], "texture": "#0"},
"down": {"uv": [7.5, 2.75, 4, 5.5], "texture": "#0"}
}
},
{
"from": [14, 0, 6],
"to": [14, 7, 8],
"shade": false,
"rotation": {"angle": 0, "axis": "y", "origin": [8, -5, 6]},
"faces": {
"north": {"uv": [0, 0, 0, 1.75], "texture": "#0"},
"east": {"uv": [9.5, 11.5, 10, 13.25], "texture": "#0"},
"south": {"uv": [0, 0, 0, 1.75], "texture": "#0"},
"west": {"uv": [10, 11.5, 10.5, 13.25], "texture": "#0"},
"up": {"uv": [0, 0.5, 0, 0], "texture": "#0"},
"down": {"uv": [0, 0, 0, 0.5], "texture": "#0"}
}
},
{
"from": [2, 0, 6],
"to": [2, 7, 8],
"shade": false,
"rotation": {"angle": 0, "axis": "y", "origin": [8, -5, 6]},
"faces": {
"north": {"uv": [0, 0, 0, 1.75], "texture": "#0"},
"east": {"uv": [11.5, 10.75, 12, 12.5], "texture": "#0"},
"south": {"uv": [0, 0, 0, 1.75], "texture": "#0"},
"west": {"uv": [0, 11.75, 0.5, 13.5], "texture": "#0"},
"up": {"uv": [0, 0.5, 0, 0], "texture": "#0"},
"down": {"uv": [0, 0, 0, 0.5], "texture": "#0"}
}
},
{
"from": [2, 7, 6],
"to": [14, 7, 8],
"shade": false,
"rotation": {"angle": 0, "axis": "y", "origin": [8, -5, 6]},
"faces": {
"north": {"uv": [0, 0, 3, 0], "texture": "#0"},
"east": {"uv": [0, 0, 0.5, 0], "texture": "#0"},
"south": {"uv": [0, 0, 3, 0], "texture": "#0"},
"west": {"uv": [0, 0, 0.5, 0], "texture": "#0"},
"up": {"uv": [13.25, 7.75, 10.25, 7.25], "texture": "#0"},
"down": {"uv": [13.25, 7.75, 10.25, 8.25], "texture": "#0"}
}
},
{
"from": [14, 0, 10],
"to": [14, 7, 12],
"shade": false,
"rotation": {"angle": 0, "axis": "y", "origin": [8, -5, 10]},
"faces": {
"north": {"uv": [0, 0, 0, 1.75], "texture": "#0"},
"east": {"uv": [0.5, 11.75, 1, 13.5], "texture": "#0"},
"south": {"uv": [0, 0, 0, 1.75], "texture": "#0"},
"west": {"uv": [1, 11.75, 1.5, 13.5], "texture": "#0"},
"up": {"uv": [0, 0.5, 0, 0], "texture": "#0"},
"down": {"uv": [0, 0, 0, 0.5], "texture": "#0"}
}
},
{
"from": [2, 0, 10],
"to": [2, 7, 12],
"shade": false,
"rotation": {"angle": 0, "axis": "y", "origin": [8, -5, 10]},
"faces": {
"north": {"uv": [0, 0, 0, 1.75], "texture": "#0"},
"east": {"uv": [1.5, 11.75, 2, 13.5], "texture": "#0"},
"south": {"uv": [0, 0, 0, 1.75], "texture": "#0"},
"west": {"uv": [11.75, 3.25, 12.25, 5], "texture": "#0"},
"up": {"uv": [0, 0.5, 0, 0], "texture": "#0"},
"down": {"uv": [0, 0, 0, 0.5], "texture": "#0"}
}
},
{
"from": [2, 7, 10],
"to": [14, 7, 12],
"shade": false,
"rotation": {"angle": 0, "axis": "y", "origin": [8, -5, 10]},
"faces": {
"north": {"uv": [0, 0, 3, 0], "texture": "#0"},
"east": {"uv": [0, 0, 0.5, 0], "texture": "#0"},
"south": {"uv": [0, 0, 3, 0], "texture": "#0"},
"west": {"uv": [0, 0, 0.5, 0], "texture": "#0"},
"up": {"uv": [13.25, 8.75, 10.25, 8.25], "texture": "#0"},
"down": {"uv": [13.25, 8.75, 10.25, 9.25], "texture": "#0"}
}
}
],
"groups": [
{
"name": "tm_machine",
"origin": [8, 8, 8],
"color": 0,
"children": [
{
"name": "machine",
"origin": [8, 0, 8],
"color": 0,
"children": [0, 1, 2, 3, 4, 5]
},
{
"name": "arm1",
"origin": [8, -5, 8],
"color": 0,
"children": [6, 7, 8]
},
{
"name": "arm2",
"origin": [8, -5, 8],
"color": 0,
"children": [9, 10, 11]
}
]
}
]
}
@@ -0,0 +1,6 @@
{
"parent": "minecraft:item/generated",
"textures": {
"layer0": "cobblemon:item/tms/blank_disc"
}
}
@@ -0,0 +1,7 @@
{
"parent": "minecraft:item/generated",
"textures": {
"layer0": "cobblemon:item/tms/tm",
"layer1": "cobblemon:item/tms/tm_overlay"
}
}
@@ -0,0 +1,3 @@
{
"parent": "cobblemon:block/tm_machine"
}
@@ -104,6 +104,26 @@
"berry.eat": {
"sounds": [ "cobblemon:berry_eat" ]
},
"tm.use": {
"sounds": [ "cobblemon:tm/tm_use" ],
"subtitle": "cobblemon.subtitle.tm.use"
},
"tmm.craft": {
"sounds": [ "cobblemon:tm/tmm_craft" ],
"subtitle": "cobblemon.subtitle.tmm.craft"
},
"tmm.craft_blank": {
"sounds": [ "cobblemon:tm/tmm_craft_blank" ],
"subtitle": "cobblemon.subtitle.tmm.craft_blank"
},
"tmm.off": {
"sounds": [ "cobblemon:tm/tmm_off" ],
"subtitle": "cobblemon.subtitle.tmm.off"
},
"tmm.on": {
"sounds": [ "cobblemon:tm/tmm_on" ],
"subtitle": "cobblemon.subtitle.tmm.on"
},
"fossilmachine.activate": {
"subtitle": "cobblemon.subtitle.fossilmachine.activate",
"sounds": [ "cobblemon:fossilmachine/activate" ]
Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 962 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 345 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 310 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 354 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 226 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 706 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 412 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 423 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.4 KiB

After

Width:  |  Height:  |  Size: 7.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 299 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 474 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 299 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 281 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 340 B

@@ -90,6 +90,8 @@ transitive-accessible method net/minecraft/client/texture/SpriteAtlasHolder getS
transitive-accessible field net/minecraft/client/texture/SpriteAtlasHolder atlas Lnet/minecraft/client/texture/SpriteAtlasTexture;
transitive-accessible field net/minecraft/client/texture/SpriteAtlasTexture width I
transitive-accessible field net/minecraft/client/texture/SpriteAtlasTexture height I
transitive-accessible class net/minecraft/screen/ScreenHandlerType$Factory
transitive-accessible method net/minecraft/client/gui/screen/ingame/HandledScreens register (Lnet/minecraft/screen/ScreenHandlerType;Lnet/minecraft/client/gui/screen/ingame/HandledScreens$Provider;)V
transitive-accessible method net/minecraft/entity/ai/brain/Activity register (Ljava/lang/String;)Lnet/minecraft/entity/ai/brain/Activity;
transitive-accessible field net/minecraft/client/model/ModelPart$Cuboid sides [Lnet/minecraft/client/model/ModelPart$Quad;
@@ -0,0 +1,34 @@
{
"parent": "cobblemon:recipes/root",
"rewards": {
"recipes": [
"cobblemon:tm_machine"
]
},
"criteria": {
"has_tm": {
"trigger": "minecraft:inventory_changed",
"conditions": {
"items": [
{
"items": [
"cobblemon:blank_tm"
]
}
]
}
},
"has_the_recipe": {
"trigger": "minecraft:recipe_unlocked",
"conditions": {
"recipe": "cobblemon:tm_machine"
}
}
},
"requirements": [
[
"has_tm",
"has_the_recipe"
]
]
}
@@ -0,0 +1,34 @@
{
"parent": "cobblemon:recipes/root",
"rewards": {
"recipes": [
"cobblemon:blank_tm"
]
},
"criteria": {
"has_amethyst": {
"trigger": "minecraft:inventory_changed",
"conditions": {
"items": [
{
"items": [
"minecraft:amethyst_shard"
]
}
]
}
},
"has_the_recipe": {
"trigger": "minecraft:recipe_unlocked",
"conditions": {
"recipe": "cobblemon:blank_tm"
}
}
},
"requirements": [
[
"has_amethyst",
"has_the_recipe"
]
]
}
@@ -0,0 +1,19 @@
{
"type": "minecraft:crafting_shaped",
"pattern": [
"AG",
"GA"
],
"key": {
"G": {
"item": "minecraft:glass"
},
"A": {
"item": "minecraft:amethyst_shard"
}
},
"result": {
"item": "cobblemon:blank_tm",
"count": 2
}
}
@@ -0,0 +1,28 @@
{
"type": "minecraft:crafting_shaped",
"pattern": [
"GGI",
"GTD",
"IRI"
],
"key": {
"G": {
"item": "minecraft:glass"
},
"I": {
"item": "minecraft:iron_ingot"
},
"T": {
"item": "cobblemon:blank_tm"
},
"D": {
"item": "minecraft:diamond"
},
"R": {
"item": "minecraft:comparator"
}
},
"result": {
"item": "cobblemon:tm_machine"
}
}
@@ -0,0 +1,10 @@
{
"moveName": "bubblebeam",
"obtainMethods": [
{
"variant": "cobblemon:advancement",
"advancement": "cobblemon:craft_remedy"
}
],
"type": "water"
}
@@ -0,0 +1,9 @@
{
"moveName": "dazzlinggleam",
"obtainMethods": [
{
"variant": "cobblemon:impossible"
}
],
"type": "fairy"
}
@@ -0,0 +1,9 @@
{
"moveName": "dragonrage",
"obtainMethods": [
{
"variant": "cobblemon:impossible"
}
],
"type": "dragon"
}
@@ -0,0 +1,9 @@
{
"moveName": "earthquake",
"obtainMethods": [
{
"variant": "cobblemon:impossible"
}
],
"type": "ground"
}

Some files were not shown because too many files have changed in this diff Show More