Compare commits

..
Author SHA1 Message Date
Guilherme Pereira 2e80924c68 fix broken skills 2026-06-19 12:00:08 -03:00
Guilherme Pereira 6749b39142 Merge branch 'poke-skills' into jack-pokeskills 2026-06-12 10:27:17 -03:00
Guilherme Pereira ff25416b07 Merge branch 'main' into poke-skills 2026-06-12 09:41:17 -03:00
jackowes bb81a44a11 - WIP pening pokeskills gui now on r+click and release chooses 2026-03-11 21:49:04 -05:00
jackowes 40dfca2294 - Take out icecube
- gui open on r+right click. Need to figure out how to exactly handle the choosing and displaying.
2026-03-10 22:37:23 -05:00
jackowes 5a40ced96b - bit of work on entity targeting
- the freeze is just a test
- add look at entity function
2026-03-08 23:09:06 -05:00
jackowes 3eb97b29a1 - WIP
- Delegation of pokeskill move action effects to the move that grants the effect itself.
- allow for targeting of arbitrary points in space with the current entity partcle spanwing logc.
TODO:
- add the self targeting logic.
- add out of battle entity targeting
- allow the target particles to play as if they hit.
2026-03-08 18:41:48 -05:00
jackowes d88de0b072 - Add dynamic expression to RunActionEffectKeyframe.kt that resolves at runtime to determine the action effect identifier.
- add some logging to avoid evil corporate silent json failure
- Add optional worldposition targeting to EntityParticlesActionEffectKeyframe.kt. If a target entity exists in the runtime context then ignore this but if no target entity exists and v.target vars are set then target that position with the particles.
2026-03-08 13:23:15 -05:00
jackowes 460c44248c - stoke (still needs the multiple levels and a few things ironed out) 2026-03-03 23:36:28 -06:00
jackowes a16668695c - got the sound working. need to add to the others but its just a temp sound rn anways
- add fertilizer skill logic (should I move it)
- still checking the species name wrong lol
2026-03-01 13:01:34 -06:00
jackowes fe5ebb5444 just sensed some gold and gems 2026-02-28 21:06:50 -06:00
jackowes c34e4c8bbc - iron ore locating working... it was very easy... I didn't realize the entity condition wasn't consuming a molang expression I gave it an evaluating it for t/f. oh well, had to learn all this at some point so maybe its not time wasted. it has me rambling in a commit message though. Are there character limits to commit messages?
- sound still bugged. might just be giving it an incorrect resource location?
2026-02-28 12:51:38 -06:00
jackowes 84e76a0a6d Initial iron sense logic. There's something I'm not getting with molang or action effects quite yet. 2026-02-27 23:00:57 -06:00
jackowes be70c1e8de Merge branch 'main' into poke-skills
# Conflicts:
#	common/src/main/kotlin/com/cobblemon/mod/common/CobblemonNetwork.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/api/storage/party/PlayerPartyStore.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/block/entity/PokemonPastureBlockEntity.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/pokemon/Pokemon.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/util/codec/internal/PokemonP3.kt
2026-02-26 18:12:49 -06:00
Guilherme Pereira fba40387bb add teleport poke skill 2025-11-21 01:22:20 -03:00
Guilherme Pereira 1217e6d101 Merge branch 'main' into poke-skills 2025-11-20 16:27:39 -03:00
Paul 905c410aee Added 'enabled' property to poke skills 2025-10-04 11:29:07 +10:00
Paul cea0c826c6 Merge remote-tracking branch 'origin/main' into poke-skills
# Conflicts:
#	common/src/main/kotlin/com/cobblemon/mod/common/CobblemonNetwork.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/data/CobblemonDataProvider.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/util/codec/internal/PokemonP3.kt
2025-10-03 15:50:05 +10:00
Paul dc3b17df3b conflicto fixo 2025-09-21 13:01:01 +10:00
Paul 5602dee9ac Merge remote-tracking branch 'origin/main' into poke-skills
# Conflicts:
#	common/src/main/kotlin/com/cobblemon/mod/common/api/molang/MoLangFunctions.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/keybind/keybinds/PartySendBinding.kt
2025-09-21 12:47:03 +10:00
Paul 9e4137cc20 Tighten poke skill keybind time 2025-09-01 21:19:58 +10:00
Paul c92248f6e9 Added poke skill system with example quick_ride.json skill, some GUI improvements needed 2025-09-01 12:13:07 +10:00
1231 changed files with 27185 additions and 163668 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 {} ./
+27 -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,25 @@
- 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
- Fixed a crash caused by adding enchanted items to the Resurrection Machine
### 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 +348,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 +361,7 @@
- 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
- Fixed nicknames not being applied to Pokémon spawned from `spawn_pool_world` files
### Molang & Datapacks
- Added `moveset_builders` datapack folder for different styles of movesets.
@@ -420,7 +372,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 +462,6 @@
- German
- Spanish
- Ecuadorian Spanish
- Portuguese
- Brazilian Portuguese
- Simplified Chinese
- Traditional Chinese
@@ -12,6 +12,7 @@ import com.cobblemon.mod.common.Cobblemon;
import com.cobblemon.mod.common.OrientationControllable;
import com.cobblemon.mod.common.api.orientation.OrientationController;
import com.cobblemon.mod.common.client.CobblemonClient;
import com.cobblemon.mod.common.client.gui.interact.wheel.InteractWheelGuiFactoryKt;
import com.cobblemon.mod.common.client.keybind.keybinds.PartySendBinding;
import com.cobblemon.mod.common.client.keybind.keybinds.RidingFreelookBinding;
import com.cobblemon.mod.common.duck.RidePassenger;
@@ -67,6 +68,39 @@ public abstract class MouseHandlerMixin {
@Unique private double cobblemon$timeDelta;
@Inject(
method = "onPress",
at = @At("HEAD"),
cancellable = true
)
public void cobblemon$pokeskillGuiControl(long windowPointer, int button, int action, int modifiers, CallbackInfo ci) {
if (button == 0 && action == 1) {
// Make sure no menus are open already
if (this.minecraft.screen == null && this.minecraft.getOverlay() == null) {
// Check to see if party key is held
if (PartySendBinding.INSTANCE.getWasDown()) {
// Don't want to send out a pokemon if we let go of the key
PartySendBinding.INSTANCE.actioned();
//Open the actual gui
var player = Minecraft.getInstance().player;
var storage = CobblemonClient.INSTANCE.getStorage();
var selectedPokemon = storage.getParty().get(storage.getSelectedSlot());
if (selectedPokemon != null && player != null) {
//canApplyChange = false
var gui = InteractWheelGuiFactoryKt.createPokeSkillGui(player, selectedPokemon);
Minecraft.getInstance().setScreen(gui);
}
// Stop the rest of minecraft click logic like punching and using items
ci.cancel();
}
}
}
}
@Inject(
method = "onScroll",
at = @At(
@@ -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
@@ -24,27 +24,13 @@ import com.cobblemon.mod.common.client.net.data.RideSettingsSyncHandler
import com.cobblemon.mod.common.client.net.debug.OpenRidingStatsDebugGUIHandler
import com.cobblemon.mod.common.client.net.dialogue.DialogueClosedHandler
import com.cobblemon.mod.common.client.net.dialogue.DialogueOpenedHandler
import com.cobblemon.mod.common.client.net.effect.PokeSnackBlockParticlesHandler
import com.cobblemon.mod.common.client.net.effect.RunPosableMoLangHandler
import com.cobblemon.mod.common.client.net.effect.SaccharineLogBlockParticlesHandler
import com.cobblemon.mod.common.client.net.effect.SpawnSnowstormEntityParticleHandler
import com.cobblemon.mod.common.client.net.effect.SpawnSnowstormParticleHandler
import com.cobblemon.mod.common.client.net.gui.ExpGainedDataPacketHandler
import com.cobblemon.mod.common.client.net.gui.InteractPokemonUIPacketHandler
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.effect.*
import com.cobblemon.mod.common.client.net.gui.*
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
import com.cobblemon.mod.common.client.net.orientation.ClientboundUpdateOrientationHandler
import com.cobblemon.mod.common.client.net.pasture.ClosePastureHandler
import com.cobblemon.mod.common.client.net.pasture.OpenPastureHandler
import com.cobblemon.mod.common.client.net.pasture.PokemonPasturedHandler
import com.cobblemon.mod.common.client.net.pasture.PokemonUnpasturedHandler
import com.cobblemon.mod.common.client.net.pasture.UpdatePastureConflictFlagHandler
import com.cobblemon.mod.common.client.net.pasture.*
import com.cobblemon.mod.common.client.net.pokedex.ServerConfirmedRegisterHandler
import com.cobblemon.mod.common.client.net.pokemon.update.ClientboundSeatAssignmentPacketHandler
import com.cobblemon.mod.common.client.net.pokemon.update.ClientboundUpdateRidingStateHandler
@@ -63,14 +49,7 @@ import com.cobblemon.mod.common.client.net.storage.party.SetPartyPokemonHandler
import com.cobblemon.mod.common.client.net.storage.party.SetPartyReferenceHandler
import com.cobblemon.mod.common.client.net.storage.pc.*
import com.cobblemon.mod.common.client.net.toast.ToastPacketHandler
import com.cobblemon.mod.common.client.net.trade.TradeAcceptanceChangedHandler
import com.cobblemon.mod.common.client.net.trade.TradeCancelledHandler
import com.cobblemon.mod.common.client.net.trade.TradeCompletedHandler
import com.cobblemon.mod.common.client.net.trade.TradeOfferExpiredHandler
import com.cobblemon.mod.common.client.net.trade.TradeOfferNotificationHandler
import com.cobblemon.mod.common.client.net.trade.TradeProcessStartedHandler
import com.cobblemon.mod.common.client.net.trade.TradeStartedHandler
import com.cobblemon.mod.common.client.net.trade.TradeUpdatedHandler
import com.cobblemon.mod.common.client.net.trade.*
import com.cobblemon.mod.common.net.PacketRegisterInfo
import com.cobblemon.mod.common.net.messages.client.OpenBehaviourEditorPacket
import com.cobblemon.mod.common.net.messages.client.PlayerInteractOptionsPacket
@@ -86,21 +65,13 @@ import com.cobblemon.mod.common.net.messages.client.data.*
import com.cobblemon.mod.common.net.messages.client.debug.RequestOpenRidingStatsDebugGUIPacket
import com.cobblemon.mod.common.net.messages.client.dialogue.DialogueClosedPacket
import com.cobblemon.mod.common.net.messages.client.dialogue.DialogueOpenedPacket
import com.cobblemon.mod.common.net.messages.client.effect.PokeSnackBlockParticlesPacket
import com.cobblemon.mod.common.net.messages.client.effect.RunPosableMoLangPacket
import com.cobblemon.mod.common.net.messages.client.effect.SaccharineLogBlockParticlesPacket
import com.cobblemon.mod.common.net.messages.client.effect.SpawnSnowstormEntityParticlePacket
import com.cobblemon.mod.common.net.messages.client.effect.SpawnSnowstormParticlePacket
import com.cobblemon.mod.common.net.messages.client.effect.*
import com.cobblemon.mod.common.net.messages.client.habitat.OpenHabitatBlockEditorPacket
import com.cobblemon.mod.common.net.messages.client.npc.CloseNPCEditorPacket
import com.cobblemon.mod.common.net.messages.client.npc.OpenNPCEditorPacket
import com.cobblemon.mod.common.net.messages.client.orientation.ClientboundUpdateDriverInputPacket
import com.cobblemon.mod.common.net.messages.client.orientation.ClientboundUpdateOrientationPacket
import com.cobblemon.mod.common.net.messages.client.pasture.ClosePasturePacket
import com.cobblemon.mod.common.net.messages.client.pasture.OpenPasturePacket
import com.cobblemon.mod.common.net.messages.client.pasture.PokemonPasturedPacket
import com.cobblemon.mod.common.net.messages.client.pasture.PokemonUnpasturedPacket
import com.cobblemon.mod.common.net.messages.client.pasture.UpdatePastureConflictFlagPacket
import com.cobblemon.mod.common.net.messages.client.pasture.*
import com.cobblemon.mod.common.net.messages.client.pokedex.ServerConfirmedRegisterPacket
import com.cobblemon.mod.common.net.messages.client.pokemon.update.*
import com.cobblemon.mod.common.net.messages.client.pokemon.update.evolution.AddEvolutionPacket
@@ -121,47 +92,17 @@ import com.cobblemon.mod.common.net.messages.client.storage.party.InitializePart
import com.cobblemon.mod.common.net.messages.client.storage.party.MoveClientPartyPokemonPacket
import com.cobblemon.mod.common.net.messages.client.storage.party.SetPartyPokemonPacket
import com.cobblemon.mod.common.net.messages.client.storage.party.SetPartyReferencePacket
import com.cobblemon.mod.common.net.messages.client.storage.pc.ClosePCPacket
import com.cobblemon.mod.common.net.messages.client.storage.pc.InitializePCPacket
import com.cobblemon.mod.common.net.messages.client.storage.pc.MoveClientPCPokemonPacket
import com.cobblemon.mod.common.net.messages.client.storage.pc.OpenPCPacket
import com.cobblemon.mod.common.net.messages.client.storage.pc.RenamePCBoxPacket
import com.cobblemon.mod.common.net.messages.client.storage.pc.SetPCBoxPacket
import com.cobblemon.mod.common.net.messages.client.storage.pc.SetPCPokemonPacket
import com.cobblemon.mod.common.net.messages.client.storage.pc.*
import com.cobblemon.mod.common.net.messages.client.storage.pc.wallpaper.ChangePCBoxWallpaperPacket
import com.cobblemon.mod.common.net.messages.client.storage.pc.wallpaper.RequestPCBoxWallpapersPacket
import com.cobblemon.mod.common.net.messages.client.storage.pc.wallpaper.SetPCBoxWallpapersPacket
import com.cobblemon.mod.common.net.messages.client.storage.pc.wallpaper.UnlockPCBoxWallpaperPacket
import com.cobblemon.mod.common.net.messages.client.tms.TechnicalMachineRegistrySyncPacket
import com.cobblemon.mod.common.net.messages.client.toast.ToastPacket
import com.cobblemon.mod.common.net.messages.client.trade.TradeAcceptanceChangedPacket
import com.cobblemon.mod.common.net.messages.client.trade.TradeCancelledPacket
import com.cobblemon.mod.common.net.messages.client.trade.TradeCompletedPacket
import com.cobblemon.mod.common.net.messages.client.trade.TradeOfferExpiredPacket
import com.cobblemon.mod.common.net.messages.client.trade.TradeOfferNotificationPacket
import com.cobblemon.mod.common.net.messages.client.trade.TradeProcessStartedPacket
import com.cobblemon.mod.common.net.messages.client.trade.TradeStartedPacket
import com.cobblemon.mod.common.net.messages.client.trade.TradeUpdatedPacket
import com.cobblemon.mod.common.net.messages.client.ui.ExpGainedDataPacket
import com.cobblemon.mod.common.net.messages.client.ui.InteractPokemonUIPacket
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
import com.cobblemon.mod.common.net.messages.server.RequestMoveSwapPacket
import com.cobblemon.mod.common.net.messages.server.RequestPlayerInteractionsPacket
import com.cobblemon.mod.common.net.messages.server.SelectStarterPacket
import com.cobblemon.mod.common.net.messages.server.SendOutPokemonPacket
import com.cobblemon.mod.common.net.messages.server.battle.BattleSelectActionsPacket
import com.cobblemon.mod.common.net.messages.server.battle.BattleTeamLeavePacket
import com.cobblemon.mod.common.net.messages.server.battle.BattleTeamRequestPacket
import com.cobblemon.mod.common.net.messages.server.battle.BattleTeamResponsePacket
import com.cobblemon.mod.common.net.messages.server.battle.RemoveSpectatorPacket
import com.cobblemon.mod.common.net.messages.server.battle.SpectateBattlePacket
import com.cobblemon.mod.common.net.messages.client.trade.*
import com.cobblemon.mod.common.net.messages.client.ui.*
import com.cobblemon.mod.common.net.messages.server.*
import com.cobblemon.mod.common.net.messages.server.battle.*
import com.cobblemon.mod.common.net.messages.server.behaviour.DamageOnCollisionPacket
import com.cobblemon.mod.common.net.messages.server.behaviour.SetEntityBehaviourPacket
import com.cobblemon.mod.common.net.messages.server.block.AdjustBlockEntityViewerCountPacket
@@ -188,11 +129,7 @@ import com.cobblemon.mod.common.net.messages.server.pasture.UnpasturePokemonPack
import com.cobblemon.mod.common.net.messages.server.pokedex.scanner.FinishScanningPacket
import com.cobblemon.mod.common.net.messages.server.pokedex.scanner.StartScanningPacket
import com.cobblemon.mod.common.net.messages.server.pokemon.interact.InteractPokemonPacket
import com.cobblemon.mod.common.net.messages.server.pokemon.update.ServerboundUpdateRidingStatePacket
import com.cobblemon.mod.common.net.messages.server.pokemon.update.SetActiveMarkPacket
import com.cobblemon.mod.common.net.messages.server.pokemon.update.SetItemHiddenPacket
import com.cobblemon.mod.common.net.messages.server.pokemon.update.SetMarkingsPacket
import com.cobblemon.mod.common.net.messages.server.pokemon.update.SetNicknamePacket
import com.cobblemon.mod.common.net.messages.server.pokemon.update.*
import com.cobblemon.mod.common.net.messages.server.pokemon.update.evolution.AcceptEvolutionPacket
import com.cobblemon.mod.common.net.messages.server.riding.DismountPokemonPacket
import com.cobblemon.mod.common.net.messages.server.riding.ServerboundUpdateDriverInputPacket
@@ -205,21 +142,12 @@ import com.cobblemon.mod.common.net.messages.server.storage.party.PartyTutorialP
import com.cobblemon.mod.common.net.messages.server.storage.party.ReleasePartyPokemonPacket
import com.cobblemon.mod.common.net.messages.server.storage.party.SwapPartyPokemonPacket
import com.cobblemon.mod.common.net.messages.server.storage.pc.*
import com.cobblemon.mod.common.net.messages.server.trade.AcceptTradeRequestPacket
import com.cobblemon.mod.common.net.messages.server.trade.CancelTradePacket
import com.cobblemon.mod.common.net.messages.server.trade.ChangeTradeAcceptancePacket
import com.cobblemon.mod.common.net.messages.server.trade.OfferTradePacket
import com.cobblemon.mod.common.net.messages.server.trade.PerformTradePacket
import com.cobblemon.mod.common.net.messages.server.trade.UpdateTradeOfferPacket
import com.cobblemon.mod.common.net.messages.server.trade.*
import com.cobblemon.mod.common.net.serverhandling.ChallengeHandler
import com.cobblemon.mod.common.net.serverhandling.ChallengeResponseHandler
import com.cobblemon.mod.common.net.serverhandling.RequestInteractionsHandler
import com.cobblemon.mod.common.net.serverhandling.battle.BattleSelectActionsHandler
import com.cobblemon.mod.common.net.serverhandling.battle.RemoveSpectatorHandler
import com.cobblemon.mod.common.net.serverhandling.battle.SpectateBattleHandler
import com.cobblemon.mod.common.net.serverhandling.battle.TeamLeaveHandler
import com.cobblemon.mod.common.net.serverhandling.battle.TeamRequestHandler
import com.cobblemon.mod.common.net.serverhandling.battle.TeamRequestResponseHandler
import com.cobblemon.mod.common.net.serverhandling.UsePokeSkillHandler
import com.cobblemon.mod.common.net.serverhandling.battle.*
import com.cobblemon.mod.common.net.serverhandling.behaviour.DamageOnCollisionPacketHandler
import com.cobblemon.mod.common.net.serverhandling.behaviour.SetEntityBehaviourHandler
import com.cobblemon.mod.common.net.serverhandling.block.AdjustBlockEntityViewerCountHandler
@@ -247,11 +175,7 @@ import com.cobblemon.mod.common.net.serverhandling.pasture.UnpasturePokemonHandl
import com.cobblemon.mod.common.net.serverhandling.pokedex.scanner.FinishScanningHandler
import com.cobblemon.mod.common.net.serverhandling.pokedex.scanner.StartScanningHandler
import com.cobblemon.mod.common.net.serverhandling.pokemon.interact.InteractPokemonHandler
import com.cobblemon.mod.common.net.serverhandling.pokemon.update.ServerboundUpdateRidingStateHandler
import com.cobblemon.mod.common.net.serverhandling.pokemon.update.SetActiveMarkHandler
import com.cobblemon.mod.common.net.serverhandling.pokemon.update.SetItemHiddenHandler
import com.cobblemon.mod.common.net.serverhandling.pokemon.update.SetMarkingsHandler
import com.cobblemon.mod.common.net.serverhandling.pokemon.update.SetNicknameHandler
import com.cobblemon.mod.common.net.serverhandling.pokemon.update.*
import com.cobblemon.mod.common.net.serverhandling.riding.DismountPokemonPacketHandler
import com.cobblemon.mod.common.net.serverhandling.riding.DriverInputPacketHandler
import com.cobblemon.mod.common.net.serverhandling.riding.ServerboundUpdatePassengerPositionHandler
@@ -267,12 +191,7 @@ import com.cobblemon.mod.common.net.serverhandling.storage.party.PartyTutorialPa
import com.cobblemon.mod.common.net.serverhandling.storage.party.ReleasePCPokemonHandler
import com.cobblemon.mod.common.net.serverhandling.storage.party.SwapPartyPokemonHandler
import com.cobblemon.mod.common.net.serverhandling.storage.pc.*
import com.cobblemon.mod.common.net.serverhandling.trade.AcceptTradeRequestHandler
import com.cobblemon.mod.common.net.serverhandling.trade.CancelTradeHandler
import com.cobblemon.mod.common.net.serverhandling.trade.ChangeTradeAcceptanceHandler
import com.cobblemon.mod.common.net.serverhandling.trade.OfferTradeHandler
import com.cobblemon.mod.common.net.serverhandling.trade.PerformTradeHandler
import com.cobblemon.mod.common.net.serverhandling.trade.UpdateTradeOfferHandler
import com.cobblemon.mod.common.net.serverhandling.trade.*
import com.cobblemon.mod.common.util.server
import net.minecraft.server.level.ServerPlayer
@@ -342,6 +261,7 @@ object CobblemonNetwork {
list.add(PacketRegisterInfo(MarkingsUpdatePacket.ID, MarkingsUpdatePacket::decode, PokemonUpdatePacketHandler()))
list.add(PacketRegisterInfo(RideBoostsUpdatePacket.ID, RideBoostsUpdatePacket::decode, PokemonUpdatePacketHandler()))
list.add(PacketRegisterInfo(RideStaminaUpdatePacket.ID, RideStaminaUpdatePacket::decode, PokemonUpdatePacketHandler()))
list.add(PacketRegisterInfo(SkillCooldownsUpdatePacket.ID, SkillCooldownsUpdatePacket::decode, PokemonUpdatePacketHandler()))
list.add(PacketRegisterInfo(AlphaUpdatePacket.ID, AlphaUpdatePacket::decode, PokemonUpdatePacketHandler()))
list.add(PacketRegisterInfo(ScaleModifierUpdatePacket.ID, ScaleModifierUpdatePacket::decode, PokemonUpdatePacketHandler()))
@@ -377,7 +297,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))
@@ -443,6 +362,7 @@ object CobblemonNetwork {
list.add(PacketRegisterInfo(BehaviourSyncPacket.ID, BehaviourSyncPacket::decode, DataRegistrySyncPacketHandler()))
list.add(PacketRegisterInfo(MarkRegistrySyncPacket.ID, MarkRegistrySyncPacket::decode, DataRegistrySyncPacketHandler()))
list.add(PacketRegisterInfo(RideSettingsSyncPacket.ID, RideSettingsSyncPacket::decode, RideSettingsSyncHandler))
list.add(PacketRegisterInfo(PokeSkillsRegistrySyncPacket.ID, PokeSkillsRegistrySyncPacket::decode, DataRegistrySyncPacketHandler()))
list.add(PacketRegisterInfo(TechnicalMachineRegistrySyncPacket.ID, TechnicalMachineRegistrySyncPacket::decode, DataRegistrySyncPacketHandler()))
// Effects
@@ -535,6 +455,7 @@ object CobblemonNetwork {
// Interaction Packets
list.add(PacketRegisterInfo(InteractPokemonPacket.ID, InteractPokemonPacket::decode, InteractPokemonHandler))
list.add(PacketRegisterInfo(RequestPlayerInteractionsPacket.ID, RequestPlayerInteractionsPacket::decode, RequestInteractionsHandler))
list.add(PacketRegisterInfo(UsePokeSkillPacket.ID, UsePokeSkillPacket::decode, UsePokeSkillHandler))
// Storage Packets
list.add(PacketRegisterInfo(SendOutPokemonPacket.ID, SendOutPokemonPacket::decode, SendOutPokemonHandler))
@@ -0,0 +1,68 @@
/*
* 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
import com.cobblemon.mod.common.CobblemonNetwork.sendPacket
import com.cobblemon.mod.common.api.data.JsonDataRegistry
import com.cobblemon.mod.common.api.molang.ExpressionLike
import com.cobblemon.mod.common.api.moves.animations.ActionEffectTimeline
import com.cobblemon.mod.common.api.reactive.SimpleObservable
import com.cobblemon.mod.common.entity.pokemon.PokeSkill
import com.cobblemon.mod.common.net.messages.client.data.PokeSkillsRegistrySyncPacket
import com.cobblemon.mod.common.pokemon.Pokemon
import com.cobblemon.mod.common.util.adapters.ActionEffectTimelineAdapter
import com.cobblemon.mod.common.util.adapters.ExpressionLikeAdapter
import com.cobblemon.mod.common.util.adapters.IdentifierAdapter
import com.cobblemon.mod.common.util.adapters.TextAdapter
import com.cobblemon.mod.common.util.cobblemonResource
import com.google.gson.GsonBuilder
import com.google.gson.reflect.TypeToken
import net.minecraft.network.chat.Component
import net.minecraft.resources.ResourceLocation
import net.minecraft.server.level.ServerPlayer
import net.minecraft.server.packs.PackType
import net.minecraft.world.entity.player.Player
/**
* The JSON data registry for all the possible [PokeSkill]s.
*
* @author Hiroku
* @since August 31st, 2025
*/
object CobblemonPokeSkills : JsonDataRegistry<PokeSkill> {
override val id = cobblemonResource("poke_skills")
override val type = PackType.SERVER_DATA
override val observable = SimpleObservable<CobblemonPokeSkills>()
override val typeToken = TypeToken.get(PokeSkill::class.java)
override val resourcePath = "poke_skills"
override val gson = GsonBuilder()
.setPrettyPrinting()
.registerTypeAdapter(ExpressionLike::class.java, ExpressionLikeAdapter)
.registerTypeAdapter(ActionEffectTimeline::class.java, ActionEffectTimelineAdapter)
.registerTypeAdapter(ResourceLocation::class.java, IdentifierAdapter)
.registerTypeAdapter(Component::class.java, TextAdapter)
.create()
var skills = mapOf<ResourceLocation, PokeSkill>()
fun getAccessibleSkills(player: Player, pokemon: Pokemon): List<PokeSkill> {
return skills.values.filter { it.canAccess(player, pokemon) }
}
override fun reload(data: Map<ResourceLocation, PokeSkill>) {
data.forEach { (id, skill) -> skill.id = id }
skills = data
observable.emit(this)
Cobblemon.LOGGER.info("Loaded ${skills.size} PokéSkills")
}
override fun sync(player: ServerPlayer) {
player.sendPacket(PokeSkillsRegistrySyncPacket(skills.values.toList()))
}
}
@@ -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
}
@@ -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()
@@ -293,11 +293,11 @@ object MoLangFunctions {
)
value.functions["is_in"] = Function put@{ params: MoParams ->
val tag = TagKey.create(key, ResourceLocation.parse(params.getString(0).replace("#", "")))
return@put DoubleValue(if (value.obj.`is`(tag)) 1.0 else 0.0)
return@put DoubleValue(value.obj.`is`(tag))
}
value.functions["is_of"] = Function put@{ params: MoParams ->
val identifier = ResourceLocation.parse(params.getString(0))
return@put DoubleValue(if (value.obj.`is`(identifier)) 1.0 else 0.0)
return@put DoubleValue(value.obj.`is`(identifier))
}
return value
}
@@ -25,7 +25,7 @@ object DropEntryMoLangFunctions : AbstractMoLangFunctionHolder<DropEntry>() {
map["max_selectable_times"] = { DoubleValue(drop.maxSelectableTimes.toDouble()) }
map["can_drop"] = { params ->
val pokemon = params.getOrNull<ObjectValue<Pokemon>>(0)?.obj
DoubleValue(if (drop.canDrop(pokemon)) 1.0 else 0.0)
DoubleValue(drop.canDrop(pokemon))
}
return map
}
@@ -35,12 +35,14 @@ import com.cobblemon.mod.common.util.effectiveName
import com.cobblemon.mod.common.util.getBlockStatesWithPos
import com.cobblemon.mod.common.util.getBooleanOrNull
import com.cobblemon.mod.common.util.getDoubleOrNull
import com.cobblemon.mod.common.util.getIntOrNull
import com.cobblemon.mod.common.util.getIsSubmerged
import com.cobblemon.mod.common.util.getOrNull
import com.cobblemon.mod.common.util.getStringOrNull
import com.cobblemon.mod.common.util.isStandingOn
import com.cobblemon.mod.common.util.resolve
import com.cobblemon.mod.common.util.worldRegistry
import net.minecraft.core.BlockPos
import net.minecraft.core.registries.Registries
import net.minecraft.server.level.ServerLevel
import net.minecraft.server.level.ServerPlayer
@@ -48,7 +50,10 @@ import net.minecraft.tags.TagKey
import net.minecraft.world.damagesource.DamageSource
import net.minecraft.world.damagesource.DamageTypes
import net.minecraft.world.entity.Entity
import net.minecraft.world.entity.LivingEntity
import net.minecraft.world.entity.TamableAnimal
import net.minecraft.world.level.block.BonemealableBlock
import net.minecraft.world.level.block.CropBlock
import net.minecraft.world.phys.AABB
import net.minecraft.world.phys.Vec3
import java.util.UUID
@@ -78,8 +83,13 @@ object EntityMoLangFunctions : AbstractMoLangFunctionHolder<Entity>() {
"vertical_velocity" to { DoubleValue(thisEntity.deltaMovement.y) },
"is_on_ground" to { _ -> DoubleValue(thisEntity.onGround()) },
"world" to { _ -> thisEntity.level().worldRegistry.wrapAsHolder(thisEntity.level()).asWorldMoLangValue() },
"dimension" to { StringValue(thisEntity.level().dimension().location().toString()) },
"biome" to { _ -> thisEntity.level().getBiome(thisEntity.blockPosition()).asBiomeMoLangValue() },
"is_passenger" to { DoubleValue(thisEntity.isPassenger) },
"is_passenger" to isPassenger@{ params ->
val passengerEntity = (params.get<MoValue>(0) as? ObjectValue<*>)?.obj as? LivingEntity ?: return@isPassenger DoubleValue.ZERO
DoubleValue(passengerEntity in thisEntity.passengers)
},
"discard" to { thisEntity.discard() },
"is_sneaking" to { _ -> DoubleValue(thisEntity.isShiftKeyDown) },
"is_sprinting" to { _ -> DoubleValue(thisEntity.isSprinting) },
@@ -121,6 +131,62 @@ object EntityMoLangFunctions : AbstractMoLangFunctionHolder<Entity>() {
listOf(thisEntity.deltaMovement.x, thisEntity.deltaMovement.y, thisEntity.deltaMovement.z)
.asArrayValue(::DoubleValue)
},
"set_position" to { params ->
val x = params.getDouble(0)
val y = params.getDouble(1)
val z = params.getDouble(2)
thisEntity.setPos(x, y, z)
DoubleValue.ONE
},
"fertilize_nearby_crops" to { params -> //TODO: pretty bespoke. Maybe should be moved or generalized?
val radius = params.getIntOrNull(0) ?: 8
val maxCrops = params.getIntOrNull(1) ?: 8
var fertilizedCount = 0
val level = thisEntity.level()
val centerPos = thisEntity.blockPosition()
// Find all bonemealable blocks within radius
val bonemealableBlocks = mutableListOf<BlockPos>()
for (x in -radius..radius) {
for (y in -3..3) { // Limited vertical range
for (z in -radius..radius) {
val pos = centerPos.offset(x, y, z)
val blockState = level.getBlockState(pos)
val block = blockState.block
// Check if block can be bonemealed
if (block is BonemealableBlock && block is CropBlock && block.isValidBonemealTarget(level, pos, blockState)) {
bonemealableBlocks.add(pos)
}
}
}
}
// Shuffle and take up to maxCrops blocks to fertilize
bonemealableBlocks.shuffle()
val blocksToFertilize = bonemealableBlocks.take(maxCrops)
for (pos in blocksToFertilize) {
val blockState = level.getBlockState(pos)
val block = blockState.block
if (block is BonemealableBlock && block.isValidBonemealTarget(level, pos, blockState)) {
if (block.isBonemealSuccess(level, level.random, pos, blockState)) {
block.performBonemeal(level as ServerLevel, level.random, pos, blockState)
// Add bonemeal particle
val particlePos = block.getParticlePos(pos)
level.levelEvent(1505, particlePos, 15) // Same event used for bonemealing in vanilla
fertilizedCount++
}
}
}
DoubleValue(fertilizedCount.toDouble())
},
"tags" to {
val tags = thisEntity.tags
val array = ArrayStruct(hashMapOf())
@@ -233,7 +299,7 @@ object EntityMoLangFunctions : AbstractMoLangFunctionHolder<Entity>() {
val intangible = params.getBooleanOrNull(0) ?: true
thisEntity.noPhysics = intangible
DoubleValue.ONE
}
},
)
@@ -39,6 +39,7 @@ import net.minecraft.world.entity.Mob
import net.minecraft.world.entity.PathfinderMob
import net.minecraft.world.entity.TamableAnimal
import net.minecraft.world.entity.ai.behavior.BlockPosTracker
import net.minecraft.world.entity.ai.behavior.EntityTracker
import net.minecraft.world.entity.ai.memory.MemoryModuleType
import net.minecraft.world.entity.ai.memory.MemoryStatus
import net.minecraft.world.entity.ai.memory.WalkTarget
@@ -123,6 +124,23 @@ object LivingEntityMoLangFunctions : AbstractMoLangFunctionHolder<LivingEntity>(
duration.toLong()
)
}
map["look_at_entity"] = put@{ params ->
val targetEntity = params.get<MoValue>(0)
val duration = params.getDoubleOrNull(1)?.toInt() ?: 20
val lookEntity = if (targetEntity is ObjectValue<*> && targetEntity.obj is Entity) {
targetEntity.obj as Entity
} else {
return@put DoubleValue.ZERO
}
// Set the current entity to track the looked for entity
val brain = entity.brain
val tracker = EntityTracker(lookEntity, true)
brain.setMemoryWithExpiry(MemoryModuleType.LOOK_TARGET, tracker, duration.toLong())
DoubleValue.ONE
}
map["get_wander_control_memory"] = put@{
val value = entity.brain.getMemorySafely(CobblemonMemories.WANDER_CONTROL).orElse(null)
?: CobblemonWanderControl()
@@ -17,14 +17,13 @@ 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
import com.cobblemon.mod.common.api.text.text
import com.cobblemon.mod.common.battles.BattleBuilder
import com.cobblemon.mod.common.battles.BattleFormat
import com.cobblemon.mod.common.client.CobblemonClient
import com.cobblemon.mod.common.entity.npc.NPCEntity
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
import com.cobblemon.mod.common.net.messages.client.battle.BattleMusicPacket
@@ -34,6 +33,7 @@ import com.cobblemon.mod.common.util.activeDialogue
import com.cobblemon.mod.common.util.asBlockPos
import com.cobblemon.mod.common.util.asResource
import com.cobblemon.mod.common.util.asUUID
import com.cobblemon.mod.common.util.blockRegistry
import com.cobblemon.mod.common.util.getBattleState
import com.cobblemon.mod.common.util.getBooleanOrNull
import com.cobblemon.mod.common.util.getDoubleOrNull
@@ -46,15 +46,19 @@ 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 com.cobblemon.mod.common.util.toArrayStruct
import net.minecraft.client.player.AbstractClientPlayer
import net.minecraft.core.registries.BuiltInRegistries
import net.minecraft.core.registries.Registries
import net.minecraft.resources.ResourceLocation
import net.minecraft.server.level.ServerPlayer
import net.minecraft.sounds.SoundSource
import net.minecraft.world.entity.Entity
import net.minecraft.world.entity.player.Player
import net.minecraft.world.item.ItemStack
import net.minecraft.world.level.ClipContext
import net.minecraft.world.level.GameType
import net.minecraft.world.phys.HitResult
import kotlin.collections.iterator
object PlayerMoLangFunctions : AbstractMoLangFunctionHolder<Player>() {
@@ -315,23 +319,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<*>) {
@@ -399,6 +386,61 @@ object PlayerMoLangFunctions : AbstractMoLangFunctionHolder<Player>() {
} ?: DoubleValue.ZERO
}
map["has_chosen_starter"] = { _ -> DoubleValue(Cobblemon.playerDataManager.getGenericData(player).starterSelected) }
map["ride"] = put@{ params ->
val entity = (params.get<MoValue>(0) as? ObjectValue<*>)?.obj as? Entity ?: return@put DoubleValue.ZERO
player.startRiding(entity)
}
map["has_respawn_position"] = {
DoubleValue(player.respawnPosition != null)
}
map["respawn_position"] = {
player.respawnPosition?.toArrayStruct() ?: DoubleValue.ZERO
}
map["respawn_dimension"] = {
StringValue(player.respawnDimension.location().toString())
}
map["teleport_to_respawn"] = put@{
val respawnPosition = player.respawnPosition?.center ?: return@put DoubleValue.ZERO
player.teleportTo(respawnPosition.x, respawnPosition.y, respawnPosition.z)
DoubleValue.ONE
}
map["get_looked_block"] = put@{ params ->
// Get the block the player is looking at 'distance' units away
val distance = params.getDoubleOrNull(0) ?: 8.0
// perform clip
val level = player.level()
val eye = player.eyePosition
val view = player.getViewVector(1.0f)
val lookPos = eye.add(view.scale(distance))
val hitResult = level.clip(ClipContext(eye, lookPos, ClipContext.Block.COLLIDER, ClipContext.Fluid.NONE, player))
if (hitResult.type == HitResult.Type.BLOCK) {
// Get base block info
val blockPos = hitResult.blockPos
val blockState = level.getBlockState(blockPos)
val blockHolder = level.blockRegistry.wrapAsHolder(blockState.block)
val blockValue = blockHolder.asMoLangValue(Registries.BLOCK)
// Attach the position to the blockValue return
blockValue.addFunction("x") { DoubleValue(blockPos.x.toDouble()) }
blockValue.addFunction("y") { DoubleValue(blockPos.y.toDouble()) }
blockValue.addFunction("z") { DoubleValue(blockPos.z.toDouble()) }
return@put blockValue
} else {
return@put DoubleValue.ZERO
}
}
map["is_battling"] = {
DoubleValue(player.isInBattle())
}
}
if (player is AbstractClientPlayer) {
map["is_battling"] = {
DoubleValue(CobblemonClient.battle?.spectating == false) // Checks not-null and not-spectating at the same time, trust
}
}
return map
@@ -15,6 +15,7 @@ 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.CobblemonMovesetBuilders
import com.cobblemon.mod.common.CobblemonPokeSkills
import com.cobblemon.mod.common.api.mark.Marks
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMoLangValue
import com.cobblemon.mod.common.api.moves.BenchedMove
@@ -26,6 +27,9 @@ import com.cobblemon.mod.common.api.riding.stats.RidingStat
import com.cobblemon.mod.common.api.storage.party.PartyStore
import com.cobblemon.mod.common.pokemon.IVs
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.pokemon.activestate.ShoulderedState
import com.cobblemon.mod.common.util.asArrayValue
import com.cobblemon.mod.common.util.asIdentifierDefaultingNamespace
import com.cobblemon.mod.common.util.getBooleanOrNull
@@ -447,6 +451,29 @@ object PokemonMoLangFunctions : AbstractMoLangFunctionHolder<Pokemon>() {
evolution?.forceEvolve(pokemon)
StringValue(evolution.toString())
}
map["is_sent_out"] = {
DoubleValue(pokemon.state is SentOutState)
}
map["is_shouldered"] = {
DoubleValue(pokemon.state is ShoulderedState)
}
map["entity"] = {
(pokemon.state as? ActivePokemonState)?.entity?.struct ?: DoubleValue.ZERO
}
map["is_rideable"] = put@{
return@put DoubleValue(!pokemon.riding.behaviours.isNullOrEmpty())
}
map["has_status"] = put@{ params ->
val status = params.getString(0).asIdentifierDefaultingNamespace()
return@put DoubleValue(pokemon.status?.status?.name == status)
}
map["add_skill_cooldown"] = put@{ params ->
val skillId = params.getString(0).asIdentifierDefaultingNamespace()
val cooldownTicks = params.getIntOrNull(1)
val skill = CobblemonPokeSkills.skills[skillId] ?: return@put DoubleValue.ZERO
pokemon.addSkillCooldown(skillId, cooldownTicks ?: skill.cooldownTicks)
return@put DoubleValue.ONE
}
map["entity"] = { pokemon.entity?.asMoLangValue() ?: DoubleValue.ZERO }
map["is_alpha"] = { DoubleValue(pokemon.isAlpha) }
@@ -40,6 +40,7 @@ import net.minecraft.world.level.Level
import net.minecraft.world.level.Level.ExplosionInteraction
import net.minecraft.world.level.biome.Biome
import net.minecraft.world.level.block.Block
import net.minecraft.world.level.block.entity.AbstractFurnaceBlockEntity
import net.minecraft.world.level.levelgen.Heightmap
import net.minecraft.world.level.storage.loot.LootParams
import net.minecraft.world.level.storage.loot.parameters.LootContextParamSets
@@ -61,6 +62,26 @@ object WorldMoLangFunctions : AbstractMoLangFunctionHolder<Holder<Level>>() {
val time = world.dayTime % 24000
return@put DoubleValue(timeOfDay.contains(time.toInt()))
}
map["add_furnace_fuel"] = put@{ params ->
val x = params.getInt(0)
val y = params.getInt(1)
val z = params.getInt(2)
val fuelTicks = params.getInt(3)
val blockEntity = world.getBlockEntity(BlockPos(x, y, z))
if (blockEntity is AbstractFurnaceBlockEntity) {
// Add fuel time to the furnace
blockEntity.litTime += fuelTicks
// If this exceeds the litDuration then bump it up
if (blockEntity.litTime >= blockEntity.litDuration) {
blockEntity.litDuration = blockEntity.litTime
}
blockEntity.setChanged()
return@put DoubleValue.ONE
}
return@put DoubleValue.ZERO
}
map["game_time"] = { _ -> DoubleValue(world.gameTime.toDouble()) }
map["time_of_day"] = put@{
val time = world.dayTime % 24000
@@ -128,13 +149,13 @@ object WorldMoLangFunctions : AbstractMoLangFunctionHolder<Holder<Level>>() {
val x = params.getDouble(0)
val y = params.getDouble(1)
val z = params.getDouble(2)
val range = params.getDouble(3).toFloat()
val range = params.getDoubleOrNull(3) ?: 8.0
world.explode(
null,
x,
y,
z,
range,
range.toFloat(),
ExplosionInteraction.valueOf(
params.getStringOrNull(4)?.uppercase() ?: ExplosionInteraction.TNT.name
)
@@ -50,7 +50,7 @@ class ActionEffectTimeline(
}
fun chainKeyframes(context: ActionEffectContext, iterator: Iterator<ActionEffectKeyframe>, finalFuture: CompletableFuture<Unit>) {
if (!iterator.hasNext()) {
if (!iterator.hasNext() || context.cancelled) {
finalFuture.complete(Unit)
} else {
val keyframe = iterator.next()
@@ -70,6 +70,7 @@ class ActionEffectContext(
val runtime: MoLangRuntime,
var canBeInterrupted: Boolean = false,
var interrupted: Boolean = false,
var cancelled: Boolean = false,
var currentKeyframes: MutableList<ActionEffectKeyframe> = mutableListOf(),
var level: Level? = null
) {
@@ -57,6 +57,7 @@ object ActionEffects : JsonDataRegistry<ActionEffectTimeline> {
ActionEffectKeyframe.register<RunActionEffectKeyframe>("run_action_effect")
ActionEffectKeyframe.register<EntityParticlesActionEffectKeyframe>("entity_particles")
ActionEffectKeyframe.register<EntitySoundActionEffectKeyframe>("entity_sound")
ActionEffectKeyframe.register<CancelActionEffectKeyframe>("cancel")
}
override val gson = GsonBuilder()
@@ -0,0 +1,19 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.api.moves.animations.keyframes
import com.cobblemon.mod.common.api.moves.animations.ActionEffectContext
import java.util.concurrent.CompletableFuture
class CancelActionEffectKeyframe : ConditionalActionEffectKeyframe() {
override fun playWhenTrue(context: ActionEffectContext): CompletableFuture<Unit> {
context.cancelled = true
return CompletableFuture.completedFuture(Unit)
}
}
@@ -21,6 +21,7 @@ import com.cobblemon.mod.common.util.asIdentifierDefaultingNamespace
import net.minecraft.commands.arguments.EntityArgument.getPlayers
import java.util.concurrent.CompletableFuture
import net.minecraft.server.level.ServerLevel
import net.minecraft.world.phys.Vec3
/**
* Spawns particles on the entity based on the given particle effect and locator.
@@ -65,15 +66,36 @@ class EntityParticlesActionEffectKeyframe : ConditionalActionEffectKeyframe(), E
allEntities.any { player.distanceTo(it) <= visibilityRange }
}
// Try to resolve a world-position target from runtime variables
val runtimeTargetPosition: Vec3? = try {
val x = "v.target_x".asExpressionLike().resolveDouble(context.runtime)
val y = "v.target_y".asExpressionLike().resolveDouble(context.runtime)
val z = "v.target_z".asExpressionLike().resolveDouble(context.runtime)
if (x != 0.0 || y != 0.0 || z != 0.0) Vec3(x, y, z) else null
} catch (e: Exception) {
null
}
sourceEntities.filter { it is PosableEntity }.forEach { entity ->
if (targetLocators == null) {
val packet = SpawnSnowstormEntityParticlePacket(effectIdentifier, entity.id, locators)
packet.sendToPlayers(players)
}
else {
// If target entities are specified, send the particle using entity locators/position.
// If there are no target entities then attempt to send to v.target world position or send without target.
if (targetEntities.isNotEmpty()) {
targetEntities.forEach { targetEntity ->
val packet = SpawnSnowstormEntityParticlePacket(effectIdentifier, entity.id, locators, targetEntity.id, targetLocators!!.toList())
if (targetLocators != null) {
val packet = SpawnSnowstormEntityParticlePacket(effectIdentifier, entity.id, locators, targetEntity.id, targetLocators!!.toList())
packet.sendToPlayers(players)
} else {
val packet = SpawnSnowstormEntityParticlePacket(effectIdentifier, entity.id, locators, targetEntity.id)
packet.sendToPlayers(players)
}
}
} else {
if (runtimeTargetPosition != null) {
val packet = SpawnSnowstormEntityParticlePacket(effectIdentifier, entity.id, locators, targetPosition = runtimeTargetPosition)
packet.sendToPlayers(players)
} else {
val packet = SpawnSnowstormEntityParticlePacket(effectIdentifier, entity.id, locators)
packet.sendToPlayers(players)
}
}
@@ -8,8 +8,6 @@
package com.cobblemon.mod.common.api.moves.animations.keyframes
import com.bedrockk.molang.runtime.struct.QueryStruct
import com.cobblemon.mod.common.Cobblemon
import com.cobblemon.mod.common.api.molang.ExpressionLike
import com.cobblemon.mod.common.api.moves.animations.ActionEffectContext
import com.cobblemon.mod.common.api.scheduling.delayedFuture
@@ -8,6 +8,8 @@
package com.cobblemon.mod.common.api.moves.animations.keyframes
import com.cobblemon.mod.common.Cobblemon
import com.cobblemon.mod.common.api.molang.ExpressionLike
import com.cobblemon.mod.common.api.moves.animations.ActionEffectContext
import com.cobblemon.mod.common.api.moves.animations.ActionEffects
import java.util.concurrent.CompletableFuture
@@ -18,16 +20,37 @@ import net.minecraft.resources.ResourceLocation
* effect is marked complete only when the action effect it runs is complete unless [waitForActionEffect] is
* false.
*
* If [expression] is set, it will be resolved at runtime to determine the action effect identifier.
* This allows dynamic delegation based on MoLang variables (e.g. v.granting_move).
* If [expression] is not set, the static [actionEffect] identifier is used instead.
*
* @author Hiroku
* @since January 21st, 2024
*/
class RunActionEffectKeyframe : ConditionalActionEffectKeyframe() {
val actionEffect: ResourceLocation? = null
val expression: ExpressionLike? = null
val waitForActionEffect = true
override fun playWhenTrue(context: ActionEffectContext): CompletableFuture<Unit> {
return if (actionEffect != null) {
ActionEffects.actionEffects[actionEffect]?.run(context)?.takeIf { waitForActionEffect } ?: skip()
val effectId = if (expression != null) {
val resolved = expression.resolveString(context.runtime)
if (resolved == "0" || resolved.isBlank()) {
Cobblemon.LOGGER.warn("RunActionEffectKeyframe expression resolved to empty/zero string: $resolved")
return skip()
}
try {
ResourceLocation.parse(resolved)
} catch (e: Exception) {
Cobblemon.LOGGER.warn("RunActionEffectKeyframe expression resolved to invalid resource location: $resolved with exception: $e")
return skip()
}
} else {
actionEffect
}
return if (effectId != null) {
ActionEffects.actionEffects[effectId]?.run(context)?.takeIf { waitForActionEffect } ?: skip()
} else {
Cobblemon.LOGGER.warn("RunActionEffectKeyframe has no action effect identifier or expression to run")
skip()
}
}
@@ -102,7 +102,7 @@ open class PlayerPartyStore(
for (pokemon in this) {
// Awake from fainted
if (pokemon.isFainted()) {
//Skip awaken logic check if config value is 0
// Skip awaken logic check if config value is 0
if (Cobblemon.config.faintAwakenHealthPercent > 0) {
pokemon.faintedTimer -= 1
if (pokemon.faintedTimer <= -1) {
@@ -119,7 +119,7 @@ open class PlayerPartyStore(
}
// Passive healing while less than full health
else if (pokemon.currentHealth < pokemon.maxHealth) {
//Skip passive healing logic check if config value is 0
// Skip passive healing logic check if config value is 0
if (Cobblemon.config.healPercent > 0) {
pokemon.healTimer--
if (pokemon.healTimer <= -1) {
@@ -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
@@ -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()
@@ -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)
}
}
@@ -179,6 +179,8 @@ object CobblemonClient {
return@subscribe
}
storage.party.forEach { it?.tickSkillCooldowns() }
val nearbyPokemon = player.level().getEntities(
player,
AABB.ofSize(player.position(), 16.0, 16.0, 16.0)
@@ -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
@@ -28,7 +28,7 @@ class InteractWheelButton(
private val tooltipText: String?,
x: Int,
y: Int,
private val isEnabled: Boolean,
private val isEnabled: () -> Boolean,
private val colour: () -> Vector3f?,
onPress: OnPress,
private val canHover: (Double, Double) -> Boolean
@@ -74,12 +74,12 @@ class InteractWheelButton(
y = y,
width = width,
height = height,
vOffset = if (isHovered(mouseX.toFloat(), mouseY.toFloat()) && isEnabled) height else 0,
vOffset = if (isHovered(mouseX.toFloat(), mouseY.toFloat()) && isEnabled()) height else 0,
textureHeight = height * 2,
alpha = if (isEnabled) 1f else 0.4F
alpha = if (isEnabled()) 1f else 0.4F
)
if(isEnabled && isHovered(mouseX.toFloat(), mouseY.toFloat())){
if (isEnabled() && isHovered(mouseX.toFloat(), mouseY.toFloat())){
tooltipText?.let {
context.renderTooltip(Minecraft.getInstance().font, Component.translatable(it), mouseX, mouseY)
}
@@ -95,7 +95,7 @@ class InteractWheelButton(
y = iconY,
width = ICON_SIZE,
height = ICON_SIZE,
alpha = if (isEnabled) 1F else 0.2F,
alpha = if (isEnabled()) 1F else 0.2F,
red = colour.x,
green = colour.y,
blue = colour.z,
@@ -114,7 +114,7 @@ class InteractWheelButton(
y = iconY - ICON_SIZE,
width = ICON_SIZE,
height = ICON_SIZE,
alpha = if (isEnabled) 1F else 0.4F,
alpha = if (isEnabled()) 1F else 0.4F,
red = colour.x,
green = colour.y,
blue = colour.z,
@@ -18,7 +18,7 @@ import net.minecraft.client.gui.screens.Screen
import net.minecraft.network.chat.Component
import kotlin.math.max
class InteractWheelGUI(private val options: Multimap<Orientation, InteractWheelOption>, title: Component) : Screen(title), CobblemonRenderable {
open class InteractWheelGUI(private val options: Multimap<Orientation, InteractWheelOption>, title: Component) : Screen(title), CobblemonRenderable {
companion object {
const val SIZE = 170
private val backgroundResource = cobblemonResource("textures/gui/interact/interact_wheel_base.png")
@@ -32,7 +32,7 @@ class InteractWheelGUI(private val options: Multimap<Orientation, InteractWheelO
return super.keyPressed(keyCode, scanCode, modifiers)
}
private val buttons = mutableListOf<InteractWheelButton>()
protected val buttons = mutableListOf<InteractWheelButton>()
private var maxPage = 1
private var currentPage = 0
override fun renderBlurredBackground(delta: Float) { }
@@ -104,7 +104,7 @@ class InteractWheelGUI(private val options: Multimap<Orientation, InteractWheelO
tooltipText = option?.tooltipText,
x = x,
y = y,
isEnabled = option != null && option.enabled,
isEnabled = { option != null && option.enabled() },
colour = option?.colour ?: { null },
onPress = { option?.onPress?.invoke() },
canHover = { a: Double, b: Double -> !isMouseInCenter(a, b)}
@@ -9,20 +9,24 @@
package com.cobblemon.mod.common.client.gui.interact.wheel
import com.cobblemon.mod.common.CobblemonNetwork
import com.cobblemon.mod.common.CobblemonPokeSkills
import com.cobblemon.mod.common.api.events.CobblemonEvents
import com.cobblemon.mod.common.api.events.pokemon.interaction.PokemonInteractionGUICreationEvent
import com.cobblemon.mod.common.client.CobblemonClient
import com.cobblemon.mod.common.client.gui.interact.battleRequest.BattleConfigureGUI
import com.cobblemon.mod.common.net.messages.client.PlayerInteractOptionsPacket
import com.cobblemon.mod.common.net.messages.server.UsePokeSkillPacket
import com.cobblemon.mod.common.net.messages.server.battle.SpectateBattlePacket
import com.cobblemon.mod.common.net.messages.server.pokemon.interact.InteractPokemonPacket
import com.cobblemon.mod.common.net.messages.server.trade.AcceptTradeRequestPacket
import com.cobblemon.mod.common.net.messages.server.trade.OfferTradePacket
import com.cobblemon.mod.common.pokemon.Pokemon
import com.cobblemon.mod.common.util.cobblemonResource
import com.google.common.collect.ArrayListMultimap
import com.google.common.collect.Multimap
import java.util.UUID
import net.minecraft.client.Minecraft
import net.minecraft.client.player.AbstractClientPlayer
import net.minecraft.network.chat.Component
import org.joml.Vector3f
@@ -30,7 +34,7 @@ fun createPokemonInteractGui(pokemonID: UUID, canMountShoulder: Boolean, canGive
val mountShoulder = InteractWheelOption(
iconResource = cobblemonResource("textures/gui/interact/interact_wheel_icon_shoulder.png"),
tooltipText = "cobblemon.ui.interact.mount.shoulder",
enabled = canMountShoulder,
enabled = { canMountShoulder },
onPress = {
if (canMountShoulder) {
InteractPokemonPacket(pokemonID, InteractTypePokemon.SHOULDER).sendToServer()
@@ -41,7 +45,7 @@ fun createPokemonInteractGui(pokemonID: UUID, canMountShoulder: Boolean, canGive
val giveHeldItem = InteractWheelOption(
iconResource = cobblemonResource("textures/gui/interact/interact_wheel_icon_held_item.png"),
tooltipText = "cobblemon.ui.interact.give.item",
enabled = canGiveHeld,
enabled = { canGiveHeld },
onPress = {
if (canGiveHeld) {
InteractPokemonPacket(pokemonID, InteractTypePokemon.HELD_ITEM).sendToServer()
@@ -52,7 +56,7 @@ fun createPokemonInteractGui(pokemonID: UUID, canMountShoulder: Boolean, canGive
val giveCosmeticItem = InteractWheelOption(
iconResource = cobblemonResource("textures/gui/interact/interact_wheel_icon_cosmetic_item.png"),
tooltipText = "cobblemon.ui.interact.give.cosmetic_item",
enabled = canGiveCosmetic,
enabled = { canGiveCosmetic },
onPress = {
if (canGiveCosmetic) {
InteractPokemonPacket(pokemonID, InteractTypePokemon.COSMETIC_ITEM).sendToServer()
@@ -64,7 +68,7 @@ fun createPokemonInteractGui(pokemonID: UUID, canMountShoulder: Boolean, canGive
val ride = InteractWheelOption(
iconResource = cobblemonResource("textures/gui/interact/interact_wheel_icon_ride.png"),
tooltipText = "cobblemon.ui.interact.ride",
enabled = canRide,
enabled = { canRide },
onPress = {
if (canRide) {
InteractPokemonPacket(pokemonID, InteractTypePokemon.RIDE).sendToServer()
@@ -177,6 +181,35 @@ fun createPlayerInteractGui(optionsPacket: PlayerInteractOptionsPacket): Interac
return InteractWheelGUI(options, Component.translatable("cobblemon.ui.interact.player"))
}
fun createPokeSkillGui(player: AbstractClientPlayer, pokemon: Pokemon): InteractWheelGUI {
val accessibleSkills = CobblemonPokeSkills.getAccessibleSkills(player, pokemon)
val options: Multimap<Orientation, InteractWheelOption> = ArrayListMultimap.create()
for (skill in accessibleSkills) {
val skillOption = InteractWheelOption(
iconResource = skill.icon,
enabled = { skill.id !in pokemon.skillCooldownsTicks },
tooltipText = skill.name,
onPress = {
CobblemonNetwork.sendToServer(UsePokeSkillPacket(skillId = skill.id, pokemonId = pokemon.uuid))
closeGUI()
}
)
when (options.size()) {
0 -> options.put(Orientation.NORTH, skillOption)
1 -> options.put(Orientation.NORTHEAST, skillOption)
2 -> options.put(Orientation.SOUTHEAST, skillOption)
3 -> options.put(Orientation.SOUTH, skillOption)
4 -> options.put(Orientation.SOUTHWEST, skillOption)
5 -> options.put(Orientation.NORTHWEST, skillOption)
6 -> options.put(Orientation.WEST, skillOption)
7 -> options.put(Orientation.EAST, skillOption)
else -> break // We only have 8 slots
}
}
return PokeSkillWheelGUI(options, Component.translatable("cobblemon.ui.interact.poke_skill"))
}
private fun getLangKey(status: PlayerInteractOptionsPacket.OptionStatus) : String {
return when (status) {
PlayerInteractOptionsPacket.OptionStatus.TOO_FAR -> "cobblemon.ui.interact.too_far"
@@ -14,7 +14,7 @@ import org.joml.Vector3f
data class InteractWheelOption(
val iconResource: ResourceLocation,
val secondaryIconResource: ResourceLocation? = null,
val enabled: Boolean = true,
val enabled: () -> Boolean = { true },
val tooltipText: String?,
val colour: () -> Vector3f? = { null },
val onPress: () -> Unit
@@ -0,0 +1,47 @@
/*
* 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.interact.wheel
import com.google.common.collect.Multimap
import net.minecraft.client.Minecraft
import net.minecraft.network.chat.Component
class PokeSkillWheelGUI(
private val options: Multimap<Orientation, InteractWheelOption>,
title: Component
) : InteractWheelGUI(options, title) {
/**
* Due to the button being held swallow the event
*/
override fun mouseClicked(mouseX: Double, mouseY: Double, button: Int): Boolean {
if (button == 0) return false
return super.mouseClicked(mouseX, mouseY, button)
}
/**
* On release will close the wheel and trigger the button press of the hovered button
* TODO: make this wheel choose more like pizza slices.
*/
override fun mouseReleased(mouseX: Double, mouseY: Double, button: Int): Boolean {
if (button == 0) {
// Manually trigger the hovered button's press
buttons.forEach { btn ->
if (btn.isMouseOver(mouseX, mouseY)) {
btn.onClick(mouseX, mouseY)
return true
}
}
Minecraft.getInstance().setScreen(null)
return true
}
return super.mouseReleased(mouseX, mouseY, button)
}
}
@@ -32,8 +32,6 @@ 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_WIDTH
@@ -429,11 +427,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()
}
@@ -764,12 +757,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)
}
@@ -22,7 +22,6 @@ 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
@@ -387,8 +386,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()
@@ -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,
@@ -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
}
}
@@ -15,6 +15,7 @@ import com.cobblemon.mod.common.battles.BattleFormat
import com.cobblemon.mod.common.client.CobblemonClient
import com.cobblemon.mod.common.client.battle.ClientBattle
import com.cobblemon.mod.common.client.gui.battle.BattleGUI
import com.cobblemon.mod.common.client.gui.interact.wheel.createPokeSkillGui
import com.cobblemon.mod.common.client.keybind.CobblemonBlockingKeyBinding
import com.cobblemon.mod.common.client.keybind.KeybindCategories
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
@@ -26,12 +27,12 @@ import com.cobblemon.mod.common.pokemon.Pokemon
import com.cobblemon.mod.common.util.isUsingPokedex
import com.cobblemon.mod.common.util.traceFirstEntityCollision
import com.mojang.blaze3d.platform.InputConstants
import kotlin.math.pow
import net.minecraft.client.Minecraft
import net.minecraft.client.player.LocalPlayer
import net.minecraft.world.entity.LivingEntity
import net.minecraft.world.entity.player.Player
import net.minecraft.world.level.ClipContext
import kotlin.math.pow
object PartySendBinding : CobblemonBlockingKeyBinding(
"key.cobblemon.throwpartypokemon",
@@ -39,32 +40,17 @@ object PartySendBinding : CobblemonBlockingKeyBinding(
InputConstants.KEY_R,
KeybindCategories.COBBLEMON_CATEGORY
) {
const val POKE_SKILL_TIME = 0.7F
var canApplyChange = true
var heldDownSeconds = 0F
fun actioned() {
canApplyChange = false
wasDown = true
heldDownSeconds = 0F
}
fun canAction() = canApplyChange && Minecraft.getInstance().player?.isUsingPokedex() == false
override fun onTick() {
if (wasDown) {
if (heldDownSeconds < 100) {
heldDownSeconds += Minecraft.getInstance().timer.getGameTimeDeltaPartialTick(false)
}
} else {
heldDownSeconds = 0F
}
super.onTick()
}
override fun onRelease() {
val canAction = canAction()
wasDown = false
canApplyChange = true
if (!canAction) {
return
@@ -105,7 +91,8 @@ object PartySendBinding : CobblemonBlockingKeyBinding(
entityClass = LivingEntity::class.java,
ignoreEntity = player,
maxDistance = Cobblemon.config.battleSpectateMaxDistance,
collideBlock = ClipContext.Fluid.NONE)
collideBlock = ClipContext.Fluid.NONE
)
if (canSendOutPokemon(player, targetEntity)) {
sendToServer(SendOutPokemonPacket(CobblemonClient.storage.selectedSlot))
} else {
@@ -127,10 +114,13 @@ object PartySendBinding : CobblemonBlockingKeyBinding(
//The server sends a packet back that opens the player interaction menu with the proper options
sendToServer(RequestPlayerInteractionsPacket(entity.uuid, entity.id, pokemon.uuid))
}
is PokemonEntity -> {
if (!entity.canBattle(player) || entity.position().distanceToSqr(player.position()) > Cobblemon.config.battleWildMaxDistance.pow(2)) return
sendToServer(BattleChallengePacket(entity.id, pokemon.uuid, BattleFormat.GEN_9_SINGLES))
}
if (!entity.canBattle(player) || entity.position()
.distanceToSqr(player.position()) > Cobblemon.config.battleWildMaxDistance.pow(2)
) return
sendToServer(BattleChallengePacket(entity.id, pokemon.uuid, BattleFormat.GEN_9_SINGLES))
}
}
}
@@ -19,6 +19,7 @@ import com.cobblemon.mod.common.entity.PosableEntity
import com.cobblemon.mod.common.net.messages.client.effect.SpawnSnowstormEntityParticlePacket
import net.minecraft.client.Minecraft
import net.minecraft.world.entity.Entity
import net.minecraft.world.phys.Vec3
object SpawnSnowstormEntityParticleHandler : ClientNetworkPacketHandler<SpawnSnowstormEntityParticlePacket> {
override fun handle(packet: SpawnSnowstormEntityParticlePacket, client: Minecraft) {
@@ -31,6 +32,7 @@ object SpawnSnowstormEntityParticleHandler : ClientNetworkPacketHandler<SpawnSno
val targetState = (targetedEntity as? PosableEntity)?.delegate as? PosableState
val sourceLocators = packet.sourceLocators.firstNotNullOfOrNull { sourceState.getMatchingLocators(it).takeIf { it.isNotEmpty() } } ?: return
val targetedLocator = packet.targetLocators?.firstOrNull { targetState?.getMatchingLocators(it)?.isNotEmpty() == true }
val targetPosition = packet.targetPosition
val rootMatrix = sourceState.locatorStates["root"]!!
sourceLocators.forEach { locator ->
@@ -40,6 +42,16 @@ object SpawnSnowstormEntityParticleHandler : ClientNetworkPacketHandler<SpawnSno
val particleRuntime = MoLangRuntime().setup().setupClient()
particleRuntime.environment.query.addFunction("entity") { sourceState.runtime.environment.query }
// Target resolution priority: entity+locator > world position > none
val targetPos: (() -> Vec3)? = if (targetedEntity != null) {
{ targetedLocator?.let { targetState?.locatorStates?.get(it) }?.getOrigin() ?: targetedEntity.position() }
} else if (targetPosition != null) {
val pos = packet.targetPosition
{ pos }
} else {
null
}
val storm = ParticleStorm(
effect = effect,
emitterSpaceMatrix = particleMatrix,
@@ -49,7 +61,7 @@ object SpawnSnowstormEntityParticleHandler : ClientNetworkPacketHandler<SpawnSno
sourceVelocity = { sourceEntity.deltaMovement },
sourceAlive = { !sourceEntity.isRemoved },
sourceVisible = { !sourceEntity.isInvisible },
targetPos = if (targetedEntity != null) { { targetedLocator?.let { targetState?.locatorStates?.get(it) }?.getOrigin() ?: targetedEntity.position() } } else null,
targetPos = targetPos,
entity = sourceEntity
)
@@ -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,
@@ -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,127 @@
/*
* 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.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.util.isBattling
import com.cobblemon.mod.common.util.isUnderWater
import com.cobblemon.mod.common.util.isInWater
import net.minecraft.client.model.geom.ModelPart
import net.minecraft.world.phys.Vec3
class ChinchouModel (root: ModelPart) : PokemonPosableModel(root) {
override val rootPart = root.registerChildWithAllChildren("chinchou")
override var portraitScale = 1.75F
override var portraitTranslation = Vec3(-0.3, -0.8, 0.0)
override var profileScale = 0.65F
override var profileTranslation = Vec3(-0.05, 0.45, 0.0)
lateinit var standing: CobblemonPose
lateinit var walk: CobblemonPose
lateinit var floating: CobblemonPose
lateinit var swimming: CobblemonPose
lateinit var sleep: CobblemonPose
lateinit var watersleep: CobblemonPose
lateinit var battleidle: CobblemonPose
lateinit var waterbattleidle: CobblemonPose
// override val cryAnimation = CryProvider { bedrockStateful("chinchou", "cry") }
override fun registerPoses() {
val blink = quirk { bedrockStateful("chinchou", "blink")}
val idleQuirk = quirk(secondsBetweenOccurrences = 60F to 120F) { bedrockStateful("chinchou", "ground_quirk")}
val waterQuirk = quirk(secondsBetweenOccurrences = 60F to 120F) { bedrockStateful("chinchou", "water_idle_quirk")}
sleep = registerPose(
poseName = "sleeping",
poseType = PoseType.SLEEP,
condition = { !it.isInWater },
animations = arrayOf(bedrock("chinchou", "sleep"))
)
watersleep = registerPose(
poseName = "water_sleeping",
poseType = PoseType.SLEEP,
condition = { it.isInWater },
animations = arrayOf(bedrock("chinchou", "water_sleep"))
)
standing = registerPose(
poseName = "standing",
poseTypes = PoseType.UI_POSES + PoseType.STAND,
transformTicks = 10,
condition = { !it.isBattling && !it.isInWater && !it.isUnderWater},
quirks = arrayOf(blink, idleQuirk),
animations = arrayOf(
bedrock("chinchou", "ground_idle")
)
)
walk = registerPose(
poseName = "walk",
transformTicks = 10,
poseType = PoseType.WALK,
condition = { !it.isInWater && !it.isUnderWater},
quirks = arrayOf(blink),
animations = arrayOf(
bedrock("chinchou", "ground_walk")
)
)
floating = registerPose(
poseName = "floating",
transformTicks = 10,
poseType = PoseType.FLOAT,
condition = { it.isInWater },
quirks = arrayOf(blink, waterQuirk),
animations = arrayOf(
bedrock("chinchou", "water_idle")
)
)
swimming = registerPose(
poseName = "swimming",
transformTicks = 10,
condition = { it.isInWater },
poseTypes = PoseType.MOVING_POSES,
quirks = arrayOf(blink),
animations = arrayOf(
bedrock("chinchou", "water_swim"),
)
)
battleidle = registerPose(
poseName = "battle_idle",
poseTypes = PoseType.STATIONARY_POSES,
transformTicks = 10,
quirks = arrayOf(blink),
condition = { it.isBattling && !it.isInWater },
animations = arrayOf(
bedrock("chinchou", "battle_idle")
)
)
waterbattleidle = registerPose(
poseName = "water_battle_idle",
poseTypes = PoseType.STATIONARY_POSES,
transformTicks = 10,
quirks = arrayOf(blink),
condition = { it.isBattling && it.isInWater },
animations = arrayOf(
bedrock("chinchou", "water_battle_idle")
)
)
}
override fun getFaintAnimation(state: PosableState) = if (state.isPosedIn(standing, walk, battleidle, sleep)) bedrockStateful("chinchou", "faint") else if (state.isPosedIn( waterbattleidle, watersleep, floating, swimming )) bedrockStateful("chinchou", "water_faint") else null
}
@@ -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)
@@ -368,6 +381,7 @@ object VaryingModelRepository {
inbuilt("magcargo", ::MagcargoModel)
inbuilt("slugma_shiny", ::SlugmaShinyModel)
inbuilt("magcargo_shiny", ::MagcargoShinyModel)
inbuilt("chinchou", ::ChinchouModel)
inbuilt("clamperl", ::ClamperlModel)
inbuilt("huntail", ::HuntailModel)
inbuilt("gorebyss", ::GorebyssModel)
@@ -535,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)
@@ -10,6 +10,13 @@ package com.cobblemon.mod.common.data
import com.cobblemon.mod.common.*
import com.cobblemon.mod.common.Cobblemon.LOGGER
import com.cobblemon.mod.common.CobblemonBehaviours
import com.cobblemon.mod.common.CobblemonCallbacks
import com.cobblemon.mod.common.CobblemonCosmeticItems
import com.cobblemon.mod.common.CobblemonMechanics
import com.cobblemon.mod.common.CobblemonPokeSkills
import com.cobblemon.mod.common.CobblemonRideSettings
import com.cobblemon.mod.common.CobblemonUnlockableWallpapers
import com.cobblemon.mod.common.api.abilities.Abilities
import com.cobblemon.mod.common.api.berry.Berries
import com.cobblemon.mod.common.api.cooking.Seasonings
@@ -73,6 +80,7 @@ object CobblemonDataProvider : DataProvider {
this.register(GlobalSpeciesFeatures, reloadable = false)
this.register(SpeciesFeatureAssignments, reloadable = false)
this.register(ActionEffects, reloadable = true)
this.register(CobblemonPokeSkills, reloadable = true)
this.register(Moves, reloadable = false)
this.register(CobblemonMovesetBuilders, reloadable = false)
this.register(Abilities, reloadable = false)
@@ -0,0 +1,360 @@
/*
* 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.entity.pokemon
import com.bedrockk.molang.runtime.MoLangRuntime
import com.bedrockk.molang.runtime.value.DoubleValue
import com.bedrockk.molang.runtime.value.StringValue
import com.cobblemon.mod.common.Cobblemon
import com.cobblemon.mod.common.api.molang.ExpressionLike
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMoLangValue
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMostSpecificMoLangValue
import com.cobblemon.mod.common.api.molang.MoLangFunctions.setup
import com.cobblemon.mod.common.api.molang.ObjectValue
import com.cobblemon.mod.common.api.moves.animations.ActionEffectContext
import com.cobblemon.mod.common.api.moves.animations.ActionEffectTimeline
import com.cobblemon.mod.common.api.moves.animations.ActionEffects
import com.cobblemon.mod.common.api.moves.animations.TargetsProvider
import com.cobblemon.mod.common.api.moves.animations.UsersProvider
import com.cobblemon.mod.common.api.pokemon.status.Statuses
import com.cobblemon.mod.common.pokemon.Pokemon
import com.cobblemon.mod.common.util.asExpressionLike
import com.cobblemon.mod.common.util.blockRegistry
import com.cobblemon.mod.common.util.cobblemonResource
import com.cobblemon.mod.common.util.codec.EXPRESSION_LIKE_CODEC
import com.cobblemon.mod.common.util.isInBattle
import com.cobblemon.mod.common.util.resolveBoolean
import com.cobblemon.mod.common.util.withQueryValue
import com.mojang.serialization.Codec
import com.mojang.serialization.codecs.RecordCodecBuilder
import net.minecraft.core.registries.Registries
import net.minecraft.network.codec.ByteBufCodecs
import net.minecraft.resources.ResourceLocation
import net.minecraft.server.level.ServerLevel
import net.minecraft.server.level.ServerPlayer
import net.minecraft.world.entity.Entity
import net.minecraft.world.entity.player.Player
import net.minecraft.world.phys.BlockHitResult
import net.minecraft.world.phys.HitResult
/**
* The reference object for a skill that a Pokémon can use in the overworld.
*
* Most skills are "wrapper" skills that play a move's action effect at a target and run
* some MoLang on impact. Custom skills can define a full action effect timeline.
*
* Access is auto-derived from grantingMoves/Abilities/Types/Species lists. If none are
* populated, accessCondition is used as a fallback.
*
* @author Hiroku
* @since August 31st, 2025
*/
class PokeSkill(
val name: String,
val enabled: Boolean = true,
val actionEffect: ActionEffectTimeline,
val icon: ResourceLocation,
val cooldownTicks: Int,
val accessCondition: ExpressionLike = "true".asExpressionLike(),
val useCondition: ExpressionLike = "true".asExpressionLike(),
// Targeting
val targetType: TargetType? = null,
val range: Double? = null,
val targetCondition: ExpressionLike? = null,
// Granting
val grantingMoves: List<String>? = null,
val grantingAbilities: List<String>? = null,
val grantingTypes: List<String>? = null,
val grantingSpecies: List<String>? = null,
// Wrapper skill fields
val hitDelay: ExpressionLike? = null,
val hitEffect: ResourceLocation? = null,
val fallbackActionEffect: ResourceLocation? = null
) {
// Enum to determine what this skill will target.
enum class TargetType {
NONE, SELF, BLOCK, ENTITY, BOTH
}
companion object {
val runtime = MoLangRuntime().setup()
val CODEC = RecordCodecBuilder.create<PokeSkill> { instance ->
instance.group(
Codec.STRING.fieldOf("name").forGetter { it.name },
Codec.BOOL.fieldOf("enabled").forGetter { it.enabled },
Codec.unit<ActionEffectTimeline> { ActionEffectTimeline.NONE }.fieldOf("actionEffect").forGetter { it.actionEffect },
ResourceLocation.CODEC.fieldOf("icon").forGetter { it.icon },
Codec.INT.fieldOf("cooldownTicks").forGetter { it.cooldownTicks },
EXPRESSION_LIKE_CODEC.fieldOf("accessCondition").forGetter { it.accessCondition },
EXPRESSION_LIKE_CODEC.fieldOf("useCondition").forGetter { it.useCondition }
).apply(instance, ::PokeSkill)
}
val PACKET_CODEC = ByteBufCodecs.fromCodecWithRegistries(CODEC)
private val DEFAULT_ACTION_EFFECT = cobblemonResource("default_poke_skill")
}
@Transient
lateinit var id: ResourceLocation
// fun canAccess(player: Player, pokemon: Pokemon): Boolean {
// if (!enabled) {
// return false
// }
//
// runtime.withQueryValue("player", player.asMostSpecificMoLangValue())
// runtime.withQueryValue("pokemon", pokemon.struct)
// pokemon.entity?.let { runtime.withQueryValue("entity", it.asMostSpecificMoLangValue()) }
// val hasAccess = runtime.resolveBoolean(accessCondition)
// return hasAccess
// }
/**
* Determines access by checking the pokemons data against the granting lists.
* If no granting lists are populated, accessCondition is used as a fallback.
*/
fun canAccess(player: Player, pokemon: Pokemon): Boolean {
if (!enabled) {
return false
}
// Check granting lists — if any are populated, check if the player has any of the listed moves/abilities/types/species
val hasGrantingLists = !grantingMoves.isNullOrEmpty() || !grantingAbilities.isNullOrEmpty() ||
!grantingTypes.isNullOrEmpty() || !grantingSpecies.isNullOrEmpty()
if (hasGrantingLists) {
val moveMatch = !grantingMoves.isNullOrEmpty() && grantingMoves.any { moveName ->
pokemon.moveSet.any { it.template.name == moveName }
}
val abilityMatch = !grantingAbilities.isNullOrEmpty() && grantingAbilities.any { abilityName ->
pokemon.ability.name == abilityName
}
val typeMatch = !grantingTypes.isNullOrEmpty() && grantingTypes.any { typeName ->
pokemon.types.any { it.name.equals(typeName, ignoreCase = true) }
}
val speciesMatch = !grantingSpecies.isNullOrEmpty() && grantingSpecies.any { speciesName ->
pokemon.species.name.equals(speciesName, ignoreCase = true)
}
if (!(moveMatch || abilityMatch || typeMatch || speciesMatch)) return false
}
// Always evaluate accessCondition — acts as additional gate when granting lists are present,
// or as the sole gate when no granting lists are populated
runtime.withQueryValue("player", player.asMostSpecificMoLangValue())
runtime.withQueryValue("pokemon", pokemon.struct)
pokemon.entity?.let { runtime.withQueryValue("entity", it.asMostSpecificMoLangValue()) }
return runtime.resolveBoolean(accessCondition ?: "true".asExpressionLike())
}
fun canUse(player: Player, pokemon: Pokemon): Boolean {
val status = pokemon.status?.status
if (id in pokemon.skillCooldownsTicks || player.isInBattle() || status == Statuses.SLEEP || status == Statuses.FROZEN) {
return false
}
runtime.withQueryValue("player", player.asMostSpecificMoLangValue())
runtime.withQueryValue("pokemon", pokemon.struct)
val canUse = runtime.resolveBoolean(useCondition)
return canUse
}
/**
* Resolves which move from the pokemon's moveset grants this skill.
* Returns the first matching move name from grantingMoves, or null if none match.
*/
fun resolveGrantingMove(pokemon: Pokemon): String? {
if (grantingMoves.isNullOrEmpty()) return null // need this guard
return grantingMoves.firstOrNull { moveName ->
pokemon.moveSet.any { it.template.name == moveName }
}
}
/**
* Resolves the action effect to use for the move visual.
* Priority: granting move's action effect > fallbackActionEffect > null
*/
fun resolveVisualEffect(pokemon: Pokemon): ResourceLocation? {
val grantingMove = resolveGrantingMove(pokemon)
if (grantingMove != null) {
val effectId = cobblemonResource(grantingMove)
if (ActionEffects.actionEffects.containsKey(effectId)) return effectId
Cobblemon.LOGGER.warn("PokeSkill '$id': granting move '$grantingMove' has no action effect at '$effectId'")
}
return fallbackActionEffect
}
/**
* Runs the skill on the given pokemon.
* Populates context and runs targeting logic.
*/
fun use(
player: ServerPlayer,
pokemon: Pokemon,
// context information!!!
): Boolean {
if (!canUse(player, pokemon)) return false
val entity = pokemon.entity ?: return false
val level = player.level() as? ServerLevel ?: return false
// I think these should be defaulted but making them nullable means I don't have to adjust the
// other jsons that don't populate them yet...
val effectiveTargetType = targetType ?: TargetType.NONE
val effectiveRange = range ?: 8.0
// Resolve the action effect to run
val effectTimeline = if (actionEffect != null && actionEffect != ActionEffectTimeline.NONE) {
actionEffect
} else {
ActionEffects.actionEffects[DEFAULT_ACTION_EFFECT] ?: run {
Cobblemon.LOGGER.warn("PokeSkill '$id': default_poke_skill action effect not found")
return false
}
}
// Set up runtime
val skillRuntime = MoLangRuntime().setup()
skillRuntime.withQueryValue("player", player.asMostSpecificMoLangValue())
skillRuntime.withQueryValue("pokemon", pokemon.struct)
skillRuntime.withQueryValue("entity", entity.asMostSpecificMoLangValue())
skillRuntime.environment.setSimpleVariable("skill_id", StringValue(id.toString()))
skillRuntime.environment.setSimpleVariable("target_type", StringValue(effectiveTargetType.name.lowercase()))
skillRuntime.environment.query.addFunction("missed") { DoubleValue(0.0) } // move action effects use this to determine if the target particles should play. We want them to always play for skills I believe
// Targeting — raycast based on targetType
when (effectiveTargetType) {
TargetType.SELF -> {
injectEntityTarget(skillRuntime, player)
skillRuntime.environment.setSimpleVariable("target_is_entity", DoubleValue(1.0))
}
TargetType.BLOCK -> {
val blockHit = getPlayerLookedBlock(player, effectiveRange)
if (blockHit == null) return false
injectBlockTarget(skillRuntime, blockHit, level)
skillRuntime.environment.setSimpleVariable("target_is_entity", DoubleValue(0.0))
}
TargetType.ENTITY -> {
val entityHit = getPlayerLookedEntity(player, effectiveRange)
if (entityHit == null) return false
injectEntityTarget(skillRuntime, entityHit)
skillRuntime.environment.setSimpleVariable("target_is_entity", DoubleValue(1.0))
}
TargetType.BOTH -> {
val entityHit = getPlayerLookedEntity(player, effectiveRange)
if (entityHit != null) {
injectEntityTarget(skillRuntime, entityHit)
skillRuntime.environment.setSimpleVariable("target_is_entity", DoubleValue(1.0))
} else {
val blockHit = getPlayerLookedBlock(player, effectiveRange)
if (blockHit == null) return false
injectBlockTarget(skillRuntime, blockHit, level)
skillRuntime.environment.setSimpleVariable("target_is_entity", DoubleValue(0.0))
}
}
TargetType.NONE -> {}
}
// Evaluate target condition
if (targetCondition != null && !skillRuntime.resolveBoolean(targetCondition)) return false
// Inject wrapper skill variables
val visualEffect = resolveVisualEffect(pokemon)
if (visualEffect != null) {
skillRuntime.environment.setSimpleVariable("granting_move", StringValue(visualEffect.toString()))
}
if (hitEffect != null) {
skillRuntime.environment.setSimpleVariable("hit_effect", StringValue(hitEffect.toString()))
}
if (hitDelay != null) {
skillRuntime.environment.setSimpleVariable("hit_delay", hitDelay.resolve(skillRuntime))
}
// Build providers
val providers = mutableListOf<Any>(
UsersProvider(entity)
)
// Build and run context
val context = ActionEffectContext(
actionEffect = effectTimeline,
runtime = skillRuntime,
providers = providers,
level = level
)
effectTimeline.run(context).thenRun {
// Auto-apply cooldown after effect completes
pokemon.skillCooldownsTicks[id] = cooldownTicks
}
return true
}
/**
* Utility functions for setting up the runtime for a skill.
*/
private fun injectBlockTarget(runtime: MoLangRuntime, blockHit: BlockHitResult, level: ServerLevel) {
val pos = blockHit.blockPos
runtime.environment.setSimpleVariable("target_x", DoubleValue(pos.x + 0.5))
runtime.environment.setSimpleVariable("target_y", DoubleValue(pos.y + 0.5))
runtime.environment.setSimpleVariable("target_z", DoubleValue(pos.z + 0.5))
runtime.environment.setSimpleVariable("target_block_x", DoubleValue(pos.x.toDouble()))
runtime.environment.setSimpleVariable("target_block_y", DoubleValue(pos.y.toDouble()))
runtime.environment.setSimpleVariable("target_block_z", DoubleValue(pos.z.toDouble()))
val blockState = level.getBlockState(pos)
val blockHolder = level.blockRegistry.wrapAsHolder(blockState.block)
val blockValue = blockHolder.asMoLangValue(Registries.BLOCK)
blockValue.addFunction("x") { DoubleValue(pos.x.toDouble()) }
blockValue.addFunction("y") { DoubleValue(pos.y.toDouble()) }
blockValue.addFunction("z") { DoubleValue(pos.z.toDouble()) }
runtime.environment.setSimpleVariable("target_block", blockValue)
}
private fun injectEntityTarget(runtime: MoLangRuntime, entityHit: Entity) {
runtime.environment.setSimpleVariable("target_x", DoubleValue(entityHit.x))
runtime.environment.setSimpleVariable("target_y", DoubleValue(entityHit.y + entityHit.bbHeight / 2.0))
runtime.environment.setSimpleVariable("target_z", DoubleValue(entityHit.z))
runtime.environment.setSimpleVariable("target_entity", entityHit.asMostSpecificMoLangValue())
}
/**
* simple raycast to get the block the player is looking at.
*/
private fun getPlayerLookedBlock(player: ServerPlayer, range: Double): BlockHitResult? {
val hitResult = player.pick(range, 0f, true)
return if (hitResult.type == HitResult.Type.BLOCK) hitResult as BlockHitResult else null
}
/**
* Raycast to determine the entity the player is looking at
*/
private fun getPlayerLookedEntity(player: ServerPlayer, range: Double): Entity? {
val eyePosition = player.getEyePosition(1.0f)
val lookVector = player.getViewVector(1.0f)
val reachVector = eyePosition.add(lookVector.x * range, lookVector.y * range, lookVector.z * range)
// Create an outer bounding box to find potential candidates
val searchBox = player.boundingBox.expandTowards(lookVector.scale(range)).inflate(1.0, 1.0, 1.0)
// Filter entities within the search box
val entityHitResult = net.minecraft.world.entity.projectile.ProjectileUtil.getEntityHitResult(
player,
eyePosition,
reachVector,
searchBox,
{ entity -> !entity.isSpectator && entity.isPickable },
range * range
)
return entityHitResult?.entity
}
}
@@ -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()
@@ -20,12 +20,13 @@ object ServerTickHandler {
secondsTick++
if (secondsTick == 20) {
secondsTick = 0
// Party tick
for (player in server.playerList.players) {
player.party().onSecondPassed(player)
// Party tick
for (player in server.playerList.players) {
val party = player.party()
party.forEach { it.tickSkillCooldowns() }
if (secondsTick == 20) {
secondsTick = 0
party.onSecondPassed(player)
}
}
}
@@ -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 } }" } ?: "" }"
}
@@ -0,0 +1,38 @@
/*
* 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.data
import com.cobblemon.mod.common.CobblemonPokeSkills
import com.cobblemon.mod.common.entity.pokemon.PokeSkill
import com.cobblemon.mod.common.util.cobblemonResource
import net.minecraft.network.RegistryFriendlyByteBuf
class PokeSkillsRegistrySyncPacket(
pokeSkills: Collection<PokeSkill>
) : DataRegistrySyncPacket<PokeSkill, PokeSkillsRegistrySyncPacket>(pokeSkills) {
override val id = ID
override fun encodeEntry(buffer: RegistryFriendlyByteBuf, entry: PokeSkill) {
PokeSkill.PACKET_CODEC.encode(buffer, entry)
}
override fun decodeEntry(buffer: RegistryFriendlyByteBuf): PokeSkill? {
return PokeSkill.PACKET_CODEC.decode(buffer)
}
override fun synchronizeDecoded(entries: Collection<PokeSkill>) {
CobblemonPokeSkills.reload(entries.associateBy { it.id })
}
companion object {
val ID = cobblemonResource("poke_skill_sync")
fun decode(buffer: RegistryFriendlyByteBuf) = PokeSkillsRegistrySyncPacket(emptyList()).apply { decodeBuffer(buffer) }
}
}
@@ -13,10 +13,15 @@ import com.cobblemon.mod.common.client.net.effect.SpawnSnowstormEntityParticleHa
import com.cobblemon.mod.common.util.*
import net.minecraft.network.RegistryFriendlyByteBuf
import net.minecraft.resources.ResourceLocation
import net.minecraft.world.phys.Vec3
/**
* Packet that spawns a snowstorm particle effect on a specified entity and specified locator.
* Can specify an optional target+locator to pass through to the spawned particle
* Can alternatively specify a [targetPosition] for entity-to-world-position targeting
* (e.g. a Pokémon firing particles at a block).
*
* Target resolution priority: targetedEntityId + targetLocators > targetPosition > no target
*
* Handled by [SpawnSnowstormEntityParticleHandler]
*
@@ -28,7 +33,8 @@ class SpawnSnowstormEntityParticlePacket(
val sourceEntityId: Int,
val sourceLocators: List<String> = listOf("root"),
val targetedEntityId: Int? = null,
val targetLocators: List<String>? = null
val targetLocators: List<String>? = null,
val targetPosition: Vec3? = null
) : NetworkPacket<SpawnSnowstormEntityParticlePacket> {
companion object {
val ID = cobblemonResource("spawn_snowstorm_entity_particle")
@@ -39,7 +45,8 @@ class SpawnSnowstormEntityParticlePacket(
val sourceLocators = buffer.readList { buffer.readString() }
val targetedEntityId = buffer.readNullable { it.readInt() }
val targetLocators = buffer.readNullable { buffer.readList { buffer.readString() }}
return SpawnSnowstormEntityParticlePacket(effectId, sourceEntityId, sourceLocators, targetedEntityId, targetLocators)
val targetPosition = buffer.readNullable { Vec3(it.readDouble(), it.readDouble(), it.readDouble()) }
return SpawnSnowstormEntityParticlePacket(effectId, sourceEntityId, sourceLocators, targetedEntityId, targetLocators, targetPosition)
}
}
@@ -55,5 +62,10 @@ class SpawnSnowstormEntityParticlePacket(
buffer.writeString(locator)
}
}
buffer.writeNullable(targetPosition) { _, value ->
buffer.writeDouble(value.x)
buffer.writeDouble(value.y)
buffer.writeDouble(value.z)
}
}
}
@@ -0,0 +1,51 @@
/*
* 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.pokemon.update
import com.cobblemon.mod.common.net.IntSize
import com.cobblemon.mod.common.pokemon.Pokemon
import com.cobblemon.mod.common.util.cobblemonResource
import com.cobblemon.mod.common.util.readSizedInt
import com.cobblemon.mod.common.util.writeSizedInt
import net.minecraft.network.RegistryFriendlyByteBuf
import net.minecraft.resources.ResourceLocation
/**
* Packet that adds a single skill cooldown to a Pokémon's skill cooldowns map.
*
* @author Hiroku
* @since August 31st, 2025
*/
class SkillCooldownsUpdatePacket(
pokemon: () -> Pokemon?,
val skillId: ResourceLocation,
val cooldownTicks: Int
) : SingleUpdatePacket<Pair<ResourceLocation, Int>, SkillCooldownsUpdatePacket>(pokemon, skillId to cooldownTicks) {
override val id: ResourceLocation = ID
override fun encodeValue(buffer: RegistryFriendlyByteBuf) {
buffer.writeResourceLocation(skillId)
buffer.writeSizedInt(IntSize.U_SHORT, cooldownTicks)
}
override fun set(pokemon: Pokemon, value: Pair<ResourceLocation, Int>) {
val (skillId, cooldownTicks) = value
pokemon.skillCooldownsTicks[skillId] = cooldownTicks
}
companion object {
val ID = cobblemonResource("skill_cooldowns_update")
fun decode(buffer: RegistryFriendlyByteBuf): SkillCooldownsUpdatePacket {
val pokemon = decodePokemon(buffer)
val skillId = buffer.readResourceLocation()
val cooldownTicks = buffer.readSizedInt(IntSize.U_SHORT)
return SkillCooldownsUpdatePacket(pokemon, skillId, cooldownTicks)
}
}
}
@@ -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)
}
}
}
@@ -0,0 +1,47 @@
/*
* 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.server
import com.cobblemon.mod.common.api.net.NetworkPacket
import java.util.UUID
import net.minecraft.network.RegistryFriendlyByteBuf
import net.minecraft.resources.ResourceLocation
/**
* Packet sent by the client to the server to indicate that it wants to use a Poké Skill.
*
* The server will validate if the skill can be used, and if so, will execute it.
*
* @param skillId The ID of the skill to use.
* @param pokemonId The UUID of the Pokémon using the skill.
*
* @author Hiroku
* @since August 31st, 2025
*/
class UsePokeSkillPacket(
val skillId: ResourceLocation,
val pokemonId: UUID,
) : NetworkPacket<UsePokeSkillPacket> {
override val id: ResourceLocation = ID
override fun encode(buffer: RegistryFriendlyByteBuf) {
buffer.writeResourceLocation(skillId)
buffer.writeUUID(pokemonId)
}
companion object {
val ID = ResourceLocation("cobblemon", "use_poke_skill")
fun decode(buffer: RegistryFriendlyByteBuf): UsePokeSkillPacket {
return UsePokeSkillPacket(
buffer.readResourceLocation(),
buffer.readUUID()
)
}
}
}
@@ -0,0 +1,27 @@
/*
* 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.serverhandling
import com.cobblemon.mod.common.CobblemonPokeSkills
import com.cobblemon.mod.common.api.net.ServerNetworkPacketHandler
import com.cobblemon.mod.common.net.messages.server.UsePokeSkillPacket
import com.cobblemon.mod.common.util.party
import net.minecraft.server.MinecraftServer
import net.minecraft.server.level.ServerPlayer
object UsePokeSkillHandler : ServerNetworkPacketHandler<UsePokeSkillPacket> {
override fun handle(packet: UsePokeSkillPacket, server: MinecraftServer, player: ServerPlayer) {
val party = player.party()
val pokemon = party[packet.pokemonId] ?: return // Who?
val skill = CobblemonPokeSkills.getAccessibleSkills(player, pokemon).firstOrNull { it.id == packet.skillId } ?: return // What skill?
if (skill.canUse(player, pokemon)) {
skill.use(player, pokemon)
}
}
}
@@ -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)
}
@@ -766,6 +767,8 @@ open class Pokemon : ShowdownIdentifiable {
val riding: RidingProperties
get() = this.form.riding
var skillCooldownsTicks: MutableMap<ResourceLocation, Int> = mutableMapOf()
init {
storeCoordinates.subscribe { if (it != null && it.store !is PCStore && this.tetheringId != null) afterOnServer(seconds = 0.05F) { this.tetheringId = null } }
storeCoordinates.subscribe {
@@ -1140,6 +1143,16 @@ open class Pokemon : ShowdownIdentifiable {
}
}
fun tickSkillCooldowns() {
this.skillCooldownsTicks.entries.forEach { (key, value) ->
val newValue = value - 1
if (newValue <= 0)
this.skillCooldownsTicks -= key
else
this.skillCooldownsTicks[key] = newValue
}
}
fun isOnInteractionCooldown(group: ResourceLocation): Boolean {
return this.interactionCooldowns.getOrDefault(group, 0) > 0
}
@@ -2228,6 +2241,11 @@ open class Pokemon : ShowdownIdentifiable {
return true
}
fun addSkillCooldown(skillId: ResourceLocation, cooldownTicks: Int) {
skillCooldownsTicks[skillId] = cooldownTicks
onChange(SkillCooldownsUpdatePacket({ this }, skillId, cooldownTicks))
}
fun notify(packet: PokemonUpdatePacket<*>) {
storeCoordinates.get()?.run { sendPacketToPlayers(store.getObservingPlayers(), packet) }
}
@@ -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")
}
@@ -10,6 +10,7 @@ package com.cobblemon.mod.common.pokemon.status.statuses.persistent
import com.cobblemon.mod.common.pokemon.status.PersistentStatus
import com.cobblemon.mod.common.util.cobblemonResource
class FrozenStatus : PersistentStatus(
name = cobblemonResource("frozen"),
showdownName = "frz",
@@ -1,36 +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.tms.obtain
import com.cobblemon.mod.common.api.tms.ObtainMethod
import com.cobblemon.mod.common.util.cobblemonResource
import net.minecraft.network.RegistryFriendlyByteBuf
import net.minecraft.server.level.ServerPlayer
/**
* An [ObtainMethod] for TMs that cannot be unlocked through gameplay triggers.
* These TMs are intended to be granted manually by command or MoLang only.
*/
class ImpossibleObtainMethod : ObtainMethod {
override val passive = false
companion object {
val ID = cobblemonResource("impossible")
fun readFromBuffer(buffer: RegistryFriendlyByteBuf): ImpossibleObtainMethod {
return ImpossibleObtainMethod()
}
}
override fun matches(player: ServerPlayer) = false
override fun writeToBuffer(buffer: RegistryFriendlyByteBuf) {
buffer.writeUtf("cobblemon:impossible")
}
}

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