Compare commits

..
Author SHA1 Message Date
Guilherme Pereira 7dd92ca351 add expand and minimize assets to evolution tree 2026-06-11 07:02:27 -03:00
Guilherme Pereira 5359cc6c21 Merge branch 'main' into evolution-tree 2026-06-11 06:29:34 -03:00
Guilherme Pereira 4421303d3b Merge branch 'main' into evolution-tree 2026-02-24 21:03:56 -03:00
Guilherme Pereira 5b62f608da Merge branch 'main' into evolution-tree 2026-01-27 08:19:06 -03:00
Guilherme Pereira 3840e9cdec Merge branch 'main' into evolution-tree 2025-11-05 09:38:53 -03:00
Guilherme Pereira 5a2ac22bc2 attempt 3 to hide unknown pokemon from evolution tree 2025-10-20 17:44:55 -03:00
Guilherme Pereira 7991662be6 hide name from unknown pokemon in the evolution tree 2025-10-20 15:25:23 -03:00
Guilherme Pereira 8d41c7ae41 evolution tree refactoring 2025-10-20 14:53:17 -03:00
Guilherme Pereira 7768969186 attempt 2 to hide unknow pokemon from evolution tree 2025-10-16 16:54:35 -03:00
Guilherme Pereira 0720ec3565 attempt to hide unknown pokemon from evolution tree 2025-10-15 15:00:36 -03:00
Guilherme Pereira 5d89d9beb6 add support for custom icons and tooltips to the dex evolution tree 2025-10-14 00:02:04 -03:00
Guilherme Pereira 8ee737ae53 Merge branch 'main' into evolution-tree 2025-10-13 22:41:47 -03:00
Guilherme Pereira 886b960572 more requirements 2025-10-13 21:06:03 -03:00
Guilherme Pereira 2d23e88ff3 prevent pcs from exploding 2025-10-12 09:53:52 -03:00
Guilherme Pereira aaa63ebc8a fix wonkiness 2025-10-11 14:44:12 -03:00
Guilherme Pereira b35a82d89e update licenses 2025-10-11 14:32:56 -03:00
Guilherme Pereira 8662d954e3 add expand evolution tree button 2025-10-11 14:30:13 -03:00
Guilherme Pereira 94ddfc8720 add proper handling of variations, shiny and gender to evolution tree 2025-10-10 23:06:53 -03:00
Guilherme Pereira b9fcae2131 add some new requirements to evolution screen 2025-10-10 22:17:32 -03:00
Guilherme Pereira b848f2be3e add some new requirements to evolution screen 2025-10-10 02:00:36 -03:00
Guilherme Pereira f7019c943b add proper handling of mon forms to evolution tree 2025-10-10 00:12:56 -03:00
Guilherme Pereira c933eb2d71 make evolution icon be drawn on top of lines 2025-10-09 02:02:55 -03:00
Guilherme Pereira 09e9946eac add has move type and has friendship to dex evolution tree 2025-10-08 16:16:00 -03:00
Guilherme Pereira 082fcab8b0 add item evolution info to evolution tree 2025-10-08 10:42:45 -03:00
Guilherme Pereira 7bdc8d03b1 add panning to evolution tree 2025-10-07 15:48:27 -03:00
Guilherme Pereira 485e4cfb22 add evolution icon and tooltip for level up evolutions 2025-10-07 10:07:25 -03:00
Guilherme Pereira 4cd69c1b30 center evolution tree based on evolution tree size 2025-10-06 15:52:47 -03:00
Guilherme Pereira 00148452aa implement simple tree drawing algorithm for drawing evolution trees 2025-10-06 11:31:27 -03:00
Guilherme Pereira 598e08b8e6 add pokemon evolution tree page to pokedex 2025-10-03 10:20:13 -03:00
1082 changed files with 27118 additions and 163798 deletions
-4
View File
@@ -16,7 +16,6 @@ check_assets_cache:
stage: preprocessing
script:
- echo "Checking if cached hash matches current hash"
- yum install -y findutils
# Calculate the current hash
- find common/src/main/resources/assets common/src/main/resources/data -type f -exec sha256sum {} + | sort -k 2 | sha256sum > current_hash.txt
@@ -149,7 +148,6 @@ build:
dependencies:
- replace_resources
script:
- yum install -y findutils
- export GRADLE_OPTS="-Xmx4G -Xms4G"
- chmod +x ./gradlew
- ./gradlew build
@@ -165,7 +163,6 @@ publish:
rules:
- if: '$CI_PROJECT_PATH == "cable-mc/cobblemon" && $CI_COMMIT_BRANCH == "main"'
script:
- yum install -y findutils
- export GRADLE_OPTS="-Xmx4G -Xms4G"
- chmod +x ./gradlew
- ./gradlew publish
@@ -179,7 +176,6 @@ deploy_artifacts:
dependencies:
- build
script:
- yum install -y findutils
- echo "Collecting artifacts..."
- find neoforge/build/libs/ -type f -name "*.jar" | grep -vE "dev-shadow|sources|javadoc" | xargs -I {} mv {} ./
- find fabric/build/libs/ -type f -name "*.jar" | grep -vE "dev-shadow|sources|javadoc" | xargs -I {} mv {} ./
+25 -77
View File
@@ -21,7 +21,7 @@
- Added Move Dex to Pokédex
- Added the Habitat Block, a spawner block for servers and adventure maps that controls spawning in an area.
- Added Disk Rack for storing disks and being an audio sequencer for Noteblocks
- Added intrinsic scaling to all Pokémon (+-5%). Some rendering cases, such as shoulder mounting, revert to 1.0 scaling to preserve animation accuracy.
- Added intrinsic scaling to all mons (+-5%). Some rendering cases, such as shoulder mounting, revert to 1.0 scaling to preserve animation accuracy.
- Added scaling to "baby" Pokémon (smaller (-20%) at level 1 → normally sized at level 10)
- Added conditional seats for riding. Seats can be gated by molang such as "is_alpha".
- Added Alpha Pokémon
@@ -42,8 +42,9 @@
- All ruin structures gilded chest loot tables have been updated to include a guaranteed TM not learned naturally by any Pokémon through their level-up moveset. Each ruin gets its own specific TM, so you can now go hunting ruins to complete your move dex!
- All fossil structures have been transferred over to biome features, allowing for better placement in generation.
- The prehistoric_underwater_fissure & prehistoric_submerged_impact fossil structures now use the biome tag `#cobblemon:is_temperate_ocean`.
- A new Biome tag called `#cobblemon:is_stony_beach` has been added.
- Gimmighoul towers now generate at ground level rather than sinking one block into the ground.
- A new shipwreck cove structure called the "magma_shipwreck_cove" has been added.
- 1 New shipwreck cove structure called the "magma_shipwreck_cove" has been added.
- Shipwreck coves now generate slightly more frequently.
- Added equipment loot tables for shipwreck cove enemies.
- Maps from abandoned fishing boats leading to shipwreck coves now will skip explored chunks, allowing the player to find more shipwreck coves easier.
@@ -56,18 +57,15 @@
- Pokémon cries now play when clicking Pokémon in the summary screen.
- Pressing the Summary key while either the starter selection or summary screen are open now closes those screens
- Ice type Pokémon are now immune to Packed Snow
- Held item visibility can now be controlled by the held_item_visible command argument.
### New rideable Pokémon
- Crobat
- Skarmory
- Milotic
- Archeops
- Goodra
- Goodra (Hisuian Form)
- Drampa
- Duraludon
- Archaludon
- Archeops
- Skarmory
- Crobat
- Goodra
- Hisuian Goodra
- Milotic
### Pokémon Added
#### Generation 3
@@ -164,10 +162,7 @@
- Cofagrigus
- Tyranitar
- Turtonator
- Golett
- Corsola
- Arbok (New Patterns: Angry, Cartoon, Clown, Comedic, Crow, Grin, Ink, Modern, Rain, Scribble, Silence, Sloth, Suspicious, Will)
- ... and Substitute
#### Model changes to the regional bias resource pack:
@@ -176,26 +171,6 @@
- Changed models for every existing regional bias
### Animation updates for the following Pokémon
- Kakuna
- Grimer
- Nidoran♀ (+ New shoulder mount)
- Nidorina
- Nidoran♂ (+ New shoulder mount)
- Sandshrew
- Diglett
- Dugtrio
- Graveler
- Happiny
- Chansey
- Blissey
- Poliwhirl
- Poliwrath
- Zubat
- Vulpix
- Drowzee
- Hypno
- Noctowl
- Skarmory
- Skitty
- Flygon
@@ -227,19 +202,8 @@
- Yamask
- Cofagrigus
- Luvdisc
- Staryu
- Starmie
- Togetic
- Rellor
- Rabsca
- Yungoos
- Gumshoos
- Cottonee
- Whimsicott
- Corsola
#### Added sounds to the following moves
- Absorb
- Aurora Beam
- Double Team
@@ -265,8 +229,13 @@
### Changes
- Stat increase and decrease particles have been changed, with the addition of alpha boost particles.
- Dragonite's mailbag cosmetic can now also be obtained with a chest in the cosmetic slot
### Fixes
- Adjusted Croagunk's walkspeed
- Adjusted Aerodactyl's walkspeed
- Fixed Blitzle's base scale being `1` rather than the intended `0.8`
- Fixed Magnezone's emissive layer for the shiny having the wrong name, thus displaying wrongly
- Fixed Litleo not blinking
- Fixed Garchomp T-posing when sleeping while out of battle.
- Sharp Beak can now be crafted
- Metal Alloy can now be crafted
- Ability Capsules can now be brewed
@@ -319,19 +288,24 @@
- Hearty Grains can be milled like Farmer's Delight Rice Panicles if both Farmer's Delight and Create are installed
- Big Roots and Revival Herbs can be milled to their respective powders
- Pep-Up Flowers, Medicinal Leeks, and all 70 berries can be milled in Create's Millstone for additional dye drops
- Auspicious Armour and Upgrades can be Haunted using Create's crafting systems
- Auspicious Armor and Upgrades can be Haunted using Create's crafting systems
- Applin Apples can be used to make Honeyed Apples in Create
- Golden Apples can now be crafted using the Applin Apples
- Prismarine Crystals and Amethyst Shards can now be used to craft Pokedexes
- Updated Pokédex Screens item tag to support tagged variants of Redstone and Glowstone Dust
- Sounds for interacting with various Cobblemon blocks now play from the centre of the block, rather than the corner
- Updated Pokedex Screens item tag to support tagged variants of Redstone and Glowstone Dust
- Sounds for interacting with various Cobblemon blocks now play from the center of the block, rather than the corner
- The `/pc` command no longer plays PC activation sounds
- Lowered the volume of Blitzle and Zebstrika's cry
- Fixed Raichu (male) and Alolan Raichu (both genders) not displaying the correct Partner Cap when Pewter Crunchies are in the cosmetic slot.
- Regional Foods will now prioritize being eaten instead of used for healing Pokémon, shift clicking will use it as healing
- Resolved Z-Fighting on Pokédex Models
- Restored Ninjask's ability to do barrel rolls
### Fixes
- Fixed Croagunk's walkspeed
- Fixed Blitzle's base scale being `1` rather than the intended `0.8`
- Fixed Magnezone's emissive layer for the shiny having the wrong name, thus displaying wrongly
- Fixed Litleo not blinking
- Fixed Omanyte and Omastar incorrectly using water animations on land.
- Fixed Pokédex layout for genderless variations
- Fixed odd stacking behaviour with the poke_bait item.
- Fixed a compatibility issue with World Game Rules which caused some log spam in specific cases.
@@ -373,30 +347,9 @@
- Fixed Exploit where you could take out the bait or drop your Pokérod with bait to avoid consuming bait, now the bobber will just disappear if you do so
- Fixed Apricorn and Saccharine boats incorrectly using chest boat models
- Fixed wild and trainer battle AI refusing to select moves with the `adjacentAlly` target type, even when it's their only option
- Fixed gilded chests being more accessible than intended
- Fixed Guilded chests being more accessible than intended
- Fixed fished up Pokémon not being added as "seen" to the Pokedex
- Fixed surprised Gimmighoul encounters not being added as "seen" to the Pokedex
- Fixed a crash involving berry trees that have been world edited.
- Fixed visual desync in multiplayer for players mounting Pokémon outside other players' loaded chunks
- Fixed Pokémon entities leveled by rare candy not getting stronger as Minecraft entities unless recalled.
- Fixed a freeze during game load that occurred when multiple mods tried to load Cobblemon API classes at the same time.
- Fixed random tick crashes from berry trees
- Lowered the volume of Blitzle and Zebstrika's cry
- Regional Foods will now prioritise being eaten instead of used for healing Pokémon, shift clicking will use it as healing
- Resolved Z-Fighting on Pokédex Models
- Restored Ninjask's ability to do barrel rolls
- Fixed Raichu (male) and Alolan Raichu (both genders) not displaying the correct Partner Cap when Pewter Crunchies are in the cosmetic slot.
- Fixed a crash caused by adding enchanted items to the Resurrection Machine
- Fixed a crash that could occur when starting a PvN battle with only fainted Pokémon.
- Fixed the Remember Riding Camera config not being respected when dismounting and resolved the incompatibility with the Auto Third Person mod
- Fixed Full Heal block not dropping Full Heals
- Fixed status cure items not returning an empty bottle when used
- Fixed Panpour consuming its held item when evolving with a Water Stone
- Fixed Smoked Tail Curry returning a Wooden Bowl when consumed despite it not being included in the recipe
- Fixed `/giveallpokemon` not respecting the min and max parameters
- Fixed the choose starter toast not disappearing when capturing a Pokémon instead of opening the starter selection screen
- Fixed an issue where certain Sinister Tea seasonings were only applying as instant effects and would not apply over time
- Long config option labels now scroll instead of overflowing
### Developer
- Added `PokeSnackSpawnerFactory` which allows influence registration on PokeSnack encounters
@@ -407,9 +360,6 @@
- Separated all the functions of MoLangFunctions.kt into their own files.
- Spawn buckets and their base weights are now provided by the spawner, with different base weights for world, fishing, snack, and habitat spawn buckets.
- Removed "SpawnBucket" class in favour of just storing maps of bucket names to weights.
- Fixed nicknames not being applied to Pokémon spawned from `spawn_pool_world` files.
- Added support for `profilePokedexScale`, `profilePokedexTranslation`, `profileSummaryScale`, and `profileSummaryTranslation` in poser files for finer control over profile displays.
- Fixed riding camera offsets defined on Pokémon forms not being applied
### Molang & Datapacks
- Added `moveset_builders` datapack folder for different styles of movesets.
@@ -420,7 +370,6 @@
- Added `q.item.is_enchanted()`
- Added `q.item.has_enchantment(minecraft:sharpness, 3)`
- Added `has_chosen_starter` & `get_starter_uuid` as available Molang functions
- Added `has_tm_move_unlocked`, `unlock_tm_move`, & `lock_tm_move` as available Molang functions for Players
- Added `marks`, `has_mark`, & `remove_marks` as available Molang functions for Pokémon
- Added Data Component support for species drops, eg `"components": {"minecraft:custom_model_data": 123}`
- Added the new `sortOrder` field to mark entries, (defaults to 0 if not specified) which controls the order in which marks are rendered on the HUD, with higher numbers being rendered on top of lower numbers
@@ -511,7 +460,6 @@
- German
- Spanish
- Ecuadorian Spanish
- Portuguese
- Brazilian Portuguese
- Simplified Chinese
- Traditional Chinese
@@ -20,8 +20,6 @@ import net.minecraft.world.level.levelgen.structure.pools.alias.PoolAliasLookup;
import net.minecraft.world.level.levelgen.structure.templatesystem.LiquidSettings;
import net.minecraft.world.level.levelgen.structure.templatesystem.StructureProcessor;
import net.minecraft.world.level.levelgen.structure.templatesystem.StructureProcessorList;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.At;
@@ -33,9 +31,6 @@ import java.util.Optional;
@Mixin(JigsawPlacement.class)
public class JigsawPlacementMixin {
@Unique
private static final Logger cobblemon$LOGGER = LoggerFactory.getLogger("Cobblemon/HeightRangeVeto");
@Inject(
method = "addPieces(Lnet/minecraft/world/level/levelgen/structure/Structure$GenerationContext;Lnet/minecraft/core/Holder;Ljava/util/Optional;ILnet/minecraft/core/BlockPos;ZLjava/util/Optional;ILnet/minecraft/world/level/levelgen/structure/pools/alias/PoolAliasLookup;Lnet/minecraft/world/level/levelgen/structure/pools/DimensionPadding;Lnet/minecraft/world/level/levelgen/structure/templatesystem/LiquidSettings;)Ljava/util/Optional;",
at = @At("RETURN"),
@@ -59,30 +54,18 @@ public class JigsawPlacementMixin {
if (result.isEmpty()) {
return;
}
BlockPos spawnPos = result.get().position();
String poolId = startPool.unwrapKey().map(key -> key.location().toString()).orElse("unknown");
boolean canPlace = cobblemon$canStructurePlace(context, startPool, spawnPos);
cobblemon$LOGGER.info(
"[HeightRangeVeto] addPieces evaluated requestedPos={} spawnPos={} startPool={} -> canPlace={}",
pos, spawnPos, poolId, canPlace
);
boolean canPlace = cobblemon$canAnyStartElementPlace(context, startPool, spawnPos);
if (canPlace) {
return;
}
cobblemon$LOGGER.info(
"[HeightRangeVeto] Vetoing structure start at {} (startPool={})",
spawnPos, poolId
);
cir.setReturnValue(Optional.empty());
}
@Unique
private static boolean cobblemon$canStructurePlace(
private static boolean cobblemon$canAnyStartElementPlace(
Structure.GenerationContext generationContext,
Holder<StructureTemplatePool> startPool,
BlockPos startPos
@@ -91,7 +74,7 @@ public class JigsawPlacementMixin {
Optional<HeightRangeStructureProcessor> heightRangeProcessor = cobblemon$getHeightRangeProcessor(element);
if (heightRangeProcessor.isEmpty()) {
continue;
return true;
}
HeightRangeStructureProcessor processor = heightRangeProcessor.get();
@@ -102,17 +85,12 @@ public class JigsawPlacementMixin {
startPos
);
cobblemon$LOGGER.info(
"[HeightRangeVeto] template={} pos={} valid={}",
element, startPos, valid
);
if (!valid) {
return false;
if (valid) {
return true;
}
}
return true;
return false;
}
@Unique
@@ -108,7 +108,6 @@ import com.cobblemon.mod.common.pokemon.helditem.CobblemonHeldItemManager
import com.cobblemon.mod.common.pokemon.properties.AspectPropertyType
import com.cobblemon.mod.common.pokemon.properties.BattleCloneProperty
import com.cobblemon.mod.common.pokemon.properties.FreezeFrameProperty
import com.cobblemon.mod.common.pokemon.properties.HeldItemVisibleProperty
import com.cobblemon.mod.common.pokemon.properties.HiddenAbilityPropertyType
import com.cobblemon.mod.common.pokemon.properties.LabelProperty
import com.cobblemon.mod.common.pokemon.properties.NoAIProperty
@@ -351,7 +350,6 @@ object Cobblemon {
CustomPokemonProperty.register(UnaspectPropertyType)
CustomPokemonProperty.register(FreezeFrameProperty)
CustomPokemonProperty.register(NoAIProperty)
CustomPokemonProperty.register(HeldItemVisibleProperty)
CobblemonEvents.POKEMON_PROPERTY_INITIALISED.emit(Unit)
@@ -405,7 +405,7 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
@JvmField
val BIG_MALASADA = regionalFoodItem("big_malasada", 64, 7, 0.3f, false)
@JvmField
val SMOKED_TAIL_CURRY = regionalFoodItem("smoked_tail_curry", 64, 10, 0.6f, false)
val SMOKED_TAIL_CURRY = regionalFoodItem("smoked_tail_curry", 64, 10, 0.6f, false, ItemStack(Items.BOWL, 1))
@JvmField
val JUBILIFE_MUFFIN = regionalFoodItem("jubilife_muffin", 64, 7, 0.3f, false)
@JvmField
@@ -35,7 +35,6 @@ import com.cobblemon.mod.common.client.net.gui.PokedexUIPacketHandler
import com.cobblemon.mod.common.client.net.gui.SetActiveTMPacketHandler
import com.cobblemon.mod.common.client.net.gui.SetTMMachineContainerDataPacketHandler
import com.cobblemon.mod.common.client.net.gui.SummaryUIPacketHandler
import com.cobblemon.mod.common.client.net.gui.SynchronizeActiveTMHandler
import com.cobblemon.mod.common.client.net.habitat.OpenHabitatBlockEditorHandler
import com.cobblemon.mod.common.client.net.npc.CloseNPCEditorHandler
import com.cobblemon.mod.common.client.net.npc.OpenNPCEditorHandler
@@ -148,7 +147,6 @@ import com.cobblemon.mod.common.net.messages.client.ui.PokedexUIPacket
import com.cobblemon.mod.common.net.messages.client.ui.SetActiveTMPacket
import com.cobblemon.mod.common.net.messages.client.ui.SetTMMachineContainerDataPacket
import com.cobblemon.mod.common.net.messages.client.ui.SummaryUIPacket
import com.cobblemon.mod.common.net.messages.client.ui.SynchronizeActiveTMPacket
import com.cobblemon.mod.common.net.messages.server.BattleChallengePacket
import com.cobblemon.mod.common.net.messages.server.BattleChallengeResponsePacket
import com.cobblemon.mod.common.net.messages.server.BenchMovePacket
@@ -377,7 +375,6 @@ object CobblemonNetwork {
list.add(PacketRegisterInfo(PlayerInteractOptionsPacket.ID, PlayerInteractOptionsPacket::decode, PlayerInteractOptionsHandler))
list.add(PacketRegisterInfo(PokedexUIPacket.ID, PokedexUIPacket::decode, PokedexUIPacketHandler))
list.add(PacketRegisterInfo(ExpGainedDataPacket.ID, ExpGainedDataPacket::decode, ExpGainedDataPacketHandler))
list.add(PacketRegisterInfo(SynchronizeActiveTMPacket.ID, SynchronizeActiveTMPacket::decode, SynchronizeActiveTMHandler))
// Starter packets
list.add(PacketRegisterInfo(OpenStarterUIPacket.ID, OpenStarterUIPacket::decode, StarterUIPacketHandler))
@@ -8,7 +8,6 @@
package com.cobblemon.mod.common.api.cooking.effects
import net.minecraft.server.level.ServerPlayer
import net.minecraft.world.effect.MobEffect
import net.minecraft.world.effect.MobEffectCategory
import net.minecraft.world.entity.Entity
@@ -19,13 +18,5 @@ class CleanseAllEffect : MobEffect(MobEffectCategory.BENEFICIAL, 0xFFFFFF) {
override fun applyInstantenousEffect(source: Entity?, indirect: Entity?, target: LivingEntity, amplifier: Int, proximity: Double) {
target.removeAllEffects()
}
override fun applyEffectTick(livingEntity: LivingEntity, amplifier: Int): Boolean {
if (livingEntity is ServerPlayer){
livingEntity.removeAllEffects()
}
return true
}
override fun shouldApplyEffectTickThisTick(duration: Int, amplifier: Int) = true
override fun shouldApplyEffectTickThisTick(duration: Int, amplifier: Int) = false
}
@@ -8,7 +8,6 @@
package com.cobblemon.mod.common.api.cooking.effects
import net.minecraft.server.level.ServerPlayer
import net.minecraft.world.effect.MobEffect
import net.minecraft.world.effect.MobEffectCategory
import net.minecraft.world.entity.Entity
@@ -24,18 +23,5 @@ class CleanseNegativeEffect : MobEffect(MobEffectCategory.BENEFICIAL, 0xFFFFFF)
}
}
}
override fun applyEffectTick(livingEntity: LivingEntity, amplifier: Int): Boolean {
if (livingEntity is ServerPlayer){
val snapshot = livingEntity.activeEffects.toList()
for (ei in snapshot) {
if (ei.effect.value().category == MobEffectCategory.HARMFUL) {
livingEntity.removeEffect(ei.effect)
}
}
}
return true
}
override fun shouldApplyEffectTickThisTick(duration: Int, amplifier: Int) = true
override fun shouldApplyEffectTickThisTick(duration: Int, amplifier: Int) = false
}
@@ -10,7 +10,6 @@ package com.cobblemon.mod.common.api.gui
import com.cobblemon.mod.common.client.gui.CobblemonRenderable
import net.minecraft.client.gui.components.AbstractWidget
import net.minecraft.client.gui.components.Renderable
import net.minecraft.client.gui.components.events.GuiEventListener
import net.minecraft.client.gui.narration.NarrationElementOutput
import net.minecraft.network.chat.Component
@@ -55,6 +54,8 @@ abstract class ParentWidget(
}
override fun mouseClicked(pMouseX: Double, pMouseY: Double, pButton: Int): Boolean {
if (!active) return false
return children.any {
it.mouseClicked(pMouseX, pMouseY, pButton)
}
@@ -0,0 +1,116 @@
/*
* 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.gui
import kotlin.math.max
import kotlin.math.min
interface TreeNode<T> {
val children: List<TreeNode<T>>
}
class TreeDrawingNode<T>(
val value: T,
val children: List<TreeDrawingNode<T>>,
) {
var x = 0
var y = 0
var offset = 0
}
fun <T> createDrawingTree(treeNode: TreeNode<T>): TreeDrawingNode<T> {
val root = setup(treeNode, 0, mutableListOf<Int>(), mutableListOf<Int>())
addMods(root, 0)
return root
}
@Suppress("UNCHECKED_CAST")
private fun <T> setup(
treeNode: TreeNode<T>,
depth: Int,
nexts: MutableList<Int>,
offset: MutableList<Int>,
): TreeDrawingNode<T> {
val children = treeNode.children.map { child ->
setup(child, depth + 1, nexts, offset)
}
val treeDrawingNode = TreeDrawingNode<T>(treeNode as T, children)
treeDrawingNode.y = depth
while (nexts.size <= depth) {
nexts.add(0)
}
while (offset.size <= depth) {
offset.add(0)
}
var place =
if (children.isEmpty()) {
nexts[depth]
} else if (children.size == 1) {
// children.first().x - 1
children.first().x
} else {
// (children[0].x + children[1].x) / 2
(children.first().x + children.last().x) / 2
}
offset[depth] = max(offset[depth], nexts[depth] - place)
if (children.isEmpty()) {
treeDrawingNode.x = place
} else {
treeDrawingNode.x = place + offset[depth]
}
nexts[depth] += 2
treeDrawingNode.offset = offset[depth]
return treeDrawingNode
}
private fun <T> addMods(
treeNode: TreeDrawingNode<T>,
modSum: Int,
) {
treeNode.x += modSum
val newModSum = modSum + treeNode.offset
treeNode.children.forEach { child ->
addMods(child, newModSum)
}
}
data class TreeDrawingBounds(val minX: Int, val maxX: Int, val minY: Int, val maxY: Int) {
val width = maxX - minX
val height = maxY - minY
val xCenter = (maxX + minX) / 2.0
val yCenter = (maxY + minY) / 2.0
}
fun <T> calculateBounds(treeDrawingNode: TreeDrawingNode<T>): TreeDrawingBounds {
var minX = treeDrawingNode.x
var maxX = treeDrawingNode.x
var minY = treeDrawingNode.y
var maxY = treeDrawingNode.y
for (child in treeDrawingNode.children) {
val childBounds = calculateBounds(child)
minX = min(minX, childBounds.minX)
maxX = max(maxX, childBounds.maxX)
minY = min(minY, childBounds.minY)
maxY = max(maxY, childBounds.maxY)
}
return TreeDrawingBounds(minX, maxX, minY, maxY)
}
@@ -69,7 +69,7 @@ class HabitatPool {
pool.spawns = spawns
return pool
} else {
return HabitatPools.habitatPoolsById[poolId] ?: default()
return HabitatPools.habitatPoolsById[poolId] ?: HabitatPool.default()
}
}
}
@@ -94,14 +94,6 @@ class HabitatPool {
return spawns.mapNotNull { it.createSpawnDetail(habitatBlockEntity) }
}
fun getPhaseCount(): Int {
return spawns
.flatMap { it.phases?.ranges?.flatten() ?: emptySet() }
.toSet()
.count()
.coerceAtLeast(1)
}
fun encode(buffer: RegistryFriendlyByteBuf) {
buffer.writeResourceLocation(id)
buffer.writeUtf(name)
@@ -17,6 +17,7 @@ import net.minecraft.network.RegistryFriendlyByteBuf
import net.minecraft.resources.ResourceLocation
class HabitatSettingsDTO() {
var numberOfPhases = 1
var phaseOrder = HabitatPhaseOrder.SIMPLE
lateinit var levelRange: IntRange
var modifiers: String = ""
@@ -27,6 +28,7 @@ class HabitatSettingsDTO() {
var naturalSettings: NaturalHabitatSettingsDTO? = null
constructor(habitatBlockEntity: HabitatBlockEntity) : this() {
this.numberOfPhases = habitatBlockEntity.numberOfPhases
this.phaseOrder = habitatBlockEntity.phaseOrder
this.levelRange = habitatBlockEntity.levelRange
this.modifiers = habitatBlockEntity.modifiers.asString()
@@ -42,6 +44,7 @@ class HabitatSettingsDTO() {
}
fun encode(buffer: RegistryFriendlyByteBuf) {
buffer.writeInt(numberOfPhases)
buffer.writeEnum(phaseOrder)
buffer.writeInt(levelRange.first)
buffer.writeInt(levelRange.last)
@@ -57,6 +60,7 @@ class HabitatSettingsDTO() {
}
fun decode(buffer: RegistryFriendlyByteBuf) {
this.numberOfPhases = buffer.readInt()
this.phaseOrder = buffer.readEnum(HabitatPhaseOrder::class.java)
val levelRangeStart = buffer.readInt()
val levelRangeEnd = buffer.readInt()
@@ -17,8 +17,6 @@ import com.bedrockk.molang.runtime.value.MoValue
import com.bedrockk.molang.runtime.value.StringValue
import com.cobblemon.mod.common.Cobblemon
import com.cobblemon.mod.common.CobblemonBlockEntities
import com.cobblemon.mod.common.api.moves.Moves
import com.cobblemon.mod.common.api.tms.TechnicalMachines
import com.cobblemon.mod.common.api.dialogue.PlayerDialogueFaceProvider
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMoLangValue
import com.cobblemon.mod.common.api.molang.ObjectValue
@@ -46,7 +44,6 @@ import com.cobblemon.mod.common.util.party
import com.cobblemon.mod.common.util.pc
import com.cobblemon.mod.common.util.pokedex
import com.cobblemon.mod.common.util.server
import com.cobblemon.mod.common.util.tmList
import net.minecraft.core.registries.BuiltInRegistries
import net.minecraft.core.registries.Registries
import net.minecraft.resources.ResourceLocation
@@ -315,23 +312,6 @@ object PlayerMoLangFunctions : AbstractMoLangFunctionHolder<Player>() {
}
return@put DoubleValue.ZERO
}
map["has_tm_move_unlocked"] = put@{ params ->
val move = Moves.getByName(params.getString(0)) ?: return@put DoubleValue.ZERO
val tm = TechnicalMachines.moveToTM[move] ?: return@put DoubleValue.ZERO
DoubleValue(if (player.tmList().learnedTMs.contains(tm.id)) 1.0 else 0.0)
}
map["unlock_tm_move"] = put@{ params ->
val move = Moves.getByName(params.getString(0)) ?: return@put DoubleValue.ZERO
val tm = TechnicalMachines.moveToTM[move] ?: return@put DoubleValue.ZERO
player.tmList().syncTMFromMove(move)
DoubleValue(if (player.tmList().learnedTMs.contains(tm.id)) 1.0 else 0.0)
}
map["lock_tm_move"] = put@{ params ->
val move = Moves.getByName(params.getString(0)) ?: return@put DoubleValue.ZERO
val tm = TechnicalMachines.moveToTM[move] ?: return@put DoubleValue.ZERO
player.tmList().syncTMLockFromMove(move)
DoubleValue(if (player.tmList().learnedTMs.contains(tm.id)) 0.0 else 1.0)
}
map["start_battle"] = put@{ params ->
val opponentValue = params.get<MoValue>(0)
val opponent = if (opponentValue is ObjectValue<*>) {
@@ -72,6 +72,40 @@ abstract class AbstractPokedexManager {
} ?: PokedexEntryProgress.UNREGISTERED
}
fun getHighestKnowledgeFor(entry: PokedexEntry, form: PokedexForm?): PokedexEntryProgress {
if (form == null) return getHighestKnowledgeFor(entry)
val speciesRecord = getSpeciesRecord(entry.speciesId) ?: return PokedexEntryProgress.UNREGISTERED
val hasAllAspects = entry.conditionAspects.all(speciesRecord::hasAspect)
if (!hasAllAspects) {
return PokedexEntryProgress.UNREGISTERED
}
return speciesRecord.getFormRecord(form.displayForm)?.knowledge ?: PokedexEntryProgress.UNREGISTERED
}
fun getHighestKnowledgeFor(entry: PokedexEntry, form: PokedexForm?, aspects: Iterable<String>): PokedexEntryProgress {
val formKnowledge = getHighestKnowledgeFor(entry, form)
if (formKnowledge == PokedexEntryProgress.UNREGISTERED) return PokedexEntryProgress.UNREGISTERED
val seenAspects = getSeenAspects(entry)
val allSeenAspects = aspects
// TODO this is ugly
.filter { it ->
if (Dexes.equivalentFormsLookup[it] != null) return@filter false
if (it.uppercase() in setOf(Gender.MALE.name, Gender.FEMALE.name, Gender.GENDERLESS.name)) return@filter false
if ("shiny".equals(it, ignoreCase = true)) return@filter false
return@filter true
}
.all { it -> seenAspects.contains(it) }
if (!allSeenAspects) return PokedexEntryProgress.UNREGISTERED
return formKnowledge
}
fun getEncounteredForms(entry: PokedexEntry) : List<PokedexForm> {
return getFormsWithKnowledge(entry, PokedexEntryProgress.SEEN)
}
@@ -10,6 +10,9 @@ package com.cobblemon.mod.common.api.pokedex
import com.cobblemon.mod.common.api.data.JsonDataRegistry
import com.cobblemon.mod.common.api.pokedex.def.PokedexDef
import com.cobblemon.mod.common.api.pokedex.entry.PokedexEntry
import com.cobblemon.mod.common.api.pokedex.entry.PokedexForm
import com.cobblemon.mod.common.api.pokemon.PokemonSpecies
import com.cobblemon.mod.common.api.reactive.SimpleObservable
import com.cobblemon.mod.common.net.messages.client.data.PokedexDexSyncPacket
import com.cobblemon.mod.common.util.adapters.CodecBackedAdapter
@@ -40,6 +43,17 @@ object Dexes : JsonDataRegistry<PokedexDef> {
//Maps a dex id to its PokedexDef
val dexEntryMap = linkedMapOf<ResourceLocation, PokedexDef>()
val equivalentForms = mapOf(
"galar" to listOf("region-bias-galar", "bias-galar", "galar-bias", "galarian", "galar"),
"alola" to listOf("region-bias-alola", "bias-alola", "alola-bias", "alolan", "alola"),
"hisui" to listOf("region-bias-hisui", "bias-hisui", "hisui-bias", "hisuian", "hisui"),
"paldea" to listOf("region-bias-paldea", "bias-paldea", "paldea-bias", "paldean", "paldea"),
)
val equivalentFormsLookup = equivalentForms.flatMap { (key, values) ->
values.map { it to key }
}.toMap()
override fun reload(data: Map<ResourceLocation, PokedexDef>) {
dexEntryMap.clear()
data.entries.sortedBy { it.value.sortOrder }.forEach { (id, def) -> dexEntryMap[id] = def }
@@ -49,4 +63,34 @@ object Dexes : JsonDataRegistry<PokedexDef> {
override fun sync(player: ServerPlayer) {
PokedexDexSyncPacket(dexEntryMap.values).sendToPlayer(player)
}
fun findDexEntryBySpeciesId(regionId: ResourceLocation, speciesId: ResourceLocation): PokedexEntry? {
return dexEntryMap[regionId]?.getEntries()?.firstOrNull { it -> it.speciesId == speciesId }
}
fun findDexEntryBySpeciesId(speciesId: ResourceLocation): PokedexEntry? {
return findDexEntryBySpeciesId(cobblemonResource("national"), speciesId)
}
fun findRootDexEntryBySpeciesId(speciesId: ResourceLocation, formName: String): Pair<PokedexEntry, PokedexForm> {
var rootSpecies = speciesId.let { PokemonSpecies.getByIdentifier(it) }!!
while (rootSpecies.preEvolution != null) {
rootSpecies = rootSpecies.preEvolution!!.species
}
val entry = findDexEntryBySpeciesId(rootSpecies.resourceIdentifier)
?: throw RuntimeException("Root dex entry not found")
val formEquivalents = getFormEquivalents(formName)
val form =
entry.forms.firstOrNull { formEquivalents.contains(it.displayForm.lowercase()) } ?:
entry.forms.first { it.displayForm.equals("Normal", ignoreCase = true) }
return entry to form
}
fun getFormEquivalents(formName: String): List<String> {
val key = equivalentFormsLookup[formName.lowercase()]
return equivalentForms[key] ?: listOf(formName.lowercase())
}
}
@@ -759,7 +759,6 @@ open class PokemonProperties {
shiny?.let { json.addProperty(DataKeys.POKEMON_SHINY, it) }
gender?.let { json.addProperty(DataKeys.POKEMON_GENDER, it.name) }
species?.let { json.addProperty(DataKeys.POKEMON_SPECIES_TEXT, it) }
nickname?.let { json.addProperty(DataKeys.POKEMON_NICKNAME, it.string) }
form?.let { json.addProperty(DataKeys.POKEMON_FORM_ID, it) }
friendship?.let { json.addProperty(DataKeys.POKEMON_FRIENDSHIP, it) }
fullness?.let { json.addProperty(DataKeys.POKEMON_FULLNESS, it) }
@@ -796,7 +795,6 @@ open class PokemonProperties {
shiny = json.get(DataKeys.POKEMON_SHINY)?.asBoolean
gender = json.get(DataKeys.POKEMON_GENDER)?.asString?.let { Gender.valueOf(it) }
species = json.get(DataKeys.POKEMON_SPECIES_TEXT)?.asString
nickname = json.get(DataKeys.POKEMON_NICKNAME)?.asString?.let(Component::literal)
form = json.get(DataKeys.POKEMON_FORM_ID)?.asString
friendship = json.get(DataKeys.POKEMON_FRIENDSHIP)?.asInt
fullness = json.get(DataKeys.POKEMON_FULLNESS)?.asInt
@@ -0,0 +1,30 @@
/*
* 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.pokemon.evolution
import com.cobblemon.mod.common.pokemon.evolution.variants.*
interface EvolutionVisitor<R> {
fun visit(evolution: Evolution): R? {
return when (evolution) {
is BlockClickEvolution -> visitBlockClickEvolution(evolution)
is DummyEvolution -> visitDummyEvolution(evolution)
is ItemInteractionEvolution -> visitItemInteractionEvolution(evolution)
is LevelUpEvolution -> visitLevelUpEvolution(evolution)
is TradeEvolution -> visitTradeEvolution(evolution)
else -> null
}
}
fun visitBlockClickEvolution(blockClickEvolution: BlockClickEvolution): R
fun visitDummyEvolution(evolution: Evolution): R // TODO: Use dummyEvolution?
fun visitItemInteractionEvolution(itemInteractionEvolution: ItemInteractionEvolution): R
fun visitLevelUpEvolution(levelUpEvolution: LevelUpEvolution): R
fun visitTradeEvolution(tradeEvolution: TradeEvolution): R
}
@@ -21,7 +21,7 @@ import net.minecraft.world.entity.LivingEntity
* @author Licious
* @since March 21st, 2022
*/
interface EntityQueryRequirement : Requirement {
abstract class EntityQueryRequirement : Requirement() {
override fun check(pokemon: Pokemon): Boolean {
val queriedEntity = pokemon.entity ?: pokemon.getOwnerPlayer() ?: return false
return this.check(pokemon, queriedEntity)
@@ -34,5 +34,5 @@ interface EntityQueryRequirement : Requirement {
* @param queriedEntity The [LivingEntity] that can be compared in context of a [Level].
* @return If the requirement was satisfied.
*/
fun check(pokemon: Pokemon, queriedEntity: LivingEntity): Boolean
abstract fun check(pokemon: Pokemon, queriedEntity: LivingEntity): Boolean
}
@@ -23,7 +23,7 @@ import net.minecraft.world.entity.player.Player
* @author Polymeta
* @since May 6th, 2025
*/
interface OwnerQueryRequirement : Requirement {
abstract class OwnerQueryRequirement : Requirement() {
override fun check(pokemon: Pokemon): Boolean {
val owner = pokemon.getOwnerEntity() ?: return false
return when (owner) {
@@ -44,7 +44,7 @@ interface OwnerQueryRequirement : Requirement {
* @param owner The [Player] that owns this [Pokemon].
* @return If the requirement was satisfied.
*/
fun checkPlayer(pokemon: Pokemon, owner: Player): Boolean
abstract fun checkPlayer(pokemon: Pokemon, owner: Player): Boolean
/**
* Checks if the given [Pokemon] & [NPCEntity] satisfies the requirement.
@@ -55,5 +55,5 @@ interface OwnerQueryRequirement : Requirement {
* @param owner The [NPCEntity] that owns this [Pokemon].
* @return If the requirement was satisfied.
*/
fun checkNPC(pokemon: Pokemon, owner: NPCEntity): Boolean
abstract fun checkNPC(pokemon: Pokemon, owner: NPCEntity): Boolean
}
@@ -11,6 +11,7 @@ package com.cobblemon.mod.common.api.pokemon.requirement
import com.cobblemon.mod.common.api.pokemon.evolution.ContextEvolution
import com.cobblemon.mod.common.api.pokemon.evolution.Evolution
import com.cobblemon.mod.common.pokemon.Pokemon
import net.minecraft.resources.ResourceLocation
/**
* Represents a universal requirement suitable for various checks on pokemon..
@@ -22,7 +23,7 @@ import com.cobblemon.mod.common.pokemon.Pokemon
* @author Licious
* @since March 19th, 2022
*/
fun interface Requirement {
abstract class Requirement {
/**
* Checks if the given [Pokemon] satisfies the requirement.
@@ -30,6 +31,8 @@ fun interface Requirement {
* @param pokemon The [Pokemon] being queried.
* @return If the requirement was satisfied.
*/
fun check(pokemon: Pokemon): Boolean
abstract fun check(pokemon: Pokemon): Boolean
val pokedexIcon: ResourceLocation? = null
val pokedexTooltip: String? = null
}
@@ -0,0 +1,74 @@
/*
* 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.pokemon.requirement
import com.cobblemon.mod.common.pokemon.requirements.*
interface RequirementVisitor<R> {
fun visit(requirement: Requirement): R? {
return when (requirement) {
is AdvancementRequirement -> visitAdvancementRequirement(requirement)
is AnyRequirement -> visitAnyRequirement(requirement)
is AreaRequirement -> visitAreaRequirement(requirement)
is AttackDefenceRatioRequirement -> visitAttackDefenceRatioRequirement(requirement)
is BattleCriticalHitsRequirement -> visitBattleCriticalHitsRequirement(requirement)
is BiomeRequirement -> visitBiomeRequirement(requirement)
is BlocksTraveledRequirement -> visitBlocksTraveledRequirement(requirement)
is DamageTakenRequirement -> visitDamageTakenRequirement(requirement)
is DefeatRequirement -> visitDefeatRequirement(requirement)
is FriendshipRequirement -> visitFriendshipRequirement(requirement)
is HeldItemRequirement -> visitHeldItemRequirement(requirement)
is LevelRequirement -> visitLevelRequirement(requirement)
is MoonPhaseRequirement -> visitMoonPhaseRequirement(requirement)
is MoveSetRequirement -> visitMoveSetRequirement(requirement)
is MoveTypeRequirement -> visitMoveTypeRequirement(requirement)
is OwnerHoldsItemRequirement -> visitOwnerHoldsItemRequirement(requirement)
is PartyMemberRequirement -> visitPartyMemberRequirement(requirement)
is PokemonPropertiesRequirement -> visitPokemonPropertiesRequirement(requirement)
is PropertyRangeRequirement -> visitPropertyRangeRequirement(requirement)
is RecoilRequirement -> visitRecoilRequirement(requirement)
is StatCompareRequirement -> visitStatCompareRequirement(requirement)
is StatEqualRequirement -> visitStatEqualRequirement(requirement)
is StructureRequirement -> visitStructureRequirement(requirement)
is TimeRangeRequirement -> visitTimeRangeRequirement(requirement)
is UseMoveRequirement -> visitUseMoveRequirement(requirement)
is WeatherRequirement -> visitWeatherRequirement(requirement)
is WorldRequirement -> visitWorldRequirement(requirement)
else -> null
}
}
fun visitAdvancementRequirement(advancementRequirement: AdvancementRequirement): R
fun visitAnyRequirement(anyRequirement: AnyRequirement): R
fun visitAreaRequirement(areaRequirement: AreaRequirement): R
fun visitAttackDefenceRatioRequirement(attackDefenceRatioRequirement: AttackDefenceRatioRequirement): R
fun visitBattleCriticalHitsRequirement(battleCriticalHitsRequirement: BattleCriticalHitsRequirement): R
fun visitBiomeRequirement(biomeRequirement: BiomeRequirement): R
fun visitBlocksTraveledRequirement(blocksTraveledRequirement: BlocksTraveledRequirement): R
fun visitDamageTakenRequirement(damageTakenRequirement: DamageTakenRequirement): R
fun visitDefeatRequirement(defeatRequirement: DefeatRequirement): R
fun visitFriendshipRequirement(friendshipRequirement: FriendshipRequirement): R
fun visitHeldItemRequirement(heldItemRequirement: HeldItemRequirement): R
fun visitLevelRequirement(levelRequirement: LevelRequirement): R
fun visitMoonPhaseRequirement(moonPhaseRequirement: MoonPhaseRequirement): R
fun visitMoveSetRequirement(moveSetRequirement: MoveSetRequirement): R
fun visitMoveTypeRequirement(moveTypeRequirement: MoveTypeRequirement): R
fun visitOwnerHoldsItemRequirement(ownerHoldsItemRequirement: OwnerHoldsItemRequirement): R
fun visitPartyMemberRequirement(partyMemberRequirement: PartyMemberRequirement): R
fun visitPokemonPropertiesRequirement(pokemonPropertiesRequirement: PokemonPropertiesRequirement): R
fun visitPropertyRangeRequirement(propertyRangeRequirement: PropertyRangeRequirement): R
fun visitRecoilRequirement(recoilRequirement: RecoilRequirement): R
fun visitStatCompareRequirement(statCompareRequirement: StatCompareRequirement): R
fun visitStatEqualRequirement(statEqualRequirement: StatEqualRequirement): R
fun visitStructureRequirement(structureRequirement: StructureRequirement): R
fun visitTimeRangeRequirement(timeRangeRequirement: TimeRangeRequirement): R
fun visitUseMoveRequirement(useMoveRequirement: UseMoveRequirement): R
fun visitWeatherRequirement(weatherRequirement: WeatherRequirement): R
fun visitWorldRequirement(worldRequirement: WorldRequirement): R
}
@@ -10,6 +10,8 @@ package com.cobblemon.mod.common.api.spawning
import com.cobblemon.mod.common.api.spawning.TimeRange.Companion.timeRanges
import com.cobblemon.mod.common.api.spawning.condition.SpawningCondition
import com.cobblemon.mod.common.util.lang
import net.minecraft.network.chat.MutableComponent
import com.cobblemon.mod.common.util.adapters.IntRangesAdapter
/**
@@ -49,4 +51,25 @@ class TimeRange : IntRanges {
constructor() : super()
constructor(vararg ranges: IntRange) : super(*ranges)
fun displayName(): MutableComponent? {
val key = timeRanges.entries.firstOrNull { entry -> this == entry.value }?.key ?: return null
return lang("ui.time_range.$key")
}
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other !is TimeRange) return false
if (other.ranges.size != this.ranges.size) return false
other.ranges.forEachIndexed { index, otherRange ->
if (this.ranges[index] != otherRange) return false
}
return true
}
override fun hashCode(): Int {
return ranges.hashCode()
}
}
@@ -8,6 +8,8 @@
package com.cobblemon.mod.common.api.spawning.condition
import com.cobblemon.mod.common.util.lang
import net.minecraft.network.chat.MutableComponent
import net.minecraft.world.level.Level
/**
@@ -42,4 +44,7 @@ enum class MoonPhase {
fun ofWorld(world: Level): MoonPhase = VALUES[world.moonPhase]
}
fun displayName(): MutableComponent {
return lang("ui.moon_phase.${this.name.lowercase()}")
}
}
@@ -9,7 +9,6 @@
package com.cobblemon.mod.common.api.tms
import com.cobblemon.mod.common.tms.obtain.DefaultObtainMethod
import com.cobblemon.mod.common.tms.obtain.ImpossibleObtainMethod
import com.cobblemon.mod.common.tms.obtain.PlayerHasAdvancementObtainMethod
import com.cobblemon.mod.common.tms.obtain.PlayerYObtainMethod
import com.cobblemon.mod.common.tms.obtain.UnlockableObtainMethod
@@ -37,7 +36,6 @@ interface ObtainMethod {
val variant = buffer.readUtf()
return when (variant) {
"cobblemon:unlockable" -> UnlockableObtainMethod()
"cobblemon:impossible" -> ImpossibleObtainMethod()
"cobblemon:default" -> DefaultObtainMethod()
"cobblemon:advancement" -> {
val advancement = buffer.readResourceLocation()
@@ -14,8 +14,6 @@ import com.cobblemon.mod.common.advancement.CobblemonCriteria
import com.cobblemon.mod.common.advancement.criterion.CountableContext
import com.cobblemon.mod.common.advancement.criterion.LearnAllTMContext
import com.cobblemon.mod.common.advancement.criterion.LearnTMContext
import com.cobblemon.mod.common.api.abilities.Ability
import com.cobblemon.mod.common.api.abilities.AbilityPool
import com.cobblemon.mod.common.api.moves.MoveTemplate
import com.cobblemon.mod.common.api.scheduling.ScheduledTask
import com.cobblemon.mod.common.api.scheduling.ServerTaskTracker
@@ -52,11 +50,6 @@ class TMMoveManager(
learn(listOf(tmId))
}
fun syncTMLockFromMove(moveTemplate: MoveTemplate) {
val tmId = TechnicalMachines.moveToTM[moveTemplate]?.id ?: return
unlearn(listOf(tmId))
}
fun getLearnableTMsFromPokemon(pokemon: Pokemon): Collection<ResourceLocation> {
val learnableMoves = pokemon.allAccessibleMoves.toMutableSet()
learnableMoves.addAll(pokemon.moveSet.map { it.template })
@@ -42,12 +42,10 @@ class ElementalType(
companion object {
@JvmStatic
val BY_STRING_CODEC: Codec<ElementalType> by lazy {
CodecUtils.createByStringCodec(
ElementalTypes::get,
{ it.showdownId }
) { id -> "No ElementalType for ID $id" }
}
val BY_STRING_CODEC: Codec<ElementalType> = CodecUtils.createByStringCodec(
ElementalTypes::get,
{it.showdownId}
) { id -> "No ElementalType for ID $id" }
}
}
}
@@ -349,12 +349,11 @@ object BattleBuilder {
npcPartyStores.add(npcParty)
}
val playerAvailablePokemon = playerActor.pokemonList.count { it.health > 0 }
if (playerAvailablePokemon < battleFormat.battleType.slotsPerActor) {
if (playerActor.pokemonList.size < battleFormat.battleType.slotsPerActor) {
errors.participantErrors[playerActor] += BattleStartError.insufficientPokemon(
actorEntity = player,
requiredCount = battleFormat.battleType.slotsPerActor,
hadCount = playerAvailablePokemon
hadCount = playerActor.pokemonList.size
)
}
@@ -163,8 +163,7 @@ class TrackerActor(val uuid: UUID) {
//we assume that AI knows it all about our allies
trackerActor.party.addAll(actor.pokemonList.map { createAllied(it) })
actor.activePokemon.forEach {
val battlePokemon = it.battlePokemon ?: return@forEach
val active = trackerActor.party.first { trackMon -> trackMon.id == battlePokemon.uuid }
val active = trackerActor.party.first { trackMon -> trackMon.id == it.battlePokemon!!.uuid }
trackerActor.party.remove(active)
trackerActor.activePokemon.add(active)
}
@@ -177,8 +176,7 @@ class TrackerActor(val uuid: UUID) {
//only know basics of what we see right now
trackerActor.party.addAll(actor.pokemonList.map { createOpposing(it) })
actor.activePokemon.forEach {
val battlePokemon = it.battlePokemon ?: return@forEach
val active = trackerActor.party.first { trackMon -> trackMon.id == battlePokemon.uuid }
val active = trackerActor.party.first { trackMon -> trackMon.id == it.battlePokemon!!.uuid }
trackerActor.party.remove(active)
trackerActor.activePokemon.add(active)
}
@@ -9,6 +9,7 @@
package com.cobblemon.mod.common.block
//import dev.lambdaurora.lambdynlights.util.SodiumDynamicLightHandler.pos
import com.cobblemon.mod.common.CobblemonBlockEntities
import com.cobblemon.mod.common.CobblemonSounds
import com.cobblemon.mod.common.api.berry.Berries
import com.cobblemon.mod.common.api.berry.Berry
@@ -39,11 +40,7 @@ import net.minecraft.world.level.BlockGetter
import net.minecraft.world.level.Level
import net.minecraft.world.level.LevelAccessor
import net.minecraft.world.level.LevelReader
import net.minecraft.world.level.block.BaseEntityBlock
import net.minecraft.world.level.block.Block
import net.minecraft.world.level.block.Blocks
import net.minecraft.world.level.block.BonemealableBlock
import net.minecraft.world.level.block.RenderShape
import net.minecraft.world.level.block.*
import net.minecraft.world.level.block.entity.BlockEntity
import net.minecraft.world.level.block.entity.BlockEntityTicker
import net.minecraft.world.level.block.entity.BlockEntityType
@@ -73,7 +70,7 @@ class BerryBlock(private val berryIdentifier: ResourceLocation, settings: Proper
override fun playerWillDestroy(world: Level, pos: BlockPos, state: BlockState, player: Player): BlockState {
if (!player.isCreative && state.getValue(AGE) == FRUIT_AGE) {
val treeEntity = world.getBlockEntity(pos) as BerryBlockEntity
treeEntity.harvest(world, state, pos, player).forEach { drop -> popResource(world, pos, drop) }
treeEntity.harvest(world, state, pos, player).forEach { drop -> Block.popResource(world, pos, drop) }
}
return super.playerWillDestroy(world, pos, state, player)
}
@@ -95,7 +92,7 @@ class BerryBlock(private val berryIdentifier: ResourceLocation, settings: Proper
// Random Tick handler: uses time compensation to ensure correct growth speed
@Deprecated("Deprecated in Java")
override fun randomTick(state: BlockState, world: ServerLevel, pos: BlockPos, random: RandomSource) {
val blockEntity = world.getBlockEntity(pos) as? BerryBlockEntity? ?: return
val blockEntity = world.getBlockEntity(pos) as? BerryBlockEntity ?: return
// processTick calculates elapsed time and updates timer, returns whether growth is needed
if (blockEntity.processTick(world, pos, state) && !world.getBlockTicks().hasScheduledTick(pos, this)) {
@@ -131,10 +128,7 @@ class BerryBlock(private val berryIdentifier: ResourceLocation, settings: Proper
val newAge = curAge + 1
if (newAge > FRUIT_AGE) return
val newState = state.setValue(AGE, newAge)
val treeEntity = world.getBlockEntity(pos) as? BerryBlockEntity? ?: run {
world.setBlock(pos, Blocks.AIR.defaultBlockState(), UPDATE_CLIENTS)
return
}
val treeEntity = world.getBlockEntity(pos) as BerryBlockEntity
if (curAge == MATURE_AGE) {
treeEntity.generateGrowthPoints(world, newState, pos, null)
determineMutation(world, random, pos, newState)
@@ -152,7 +146,7 @@ class BerryBlock(private val berryIdentifier: ResourceLocation, settings: Proper
for (direction in this.lookupDirections) {
val redirectedPos = pos.offset(direction.normal)
val redirectedState = world.getBlockState(redirectedPos)
val berryBlock = redirectedState.block as? BerryBlock? ?: continue
val berryBlock = redirectedState.block as? BerryBlock ?: continue
val berry = berryBlock.berry() ?: continue
val mutation = this.berry()?.mutationWith(berry) ?: continue
mutations += mutation
@@ -166,7 +160,7 @@ class BerryBlock(private val berryIdentifier: ResourceLocation, settings: Proper
treeEntity.decrementMulchDuration(world, pos, state)
}
val mutation = if (random.nextInt(1000) < mutateChance) mutations.random() else null
(world.getBlockEntity(pos) as? BerryBlockEntity?)?.let { blockEntity ->
(world.getBlockEntity(pos) as? BerryBlockEntity)?.let { blockEntity ->
CobblemonEvents.BERRY_MUTATION_RESULT.post(BerryMutationResultEvent(berry, world, state, pos, berryMutationOffer.mutations, mutation)) { berryMutationResult ->
berryMutationResult.pickedMutation?.let { mutation -> blockEntity.mutate(mutation) }
}
@@ -184,7 +178,7 @@ class BerryBlock(private val berryIdentifier: ResourceLocation, settings: Proper
): Boolean {
val underBlockState = world.getBlockState(pos.below())
val validSoil = state.getValue(IS_ROOTED) || underBlockState.`is`(CobblemonBlockTags.BERRY_SOIL)
val treeEntity = world.getBlockEntity(pos) as? BerryBlockEntity? ?: return false
val treeEntity = world.getBlockEntity(pos) as? BerryBlockEntity ?: return false
return getMulch(treeEntity) == MulchVariant.NONE && state.getValue(AGE) < FLOWER_AGE && validSoil
}
@@ -359,7 +353,7 @@ class BerryBlock(private val berryIdentifier: ResourceLocation, settings: Proper
fun getMulch(entity: BerryBlockEntity) = entity.mulchVariant
fun convertMulchToEntity(world: ServerLevel, state: BlockState, pos: BlockPos) {
val entity = world.getBlockEntity(pos) as? BerryBlockEntity? ?: return
val entity = world.getBlockEntity(pos) as? BerryBlockEntity ?: return
if (state.getValue(MULCH) != MulchVariant.NONE && state.getValue(MULCH) != entity.mulchVariant) {
entity.mulchVariant = state.getValue(MULCH)
world.setBlockAndUpdate(pos, state.setValue(MULCH, MulchVariant.NONE))
@@ -376,9 +370,9 @@ class BerryBlock(private val berryIdentifier: ResourceLocation, settings: Proper
}
private fun harvestBerry(world: Level, state: BlockState, pos: BlockPos, player: Player? = null): Boolean {
val blockEntity = world.getBlockEntity(pos) as? BerryBlockEntity? ?: return false
val blockEntity = world.getBlockEntity(pos) as? BerryBlockEntity ?: return false
blockEntity.harvest(world, state, pos, player).forEach { drop ->
popResource(world, pos, drop)
Block.popResource(world, pos, drop)
}
val sound = if (player != null) CobblemonSounds.BERRY_HARVEST else SoundEvents.SHEEP_SHEAR
@@ -16,20 +16,24 @@ import net.minecraft.core.BlockPos
import net.minecraft.core.Direction
import net.minecraft.core.HolderLookup
import net.minecraft.core.NonNullList
import net.minecraft.core.component.DataComponents
import net.minecraft.nbt.CompoundTag
import net.minecraft.network.protocol.game.ClientboundBlockEntityDataPacket
import net.minecraft.sounds.SoundEvent
import net.minecraft.sounds.SoundSource
import net.minecraft.world.*
import net.minecraft.world.ContainerHelper
import net.minecraft.world.Containers
import net.minecraft.world.InteractionResult
import net.minecraft.world.ItemInteractionResult
import net.minecraft.world.WorldlyContainer
import net.minecraft.world.entity.player.Player
import net.minecraft.world.item.ItemStack
import net.minecraft.world.item.Items
import net.minecraft.world.level.Level
import net.minecraft.world.level.block.entity.BlockEntity
import net.minecraft.world.level.block.state.BlockState
import net.minecraft.world.level.gameevent.GameEvent
import net.minecraft.world.phys.BlockHitResult
import java.util.*
import net.minecraft.world.level.gameevent.GameEvent
import java.util.OptionalInt
import kotlin.math.pow
class DiscShelfBlockEntity(pos: BlockPos, state: BlockState) : BlockEntity(CobblemonBlockEntities.DISC_SHELF, pos, state), WorldlyContainer {
@@ -130,7 +134,25 @@ class DiscShelfBlockEntity(pos: BlockPos, state: BlockState) : BlockEntity(Cobbl
return stack.item is TechnicalMachineItem
|| stack.item == CobblemonItems.UPGRADE
|| stack.item == CobblemonItems.DUBIOUS_DISC
|| stack.has(DataComponents.JUKEBOX_PLAYABLE)
|| stack.item == Items.MUSIC_DISC_13
|| stack.item == Items.MUSIC_DISC_CAT
|| stack.item == Items.MUSIC_DISC_BLOCKS
|| stack.item == Items.MUSIC_DISC_CHIRP
|| stack.item == Items.MUSIC_DISC_FAR
|| stack.item == Items.MUSIC_DISC_MALL
|| stack.item == Items.MUSIC_DISC_MELLOHI
|| stack.item == Items.MUSIC_DISC_STAL
|| stack.item == Items.MUSIC_DISC_STRAD
|| stack.item == Items.MUSIC_DISC_WARD
|| stack.item == Items.MUSIC_DISC_11
|| stack.item == Items.MUSIC_DISC_WAIT
|| stack.item == Items.MUSIC_DISC_OTHERSIDE
|| stack.item == Items.MUSIC_DISC_5
|| stack.item == Items.MUSIC_DISC_RELIC
|| stack.item == Items.MUSIC_DISC_PRECIPICE
|| stack.item == Items.MUSIC_DISC_CREATOR
|| stack.item == Items.MUSIC_DISC_CREATOR_MUSIC_BOX
|| stack.item == Items.MUSIC_DISC_PIGSTEP
}
fun onNoteBlockPulse(level: Level, noteBlockPos: BlockPos, soundEvent: SoundEvent) {
@@ -14,6 +14,7 @@ import com.cobblemon.mod.common.api.multiblock.MultiblockEntity
import com.cobblemon.mod.common.api.multiblock.MultiblockStructure
import com.cobblemon.mod.common.api.multiblock.builder.MultiblockStructureBuilder
import com.cobblemon.mod.common.api.pokemon.PokemonProperties
import com.cobblemon.mod.common.api.tms.TechnicalMachines
import com.cobblemon.mod.common.api.types.ElementalTypes
import com.cobblemon.mod.common.block.MonitorBlock
import com.cobblemon.mod.common.block.multiblock.FossilMultiblockStructure
@@ -306,7 +307,8 @@ open class FossilMultiblockEntity(
private fun unlockTmForPlayer(player: ServerPlayer, stack: ItemStack) {
if (stack.item !is TechnicalMachineItem) return
val move = TMMoveComponent.getTMMove(stack) ?: return
player.tmList().syncTMFromMove(move)
val tmId = TechnicalMachines.moveToTM[move]?.id ?: return
player.tmList()?.learn(listOf(tmId))
}
private fun updateMonitorScreen() {
@@ -25,7 +25,6 @@ import net.minecraft.world.level.block.SoundType
import net.minecraft.world.level.block.entity.BlockEntity
import net.minecraft.world.level.block.entity.BlockEntityTicker
import net.minecraft.world.level.block.entity.BlockEntityType
import net.minecraft.world.level.block.entity.CommandBlockEntity
import net.minecraft.world.level.block.state.BlockState
import net.minecraft.world.level.block.state.StateDefinition
import net.minecraft.world.level.block.state.properties.BooleanProperty
@@ -81,13 +80,11 @@ class HabitatBlock(properties: Properties) : Block(properties), EntityBlock {
}
override fun useWithoutItem(state: BlockState, level: Level, pos: BlockPos, player: Player, hitResult: BlockHitResult): InteractionResult {
val blockEntity = level.getBlockEntity(pos)
val be = level.getBlockEntity(pos) as? HabitatBlockEntity ?: return InteractionResult.PASS
return if (blockEntity is HabitatBlockEntity && player.canUseGameMasterBlocks()) {
be.onUse(player, hitResult)
} else {
InteractionResult.PASS
if (!level.isClientSide) {
val be = level.getBlockEntity(pos) as? HabitatBlockEntity ?: return InteractionResult.PASS
return be.onUse(player, hitResult)
}
return InteractionResult.SUCCESS
}
override fun getDrops(state: BlockState, params: LootParams.Builder): MutableList<ItemStack> {
@@ -60,12 +60,10 @@ class HabitatBlockEntity(pos: BlockPos, state: BlockState) :
var spawningStyle: HabitatSpawningStyle = ActivatedHabitatSpawning(this)
var numberOfPhases: Int = 1
var phaseOrder = HabitatPhaseOrder.SIMPLE
var currentPhase = 1
val numberOfPhases: Int
get() = pool.getPhaseCount()
var levelRange: IntRange = 1..Cobblemon.config.maxPokemonLevel
var modifiers: PokemonProperties = PokemonProperties()
var pool: HabitatPool = HabitatPool.default()
@@ -141,6 +139,7 @@ class HabitatBlockEntity(pos: BlockPos, state: BlockState) :
val activatedSettings = habitatSettingsDTO.activatedSettings
val naturalSettings = habitatSettingsDTO.naturalSettings
val isActivated = habitatSettingsDTO.isActivatedSpawning
this.numberOfPhases = habitatSettingsDTO.numberOfPhases
this.phaseOrder = habitatSettingsDTO.phaseOrder
this.levelRange = habitatSettingsDTO.levelRange
this.modifiers = PokemonProperties.parse(habitatSettingsDTO.modifiers)
@@ -170,6 +169,7 @@ class HabitatBlockEntity(pos: BlockPos, state: BlockState) :
override fun saveAdditional(tag: CompoundTag, registryLookup: HolderLookup.Provider) {
super.saveAdditional(tag, registryLookup)
tag.putString(DataKeys.HABITAT_MIMIC, mimicId.toString())
tag.putInt(DataKeys.HABITAT_PHASE_COUNT, numberOfPhases)
tag.putString(DataKeys.HABITAT_PHASE_ORDER, phaseOrder.toString())
// Only save the level range when it's a non-trivial one
if (levelRange.first != 1 || levelRange.last != Cobblemon.config.maxPokemonLevel) {
@@ -201,6 +201,7 @@ class HabitatBlockEntity(pos: BlockPos, state: BlockState) :
return // Client doesn't need to try loading the rest
}
numberOfPhases = tag.getInt(DataKeys.HABITAT_PHASE_COUNT)
phaseOrder = HabitatPhaseOrder.valueOf(tag.getString(DataKeys.HABITAT_PHASE_ORDER))
levelRange = tag.getString(DataKeys.HABITAT_LEVEL_RANGE).takeIf { it.isNotBlank() }?.let(IntRangeAdapter::deserialize) ?: 1..Cobblemon.config.maxPokemonLevel
modifiers = tag.getString(DataKeys.HABITAT_MODIFIERS).takeIf { it.isNotBlank() }?.let(PokemonProperties::parse) ?: PokemonProperties()
@@ -630,8 +630,7 @@ class FossilMultiblockStructure (
result.putInt(DataKeys.ORGANIC_MATERIAL, organicMaterialInside)
val fossilInv = ListTag()
val ops = registryLookup.createSerializationContext(NbtOps.INSTANCE)
fossilInventory.forEach { fossilInv.add(ItemStack.CODEC.encodeStart(ops, it).getOrThrow()) }
fossilInventory.forEach { fossilInv.add(ItemStack.CODEC.encodeStart(NbtOps.INSTANCE, it).orThrow) }
result.put(DataKeys.FOSSIL_INVENTORY, fossilInv)
result.putString(DataKeys.CONNECTOR_DIRECTION, tankConnectorDirection?.toString())
@@ -653,9 +652,9 @@ class FossilMultiblockStructure (
const val TICKS_PER_MINUTE = 1200
const val MATERIAL_TO_START = 128
const val TIME_TO_TAKE = TICKS_PER_MINUTE * 12
const val TIME_PER_STAGE = TIME_TO_TAKE / 8
const val PROTECTION_TIME = TICKS_PER_MINUTE * 5
const val TIME_TO_TAKE = 100
const val TIME_PER_STAGE = 100 / 8
const val PROTECTION_TIME = 100
fun fromNbt(nbt: CompoundTag, registryLookup: HolderLookup.Provider, animAge: Int = -1, partialTicks: Float = 0f): FossilMultiblockStructure {
val monitorPos = NbtUtils.readBlockPos(nbt, DataKeys.MONITOR_POS).get()
@@ -670,10 +669,7 @@ class FossilMultiblockStructure (
val fossilInv = if (nbt.contains(DataKeys.FOSSIL_INVENTORY)) { (nbt.get(DataKeys.FOSSIL_INVENTORY) as ListTag) } else ListTag()
val actualFossilList = mutableListOf<ItemStack>()
val ops = registryLookup.createSerializationContext(NbtOps.INSTANCE)
fossilInv.forEach { ItemStack.CODEC.parse(ops, it).result().ifPresent(actualFossilList::add) }
fossilInv.forEach { ItemStack.parse(registryLookup, it).ifPresent(actualFossilList::add) }
result.fossilInventory = actualFossilList
result.tankConnectorDirection = Direction.byName(nbt.getString(DataKeys.CONNECTOR_DIRECTION))
@@ -10,13 +10,11 @@ package com.cobblemon.mod.common.block.tmmachine
import com.cobblemon.mod.common.CobblemonItems
import com.cobblemon.mod.common.CobblemonMenuType
import com.cobblemon.mod.common.CobblemonNetwork.sendPacket
import com.cobblemon.mod.common.api.moves.Moves
import com.cobblemon.mod.common.api.tms.TechnicalMachine
import com.cobblemon.mod.common.api.tms.TechnicalMachines
import com.cobblemon.mod.common.block.entity.TMMachineBlockEntity
import com.cobblemon.mod.common.net.messages.client.ui.SynchronizeActiveTMPacket
import net.minecraft.server.level.ServerPlayer
import com.cobblemon.mod.common.util.itemRegistry
import net.minecraft.server.level.ServerLevel
import net.minecraft.util.Mth
import net.minecraft.world.Container
import net.minecraft.world.SimpleContainer
@@ -37,45 +35,15 @@ class TMMachineMenu(menuType: MenuType<*>, syncId: Int) : AbstractContainerMenu(
var inventory: Container? = null
var containerData: ContainerData? = null
var currentlySelectedTM: TechnicalMachine? = null
private var lastSelectedTM: TechnicalMachine? = null
var onSelectedTMUpdate: (TechnicalMachine?) -> Unit = {}
constructor(syncId: Int, playerInventory: Inventory) : this(CobblemonMenuType.TM_MACHINE, syncId) {
this.playerInventory = playerInventory
this.inventory = SimpleContainer(5)
this.containerData = SimpleContainerData(6)
this.tmMachineEntity = (inventory as? TMMachineBlockEntity.TMMachineBlockInventory)?.blockEntity
this.addDataSlots(containerData!!)
inventory?.startOpen(playerInventory.player)
initiateSlots()
}
constructor(syncId: Int, playerInventory: Inventory, inventory: Container, containerData: ContainerData) : this(CobblemonMenuType.TM_MACHINE, syncId) {
this.playerInventory = playerInventory
this.inventory = inventory
this.containerData = containerData
this.tmMachineEntity = (inventory as? TMMachineBlockEntity.TMMachineBlockInventory)?.blockEntity
this.addDataSlots(containerData)
inventory.startOpen(playerInventory.player)
initiateSlots()
tmMachineEntity?.let {
val move = Moves.getByName(it.activeMove)
move.let {
currentlySelectedTM = TechnicalMachines.moveToTM[it]
synchronizeSelectedTM()
}
}
this.addSlotListener(this)
}
private fun initiateSlots() {
val startX = 15
val startY = 144
val slotWidth = 18
@@ -90,7 +58,41 @@ class TMMachineMenu(menuType: MenuType<*>, syncId: Int) : AbstractContainerMenu(
this.addSlot(Slot(playerInventory, col, startX + (slotWidth * col), startY + 58))
}
val container = inventory!!
val container = inventory
container?.let {
this.addSlot(TMResultSlot(container, RESULT_SLOT, startX + 37, startY - 28)) // Output slot
this.addSlot(BlankTMSlot(container, BLANK_TM_SLOT, startX + 90, startY - 28)) // Blank TM
for (index in INGREDIENT_SLOTS) {
this.addSlot(Slot(container, index, startX + 114 + (18 * (index - INGREDIENT_SLOTS.first)), startY - 28))
}
}
this.addSlotListener(this)
}
constructor(syncId: Int, playerInventory: Inventory, inventory: Container, containerData: ContainerData) : this(CobblemonMenuType.TM_MACHINE, syncId) {
this.playerInventory = playerInventory
this.inventory = inventory
this.containerData = containerData
this.tmMachineEntity = (inventory as? TMMachineBlockEntity.TMMachineBlockInventory)?.blockEntity
this.addDataSlots(containerData)
inventory.startOpen(playerInventory.player)
val startX = 15
val startY = 144
val slotWidth = 18
val slotHeight = 18
for (row in 0..2) {
for (col in 0..8) {
this.addSlot(Slot(playerInventory, 9 + (row * 9) + col, startX + (slotWidth * col), startY + (slotHeight * row)))
}
}
for (col in 0..8) {
this.addSlot(Slot(playerInventory, col, startX + (slotWidth * col), startY + 58))
}
val container = inventory
container.let {
this.addSlot(TMResultSlot(container, RESULT_SLOT, startX + 37, startY - 28)) // Output slot
this.addSlot(BlankTMSlot(container, BLANK_TM_SLOT, startX + 90, startY - 28)) // Blank TM
@@ -98,6 +100,7 @@ class TMMachineMenu(menuType: MenuType<*>, syncId: Int) : AbstractContainerMenu(
this.addSlot(Slot(container, index, startX + 114 + (18 * (index - INGREDIENT_SLOTS.first)), startY - 28))
}
}
this.addSlotListener(this)
}
override fun quickMoveStack(player: Player, index: Int): ItemStack {
@@ -204,25 +207,4 @@ class TMMachineMenu(menuType: MenuType<*>, syncId: Int) : AbstractContainerMenu(
override fun dataChanged(containerMenu: AbstractContainerMenu, dataSlotIndex: Int, value: Int) {
broadcastChanges()
}
fun synchronizeSelectedTM() {
val serverPlayer = playerInventory?.player as? ServerPlayer ?: return
serverPlayer.sendPacket(SynchronizeActiveTMPacket(currentlySelectedTM))
lastSelectedTM = currentlySelectedTM
}
override fun sendAllDataToRemote() {
super.sendAllDataToRemote()
synchronizeSelectedTM()
}
override fun broadcastChanges() {
super.broadcastChanges()
if (lastSelectedTM != currentlySelectedTM) synchronizeSelectedTM()
}
fun clientSetSelectedTM(tm: TechnicalMachine?) {
currentlySelectedTM = tm
onSelectedTMUpdate(tm)
}
}
@@ -49,7 +49,7 @@ object MountedCameraTypeHandler {
return
}
val currentCameraType = mc.options.cameraType
if (Cobblemon.config.rememberRidingCamera && currentCameraType != unmountedCameraType) {
if (currentCameraType != unmountedCameraType) {
mc.options.cameraType = unmountedCameraType
}
val data = ClientPersistedData.ridingPerspectives
@@ -130,25 +130,20 @@ class PartyOverlay : Gui(Minecraft.getInstance()) {
val party = CobblemonClient.storage.party
val matrices = context.pose()
if (party.slots.none { it != null }) {
if (!this.attachedToast &&
CobblemonClient.clientPlayerData.promptStarter &&
if (CobblemonClient.clientPlayerData.promptStarter &&
!CobblemonClient.clientPlayerData.starterLocked &&
!CobblemonClient.clientPlayerData.starterSelected &&
!CobblemonClient.checkedStarterScreen
) {
// Adding starter toast on start and connect of client to server.
minecraft.toasts.addToast(this.starterToast)
this.attachedToast = true
if (!this.attachedToast) {
// Adding starter toast on start and connect of client to server.
minecraft.toasts.addToast(this.starterToast)
this.attachedToast = true
}
}
return // Don't render the stuff below if no Pokémon in party
}
// Without this simply capturing a Pokémon instead of opening the starter screen won't dismiss the toast
if (!CobblemonClient.checkedStarterScreen) {
CobblemonClient.checkedStarterScreen = true
starterToast.nextVisibility = Toast.Visibility.HIDE
}
val totalHeight = party.slots.size * SLOT_HEIGHT
val midY = minecraft.window.guiScaledHeight / 2
val startY = (midY - totalHeight / 2) - ((SLOT_SPACING * 5) / 2)
@@ -27,18 +27,10 @@ import net.minecraft.client.renderer.RenderType
import net.minecraft.client.renderer.texture.OverlayTexture
import net.minecraft.resources.ResourceLocation
import net.minecraft.util.Mth
import net.minecraft.world.phys.Vec3
import org.joml.Quaternionf
import org.joml.Vector3f
import kotlin.math.atan
enum class ProfileTransformType {
PROFILE,
NONE,
POKEDEX,
SUMMARY,
}
fun drawProfilePokemon(
renderablePokemon: RenderablePokemon,
matrixStack: PoseStack,
@@ -47,7 +39,7 @@ fun drawProfilePokemon(
state: PosableState,
partialTicks: Float,
scale: Float = 20F,
profileTransformType: ProfileTransformType = ProfileTransformType.PROFILE,
applyProfileTransform: Boolean = true,
applyBaseScale: Boolean = false,
r: Float = 1F,
g: Float = 1F,
@@ -64,7 +56,7 @@ fun drawProfilePokemon(
state = state.also { it.currentAspects = renderablePokemon.aspects },
partialTicks = partialTicks,
scale = scale,
profileTransformType = profileTransformType,
applyProfileTransform = applyProfileTransform,
applyBaseScale = applyBaseScale,
r = r,
g = g,
@@ -83,7 +75,7 @@ fun drawProfilePokemon(
state: PosableState,
partialTicks: Float,
scale: Float = 20F,
profileTransformType: ProfileTransformType = ProfileTransformType.PROFILE,
applyProfileTransform: Boolean = true,
applyBaseScale: Boolean = false,
doQuirks: Boolean = false,
r: Float = 1F,
@@ -122,38 +114,18 @@ fun drawProfilePokemon(
state.setPoseToFirstSuitable(poseType)
state.updatePartialTicks(partialTicks)
if (profileTransformType == ProfileTransformType.NONE) {
if (applyProfileTransform) {
matrixStack.translate(
model.profileTranslation.x,
model.profileTranslation.y + 1.5 * model.profileScale,
model.profileTranslation.z - 4.0
)
matrixStack.scale(model.profileScale, model.profileScale, 1 / model.profileScale)} else {
matrixStack.translate(0F, 0F, -4.0F)
if (applyBaseScale) {
matrixStack.scale(baseScale, baseScale, 1 / baseScale)
}
} else {
var profileScale: Float
var profileTranslation: Vec3
when (profileTransformType) {
ProfileTransformType.POKEDEX -> {
profileScale = model.profilePokedexScale ?: model.profileScale
profileTranslation = model.profilePokedexTranslation ?: model.profileTranslation
}
ProfileTransformType.SUMMARY -> {
profileScale = model.profileSummaryScale ?: model.profileScale
profileTranslation = model.profileSummaryTranslation ?: model.profileTranslation
}
else -> {
profileScale = model.profileScale
profileTranslation = model.profileTranslation
}
}
matrixStack.translate(
profileTranslation.x,
profileTranslation.y + 1.5 * profileScale,
profileTranslation.z - 4.0
)
matrixStack.scale(profileScale, profileScale, 1 / profileScale)
}
matrixStack.mulPose(rotation)
model.applyAnimations(null, state, 0F, 0F, 0F, headYaw, headPitch)
@@ -1,97 +0,0 @@
/*
* 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.Cobblemon
import com.cobblemon.mod.common.client.render.models.blockbench.FloatingState
import com.cobblemon.mod.common.client.render.models.blockbench.repository.VaryingModelRepository
import com.mojang.blaze3d.platform.InputConstants
import net.minecraft.client.Minecraft
import net.minecraft.network.chat.Component
import net.minecraft.resources.ResourceLocation
import net.minecraft.world.phys.Vec3
fun handleProfileDebugKeys(keyCode: Int, poserResourceLocation: ResourceLocation, state: FloatingState) {
if (!Cobblemon.config.enableDebugKeys) {
return
}
val model = VaryingModelRepository.getPoser(poserResourceLocation, state)
val delta = when (keyCode) {
InputConstants.KEY_UP -> Vec3(0.0, -0.01, 0.0)
InputConstants.KEY_DOWN -> Vec3(0.0, 0.01, 0.0)
InputConstants.KEY_LEFT -> Vec3(-0.01, 0.0, 0.0)
InputConstants.KEY_RIGHT -> Vec3(0.01, 0.0, 0.0)
else -> null
}
if (delta != null) {
model.profileTranslation = model.profileTranslation.add(delta)
model.profileSummaryTranslation = model.profileSummaryTranslation?.add(delta)
model.profilePokedexTranslation = model.profilePokedexTranslation?.add(delta)
}
val scaleDelta = when (keyCode) {
InputConstants.KEY_EQUALS -> 0.01F
InputConstants.KEY_MINUS -> -0.01F
else -> null
}
if (scaleDelta != null) {
model.profileScale += scaleDelta
model.profileSummaryScale = model.profileSummaryScale?.plus(scaleDelta)
model.profilePokedexScale = model.profilePokedexScale?.plus(scaleDelta)
}
}
fun logProfileTranslations(poserResourceLocation: ResourceLocation, state: FloatingState) {
if (!Cobblemon.config.enableDebugKeys) {
return
}
val model = VaryingModelRepository.getPoser(poserResourceLocation, state)
val player = Minecraft.getInstance().player
fun Double.f2() = "%.2f".format(this)
fun Float.f2() = "%.2f".format(this)
fun sendTranslation(name: String, translation: Vec3) {
player?.sendSystemMessage(Component.literal("$name Translation: (${translation.x.f2()}, ${translation.y.f2()}, ${translation.z.f2()})"))
}
fun sendScale(name: String, scale: Float) {
player?.sendSystemMessage(Component.literal("$name Scale: ${scale.f2()}"))
}
fun logTranslation(name: String, translation: Vec3) {
Cobblemon.LOGGER.info("override var ${name.replaceFirstChar(Char::lowercase)}Translation = Vec3(${translation.x.f2()}, ${translation.y.f2()}, ${translation.z.f2()})")
}
fun logScale(name: String, scale: Float) {
Cobblemon.LOGGER.info("override var ${name.replaceFirstChar(Char::lowercase)}Scale = ${scale.f2()}F")
}
sendTranslation("Profile", model.profileTranslation)
sendScale("Profile", model.profileScale)
model.profileSummaryTranslation?.let { sendTranslation("Summary Profile", it) }
model.profileSummaryScale?.let { sendScale("Summary Profile", it) }
model.profilePokedexTranslation?.let { sendTranslation("Pokedex Profile", it) }
model.profilePokedexScale?.let { sendScale("Pokedex Profile", it) }
logTranslation("Profile", model.profileTranslation)
logScale("Profile", model.profileScale)
model.profileSummaryTranslation?.let { logTranslation("ProfileSummary", it) }
model.profileSummaryScale?.let { logScale("ProfileSummary", it) }
model.profilePokedexTranslation?.let { logTranslation("ProfilePokedex", it) }
model.profilePokedexScale?.let { logScale("ProfilePokedex", it) }
}
@@ -41,7 +41,6 @@ class CobblemonConfigScreen(
const val WIDGET_HEIGHT = SLOT_HEIGHT - PADDING
const val LABEL_Y_OFFSET = 4
const val WIDGET_Y_OFFSET = 0
const val LABEL_MAX_WIDTH = SLOT_WIDTH - RESET_SLOT_WIDTH - WIDGET_WIDTH - PADDING * 2
}
val clonedConfig = Cobblemon.config.clone()
@@ -8,18 +8,17 @@
package com.cobblemon.mod.common.client.gui.config.variable
import com.cobblemon.mod.common.client.gui.config.CobblemonConfigScreen.Companion.LABEL_MAX_WIDTH
import com.cobblemon.mod.common.client.gui.config.CobblemonConfigScreen.Companion.LABEL_Y_OFFSET
import com.cobblemon.mod.common.client.gui.config.CobblemonConfigScreen.Companion.RESET_SLOT_WIDTH
import com.cobblemon.mod.common.client.gui.config.CobblemonConfigScreen.Companion.SLOT_WIDTH
import com.cobblemon.mod.common.client.gui.config.CobblemonConfigScreen.Companion.WIDGET_HEIGHT
import com.cobblemon.mod.common.client.gui.config.CobblemonConfigScreen.Companion.WIDGET_Y_OFFSET
import com.cobblemon.mod.common.client.gui.config.CobblemonConfigVariableList
import com.cobblemon.mod.common.client.gui.config.CobblemonConfigVariableList.CobblemonConfigVariableListEntry
import com.cobblemon.mod.common.client.render.drawScrollingText
import com.cobblemon.mod.common.client.render.drawScaledText
import com.cobblemon.mod.common.config.CobblemonConfig
import com.cobblemon.mod.common.config.CobblemonConfigField
import com.cobblemon.mod.common.util.lang
import net.minecraft.client.Minecraft
import net.minecraft.client.gui.GuiGraphics
import net.minecraft.client.gui.components.Button
import net.minecraft.client.gui.components.Tooltip
@@ -92,15 +91,12 @@ abstract class CobblemonConfigVariable(
val x = getX(left)
val y = getY(top)
drawScrollingText(
context,
Minecraft.getInstance().font,
labelLang,
x,
y + WIDGET_Y_OFFSET,
x + LABEL_MAX_WIDTH,
y + WIDGET_Y_OFFSET + WIDGET_HEIGHT,
-1
drawScaledText(
context = context,
text = labelLang,
x = getX(left),
y = getY(top) + LABEL_Y_OFFSET,
shadow = true
)
resetButton.x = x + SLOT_WIDTH - RESET_SLOT_WIDTH
@@ -115,19 +115,35 @@ class HabitatEditGUI(
addOptionWidget(mimicInput)
y += spacing
// Phase setting only visible if there's more than one phase
val phaseCount = habitatSettingsDTO.pool.toHabitatPool()?.getPhaseCount() ?: 1
if (phaseCount > 1) {
phaseOrderButton = addOptionWidget(
Button.builder(getPhaseOrderText()) {
val orders = HabitatPhaseOrder.entries
val currentIndex = orders.indexOf(habitatSettingsDTO.phaseOrder)
habitatSettingsDTO.phaseOrder = orders[(currentIndex + 1) % orders.size]
refresh()
}.bounds(10, y, buttonWidth, 20).build()
)
y += spacing
labels.add(lang("ui.edit.habitat.phase_number") to (10 to y))
y += 12
val phasesInput = EditBox(font, 10, y, buttonWidth, 20, "Phases".text())
phasesInput.value = habitatSettingsDTO.numberOfPhases.toString()
phasesInput.setResponder { value ->
val phases = value.toIntOrNull()
val valid = phases != null && phases > 0
if (valid) {
habitatSettingsDTO.numberOfPhases = phases
}
phasesInput.setTextColor(if (valid) validTextColor else invalidTextColor)
setFieldValidity("phases", valid, "ui.edit.habitat.validation.phases")
}
val initialPhases = phasesInput.value.toIntOrNull()
val initialPhasesValid = initialPhases != null && initialPhases > 0
phasesInput.setTextColor(if (initialPhasesValid) validTextColor else invalidTextColor)
setFieldValidity("phases", initialPhasesValid, "ui.edit.habitat.validation.phases")
addOptionWidget(phasesInput)
y += spacing
phaseOrderButton = addOptionWidget(
Button.builder(getPhaseOrderText()) {
val orders = HabitatPhaseOrder.entries
val currentIndex = orders.indexOf(habitatSettingsDTO.phaseOrder)
habitatSettingsDTO.phaseOrder = orders[(currentIndex + 1) % orders.size]
refresh()
}.bounds(10, y, buttonWidth, 20).build()
)
y += spacing
labels.add(lang("ui.edit.habitat.level_range") to (10 to y))
y += 12
@@ -374,10 +390,7 @@ class HabitatEditGUI(
}
fun refresh() {
val phaseCount = habitatSettingsDTO.pool.toHabitatPool()?.getPhaseCount() ?: 1
if (phaseCount > 1 && ::phaseOrderButton.isInitialized) {
phaseOrderButton.message = getPhaseOrderText()
}
phaseOrderButton.message = getPhaseOrderText()
spawnModeButton.message = getSpawnModeText()
poolSelectorButton.message = getPoolText()
viewPoolButton.message = getViewPoolText()
@@ -426,7 +439,6 @@ class HabitatEditGUI(
}
habitatSettingsDTO.pool = newCustomPool
}
rebuildWidgets()
return
}
@@ -439,7 +451,6 @@ class HabitatEditGUI(
}
habitatSettingsDTO.pool = selectedPool
rebuildWidgets()
}
private fun validateLevelRangeInputs() {
@@ -45,6 +45,7 @@ class HabitatSpawnEditorGUI(
private val actionButtonBottomMargin = 10
private val validTextColor = 0xFFFFFF
private val invalidTextColor = 0xFF5555
private val moonPhaseRange = 0..7
private lateinit var positionTypeButton: Button
private lateinit var bucketButton: Button
private lateinit var timeOfDayButton: Button
@@ -184,7 +185,7 @@ class HabitatSpawnEditorGUI(
phasesInput.setTextColor(validTextColor)
setFieldValidity("phases_list", true, "ui.edit.habitat.validation.phases_list")
} else {
val parsed = parsePhases(value)
val parsed = parseMoonPhases(value)
val valid = parsed != null
if (valid) {
spawn.phases = parsed
@@ -193,7 +194,7 @@ class HabitatSpawnEditorGUI(
setFieldValidity("phases_list", valid, "ui.edit.habitat.validation.phases_list")
}
}
val initialPhasesValid = phasesInput.value.isBlank() || parsePhases(phasesInput.value) != null
val initialPhasesValid = phasesInput.value.isBlank() || parseMoonPhases(phasesInput.value) != null
phasesInput.setTextColor(if (initialPhasesValid) validTextColor else invalidTextColor)
setFieldValidity("phases_list", initialPhasesValid, "ui.edit.habitat.validation.phases_list")
addOptionWidget(phasesInput)
@@ -331,7 +332,7 @@ class HabitatSpawnEditorGUI(
return runCatching { PokemonSpecies.getByName(lowered) }.getOrNull()
}
private fun parsePhases(raw: String): IntRanges? {
private fun parseMoonPhases(raw: String): IntRanges? {
val ranges = mutableListOf<IntRange>()
val tokens = raw.split(",").map(String::trim)
if (tokens.isEmpty() || tokens.any { it.isEmpty() }) {
@@ -343,12 +344,13 @@ class HabitatSpawnEditorGUI(
val range = when (parts.size) {
1 -> {
val value = parts[0].toIntOrNull() ?: return null
if (value !in moonPhaseRange) return null
value..value
}
2 -> {
val start = parts[0].toIntOrNull() ?: return null
val end = parts[1].toIntOrNull() ?: return null
if (start > end) {
if (start !in moonPhaseRange || end !in moonPhaseRange || start > end) {
return null
}
start..end
@@ -32,32 +32,29 @@ import com.cobblemon.mod.common.client.ClientMoLangFunctions.setupClient
import com.cobblemon.mod.common.client.CobblemonClient
import com.cobblemon.mod.common.client.CobblemonResources
import com.cobblemon.mod.common.client.gui.CobblemonRenderable
import com.cobblemon.mod.common.client.gui.handleProfileDebugKeys
import com.cobblemon.mod.common.client.gui.logProfileTranslations
import com.cobblemon.mod.common.client.gui.pokedex.PokedexGUIConstants.BASE_HEIGHT
import com.cobblemon.mod.common.client.gui.pokedex.PokedexGUIConstants.BASE_WIDTH
import com.cobblemon.mod.common.client.gui.pokedex.PokedexGUIConstants.HALF_OVERLAY_HEIGHT
import com.cobblemon.mod.common.client.gui.pokedex.PokedexGUIConstants.HALF_OVERLAY_WIDTH
import com.cobblemon.mod.common.client.gui.pokedex.PokedexGUIConstants.HALF_OVERLAY_WIDTH
import com.cobblemon.mod.common.client.gui.pokedex.PokedexGUIConstants.HEADER_BAR_HEIGHT
import com.cobblemon.mod.common.client.gui.pokedex.PokedexGUIConstants.ICONS_ARROW_PADDING_AROUND
import com.cobblemon.mod.common.client.gui.pokedex.PokedexGUIConstants.ICONS_PADDING_AROUND
import com.cobblemon.mod.common.client.gui.pokedex.PokedexGUIConstants.SCALE
import com.cobblemon.mod.common.client.gui.pokedex.PokedexGUIConstants.TAB_ABILITIES
import com.cobblemon.mod.common.client.gui.pokedex.PokedexGUIConstants.TAB_DESCRIPTION
import com.cobblemon.mod.common.client.gui.pokedex.PokedexGUIConstants.TAB_DROPS
import com.cobblemon.mod.common.client.gui.pokedex.PokedexGUIConstants.TAB_EVOLUTION_TREE
import com.cobblemon.mod.common.client.gui.pokedex.PokedexGUIConstants.TAB_ICON_SIZE
import com.cobblemon.mod.common.client.gui.pokedex.PokedexGUIConstants.TAB_MOVES
import com.cobblemon.mod.common.client.gui.pokedex.PokedexGUIConstants.TAB_SIZE
import com.cobblemon.mod.common.client.gui.pokedex.PokedexGUIConstants.TAB_STATS
import com.cobblemon.mod.common.client.gui.pokedex.widgets.AbilitiesWidget
import com.cobblemon.mod.common.client.gui.pokedex.widgets.DescriptionWidget
import com.cobblemon.mod.common.client.gui.pokedex.widgets.DropsScrollingWidget
import com.cobblemon.mod.common.client.gui.pokedex.widgets.EntriesScrollingWidget
import com.cobblemon.mod.common.client.gui.pokedex.widgets.MovesLearnsetWidget
import com.cobblemon.mod.common.client.gui.pokedex.widgets.PokemonInfoWidget
import com.cobblemon.mod.common.client.gui.pokedex.widgets.SearchWidget
import com.cobblemon.mod.common.client.gui.pokedex.widgets.SizeWidget
import com.cobblemon.mod.common.client.gui.pokedex.widgets.StatsWidget
import com.cobblemon.mod.common.client.gui.pokedex.widgets.*
import com.cobblemon.mod.common.client.gui.pokedex.widgets.evolutiontree.EvolutionTreeWidget
import com.cobblemon.mod.common.client.pokedex.PokedexType
import com.cobblemon.mod.common.client.render.drawScaledText
import com.cobblemon.mod.common.net.messages.server.block.AdjustBlockEntityViewerCountPacket
import com.cobblemon.mod.common.pokemon.Gender
import com.cobblemon.mod.common.pokemon.abilities.HiddenAbility
import com.cobblemon.mod.common.util.cobblemonResource
import com.cobblemon.mod.common.util.isInventoryKeyPressed
@@ -94,6 +91,10 @@ class PokedexGUI private constructor(
private val categoryBarOverlay = cobblemonResource("textures/gui/pokedex/pokedex_screen_bar_category.png")
// TODO: separate into smaller components / widgets?
private val backgroundOverlay = cobblemonResource("textures/gui/pokedex/pokedex_screen_info_overlay.png")
private val expandedBackgroundOverlay = cobblemonResource("textures/gui/pokedex/pokedex_screen_info_overlay_expanded.png")
private val tabSelectArrow = cobblemonResource("textures/gui/pokedex/select_arrow.png")
private val tabIcons = arrayOf(
cobblemonResource("textures/gui/pokedex/tab_info.png"),
@@ -101,7 +102,8 @@ class PokedexGUI private constructor(
cobblemonResource("textures/gui/pokedex/tab_size.png"),
cobblemonResource("textures/gui/pokedex/tab_stats.png"),
cobblemonResource("textures/gui/pokedex/tab_drops.png"),
cobblemonResource("textures/gui/pokedex/tab_moves.png")
cobblemonResource("textures/gui/pokedex/tab_moves.png"),
cobblemonResource("textures/gui/pokedex/tab_evolution_tree.png"),
)
val arrowUpIcon = cobblemonResource("textures/gui/pokedex/arrow_up.png")
@@ -114,6 +116,8 @@ class PokedexGUI private constructor(
TAB_MOVES
)
private val ICONS_PADDING_BETWEEN = (BASE_WIDTH / 2 - ICONS_PADDING_AROUND * 2) / tabIcons.size
/**
* Attempts to open this screen for a client.
*/
@@ -132,6 +136,7 @@ class PokedexGUI private constructor(
var oldDragPosX = 0.0
var canDragRender = false
private var activeDragableElement: GuiEventListener? = null
private var filteredPokedex: Collection<PokedexDef> = mutableListOf()
private var seenCount = "0000"
@@ -155,13 +160,29 @@ class PokedexGUI private constructor(
private lateinit var scrollScreen: EntriesScrollingWidget
private lateinit var pokemonInfoWidget: PokemonInfoWidget
private lateinit var searchWidget: SearchWidget
private lateinit var pokemonNameWidget: PokemonNameWidget
private var selectedSearchByType: SearchByType = SearchByType.SPECIES
private var selectedCategoryFilter: PokedexCategoryFilterType = PokedexCategoryFilterType.ALL
private val tabButtons: MutableList<ScaledButton> = mutableListOf()
var seenShinyStates = setOf<String>()
var shiny = false
var maleRatio = -1F
var gender = Gender.GENDERLESS
var aspects = mutableSetOf<String>()
lateinit var tabInfoElement: GuiEventListener
var tabInfoIndex = TAB_DESCRIPTION
var evolutionTreeExpanded = false
set(value) {
field = value
if (::pokemonInfoWidget.isInitialized) {
pokemonInfoWidget.active = !value
pokemonInfoWidget.visible = !value
}
}
override fun renderBlurredBackground(delta: Float) {}
override fun renderMenuBackground(context: GuiGraphics) {}
@@ -180,7 +201,7 @@ class PokedexGUI private constructor(
//Info Widget
if (::pokemonInfoWidget.isInitialized) removeWidget(pokemonInfoWidget)
pokemonInfoWidget = PokemonInfoWidget(x + 180, y + 28) { newForm -> updateSelectedForm(newForm) }
pokemonInfoWidget = PokemonInfoWidget(this, x + 180, y + 28) { newForm -> updateSelectedForm(newForm) }
addRenderableWidget(pokemonInfoWidget)
setUpTabs()
@@ -192,6 +213,10 @@ class PokedexGUI private constructor(
searchWidget = SearchWidget(x + 26, y + 28, 120, HEADER_BAR_HEIGHT, update = ::updateFilters)
addRenderableWidget(searchWidget)
if (::pokemonNameWidget.isInitialized) removeWidget(pokemonNameWidget)
pokemonNameWidget = PokemonNameWidget(this, x + 180, y + 28)
addRenderableWidget(pokemonNameWidget)
if (::regionSelectWidgetUp.isInitialized) removeWidget(regionSelectWidgetUp)
regionSelectWidgetUp = ScaledButton(
buttonX = (x + 95).toFloat(),
@@ -367,6 +392,14 @@ class PokedexGUI private constructor(
shadow = true
)
blitk(
matrixStack = matrices,
texture = if (evolutionTreeExpanded) expandedBackgroundOverlay else backgroundOverlay,
x = pokemonInfoWidget.x, y = pokemonInfoWidget.y,
width = HALF_OVERLAY_WIDTH,
height = HALF_OVERLAY_HEIGHT
)
// Category filter
blitk(
matrixStack = matrices,
@@ -402,7 +435,7 @@ class PokedexGUI private constructor(
blitk(
matrixStack = matrices,
texture = tabSelectArrow,
x = (x + 191.5F + (22F * tabInfoIndex)) / SCALE,
x = (x + BASE_WIDTH / 2 + ICONS_ARROW_PADDING_AROUND + tabInfoIndex * ICONS_PADDING_BETWEEN) / SCALE,
y = (y + 177) / SCALE,
width = 12,
height = 6,
@@ -429,11 +462,6 @@ class PokedexGUI private constructor(
override fun onClose() {
if (blockPos != null) AdjustBlockEntityViewerCountPacket(blockPos, false).sendToServer()
playSound(CobblemonSounds.POKEDEX_CLOSE)
selectedEntry?.speciesId?.let { speciesId ->
logProfileTranslations(speciesId, pokemonInfoWidget.state)
}
super.onClose()
}
@@ -441,6 +469,7 @@ class PokedexGUI private constructor(
val canDisplayEntry = true //selectedForm?.unlockForms
if (::pokemonInfoWidget.isInitialized
&& pokemonInfoWidget.active
&& !pokemonInfoWidget.suppressViewport
&& pokemonInfoWidget.isWithinPortraitSpace(mouseX, mouseY)
&& canDisplayEntry == true
@@ -449,6 +478,12 @@ class PokedexGUI private constructor(
isDragging = true
oldDragPosX = mouseX
playSound(CobblemonSounds.POKEDEX_CLICK_SHORT)
activeDragableElement = pokemonInfoWidget
} else if (tabInfoIndex == TAB_EVOLUTION_TREE &&
::tabInfoElement.isInitialized &&
(tabInfoElement as EvolutionTreeWidget).isHovered(mouseX, mouseY)
) {
activeDragableElement = tabInfoElement
}
return try {
super.mouseClicked(mouseX, mouseY, button)
@@ -460,14 +495,18 @@ class PokedexGUI private constructor(
override fun mouseReleased(pMouseX: Double, pMouseY: Double, pButton: Int): Boolean {
if (canDragRender) canDragRender = false
if (isDragging) isDragging = false
activeDragableElement = null
return super.mouseReleased(pMouseX, pMouseY, pButton)
}
override fun mouseDragged(mouseX: Double, mouseY: Double, button: Int, deltaX: Double, deltaY: Double): Boolean {
if (isDragging && canDragRender) {
if (isDragging && canDragRender && activeDragableElement == pokemonInfoWidget) {
val dragOffsetY = (oldDragPosX - mouseX).toFloat()
pokemonInfoWidget.rotationY = (((pokemonInfoWidget.rotationY + dragOffsetY) % 360 + 360) % 360)
} else if (activeDragableElement == tabInfoElement) {
tabInfoElement.mouseDragged(mouseX, mouseY, button, deltaX, deltaY)
}
oldDragPosX = mouseX
return super.mouseDragged(mouseX, mouseY, button, deltaX, deltaY)
}
@@ -558,6 +597,8 @@ class PokedexGUI private constructor(
selectedForm = CobblemonClient.clientPokedexData.getEncounteredForms(newSelectedEntry).firstOrNull()
pokemonInfoWidget.setDexEntry(selectedEntry!!)
pokemonNameWidget.update(selectedEntry!!)
displaytabInfoElement(tabInfoIndex)
}
@@ -569,7 +610,7 @@ class PokedexGUI private constructor(
for (i in tabIcons.indices) {
tabButtons.add(ScaledButton(
x + 190.5F + (i * 22F),
x + BASE_WIDTH / 2 + ICONS_PADDING_AROUND + i * ICONS_PADDING_BETWEEN,
y + 181.5F,
TAB_ICON_SIZE,
TAB_ICON_SIZE,
@@ -582,6 +623,8 @@ class PokedexGUI private constructor(
}
fun displaytabInfoElement(tabIndex: Int, update: Boolean = true) {
if (tabIndex != TAB_EVOLUTION_TREE) evolutionTreeExpanded = false
val showActiveTab = selectedEntry?.let { selectedForm in getSufficientlyKnownForms(it, tabIndex) } == true
var statSubIndex = 0
@@ -633,6 +676,9 @@ class PokedexGUI private constructor(
TAB_MOVES -> {
tabInfoElement = MovesLearnsetWidget(x + 180, y + 28)
}
TAB_EVOLUTION_TREE -> {
tabInfoElement = EvolutionTreeWidget(this, x, y)
}
}
val element = tabInfoElement
if (element is Renderable && element is NarratableEntry) {
@@ -707,6 +753,9 @@ class PokedexGUI private constructor(
selectedForm = fallbackForm
) { next -> cycleSelectedForm(next) }
}
TAB_EVOLUTION_TREE -> {
(tabInfoElement as EvolutionTreeWidget).setup(selectedEntry, selectedForm)
}
}
} else {
if (tabInfoIndex != TAB_DESCRIPTION) displaytabInfoElement(TAB_DESCRIPTION)
@@ -764,12 +813,6 @@ class PokedexGUI private constructor(
return true
}
if (!searchWidget.isFocused) {
selectedEntry?.speciesId?.let { speciesId ->
handleProfileDebugKeys(keyCode, speciesId, pokemonInfoWidget.state)
}
}
return super.keyPressed(keyCode, scanCode, modifiers)
}
@@ -16,6 +16,8 @@ object PokedexGUIConstants {
const val HEADER_BAR_HEIGHT = 11
const val POKEMON_DESCRIPTION_HEIGHT = 42
const val POKEMON_DESCRIPTION_PADDING = 9
const val ICONS_PADDING_AROUND = 18.5f
const val ICONS_ARROW_PADDING_AROUND = ICONS_PADDING_AROUND + 1
const val TAB_ICON_SIZE = 16
@@ -36,6 +38,7 @@ object PokedexGUIConstants {
const val TAB_STATS = 3
const val TAB_DROPS = 4
const val TAB_MOVES = 5
const val TAB_EVOLUTION_TREE = 6
// RowScrollingWidget
const val SCROLL_BASE_HEIGHT = 141
@@ -20,31 +20,95 @@ import net.minecraft.network.chat.MutableComponent
private val tooltipEdge = cobblemonResource("textures/gui/pokedex/tooltip_edge.png")
private val tooltipBackground = cobblemonResource("textures/gui/pokedex/tooltip_background.png")
fun renderTooltip(context: GuiGraphics, text: MutableComponent, posX: Int, posY: Int, delta: Float, offsetY: Int = 0) {
fun renderTooltip(
context: GuiGraphics,
text: MutableComponent,
posX: Int,
posY: Int,
delta: Float,
offsetY: Int = 0,
) {
renderTooltip(
context,
listOf(text),
posX,
posY,
delta,
offsetY,
)
}
fun renderTooltip(
context: GuiGraphics,
text: List<MutableComponent>,
posX: Int,
posY: Int,
delta: Float,
offsetY: Int = 0,
) {
val poseStack = context.pose()
val textWidth = Minecraft.getInstance().font.width(text.font(CobblemonResources.DEFAULT_LARGE))
val tooltipWidth = textWidth + 6
val textWidth = text.maxOf { Minecraft.getInstance().font.width(it.font(CobblemonResources.DEFAULT_LARGE)) }
val tooltipPadding = 6
val tooltipWidth = textWidth + tooltipPadding
val tooltipHeight = 11
val tooltipTop = posY + offsetY
poseStack.pushPose()
poseStack.translate(0.0, 0.0, 1000.0)
Minecraft.getInstance().let {
it.mainRenderTarget.bindWrite(false)
context.enableScissor(
posX - (tooltipWidth / 2),
tooltipTop + 1,
(posX - (tooltipWidth / 2)) + tooltipWidth,
tooltipTop + 10
tooltipTop + tooltipHeight * text.size - 1
)
it.gameRenderer.processBlurEffect(delta)
context.disableScissor()
it.mainRenderTarget.bindWrite(true)
}
blitk(matrixStack = poseStack, texture = tooltipEdge, x = posX - (tooltipWidth / 2) - 1, y = tooltipTop, width = 1, height = tooltipHeight)
blitk(matrixStack = poseStack, texture = tooltipBackground, x = posX - (tooltipWidth / 2), y = tooltipTop, width = tooltipWidth, height = tooltipHeight)
blitk(matrixStack = poseStack, texture = tooltipEdge, x = posX + (tooltipWidth / 2), y = tooltipTop, width = 1, height = tooltipHeight)
drawScaledText(context = context, font = CobblemonResources.DEFAULT_LARGE, text = text, x = posX, y = tooltipTop + 1, shadow = true, centered = true)
blitk(
matrixStack = poseStack,
texture = tooltipEdge,
x = posX - (tooltipWidth / 2) - 1,
y = tooltipTop,
width = 1,
height = tooltipHeight * text.size
)
blitk(
matrixStack = poseStack,
texture = tooltipBackground,
x = posX - (tooltipWidth / 2),
y = tooltipTop,
width = tooltipWidth,
height = tooltipHeight * text.size
)
blitk(
matrixStack = poseStack,
texture = tooltipEdge,
x = posX + (tooltipWidth / 2),
y = tooltipTop,
width = 1,
height = tooltipHeight * text.size
)
val centered = text.size == 1
text.forEachIndexed { index, it ->
drawScaledText(
context = context,
font = CobblemonResources.DEFAULT_LARGE,
text = it,
x = if (centered) posX else posX - tooltipWidth / 2 + tooltipPadding / 2,
y = tooltipTop + 1 + (tooltipHeight - 2) * index,
shadow = true,
centered = centered
)
}
poseStack.popPose()
}
@@ -20,8 +20,8 @@ import net.minecraft.client.sounds.SoundManager
import net.minecraft.resources.ResourceLocation
class ScaledButton(
var buttonX: Float,
var buttonY: Float,
buttonX: Float,
buttonY: Float,
val buttonWidth: Number,
val buttonHeight: Number,
var resource: ResourceLocation? = null,
@@ -30,6 +30,18 @@ class ScaledButton(
val clickAction: Button.OnPress
): Button(buttonX.toInt(), buttonY.toInt(), buttonWidth.toInt(), buttonHeight.toInt(), "".text(), clickAction, DEFAULT_NARRATION), CobblemonRenderable {
var buttonX: Float = buttonX
set(value) {
field = value
this.x = value.toInt()
}
var buttonY: Float = buttonY
set(value) {
field = value
this.y = value.toInt()
}
var isWidgetActive = false
var isVisible = true
@@ -12,14 +12,13 @@ import com.bedrockk.molang.runtime.MoLangRuntime
import com.cobblemon.mod.common.CobblemonSounds
import com.cobblemon.mod.common.api.gui.blitk
import com.cobblemon.mod.common.api.molang.MoLangFunctions.setup
import com.cobblemon.mod.common.api.pokedex.entry.PokedexEntry
import com.cobblemon.mod.common.api.pokedex.PokedexEntryProgress
import com.cobblemon.mod.common.api.pokedex.entry.PokedexEntry
import com.cobblemon.mod.common.api.pokemon.PokemonSpecies
import com.cobblemon.mod.common.api.text.text
import com.cobblemon.mod.common.client.ClientMoLangFunctions.setupClient
import com.cobblemon.mod.common.client.CobblemonClient
import com.cobblemon.mod.common.client.gui.ScrollingWidget
import com.cobblemon.mod.common.client.gui.drawProfilePokemon
import com.cobblemon.mod.common.client.gui.pokedex.PokedexGUIConstants
import com.cobblemon.mod.common.client.gui.pokedex.PokedexGUIConstants.SCALE
import com.cobblemon.mod.common.client.gui.pokedex.PokedexGUIConstants.SCROLL_BAR_WIDTH
@@ -27,19 +26,14 @@ import com.cobblemon.mod.common.client.gui.pokedex.PokedexGUIConstants.SCROLL_BA
import com.cobblemon.mod.common.client.gui.pokedex.PokedexGUIConstants.SCROLL_SLOT_SIZE
import com.cobblemon.mod.common.client.gui.pokedex.PokedexGUIConstants.SCROLL_SLOT_SPACING
import com.cobblemon.mod.common.client.gui.pokedex.widgets.EntriesScrollingWidget.PokemonScrollSlotRow
import com.cobblemon.mod.common.client.render.drawScaledText
import com.cobblemon.mod.common.client.render.models.blockbench.FloatingState
import com.cobblemon.mod.common.pokemon.Gender
import com.cobblemon.mod.common.pokemon.RenderablePokemon
import com.cobblemon.mod.common.util.cobblemonResource
import com.cobblemon.mod.common.util.math.fromEulerXYZDegrees
import net.minecraft.client.Minecraft
import net.minecraft.client.gui.GuiGraphics
import net.minecraft.client.resources.sounds.SimpleSoundInstance
import net.minecraft.network.chat.Component
import net.minecraft.util.Mth
import org.joml.Quaternionf
import org.joml.Vector3f
class EntriesScrollingWidget(val pX: Int, val pY: Int, val setPokedexEntry: (PokedexEntry) -> (Unit)): ScrollingWidget<PokemonScrollSlotRow>(
width = PokedexGUIConstants.HALF_OVERLAY_WIDTH,
@@ -135,13 +129,6 @@ class EntriesScrollingWidget(val pX: Int, val pY: Int, val setPokedexEntry: (Pok
val discoveryLevelList: MutableList<PokedexEntryProgress>,
val setPokedexEntry : (PokedexEntry) -> (Unit)
): Slot<PokemonScrollSlotRow>() {
companion object {
private val slotResource = cobblemonResource("textures/gui/pokedex/pokedex_slot.png")
private val slotHighlight = cobblemonResource("textures/gui/pokedex/slot_select.png")
private val caughtIcon = cobblemonResource("textures/gui/pokedex/caught_icon_small.png")
private val unknownIcon = cobblemonResource("textures/gui/pokedex/pokedex_slot_unknown.png")
private val unimplementedIcon = cobblemonResource("textures/gui/pokedex/pokedex_slot_unimplemented.png")
}
val runtime = MoLangRuntime().setupClient().setup().also {
it.environment.query.addFunction("get_pokedex") { CobblemonClient.clientPokedexData.struct }
}
@@ -161,128 +148,42 @@ class EntriesScrollingWidget(val pX: Int, val pY: Int, val setPokedexEntry: (Pok
hovered: Boolean,
tickDelta: Float
) {
dexDataList.forEachIndexed { index, dexData ->
val state = FloatingState()
val species = PokemonSpecies.getByIdentifier(dexData.speciesId)
//FIXME: This may not work properly when accounting for custom pokemon with the same dex number
val pokemonNumber = (species?.nationalPokedexNumber?.toString() ?: "0").padStart(4, '0')
val speciesNumber = pokemonNumber.text()
dexDataList.forEachIndexed { index, pokedexEntry ->
val species = PokemonSpecies.getByIdentifier(pokedexEntry.speciesId)
val discoveryLevel = discoveryLevelList[index]
val firstVisibleForm = CobblemonClient.clientPokedexData.getEncounteredForms(dexData).firstOrNull()
val shouldDrawMon = firstVisibleForm != null
val firstVisibleForm = CobblemonClient.clientPokedexData.getEncounteredForms(pokedexEntry).firstOrNull()
if (species == null) {
return@forEachIndexed
}
val matrices = context.pose()
val renderablePokemon =
if (firstVisibleForm != null) {
val firstVisibleGender = CobblemonClient.clientPokedexData.getSeenGenders(pokedexEntry, firstVisibleForm).firstOrNull()
val shinyStates = CobblemonClient.clientPokedexData.getSeenShinyStates(pokedexEntry, firstVisibleForm)
val firstVisibleShiny = shinyStates.count() == 1 && shinyStates.first() == "shiny"
val formAspects = species.forms.firstOrNull { it.name.equals(firstVisibleForm.displayForm, ignoreCase = true) }?.aspects ?: species.standardForm.aspects
val seenAspects = CobblemonClient.clientPokedexData.getSeenAspects(pokedexEntry)
val variationAspects = pokedexEntry.variations.mapNotNull { it.aspects.firstOrNull { it in seenAspects } }
val aspectsToDraw = (pokedexEntry.displayAspects + variationAspects + formAspects + (firstVisibleGender ?: Gender.GENDERLESS).name.lowercase()).toMutableSet()
if (firstVisibleShiny) {
aspectsToDraw.add("shiny")
}
val startPosX = x + ((SCROLL_SLOT_SPACING + SCROLL_SLOT_SIZE) * index)
val startPosY = y + SCROLL_SLOT_SPACING + 1
blitk(
matrixStack = matrices,
texture = slotResource,
x = startPosX,
y = startPosY,
width = SCROLL_SLOT_SIZE,
height = SCROLL_SLOT_SIZE
)
if (getHoveredSlotIndex(mouseX, mouseY) == index) {
blitk(
matrixStack = matrices,
texture = slotHighlight,
x = startPosX,
y = startPosY,
width = SCROLL_SLOT_SIZE,
height = SCROLL_SLOT_SIZE,
vOffset = SCROLL_SLOT_SIZE,
textureHeight = SCROLL_SLOT_SIZE * 2
)
}
if (shouldDrawMon) {
val firstVisibleGender = CobblemonClient.clientPokedexData.getSeenGenders(dexData, firstVisibleForm).firstOrNull()
val shinyStates = CobblemonClient.clientPokedexData.getSeenShinyStates(dexData, firstVisibleForm)
val firstVisibleShiny = shinyStates.count() == 1 && shinyStates.first() == "shiny"
val formAspects = species.forms.firstOrNull { it.name.equals(firstVisibleForm.displayForm, ignoreCase = true) }?.aspects ?: species.standardForm.aspects
val seenAspects = CobblemonClient.clientPokedexData.getSeenAspects(dexData)
val variationAspects = dexData.variations.mapNotNull { it.aspects.firstOrNull { it in seenAspects } }
context.enableScissor(
startPosX + 1,
startPosY + 1,
startPosX + SCROLL_SLOT_SIZE - 1,
startPosY + SCROLL_SLOT_SIZE - 2
)
val aspectsToDraw = (dexData.displayAspects + variationAspects + formAspects + (firstVisibleGender ?: Gender.GENDERLESS).name.lowercase()).toMutableSet()
if (firstVisibleShiny) {
aspectsToDraw.add("shiny")
RenderablePokemon(species, aspectsToDraw)
} else {
null
}
state.currentAspects = aspectsToDraw
matrices.pushPose()
matrices.translate(startPosX + (SCROLL_SLOT_SIZE / 2.0), startPosY + 1.0, 0.0)
matrices.scale(2.5F, 2.5F, 1F)
drawProfilePokemon(
renderablePokemon = RenderablePokemon(species, aspectsToDraw),
matrixStack = matrices,
rotation = Quaternionf().fromEulerXYZDegrees(Vector3f(13F, 35F, 0F)),
state = state,
partialTicks = 0F,
scale = 4.5F
)
matrices.popPose()
context.disableScissor()
} else {
blitk(
matrixStack = matrices,
texture = unknownIcon,
x = startPosX + 8.5,
y = startPosY + 9,
width = 8,
height = 10
)
if (!species.implemented) {
blitk(
matrixStack = matrices,
texture = unimplementedIcon,
x = (startPosX + 14) / SCALE,
y = (startPosY + 15.5) / SCALE,
width = 7,
height = 7,
scale = SCALE
)
}
}
// Ensure elements are not hidden behind Pokémon render
matrices.pushPose()
matrices.translate(0.0, 0.0, 100.0)
drawScaledText(
context = context,
text = speciesNumber,
x = startPosX + 1.5,//2,
y = startPosY + 2.5,//2
shadow = true,
scale = SCALE
PokemonSlotWidget.render(
context,
x = x + (SCROLL_SLOT_SPACING + SCROLL_SLOT_SIZE) * index,
y = y + SCROLL_SLOT_SPACING + 1,
getHoveredSlotIndex(mouseX, mouseY) == index,
species,
renderablePokemon,
discoveryLevel,
)
if (discoveryLevel == PokedexEntryProgress.OWNED) {
blitk(
matrixStack = matrices,
texture = caughtIcon,
x = (startPosX + 18) / SCALE,
y = (startPosY + 1.5) / SCALE,
width = 11,
height = 11,
scale = SCALE
)
}
matrices.popPose()
}
}
@@ -10,10 +10,10 @@ package com.cobblemon.mod.common.client.gui.pokedex.widgets
import com.bedrockk.molang.runtime.MoLangRuntime
import com.cobblemon.mod.common.api.gui.blitk
import com.cobblemon.mod.common.api.pokedex.entry.PokedexEntry
import com.cobblemon.mod.common.api.molang.MoLangFunctions.setup
import com.cobblemon.mod.common.api.pokedex.PokedexEntryProgress
import com.cobblemon.mod.common.api.pokedex.entry.PokedexCosmeticVariation
import com.cobblemon.mod.common.api.pokedex.entry.PokedexEntry
import com.cobblemon.mod.common.api.pokedex.entry.PokedexForm
import com.cobblemon.mod.common.api.pokemon.PokemonSpecies
import com.cobblemon.mod.common.api.text.bold
@@ -22,11 +22,11 @@ import com.cobblemon.mod.common.api.types.ElementalType
import com.cobblemon.mod.common.client.ClientMoLangFunctions.setupClient
import com.cobblemon.mod.common.client.CobblemonClient
import com.cobblemon.mod.common.client.CobblemonResources
import com.cobblemon.mod.common.client.gui.ProfileTransformType
import com.cobblemon.mod.common.client.gui.TypeIcon
import com.cobblemon.mod.common.client.gui.drawProfilePokemon
import com.cobblemon.mod.common.client.gui.pokedex.PokedexGUIConstants.HALF_OVERLAY_HEIGHT
import com.cobblemon.mod.common.client.gui.pokedex.PokedexGUI
import com.cobblemon.mod.common.client.gui.pokedex.PokedexGUIConstants.HALF_OVERLAY_WIDTH
import com.cobblemon.mod.common.client.gui.pokedex.PokedexGUIConstants.HALF_OVERLAY_HEIGHT
import com.cobblemon.mod.common.client.gui.pokedex.PokedexGUIConstants.POKEMON_PORTRAIT_HEIGHT
import com.cobblemon.mod.common.client.gui.pokedex.PokedexGUIConstants.POKEMON_PORTRAIT_WIDTH
import com.cobblemon.mod.common.client.gui.pokedex.PokedexGUIConstants.PORTRAIT_POKE_BALL_HEIGHT
@@ -52,15 +52,13 @@ import com.cobblemon.mod.common.util.math.fromEulerXYZDegrees
import net.minecraft.client.Minecraft
import net.minecraft.client.gui.GuiGraphics
import net.minecraft.client.resources.sounds.SimpleSoundInstance
import net.minecraft.network.chat.Component
import net.minecraft.network.chat.MutableComponent
import net.minecraft.resources.ResourceLocation
import net.minecraft.sounds.SoundEvent
import org.joml.Quaternionf
import org.joml.Vector3f
import java.io.FileNotFoundException
class PokemonInfoWidget(val pX: Int, val pY: Int, val updateForm: (PokedexForm) -> (Unit)) : SoundlessWidget(
class PokemonInfoWidget(val parent: PokedexGUI, val pX: Int, val pY: Int, val updateForm: (PokedexForm) -> (Unit)) : SoundlessWidget(
pX,
pY,
POKEMON_PORTRAIT_WIDTH,
@@ -82,7 +80,6 @@ class PokemonInfoWidget(val pX: Int, val pY: Int, val updateForm: (PokedexForm)
private val arrowFormLeft = cobblemonResource("textures/gui/pokedex/forms_arrow_left.png")
private val arrowFormRight = cobblemonResource("textures/gui/pokedex/forms_arrow_right.png")
private val caughtIcon = cobblemonResource("textures/gui/pokedex/caught_icon.png")
private val typeBar = cobblemonResource("textures/gui/pokedex/type_bar.png")
private val typeBarDouble = cobblemonResource("textures/gui/pokedex/type_bar_double.png")
@@ -100,9 +97,6 @@ class PokemonInfoWidget(val pX: Int, val pY: Int, val updateForm: (PokedexForm)
var currentEntry : PokedexEntry? = null
var speciesName: MutableComponent = Component.translatable("")
var speciesNumber: MutableComponent = "0000".text()
val runtime = MoLangRuntime().setupClient().setup().also {
it.environment.query.addFunction("get_pokedex") { CobblemonClient.clientPokedexData.struct }
}
@@ -111,10 +105,6 @@ class PokemonInfoWidget(val pX: Int, val pY: Int, val updateForm: (PokedexForm)
var selectedFormIndex: Int = 0
var type: Array<ElementalType?> = arrayOf(null, null)
var seenShinyStates: Set<String> = setOf()
var shiny = false
var maleRatio = -1F
var gender: Gender = Gender.GENDERLESS
var renderablePokemon : RenderablePokemon? = null
@@ -195,7 +185,10 @@ class PokemonInfoWidget(val pX: Int, val pY: Int, val updateForm: (PokedexForm)
20,
resource = buttonGenderMale,
clickAction = {
if (maleRatio > 0 && maleRatio < 1) gender = if (gender == Gender.MALE) Gender.FEMALE else Gender.MALE
val maleRatio = parent.maleRatio
if (maleRatio > 0 && maleRatio < 1) {
parent.gender = if (parent.gender == Gender.MALE) Gender.FEMALE else Gender.MALE
}
updateAspects()
}
).apply { addWidget(this) }
@@ -207,8 +200,8 @@ class PokemonInfoWidget(val pX: Int, val pY: Int, val updateForm: (PokedexForm)
20,
buttonNone,
clickAction = {
if (seenShinyStates.size > 1) {
shiny = !shiny
if (parent.seenShinyStates.size > 1) {
parent.shiny = !parent.shiny
updateAspects()
}
}
@@ -263,8 +256,7 @@ class PokemonInfoWidget(val pX: Int, val pY: Int, val updateForm: (PokedexForm)
override fun renderWidget(context: GuiGraphics, mouseX: Int, mouseY: Int, delta: Float) {
val currentEntry = this.currentEntry ?: return
val hasKnowledge =
CobblemonClient.clientPokedexData.getKnowledgeForSpecies(currentEntry.speciesId) != PokedexEntryProgress.UNREGISTERED
val hasKnowledge = CobblemonClient.clientPokedexData.getKnowledgeForSpecies(currentEntry.speciesId) != PokedexEntryProgress.UNREGISTERED
val species = currentEntry.speciesId.let { PokemonSpecies.getByIdentifier(it) } ?: return
val matrices = context.pose()
@@ -277,37 +269,6 @@ class PokemonInfoWidget(val pX: Int, val pY: Int, val updateForm: (PokedexForm)
height = HALF_OVERLAY_HEIGHT
)
drawScaledText(
context = context,
font = CobblemonResources.DEFAULT_LARGE,
text = speciesNumber.bold(),
x = pX + 3,
y = pY + 1,
shadow = true
)
drawScaledText(
context = context,
font = CobblemonResources.DEFAULT_LARGE,
text = (if (hasKnowledge) speciesName else lang("ui.generic.question_marks")).bold(),
x = pX + 26,
y = pY + 1,
colour = 0x606B6E
)
// Caught icon
if (isSelectedPokemonOwned()) {
blitk(
matrixStack = matrices,
texture = caughtIcon,
x = (pX + 129) / SCALE,
y = (pY + 2) / SCALE,
width = 14,
height = 14,
scale = SCALE
)
}
if (!suppressViewport) {
blitk(
matrixStack = matrices,
@@ -387,8 +348,7 @@ class PokemonInfoWidget(val pX: Int, val pY: Int, val updateForm: (PokedexForm)
partialTicks = delta,
rotation = Quaternionf().fromEulerXYZDegrees(rotationVector),
state = state,
blockLight = 15,
profileTransformType = ProfileTransformType.POKEDEX,
blockLight = 15
)
matrices.popPose()
@@ -571,8 +531,6 @@ class PokemonInfoWidget(val pX: Int, val pY: Int, val updateForm: (PokedexForm)
if (species != null) {
this.visibleForms = CobblemonClient.clientPokedexData.getEncounteredForms(pokedexEntry).toMutableList()
this.speciesNumber = species.nationalPokedexNumber.toString().padStart(4, '0').text()
this.speciesName = species.translatedName
if (forms.isNotEmpty()) {
formLeftButton.active = true
@@ -598,23 +556,23 @@ class PokemonInfoWidget(val pX: Int, val pY: Int, val updateForm: (PokedexForm)
variationButtons.forEach { removeWidget(it.getWidget()) }
variationButtons.clear()
seenShinyStates = CobblemonClient.clientPokedexData.getSeenShinyStates(pokedexEntry, pokedexForm)
shiny = seenShinyStates.count() == 1 && seenShinyStates.first() == "shiny"
shinyButton.resource = if (shiny) buttonShiny else buttonNone
shinyButton.visible = shiny || seenShinyStates.size > 1
shinyButton.active = seenShinyStates.size > 1
parent.seenShinyStates = CobblemonClient.clientPokedexData.getSeenShinyStates(pokedexEntry, pokedexForm)
parent.shiny = parent.seenShinyStates.count() == 1 && parent.seenShinyStates.first() == "shiny"
shinyButton.resource = if (parent.shiny) buttonShiny else buttonNone
shinyButton.visible = parent.shiny || parent.seenShinyStates.size > 1
shinyButton.active = parent.seenShinyStates.size > 1
val form = species.forms.find { it.name.equals(pokedexForm.displayForm, ignoreCase = true) } ?: species.standardForm
maleRatio = form.maleRatio
parent.maleRatio = form.maleRatio
val seenGenders = CobblemonClient.clientPokedexData.getSeenGenders(pokedexEntry, pokedexForm)
val visibleGenders = seenGenders.filter { it != Gender.GENDERLESS }
if (visibleGenders.isEmpty()) {
gender = Gender.GENDERLESS
parent.gender = Gender.GENDERLESS
genderButton.visible = false
genderButton.active = false
} else {
gender = visibleGenders.first()
parent.gender = visibleGenders.first()
genderButton.visible = true
genderButton.active = visibleGenders.size > 1
}
@@ -693,8 +651,8 @@ class PokemonInfoWidget(val pX: Int, val pY: Int, val updateForm: (PokedexForm)
return
}
genderButton.resource = if (gender == Gender.FEMALE) buttonGenderFemale else buttonGenderMale
shinyButton.resource = if (shiny) buttonShiny else buttonNone
genderButton.resource = if (parent.gender == Gender.FEMALE) buttonGenderFemale else buttonGenderMale
shinyButton.resource = if (parent.shiny) buttonShiny else buttonNone
val species = currentEntry?.speciesId?.let { PokemonSpecies.getByIdentifier(it) }
if (species != null) {
@@ -703,12 +661,14 @@ class PokemonInfoWidget(val pX: Int, val pY: Int, val updateForm: (PokedexForm)
updateType(species, form)
val aspects = mutableSetOf<String>()
if (shiny) aspects.add(SHINY_ASPECT.aspect)
val aspects = parent.aspects
aspects.clear()
if (gender == Gender.FEMALE) {
if (parent.shiny) aspects.add(SHINY_ASPECT.aspect)
if (parent.gender == Gender.FEMALE) {
aspects.add("female")
} else if (gender == Gender.MALE) {
} else if (parent.gender == Gender.MALE) {
aspects.add("male")
}
@@ -0,0 +1,100 @@
/*
* 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.pokedex.widgets
import com.cobblemon.mod.common.api.gui.blitk
import com.cobblemon.mod.common.api.pokedex.PokedexEntryProgress
import com.cobblemon.mod.common.api.pokedex.entry.PokedexEntry
import com.cobblemon.mod.common.api.pokemon.PokemonSpecies
import com.cobblemon.mod.common.api.text.bold
import com.cobblemon.mod.common.api.text.text
import com.cobblemon.mod.common.client.CobblemonClient
import com.cobblemon.mod.common.client.CobblemonResources
import com.cobblemon.mod.common.client.gui.pokedex.PokedexGUI
import com.cobblemon.mod.common.client.gui.pokedex.PokedexGUIConstants.POKEMON_PORTRAIT_HEIGHT
import com.cobblemon.mod.common.client.gui.pokedex.PokedexGUIConstants.POKEMON_PORTRAIT_WIDTH
import com.cobblemon.mod.common.client.gui.pokedex.PokedexGUIConstants.SCALE
import com.cobblemon.mod.common.client.gui.summary.widgets.SoundlessWidget
import com.cobblemon.mod.common.client.render.drawScaledText
import com.cobblemon.mod.common.util.cobblemonResource
import com.cobblemon.mod.common.util.lang
import net.minecraft.client.gui.GuiGraphics
import net.minecraft.network.chat.Component
import net.minecraft.network.chat.MutableComponent
class PokemonNameWidget(
val parent: PokedexGUI,
val pX: Int,
val pY: Int,
) : SoundlessWidget(
pX,
pY,
POKEMON_PORTRAIT_WIDTH,
POKEMON_PORTRAIT_HEIGHT,
lang("ui.pokedex.pokemon_name"),
) {
companion object {
private val caughtIcon = cobblemonResource("textures/gui/pokedex/caught_icon.png")
}
var hasKnowledge: Boolean = false
var isOwned: Boolean = false
var speciesName: MutableComponent = Component.translatable("")
var speciesNumber: MutableComponent = "0000".text()
override fun renderWidget(
context: GuiGraphics,
mouseX: Int,
mouseY: Int,
partialTick: Float
) {
drawScaledText(
context = context,
font = CobblemonResources.DEFAULT_LARGE,
text = speciesNumber.bold(),
x = pX + 3,
y = pY + 1,
shadow = true
)
if (hasKnowledge) {
drawScaledText(
context = context,
font = CobblemonResources.DEFAULT_LARGE,
text = speciesName.bold(),
x = pX + 26,
y = pY + 1,
colour = 0x606B6E
)
}
if (isOwned) {
blitk(
matrixStack = context.pose(),
texture = caughtIcon,
x = (pX + 129) / SCALE,
y = (pY + 2) / SCALE,
width = 14,
height = 14,
scale = SCALE
)
}
}
fun update(pokedexEntry: PokedexEntry) {
val species = PokemonSpecies.getByIdentifier(pokedexEntry.speciesId) ?: return
val progress = CobblemonClient.clientPokedexData.getKnowledgeForSpecies(pokedexEntry.speciesId)
this.hasKnowledge = progress != PokedexEntryProgress.UNREGISTERED
this.isOwned = progress == PokedexEntryProgress.OWNED
this.speciesNumber = species.nationalPokedexNumber.toString().padStart(4, '0').text()
this.speciesName = species.translatedName
}
}
@@ -0,0 +1,151 @@
/*
* 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.pokedex.widgets
import com.cobblemon.mod.common.api.gui.blitk
import com.cobblemon.mod.common.api.pokedex.PokedexEntryProgress
import com.cobblemon.mod.common.api.text.text
import com.cobblemon.mod.common.client.gui.drawProfilePokemon
import com.cobblemon.mod.common.client.gui.pokedex.PokedexGUIConstants.SCALE
import com.cobblemon.mod.common.client.gui.pokedex.PokedexGUIConstants.SCROLL_SLOT_SIZE
import com.cobblemon.mod.common.client.render.drawScaledText
import com.cobblemon.mod.common.client.render.models.blockbench.FloatingState
import com.cobblemon.mod.common.pokemon.RenderablePokemon
import com.cobblemon.mod.common.pokemon.Species
import com.cobblemon.mod.common.util.cobblemonResource
import com.cobblemon.mod.common.util.math.fromEulerXYZDegrees
import net.minecraft.client.gui.GuiGraphics
import org.joml.Quaternionf
import org.joml.Vector3f
abstract class PokemonSlotWidget {
companion object {
private val slotResource = cobblemonResource("textures/gui/pokedex/pokedex_slot.png")
private val slotHighlight = cobblemonResource("textures/gui/pokedex/slot_select.png")
private val caughtIcon = cobblemonResource("textures/gui/pokedex/caught_icon_small.png")
private val unknownIcon = cobblemonResource("textures/gui/pokedex/pokedex_slot_unknown.png")
private val unimplementedIcon = cobblemonResource("textures/gui/pokedex/pokedex_slot_unimplemented.png")
fun render(
context: GuiGraphics,
x: Int,
y: Int,
isHovered: Boolean,
species: Species,
renderablePokemon: RenderablePokemon?,
discoveryLevel: PokedexEntryProgress,
) {
val shouldDrawMon = renderablePokemon != null
// FIXME: This may not work properly when accounting for custom pokemon with the same dex number
val pokemonNumber = species.nationalPokedexNumber.toString().padStart(4, '0')
val speciesNumber = pokemonNumber.text()
val matrices = context.pose()
blitk(
matrixStack = matrices,
texture = slotResource,
x = x,
y = y,
width = SCROLL_SLOT_SIZE,
height = SCROLL_SLOT_SIZE,
)
if (isHovered) {
blitk(
matrixStack = matrices,
texture = slotHighlight,
x = x,
y = y,
width = SCROLL_SLOT_SIZE,
height = SCROLL_SLOT_SIZE,
vOffset = SCROLL_SLOT_SIZE,
textureHeight = SCROLL_SLOT_SIZE * 2,
)
}
if (shouldDrawMon && discoveryLevel != PokedexEntryProgress.UNREGISTERED) {
context.enableScissor(
x + 1,
y + 1,
x + SCROLL_SLOT_SIZE - 1,
y + SCROLL_SLOT_SIZE - 2,
)
matrices.pushPose()
matrices.translate(x + SCROLL_SLOT_SIZE / 2.0, y + 1.0, 0.0)
matrices.scale(2.5F, 2.5F, 1F)
val state = FloatingState()
state.currentAspects = renderablePokemon.aspects
drawProfilePokemon(
renderablePokemon = renderablePokemon,
matrixStack = matrices,
rotation = Quaternionf().fromEulerXYZDegrees(Vector3f(13F, 35F, 0F)),
state = state,
partialTicks = 0F,
scale = 4.5F
)
matrices.popPose()
context.disableScissor()
} else {
blitk(
matrixStack = matrices,
texture = unknownIcon,
x = x + 8.5,
y = y + 9,
width = 8,
height = 10
)
if (!species.implemented) {
blitk(
matrixStack = matrices,
texture = unimplementedIcon,
x = (x + 14) / SCALE,
y = (y + 15.5) / SCALE,
width = 7,
height = 7,
scale = SCALE
)
}
}
// Ensure elements are not hidden behind Pokémon render
matrices.pushPose()
matrices.translate(0.0, 0.0, 100.0)
drawScaledText(
context = context,
text = speciesNumber,
x = x + 1.5,
y = y + 2.5,
shadow = true,
scale = SCALE
)
if (discoveryLevel == PokedexEntryProgress.OWNED) {
blitk(
matrixStack = matrices,
texture = caughtIcon,
x = (x + 18) / SCALE,
y = (y + 1.5) / SCALE,
width = 11,
height = 11,
scale = SCALE
)
}
matrices.popPose()
}
}
}
@@ -11,7 +11,6 @@ package com.cobblemon.mod.common.client.gui.pokedex.widgets
import com.cobblemon.mod.common.api.gui.blitk
import com.cobblemon.mod.common.api.text.bold
import com.cobblemon.mod.common.client.CobblemonResources
import com.cobblemon.mod.common.client.gui.ProfileTransformType
import com.cobblemon.mod.common.client.gui.drawProfilePokemon
import com.cobblemon.mod.common.client.gui.pokedex.PokedexGUIConstants.HALF_OVERLAY_WIDTH
import com.cobblemon.mod.common.client.gui.pokedex.PokedexGUIConstants.POKEMON_DESCRIPTION_HEIGHT
@@ -91,7 +90,7 @@ class SizeWidget(val pX: Int, val pY: Int) : SoundlessWidget(
rotation = Quaternionf().fromEulerXYZDegrees(Vector3f(0F, 0F, 0F)),
state = FloatingState(),
scale = modelScale,
profileTransformType = ProfileTransformType.NONE,
applyProfileTransform = false,
applyBaseScale = true,
r = 0F,
g = 0F,
@@ -0,0 +1,124 @@
/*
* 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.pokedex.widgets.evolutiontree
import com.cobblemon.mod.common.CobblemonItems
import com.cobblemon.mod.common.api.pokemon.PokemonSpecies
import com.cobblemon.mod.common.api.pokemon.evolution.Evolution
import com.cobblemon.mod.common.api.pokemon.evolution.EvolutionVisitor
import com.cobblemon.mod.common.api.pokemon.requirement.Requirement
import com.cobblemon.mod.common.api.text.bold
import com.cobblemon.mod.common.api.text.green
import com.cobblemon.mod.common.client.gui.pokedex.widgets.evolutiontree.EvolutionTreeEvolutionVisitor.RenderEvolutionData
import com.cobblemon.mod.common.client.gui.pokedex.widgets.evolutiontree.EvolutionTreeRequirementVisitor.RenderRequirementData
import com.cobblemon.mod.common.pokemon.evolution.variants.BlockClickEvolution
import com.cobblemon.mod.common.pokemon.evolution.variants.ItemInteractionEvolution
import com.cobblemon.mod.common.pokemon.evolution.variants.LevelUpEvolution
import com.cobblemon.mod.common.pokemon.evolution.variants.TradeEvolution
import com.cobblemon.mod.common.util.cobblemonResource
import com.cobblemon.mod.common.util.itemRegistry
import com.cobblemon.mod.common.util.lang
import net.minecraft.client.Minecraft
import net.minecraft.network.chat.Component
import net.minecraft.network.chat.MutableComponent
import net.minecraft.resources.ResourceLocation
import net.minecraft.world.item.Item
import net.minecraft.world.item.ItemStack
class EvolutionTreeEvolutionVisitor : EvolutionVisitor<RenderEvolutionData?> {
data class RenderEvolutionData(
val label: MutableComponent,
val icons: List<Item>,
val tooltips: List<MutableComponent>,
)
private val requirementVisitor = EvolutionTreeRequirementVisitor()
private fun visitRequirement(requirement: Requirement): RenderRequirementData? {
val icon = requirement.pokedexIcon?.let {
Minecraft.getInstance()?.player?.level()?.itemRegistry?.get(it)
}
val tooltip = requirement.pokedexTooltip?.let {
Component.translatable(it)
}
if (icon != null && tooltip != null) {
return RenderRequirementData(icon, tooltip)
}
return requirementVisitor.visit(requirement)
}
override fun visitBlockClickEvolution(blockClickEvolution: BlockClickEvolution): RenderEvolutionData? {
return null
}
override fun visitDummyEvolution(evolution: Evolution): RenderEvolutionData? {
return null
}
override fun visitItemInteractionEvolution(itemInteractionEvolution: ItemInteractionEvolution): RenderEvolutionData? {
val label = lang("ui.pokedex.evolution.item_interact.label").bold()
val item = itemInteractionEvolution.requiredContext.items.get().first().value()
val icons = mutableListOf(item)
val tooltips =
mutableListOf(lang("ui.pokedex.evolution.item_interact.tooltip", item.description.plainCopy().green()))
val requirementsDataList = itemInteractionEvolution.requirements.mapNotNull { requirement ->
visitRequirement(requirement)
}
requirementsDataList.forEach { requirement ->
icons.add(requirement.icon)
tooltips.add(requirement.tooltip)
}
return RenderEvolutionData(label, icons, tooltips)
}
override fun visitLevelUpEvolution(levelUpEvolution: LevelUpEvolution): RenderEvolutionData? {
val requirementsDataList = levelUpEvolution.requirements.map { requirement ->
visitRequirement(requirement)
}
val label = requirementsDataList.firstNotNullOfOrNull { requirement -> requirement?.label }
val icons = requirementsDataList.mapNotNull { requirementData -> requirementData?.icon }
val tooltips = requirementsDataList.mapNotNull { requirementData -> requirementData?.tooltip }
return RenderEvolutionData(label ?: Component.literal(""), icons, tooltips)
}
override fun visitTradeEvolution(tradeEvolution: TradeEvolution): RenderEvolutionData? {
val label = lang("ui.pokedex.evolution.trade.label")
val icons = mutableListOf<Item>(CobblemonItems.LINK_CABLE)
val tooltips = mutableListOf<MutableComponent>()
val species = tradeEvolution.requiredContext.species
if (species == null) {
tooltips.add(lang("ui.pokedex.evolution.trade.tooltip.with_any_species"))
} else {
PokemonSpecies.getByIdentifier(cobblemonResource(species))?.let {
tooltips.add(lang("ui.pokedex.evolution.trade.tooltip.with_species", it.translatedName.green()))
}
}
val requirementsDataList = tradeEvolution.requirements.mapNotNull { requirement ->
visitRequirement(requirement)
}
requirementsDataList.forEach { requirement ->
icons.add(requirement.icon)
tooltips.add(requirement.tooltip)
}
return RenderEvolutionData(label, icons, tooltips)
}
}
@@ -0,0 +1,271 @@
/*
* 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.pokedex.widgets.evolutiontree
import com.cobblemon.mod.common.client.gui.pokedex.widgets.evolutiontree.EvolutionTreeRequirementVisitor.RenderRequirementData
import com.cobblemon.mod.common.CobblemonItems
import com.cobblemon.mod.common.api.pokemon.PokemonSpecies
import com.cobblemon.mod.common.api.pokemon.requirement.RequirementVisitor
import com.cobblemon.mod.common.api.pokemon.stats.Stats
import com.cobblemon.mod.common.api.text.add
import com.cobblemon.mod.common.api.text.green
import com.cobblemon.mod.common.api.types.ElementalTypes
import com.cobblemon.mod.common.pokemon.requirements.*
import com.cobblemon.mod.common.util.cobblemonResource
import com.cobblemon.mod.common.util.lang
import net.minecraft.network.chat.Component
import net.minecraft.network.chat.MutableComponent
import net.minecraft.world.item.Item
import net.minecraft.world.item.Items
class EvolutionTreeRequirementVisitor : RequirementVisitor<RenderRequirementData?> {
data class RenderRequirementData(
val icon: Item,
val tooltip: MutableComponent,
val label: MutableComponent? = null,
)
override fun visitAdvancementRequirement(advancementRequirement: AdvancementRequirement): RenderRequirementData? {
val icon = Items.BOOK
val advancementLanguageKey = advancementRequirement.requiredAdvancement.toLanguageKey()
val advancementComponent = Component.translatable("advancements.$advancementLanguageKey").green()
val tooltip = lang("ui.pokedex.requirement.advancement.tooltip", advancementComponent)
return RenderRequirementData(icon, tooltip)
}
override fun visitAnyRequirement(anyRequirement: AnyRequirement): RenderRequirementData? {
return null
}
override fun visitAreaRequirement(areaRequirement: AreaRequirement): RenderRequirementData? {
return null
}
override fun visitAttackDefenceRatioRequirement(attackDefenceRatioRequirement: AttackDefenceRatioRequirement): RenderRequirementData? {
return null
}
override fun visitBattleCriticalHitsRequirement(battleCriticalHitsRequirement: BattleCriticalHitsRequirement): RenderRequirementData? {
val icon = CobblemonItems.MEDICINAL_LEEK
val criticalsComponent = Component.literal(battleCriticalHitsRequirement.amount.toString()).green()
val tooltip = lang("ui.pokedex.requirement.battle_critical_hits.tooltip", criticalsComponent)
return RenderRequirementData(icon, tooltip)
}
override fun visitBiomeRequirement(biomeRequirement: BiomeRequirement): RenderRequirementData? {
return null
}
override fun visitBlocksTraveledRequirement(blocksTraveledRequirement: BlocksTraveledRequirement): RenderRequirementData? {
val icon = Items.LEATHER_BOOTS
val blocksComponent = Component.literal(blocksTraveledRequirement.amount.toString()).green()
val tooltip = lang("ui.pokedex.requirement.blocks_traveled.tooltip", blocksComponent)
return RenderRequirementData(icon, tooltip)
}
override fun visitDamageTakenRequirement(damageTakenRequirement: DamageTakenRequirement): RenderRequirementData? {
val icon = CobblemonItems.PUNCHING_GLOVE
val blocksComponent = Component.literal(damageTakenRequirement.amount.toString()).green()
val tooltip = lang("ui.pokedex.requirement.damage_taken.tooltip", blocksComponent)
return RenderRequirementData(icon, tooltip)
}
override fun visitDefeatRequirement(defeatRequirement: DefeatRequirement): RenderRequirementData? {
val species = defeatRequirement.target.species?.let { PokemonSpecies.getByIdentifier(cobblemonResource(it)) } ?: return null
val icon = CobblemonItems.PUNCHING_GLOVE
val defeatedAmount = defeatRequirement.amount
val descriptionComponent = Component.literal(defeatedAmount.toString()).plainCopy().add(" ").add(species.translatedName).green()
val tooltip = lang("ui.pokedex.requirement.defeat.tooltip", descriptionComponent)
return RenderRequirementData(icon, tooltip)
}
override fun visitFriendshipRequirement(friendshipRequirement: FriendshipRequirement): RenderRequirementData? {
val icon = CobblemonItems.SOOTHE_BELL
val friendshipAmountComponent = Component.literal(friendshipRequirement.amount.toString()).green()
val tooltip = lang("ui.pokedex.requirement.friendship.tooltip", friendshipAmountComponent)
val label = lang("ui.pokedex.requirement.friendship.label")
return RenderRequirementData(icon, tooltip, label)
}
override fun visitHeldItemRequirement(heldItemRequirement: HeldItemRequirement): RenderRequirementData? {
val item = heldItemRequirement.itemCondition.items.get().first().value()
val tooltip = lang("ui.pokedex.requirement.held_item.tooltip", item.description.plainCopy().green())
return RenderRequirementData(item, tooltip)
}
override fun visitLevelRequirement(levelRequirement: LevelRequirement): RenderRequirementData? {
val minLevel = levelRequirement.minLevel
val maxLevel = levelRequirement.maxLevel
val icon = CobblemonItems.RARE_CANDY
val tooltip =
if (minLevel == maxLevel || maxLevel == Int.MAX_VALUE)
lang("ui.pokedex.requirement.level.tooltip.min", Component.literal(minLevel.toString()).green())
else
lang("ui.pokedex.requirement.level.tooltip.between", Component.literal(minLevel.toString()).green(), Component.literal(maxLevel.toString()).green())
val label = lang("ui.pokedex.requirement.level.label", minLevel)
return RenderRequirementData(icon, tooltip, label)
}
override fun visitMoonPhaseRequirement(moonPhaseRequirement: MoonPhaseRequirement): RenderRequirementData? {
val icon = Items.CLOCK
val moonPhaseComponent = moonPhaseRequirement.moonPhase.displayName().green()
val tooltip = lang("ui.pokedex.requirement.moon_phase.tooltip", moonPhaseComponent)
return RenderRequirementData(icon, tooltip)
}
override fun visitMoveSetRequirement(moveSetRequirement: MoveSetRequirement): RenderRequirementData? {
val icon = CobblemonItems.PP_MAX
val tooltip = lang("ui.pokedex.requirement.has_move.tooltip", moveSetRequirement.move.displayName.green())
return RenderRequirementData(icon, tooltip)
}
override fun visitMoveTypeRequirement(moveTypeRequirement: MoveTypeRequirement): RenderRequirementData? {
val type = ElementalTypes.get(moveTypeRequirement.type.name)
val icon = when (type) {
ElementalTypes.NORMAL -> CobblemonItems.NORMAL_GEM
ElementalTypes.FIRE -> CobblemonItems.FIRE_GEM
ElementalTypes.WATER -> CobblemonItems.WATER_GEM
ElementalTypes.GRASS -> CobblemonItems.GRASS_GEM
ElementalTypes.ELECTRIC -> CobblemonItems.ELECTRIC_GEM
ElementalTypes.ICE -> CobblemonItems.ICE_GEM
ElementalTypes.FIGHTING -> CobblemonItems.FIGHTING_GEM
ElementalTypes.POISON -> CobblemonItems.POISON_GEM
ElementalTypes.GROUND -> CobblemonItems.GROUND_GEM
ElementalTypes.FLYING -> CobblemonItems.FLYING_GEM
ElementalTypes.PSYCHIC -> CobblemonItems.PSYCHIC_GEM
ElementalTypes.BUG -> CobblemonItems.BUG_GEM
ElementalTypes.ROCK -> CobblemonItems.ROCK_GEM
ElementalTypes.GHOST -> CobblemonItems.GHOST_GEM
ElementalTypes.DRAGON -> CobblemonItems.DRAGON_GEM
ElementalTypes.DARK -> CobblemonItems.DARK_GEM
ElementalTypes.STEEL -> CobblemonItems.STEEL_GEM
ElementalTypes.FAIRY -> CobblemonItems.FAIRY_GEM
else -> CobblemonItems.NORMAL_GEM
}
val tooltip = lang("ui.pokedex.requirement.has_move_type.tooltip", moveTypeRequirement.type.displayName.green())
val label = lang("ui.pokedex.requirement.has_move_type.label")
return RenderRequirementData(icon, tooltip, label)
}
// TODO test
override fun visitOwnerHoldsItemRequirement(ownerHoldsItemRequirement: OwnerHoldsItemRequirement): RenderRequirementData? {
val item = ownerHoldsItemRequirement.itemCondition.items.get().first().value()
val tooltip = lang("ui.pokedex.requirement.owner_held_item.tooltip", item.description.plainCopy().green())
return RenderRequirementData(item, tooltip)
}
override fun visitPartyMemberRequirement(partyMemberRequirement: PartyMemberRequirement): RenderRequirementData? {
return null
}
override fun visitPokemonPropertiesRequirement(pokemonPropertiesRequirement: PokemonPropertiesRequirement): RenderRequirementData? {
return null
}
override fun visitPropertyRangeRequirement(propertyRangeRequirement: PropertyRangeRequirement): RenderRequirementData? {
return null
}
override fun visitRecoilRequirement(recoilRequirement: RecoilRequirement): RenderRequirementData? {
val icon = CobblemonItems.LIFE_ORB
val recoilComponent = Component.literal(recoilRequirement.amount.toString()).green()
val tooltip = lang("ui.pokedex.requirement.recoil.tooltip", recoilComponent)
return RenderRequirementData(icon, tooltip)
}
override fun visitStatCompareRequirement(statCompareRequirement: StatCompareRequirement): RenderRequirementData? {
val highStat = Stats.getStat(statCompareRequirement.highStat)
val lowStat = Stats.getStat(statCompareRequirement.lowStat)
val icon = when (highStat) {
Stats.HP, Stats.EVASION, Stats.ACCURACY -> CobblemonItems.HEALTH_MOCHI
Stats.ATTACK -> CobblemonItems.MUSCLE_MOCHI
Stats.DEFENCE -> CobblemonItems.RESIST_MOCHI
Stats.SPECIAL_ATTACK -> CobblemonItems.GENIUS_MOCHI
Stats.SPECIAL_DEFENCE -> CobblemonItems.CLEVER_MOCHI
Stats.SPEED -> CobblemonItems.SWIFT_MOCHI
}
val highStatComponent = highStat.displayName.plainCopy().green()
val lowStatComponent = lowStat.displayName.plainCopy().green()
val tooltip = lang("ui.pokedex.requirement.stat_compare.tooltip", highStatComponent, lowStatComponent)
return RenderRequirementData(icon, tooltip)
}
override fun visitStatEqualRequirement(statEqualRequirement: StatEqualRequirement): RenderRequirementData? {
val statOne = Stats.getStat(statEqualRequirement.statOne)
val statTwo = Stats.getStat(statEqualRequirement.statTwo)
val statOneComponent = statOne.displayName.plainCopy().green()
val statTwoComponent = statTwo.displayName.plainCopy().green()
val icon = CobblemonItems.FRESH_START_MOCHI
val tooltip = lang("ui.pokedex.requirement.stat_equal.tooltip", statOneComponent, statTwoComponent)
return RenderRequirementData(icon, tooltip)
}
override fun visitStructureRequirement(structureRequirement: StructureRequirement): RenderRequirementData? {
return null
}
override fun visitTimeRangeRequirement(timeRangeRequirement: TimeRangeRequirement): RenderRequirementData? {
val icon = Items.CLOCK
val timeRangeComponent = timeRangeRequirement.range.displayName() ?: return null
val tooltip = lang("ui.pokedex.requirement.time_range.tooltip", timeRangeComponent.green())
return RenderRequirementData(icon, tooltip)
}
override fun visitUseMoveRequirement(useMoveRequirement: UseMoveRequirement): RenderRequirementData? {
val icon = CobblemonItems.CHOICE_BAND
val tooltip = lang("ui.pokedex.requirement.use_move.tooltip", useMoveRequirement.move.displayName.green())
return RenderRequirementData(icon, tooltip)
return null
}
override fun visitWeatherRequirement(weatherRequirement: WeatherRequirement): RenderRequirementData? {
var icon: Item
var tooltip: MutableComponent
if (weatherRequirement.isThundering == true) {
icon = Items.LIGHTNING_ROD
tooltip = lang("ui.pokedex.requirement.weather.tooltip.thundering")
} else {
icon = Items.WATER_BUCKET
tooltip = lang("ui.pokedex.requirement.weather.tooltip.raining")
}
return RenderRequirementData(icon, tooltip)
}
override fun visitWorldRequirement(worldRequirement: WorldRequirement): RenderRequirementData? {
return null
}
}
@@ -0,0 +1,552 @@
/*
* 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.pokedex.widgets.evolutiontree
import com.cobblemon.mod.common.Cobblemon
import com.cobblemon.mod.common.api.gui.*
import com.cobblemon.mod.common.api.pokedex.Dexes
import com.cobblemon.mod.common.api.pokedex.PokedexEntryProgress
import com.cobblemon.mod.common.api.pokedex.entry.PokedexEntry
import com.cobblemon.mod.common.api.pokedex.entry.PokedexForm
import com.cobblemon.mod.common.api.pokemon.PokemonSpecies
import com.cobblemon.mod.common.api.pokemon.evolution.Evolution
import com.cobblemon.mod.common.api.text.add
import com.cobblemon.mod.common.api.text.bold
import com.cobblemon.mod.common.client.CobblemonClient
import com.cobblemon.mod.common.client.CobblemonResources
import com.cobblemon.mod.common.client.gui.pokedex.PokedexGUI
import com.cobblemon.mod.common.client.gui.pokedex.PokedexGUIConstants
import com.cobblemon.mod.common.client.gui.pokedex.PokedexGUIConstants.HALF_OVERLAY_WIDTH
import com.cobblemon.mod.common.client.gui.pokedex.PokedexGUIConstants.POKEMON_DESCRIPTION_HEIGHT
import com.cobblemon.mod.common.client.gui.pokedex.PokedexGUIConstants.SCROLL_SLOT_SIZE
import com.cobblemon.mod.common.client.gui.pokedex.ScaledButton
import com.cobblemon.mod.common.client.gui.pokedex.renderTooltip
import com.cobblemon.mod.common.client.gui.pokedex.widgets.PokemonSlotWidget
import com.cobblemon.mod.common.client.gui.pokedex.widgets.evolutiontree.EvolutionTreeEvolutionVisitor.RenderEvolutionData
import com.cobblemon.mod.common.client.gui.summary.widgets.SoundlessWidget
import com.cobblemon.mod.common.client.render.drawScaledText
import com.cobblemon.mod.common.client.render.renderScaledGuiItemIcon
import com.cobblemon.mod.common.pokemon.Gender
import com.cobblemon.mod.common.pokemon.RenderablePokemon
import com.cobblemon.mod.common.util.cobblemonResource
import com.cobblemon.mod.common.util.lang
import net.minecraft.client.gui.GuiGraphics
import net.minecraft.network.chat.Component
import net.minecraft.network.chat.MutableComponent
class EvolutionTreeWidget(
val parent: PokedexGUI,
val pX: Int,
val pY: Int,
) : SoundlessWidget(
pX, pY,
HALF_OVERLAY_WIDTH,
POKEMON_DESCRIPTION_HEIGHT,
lang("ui.pokedex.pokemon_info")
) {
companion object {
private val slotResource = cobblemonResource("textures/gui/pokedex/pokedex_slot.png")
private val expandResource = cobblemonResource("textures/gui/pokedex/expand.png")
private val minimizeResource = cobblemonResource("textures/gui/pokedex/minimize.png")
const val X_MARGIN = 180
const val Y_MARGIN_MINIMIZED = 135
const val Y_MARGIN_EXPANDED = 53
const val EXPANDED_HEIGHT = 125
const val HORIZONTAL_PADDING = 38
const val VERTICAL_PADDING = 2
const val TREE_FORK_LENGTH = 4
const val ICON_X_PADDING = -4.0
const val ICON_Y_PADDING = -4.0
const val MILLIS_BETWEEN_ICONS_CYCLE = 1000
const val ICON_SLOT_BACKGROUND_SIZE = 8
const val ICON_SLOT_PADDING = 4
const val ICON_SLOT_HALF_PADDING = ICON_SLOT_PADDING / 2
const val LINE_COLOR = 0xff1d6b85.toInt()
const val EXPAND_BUTTON_X_MARGIN = 127f
const val EXPAND_BUTTON_Y_MARGIN = -10.5f
const val EXPAND_BUTTON_SIZE = 20
private var previousRootPokedexEntry: PokedexEntry? = null
private var previousRootPokedexForm: PokedexForm? = null
private val evolutionVisitor = EvolutionTreeEvolutionVisitor()
}
private var rootTreeDrawingNode: TreeDrawingNode<EvolutionNode>? = null
private var treeDrawingBounds: TreeDrawingBounds? = null
private var zoomLevel: Double = 0.0
private var panningX: Double = 0.0
private var panningY: Double = 0.0
private var hoveredTooltips: List<MutableComponent>? = null
private val expandButton: ScaledButton = ScaledButton(
0f,
0f,
EXPAND_BUTTON_SIZE,
EXPAND_BUTTON_SIZE,
resource = expandResource,
clickAction = {
parent.evolutionTreeExpanded = !parent.evolutionTreeExpanded
expandButton.resource = if (parent.evolutionTreeExpanded) minimizeResource else expandResource
updatePositioning()
}
).apply { addWidget(this) }
override fun renderWidget(
guiGraphics: GuiGraphics,
mouseX: Int,
mouseY: Int,
partialTick: Float,
) {
drawScaledText(
context = guiGraphics,
font = CobblemonResources.DEFAULT_LARGE,
text = Component.translatable("cobblemon.ui.pokedex.info.evolution_tree").bold(),
x = x + 9,
y = y - 10,
shadow = true
)
expandButton.render(guiGraphics, mouseX, mouseY, partialTick)
rootTreeDrawingNode?.let {
enableScissors(guiGraphics)
renderTreeDrawingNode(guiGraphics, it, mouseX, mouseY, partialTick)
guiGraphics.disableScissor()
hoveredTooltips?.let { tooltips ->
renderTooltip(
guiGraphics,
tooltips,
mouseX,
mouseY,
partialTick,
4,
)
}
hoveredTooltips = null
}
}
fun setup(pokedexEntry: PokedexEntry?, pokedexForm: PokedexForm?) {
if (pokedexEntry == null || pokedexForm == null) return
updatePositioning()
val (rootPokedexEntry, rootPokedexForm) = Dexes.findRootDexEntryBySpeciesId(pokedexEntry.speciesId, pokedexForm.displayForm)
val rootEvolutionNode = buildEvolutionTree(rootPokedexEntry, rootPokedexForm, null)
// val isSameEntry = previousRootPokedexEntry != null && pokedexEntry?.id == previousRootPokedexEntry?.id
// val isSameForm =
// previousRootPokedexForm != null && pokedexForm?.displayForm == previousRootPokedexForm?.displayForm
// TODO: figure out how to prevent pokedex from resetting all the widgets state
// if (isSameEntry && isSameForm) {
// return
// }
previousRootPokedexEntry = pokedexEntry
previousRootPokedexForm = pokedexForm
createDrawingTree(rootEvolutionNode).also {
rootTreeDrawingNode = it
treeDrawingBounds = calculateBounds<EvolutionNode>(it)
}
zoomLevel = 0.0
panningX = 0.0
panningY = 0.0
}
fun updatePositioning() {
x = pX + X_MARGIN
y = pY + if (parent.evolutionTreeExpanded) Y_MARGIN_EXPANDED else Y_MARGIN_MINIMIZED
height = if (parent.evolutionTreeExpanded) EXPANDED_HEIGHT else POKEMON_DESCRIPTION_HEIGHT
panningX = 0.0
panningY = 0.0
expandButton.buttonX = x + EXPAND_BUTTON_X_MARGIN
expandButton.buttonY = y + EXPAND_BUTTON_Y_MARGIN
}
private fun buildEvolutionTree(
pokedexEntry: PokedexEntry,
pokedexForm: PokedexForm,
evolution: Evolution? = null
): EvolutionNode {
val species = PokemonSpecies.getByIdentifier(pokedexEntry.speciesId)!!
val formEquivalents = Dexes.getFormEquivalents(pokedexForm.displayForm)
val form = species.forms.firstOrNull { formEquivalents.contains(it.name.lowercase()) }
val parentSpecies = Dexes.findDexEntryBySpeciesId(species.resourceIdentifier)!!
val parentPokedexForm = parentSpecies.forms.first { formEquivalents.contains(it.displayForm.lowercase()) }
val aspects = evolution?.result?.aspects?.toMutableSet() ?: mutableSetOf()
form?.aspects?.let { aspects.addAll(it) }
val discoveryLevel = CobblemonClient.clientPokedexData.getHighestKnowledgeFor(pokedexEntry, pokedexForm, aspects)
val evolutions = form?.evolutions ?: species.evolutions
val drawData = evolution?.let { evolutionVisitor.visit(evolution) }
// TODO: figure out if this works for fakemon
val children = evolutions.mapNotNull { evolution ->
val speciesId = cobblemonResource(evolution.result.species!!)
val childPokedexEntry =
Dexes.findDexEntryBySpeciesId(speciesId)
if (childPokedexEntry == null) {
Cobblemon.LOGGER.warn("Dex entry not found for species: $speciesId")
return@mapNotNull null
}
val evolutionResult = evolution.result.create()
val formEquivalents = Dexes.getFormEquivalents(evolutionResult.form.name.lowercase())
val childPokedexForm = childPokedexEntry.forms.first { formEquivalents.contains(it.displayForm.lowercase()) }
return@mapNotNull buildEvolutionTree(childPokedexEntry, childPokedexForm, evolution)
}
return EvolutionNode(pokedexEntry, parentPokedexForm, aspects, discoveryLevel, children, drawData)
}
private fun renderTreeDrawingNode(
guiGraphics: GuiGraphics,
treeDrawingNode: TreeDrawingNode<EvolutionNode>,
mouseX: Int,
mouseY: Int,
delta: Float,
) {
val (treeX, treeY) = getDrawingCoordinates(treeDrawingNode)
if (treeDrawingNode.children.size == 1) {
val child = treeDrawingNode.children.first()
val (childX, _) = getDrawingCoordinates(child)
val lineStartX = treeX + SCROLL_SLOT_SIZE
val lineEndX = childX
val lineY = treeY + SCROLL_SLOT_SIZE / 2
child.value.renderData?.let { renderData ->
drawEvolutionInfo(
guiGraphics,
renderData,
lineStartX,
lineEndX,
lineY,
mouseX,
mouseY,
delta,
)
}
} else if (treeDrawingNode.children.size > 1) {
val treeForkStart = treeX + SCROLL_SLOT_SIZE
val treeForkEnd = treeX + SCROLL_SLOT_SIZE + TREE_FORK_LENGTH
val middleStart = treeY + SCROLL_SLOT_SIZE / 2
val (_, firstChildY) = getDrawingCoordinates(treeDrawingNode.children.first())
val (_, lastChildY) = getDrawingCoordinates(treeDrawingNode.children.last())
guiGraphics.hLine(
treeForkStart,
treeForkEnd,
middleStart,
LINE_COLOR,
)
guiGraphics.vLine(
treeForkEnd,
firstChildY + SCROLL_SLOT_SIZE / 2,
lastChildY + SCROLL_SLOT_SIZE / 2,
LINE_COLOR,
)
treeDrawingNode.children.forEach { child ->
val (childX, childY) = getDrawingCoordinates(child)
val lineStartX = treeForkEnd
val lineEndX = childX
val lineY = childY + SCROLL_SLOT_SIZE / 2
child.value.renderData?.let { renderData ->
drawEvolutionInfo(
guiGraphics,
renderData,
lineStartX,
lineEndX,
lineY,
mouseX,
mouseY,
delta,
)
}
}
}
treeDrawingNode.children.forEach { child ->
renderTreeDrawingNode(guiGraphics, child, mouseX, mouseY, delta)
}
val isVisible =
treeX >= x - SCROLL_SLOT_SIZE &&
treeX <= x + width &&
treeY >= y - SCROLL_SLOT_SIZE &&
treeY <= y + height
if (!isVisible) return
val evolutionNode = treeDrawingNode.value
val isSlotHovered =
isElementHovered(mouseX, mouseY, treeX, treeX + SCROLL_SLOT_SIZE, treeY, treeY + SCROLL_SLOT_SIZE)
val discoveryLevel = evolutionNode.pokedexEntryProgress
if (isSlotHovered) {
val text =
if (discoveryLevel == PokedexEntryProgress.UNREGISTERED) {
lang("ui.pokedex.unknown")
} else {
val species = PokemonSpecies.getByIdentifier(evolutionNode.pokedexEntry.speciesId)!!
val speciesComponent = species.translatedName
val formName = evolutionNode.pokedexForm.displayForm.lowercase()
val formComponent =
if (formName == "normal") null
else lang("ui.pokedex.info.form.${species}-${formName.replace("-", "")}")
formComponent?.add(" ")?.add(speciesComponent) ?: speciesComponent
}
guiGraphics.disableScissor()
renderTooltip(
context = guiGraphics,
text = text,
posX = mouseX,
posY = mouseY,
delta,
4,
)
enableScissors(guiGraphics)
}
val pokedexEntry = evolutionNode.pokedexEntry
val pokedexForm = evolutionNode.pokedexForm
val species = PokemonSpecies.getByIdentifier(evolutionNode.pokedexEntry.speciesId)!!
val encounteredForms = CobblemonClient.clientPokedexData.getEncounteredForms(pokedexEntry)
val formToRender = encounteredForms.firstOrNull { it.displayForm.equals(pokedexForm.displayForm, ignoreCase = true) }
val renderablePokemon =
if (formToRender != null) {
val seenGenders = CobblemonClient.clientPokedexData.getSeenGenders(pokedexEntry, formToRender)
val seenShinyStates = CobblemonClient.clientPokedexData.getSeenShinyStates(pokedexEntry, formToRender)
val aspectsToDraw = (pokedexEntry.displayAspects + evolutionNode.aspects).toMutableSet()
val formAspects = species.forms.firstOrNull { it.name.equals(formToRender.displayForm, ignoreCase = true) }?.aspects
if (formAspects != null) {
aspectsToDraw.addAll(formAspects)
}
if (seenGenders.contains(parent.gender)) {
aspectsToDraw.add(parent.gender.name.lowercase())
} else {
aspectsToDraw.add((seenGenders.firstOrNull() ?: Gender.GENDERLESS).name.lowercase())
}
if (parent.shiny && seenShinyStates.contains("shiny")) {
aspectsToDraw.add("shiny")
}
RenderablePokemon(species, aspectsToDraw)
} else {
null
}
PokemonSlotWidget.render(
context = guiGraphics,
x = treeX,
y = treeY,
isHovered = isSlotHovered,
species = species,
renderablePokemon = renderablePokemon,
discoveryLevel = discoveryLevel,
)
}
private fun drawEvolutionInfo(
guiGraphics: GuiGraphics,
renderData: RenderEvolutionData,
lineStartX: Int,
lineEndX: Int,
lineY: Int,
mouseX: Int,
mouseY: Int,
delta: Float,
) {
val lineXMiddle = (lineStartX + lineEndX) / 2
val iconX = (lineXMiddle + ICON_X_PADDING - ICON_SLOT_HALF_PADDING).toInt()
val iconY = (lineY + ICON_Y_PADDING - ICON_SLOT_HALF_PADDING).toInt()
val iconSize = ICON_SLOT_BACKGROUND_SIZE + ICON_SLOT_PADDING
val isVisible =
iconX >= x - iconSize &&
iconX <= x + width &&
iconY >= y - iconSize &&
iconY <= y + height
if (!isVisible) {
return
}
if (renderData.icons.isEmpty()) {
guiGraphics.hLine(
lineStartX,
lineEndX,
lineY,
LINE_COLOR,
)
} else {
guiGraphics.hLine(
lineStartX,
iconX - 1,
lineY,
LINE_COLOR,
)
guiGraphics.hLine(
iconX + iconSize,
lineEndX,
lineY,
LINE_COLOR,
)
blitk(
matrixStack = guiGraphics.pose(),
texture = slotResource,
x = iconX,
y = iconY,
width = iconSize,
height = iconSize,
)
val index = (System.currentTimeMillis() / MILLIS_BETWEEN_ICONS_CYCLE) % renderData.icons.size
val item = renderData.icons[index.toInt()]
renderScaledGuiItemIcon(
itemStack = item.defaultInstance,
x = lineXMiddle + ICON_X_PADDING,
y = lineY + ICON_Y_PADDING,
matrixStack = guiGraphics.pose(),
scale = PokedexGUIConstants.SCALE.toDouble(),
)
}
val isLineHovered = isElementHovered(mouseX, mouseY, lineStartX, lineEndX, lineY - 1, lineY + 1)
val isIconHovered = isElementHovered(
mouseX,
mouseY,
iconX.toInt(),
iconX.toInt() + iconSize,
iconY.toInt(),
iconY.toInt() + iconSize,
)
if (renderData.tooltips.isNotEmpty() &&
(isLineHovered || isIconHovered) &&
this.isHovered(mouseX.toDouble(), mouseY.toDouble())
) {
hoveredTooltips = renderData.tooltips
}
}
private fun getDrawingCoordinates(node: TreeDrawingNode<EvolutionNode>): Pair<Int, Int> {
val halfSlot = SCROLL_SLOT_SIZE / 2f
val xStep = halfSlot + HORIZONTAL_PADDING
val yStep = halfSlot + VERTICAL_PADDING
// Swaps the x and y to draw the tree horizontally
val xDislocation = (node.y - treeDrawingBounds!!.yCenter) * xStep
val yDislocation = (node.x - treeDrawingBounds!!.xCenter) * yStep
val xCenter = width / 2f - halfSlot
val yCenter = height / 2f - halfSlot
val screenX = (xCenter.toInt() + xDislocation.toInt() + panningX.toInt() + x)
val screenY = (yCenter.toInt() + yDislocation.toInt() + panningY.toInt() + y)
return screenX to screenY
}
private fun isElementHovered(
mouseX: Int,
mouseY: Int,
startX: Int,
endX: Int,
startY: Int,
endY: Int,
): Boolean {
return mouseX >= startX && mouseX <= endX && mouseY >= startY && mouseY <= endY
}
override fun mouseDragged(
mouseX: Double,
mouseY: Double,
button: Int,
deltaX: Double,
deltaY: Double
): Boolean {
panningX += deltaX
panningY += deltaY
val bounds = treeDrawingBounds ?: return super.mouseDragged(mouseX, mouseY, button, deltaX, deltaY)
val treeHeight = bounds.height.coerceAtLeast(1)
val treeWidth = bounds.width.coerceAtLeast(1)
val xStep = HORIZONTAL_PADDING + SCROLL_SLOT_SIZE / 2.0
val yStep = VERTICAL_PADDING + SCROLL_SLOT_SIZE / 2.0
val minPanningX = (treeHeight - 1) * -xStep / 2.0 - (width + SCROLL_SLOT_SIZE) / 2.0
val maxPanningX = (treeHeight - 1) * xStep / 2.0 + (width + SCROLL_SLOT_SIZE) / 2.0
val divideBy = if (treeWidth % 2 == 0) 4.0 else 2.0
val minPanningY = (treeWidth - 1) * -yStep / 2.0 - height / 2.0 + SCROLL_SLOT_SIZE / divideBy
val maxPanningY = (treeWidth - 1) * yStep / 2.0 + height / 2.0 - SCROLL_SLOT_SIZE / divideBy
panningX = panningX.coerceIn(minPanningX, maxPanningX)
panningY = panningY.coerceIn(minPanningY, maxPanningY)
return super.mouseDragged(mouseX, mouseY, button, deltaX, deltaY)
}
fun isHovered(mouseX: Double, mouseY: Double): Boolean {
return mouseX.toInt() in x..(x + width) && mouseY.toInt() in y..(y + height)
}
fun enableScissors(guiGraphics: GuiGraphics) {
guiGraphics.enableScissor(x + 1, y, x + width - 1, y + height)
}
private class EvolutionNode(
val pokedexEntry: PokedexEntry,
val pokedexForm: PokedexForm,
val aspects: Set<String>,
val pokedexEntryProgress: PokedexEntryProgress,
override val children: List<EvolutionNode>,
val renderData: RenderEvolutionData?,
) : TreeNode<EvolutionNode>
}
@@ -8,6 +8,7 @@
package com.cobblemon.mod.common.client.gui.summary
import com.cobblemon.mod.common.Cobblemon
import com.cobblemon.mod.common.CobblemonItems
import com.cobblemon.mod.common.CobblemonNetwork.sendToServer
import com.cobblemon.mod.common.CobblemonSounds
@@ -20,8 +21,14 @@ import com.cobblemon.mod.common.api.text.bold
import com.cobblemon.mod.common.api.text.text
import com.cobblemon.mod.common.client.CobblemonClient
import com.cobblemon.mod.common.client.CobblemonResources
import com.cobblemon.mod.common.client.gui.*
import com.cobblemon.mod.common.client.gui.summary.widgets.*
import com.cobblemon.mod.common.client.gui.CobblemonRenderable
import com.cobblemon.mod.common.client.gui.ExitButton
import com.cobblemon.mod.common.client.gui.TypeIcon
import com.cobblemon.mod.common.client.gui.summary.widgets.EvolutionSelectScreen
import com.cobblemon.mod.common.client.gui.summary.widgets.MarkingsWidget
import com.cobblemon.mod.common.client.gui.summary.widgets.ModelWidget
import com.cobblemon.mod.common.client.gui.summary.widgets.NicknameEntryWidget
import com.cobblemon.mod.common.client.gui.summary.widgets.PartyWidget
import com.cobblemon.mod.common.client.gui.summary.widgets.screens.SummaryTab
import com.cobblemon.mod.common.client.gui.summary.widgets.screens.info.InfoWidget
import com.cobblemon.mod.common.client.gui.summary.widgets.screens.marks.MarksWidget
@@ -30,6 +37,7 @@ import com.cobblemon.mod.common.client.gui.summary.widgets.screens.moves.MovesWi
import com.cobblemon.mod.common.client.gui.summary.widgets.screens.stats.StatWidget
import com.cobblemon.mod.common.client.keybind.keybinds.SummaryBinding
import com.cobblemon.mod.common.client.render.drawScaledText
import com.cobblemon.mod.common.client.render.models.blockbench.repository.VaryingModelRepository
import com.cobblemon.mod.common.net.messages.server.pokemon.update.SetItemHiddenPacket
import com.cobblemon.mod.common.net.messages.server.storage.party.MovePartyPokemonPacket
import com.cobblemon.mod.common.net.messages.server.storage.party.SwapPartyPokemonPacket
@@ -707,9 +715,27 @@ class Summary private constructor(party: Collection<Pokemon?>, private val edita
) {
this.focused = null
}
handleProfileDebugKeys(keyCode, selectedPokemon.species.resourceIdentifier, modelWidget.state)
if (Cobblemon.config.enableDebugKeys) {
val model = VaryingModelRepository.getPoser(selectedPokemon.species.resourceIdentifier, modelWidget.state)
if (keyCode == InputConstants.KEY_UP) {
model.profileTranslation = model.profileTranslation.add(0.0, -0.01, 0.0)
}
if (keyCode == InputConstants.KEY_DOWN) {
model.profileTranslation = model.profileTranslation.add(0.0, 0.01, 0.0)
}
if (keyCode == InputConstants.KEY_LEFT) {
model.profileTranslation = model.profileTranslation.add(-0.01, 0.0, 0.0)
}
if (keyCode == InputConstants.KEY_RIGHT) {
model.profileTranslation = model.profileTranslation.add(0.01, 0.0, 0.0)
}
if (keyCode == InputConstants.KEY_EQUALS) {
model.profileScale += 0.01F
}
if (keyCode == InputConstants.KEY_MINUS) {
model.profileScale -= 0.01F
}
}
return super.keyPressed(keyCode, scanCode, modifiers)
}
@@ -718,8 +744,13 @@ class Summary private constructor(party: Collection<Pokemon?>, private val edita
}
override fun onClose() {
logProfileTranslations(selectedPokemon.species.resourceIdentifier, modelWidget.state)
if (Cobblemon.config.enableDebugKeys) {
val model = VaryingModelRepository.getPoser(selectedPokemon.species.resourceIdentifier, modelWidget.state)
Minecraft.getInstance().player?.sendSystemMessage(Component.literal("Profile Translation: ${model.profileTranslation}"))
Minecraft.getInstance().player?.sendSystemMessage(Component.literal("Profile Scale: ${model.profileScale}"))
Cobblemon.LOGGER.info("override var profileTranslation = Vec3d(${model.profileTranslation.x}, ${model.profileTranslation.y}, ${model.profileTranslation.z})")
Cobblemon.LOGGER.info("override var profileScale = ${model.profileScale}F")
}
super.onClose()
}
}
@@ -11,7 +11,6 @@ package com.cobblemon.mod.common.client.gui.summary.widgets
import com.bedrockk.molang.runtime.value.DoubleValue
import com.cobblemon.mod.common.Cobblemon
import com.cobblemon.mod.common.api.tags.CobblemonItemTags
import com.cobblemon.mod.common.client.gui.ProfileTransformType
import com.cobblemon.mod.common.client.gui.drawProfilePokemon
import com.cobblemon.mod.common.client.gui.calculateHeadYawAndPitch
import com.cobblemon.mod.common.client.render.models.blockbench.FloatingState
@@ -117,8 +116,7 @@ class ModelWidget(
partialTicks = partialTicks,
headYaw = currentYawAndPitch.first,
headPitch = currentYawAndPitch.second,
blockLight = blockLight,
profileTransformType = ProfileTransformType.SUMMARY,
blockLight = blockLight
)
heldItemRenderer.renderOnModel(
@@ -120,7 +120,7 @@ class TMMachineScreen(containerMenu: TMMachineMenu, val inventory: Inventory, ti
fun getLogoResource(langCode: String?): ResourceLocation =
logoResourceMap.entries.find { it.value.contains(langCode?.substringBefore("_")) }?.key ?: logo
}
var selectedTM: TechnicalMachine? = null
var heldStackMove: MoveTemplate? = null
var tmList: SettableObservable<MutableList<TechnicalMachine>> = SettableObservable(mutableListOf())
var output: ItemStack? = null
@@ -159,8 +159,6 @@ class TMMachineScreen(containerMenu: TMMachineMenu, val inventory: Inventory, ti
var oldIngredientItems: Array<Item> = arrayOf(Items.AIR, Items.AIR, Items.AIR)
var oldResultTmSlotItem: Item = Items.AIR
var moveInfoTM: TechnicalMachine? = null
override fun init() {
imageWidth = WIDTH
imageHeight = HEIGHT
@@ -173,8 +171,6 @@ class TMMachineScreen(containerMenu: TMMachineMenu, val inventory: Inventory, ti
logoPosY = topPos + 1
scanPosY = topPos + 1
menu.onSelectedTMUpdate = { updateSelectedTM(it) }
partySlotList.clear()
CobblemonClient.storage.party.forEachIndexed { index, pokemon ->
partySlotList.add(TMPartySlotWidget(
@@ -230,14 +226,7 @@ class TMMachineScreen(containerMenu: TMMachineMenu, val inventory: Inventory, ti
pX = leftPos + 4,
pY = topPos + 29,
tmList,
setTM = { tm, clicked ->
if (clicked) {
if (tm != menu.currentlySelectedTM) SetActiveTMPacket(tm).sendToServer()
setScreenFromMode(TM_BURN_MODE)
} else {
updateMoveInformation(tm)
}
}
setTM = { tm, clicked -> setSelectedTM(tm, clicked) }
)
if (!children().contains(movesScrollingList)) addRenderableWidget(movesScrollingList)
@@ -263,21 +252,24 @@ class TMMachineScreen(containerMenu: TMMachineMenu, val inventory: Inventory, ti
selectedMoveButton = MoveSlotButton(
leftPos + 6,
topPos + 6,
move = menu.currentlySelectedTM?.moveName,
pp = menu.currentlySelectedTM?.moveName?.pp ?: 0,
move = selectedTM?.moveName,
pp = selectedTM?.moveName?.pp ?: 0,
ppAsFraction = false
) {
if ((it as MoveSlotButton).enabled) {
if (::movesScrollingList.isInitialized && movesScrollingList.children().isEmpty()) setMoveList()
playSound(CobblemonSounds.GUI_CLICK)
setScreenFromMode(MOVE_SELECT_MODE)
// Clear active TM
CobblemonNetwork.sendToServer(SetActiveTMPacket(null))
}
}
if (!children().contains(selectedMoveButton)) addRenderableWidget(selectedMoveButton)
startButton = StartButton(leftPos + 5F, topPos + 35F) {
if (!(it as StartButton).disabled) {
menu.currentlySelectedTM?.let {
selectedTM?.let {
val burnActive = menu.containerData?.get(TMMachineBlockEntity.BURN_ACTIVE_INDEX) ?: 0
CobblemonNetwork.sendToServer(SetTMMachineContainerDataPacket(
TMMachineBlockEntity.BURN_ACTIVE_INDEX,
@@ -292,14 +284,17 @@ class TMMachineScreen(containerMenu: TMMachineMenu, val inventory: Inventory, ti
))
}*/
//CobblemonNetwork.sendToServer(SetActiveTMPacket(it))
CobblemonNetwork.sendToServer(SetActiveTMPacket(it))
if (burnActive != 1) playSound(CobblemonSounds.TM_MACHINE_START)
inventory.setChanged()
menu.broadcastChanges()
}
}
}
if (!children().contains(startButton)) addRenderableWidget(startButton)
setScreenFromMode(mode)
initScreen = false
updateSlotItemMemory()
}
@@ -311,7 +306,7 @@ class TMMachineScreen(containerMenu: TMMachineMenu, val inventory: Inventory, ti
if (scanPosY + 1 >= (topPos + SCREEN_SAVER_HEIGHT) * 2) scanPosY = 0
if (mode == TM_BURN_MODE) {
menu.currentlySelectedTM?.let { tm ->
selectedTM?.let { tm ->
val resultStack = menu.inventory!!.getItem(TMMachineMenu.RESULT_SLOT)
val craftedTmStack = ItemStack(CobblemonItems.TECHNICAL_MACHINE)
.also { TMMoveComponent.setTMMove(it, tm.moveName) }
@@ -344,7 +339,7 @@ class TMMachineScreen(containerMenu: TMMachineMenu, val inventory: Inventory, ti
}
if (::selectedMoveButton.isInitialized) {
selectedMoveButton.enabled = (heldStackMove == null || heldStackMove == menu.currentlySelectedTM?.moveName)
selectedMoveButton.enabled = !isBurnActive() && (heldStackMove == null || heldStackMove == selectedTM?.moveName)
}
if (isBurnActive()) {
@@ -355,6 +350,9 @@ class TMMachineScreen(containerMenu: TMMachineMenu, val inventory: Inventory, ti
}
}
}
} else {
// Check if screen should be switched upon opening UI
if (!initScreen) loadBurnScreenData()
}
if (heldMoveItemChanged) {
@@ -402,6 +400,32 @@ class TMMachineScreen(containerMenu: TMMachineMenu, val inventory: Inventory, ti
return wasScreenSaverActive
}
private fun loadBurnScreenData() {
var tm: TechnicalMachine? = null
val blockPos = menu.containerData?.let {
val x = it.get(TMMachineBlockEntity.POSITION_X_INDEX)
val y = it.get(TMMachineBlockEntity.POSITION_Y_INDEX)
val z = it.get(TMMachineBlockEntity.POSITION_Z_INDEX)
BlockPos(x, y, z)
}
inventory.player.level().getBlockEntity(blockPos)?.let { blockEntity ->
if (blockEntity is TMMachineBlockEntity) {
Moves.getByName(blockEntity.activeMove)?.let {
tm = TechnicalMachines.moveToTM[it]
}
}
}
// If burn currently in progress or if active TM set, set to burn screen
if (isBurnActive() || tm != null) {
setSelectedTM(tm, true)
}
initScreen = true
}
private fun isBurnActive(): Boolean = (menu.containerData?.get(TMMachineBlockEntity.BURN_ACTIVE_INDEX) ?: 0) == 1
private fun setScreenFromMode(screen: Int) {
@@ -443,6 +467,7 @@ class TMMachineScreen(containerMenu: TMMachineMenu, val inventory: Inventory, ti
private fun toggleTypeSelect(isVisible: Boolean) {
if (isVisible) {
setSelectedTM(null, false)
if (::moveSearchWidget.isInitialized) moveSearchWidget.value = ""
if (selectedPokemon != null) selectedPokemon = null
sortType = null
@@ -480,6 +505,7 @@ class TMMachineScreen(containerMenu: TMMachineMenu, val inventory: Inventory, ti
}
private fun toggleTMBurn(isVisible: Boolean) {
if (!isVisible) setSelectedTM(null, false)
if (::selectedMoveButton.isInitialized) selectedMoveButton.visible = isVisible
if (::startButton.isInitialized) startButton.visible = isVisible
}
@@ -490,40 +516,35 @@ class TMMachineScreen(containerMenu: TMMachineMenu, val inventory: Inventory, ti
return if (learnableMoves.contains(move)) TMPartySlotWidget.CAN_LEARN else TMPartySlotWidget.CANNOT_LEARN
}
fun updateSelectedTM(tm: TechnicalMachine?) {
if (!initScreen) {
initScreen = true
tm?.let {
setScreenFromMode(TM_BURN_MODE)
sortType = ElementalTypes.get(tm.type)
setMoveList()
}
fun setSelectedTM(tm: TechnicalMachine?, clicked: Boolean) {
if (selectedTM != tm) {
selectedTM = tm
updatePartySlotStatus(tm?.moveName)
}
if (mode == TM_BURN_MODE) updateMoveInformation(tm)
tm?.let {
if (::selectedMoveButton.isInitialized) {
selectedMoveButton.apply {
move = it.moveName
pp = it.moveName.pp
}
}
if (::movesScrollingList.isInitialized) {
movesScrollingList.setSlotHighlighted(if (clicked) null else selectedTM?.id)
}
}
fun updateMoveInformation(tm: TechnicalMachine?) {
moveInfoTM = tm
if (::moveDescriptionWidget.isInitialized) {
val selectedDescription = tm?.moveName?.description?.string
val selectedDescription = selectedTM?.moveName?.description?.string
moveDescriptionWidget.setText(
if (selectedDescription != null) listOf(selectedDescription) else emptyList()
)
}
if (::movesScrollingList.isInitialized) {
movesScrollingList.setSlotHighlighted(tm?.id)
if (clicked) {
CobblemonNetwork.sendToServer(SetActiveTMPacket(tm))
selectedTM?.let {
if (::selectedMoveButton.isInitialized) {
selectedMoveButton.apply {
move = it.moveName
pp = it.moveName.pp
}
setScreenFromMode(TM_BURN_MODE)
}
}
}
}
@@ -536,7 +557,7 @@ class TMMachineScreen(containerMenu: TMMachineMenu, val inventory: Inventory, ti
}
fun renderDiscTypeOverlay(poseStack: PoseStack, isDiscRotating: Boolean, alpha: Float = 1F) {
menu.currentlySelectedTM?.let {
selectedTM?.let {
val primaryRgb = it.moveName.elementalType.primaryColor.toRGB()
val secondaryRgb = it.moveName.elementalType.secondaryColor.toRGB()
blitk(
@@ -685,7 +706,7 @@ class TMMachineScreen(containerMenu: TMMachineMenu, val inventory: Inventory, ti
}
fun renderMoveInfo(context: GuiGraphics, mouseX: Int, mouseY: Int) {
val moveTemplate = moveInfoTM?.moveName
val moveTemplate = selectedTM?.moveName
blitk(
matrixStack = context.pose(),
@@ -1036,7 +1057,7 @@ class TMMachineScreen(containerMenu: TMMachineMenu, val inventory: Inventory, ti
movesScrollingList.setDisabled(true, TechnicalMachines.moveToTM[heldStackMove])
if (mode == MOVE_SELECT_MODE) {
val heldStackTm = TechnicalMachines.moveToTM[heldStackMove]
updateMoveInformation(if (tmList.get().contains(heldStackTm)) heldStackTm else null)
setSelectedTM(if (tmList.get().contains(heldStackTm)) heldStackTm else null, false)
// Scroll to move if moves list contains held TM move
if (tmList.get().contains(heldStackTm)) {
@@ -1056,8 +1077,8 @@ class TMMachineScreen(containerMenu: TMMachineMenu, val inventory: Inventory, ti
heldStackMove = null
// Reset selected move on move select screen
if (mode == MOVE_SELECT_MODE) updateMoveInformation(null)
updatePartySlotStatus(menu.currentlySelectedTM?.moveName)
if (mode == MOVE_SELECT_MODE) setSelectedTM(null, false)
updatePartySlotStatus(selectedTM?.moveName)
if (::movesScrollingList.isInitialized) {
movesScrollingList.setDisabled(false)
@@ -1134,7 +1155,7 @@ class TMMachineScreen(containerMenu: TMMachineMenu, val inventory: Inventory, ti
if (isInventoryKeyPressed(minecraft, keyCode, scanCode)) {
if (searchFocused) { return true }
else {
onClose()
Minecraft.getInstance().setScreen(null)
return true
}
}
@@ -1145,7 +1166,7 @@ class TMMachineScreen(containerMenu: TMMachineMenu, val inventory: Inventory, ti
this.focused = null
return true
} else {
onClose()
Minecraft.getInstance().setScreen(null)
return true
}
}
@@ -19,6 +19,7 @@ import net.minecraft.world.level.block.Block
object SetActiveTMPacketHandler : ServerNetworkPacketHandler<SetActiveTMPacket> {
override fun handle(packet: SetActiveTMPacket, server: MinecraftServer, player: ServerPlayer) {
val menu = player.containerMenu as? TMMachineMenu ?: return
val inventory = menu.inventory ?: return
val tmData = Cobblemon.playerDataManager.getTMData(player)
if (packet.tm != null && (!packet.tm.isPassivelyObtained() && packet.tm.id !in tmData.learnedTMs)) {
@@ -29,17 +30,9 @@ object SetActiveTMPacketHandler : ServerNetworkPacketHandler<SetActiveTMPacket>
blockEntity.activeMove = packet.tm?.moveName?.name ?: ""
blockEntity.setChanged()
player.level().sendBlockUpdated(blockEntity.blockPos, blockEntity.blockState, blockEntity.blockState, Block.UPDATE_CLIENTS)
blockEntity.burnActive = false
blockEntity.burnProgress = 0
player.level().players().forEach { thePlayer -> //Update all players with matching menu/blockentity
val tmmMenu = thePlayer.containerMenu as? TMMachineMenu ?: return@forEach
if (tmmMenu.tmMachineEntity == blockEntity) {
tmmMenu.currentlySelectedTM = packet.tm
tmmMenu.broadcastChanges()
}
}
}
inventory.setChanged()
menu.broadcastChanges()
}
}
@@ -1,21 +0,0 @@
/*
* 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.net.gui
import com.cobblemon.mod.common.api.net.ClientNetworkPacketHandler
import com.cobblemon.mod.common.block.tmmachine.TMMachineMenu
import com.cobblemon.mod.common.net.messages.client.ui.SynchronizeActiveTMPacket
import net.minecraft.client.Minecraft
object SynchronizeActiveTMHandler: ClientNetworkPacketHandler<SynchronizeActiveTMPacket> {
override fun handle(packet: SynchronizeActiveTMPacket, client: Minecraft) {
val tmmMenu = client.player?.containerMenu as? TMMachineMenu ?: return
tmmMenu.clientSetSelectedTM(packet.tm)
}
}
@@ -18,23 +18,17 @@ import com.mojang.blaze3d.systems.RenderSystem
import com.mojang.blaze3d.vertex.PoseStack
import com.mojang.blaze3d.vertex.VertexConsumer
import com.mojang.math.Axis
import net.minecraft.Util
import net.minecraft.client.Minecraft
import net.minecraft.client.gui.Font
import net.minecraft.client.gui.GuiGraphics
import net.minecraft.client.renderer.MultiBufferSource
import net.minecraft.client.renderer.RenderType
import net.minecraft.client.renderer.texture.OverlayTexture
import net.minecraft.client.renderer.texture.TextureAtlas
import net.minecraft.network.chat.Component
import net.minecraft.network.chat.MutableComponent
import net.minecraft.resources.ResourceLocation
import net.minecraft.util.FormattedCharSequence
import net.minecraft.util.Mth
import net.minecraft.world.item.ItemDisplayContext
import net.minecraft.world.item.ItemStack
import kotlin.math.cos
import kotlin.math.sin
fun renderScaledGuiItemIcon(itemStack: ItemStack, x: Double, y: Double, scale: Double = 1.0, zTranslation: Float = 100.0F, matrixStack: PoseStack? = null) {
val itemRenderer = Minecraft.getInstance().itemRenderer
@@ -103,55 +97,6 @@ fun getDepletableRedGreen(
return r.toFloat() to g.toFloat()
}
fun drawScrollingText(
context: GuiGraphics,
font: Font,
text: Component,
minX: Int,
minY: Int,
maxX: Int,
maxY: Int,
colour: Int,
minScrollVelocity: Double? = 10.0
) {
val textWidth = font.width(text)
val fittedMaxX = if (textWidth <= maxX - minX) minX + textWidth else maxX
renderScrollingString(context, font, text, minX, minY, fittedMaxX, maxY, colour, minScrollVelocity)
}
/** Copied from [net.minecraft.client.gui.components.AbstractWidget.renderScrollingString] **/
fun renderScrollingString(
context: GuiGraphics,
font: Font,
text: Component,
minX: Int,
minY: Int,
maxX: Int,
maxY: Int,
colour: Int,
minScrollVelocity: Double? = 10.0
) {
val textWidth = font.width(text)
val centerY = (minY + maxY - 9) / 2 + 1
val boxWidth = maxX - minX
if (textWidth <= boxWidth) {
val centerX = Mth.clamp((minX + maxX) / 2, minX + textWidth / 2, maxX - textWidth / 2)
context.drawCenteredString(font, text, centerX, centerY, colour)
return
}
val overflow = textWidth - boxWidth
var period = (overflow * 0.5).coerceAtLeast(3.0)
if (minScrollVelocity != null) {
period = period.coerceAtMost(2 * overflow / minScrollVelocity)
}
val time = Util.getMillis() / 1000.0
val easedProgress = sin((Math.PI / 2) * cos(2 * Math.PI * time / period)) / 2.0 + 0.5
val offset = Mth.lerp(easedProgress, 0.0, overflow.toDouble())
context.enableScissor(minX, minY, maxX, maxY)
context.drawString(font, text, minX - offset.toInt(), centerY, colour)
context.disableScissor()
}
fun drawScaledText(
context: GuiGraphics,
@@ -15,7 +15,6 @@ import com.cobblemon.mod.common.util.cobblemonResource
import com.mojang.blaze3d.vertex.PoseStack
import com.mojang.blaze3d.vertex.VertexConsumer
import com.mojang.math.Axis
import net.minecraft.client.Minecraft
import net.minecraft.client.renderer.LevelRenderer
import net.minecraft.client.renderer.MultiBufferSource
import net.minecraft.client.renderer.RenderType
@@ -40,13 +39,13 @@ class DiscShelfBlockEntityRenderer(ctx: BlockEntityRendererProvider.Context) :
private val leftMargin = 1f
private val rightMargin = 1f
private val topMargin = 1f
private val bottomMargin = 1f
private val interRowSpacing = 0f
private val tmOverlayDepthOffset = -0.0002f
private val slotBrightnessMultiplier = 0.65f
private val tmBaseTexture = cobblemonResource("textures/block/disc_shelf/technical_machine_base.png")
private val tmOverlayTexture = cobblemonResource("textures/block/disc_shelf/technical_machine_overlay.png")
private val musicDiscUnknownTexture = cobblemonResource("textures/block/disc_shelf/music_disc_unknown.png")
override fun render(
entity: DiscShelfBlockEntity,
@@ -78,6 +77,7 @@ class DiscShelfBlockEntityRenderer(ctx: BlockEntityRendererProvider.Context) :
val slotWidth = slotWidthPixels / textureSize
val slotHeight = slotHeightPixels / textureSize
val verticalSpacing = (slotHeightPixels + interRowSpacing) / textureSize
val totalHeight = slotHeight * 7 + interRowSpacing * 6 / textureSize
val startY = topMargin / textureSize
for ((index, item) in entity.items.withIndex()) {
@@ -188,13 +188,6 @@ class DiscShelfBlockEntityRenderer(ctx: BlockEntityRendererProvider.Context) :
private fun getItemTexture(itemStack: ItemStack): ResourceLocation {
val id = BuiltInRegistries.ITEM.getKey(itemStack.item)
val resource = cobblemonResource("textures/block/disc_shelf/${id.path}.png")
val resourceManager = Minecraft.getInstance().resourceManager
if (resourceManager.getResource(resource).isEmpty) {
return musicDiscUnknownTexture
}
return resource
return cobblemonResource("textures/block/disc_shelf/${id.path}.png")
}
}
@@ -72,8 +72,7 @@ object MountedCameraRenderer {
val rollable = vehicle as OrientationControllable
val vehicleController = rollable.getOrientationController()
val state = FloatingState().also { it.currentAspects = vehicle.pokemon.aspects }
val model = getPoser(vehicle.pokemon.species.resourceIdentifier, state)
val model = getPoser(vehicle.pokemon.species.resourceIdentifier, FloatingState())
val locatorName = delegate.getSeatLocator(driver)
val locator = delegate.locatorStates[locatorName] ?: return null
@@ -34,6 +34,7 @@ import com.cobblemon.mod.common.client.render.models.blockbench.quirk.ModelQuirk
import com.cobblemon.mod.common.client.render.models.blockbench.quirk.SimpleQuirk
import com.cobblemon.mod.common.client.render.models.blockbench.repository.RenderContext
import com.cobblemon.mod.common.client.render.models.blockbench.wavefunction.WaveFunction
import com.cobblemon.mod.common.client.util.exists
import com.cobblemon.mod.common.entity.PosableEntity
import com.cobblemon.mod.common.entity.PoseType
import com.cobblemon.mod.common.entity.generic.GenericBedrockEntity
@@ -133,11 +134,6 @@ open class PosableModel(@Transient override val rootPart: Bone) : ModelFrame {
*/
open var profileTranslation = Vec3(0.0, 0.0, 0.0)
open var profilePokedexScale: Float? = null
open var profilePokedexTranslation: Vec3? = null
open var profileSummaryScale: Float? = null
open var profileSummaryTranslation: Vec3? = null
var red = 1F
var green = 1F
var blue = 1F
@@ -255,7 +251,7 @@ open class PosableModel(@Transient override val rootPart: Bone) : ModelFrame {
}
fun setLayerContext(buffer: MultiBufferSource, state: PosableState, layers: Iterable<ModelLayer>) {
currentLayers = layers.sortedBy { it.translucent }
currentLayers = layers
bufferProvider = buffer
currentState = state
}
@@ -0,0 +1,85 @@
/*
* 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.render.models.blockbench.pokemon.gen1
import com.cobblemon.mod.common.client.render.models.blockbench.PosableState
import com.cobblemon.mod.common.client.render.models.blockbench.frame.BipedFrame
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.CryProvider
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.PokemonPosableModel
import com.cobblemon.mod.common.client.render.models.blockbench.pose.CobblemonPose
import com.cobblemon.mod.common.entity.PoseType
import com.cobblemon.mod.common.entity.PoseType.Companion.MOVING_POSES
import com.cobblemon.mod.common.entity.PoseType.Companion.STATIONARY_POSES
import com.cobblemon.mod.common.entity.PoseType.Companion.UI_POSES
import com.cobblemon.mod.common.util.isBattling
import net.minecraft.client.model.geom.ModelPart
import net.minecraft.world.phys.Vec3
class ChanseyModel(root: ModelPart) : PokemonPosableModel(root), BipedFrame {
override val rootPart = root.registerChildWithAllChildren("chansey")
override val leftLeg = getPart("left_foot")
override val rightLeg = getPart("right_foot")
override var portraitScale = 1.5F
override var portraitTranslation = Vec3(-0.35, 0.3, 0.0)
override var profileScale = 0.8F
override var profileTranslation = Vec3(0.0, 0.55, 0.0)
lateinit var standing: CobblemonPose
lateinit var walk: CobblemonPose
lateinit var sleep: CobblemonPose
lateinit var battleIdle: CobblemonPose
override val cryAnimation = CryProvider { bedrockStateful("chansey", "cry") }
override fun registerPoses() {
val blink = quirk { bedrockStateful("chansey", "blink") }
sleep = registerPose(
poseName = "sleep",
poseType = PoseType.SLEEP,
animations = arrayOf(
bedrock("chansey", "sleep")
)
)
standing = registerPose(
poseName = "standing",
poseTypes = STATIONARY_POSES + UI_POSES,
condition = { !it.isBattling },
transformTicks = 10,
animations = arrayOf(
bedrock("chansey", "ground_idle")
)
)
walk = registerPose(
poseName = "walk",
poseTypes = MOVING_POSES,
transformTicks = 10,
quirks = arrayOf(blink),
animations = arrayOf(
bedrock("chansey", "ground_walk")
)
)
battleIdle = registerPose(
poseName = "battle_idle",
poseTypes = PoseType.STATIONARY_POSES,
condition = { it.isBattling },
transformTicks = 10,
animations = arrayOf(
bedrock("chansey", "battle_idle")
)
)
}
override fun getFaintAnimation(state: PosableState) = bedrockStateful("chansey", "faint")
}
@@ -0,0 +1,74 @@
/*
* 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.render.models.blockbench.pokemon.gen1
import com.cobblemon.mod.common.client.render.models.blockbench.PosableState
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.CryProvider
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.PokemonPosableModel
import com.cobblemon.mod.common.client.render.models.blockbench.pose.CobblemonPose
import com.cobblemon.mod.common.entity.PoseType
import com.cobblemon.mod.common.entity.PoseType.Companion.MOVING_POSES
import com.cobblemon.mod.common.entity.PoseType.Companion.STATIONARY_POSES
import com.cobblemon.mod.common.entity.PoseType.Companion.UI_POSES
import com.cobblemon.mod.common.util.isBattling
import net.minecraft.client.model.geom.ModelPart
import net.minecraft.world.phys.Vec3
class DiglettAlolanModel(root: ModelPart) : PokemonPosableModel(root) {
override val rootPart = root.registerChildWithAllChildren("diglett_alolan")
override var portraitScale = 1.8F
override var portraitTranslation = Vec3(-0.06, -0.86, 0.0)
override var profileScale = 0.9F
override var profileTranslation = Vec3(0.0, 0.32, 0.0)
lateinit var stand: CobblemonPose
lateinit var walk: CobblemonPose
lateinit var battleidle: CobblemonPose
lateinit var sleep: CobblemonPose
override val cryAnimation = CryProvider { bedrockStateful("diglett_alolan", "cry") }
override fun registerPoses() {
val blink = quirk { bedrockStateful("diglett_alolan", "blink")}
val quirk = quirk { bedrockStateful("diglett_alolan", "quirk_idle")}
sleep = registerPose(
poseName = "sleep",
poseType = PoseType.SLEEP,
animations = arrayOf(bedrock("diglett_alolan", "sleep"))
)
stand = registerPose(
poseName = "stand",
poseTypes = STATIONARY_POSES + UI_POSES,
condition = { !it.isBattling },
quirks = arrayOf(blink,quirk),
animations = arrayOf(bedrock("diglett_alolan", "ground_idle"))
)
walk = registerPose(
poseName = "walk",
poseTypes = MOVING_POSES,
quirks = arrayOf(blink),
animations = arrayOf(bedrock("diglett_alolan", "ground_idle"))
)
battleidle = registerPose(
poseName = "battleidle",
poseTypes = STATIONARY_POSES,
condition = { it.isBattling },
quirks = arrayOf(blink),
animations = arrayOf(bedrock("diglett_alolan", "battle_idle"))
)
}
override fun getFaintAnimation(state: PosableState) = bedrockStateful("diglett_alolan", "faint")
}
@@ -0,0 +1,71 @@
/*
* 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.render.models.blockbench.pokemon.gen1
import com.cobblemon.mod.common.client.render.models.blockbench.PosableState
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.CryProvider
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.PokemonPosableModel
import com.cobblemon.mod.common.client.render.models.blockbench.pose.CobblemonPose
import com.cobblemon.mod.common.entity.PoseType
import com.cobblemon.mod.common.entity.PoseType.Companion.MOVING_POSES
import com.cobblemon.mod.common.entity.PoseType.Companion.STATIONARY_POSES
import com.cobblemon.mod.common.entity.PoseType.Companion.UI_POSES
import net.minecraft.client.model.geom.ModelPart
import net.minecraft.world.phys.Vec3
class DiglettModel(root: ModelPart) : PokemonPosableModel(root) {
override val rootPart = root.registerChildWithAllChildren("diglett")
override var portraitScale = 1.8F
override var portraitTranslation = Vec3(-0.06, -0.86, 0.0)
override var profileScale = 0.9F
override var profileTranslation = Vec3(0.0, 0.32, 0.0)
lateinit var stand: CobblemonPose
lateinit var walk: CobblemonPose
lateinit var battleidle: CobblemonPose
lateinit var sleep: CobblemonPose
override val cryAnimation = CryProvider { bedrockStateful("diglett", "cry") }
override fun registerPoses() {
val blink = quirk { bedrockStateful("diglett", "blink")}
val quirk = quirk { bedrockStateful("diglett", "quirk_idle")}
sleep = registerPose(
poseName = "sleep",
poseType = PoseType.SLEEP,
animations = arrayOf(bedrock("diglett", "sleep"))
)
stand = registerPose(
poseName = "stand",
poseTypes = STATIONARY_POSES + UI_POSES,
quirks = arrayOf(blink, quirk),
animations = arrayOf(bedrock("diglett", "ground_idle"))
)
walk = registerPose(
poseName = "walk",
poseTypes = MOVING_POSES,
quirks = arrayOf(blink),
animations = arrayOf(bedrock("diglett", "ground_walk"))
)
battleidle = registerPose(
poseName = "battleidle",
poseTypes = STATIONARY_POSES,
quirks = arrayOf(blink, quirk),
animations = arrayOf(bedrock("diglett", "battle_idle"))
)
}
override fun getFaintAnimation(state: PosableState) = bedrockStateful("diglett", "faint")
}
@@ -0,0 +1,79 @@
/*
* 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.render.models.blockbench.pokemon.gen1
import com.cobblemon.mod.common.client.render.models.blockbench.PosableState
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.CryProvider
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.PokemonPosableModel
import com.cobblemon.mod.common.client.render.models.blockbench.pose.CobblemonPose
import com.cobblemon.mod.common.entity.PoseType
import com.cobblemon.mod.common.entity.PoseType.Companion.MOVING_POSES
import com.cobblemon.mod.common.entity.PoseType.Companion.STATIONARY_POSES
import com.cobblemon.mod.common.entity.PoseType.Companion.UI_POSES
import com.cobblemon.mod.common.util.isBattling
import net.minecraft.client.model.geom.ModelPart
import net.minecraft.world.phys.Vec3
class DugtrioAlolanModel(root: ModelPart) : PokemonPosableModel(root) {
override val rootPart = root.registerChildWithAllChildren("dugtrio_alolan")
override var portraitScale = 1.3F
override var portraitTranslation = Vec3(-0.11, -0.1, 0.0)
override var profileScale = 0.9F
override var profileTranslation = Vec3(0.0, 0.29, 0.0)
lateinit var standing: CobblemonPose
lateinit var walking: CobblemonPose
lateinit var battleidle: CobblemonPose
lateinit var sleep: CobblemonPose
override val cryAnimation = CryProvider { bedrockStateful("dugtrio_alolan", "cry") }
override fun registerPoses() {
val blink = quirk { bedrockStateful("dugtrio_alolan", "blink")}
val blink2 = quirk { bedrockStateful("dugtrio_alolan", "blink2")}
val blink3 = quirk { bedrockStateful("dugtrio_alolan", "blink3")}
val quirk = quirk { bedrockStateful("dugtrio_alolan", "quirk_idle")}
val quirk2 = quirk { bedrockStateful("dugtrio_alolan", "quirk_idle2")}
val quirk3 = quirk { bedrockStateful("dugtrio_alolan", "quirk_idle3")}
sleep = registerPose(
poseName = "sleep",
poseType = PoseType.SLEEP,
animations = arrayOf(bedrock("dugtrio_alolan", "sleep"))
)
standing = registerPose(
poseName = "stand",
poseTypes = STATIONARY_POSES + UI_POSES,
condition = { !it.isBattling },
quirks = arrayOf(blink, blink2, blink3, quirk, quirk2, quirk3),
animations = arrayOf(bedrock("dugtrio_alolan", "ground_idle"))
)
walking = registerPose(
poseName = "walk",
poseTypes = MOVING_POSES,
quirks = arrayOf(blink, blink2, blink3),
animations = arrayOf(bedrock("dugtrio_alolan", "ground_idle"))
)
battleidle = registerPose(
poseName = "battleidle",
poseTypes = STATIONARY_POSES,
condition = { it.isBattling },
quirks = arrayOf(blink, blink2, blink3, quirk, quirk2, quirk3),
animations = arrayOf(bedrock("dugtrio_alolan", "battle_idle"))
)
}
override fun getFaintAnimation(state: PosableState) = bedrockStateful("dugtrio_alolan", "faint")
}
@@ -0,0 +1,99 @@
/*
* 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.render.models.blockbench.pokemon.gen1
import com.cobblemon.mod.common.client.render.models.blockbench.PosableState
import com.cobblemon.mod.common.client.render.models.blockbench.animation.SingleBoneLookAnimation
import com.cobblemon.mod.common.client.render.models.blockbench.frame.HeadedFrame
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.CryProvider
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.PokemonPosableModel
import com.cobblemon.mod.common.client.render.models.blockbench.pose.CobblemonPose
import com.cobblemon.mod.common.entity.PoseType
import com.cobblemon.mod.common.entity.PoseType.Companion.MOVING_POSES
import com.cobblemon.mod.common.entity.PoseType.Companion.STATIONARY_POSES
import com.cobblemon.mod.common.entity.PoseType.Companion.UI_POSES
import com.cobblemon.mod.common.util.isBattling
import net.minecraft.client.model.geom.ModelPart
import net.minecraft.world.phys.Vec3
class DugtrioModel(root: ModelPart) : PokemonPosableModel(root), HeadedFrame {
override val rootPart = root.registerChildWithAllChildren("dugtrio")
override val head = getPart("body3")
val lefthead = object : HeadedFrame {
override val rootPart = this@DugtrioModel.rootPart
override val head: ModelPart = getPart("body2")
}
val righthead = object : HeadedFrame {
override val rootPart = this@DugtrioModel.rootPart
override val head: ModelPart = getPart("body1")
}
override var portraitScale = 1.3F
override var portraitTranslation = Vec3(-0.11, -0.1, 0.0)
override var profileScale = 0.9F
override var profileTranslation = Vec3(0.0, 0.29, 0.0)
lateinit var standing: CobblemonPose
lateinit var walking: CobblemonPose
lateinit var battleidle: CobblemonPose
lateinit var sleep: CobblemonPose
override val cryAnimation = CryProvider { bedrockStateful("dugtrio", "cry") }
override fun registerPoses() {
val blink = quirk { bedrockStateful("dugtrio", "blink")}
val blink2 = quirk { bedrockStateful("dugtrio", "blink2")}
val blink3 = quirk { bedrockStateful("dugtrio", "blink3")}
val quirk = quirk { bedrockStateful("dugtrio", "quirk_idle")}
val quirk2 = quirk { bedrockStateful("dugtrio", "quirk_idle2")}
val quirk3 = quirk { bedrockStateful("dugtrio", "quirk_idle3")}
sleep = registerPose(
poseName = "sleep",
poseType = PoseType.SLEEP,
animations = arrayOf(bedrock("dugtrio", "sleep"))
)
standing = registerPose(
poseName = "stand",
poseTypes = STATIONARY_POSES + UI_POSES,
condition = { !it.isBattling },
quirks = arrayOf(blink, blink2, blink3, quirk, quirk2, quirk3),
animations = arrayOf(
singleBoneLook(pitchMultiplier = 0.6F, yawMultiplier = 0.4F, maxPitch = 10F, minPitch = -30F),
SingleBoneLookAnimation(lefthead, false, false, false, false, 1F, 1.4F, 0F, -30F, 20F, -45F),
SingleBoneLookAnimation(righthead, false, false, false, false, 1F, 1.4F, 0F, -30F, 45F, -25F),
bedrock("dugtrio", "ground_idle"))
)
walking = registerPose(
poseName = "walk",
poseTypes = MOVING_POSES,
quirks = arrayOf(blink, blink2, blink3),
animations = arrayOf(
singleBoneLook(pitchMultiplier = 0.6F, yawMultiplier = 0.4F, maxPitch = 10F, minPitch = -30F),
SingleBoneLookAnimation(lefthead, false, false, false, false, 1F, 1.4F, 0F, -30F, 20F, -45F),
SingleBoneLookAnimation(righthead, false, false, false, false, 1F, 1.4F, 0F, -30F, 45F, -25F),
bedrock("dugtrio", "ground_walk"))
)
battleidle = registerPose(
poseName = "battleidle",
poseTypes = STATIONARY_POSES,
condition = { it.isBattling },
quirks = arrayOf(blink, blink2, blink3, quirk, quirk2, quirk3),
animations = arrayOf(bedrock("dugtrio", "battle_idle"))
)
}
override fun getFaintAnimation(state: PosableState) = bedrockStateful("dugtrio", "faint")
}
@@ -0,0 +1,66 @@
/*
* 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.render.models.blockbench.pokemon.gen1
import com.cobblemon.mod.common.client.render.models.blockbench.animation.BipedWalkAnimation
import com.cobblemon.mod.common.client.render.models.blockbench.frame.BipedFrame
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.CryProvider
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.PokemonPosableModel
import com.cobblemon.mod.common.client.render.models.blockbench.pose.CobblemonPose
import com.cobblemon.mod.common.entity.PoseType.Companion.MOVING_POSES
import com.cobblemon.mod.common.entity.PoseType.Companion.STATIONARY_POSES
import com.cobblemon.mod.common.entity.PoseType.Companion.UI_POSES
import net.minecraft.client.model.geom.ModelPart
import net.minecraft.world.phys.Vec3
class GravelerModel(root: ModelPart) : PokemonPosableModel(root), BipedFrame {
override val rootPart = root.registerChildWithAllChildren("graveler")
override val leftLeg = getPart("leg_left")
override val rightLeg = getPart("leg_right")
override var portraitScale = 1.4F
override var portraitTranslation = Vec3(-0.1, -0.28, 0.0)
override var profileScale = 0.9F
override var profileTranslation = Vec3(0.0, 0.37, 0.0)
lateinit var standing: CobblemonPose
lateinit var walk: CobblemonPose
override val cryAnimation = CryProvider { bedrockStateful("graveler", "cry") }
override fun registerPoses() {
val blink = quirk { bedrockStateful("graveler", "blink")}
standing = registerPose(
poseName = "standing",
poseTypes = STATIONARY_POSES + UI_POSES,
quirks = arrayOf(blink),
animations = arrayOf(
bedrock("graveler", "ground_idle")
)
)
walk = registerPose(
poseName = "walk",
poseTypes = MOVING_POSES,
quirks = arrayOf(blink),
animations = arrayOf(
BipedWalkAnimation(this, periodMultiplier = 1.1F),
bedrock("graveler", "ground_idle")
//bedrock("graveler", "ground_walk")
)
)
}
// override fun getFaintAnimation(
// pokemonEntity: PokemonEntity,
// state: PosableState<PokemonEntity>
// ) = if (state.isPosedIn(standing, walk)) bedrockStateful("graveler", "faint") else null
}
@@ -0,0 +1,52 @@
/*
* 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.render.models.blockbench.pokemon.gen1
import com.cobblemon.mod.common.client.render.models.blockbench.PosableState
import com.cobblemon.mod.common.client.render.models.blockbench.frame.HeadedFrame
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.CryProvider
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.PokemonPosableModel
import com.cobblemon.mod.common.client.render.models.blockbench.pose.Pose
import com.cobblemon.mod.common.entity.PoseType
import com.cobblemon.mod.common.entity.PoseType.Companion.ALL_POSES
import net.minecraft.client.model.geom.ModelPart
import net.minecraft.world.phys.Vec3
class KakunaModel(root: ModelPart) : PokemonPosableModel(root), HeadedFrame {
override val rootPart = root.registerChildWithAllChildren("kakuna")
override val head = getPart("head")
override var portraitScale = 1.7F
override var portraitTranslation = Vec3(0.1, -0.4, 0.0)
override var profileScale = 0.96F
override var profileTranslation = Vec3(0.0, 0.35, 0.0)
lateinit var sleep: Pose
lateinit var standing: Pose
override val cryAnimation = CryProvider { bedrockStateful("kakuna", "cry") }
override fun registerPoses() {
sleep = registerPose(
poseType = PoseType.SLEEP,
animations = arrayOf(bedrock("kakuna", "sleep"))
)
standing = registerPose(
poseName = "standing",
poseTypes = ALL_POSES - PoseType.SLEEP,
animations = arrayOf(
singleBoneLook(),
bedrock("kakuna", "ground_idle")
)
)
}
override fun getFaintAnimation(state: PosableState) = bedrockStateful("kakuna", "faint")
}
@@ -0,0 +1,73 @@
/*
* 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.render.models.blockbench.pokemon.gen1
import com.cobblemon.mod.common.client.render.models.blockbench.animation.QuadrupedWalkAnimation
import com.cobblemon.mod.common.client.render.models.blockbench.frame.HeadedFrame
import com.cobblemon.mod.common.client.render.models.blockbench.frame.QuadrupedFrame
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.CryProvider
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.PokemonPosableModel
import com.cobblemon.mod.common.client.render.models.blockbench.pose.CobblemonPose
import com.cobblemon.mod.common.entity.PoseType.Companion.MOVING_POSES
import com.cobblemon.mod.common.entity.PoseType.Companion.STATIONARY_POSES
import com.cobblemon.mod.common.entity.PoseType.Companion.UI_POSES
import net.minecraft.client.model.geom.ModelPart
import net.minecraft.world.phys.Vec3
class NidoranfModel(root: ModelPart) : PokemonPosableModel(root), HeadedFrame, QuadrupedFrame {
override val rootPart = root.registerChildWithAllChildren("nidoran_f")
override val head = getPart("head")
override val foreLeftLeg = getPart("leg_front_left")
override val foreRightLeg = getPart("leg_front_right")
override val hindLeftLeg = getPart("leg_back_left")
override val hindRightLeg = getPart("leg_back_right")
override var portraitScale = 2.0F
override var portraitTranslation = Vec3(-0.16, -0.85, 0.0)
override var profileScale = 1.03F
override var profileTranslation = Vec3(0.02, 0.21, 0.0)
lateinit var sleep: CobblemonPose
lateinit var standing: CobblemonPose
lateinit var walk: CobblemonPose
override val cryAnimation = CryProvider { bedrockStateful("nidoranf", "cry") }
override fun registerPoses() {
val blink = quirk { bedrockStateful("nidoranf", "blink") }
standing = registerPose(
poseName = "standing",
poseTypes = STATIONARY_POSES + UI_POSES,
transformTicks = 10,
quirks = arrayOf(blink),
animations = arrayOf(
singleBoneLook(),
bedrock("nidoranf", "idle")
)
)
walk = registerPose(
poseName = "walk",
poseTypes = MOVING_POSES,
transformTicks = 10,
quirks = arrayOf(blink),
animations = arrayOf(
singleBoneLook(),
bedrock("nidoranf", "idle"),
QuadrupedWalkAnimation(this)
)
)
}
// override fun getFaintAnimation(
// pokemonEntity: PokemonEntity,
// state: PosableState<PokemonEntity>
// ) = if (state.isPosedIn(standing, walk)) bedrockStateful("nidoranf", "faint") else null
}
@@ -0,0 +1,73 @@
/*
* 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.render.models.blockbench.pokemon.gen1
import com.cobblemon.mod.common.client.render.models.blockbench.animation.QuadrupedWalkAnimation
import com.cobblemon.mod.common.client.render.models.blockbench.frame.HeadedFrame
import com.cobblemon.mod.common.client.render.models.blockbench.frame.QuadrupedFrame
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.CryProvider
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.PokemonPosableModel
import com.cobblemon.mod.common.client.render.models.blockbench.pose.Pose
import com.cobblemon.mod.common.entity.PoseType.Companion.MOVING_POSES
import com.cobblemon.mod.common.entity.PoseType.Companion.STATIONARY_POSES
import com.cobblemon.mod.common.entity.PoseType.Companion.UI_POSES
import net.minecraft.client.model.geom.ModelPart
import net.minecraft.world.phys.Vec3
class NidoranmModel(root: ModelPart) : PokemonPosableModel(root), HeadedFrame, QuadrupedFrame {
override val rootPart = root.registerChildWithAllChildren("nidoran_m")
override val head = getPart("head")
override val foreLeftLeg = getPart("leg_front_left")
override val foreRightLeg = getPart("leg_front_right")
override val hindLeftLeg = getPart("leg_back_left")
override val hindRightLeg = getPart("leg_back_right")
override var portraitScale = 1.97F
override var portraitTranslation = Vec3(-0.18, -1.28, 0.0)
override var profileScale = 1.05F
override var profileTranslation = Vec3(0.03, 0.11, 0.0)
lateinit var sleep: Pose
lateinit var standing: Pose
lateinit var walk: Pose
override val cryAnimation = CryProvider { bedrockStateful("nidoranm", "cry") }
override fun registerPoses() {
val blink = quirk { bedrockStateful("nidoranm", "blink") }
standing = registerPose(
poseName = "standing",
poseTypes = STATIONARY_POSES + UI_POSES,
transformTicks = 10,
quirks = arrayOf(blink),
animations = arrayOf(
singleBoneLook(),
bedrock("nidoranm", "idle")
)
)
walk = registerPose(
poseName = "walk",
poseTypes = MOVING_POSES,
transformTicks = 10,
quirks = arrayOf(blink),
animations = arrayOf(
singleBoneLook(),
bedrock("nidoranm", "idle"),
QuadrupedWalkAnimation(this)
)
)
}
// override fun getFaintAnimation(
// pokemonEntity: PokemonEntity,
// state: PosableState<PokemonEntity>
// ) = if (state.isPosedIn(standing, walk)) bedrockStateful("nidoranm", "faint") else null
}
@@ -0,0 +1,92 @@
/*
* 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.render.models.blockbench.pokemon.gen1
import com.cobblemon.mod.common.client.render.models.blockbench.animation.QuadrupedWalkAnimation
import com.cobblemon.mod.common.client.render.models.blockbench.frame.HeadedFrame
import com.cobblemon.mod.common.client.render.models.blockbench.frame.QuadrupedFrame
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.CryProvider
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.PokemonPosableModel
import com.cobblemon.mod.common.client.render.models.blockbench.pose.Pose
import com.cobblemon.mod.common.entity.PoseType
import com.cobblemon.mod.common.entity.PoseType.Companion.MOVING_POSES
import com.cobblemon.mod.common.entity.PoseType.Companion.STATIONARY_POSES
import com.cobblemon.mod.common.entity.PoseType.Companion.UI_POSES
import com.cobblemon.mod.common.util.isBattling
import net.minecraft.client.model.geom.ModelPart
import net.minecraft.world.phys.Vec3
class NidorinaModel(root: ModelPart) : PokemonPosableModel(root), HeadedFrame, QuadrupedFrame {
override val rootPart = root.registerChildWithAllChildren("nidorina")
override val head = getPart("head")
override val foreLeftLeg= getPart("left_upper_arm")
override val foreRightLeg = getPart("right_upper_arm")
override val hindLeftLeg = getPart("left_leg")
override val hindRightLeg = getPart("right_leg")
override var portraitScale = 2.13F
override var portraitTranslation = Vec3(-0.05, -0.71, 0.0)
override var profileScale = 1.0F
override var profileTranslation = Vec3(0.0, 0.21, 0.0)
lateinit var sleep: Pose
lateinit var standing: Pose
lateinit var walk: Pose
lateinit var battleidle: Pose
override val cryAnimation = CryProvider { bedrockStateful("nidorina", "cry") }
override fun registerPoses() {
val blink = quirk { bedrockStateful("nidorina", "blink")}
standing = registerPose(
poseName = "standing",
poseTypes = STATIONARY_POSES + UI_POSES,
condition = { !it.isBattling },
quirks = arrayOf(blink),
animations = arrayOf(
singleBoneLook(),
bedrock("nidorina", "idle3")
)
)
sleep = registerPose(
poseType = PoseType.SLEEP,
animations = arrayOf(bedrock("nidorina", "idle2"))
)
walk = registerPose(
poseName = "walk",
poseTypes = MOVING_POSES,
quirks = arrayOf(blink),
animations = arrayOf(
singleBoneLook(),
bedrock("nidorina", "idle2"),
QuadrupedWalkAnimation(this)
)
)
battleidle = registerPose(
poseName = "battle_idle",
poseTypes = PoseType.STATIONARY_POSES,
transformTicks = 10,
quirks = arrayOf(blink),
condition = { it.isBattling },
animations = arrayOf(
singleBoneLook(),
bedrock("nidorina", "idle")
)
)
}
// override fun getFaintAnimation(
// pokemonEntity: PokemonEntity,
// state: PosableState<PokemonEntity>
// ) = if (state.isPosedIn(standing, walk)) bedrockStateful("nidorina", "faint") else null
}
@@ -0,0 +1,206 @@
/*
* 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.render.models.blockbench.pokemon.gen1
import com.cobblemon.mod.common.client.render.models.blockbench.createTransformation
import com.cobblemon.mod.common.client.render.models.blockbench.frame.BiWingedFrame
import com.cobblemon.mod.common.client.render.models.blockbench.frame.BipedFrame
import com.cobblemon.mod.common.client.render.models.blockbench.frame.HeadedFrame
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.CryProvider
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.PokemonPosableModel
import com.cobblemon.mod.common.client.render.models.blockbench.pose.ModelPartTransformation
import com.cobblemon.mod.common.client.render.models.blockbench.pose.Pose
import com.cobblemon.mod.common.client.render.models.blockbench.wavefunction.parabolaFunction
import com.cobblemon.mod.common.client.render.models.blockbench.wavefunction.sineFunction
import com.cobblemon.mod.common.entity.PoseType
import com.cobblemon.mod.common.entity.PoseType.Companion.STATIONARY_POSES
import com.cobblemon.mod.common.entity.PoseType.Companion.UI_POSES
import com.cobblemon.mod.common.util.math.geometry.toRadians
import net.minecraft.client.model.geom.ModelPart
import net.minecraft.world.phys.Vec3
class PidgeottoModel(root: ModelPart) : PokemonPosableModel(root), HeadedFrame, BipedFrame, BiWingedFrame {
override val rootPart = root.registerChildWithAllChildren("pidgeotto")
override val head = getPart("neck")
override val leftWing = getPart("wing_closed_left")
override val rightWing = getPart("wing_closed_right")
override val leftLeg = getPart("leg_left")
override val rightLeg = getPart("leg_right")
private val tail = getPart("tail")
private val wingOpenRight = getPart("wing_open_right")
private val wingOpenLeft = getPart("wing_open_left")
private val wingClosedRight = getPart("wing_closed_right")
private val wingClosedLeft = getPart("wing_closed_left")
override var portraitScale = 2.8F
override var portraitTranslation = Vec3(-0.4, -0.9, 0.0)
override var profileScale = 1.1F
override var profileTranslation = Vec3(0.0, 0.1, 0.0)
lateinit var sleep: Pose
lateinit var stand: Pose
lateinit var walk: Pose
lateinit var hover: Pose
lateinit var fly: Pose
override val cryAnimation = CryProvider { bedrockStateful("pidgeotto", "cry") }
override fun registerPoses() {
val blink = quirk { bedrockStateful("pidgeotto", "blink")}
val flyQuirk1 = quirk { bedrockStateful("pidgeotto", "air_fly_quirk") }
val flyQuirk2 = quirk { bedrockStateful("pidgeotto", "air_fly_quirk2") }
sleep = registerPose(
poseName = "sleep",
poseType = PoseType.SLEEP,
transformedParts = arrayOf(
wingClosedLeft.createTransformation().withVisibility(visibility = true),
wingClosedRight.createTransformation().withVisibility(visibility = true),
wingOpenLeft.createTransformation().withVisibility(visibility = false),
wingOpenRight.createTransformation().withVisibility(visibility = false)
),
animations = arrayOf(bedrock("pidgeotto", "sleep_PLACEHOLDER"))
)
stand = registerPose(
poseName = "stand",
poseTypes = STATIONARY_POSES - PoseType.HOVER + UI_POSES,
transformedParts = arrayOf(
wingClosedLeft.createTransformation().withVisibility(visibility = true),
wingClosedRight.createTransformation().withVisibility(visibility = true),
wingOpenLeft.createTransformation().withVisibility(visibility = false),
wingOpenRight.createTransformation().withVisibility(visibility = false)
),
quirks = arrayOf(blink),
animations = arrayOf(
singleBoneLook(),
bedrock("pidgeotto", "ground_idle_PLACEHOLDER")
)
)
walk = registerPose(
poseName = "hover",
poseTypes = PoseType.MOVING_POSES - PoseType.FLY,
transformedParts = arrayOf(
wingClosedLeft.createTransformation().withVisibility(visibility = true),
wingClosedRight.createTransformation().withVisibility(visibility = true),
wingOpenLeft.createTransformation().withVisibility(visibility = false),
wingOpenRight.createTransformation().withVisibility(visibility = false)
),
quirks = arrayOf(blink),
animations = arrayOf(
singleBoneLook(),
bedrock("pidgeotto", "ground_idle_PLACEHOLDER"),
rootPart.translation(
function = parabolaFunction(
peak = -4F,
period = 0.4F
),
timeVariable = { state, _, _ -> state.animationSeconds },
axis = ModelPartTransformation.Y_AXIS
),
head.translation(
function = sineFunction(
amplitude = (-20F).toRadians(),
period = 1F,
verticalShift = (-10F).toRadians()
),
axis = ModelPartTransformation.X_AXIS,
timeVariable = { state, _, _ -> state.animationSeconds }
),
leftLeg.rotation(
function = parabolaFunction(
tightness = -20F,
phaseShift = 0F,
verticalShift = (30F).toRadians()
),
axis = ModelPartTransformation.X_AXIS,
timeVariable = { _, _, ageInTicks -> ageInTicks / 20 },
),
rightLeg.rotation(
function = parabolaFunction(
tightness = -20F,
phaseShift = 0F,
verticalShift = (30F).toRadians()
),
axis = ModelPartTransformation.X_AXIS,
timeVariable = { _, _, ageInTicks -> ageInTicks / 20 },
),
tail.rotation(
function = sineFunction(
amplitude = (-5F).toRadians(),
period = 1F
),
axis = ModelPartTransformation.X_AXIS,
timeVariable = { _, _, ageInTicks -> ageInTicks / 20 },
),
wingFlap(
flapFunction = sineFunction(
amplitude = (-5F).toRadians(),
period = 0.4F,
phaseShift = 0.00F,
verticalShift = (-20F).toRadians()
),
timeVariable = { state, _, _ -> state.animationSeconds },
axis = ModelPartTransformation.Z_AXIS
),
rightWing.translation(
function = parabolaFunction(
tightness = -10F,
phaseShift = 30F,
verticalShift = (25F).toRadians()
),
axis = ModelPartTransformation.Y_AXIS,
timeVariable = { _, _, ageInTicks -> ageInTicks / 20 },
),
leftWing.translation(
function = parabolaFunction(
tightness = -10F,
phaseShift = 30F,
verticalShift = (25F).toRadians()
),
axis = ModelPartTransformation.Y_AXIS,
timeVariable = { _, _, ageInTicks -> ageInTicks / 20 },
),
)
)
hover = registerPose(
poseName = "fly",
poseType = PoseType.HOVER,
transformedParts = arrayOf(
wingClosedLeft.createTransformation().withVisibility(visibility = false),
wingClosedRight.createTransformation().withVisibility(visibility = false),
wingOpenLeft.createTransformation().withVisibility(visibility = true),
wingOpenRight.createTransformation().withVisibility(visibility = true)
),
quirks = arrayOf(blink),
animations = arrayOf(
singleBoneLook(),
bedrock("pidgeotto", "air_idle")
)
)
fly = registerPose(
poseName = "walk",
poseType = PoseType.FLY,
transformedParts = arrayOf(
wingClosedLeft.createTransformation().withVisibility(visibility = false),
wingClosedRight.createTransformation().withVisibility(visibility = false),
wingOpenLeft.createTransformation().withVisibility(visibility = true),
wingOpenRight.createTransformation().withVisibility(visibility = true)
),
transformTicks = 10,
quirks = arrayOf(blink, flyQuirk1, flyQuirk2),
animations = arrayOf(
singleBoneLook(),
bedrock("pidgeotto", "air_fly")
)
)
}
}
@@ -0,0 +1,131 @@
/*
* 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.render.models.blockbench.pokemon.gen1
import com.cobblemon.mod.common.client.render.models.blockbench.animation.PitchTiltAnimation
import com.cobblemon.mod.common.client.render.models.blockbench.createTransformation
import com.cobblemon.mod.common.client.render.models.blockbench.frame.HeadedFrame
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.CryProvider
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.PokemonPosableModel
import com.cobblemon.mod.common.client.render.models.blockbench.pose.CobblemonPose
import com.cobblemon.mod.common.entity.PoseType
import com.cobblemon.mod.common.entity.PoseType.Companion.SHOULDER_POSES
import com.cobblemon.mod.common.entity.PoseType.Companion.UI_POSES
import net.minecraft.client.model.geom.ModelPart
import net.minecraft.world.phys.Vec3
class PidgeyModel(root: ModelPart) : PokemonPosableModel(root), HeadedFrame {
override val rootPart = root.registerChildWithAllChildren("pidgey")
override val head = getPart("head")
private val wingOpenRight = getPart("wing_open_right")
private val wingOpenLeft = getPart("wing_open_left")
private val wingClosedRight = getPart("wing_closed_right")
private val wingClosedLeft = getPart("wing_closed_left")
override var portraitScale = 3.5F
override var portraitTranslation = Vec3(-0.1, -2.1, 0.0)
override var profileScale = 1.2F
override var profileTranslation = Vec3(0.0, -0.01, 0.0)
lateinit var sleep: CobblemonPose
lateinit var stand: CobblemonPose
lateinit var walk: CobblemonPose
lateinit var hover: CobblemonPose
lateinit var fly: CobblemonPose
override val cryAnimation = CryProvider { bedrockStateful("pidgey", "cry") }
override fun registerPoses() {
val blink = quirk { bedrockStateful("pidgey", "blink") }
sleep = registerPose(
poseName = "sleeping",
transformedParts = arrayOf(
wingClosedLeft.createTransformation().withVisibility(visibility = true),
wingClosedRight.createTransformation().withVisibility(visibility = true),
wingOpenLeft.createTransformation().withVisibility(visibility = false),
wingOpenRight.createTransformation().withVisibility(visibility = false)
),
poseType = PoseType.SLEEP,
animations = arrayOf(bedrock("pidgey", "sleep_PLACEHOLDER"))
)
stand = registerPose(
poseName = "standing",
poseTypes = SHOULDER_POSES + UI_POSES + PoseType.STATIONARY_POSES - PoseType.HOVER,
transformTicks = 10,
transformedParts = arrayOf(
wingClosedLeft.createTransformation().withVisibility(visibility = true),
wingClosedRight.createTransformation().withVisibility(visibility = true),
wingOpenLeft.createTransformation().withVisibility(visibility = false),
wingOpenRight.createTransformation().withVisibility(visibility = false)
),
quirks = arrayOf(blink),
animations = arrayOf(
singleBoneLook(),
bedrock("pidgey", "ground_idle")
)
)
hover = registerPose(
poseName = "hover",
poseType = PoseType.HOVER,
transformedParts = arrayOf(
wingClosedLeft.createTransformation().withVisibility(visibility = false),
wingClosedRight.createTransformation().withVisibility(visibility = false),
wingOpenLeft.createTransformation().withVisibility(visibility = true),
wingOpenRight.createTransformation().withVisibility(visibility = true)
),
transformTicks = 10,
quirks = arrayOf(blink),
animations = arrayOf(
PitchTiltAnimation(bone = getPart("body"), maxChangePerTick = 1F),
singleBoneLook(),
bedrock("pidgey", "air_idle")
)
)
fly = registerPose(
poseName = "fly",
poseType = PoseType.FLY,
transformedParts = arrayOf(
wingClosedLeft.createTransformation().withVisibility(visibility = false),
wingClosedRight.createTransformation().withVisibility(visibility = false),
wingOpenLeft.createTransformation().withVisibility(visibility = true),
wingOpenRight.createTransformation().withVisibility(visibility = true)
),
transformTicks = 10,
quirks = arrayOf(blink),
animations = arrayOf(
PitchTiltAnimation(bone = getPart("body"), maxChangePerTick = 1F),
singleBoneLook(),
bedrock("pidgey", "air_fly")
)
)
walk = registerPose(
poseName = "walking",
poseTypes = PoseType.MOVING_POSES - PoseType.FLY,
transformedParts = arrayOf(
wingClosedLeft.createTransformation().withVisibility(visibility = true),
wingClosedRight.createTransformation().withVisibility(visibility = true),
wingOpenLeft.createTransformation().withVisibility(visibility = false),
wingOpenRight.createTransformation().withVisibility(visibility = false)
),
transformTicks = 10,
quirks = arrayOf(blink),
animations = arrayOf(
singleBoneLook(),
bedrock("pidgey", "ground_walk")
)
)
}
}
@@ -0,0 +1,93 @@
/*
* 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.render.models.blockbench.pokemon.gen1
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.PokemonPosableModel
import com.cobblemon.mod.common.client.render.models.blockbench.pose.CobblemonPose
import com.cobblemon.mod.common.entity.PoseType
import com.cobblemon.mod.common.entity.PoseType.Companion.UI_POSES
import com.cobblemon.mod.common.util.isInWater
import net.minecraft.client.model.geom.ModelPart
import net.minecraft.world.phys.Vec3
class TentacoolModel(root: ModelPart) : PokemonPosableModel(root) {
override val rootPart = root.registerChildWithAllChildren("tentacool")
override var portraitScale = 1.2F
override var portraitTranslation = Vec3(0.1, 1.1, 0.0)
override var profileScale = 0.6F
override var profileTranslation = Vec3(0.0, 0.8, 0.0)
lateinit var standing: CobblemonPose
lateinit var walk: CobblemonPose
lateinit var swim: CobblemonPose
lateinit var float: CobblemonPose
lateinit var sleep: CobblemonPose
lateinit var watersleep: CobblemonPose
override fun registerPoses() {
val blink = quirk { bedrockStateful("tentacool", "blink")}
standing = registerPose(
poseName = "standing",
poseType = PoseType.STAND,
quirks = arrayOf(blink),
animations = arrayOf(
bedrock("tentacool", "ground_idle")
)
)
walk = registerPose(
poseName = "walk",
poseType = PoseType.WALK,
quirks = arrayOf(blink),
animations = arrayOf(
bedrock("tentacool", "ground_idle")
//bedrock("tentacool", "ground_walk")
)
)
float = registerPose(
poseName = "float",
poseTypes = UI_POSES + PoseType.FLOAT,
quirks = arrayOf(blink),
animations = arrayOf(
bedrock("tentacool", "water_idle")
)
)
swim = registerPose(
poseName = "swim",
poseType = PoseType.SWIM,
quirks = arrayOf(blink),
animations = arrayOf(
bedrock("tentacool", "water_swim")
)
)
sleep = registerPose(
poseName = "sleep",
poseType = PoseType.SLEEP,
condition = { !it.isInWater },
animations = arrayOf(bedrock("tentacool", "sleep"))
)
watersleep = registerPose(
poseName = "watersleep",
poseType = PoseType.SLEEP,
condition = { it.isInWater },
animations = arrayOf(bedrock("tentacool", "water_sleep"))
)
}
// override fun getFaintAnimation(
// pokemonEntity: PokemonEntity,
// state: PosableState<PokemonEntity>
// ) = if (state.isPosedIn(standing, walk)) bedrockStateful("tentacool", "faint") else null
}
@@ -30,7 +30,7 @@ class WartortleModel(root: ModelPart) : PokemonPosableModel(root), HeadedFrame {
override var portraitTranslation = Vec3(-0.17, 0.54, 0.0)
override var profileScale = 0.69F
override var profileTranslation = Vec3(0.0, 0.69, 0.0)
override var profileTranslation = Vec3(-0.04, 0.69, 0.0)
lateinit var sleep: CobblemonPose
lateinit var standing: CobblemonPose
@@ -0,0 +1,86 @@
/*
* 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.render.models.blockbench.pokemon.gen2
import com.cobblemon.mod.common.client.render.models.blockbench.PosableState
import com.cobblemon.mod.common.client.render.models.blockbench.frame.BimanualFrame
import com.cobblemon.mod.common.client.render.models.blockbench.frame.BipedFrame
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.PokemonPosableModel
import com.cobblemon.mod.common.client.render.models.blockbench.pose.CobblemonPose
import com.cobblemon.mod.common.entity.PoseType
import com.cobblemon.mod.common.entity.PoseType.Companion.MOVING_POSES
import com.cobblemon.mod.common.entity.PoseType.Companion.STATIONARY_POSES
import com.cobblemon.mod.common.entity.PoseType.Companion.UI_POSES
import com.cobblemon.mod.common.util.isBattling
import net.minecraft.client.model.geom.ModelPart
import net.minecraft.world.phys.Vec3
class BlisseyModel(root: ModelPart) : PokemonPosableModel(root), BipedFrame, BimanualFrame {
override val rootPart = root.registerChildWithAllChildren("blissey")
override val leftLeg = getPart("left_foot")
override val rightLeg = getPart("right_foot")
override val leftArm = getPart("left_arm")
override val rightArm = getPart("right_arm")
override var portraitScale = 1.5F
override var portraitTranslation = Vec3(-0.6, 0.9, 0.0)
override var profileScale = 0.7F
override var profileTranslation = Vec3(0.0, 0.7, 0.0)
lateinit var standing: CobblemonPose
lateinit var walk: CobblemonPose
lateinit var sleep: CobblemonPose
lateinit var battle_idle: CobblemonPose
override fun registerPoses() {
val blink = quirk { bedrockStateful("blissey", "blink") }
val eggQuirk = quirk { bedrockStateful("blissey", "eggadjust_quirk") }
sleep = registerPose(
poseName = "sleep",
poseType = PoseType.SLEEP,
animations = arrayOf(
bedrock("blissey", "sleep")
)
)
standing = registerPose(
poseName = "standing",
poseTypes = STATIONARY_POSES + UI_POSES,
condition = { !it.isBattling },
quirks = arrayOf(blink, eggQuirk),
animations = arrayOf(
bedrock("blissey", "ground_idle")
)
)
walk = registerPose(
poseName = "walk",
poseTypes = MOVING_POSES,
quirks = arrayOf(blink),
animations = arrayOf(
bedrock("blissey", "ground_walk")
)
)
battle_idle = registerPose(
poseName = "battle_idle",
poseTypes = STATIONARY_POSES,
condition = { it.isBattling },
quirks = arrayOf(blink, eggQuirk),
animations = arrayOf(
bedrock("blissey", "battle_idle")
)
)
}
override fun getFaintAnimation(state: PosableState) = bedrockStateful("blissey", "faint")
}
@@ -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.client.render.models.blockbench.pokemon.gen5
import com.cobblemon.mod.common.client.render.models.blockbench.PosableState
import com.cobblemon.mod.common.client.render.models.blockbench.animation.ActiveAnimation
import com.cobblemon.mod.common.client.render.models.blockbench.frame.BimanualFrame
import com.cobblemon.mod.common.client.render.models.blockbench.frame.BipedFrame
import com.cobblemon.mod.common.client.render.models.blockbench.frame.HeadedFrame
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.CryProvider
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.PokemonPosableModel
import com.cobblemon.mod.common.client.render.models.blockbench.pose.Pose
import com.cobblemon.mod.common.entity.PoseType
import net.minecraft.client.model.geom.ModelPart
import net.minecraft.world.phys.Vec3
class GolettModel (root: ModelPart) : PokemonPosableModel(root), HeadedFrame, BipedFrame, BimanualFrame {
override val rootPart = root.registerChildWithAllChildren("golett")
override val head = getPart("head")
override val leftArm = getPart("arm_left")
override val rightArm = getPart("arm_right")
override val leftLeg = getPart("leg_left")
override val rightLeg = getPart("leg_right")
override var portraitScale = 3.0F
override var portraitTranslation = Vec3(-0.15, -0.45, 0.0)
override var profileScale = 0.8F
override var profileTranslation = Vec3(0.0, 0.55, 0.0)
lateinit var standing: Pose
lateinit var walk: Pose
lateinit var sleep: Pose
override val cryAnimation = CryProvider { bedrockStateful("golett", "cry") }
override fun registerPoses() {
val blink = quirk { bedrockStateful("golett", "blink") }
standing = registerPose(
poseName = "standing",
poseTypes = PoseType.STATIONARY_POSES + PoseType.UI_POSES,
quirks = arrayOf(blink),
animations = arrayOf(
singleBoneLook(),
bedrock("golett", "ground_idle")
)
)
walk = registerPose(
poseName = "walk",
poseTypes = PoseType.MOVING_POSES,
quirks = arrayOf(blink),
animations = arrayOf(
singleBoneLook(),
bedrock("golett", "ground_walk")
)
)
sleep = registerPose(
poseName = "sleep",
poseType = PoseType.SLEEP,
animations = arrayOf(bedrock("golett", "sleep"))
)
}
override fun getFaintAnimation(state: PosableState): ActiveAnimation? {
return if (state.isNotPosedIn(sleep, standing, walk)) bedrockStateful("golett", "faint") else null
}
}
@@ -224,11 +224,16 @@ object VaryingModelRepository {
inbuilt("metapod", ::MetapodModel)
inbuilt("butterfree", ::ButterfreeModel)
inbuilt("weedle", ::WeedleModel)
inbuilt("kakuna", ::KakunaModel)
inbuilt("beedrill", ::BeedrillModel)
inbuilt("rattata", ::RattataModel)
inbuilt("raticate", ::RaticateModel)
inbuilt("rattata_alolan", ::RattataAlolanModel)
inbuilt("raticate_alolan", ::RaticateAlolanModel)
inbuilt("pidgey", ::PidgeyModel)
inbuilt("pidgeotto", ::PidgeottoModel)
inbuilt("diglett", ::DiglettModel)
inbuilt("dugtrio", ::DugtrioModel)
inbuilt("krabby", ::KrabbyModel)
inbuilt("paras", ::ParasModel)
inbuilt("mankey", ::MankeyModel)
@@ -243,6 +248,7 @@ object VaryingModelRepository {
inbuilt("machop", ::MachopModel)
inbuilt("machoke", ::MachokeModel)
inbuilt("machamp", ::MachampModel)
inbuilt("chansey", ::ChanseyModel)
inbuilt("cubone", ::CuboneModel)
inbuilt("dodrio", ::DodrioModel)
inbuilt("doduo", ::DoduoModel)
@@ -255,6 +261,7 @@ object VaryingModelRepository {
inbuilt("geodude", ::GeodudeModel)
inbuilt("golduck", ::GolduckModel)
inbuilt("golem", ::GolemModel)
inbuilt("graveler", ::GravelerModel)
inbuilt("hitmonchan", ::HitmonchanModel)
inbuilt("hitmonlee", ::HitmonleeModel)
inbuilt("kabuto", ::KabutoModel)
@@ -265,6 +272,9 @@ object VaryingModelRepository {
inbuilt("marowak", ::MarowakModel)
inbuilt("meowth", ::MeowthModel)
inbuilt("nidoqueen", ::NidoqueenModel)
inbuilt("nidoranf", ::NidoranfModel)
inbuilt("nidoranm", ::NidoranmModel)
inbuilt("nidorina", ::NidorinaModel)
inbuilt("nidorino", ::NidorinoModel)
inbuilt("persian", ::PersianModel)
inbuilt("pinsir", ::PinsirModel)
@@ -275,12 +285,14 @@ object VaryingModelRepository {
inbuilt("rapidash", ::RapidashModel)
inbuilt("sandslash", ::SandslashModel)
inbuilt("tangela", ::TangelaModel)
inbuilt("tentacool", ::TentacoolModel)
inbuilt("venomoth", ::VenomothModel)
inbuilt("venonat", ::VenonatModel)
inbuilt("elekid", ::ElekidModel)
inbuilt("hitmontop", ::HitmontopModel)
inbuilt("electivire", ::ElectivireModel)
inbuilt("tangrowth", ::TangrowthModel)
inbuilt("blissey", ::BlisseyModel)
inbuilt("piloswine", ::PiloswineModel)
inbuilt("quagsire", ::QuagsireModel)
inbuilt("swinub", ::SwinubModel)
@@ -329,6 +341,7 @@ object VaryingModelRepository {
inbuilt("lotad", :: LotadModel)
inbuilt("lombre", :: LombreModel)
inbuilt("ludicolo", :: LudicoloModel)
inbuilt("golett", :: GolettModel)
inbuilt("stantler", :: StantlerModel)
inbuilt("bergmite", :: BergmiteModel)
inbuilt("avalugg", :: AvaluggModel)
@@ -536,6 +549,8 @@ object VaryingModelRepository {
inbuilt("beartic", ::BearticModel)
inbuilt("dreepy", ::DreepyModel)
inbuilt("drakloak", ::DrakloakModel)
inbuilt("diglett_alolan", ::DiglettAlolanModel)
inbuilt("dugtrio_alolan", ::DugtrioAlolanModel)
inbuilt("makuhita", ::MakuhitaModel)
inbuilt("hariyama", ::HariyamaModel)
inbuilt("alomomola", ::AlomomolaModel)
@@ -45,9 +45,6 @@ object GiveAllPokemon {
val orderedSpeces = PokemonSpecies.implemented.sortedBy { it.nationalPokedexNumber }
for (species in orderedSpeces) {
if (species.nationalPokedexNumber !in range) {
continue
}
val pokemon = species.create()
pokemon.setOriginalTrainer(player.uuid)
pc.add(pokemon)//.sendOut(player.level() as ServerWorld, player.pos)
@@ -14,6 +14,7 @@ import com.bedrockk.molang.runtime.value.MoValue
import com.cobblemon.mod.common.Cobblemon
import com.cobblemon.mod.common.CobblemonMemories
import com.cobblemon.mod.common.CobblemonSounds
import com.cobblemon.mod.common.OrientationControllable
import com.cobblemon.mod.common.api.entity.PokemonSender
import com.cobblemon.mod.common.api.entity.PokemonSideDelegate
import com.cobblemon.mod.common.api.molang.MoLangFunctions.addPokemonEntityFunctions
@@ -30,6 +31,7 @@ import com.cobblemon.mod.common.pokemon.Pokemon
import com.cobblemon.mod.common.pokemon.activestate.ActivePokemonState
import com.cobblemon.mod.common.pokemon.activestate.SentOutState
import com.cobblemon.mod.common.util.*
import com.cobblemon.mod.common.util.math.geometry.toRadians
import com.cobblemon.mod.common.world.gamerules.CobblemonGameRules
import net.minecraft.network.chat.Component
import net.minecraft.network.syncher.EntityDataAccessor
@@ -41,6 +43,8 @@ import net.minecraft.world.entity.ai.attributes.Attributes
import net.minecraft.world.item.ItemStack
import net.minecraft.world.level.pathfinder.PathType
import net.minecraft.world.phys.Vec3
import org.joml.Matrix3f
import org.joml.Vector3f
import java.util.*
import kotlin.math.*
@@ -48,7 +52,6 @@ import kotlin.math.*
class PokemonServerDelegate : PokemonSideDelegate {
lateinit var entity: PokemonEntity
var acknowledgedHPValue = -1
var acknowledgedLevel = -1
val passengerOffsets = mutableMapOf<Int, Vec3>()
/** Mocked properties exposed to the client [PokemonEntity]. */
@@ -298,11 +301,6 @@ class PokemonServerDelegate : PokemonSideDelegate {
if (entity.ownerUUID == null) entity.ownerUUID = entity.pokemon.getOwnerUUID()
}
if (acknowledgedLevel != entity.pokemon.level) {
acknowledgedLevel = entity.pokemon.level
updateAttributes(entity.pokemon)
}
val tethering = entity.tethering
if (tethering != null && entity.pokemon.tetheringId != tethering.tetheringId) {
return entity.discard()
@@ -9,7 +9,6 @@
package com.cobblemon.mod.common.item
import com.cobblemon.mod.common.CobblemonSounds
import com.cobblemon.mod.common.block.TypeGemClusterBlock
import net.minecraft.sounds.SoundEvents
import net.minecraft.sounds.SoundSource
import net.minecraft.world.InteractionResult
@@ -30,7 +29,7 @@ class GemItem(settings: Properties, val block: Block): Item(settings) {
if (state.isFaceSturdy(world, pos, direction)) {
if (!world.getBlockState(pos.relative(direction)).isAir) return InteractionResult.FAIL
context.itemInHand.consume(1, context.player)
world.setBlockAndUpdate(pos.relative(direction), block.defaultBlockState().setValue(DirectionalBlock.FACING, direction).setValue(TypeGemClusterBlock.STAGE, 1))
world.setBlockAndUpdate(pos.relative(direction), block.defaultBlockState().setValue(DirectionalBlock.FACING, direction))
world.playSound(null, pos, CobblemonSounds.TYPE_GEM_CLUSTER_SOUNDS.placeSound, SoundSource.BLOCKS)
return InteractionResult.SUCCESS
}
@@ -316,6 +316,7 @@ object CobblemonItemGroups {
entries.accept(CobblemonItems.PASTURE)
entries.accept(CobblemonItems.TM_MACHINE)
entries.accept(CobblemonItems.DISC_SHELF)
entries.accept(CobblemonItems.HABITAT_BLOCK)
entries.accept(CobblemonItems.GILDED_CHEST)
entries.accept(CobblemonItems.YELLOW_GILDED_CHEST)
@@ -40,7 +40,7 @@ class SinisterTeaItem : Item(
val holder = inst.effect
val effect = holder.value()
if (effect.isInstantenous && (inst.duration <= 1)) {
if (effect.isInstantenous) {
effect.applyInstantenousEffect(user as? Player, null, user, inst.amplifier, 1.0)
} else {
user.addEffect(inst)
@@ -36,7 +36,7 @@ import net.minecraft.world.level.block.Block
class StatusCureItem(val itemName: String, vararg val status: Status, block: Block) : ItemNameBlockItem(block, Properties()), PokemonSelectingItem {
override val bagItem = object : BagItem {
override val itemName = this@StatusCureItem.itemName
override val returnItem = Items.GLASS_BOTTLE
override val returnItem = Items.AIR
override fun canUse(stack: ItemStack, battle: PokemonBattle, target: BattlePokemon) = canUseOnPokemon(stack, target.effectedPokemon)
override fun getShowdownInput(actor: BattleActor, battlePokemon: BattlePokemon, data: String?) = "cure_status${status.takeIf { it.isNotEmpty() }?.let { " ${it.joinToString(separator = " ") { it.showdownName } }" } ?: "" }"
}
@@ -64,7 +64,6 @@ class SpawnPokemonPacket(
var rideStamina: Float,
var isAlpha: Boolean,
var silent: Boolean,
var riders: List<Int>,
vanillaSpawnPacket: ClientboundAddEntityPacket,
) : SpawnExtraDataEntityPacket<SpawnPokemonPacket, PokemonEntity>(vanillaSpawnPacket) {
@@ -99,7 +98,6 @@ class SpawnPokemonPacket(
entity.entityData.get(PokemonEntity.RIDE_STAMINA),
entity.entityData.get(PokemonEntity.IS_ALPHA),
entity.isSilent,
entity.occupiedSeats.map { entry -> entry.value.id }.toList(),
vanillaSpawnPacket
)
@@ -136,7 +134,6 @@ class SpawnPokemonPacket(
buffer.writeFloat(rideStamina)
buffer.writeBoolean(isAlpha)
buffer.writeBoolean(silent)
buffer.writeCollection(this.riders) { pb, value -> pb.writeInt(value) }
}
override fun applyData(entity: PokemonEntity, level: ClientLevel) {
@@ -187,10 +184,6 @@ class SpawnPokemonPacket(
entity.tickSpawned = this.tickSpawned
entity.delegate.updateAge(this.tickSpawned)
if (this.riders.isNotEmpty()) {
this.riders.forEach { level.getEntity(it)?.startRiding(entity) }
}
}
override fun checkType(entity: Entity): Boolean = entity is PokemonEntity
@@ -229,7 +222,6 @@ class SpawnPokemonPacket(
val rideStamina = buffer.readFloat()
val isAlpha = buffer.readBoolean()
val silent = buffer.readBoolean()
val riders = buffer.readList { it.readInt() }.toList()
val vanillaPacket = decodeVanillaPacket(buffer)
return SpawnPokemonPacket(
@@ -261,7 +253,6 @@ class SpawnPokemonPacket(
rideStamina,
isAlpha,
silent,
riders,
vanillaPacket
)
}
@@ -1,33 +0,0 @@
/*
* 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.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.network.RegistryFriendlyByteBuf
class SynchronizeActiveTMPacket(val tm: TechnicalMachine?): NetworkPacket<SynchronizeActiveTMPacket> {
override val id = ID
override fun encode(buffer: RegistryFriendlyByteBuf) {
buffer.writeNullable(tm?.id) { pb, value -> pb.writeResourceLocation(value) }
}
companion object {
val ID = cobblemonResource("synchronize_active_tm")
fun decode(buffer: RegistryFriendlyByteBuf): SynchronizeActiveTMPacket {
val resourceLocation = buffer.readNullable { it.readResourceLocation() }
if (resourceLocation == null) return SynchronizeActiveTMPacket(null)
val tm = TechnicalMachines.tmMap[resourceLocation]
return SynchronizeActiveTMPacket(tm)
}
}
}
@@ -327,6 +327,7 @@ open class Pokemon : ShowdownIdentifiable {
if (experienceGroup.getLevel(experience) != boundedValue || value == Cobblemon.config.maxPokemonLevel) {
experience = experienceGroup.getExperience(boundedValue)
}
// _level.emit(value)
currentHealth = ceil(hpRatio * maxHealth).coerceIn(0..maxHealth)
}
@@ -1,34 +0,0 @@
/*
* 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.pokemon.properties
import com.cobblemon.mod.common.api.properties.CustomPokemonPropertyType
object HeldItemVisibleProperty : CustomPokemonPropertyType<BooleanProperty> {
override val keys = setOf("held_item_visible")
override val needsKey = true
override fun fromString(value: String?) =
when {
value == null || value.lowercase() in listOf("true", "yes") -> heldItemVisible(true)
value.lowercase() in listOf("false", "no") -> heldItemVisible(false)
else -> null
}
fun heldItemVisible(value: Boolean) = BooleanProperty(
key = keys.first(),
value = value,
pokemonApplicator = { pokemon, _ -> pokemon.heldItemVisible = value },
entityApplicator = { pokemonEntity, _ -> pokemonEntity.pokemon.heldItemVisible = value },
pokemonMatcher = { pokemon, _ -> pokemon.heldItemVisible == value },
entityMatcher = { pokemonEntity, _ -> pokemonEntity.pokemon.heldItemVisible == value }
)
override fun examples() = setOf("yes", "no")
}
@@ -22,7 +22,7 @@ import net.minecraft.world.entity.player.Player
*
* @author whatsy
*/
class AdvancementRequirement(val requiredAdvancement: ResourceLocation) : OwnerQueryRequirement {
class AdvancementRequirement(val requiredAdvancement: ResourceLocation) : OwnerQueryRequirement() {
override fun checkPlayer(
pokemon: Pokemon,
@@ -16,7 +16,7 @@ import com.cobblemon.mod.common.pokemon.Pokemon
*
* @property possibilities A collection of possible [Requirement]s that can allow this requirement to be valid.
*/
class AnyRequirement(val possibilities: Collection<Requirement>) : Requirement {
class AnyRequirement(val possibilities: Collection<Requirement>) : Requirement() {
override fun check(pokemon: Pokemon) = this.possibilities.any { it.check(pokemon) }
companion object {
const val ADAPTER_VARIANT = "any"
@@ -21,7 +21,7 @@ import net.minecraft.world.phys.Vec3
* @author Licious
* @since March 21st, 2022
*/
class AreaRequirement : EntityQueryRequirement {
class AreaRequirement : EntityQueryRequirement() {
companion object {
const val ADAPTER_VARIANT = "area"
}
@@ -11,7 +11,7 @@ package com.cobblemon.mod.common.pokemon.requirements
import com.cobblemon.mod.common.api.pokemon.requirement.Requirement
import com.cobblemon.mod.common.pokemon.Pokemon
class AttackDefenceRatioRequirement : Requirement {
class AttackDefenceRatioRequirement : Requirement() {
companion object {
const val ADAPTER_VARIANT = "attack_defence_ratio"
}
@@ -21,7 +21,7 @@ import com.cobblemon.mod.common.pokemon.evolution.progress.LastBattleCriticalHit
* @since October 2nd, 2022
*/
@Suppress("unused", "CanBePrimaryConstructorProperty")
class BattleCriticalHitsRequirement(amount: Int) : Requirement {
class BattleCriticalHitsRequirement(amount: Int) : Requirement() {
constructor() : this(0)
@@ -24,7 +24,7 @@ import net.minecraft.world.level.biome.Biome
* @author Licious
* @since March 21st, 2022
*/
class BiomeRequirement : EntityQueryRequirement {
class BiomeRequirement : EntityQueryRequirement() {
val biomeCondition: RegistryLikeCondition<Biome>? = null
val biomeAnticondition: RegistryLikeCondition<Biome>? = null
override fun check(pokemon: Pokemon, queriedEntity: LivingEntity): Boolean {
@@ -20,7 +20,7 @@ import com.cobblemon.mod.common.pokemon.Pokemon
* @author Licious
* @since January 28th, 2023
*/
class BlocksTraveledRequirement(amount: Int) : Requirement {
class BlocksTraveledRequirement(amount: Int) : Requirement() {
constructor() : this(0)
@@ -22,7 +22,7 @@ import kotlin.random.Random
* @author Hiroku
* @since January 30th, 2026
*/
class ChanceRequirement : Requirement {
class ChanceRequirement : Requirement() {
companion object {
const val ADAPTER_VARIANT = "chance"
}
@@ -21,7 +21,7 @@ import com.cobblemon.mod.common.pokemon.evolution.progress.DamageTakenEvolutionP
* @author Licious
* @since January 27th, 2022
*/
class DamageTakenRequirement(amount: Int) : Requirement {
class DamageTakenRequirement(amount: Int) : Requirement() {
constructor() : this(0)

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