Compare commits

...
Author SHA1 Message Date
Hiroku 45a9ad866e Fixed heaps of transformations passively activating outside of battle 2026-09-26 18:46:42 +10:00
Hiroku 9c3066e787 Labelled many more forms as temporary 2026-09-20 11:34:59 +10:00
Hiroku eb8598278f Various form change corrections and marked cherrim sunshine as a temporary form in the data 2026-09-20 11:02:04 +10:00
Hiroku 6777c8d57d Merge remote-tracking branch 'origin/main' into form_changes
# Conflicts:
#	common/src/main/kotlin/com/cobblemon/mod/common/api/molang/function/EvolutionMoLangFunctions.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/api/molang/function/PokemonMoLangFunctions.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/item/interactive/PPUpItem.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/pokemon/requirements/StatCompareRequirement.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/pokemon/requirements/StatEqualRequirement.kt
#	gradle.properties
2026-09-20 10:23:05 +10:00
Polymeta bf7d40c9b5 Merge branch 'small-jvm-fix' into 'main'
Added JvmField to Some values in Cobblemon Blocks cause it was forgotten

See merge request cable-mc/cobblemon!2419
2026-09-18 18:30:24 +00:00
Polymeta 5abb3d7f97 Merge branch 'fix/molang-delete-variables-fn' into 'main'
fix: reintroduce `delete_variables` general molang fn

See merge request cable-mc/cobblemon!2421
2026-09-18 18:29:23 +00:00
Gitoido 975ad8186a chore: dangling variable 2026-09-18 18:03:41 +00:00
Gitoido 26b6419f04 fix: reintroduce delete_variables general molang fn 2026-09-18 18:00:44 +00:00
Aram 89e43945a3 Edit CobblemonBlocks.kt 2026-09-16 14:25:26 +02:00
Aram bd8dcddf35 Edit CobblemonBlocks.kt 2026-09-16 14:24:31 +02:00
Polymeta dd372f3160 Merge branch 'recipe-booking' into 'main'
Recipe Book Tweaks

Closes #2088

See merge request cable-mc/cobblemon!2418
2026-09-16 10:03:42 +00:00
dhi_holo c56aab28d4 Recipe Book Tweaks
Closes #2088 as well as fixes a lot of similar issues for gameplay consistency
2026-09-16 18:41:05 +10:00
Polymeta 3cdf28ffdd Merge branch 'Chorus-Briar-Fix' into 'main'
I'm never doing an update where I have to keep track of 650+ structure files again

See merge request cable-mc/cobblemon!2414
2026-09-14 21:18:29 +00:00
Slippy c6fb18ea51 I'm never doing an update hwere I have to keep track of 650+ structure files again 2026-09-14 10:48:01 -05:00
Polymeta 2d851cb134 Merge branch 'tm-crafting-corrections' into 'main'
TM Recipes

See merge request cable-mc/cobblemon!2413
2026-09-14 13:03:40 +00:00
dhi_holo f685be0aab TM Recipes
Corrected two incorrect TM recieps, both in the jsons and the spreadsheets
2026-09-14 16:30:06 +10:00
Polymeta 6ab5ad52ec Merge branch 'typegem-advancement-trigger' into 'main'
Adds typegem item advancement trigger

Closes #2086

See merge request cable-mc/cobblemon!2411
2026-09-13 20:58:08 +00:00
PieDuck 079b2ae766 Merge branch 'typegem-advancement-trigger' of https://gitlab.com/dmnaru/cobblemon into typegem-advancement-trigger 2026-09-13 21:51:29 +01:00
PieDuck 34eea827e7 changelog 2026-09-13 21:51:09 +01:00
PieDuck 06c6ee5a9c Merge branch cobblemon:main into typegem-advancement-trigger 2026-09-13 21:37:22 +01:00
PieDuck 54748c20ea Add type gem item advancement trigger 2026-09-13 21:36:18 +01:00
Polymeta 02e63b6fc8 Merge branch 'gem-block-alert' into 'main'
Fixed Missing Recipe Advancements

See merge request cable-mc/cobblemon!2409
2026-09-13 14:41:13 +00:00
Polymeta 3aebcf66ec rename lang file to match convention 2026-09-13 14:26:44 +00:00
dhi_holo 49a5f716b7 Fixed Missing Recipe Advancements
Why were the advancements in the recipes..?
2026-09-13 22:05:44 +10:00
Hiroku 0bd7b4dab3 Merge branch 'decorative-items-restored' into 'main'
Decorative Items Project Returns

See merge request cable-mc/cobblemon!2343
2026-09-13 02:24:00 +00:00
Hiroku 8cbada0cf5 Fix changelog whackiness [skip-ci] 2026-09-13 12:23:40 +10:00
Hiroku f0784fec2d Merge remote-tracking branch 'origin/main' into decorative-items-restored 2026-09-13 12:21:54 +10:00
Hiroku cfe0c5e0a5 Snap on 2026-09-13 11:27:40 +10:00
Paul f6dbb1387c lil bit of doco [skip-ci] 2026-09-08 18:23:00 +10:00
Paul 1a27e14bec Wait that's meant to be withSuffix 2026-09-08 18:17:37 +10:00
dhi_holo 75bc03fdcb Merge branch 'main' into decorative-items-restored 2026-09-07 15:19:27 +10:00
Paul 7915f3f94e Merge branch 'version/1.9' into form_changes
# Conflicts:
#	common/src/main/java/com/cobblemon/mod/common/mixin/ClientPacketListenerMixin.java
#	common/src/main/kotlin/com/cobblemon/mod/common/api/tms/TechnicalMachines.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/block/entity/PokeSnackBlockEntity.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/block/tmmachine/TMMachineMenu.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/gui/summary/Summary.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/render/models/blockbench/pokemon/gen1/RattataAlolanModel.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/render/models/blockbench/pokemon/gen1/RattataModel.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/net/messages/client/pokemon/update/evolution/ClientboundSeatAssignmentPacket.kt
#	common/src/main/resources/data/cobblemon/species/generation5/panpour.json
#	common/src/main/resources/data/cobblemon/species/generation8/duraludon.json
2026-09-07 11:46:52 +10:00
Paul 396ab13164 1.9 in gradle properties 2026-09-06 20:01:10 +10:00
dhi_holo 309ff3da13 Loaded Cleanup
Added Loaded Dice, cleaned up some particles
2026-08-12 20:15:52 +10:00
dhi_holo 3af91e2a74 Further Tweaking 2026-08-12 14:26:20 +10:00
dhi_holo 2e027e3db7 Some Visual and Auditory Tweaks 2026-08-12 14:13:21 +10:00
dhi_holo fc40fb02c0 Next Batch
Never-Melt Ice, Wide, Scope, and Zoom Lens, as well as new designs for Upgrade and Dubious Disc
2026-08-12 13:52:13 +10:00
dhi_holo 2c1c0299f9 SPHERICAL!
Adds Flame Orb, Life Orb, Toxic Orb, Light Ball, and Smoke Ball blocks
2026-08-12 12:24:21 +10:00
dhi_holo 08cbbaf68c Merge branch 'main' into decorative-items-restored 2026-08-10 10:21:06 +10:00
Sterrezo 6e911acf01 Sound tweaks
Swapped pot sound types from tumblestone to decorated pots and rock sounds from tumblestone to deepslate.
2026-08-09 12:20:13 +02:00
dhi_holo f6d82a1b28 Changelog
and some last second sound tweaks
2026-08-09 19:17:19 +10:00
dhi_holo 702126aeab Adds Throat Spray and Iron Ball
Adds in Throat Spray and Iron Ball blocks, finishes clean up of King's Rock to look a bit more consistent
2026-08-09 19:04:08 +10:00
dhi_holo df566e8fcb Wearable Hat Cleanup
Fixed King's Rock Blockstate and loot table as well

Wearable "Hat" Items can now be prevented from swapping when trying to open the interaction wheel (sneak right-click), making it not a nightmare to give certain items to Pokemon. Yippee!
2026-08-09 18:53:58 +10:00
dhi_holo c83e0f33b5 Wearable Items Mostly Working Better
Wearable Items now can either be "Blocks" or "Hats"
"Blocks" can be placed as blocks in the world, while "Hats" can be put on the player's head by right clicking them in hand
Need to add some form of override when crouching and looking at a Pokemon though
2026-08-09 17:30:49 +10:00
dhi_holo f279f936b6 Generified Plaque/Wreath/Magnet Code
Moved shared code to a singular class
2026-08-09 16:04:22 +10:00
dhi_holo f8e20bafd9 Import Cleanup 2026-08-09 12:23:19 +10:00
dhi_holo a5211ca7ff Convention Alignment
Changed all stackable item blockstates/model files to utilise the convention from vanilla (seen on blocks such as pink petals)
This commit adds no files, and removes no files, it purely renames and swaps out numbers
2026-08-09 12:06:01 +10:00
dhi_holo 2f7bedf001 Update scribblenotes - Decorative Items.txt 2026-08-08 18:05:17 +10:00
dhi_holo 44c31a9ddb Update StackableItemBlock.kt
Simplified the way the hitboxes are defined, to allow for future planned hitboxes to actually work as intended
2026-08-08 17:33:34 +10:00
dhi_holo cfc8a15db1 Update scribblenotes - Decorative Items.txt 2026-08-06 18:35:29 +10:00
dhi_holo d5ba22a86c Removal of Unneeded Lines
deprecate deez nuts
2026-08-06 15:01:34 +10:00
dhi_holo a38505f1c5 Update scribblenotes - Decorative Items.txt
Documenting ideas and plans for future me
2026-08-05 19:28:29 +10:00
dhi_holo 3cf1ba1fb3 Tag Tweaks
Added stuff to relevant tags, removed unused tag from removed feature
2026-08-05 18:36:38 +10:00
dhi_holo 9f5d595827 Import Cleanup
Just removing some imports from reverted changes that snuck into commits
2026-08-05 18:03:06 +10:00
dhi_holo 75673f0204 Mild Polish 2026-08-05 17:09:40 +10:00
dhi_holo b43a7571ff Eject Button
Now with cleaner code, I hope this is more acceptable
2026-08-05 16:13:24 +10:00
dhi_holo b071dc04d3 Metronome
Reimplemented the Metronome, the code has been genericized to allow for more items to be implemented off the same base, although a little bit more work does need to be done there with the comparator output specifically
2026-08-05 15:34:32 +10:00
dhi_holo 12f9ff1647 Wreath, Magnet, and some tweaks to Plaques
Plaques now place the way I had originally set them up, and Galarica Wreaths along with the Magnet are back
2026-08-05 14:34:41 +10:00
dhi_holo 3256a302df Ring Target
Could maybe be polished up, but is good
2026-08-05 13:06:07 +10:00
dhi_holo edbe447477 Basic Decorations
Reimplemented Galarica Cuff, Teapots, Teacups, Weather Rocks, Sachet, Metal Powder, Quick Powder, Bright Powder, Destiny Knot, and Luminous Moss
2026-08-05 12:04:48 +10:00
Gertimoshka 2f43910368 Cleaner Implementation with less duplicate code 2026-08-04 22:21:58 +03:00
dhi_holo c2e87e4cfa Placeable Vitamins Experiment A
Need coder feedback regarding this
Makes Mochi and Feathers require clicking in the air or directly on a Pokemon, if it thinks it can place as a block it prevents usage
2026-08-04 19:25:13 +10:00
dhi_holo e40d2ee806 Create scribblenotes - Decorative Items.txt
Making this a unique commit so it's easy to reference back to later
2026-08-04 14:53:53 +10:00
dhi_holo ba74e7603b Wearables 1
Made Sharp Beak, Covert Cloak, and Shell Helmet wearable
2026-08-04 13:51:49 +10:00
dhi_holo 19c3fe6dc4 Update StackableItemBlock.kt
Fixed hitbox oversight
2026-08-04 13:35:17 +10:00
dhi_holo d0778dd124 Missing Stackables 1
Reimplemented Metal Coat, PP Up, and PP Max's placeable logic
Began work for other Vitamins to work (incomplete)
Added models, textures, blockstates, and loot tables for most incoming blocks
2026-08-04 13:16:46 +10:00
Paul e29087c805 Added molang TransformationRequirement 2026-06-12 15:18:51 +10:00
Paul e850253d88 Implemented action-effect driven temporary form reversion and custom Schedulables in action effects 2026-06-12 14:42:14 +10:00
Paul bbb692f521 Moved transformation progress to a common location and reduced the Transformation tree complexity. Progress works for forms 2026-06-12 12:22:15 +10:00
Paul da1d67bbe6 Clean up parentForm mechanism in FormData 2026-06-08 09:01:24 +10:00
Paul 792834f219 Oh yeah compilation should succeed 2026-06-04 18:27:37 +10:00
Paul 94b31cd658 Remove comment 2026-06-04 18:08:52 +10:00
Paul 19364f39c6 Renaming and restructuring of the actual starting of transformations, added FormEvents 2026-06-04 14:45:13 +10:00
Paul 2fc8f6b9df Oi you got a loicense for that television bruv 2026-05-31 22:15:06 +10:00
Paul 9089ff3bbb Why is the species schema JSON malformed 2026-05-31 21:47:02 +10:00
Paul 90f581051c Simplifications and straightening of transformation controller class tree and codecs 2026-05-31 21:43:06 +10:00
Paul 061bdcc478 Action effect improvements for form transition effects, some cleanup of TemporaryForm reverting 2026-05-31 14:52:12 +10:00
Paul 6811394f71 Compilation fixes and merge conflict resolutions 2026-05-30 13:08:20 +10:00
Paul 1235a70323 Conflict resolve maybe 2026-05-26 21:15:00 +10:00
Segfault Guy d94952347f Portrait updates and form effects. 2025-04-30 00:30:06 -04:00
Segfault Guy 7fe6141640 form20 blaze it 2025-04-20 23:41:12 -04:00
Segfault Guy 4b1653ca6c Merge remote-tracking branch 'origin/main' into form_changes 2025-04-20 20:53:54 -04:00
Segfault Guy 7265ab57b9 Apply species schema changes to evolutions. 2025-04-11 01:47:41 -04:00
Segfault Guy 27e3a95b06 cleanup test changes 2025-04-11 01:17:29 -04:00
Segfault Guy 38de3c6267 In-battle form changes and PokemonProperties form completion. 2025-04-09 00:18:10 -04:00
Segfault Guy 376e5ac906 Merge branch 'main' into form_changes 2025-03-18 22:26:00 -04:00
Segfault Guy b225283dcc Toggleable, deferrable, and wild forms. 2025-03-12 23:00:29 -04:00
Segfault Guy b90f852a71 Clear invalid forms on species change. 2025-02-24 20:12:23 -05:00
Segfault Guy fdf7a9703a coalesce temp and perm forms under same property and instead deserialize by custom adapter instead of having unique properties. 2025-02-23 23:21:43 -05:00
Segfault Guy bb41f28342 Merge remote-tracking branch 'origin/main' into form_changes 2025-02-18 22:33:23 -05:00
Segfault Guy c5ee7ebe7a Fix ability registration for forms. 2025-02-11 21:40:35 -05:00
Segfault Guy f6ae10e1d9 It's about f(orm)cking time. 2025-02-03 23:38:53 -05:00
Segfault GuyandSegfault Guy b2070b53fb Changing form... changes form? Wow! 2024-12-03 23:41:17 -05:00
Segfault GuyandSegfault Guy 7fb873dc2c Showdown Form and Species registration rework. 2024-12-03 23:10:25 -05:00
Segfault GuyandSegfault Guy 641f529de3 Better Form and Evolution triggering. 2024-12-03 19:12:41 -05:00
Segfault GuyandSegfault Guy db9fb4fefa Refactor Evolution and add Transformation to expand application of Evolution events and requirements. 2024-12-02 23:13:57 -05:00
1835 changed files with 22180 additions and 8147 deletions
+41 -34
View File
@@ -1,41 +1,48 @@
# Changelog
## [1.8.1 (September 13th, 2026)](#1-8-1)
## [1.8.2 (MONTH xth, 2026)](#1-8-2)
### Additions
- The following items can now be placed on the ground as blocks:
- King's Rock, Galarica Cuff, Unremarkable Teacup, Masterpiece Teacup, Chipped Pot, Cracked Pot, Sachet, Metal Powder, Quick Powder, Bright Powder, Icy Rock, Heat Rock, Smooth Rock, Damp Rock, Destiny Knot, Luminous Moss, Never-Melt Ice, Wide Lens, Scope Lens, and Zoom Lens.
- Iron Ball, Metal Coat, Throat Spray, HP Up, Protein, Iron, Carbos, Calcium, Zinc, PP Up, PP Max, Upgrade, Dubious Disc, and Loaded Dice.
- The following items can now be placed on various surfaces:
- Galarica Wreath, Magnet, Flame Orb, Life Orb, Toxic Orb, Light Ball, and Smoke Ball.
- The following items can now be placed as blocks, and have additional functionality:
- Ring Target, Metronome, and Eject Button.
- The following items can now be worn by Players and Pokémon:
- Galarica Wreath, Cleanse Tag, Spell Tag, Sharp Beak, Covert Cloak, Shell Helmet, and Never-Melt Ice.
- Wearable items can now be equipped by a player by holding it and right-clicking (or rebound use/interact)
- Wearable items that can be placed down are exempt from this behaviour.
### New rideable Pokémon
### Pokémon Added
#### Regional Forms
### Model updates for the following Pokémon
### Animation updates for the following Pokémon
- Flapple, Appletun, Dipplin, Hydrapple (placeholder animations only).
#### Added sounds to the following moves
### Changes
- Updated various recipes to display in Recipe Groups within the Recipe Book
- Updated most recipes to display more logically/consistently within the Recipe Book's categories
### Fixes
- Fixed a potential world generation stall caused by Type Gem clusters.
- Fixed Pokémon on shoulders not animating if they are visibly holding a held item.
- Fixed NPCs getting their own TM progress file.
- Fixed odd NeoForge crash due to a dependency being outdated. It will now correctly flag the dependency for being outdated.
- Fixed the TM Machine refusing move selections that the `unlockAllMoveDexMovesByDefault` config had made visible, leaving the move slot blank and the craft button unresponsive.
- Fixed the Beast Ball not applying its 0.1× penalty to Pokémon that are not Ultra Beasts.
- Fixed the Moon Ball reading the world's total elapsed time instead of the time of day, so its bonus applied during the day instead.
- Fixed the Love Ball never awarding its 2.5× opposite gender bonus, and matching species by display name instead of identifier.
- Fixed the Timer Ball being weaker than a regular Poké Ball on early turns and only reaching 4× on turn 14 instead of turn 10.
- Fixed the Luxury Ball only doubling Friendship gains of 1, leaving level up and berry gains unaffected.
- Fixed Rufflet, Braviary, and Hisuian Braviary flooding logs with errors about missing sound events.
- Fixed Pokémon property typos in Pangoro and Dedenne herd spawn files.
- Fixed unintentional watermelon cosmetic for Hisuian Electrode.
- Fixed Blastoise having an unintentional passenger seat.
- Fixed form typo in Rockruff-Dusk spawn, preventing it from being able to spawn.
- Fixed the `stat_compare` and `stat_equal` evolution requirements crashing the game when given `special_attack` or `special_defence`, and made them treat any non-permanent stat as a failed requirement instead of crashing.
- Fixed Rowap and Jacoba berries not correctly altering Pokémon sizes when used as bait.
- Fixed Ampharos' eyes not emitting particles.
- Fixed Alolan Raticate's cry not playing.
- Fixed several incorrect light-based spawning conditions for ghosts and bugs.
- Removed unused, placeholder habitat pools.
- Fixed Mantyke, Mantine, and Quaxly getting stuck in a recoil 'expression' during battles due to having an expression assigned as a recoil animation.
- Fixed Lucario's aura particles not emitting.
- Fixed Lycanroc's head movement.
- Added head movement to Archaludon.
- Fixed Duraludon line not having their sleep animations.
- Fixed Diglett line not having their faint animations.
- Fixed Kingambit moving its legs while walking.
- Correctly grants "They're Minerals!" advancement when planting a type gem
- Type Gem Blocks now have advancements to give you the recipe in the recipe book (the data for the advancements were inside the recipes somehow??)
- Some other recipes without advancements have also been corrected
- Corrected the TM Recipes for Charge Beam and Payday
### Developer
### Molang & Datapacks
### Particles
#### New Move Animations
### Localization
- Updated translations for:
- Brazilian Portuguese
- Simplified Chinese
- Japanese
- Updated translations for:
+41
View File
@@ -0,0 +1,41 @@
# Changelog
## [1.8.1 (September 13th, 2026)](#1-8-1)
### Animation updates for the following Pokémon
- Flapple, Appletun, Dipplin, Hydrapple (placeholder animations only).
### Fixes
- Fixed a potential world generation stall caused by Type Gem clusters.
- Fixed Pokémon on shoulders not animating if they are visibly holding a held item.
- Fixed NPCs getting their own TM progress file.
- Fixed odd NeoForge crash due to a dependency being outdated. It will now correctly flag the dependency for being outdated.
- Fixed the TM Machine refusing move selections that the `unlockAllMoveDexMovesByDefault` config had made visible, leaving the move slot blank and the craft button unresponsive.
- Fixed the Beast Ball not applying its 0.1× penalty to Pokémon that are not Ultra Beasts.
- Fixed the Moon Ball reading the world's total elapsed time instead of the time of day, so its bonus applied during the day instead.
- Fixed the Love Ball never awarding its 2.5× opposite gender bonus, and matching species by display name instead of identifier.
- Fixed the Timer Ball being weaker than a regular Poké Ball on early turns and only reaching 4× on turn 14 instead of turn 10.
- Fixed the Luxury Ball only doubling Friendship gains of 1, leaving level up and berry gains unaffected.
- Fixed Rufflet, Braviary, and Hisuian Braviary flooding logs with errors about missing sound events.
- Fixed Pokémon property typos in Pangoro and Dedenne herd spawn files.
- Fixed unintentional watermelon cosmetic for Hisuian Electrode.
- Fixed Blastoise having an unintentional passenger seat.
- Fixed form typo in Rockruff-Dusk spawn, preventing it from being able to spawn.
- Fixed the `stat_compare` and `stat_equal` evolution requirements crashing the game when given `special_attack` or `special_defence`, and made them treat any non-permanent stat as a failed requirement instead of crashing.
- Fixed Rowap and Jacoba berries not correctly altering Pokémon sizes when used as bait.
- Fixed Ampharos' eyes not emitting particles.
- Fixed Alolan Raticate's cry not playing.
- Fixed several incorrect light-based spawning conditions for ghosts and bugs.
- Removed unused, placeholder habitat pools.
- Fixed Mantyke, Mantine, and Quaxly getting stuck in a recoil 'expression' during battles due to having an expression assigned as a recoil animation.
- Fixed Lucario's aura particles not emitting.
- Fixed Lycanroc's head movement.
- Added head movement to Archaludon.
- Fixed Duraludon line not having their sleep animations.
- Fixed Diglett line not having their faint animations.
- Fixed Kingambit moving its legs while walking.
### Localization
- Updated translations for:
- Brazilian Portuguese
- Simplified Chinese
- Japanese
+2 -2
View File
@@ -1,9 +1,9 @@
import utilities.isSnapshot
import utilities.version
import java.time.OffsetDateTime
import java.time.ZoneOffset
import java.time.format.DateTimeFormatter
import utilities.isSnapshot
import utilities.version
/*
*
@@ -10,9 +10,7 @@ package com.cobblemon.mod.common.mixin.accessor;
import net.minecraft.client.gui.components.StateSwitchingButton;
import net.minecraft.client.gui.screens.recipebook.RecipeBookComponent;
import net.minecraft.network.chat.Component;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Mutable;
import org.spongepowered.asm.mixin.gen.Accessor;
@Mixin(RecipeBookComponent.class)
@@ -15,11 +15,9 @@ import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
import com.llamalad7.mixinextras.sugar.Local;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.core.NonNullList;
import net.minecraft.world.Containers;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.Items;
import net.minecraft.world.item.alchemy.PotionBrewing;
import net.minecraft.world.item.crafting.RecipeHolder;
import net.minecraft.world.item.crafting.RecipeManager;
@@ -34,6 +32,7 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
import java.util.List;
import java.util.Optional;
@Mixin(BrewingStandBlockEntity.class)
public class BrewingStandBlockEntityMixin {
@@ -9,17 +9,11 @@
package com.cobblemon.mod.common.mixin.brewing;
import com.cobblemon.mod.common.duck.RecipeAwareSlot;
import com.cobblemon.mod.common.item.crafting.brewingstand.BrewingStandRecipe;
import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
import com.llamalad7.mixinextras.sugar.Local;
import net.minecraft.world.Container;
import net.minecraft.world.entity.player.Inventory;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.inventory.BrewingStandMenu;
import net.minecraft.world.inventory.ContainerData;
import net.minecraft.world.inventory.Slot;
import net.minecraft.world.item.ItemStack;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
@@ -13,7 +13,6 @@ import com.cobblemon.mod.common.item.crafting.brewingstand.BrewingStandRecipe;
import net.minecraft.world.inventory.BrewingStandMenu;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.crafting.RecipeManager;
import net.minecraft.world.level.Level;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.At;
@@ -19,7 +19,6 @@ import net.minecraft.client.Camera;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.level.BlockGetter;
import net.minecraft.world.phys.Vec3;
import org.joml.Quaternionf;
import org.joml.Vector3f;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
@@ -10,9 +10,7 @@ package com.cobblemon.mod.common.mixin.client;
import com.cobblemon.mod.common.CobblemonRecipeCategories;
import com.cobblemon.mod.common.item.crafting.CookingPotBookCategory;
import com.cobblemon.mod.common.item.crafting.CookingPotRecipe;
import com.cobblemon.mod.common.item.crafting.CookingPotRecipeBase;
import com.cobblemon.mod.common.item.crafting.CookingPotShapelessRecipe;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Maps;
@@ -97,10 +97,10 @@ import com.cobblemon.mod.common.pokemon.Pokemon
import com.cobblemon.mod.common.pokemon.aspects.ALPHA_ASPECT
import com.cobblemon.mod.common.pokemon.aspects.CHARACTERISTIC_RAINBOW_ASPECT
import com.cobblemon.mod.common.pokemon.aspects.COSMETIC_SLOT_ASPECT
import com.cobblemon.mod.common.pokemon.aspects.FORM_ASPECTS
import com.cobblemon.mod.common.pokemon.aspects.GENDER_ASPECT
import com.cobblemon.mod.common.pokemon.aspects.MARK_ASPECT
import com.cobblemon.mod.common.pokemon.aspects.SHINY_ASPECT
import com.cobblemon.mod.common.pokemon.evolution.variants.BlockClickEvolution
import com.cobblemon.mod.common.pokemon.feature.SlowpokeTailRegrowthSpeciesFeature
import com.cobblemon.mod.common.pokemon.feature.SlowpokeTailRegrowthSpeciesFeatureProvider
import com.cobblemon.mod.common.pokemon.feature.TagSeasonResolver
@@ -115,6 +115,7 @@ import com.cobblemon.mod.common.pokemon.properties.NoAIProperty
import com.cobblemon.mod.common.pokemon.properties.UnaspectPropertyType
import com.cobblemon.mod.common.pokemon.properties.UncatchableProperty
import com.cobblemon.mod.common.pokemon.stat.CobblemonStatProvider
import com.cobblemon.mod.common.pokemon.transformation.triggers.BlockClickTrigger
import com.cobblemon.mod.common.starter.CobblemonStarterHandler
import com.cobblemon.mod.common.util.*
import com.cobblemon.mod.common.world.feature.CobblemonPlacedFeatures
@@ -273,13 +274,8 @@ object Cobblemon {
PlatformEvents.RIGHT_CLICK_BLOCK.subscribe { event ->
val player = event.player
val block = player.level().getBlockState(event.pos).block
player.party().forEach { pokemon ->
pokemon.lockedEvolutions
.filterIsInstance<BlockClickEvolution>()
.forEach { evolution ->
evolution.attemptEvolution(pokemon, BlockClickEvolution.BlockInteractionContext(block, player.level()))
}
}
val context = BlockClickTrigger.Context(block, player.level())
player.party().forEach { pokemon -> pokemon.triggerTransformations<BlockClickTrigger>(context) }
}
PlatformEvents.CHANGE_DIMENSION.subscribe {
@@ -323,6 +319,7 @@ object Cobblemon {
SHINY_ASPECT.register()
GENDER_ASPECT.register()
FORM_ASPECTS.register()
COSMETIC_SLOT_ASPECT.register()
CHARACTERISTIC_RAINBOW_ASPECT.register()
ALPHA_ASPECT.register()
@@ -9,6 +9,7 @@
package com.cobblemon.mod.common
import com.bedrockk.molang.Expression
import com.cobblemon.mod.common.CobblemonBehaviours.autoPokemonBehaviours
import com.cobblemon.mod.common.CobblemonNetwork.sendPacket
import com.cobblemon.mod.common.api.ai.CobblemonBehaviour
import com.cobblemon.mod.common.api.ai.config.BehaviourConfig
@@ -19,16 +20,7 @@ import com.cobblemon.mod.common.api.molang.ExpressionLike
import com.cobblemon.mod.common.api.npc.configuration.MoLangConfigVariable
import com.cobblemon.mod.common.api.reactive.SimpleObservable
import com.cobblemon.mod.common.net.messages.client.data.BehaviourSyncPacket
import com.cobblemon.mod.common.util.adapters.ActivityAdapter
import com.cobblemon.mod.common.util.adapters.BehaviourConfigAdapter
import com.cobblemon.mod.common.util.adapters.ExpressionAdapter
import com.cobblemon.mod.common.util.adapters.ExpressionLikeAdapter
import com.cobblemon.mod.common.util.adapters.ExpressionOrEntityVariableAdapter
import com.cobblemon.mod.common.util.adapters.IdentifierAdapter
import com.cobblemon.mod.common.util.adapters.MemoryModuleTypeAdapter
import com.cobblemon.mod.common.util.adapters.SensorTypeAdapter
import com.cobblemon.mod.common.util.adapters.TaskConfigAdapter
import com.cobblemon.mod.common.util.adapters.TranslatedTextAdapter
import com.cobblemon.mod.common.util.adapters.*
import com.cobblemon.mod.common.util.cobblemonResource
import com.cobblemon.mod.common.util.endsWith
import com.google.gson.Gson
@@ -16,6 +16,8 @@ import com.cobblemon.mod.common.block.MintBlock.MintType
import com.cobblemon.mod.common.block.campfirepot.CampfireBlock
import com.cobblemon.mod.common.block.campfirepot.CampfirePotBlock
import com.cobblemon.mod.common.block.chest.GildedChestBlock
import com.cobblemon.mod.common.block.decor.ActivatableDecorationBlock
import com.cobblemon.mod.common.block.decor.RingTargetBlock
import com.cobblemon.mod.common.block.general.BaleBlock
import com.cobblemon.mod.common.block.general.HorizontalRotationCarpetBlock
import com.cobblemon.mod.common.block.general.HorizontalRotationalBlock
@@ -620,6 +622,88 @@ object CobblemonBlocks : PlatformRegistry<Registry<Block>, ResourceKey<Registry<
@JvmField
val WEAKNESS_POLICY = create("weakness_policy", WallAttachedDirectionalShapeBlock(BlockBehaviour.Properties.of().sound(CobblemonSounds.ITEM_BLOCK_PAPER_LARGE_SOUNDS).mapColor(MapColor.NONE).noOcclusion().noCollission(), 14, 12, 1))
@JvmField
val RING_TARGET = create("ring_target", RingTargetBlock(BlockBehaviour.Properties.of().sound(SoundType.WOOD).mapColor(MapColor.NONE).noOcclusion().strength(0.125f)))
@JvmField
val MAGNET = create("magnet", MagnetBlock(BlockBehaviour.Properties.of().sound(SoundType.METAL).mapColor(MapColor.NONE).noOcclusion().strength(0.075f)))
@JvmField
val GALARICA_WREATH = create("galarica_wreath", GalaricaWreathBlock(BlockBehaviour.Properties.of().sound(SoundType.AZALEA_LEAVES).mapColor(MapColor.NONE).noOcclusion().noCollission()))
@JvmField
val FLAME_ORB = create("flame_orb", OrbBlock(BlockBehaviour.Properties.of().sound(SoundType.GLASS).mapColor(MapColor.NONE).noOcclusion().lightLevel{15}))
@JvmField
val TOXIC_ORB = create("toxic_orb", OrbBlock(BlockBehaviour.Properties.of().sound(SoundType.GLASS).mapColor(MapColor.NONE).noOcclusion()))
@JvmField
val LIFE_ORB = create("life_orb", OrbBlock(BlockBehaviour.Properties.of().sound(SoundType.GLASS).mapColor(MapColor.NONE).noOcclusion().lightLevel{7}))
@JvmField
val LIGHT_BALL = create("light_ball", OrbBlock(BlockBehaviour.Properties.of().sound(SoundType.GLASS).mapColor(MapColor.NONE).noOcclusion().lightLevel{13}))
@JvmField
val SMOKE_BALL = create("smoke_ball", OrbBlock(BlockBehaviour.Properties.of().sound(SoundType.GLASS).mapColor(MapColor.NONE).noOcclusion()))
@JvmField
val KINGS_ROCK = create("kings_rock", DecorativeItemBlock(BlockBehaviour.Properties.of().sound(CobblemonSounds.TUMBLESTONE_BLOCK_SOUNDS).mapColor(MapColor.NONE).noOcclusion(), DecorativeItemBlock.DecorativeItemBlockType.CENTERED_6x))
@JvmField
val GALARICA_CUFF = create("galarica_cuff", DecorativeItemBlock(BlockBehaviour.Properties.of().sound(SoundType.AZALEA_LEAVES).mapColor(MapColor.NONE).noCollission().noOcclusion(), DecorativeItemBlock.DecorativeItemBlockType.FLATTENED_10x4))
@JvmField
val UNREMARKABLE_TEACUP = create("unremarkable_teacup", DecorativeItemBlock(BlockBehaviour.Properties.of().sound(SoundType.DECORATED_POT).mapColor(MapColor.NONE).noOcclusion(), DecorativeItemBlock.DecorativeItemBlockType.TEACUP))
@JvmField
val MASTERPIECE_TEACUP = create("masterpiece_teacup", DecorativeItemBlock(BlockBehaviour.Properties.of().sound(SoundType.DECORATED_POT).mapColor(MapColor.NONE).noOcclusion(), DecorativeItemBlock.DecorativeItemBlockType.TEACUP))
@JvmField
val CHIPPED_POT = create("chipped_pot", DecorativeItemBlock(BlockBehaviour.Properties.of().sound(SoundType.DECORATED_POT).mapColor(MapColor.NONE).noOcclusion(), DecorativeItemBlock.DecorativeItemBlockType.TEAPOT))
@JvmField
val CRACKED_POT = create("cracked_pot", DecorativeItemBlock(BlockBehaviour.Properties.of().sound(SoundType.DECORATED_POT).mapColor(MapColor.NONE).noOcclusion(), DecorativeItemBlock.DecorativeItemBlockType.TEAPOT))
@JvmField
val SACHET = create("sachet", DecorativeItemBlock(BlockBehaviour.Properties.of().sound(SoundType.WOOL).mapColor(MapColor.NONE).noOcclusion(), DecorativeItemBlock.DecorativeItemBlockType.POUCH))
@JvmField
val METAL_POWDER = create("metal_powder", DecorativeItemBlock(BlockBehaviour.Properties.of().sound(SoundType.WOOL).mapColor(MapColor.NONE).noOcclusion(), DecorativeItemBlock.DecorativeItemBlockType.POUCH))
@JvmField
val QUICK_POWDER = create("quick_powder", DecorativeItemBlock(BlockBehaviour.Properties.of().sound(SoundType.WOOL).mapColor(MapColor.NONE).noOcclusion(), DecorativeItemBlock.DecorativeItemBlockType.POUCH))
@JvmField
val BRIGHT_POWDER = create("bright_powder", DecorativeItemBlock(BlockBehaviour.Properties.of().sound(SoundType.WOOL).mapColor(MapColor.NONE).noOcclusion().lightLevel{3}, DecorativeItemBlock.DecorativeItemBlockType.POUCH))
@JvmField
val NEVER_MELT_ICE = create("never_melt_ice", DecorativeItemBlock(BlockBehaviour.Properties.of().sound(SoundType.GLASS).mapColor(MapColor.NONE).noOcclusion().friction(0.989F), DecorativeItemBlock.DecorativeItemBlockType.NEVERMELT))
@JvmField
val SCOPE_LENS = create("scope_lens", DecorativeItemBlock(BlockBehaviour.Properties.of().sound(SoundType.COPPER).mapColor(MapColor.NONE).noOcclusion(), DecorativeItemBlock.DecorativeItemBlockType.SCOPE))
@JvmField
val WIDE_LENS = create("wide_lens", DecorativeItemBlock(BlockBehaviour.Properties.of().sound(SoundType.COPPER).mapColor(MapColor.NONE).noOcclusion(), DecorativeItemBlock.DecorativeItemBlockType.WIDE))
@JvmField
val ZOOM_LENS = create("zoom_lens", DecorativeItemBlock(BlockBehaviour.Properties.of().sound(SoundType.COPPER).mapColor(MapColor.NONE).noOcclusion(), DecorativeItemBlock.DecorativeItemBlockType.ZOOM))
@JvmField
val ICY_ROCK = create("icy_rock", DecorativeItemBlock(BlockBehaviour.Properties.of().sound(SoundType.DEEPSLATE).mapColor(MapColor.NONE).noOcclusion(), DecorativeItemBlock.DecorativeItemBlockType.FLATTENED_8x4))
@JvmField
val HEAT_ROCK = create("heat_rock", DecorativeItemBlock(BlockBehaviour.Properties.of().sound(SoundType.DEEPSLATE).mapColor(MapColor.NONE).noOcclusion(), DecorativeItemBlock.DecorativeItemBlockType.FLATTENED_8x4))
@JvmField
val SMOOTH_ROCK = create("smooth_rock", DecorativeItemBlock(BlockBehaviour.Properties.of().sound(SoundType.DEEPSLATE).mapColor(MapColor.NONE).noOcclusion(), DecorativeItemBlock.DecorativeItemBlockType.FLATTENED_8x4))
@JvmField
val DAMP_ROCK = create("damp_rock", DecorativeItemBlock(BlockBehaviour.Properties.of().sound(SoundType.DEEPSLATE).mapColor(MapColor.NONE).noOcclusion(), DecorativeItemBlock.DecorativeItemBlockType.FLATTENED_8x6))
@JvmField
val DESTINY_KNOT = create("destiny_knot", DecorativeItemBlock(BlockBehaviour.Properties.of().sound(SoundType.WOOL).mapColor(MapColor.NONE).noOcclusion(), DecorativeItemBlock.DecorativeItemBlockType.KNOT))
@JvmField
val LUMINOUS_MOSS = create("luminous_moss", DecorativeItemBlock(BlockBehaviour.Properties.of().sound(SoundType.MOSS).mapColor(MapColor.NONE).noOcclusion().lightLevel{5}, DecorativeItemBlock.DecorativeItemBlockType.CENTERED_8x))
@JvmField
val METRONOME = create("metronome", ActivatableDecorationBlock(BlockBehaviour.Properties.of().sound(SoundType.METAL).mapColor(MapColor.NONE).pushReaction(PushReaction.DESTROY).noOcclusion(), ActivatableDecorationBlock.ActivatableDecorationBlockType.METRONOME))
@JvmField
val EJECT_BUTTON = create("eject_button", EjectButtonBlock(BlockBehaviour.Properties.of().sound(SoundType.METAL).mapColor(MapColor.NONE).pushReaction(PushReaction.DESTROY).noOcclusion().strength(0.125f), 40))
@JvmField
val LOADED_DICE = create("loaded_dice", StackableItemBlock(BlockBehaviour.Properties.of().sound(SoundType.CANDLE).mapColor(MapColor.NONE).noOcclusion(), StackableItemBlock.StackableItemBlockType.DICE))
@JvmField
val IRON_BALL = create("iron_ball", StackableItemBlock(BlockBehaviour.Properties.of().sound(SoundType.METAL).mapColor(MapColor.NONE).noOcclusion(), StackableItemBlock.StackableItemBlockType.IRON_BALL))
@JvmField
val METAL_COAT = create("metal_coat", StackableItemBlock(BlockBehaviour.Properties.of().sound(SoundType.METAL).mapColor(MapColor.NONE).noOcclusion(), StackableItemBlock.StackableItemBlockType.METAL_COAT))
@JvmField
val UPGRADE = create("upgrade", StackableItemBlock(BlockBehaviour.Properties.of().sound(SoundType.CANDLE).mapColor(MapColor.NONE).noOcclusion(), StackableItemBlock.StackableItemBlockType.UPGRADE))
@JvmField
val DUBIOUS_DISC = create("dubious_disc", StackableItemBlock(BlockBehaviour.Properties.of().sound(SoundType.CANDLE).mapColor(MapColor.NONE).noOcclusion(), StackableItemBlock.StackableItemBlockType.UPGRADE))
@JvmField
val THROAT_SPRAY = create("throat_spray", StackableItemBlock(BlockBehaviour.Properties.of().sound(SoundType.CANDLE).mapColor(MapColor.NONE).noOcclusion(), StackableItemBlock.StackableItemBlockType.THROAT_SPRAY))
@JvmField
val FULL_HEAL = create("full_heal", StackableItemBlock(BlockBehaviour.Properties.of().sound(SoundType.CANDLE).mapColor(MapColor.NONE).noOcclusion(), StackableItemBlock.StackableItemBlockType.STATUS_RESTORE))
@JvmField
@@ -670,6 +754,23 @@ object CobblemonBlocks : PlatformRegistry<Registry<Block>, ResourceKey<Registry<
@JvmField
val X_SPEED = create("x_${Stats.SPEED.identifier.path}", StackableItemBlock(BlockBehaviour.Properties.of().sound(SoundType.CANDLE).mapColor(MapColor.NONE).noOcclusion(), StackableItemBlock.StackableItemBlockType.BATTLE_ITEM))
@JvmField
val HP_UP = create("hp_up", StackableItemBlock(BlockBehaviour.Properties.of().sound(SoundType.CANDLE).mapColor(MapColor.NONE).noOcclusion(), StackableItemBlock.StackableItemBlockType.VITAMIN))
@JvmField
val PROTEIN = create("protein", StackableItemBlock(BlockBehaviour.Properties.of().sound(SoundType.CANDLE).mapColor(MapColor.NONE).noOcclusion(), StackableItemBlock.StackableItemBlockType.VITAMIN))
@JvmField
val IRON = create("iron", StackableItemBlock(BlockBehaviour.Properties.of().sound(SoundType.CANDLE).mapColor(MapColor.NONE).noOcclusion(), StackableItemBlock.StackableItemBlockType.VITAMIN))
@JvmField
val CARBOS = create("carbos", StackableItemBlock(BlockBehaviour.Properties.of().sound(SoundType.CANDLE).mapColor(MapColor.NONE).noOcclusion(), StackableItemBlock.StackableItemBlockType.VITAMIN))
@JvmField
val CALCIUM = create("calcium", StackableItemBlock(BlockBehaviour.Properties.of().sound(SoundType.CANDLE).mapColor(MapColor.NONE).noOcclusion(), StackableItemBlock.StackableItemBlockType.VITAMIN))
@JvmField
val ZINC = create("zinc", StackableItemBlock(BlockBehaviour.Properties.of().sound(SoundType.CANDLE).mapColor(MapColor.NONE).noOcclusion(), StackableItemBlock.StackableItemBlockType.VITAMIN))
@JvmField
val PP_UP = create("pp_up", StackableItemBlock(BlockBehaviour.Properties.of().sound(SoundType.CANDLE).mapColor(MapColor.NONE).noOcclusion(), StackableItemBlock.StackableItemBlockType.VITAMIN))
@JvmField
val PP_MAX = create("pp_max", StackableItemBlock(BlockBehaviour.Properties.of().sound(SoundType.CANDLE).mapColor(MapColor.NONE).noOcclusion(), StackableItemBlock.StackableItemBlockType.VITAMIN))
@JvmField
val MONITOR = create("monitor", MonitorBlock(BlockBehaviour.Properties.of().mapColor(MapColor.METAL).sound(SoundType.METAL).pushReaction(PushReaction.BLOCK).requiresCorrectToolForDrops().strength(5.0F, 6.0F).lightLevel { if (it.getValue(MonitorBlock.SCREEN) != MonitorBlock.MonitorScreen.OFF) 13 else 0 }))
@JvmField
@@ -685,6 +786,7 @@ object CobblemonBlocks : PlatformRegistry<Registry<Block>, ResourceKey<Registry<
@JvmField
val PC = create("pc", PCBlock(BlockBehaviour.Properties.of().mapColor(MapColor.METAL).sound(SoundType.METAL).pushReaction(PushReaction.BLOCK).strength(2F).noOcclusion().lightLevel { if ((it.getValue(PCBlock.ON) as Boolean) && (it.getValue(PCBlock.PART) == PCBlock.PCPart.TOP)) 13 else 0 }))
@JvmField
val TM_MACHINE = create(
"tm_machine",
TMMachineBlock(
@@ -713,7 +815,7 @@ object CobblemonBlocks : PlatformRegistry<Registry<Block>, ResourceKey<Registry<
@JvmField
val PASTURE = create("pasture", PastureBlock(BlockBehaviour.Properties.of().mapColor(MapColor.COLOR_BROWN).sound(SoundType.WOOD).strength(2F).noOcclusion().pushReaction(PushReaction.BLOCK).lightLevel { if ((it.getValue(PastureBlock.ON) as Boolean) && (it.getValue(PastureBlock.PART) == PastureBlock.PasturePart.TOP)) 13 else 0 }))
@JvmField
val RED_MINT = create("red_mint", MintBlock(MintType.RED, BlockBehaviour.Properties.of().mapColor(MapColor.COLOR_RED).noCollission().randomTicks().instabreak().sound(CobblemonSounds.MINT_SOUNDS).pushReaction(PushReaction.DESTROY)))
@JvmField
val BLUE_MINT = create("blue_mint", MintBlock(MintType.BLUE, BlockBehaviour.Properties.of().mapColor(MapColor.COLOR_BLUE).noCollission().randomTicks().instabreak().sound(CobblemonSounds.MINT_SOUNDS).pushReaction(PushReaction.DESTROY)))
@@ -19,7 +19,6 @@ import net.minecraft.server.level.ServerPlayer
import net.minecraft.server.packs.PackType
import net.minecraft.server.packs.resources.PreparableReloadListener
import net.minecraft.tags.TagKey
import net.minecraft.world.inventory.MenuType
import net.minecraft.world.level.GameRules
import net.minecraft.world.level.ItemLike
import net.minecraft.world.level.biome.Biome
@@ -472,9 +472,9 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
// Evolution items
@JvmField val LINK_CABLE = create("link_cable", LinkCableItem())
@JvmField val DRAGON_SCALE = noSettingsItem("dragon_scale")
@JvmField val METAL_COAT = noSettingsItem("metal_coat")
@JvmField val UPGRADE = noSettingsItem("upgrade")
@JvmField val DUBIOUS_DISC = noSettingsItem("dubious_disc")
@JvmField val METAL_COAT = itemNameBlockItem("metal_coat", CobblemonBlocks.METAL_COAT)
@JvmField val UPGRADE = itemNameBlockItem("upgrade", CobblemonBlocks.UPGRADE)
@JvmField val DUBIOUS_DISC = itemNameBlockItem("dubious_disc", CobblemonBlocks.DUBIOUS_DISC)
@JvmField val DEEP_SEA_SCALE = noSettingsItem("deep_sea_scale")
@JvmField val DEEP_SEA_TOOTH = noSettingsItem("deep_sea_tooth")
@JvmField val ELECTIRIZER = noSettingsItem("electirizer")
@@ -483,7 +483,7 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
@JvmField val PROTECTOR = noSettingsItem("protector")
@JvmField val REAPER_CLOTH = noSettingsItem("reaper_cloth")
@JvmField val PRISM_SCALE = noSettingsItem("prism_scale")
@JvmField val SACHET = noSettingsItem("sachet")
@JvmField val SACHET = itemNameBlockItem("sachet", CobblemonBlocks.SACHET)
@JvmField val WHIPPED_DREAM = create("whipped_dream", foodItem(8, 0.3f))
@JvmField val STRAWBERRY_SWEET = create("strawberry_sweet", foodItem(6, 0.125f))
@JvmField val LOVE_SWEET = create("love_sweet", foodItem(6, 0.125f))
@@ -492,22 +492,20 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
@JvmField val FLOWER_SWEET = create("flower_sweet", foodItem(6, 0.125f))
@JvmField val STAR_SWEET = create("star_sweet", foodItem(6, 0.125f))
@JvmField val RIBBON_SWEET = create("ribbon_sweet", foodItem(6, 0.125f))
@JvmField val CHIPPED_POT = noSettingsItem("chipped_pot")
@JvmField val CRACKED_POT = noSettingsItem("cracked_pot")
@JvmField val MASTERPIECE_TEACUP = noSettingsItem("masterpiece_teacup")
@JvmField val UNREMARKABLE_TEACUP = noSettingsItem("unremarkable_teacup")
@JvmField val CHIPPED_POT = itemNameBlockItem("chipped_pot", CobblemonBlocks.CHIPPED_POT)
@JvmField val CRACKED_POT = itemNameBlockItem("cracked_pot", CobblemonBlocks.CRACKED_POT)
@JvmField val MASTERPIECE_TEACUP = itemNameBlockItem("masterpiece_teacup", CobblemonBlocks.MASTERPIECE_TEACUP)
@JvmField val UNREMARKABLE_TEACUP = itemNameBlockItem("unremarkable_teacup", CobblemonBlocks.UNREMARKABLE_TEACUP)
@JvmField val SWEET_APPLE = compostableItem("sweet_apple", foodItem(4, 0.3f), 0.65f)
@JvmField val TART_APPLE = compostableItem("tart_apple", foodItem(4, 0.3f), 0.65f)
@JvmField val SYRUPY_APPLE = compostableItem("syrupy_apple", foodItem(4, 0.3f), 0.65f)
@JvmField val GALARICA_CUFF = noSettingsItem("galarica_cuff")
@JvmField val GALARICA_WREATH = noSettingsItem("galarica_wreath")
@JvmField val GALARICA_CUFF = itemNameBlockItem("galarica_cuff", CobblemonBlocks.GALARICA_CUFF)
@JvmField val BLACK_AUGURITE = noSettingsItem("black_augurite")
@JvmField val PEAT_BLOCK = noSettingsItem("peat_block")
@JvmField val RAZOR_CLAW = noSettingsItem("razor_claw")
@JvmField val RAZOR_FANG = noSettingsItem("razor_fang")
@JvmField val AUSPICIOUS_ARMOR = heldItem("auspicious_armor")
@JvmField val MALICIOUS_ARMOR = heldItem("malicious_armor")
@JvmField val SHELL_HELMET = heldItem("shell_helmet")
@JvmField val METAL_ALLOY = noSettingsItem("metal_alloy")
@JvmField val SCROLL_OF_DARKNESS = noSettingsItem("scroll_of_darkness")
@JvmField val SCROLL_OF_WATERS = noSettingsItem("scroll_of_waters")
@@ -651,17 +649,17 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
@JvmField
val EXPERIENCE_CANDY_XL = candyItem("exp_candy_xl") { _, _ -> CandyItem.DEFAULT_XL_CANDY_YIELD }
@JvmField
val CALCIUM = create("calcium", VitaminItem(Stats.SPECIAL_ATTACK))
val CALCIUM = create("calcium", VitaminItem(Stats.SPECIAL_ATTACK, CobblemonBlocks.CALCIUM))
@JvmField
val CARBOS = create("carbos", VitaminItem(Stats.SPEED))
val CARBOS = create("carbos", VitaminItem(Stats.SPEED, CobblemonBlocks.CARBOS))
@JvmField
val HP_UP = create("hp_up", VitaminItem(Stats.HP))
val HP_UP = create("hp_up", VitaminItem(Stats.HP, CobblemonBlocks.HP_UP))
@JvmField
val IRON = create("iron", VitaminItem(Stats.DEFENCE))
val IRON = create("iron", VitaminItem(Stats.DEFENCE, CobblemonBlocks.IRON))
@JvmField
val PROTEIN = create("protein", VitaminItem(Stats.ATTACK))
val PROTEIN = create("protein", VitaminItem(Stats.ATTACK, CobblemonBlocks.PROTEIN))
@JvmField
val ZINC = create("zinc", VitaminItem(Stats.SPECIAL_DEFENCE))
val ZINC = create("zinc", VitaminItem(Stats.SPECIAL_DEFENCE, CobblemonBlocks.ZINC))
@JvmField
val HEALTH_MOCHI = create("health_mochi", MochiItem(Stats.HP))
@JvmField
@@ -743,9 +741,9 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
@JvmField
val MAX_REVIVE = create("max_revive", ReviveItem(max = true))
@JvmField
val PP_UP = create("pp_up", PPUpItem(1))
val PP_UP = create("pp_up", PPUpItem(1, CobblemonBlocks.PP_UP))
@JvmField
val PP_MAX = create("pp_max", PPUpItem(3))
val PP_MAX = create("pp_max", PPUpItem(3, CobblemonBlocks.PP_MAX))
@JvmField
val RED_MINT_SEEDS = mintSeed("red", MintType.RED.getCropBlock())
@@ -922,11 +920,18 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
@JvmField val CHOICE_SPECS = wearableItem("choice_specs")
@JvmField val EXP_SHARE = wearableItem("exp_share")
@JvmField val FOCUS_BAND = wearableItem("focus_band")
@JvmField val KINGS_ROCK = wearableItem("kings_rock")
@JvmField val KINGS_ROCK = wearableBlockItem("kings_rock", CobblemonBlocks.KINGS_ROCK)
@JvmField val NEVER_MELT_ICE = wearableBlockItem("never_melt_ice", CobblemonBlocks.NEVER_MELT_ICE)
@JvmField val MUSCLE_BAND = wearableItem("muscle_band")
@JvmField val ROCKY_HELMET = wearableItem("rocky_helmet")
@JvmField val SAFETY_GOGGLES = wearableItem("safety_goggles")
@JvmField val WISE_GLASSES = wearableItem("wise_glasses")
@JvmField val SHARP_BEAK = wearableItem("sharp_beak")
@JvmField val COVERT_CLOAK = wearableItem("covert_cloak")
@JvmField val SHELL_HELMET = wearableItem("shell_helmet")
@JvmField val GALARICA_WREATH = wearableBlockItem("galarica_wreath", CobblemonBlocks.GALARICA_WREATH)
@JvmField val CLEANSE_TAG = wearableBlockItem("cleanse_tag", CobblemonBlocks.CLEANSE_TAG)
@JvmField val SPELL_TAG = wearableBlockItem("spell_tag", CobblemonBlocks.SPELL_TAG)
// Held Items
@JvmField
@@ -954,17 +959,13 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
@JvmField
val CHOICE_SCARF = heldItem("choice_scarf")
@JvmField
val CLEANSE_TAG = itemNameBlockItem("cleanse_tag", CobblemonBlocks.CLEANSE_TAG)
@JvmField
val CLEAR_AMULET = heldItem("clear_amulet")
@JvmField
val COVERT_CLOAK = heldItem("covert_cloak")
@JvmField
val DESTINY_KNOT = heldItem("destiny_knot")
val DESTINY_KNOT = itemNameBlockItem("destiny_knot", CobblemonBlocks.DESTINY_KNOT)
@JvmField
val DRAGON_FANG = heldItem("dragon_fang")
@JvmField
val EJECT_BUTTON = heldItem("eject_button")
val EJECT_BUTTON = itemNameBlockItem("eject_button", CobblemonBlocks.EJECT_BUTTON)
@JvmField
val EJECT_PACK = heldItem("eject_pack")
@JvmField
@@ -978,7 +979,7 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
@JvmField
val FAIRY_FEATHER = heldItem("fairy_feather")
@JvmField
val FLAME_ORB = heldItem("flame_orb")
val FLAME_ORB = itemNameBlockItem("flame_orb", CobblemonBlocks.FLAME_ORB)
@JvmField
val FLOAT_STONE = heldItem("float_stone")
@JvmField
@@ -992,34 +993,32 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
@JvmField
val HEAVY_DUTY_BOOTS = heldItem("heavy_duty_boots")
@JvmField
val IRON_BALL = heldItem("iron_ball")
val IRON_BALL = itemNameBlockItem("iron_ball", CobblemonBlocks.IRON_BALL)
@JvmField
val LAGGING_TAIL = heldItem("lagging_tail")
@JvmField
val LEFTOVERS = compostableHeldItem("leftovers", null, 0.50f)
@JvmField
val LIFE_ORB = heldItem("life_orb")
val LIFE_ORB = itemNameBlockItem("life_orb", CobblemonBlocks.LIFE_ORB)
@JvmField
val LIGHT_BALL = heldItem("light_ball")
val LIGHT_BALL = itemNameBlockItem("light_ball", CobblemonBlocks.LIGHT_BALL)
@JvmField
val LIGHT_CLAY = heldItem("light_clay")
@JvmField
val LOADED_DICE = heldItem("loaded_dice")
val LOADED_DICE = itemNameBlockItem("loaded_dice", CobblemonBlocks.LOADED_DICE)
@JvmField
val LUCKY_EGG = heldItem("lucky_egg")
@JvmField
val LUMINOUS_MOSS = heldItem("luminous_moss")
val LUMINOUS_MOSS = itemNameBlockItem("luminous_moss", CobblemonBlocks.LUMINOUS_MOSS)
@JvmField
val MAGNET = heldItem("magnet")
val MAGNET = itemNameBlockItem("magnet", CobblemonBlocks.MAGNET)
@JvmField
val METRONOME = heldItem("metronome")
val METRONOME = itemNameBlockItem("metronome", CobblemonBlocks.METRONOME)
@JvmField
val MIRACLE_SEED = heldItem("miracle_seed")
@JvmField
val MYSTIC_WATER = heldItem("mystic_water")
@JvmField
val NEVER_MELT_ICE = heldItem("never_melt_ice")
@JvmField
val POISON_BARB = heldItem("poison_barb")
@JvmField
val POWER_ANKLET = heldItem("power_anklet")
@@ -1044,13 +1043,11 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
@JvmField
val RED_CARD = heldItem("red_card")
@JvmField
val RING_TARGET = heldItem("ring_target")
val RING_TARGET = itemNameBlockItem("ring_target", CobblemonBlocks.RING_TARGET)
@JvmField
val ROOM_SERVICE = heldItem("room_service")
@JvmField
val SCOPE_LENS = heldItem("scope_lens")
@JvmField
val SHARP_BEAK = heldItem("sharp_beak")
val SCOPE_LENS = itemNameBlockItem("scope_lens", CobblemonBlocks.SCOPE_LENS)
@JvmField
val SHED_SHELL = heldItem("shed_shell")
@JvmField
@@ -1062,9 +1059,7 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
@JvmField
val SOFT_SAND = heldItem("soft_sand")
@JvmField
val SPELL_TAG = itemNameBlockItem("spell_tag", CobblemonBlocks.SPELL_TAG)
@JvmField
val SMOKE_BALL = heldItem("smoke_ball")
val SMOKE_BALL = itemNameBlockItem("smoke_ball", CobblemonBlocks.SMOKE_BALL)
@JvmField
val SOOTHE_BELL = heldItem("soothe_bell")
@JvmField
@@ -1072,9 +1067,9 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
@JvmField
val TERRAIN_EXTENDER = heldItem("terrain_extender")
@JvmField
val THROAT_SPRAY = heldItem("throat_spray")
val THROAT_SPRAY = itemNameBlockItem("throat_spray", CobblemonBlocks.THROAT_SPRAY)
@JvmField
val TOXIC_ORB = heldItem("toxic_orb")
val TOXIC_ORB = itemNameBlockItem("toxic_orb", CobblemonBlocks.TOXIC_ORB)
@JvmField
val TWISTED_SPOON = heldItem("twisted_spoon")
@JvmField
@@ -1082,9 +1077,9 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
@JvmField
val WEAKNESS_POLICY = itemNameBlockItem("weakness_policy", CobblemonBlocks.WEAKNESS_POLICY)
@JvmField
val WIDE_LENS = heldItem("wide_lens")
val WIDE_LENS = itemNameBlockItem("wide_lens", CobblemonBlocks.WIDE_LENS)
@JvmField
val ZOOM_LENS = heldItem("zoom_lens")
val ZOOM_LENS = itemNameBlockItem("zoom_lens", CobblemonBlocks.ZOOM_LENS)
@JvmField
val MENTAL_HERB = compostableHeldItem("mental_herb", null, 0.85F)
@JvmField
@@ -1096,19 +1091,19 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
@JvmField
val WHITE_HERB = compostableHeldItem("white_herb", null, 0.85F)
@JvmField
val BRIGHT_POWDER = heldItem("bright_powder")
val BRIGHT_POWDER = itemNameBlockItem("bright_powder", CobblemonBlocks.BRIGHT_POWDER)
@JvmField
val METAL_POWDER = heldItem("metal_powder")
val METAL_POWDER = itemNameBlockItem("metal_powder", CobblemonBlocks.METAL_POWDER)
@JvmField
val QUICK_POWDER = heldItem("quick_powder")
val QUICK_POWDER = itemNameBlockItem("quick_powder", CobblemonBlocks.QUICK_POWDER)
@JvmField
val DAMP_ROCK = heldItem("damp_rock")
val DAMP_ROCK = itemNameBlockItem("damp_rock", CobblemonBlocks.DAMP_ROCK)
@JvmField
val HEAT_ROCK = heldItem("heat_rock")
val HEAT_ROCK = itemNameBlockItem("heat_rock", CobblemonBlocks.HEAT_ROCK)
@JvmField
val SMOOTH_ROCK = heldItem("smooth_rock")
val SMOOTH_ROCK = itemNameBlockItem("smooth_rock", CobblemonBlocks.SMOOTH_ROCK)
@JvmField
val ICY_ROCK = heldItem("icy_rock")
val ICY_ROCK = itemNameBlockItem("icy_rock", CobblemonBlocks.ICY_ROCK)
// Mulch
@JvmField
@@ -1599,7 +1594,16 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
private fun wearableItem(name: String, heldItemRemappedName: String? = null): CobblemonItem = create(
name,
WearableItem(name).also {
WearableHatItem(name).also {
wearables.add(it)
if (heldItemRemappedName != null) {
CobblemonHeldItemManager.registerRemap(it, heldItemRemappedName)
}
}
)
private fun wearableBlockItem(name: String, block: Block, heldItemRemappedName: String? = null): WearableBlockItem = create(
name,
WearableBlockItem(name, block).also {
wearables.add(it)
if (heldItemRemappedName != null) {
CobblemonHeldItemManager.registerRemap(it, heldItemRemappedName)
@@ -15,12 +15,12 @@ import com.cobblemon.mod.common.api.moves.animations.ActionEffectContext
import com.mojang.serialization.Codec
import com.mojang.serialization.codecs.ListCodec
import com.mojang.serialization.codecs.PrimitiveCodec
import java.util.Optional
import java.util.UUID
import net.minecraft.core.BlockPos
import net.minecraft.core.GlobalPos
import net.minecraft.core.UUIDUtil
import net.minecraft.world.entity.LivingEntity
import net.minecraft.world.entity.ai.memory.MemoryModuleType
import java.util.*
object CobblemonMemories {
val memories = mutableMapOf<String, MemoryModuleType<*>>()
@@ -107,6 +107,9 @@ import com.cobblemon.mod.common.net.messages.client.pokemon.update.evolution.Add
import com.cobblemon.mod.common.net.messages.client.pokemon.update.evolution.ClearEvolutionsPacket
import com.cobblemon.mod.common.net.messages.client.pokemon.update.evolution.ClientboundSeatAssignmentPacket
import com.cobblemon.mod.common.net.messages.client.pokemon.update.evolution.RemoveEvolutionPacket
import com.cobblemon.mod.common.net.messages.client.pokemon.update.form.AddFormPacket
import com.cobblemon.mod.common.net.messages.client.pokemon.update.form.ClearFormsPacket
import com.cobblemon.mod.common.net.messages.client.pokemon.update.form.RemoveFormPacket
import com.cobblemon.mod.common.net.messages.client.settings.OpenCobblemonConfigScreenPacket
import com.cobblemon.mod.common.net.messages.client.settings.ServerSettingsPacket
import com.cobblemon.mod.common.net.messages.client.sound.UnvalidatedPlaySoundS2CPacket
@@ -194,6 +197,8 @@ import com.cobblemon.mod.common.net.messages.server.pokemon.update.SetItemHidden
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.evolution.AcceptEvolutionPacket
import com.cobblemon.mod.common.net.messages.server.pokemon.update.form.AcceptFormPacket
import com.cobblemon.mod.common.net.messages.server.pokemon.update.form.RevertFormPacket
import com.cobblemon.mod.common.net.messages.server.riding.DismountPokemonPacket
import com.cobblemon.mod.common.net.messages.server.riding.ServerboundUpdateDriverInputPacket
import com.cobblemon.mod.common.net.messages.server.riding.ServerboundUpdatePassengerPositionPacket
@@ -211,9 +216,11 @@ import com.cobblemon.mod.common.net.messages.server.trade.ChangeTradeAcceptanceP
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.serverhandling.AcceptFormHandler
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.RevertFormHandler
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
@@ -506,6 +513,11 @@ object CobblemonNetwork {
// Pokédex scanning
list.add(PacketRegisterInfo(ServerConfirmedRegisterPacket.ID, ServerConfirmedRegisterPacket::decode, ServerConfirmedRegisterHandler))
// Form packets
list.add(PacketRegisterInfo(AddFormPacket.ID, AddFormPacket::decode, PokemonUpdatePacketHandler()))
list.add(PacketRegisterInfo(ClearFormsPacket.ID, ClearFormsPacket::decode, PokemonUpdatePacketHandler()))
list.add(PacketRegisterInfo(RemoveFormPacket.ID, RemoveFormPacket::decode, PokemonUpdatePacketHandler()))
// Riding
list.add(PacketRegisterInfo(ClientboundUpdateRidingStatePacket.ID, ClientboundUpdateRidingStatePacket::decode, ClientboundUpdateRidingStateHandler))
list.add(PacketRegisterInfo(ClientboundUpdateDriverInputPacket.ID, ClientboundUpdateDriverInputPacket::decode, ClientboundUpdateDriverInputHandler))
@@ -621,6 +633,10 @@ object CobblemonNetwork {
// NPC packets
list.add(PacketRegisterInfo(SaveNPCPacket.ID, SaveNPCPacket::decode, SaveNPCHandler))
// Form Packets
list.add(PacketRegisterInfo(AcceptFormPacket.ID, AcceptFormPacket::decode, AcceptFormHandler))
list.add(PacketRegisterInfo(RevertFormPacket.ID, RevertFormPacket::decode, RevertFormHandler))
// Riding packet(s)
list.add(PacketRegisterInfo(ServerboundUpdateOrientationPacket.ID, ServerboundUpdateOrientationPacket::decode, ServerboundUpdateOrientationHandler))
list.add(PacketRegisterInfo(ServerboundUpdateRidingStatePacket.ID, ServerboundUpdateRidingStatePacket::decode, ServerboundUpdateRidingStateHandler))
@@ -9,9 +9,9 @@
package com.cobblemon.mod.common
import com.cobblemon.mod.common.entity.pokemon.ai.sensors.*
import com.cobblemon.mod.common.pokemon.ai.PokemonDisturbancesSensor
import com.cobblemon.mod.common.entity.sensor.BattlingPokemonSensor
import com.cobblemon.mod.common.entity.sensor.NPCBattlingSensor
import com.cobblemon.mod.common.pokemon.ai.PokemonDisturbancesSensor
import java.util.function.Supplier
import net.minecraft.world.entity.Entity
import net.minecraft.world.entity.ai.sensing.Sensor
@@ -8,6 +8,7 @@
package com.cobblemon.mod.common
import java.util.Optional
import net.minecraft.core.registries.BuiltInRegistries
import net.minecraft.util.RandomSource
import net.minecraft.world.entity.Entity
@@ -18,7 +19,6 @@ import net.minecraft.world.item.ItemStack
import net.minecraft.world.item.Items
import net.minecraft.world.item.trading.ItemCost
import net.minecraft.world.item.trading.MerchantOffer
import java.util.Optional
/**
* A generator for various trade offers in the mod.
@@ -11,10 +11,10 @@ package com.cobblemon.mod.common.advancement.criterion
import com.cobblemon.mod.common.util.cobblemonResource
import com.mojang.serialization.Codec
import com.mojang.serialization.codecs.RecordCodecBuilder
import java.util.Optional
import net.minecraft.advancements.critereon.ContextAwarePredicate
import net.minecraft.resources.ResourceLocation
import net.minecraft.server.level.ServerPlayer
import java.util.Optional
class AspectCriterion(
playerCtx: Optional<ContextAwarePredicate>,
@@ -14,8 +14,8 @@ import com.mojang.serialization.codecs.RecordCodecBuilder
import java.util.Optional
import net.minecraft.advancements.critereon.ContextAwarePredicate
import net.minecraft.advancements.critereon.EntityPredicate
import net.minecraft.server.level.ServerPlayer
import net.minecraft.resources.ResourceLocation
import net.minecraft.server.level.ServerPlayer
class CastPokeRodContext(val baitId: ResourceLocation)
@@ -10,10 +10,10 @@ package com.cobblemon.mod.common.advancement.criterion
import com.mojang.serialization.Codec
import com.mojang.serialization.codecs.RecordCodecBuilder
import java.util.Optional
import net.minecraft.advancements.critereon.ContextAwarePredicate
import net.minecraft.advancements.critereon.EntityPredicate
import net.minecraft.server.level.ServerPlayer
import java.util.Optional
/**
* A context that is used when you require a [CountableContext] along with some type string.
@@ -14,8 +14,8 @@ import com.mojang.serialization.codecs.RecordCodecBuilder
import java.util.Optional
import net.minecraft.advancements.critereon.ContextAwarePredicate
import net.minecraft.advancements.critereon.EntityPredicate
import net.minecraft.server.level.ServerPlayer
import net.minecraft.resources.ResourceLocation
import net.minecraft.server.level.ServerPlayer
class ReelInPokemonContext(val species : ResourceLocation, val baitId: ResourceLocation)
@@ -9,6 +9,7 @@
package com.cobblemon.mod.common.api.abilities
import com.cobblemon.mod.common.api.Priority
import com.cobblemon.mod.common.api.data.ShowdownIdentifiable
import com.cobblemon.mod.common.util.codec.CodecUtils
import com.google.gson.JsonObject
import com.mojang.serialization.Codec
@@ -25,7 +26,7 @@ class AbilityTemplate(
var builder: (AbilityTemplate, forced: Boolean, priority: Priority) -> Ability = { template, forced, priority -> Ability(template, forced, priority) },
val displayName: String = "cobblemon.ability.$name",
val description: String = "cobblemon.ability.$name.desc"
) {
) : ShowdownIdentifiable {
/**
* Returns the Ability or if applicable the extension connected to this template
*/
@@ -45,6 +46,8 @@ class AbilityTemplate(
*/
fun create(json: JsonObject) = create().loadFromJSON(json)
override fun showdownId(): String = ShowdownIdentifiable.REGEX.replace(this.name.lowercase(), "")
companion object {
@JvmStatic
@@ -18,7 +18,6 @@ import com.cobblemon.mod.common.api.molang.MoLangFunctions.addStandardFunctions
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.scripting.CobblemonScripts
import com.cobblemon.mod.common.entity.MoLangScriptingEntity
import com.cobblemon.mod.common.util.activityRegistry
import com.cobblemon.mod.common.util.asIdentifierDefaultingNamespace
@@ -13,7 +13,6 @@ import com.cobblemon.mod.common.api.ai.config.BehaviourConfig
import com.cobblemon.mod.common.api.molang.ExpressionLike
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMostSpecificMoLangValue
import com.cobblemon.mod.common.api.molang.MoLangFunctions.setup
import com.cobblemon.mod.common.api.scripting.CobblemonScripts
import com.cobblemon.mod.common.util.asTranslated
import com.cobblemon.mod.common.util.resolve
import com.cobblemon.mod.common.util.withQueryValue
@@ -13,7 +13,6 @@ import com.cobblemon.mod.common.util.getBooleanOrNull
import com.cobblemon.mod.common.util.getDoubleOrNull
import kotlin.math.sqrt
import net.minecraft.core.BlockPos
import net.minecraft.world.entity.PathfinderMob
/**
* Used to maintain some settings around how the entity should wander this tick. The idea is you
@@ -8,16 +8,12 @@
package com.cobblemon.mod.common.api.ai.config
import com.bedrockk.molang.runtime.MoLangRuntime
import com.cobblemon.mod.common.api.ai.BehaviourConfigurationContext
import com.cobblemon.mod.common.api.ai.ExpressionOrEntityVariable
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMostSpecificMoLangValue
import com.cobblemon.mod.common.api.molang.MoLangFunctions.setup
import com.cobblemon.mod.common.api.npc.configuration.MoLangConfigVariable
import com.cobblemon.mod.common.util.asExpression
import com.cobblemon.mod.common.util.cobblemonResource
import com.cobblemon.mod.common.util.resolveBoolean
import com.cobblemon.mod.common.util.withQueryValue
import net.minecraft.resources.ResourceLocation
import net.minecraft.world.entity.LivingEntity
@@ -11,13 +11,8 @@ package com.cobblemon.mod.common.api.ai.config.task
import com.cobblemon.mod.common.api.ai.BehaviourConfigurationContext
import com.cobblemon.mod.common.api.ai.ExpressionOrEntityVariable
import com.cobblemon.mod.common.api.ai.asVariables
import com.cobblemon.mod.common.api.molang.ExpressionLike
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMostSpecificMoLangValue
import com.cobblemon.mod.common.util.asExpression
import com.cobblemon.mod.common.util.asExpressionLike
import com.cobblemon.mod.common.util.resolveBoolean
import com.cobblemon.mod.common.util.weightedSelection
import com.cobblemon.mod.common.util.withQueryValue
import com.mojang.datafixers.util.Either
import net.minecraft.world.entity.LivingEntity
import net.minecraft.world.entity.ai.behavior.BehaviorControl
@@ -8,12 +8,10 @@
package com.cobblemon.mod.common.api.ai.config.task
import com.bedrockk.molang.runtime.MoLangRuntime
import com.cobblemon.mod.common.CobblemonMemories
import com.cobblemon.mod.common.api.ai.BehaviourConfigurationContext
import com.cobblemon.mod.common.api.ai.WrapperLivingEntityTask.Companion.wrapped
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMostSpecificMoLangValue
import com.cobblemon.mod.common.api.molang.MoLangFunctions.setup
import com.cobblemon.mod.common.api.npc.configuration.MoLangConfigVariable
import com.cobblemon.mod.common.util.mainThreadRuntime
import com.cobblemon.mod.common.util.resolveBoolean
@@ -10,8 +10,6 @@ package com.cobblemon.mod.common.api.ai.config.task
import com.cobblemon.mod.common.api.ai.BehaviourConfigurationContext
import com.cobblemon.mod.common.api.ai.asVariables
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMostSpecificMoLangValue
import com.cobblemon.mod.common.util.withQueryValue
import net.minecraft.world.entity.LivingEntity
import net.minecraft.world.entity.ai.behavior.BehaviorControl
import net.minecraft.world.entity.ai.behavior.StopBeingAngryIfTargetDead
@@ -9,9 +9,7 @@
package com.cobblemon.mod.common.api.ai.config.task
import com.cobblemon.mod.common.api.ai.BehaviourConfigurationContext
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMostSpecificMoLangValue
import com.cobblemon.mod.common.api.npc.configuration.MoLangConfigVariable
import com.cobblemon.mod.common.util.withQueryValue
import net.minecraft.world.Difficulty
import net.minecraft.world.entity.LivingEntity
import net.minecraft.world.entity.ai.behavior.declarative.BehaviorBuilder
@@ -15,7 +15,6 @@ import com.cobblemon.mod.common.api.npc.configuration.MoLangConfigVariable
import com.cobblemon.mod.common.entity.npc.ai.SwitchToBattleTask
import net.minecraft.world.entity.LivingEntity
import net.minecraft.world.entity.ai.behavior.BehaviorControl
import net.minecraft.world.entity.ai.memory.MemoryModuleType
class SwitchToNPCBattleTaskConfig : SingleTaskConfig {
override fun getVariables(entity: LivingEntity, behaviourConfigurationContext: BehaviourConfigurationContext) = emptyList<MoLangConfigVariable>()
@@ -10,8 +10,6 @@ package com.cobblemon.mod.common.api.ai.config.task
import com.cobblemon.mod.common.api.ai.BehaviourConfigurationContext
import com.cobblemon.mod.common.api.ai.asVariables
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMostSpecificMoLangValue
import com.cobblemon.mod.common.util.withQueryValue
import net.minecraft.world.entity.LivingEntity
import net.minecraft.world.entity.PathfinderMob
import net.minecraft.world.entity.ai.behavior.BehaviorControl
@@ -10,8 +10,6 @@ package com.cobblemon.mod.common.api.ai.config.task
import com.cobblemon.mod.common.api.ai.BehaviourConfigurationContext
import com.cobblemon.mod.common.api.ai.asVariables
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMostSpecificMoLangValue
import com.cobblemon.mod.common.util.withQueryValue
import net.minecraft.world.entity.LivingEntity
import net.minecraft.world.entity.PathfinderMob
import net.minecraft.world.entity.ai.behavior.BehaviorControl
@@ -25,7 +25,6 @@ import net.minecraft.world.entity.ai.behavior.BehaviorControl
import net.minecraft.world.entity.ai.behavior.declarative.BehaviorBuilder
import net.minecraft.world.entity.ai.behavior.declarative.Trigger
import net.minecraft.world.entity.ai.memory.MemoryModuleType
import net.minecraft.world.entity.ai.memory.MemoryStatus
import net.minecraft.world.entity.ai.sensing.SensorType
/**
@@ -22,6 +22,7 @@ import com.cobblemon.mod.common.util.mainThreadRuntime
import com.cobblemon.mod.common.util.resolveFloat
import com.cobblemon.mod.common.util.withQueryValue
import com.mojang.datafixers.util.Either
import kotlin.math.ceil
import net.minecraft.core.BlockPos
import net.minecraft.world.entity.LivingEntity
import net.minecraft.world.entity.PathfinderMob
@@ -34,7 +35,6 @@ import net.minecraft.world.entity.ai.memory.MemoryModuleType
import net.minecraft.world.level.material.Fluids
import net.minecraft.world.level.pathfinder.PathType
import net.minecraft.world.phys.Vec3
import kotlin.math.ceil
class WaterWanderTaskConfig : SingleTaskConfig {
val condition = booleanVariable(WANDER, "water_wanders", true).asExpressible()
@@ -54,9 +54,9 @@ import com.cobblemon.mod.common.net.messages.client.battle.BattleEndPacket
import com.cobblemon.mod.common.net.messages.client.battle.BattleMakeChoicePacket
import com.cobblemon.mod.common.net.messages.client.battle.BattleMessagePacket
import com.cobblemon.mod.common.net.messages.client.battle.BattleQueueRequestPacket
import com.cobblemon.mod.common.pokemon.evolution.progress.DefeatEvolutionProgress
import com.cobblemon.mod.common.pokemon.evolution.progress.LastBattleCriticalHitsEvolutionProgress
import com.cobblemon.mod.common.pokemon.requirements.DefeatRequirement
import com.cobblemon.mod.common.pokemon.transformation.progress.DefeatTransformationProgress
import com.cobblemon.mod.common.pokemon.transformation.progress.LastBattleCriticalHitsTransformationProgress
import com.cobblemon.mod.common.pokemon.transformation.requirements.DefeatRequirement
import com.cobblemon.mod.common.util.battleLang
import com.cobblemon.mod.common.util.getPlayer
import com.cobblemon.mod.common.util.giveOrDropItemStack
@@ -97,8 +97,8 @@ open class PokemonBattle(
this.actors.forEach { actor ->
actor.battle = this
actor.pokemonList.forEach { battlePokemon ->
battlePokemon.effectedPokemon.evolutionProxy.current().progress()
.filterIsInstance<LastBattleCriticalHitsEvolutionProgress>()
battlePokemon.effectedPokemon.requirementProgress
.filterIsInstance<LastBattleCriticalHitsTransformationProgress>()
.forEach { it.reset() }
}
}
@@ -271,12 +271,13 @@ open class PokemonBattle(
val facedFainted = opponentPokemon.facedOpponents.contains(faintedPokemon)
val pokemon = opponentPokemon.effectedPokemon
if (facedFainted) {
pokemon.lockedEvolutions.forEach { evolution ->
evolution.requirements.filterIsInstance<DefeatRequirement>().forEach { defeatRequirement ->
if (defeatRequirement.target.matches(faintedPokemon.effectedPokemon)) {
val progress = pokemon.evolutionProxy.current().progressFirstOrCreate({ it is DefeatEvolutionProgress && it.currentProgress().target == defeatRequirement.target }) { DefeatEvolutionProgress() }
progress.updateProgress(DefeatEvolutionProgress.Progress(defeatRequirement.target, progress.currentProgress().amount + 1))
}
if (pokemon.hasMatchingRequirement<DefeatRequirement>({ it.target.matches(faintedPokemon.effectedPokemon) })) {
val requiredPokemonProperties = pokemon.getRelevantRequirements<DefeatRequirement> { it.target.matches(faintedPokemon.effectedPokemon) }
.map { it.target }
.distinctBy { it.asString() }
for (props in requiredPokemonProperties) {
val progress = pokemon.progressFirstOrCreate({ it is DefeatTransformationProgress && it.currentProgress().target.asString().equals(props.asString(), ignoreCase = true) }, ::DefeatTransformationProgress)
progress.updateProgress(DefeatTransformationProgress.Progress(props.copy(), progress.currentProgress().amount + 1))
}
}
}
@@ -22,9 +22,9 @@ import com.cobblemon.mod.common.item.battle.BagItem
import com.cobblemon.mod.common.net.messages.client.battle.BattleApplyPassResponsePacket
import com.cobblemon.mod.common.net.messages.client.battle.BattleMakeChoicePacket
import com.cobblemon.mod.common.net.messages.client.battle.BattleMessagePacket
import java.util.UUID
import net.minecraft.network.chat.Component
import net.minecraft.network.chat.MutableComponent
import java.util.UUID
import net.minecraft.server.level.ServerPlayer
abstract class BattleActor(
@@ -21,6 +21,7 @@ import com.cobblemon.mod.common.util.adapters.*
import com.cobblemon.mod.common.util.cobblemonResource
import com.google.gson.GsonBuilder
import com.google.gson.reflect.TypeToken
import java.awt.Color
import net.minecraft.advancements.critereon.MinMaxBounds
import net.minecraft.core.registries.Registries
import net.minecraft.resources.ResourceLocation
@@ -30,7 +31,6 @@ import net.minecraft.tags.TagKey
import net.minecraft.world.level.biome.Biome
import net.minecraft.world.phys.AABB
import net.minecraft.world.phys.Vec3
import java.awt.Color
/**
* The data registry for [Berry].
@@ -26,10 +26,10 @@ import com.cobblemon.mod.common.util.writeBox
import com.cobblemon.mod.common.util.writeEnumConstant
import com.cobblemon.mod.common.util.writeIdentifier
import com.google.gson.annotations.SerializedName
import net.minecraft.core.BlockPos
import net.minecraft.network.RegistryFriendlyByteBuf
import java.awt.Color
import java.util.EnumSet
import net.minecraft.core.BlockPos
import net.minecraft.network.RegistryFriendlyByteBuf
import net.minecraft.resources.ResourceLocation
import net.minecraft.tags.TagKey
import net.minecraft.world.entity.LivingEntity
@@ -8,11 +8,11 @@
package com.cobblemon.mod.common.api.drop
import com.cobblemon.mod.common.api.pokemon.requirement.Requirement
import com.cobblemon.mod.common.api.pokemon.transformation.requirement.TransformationRequirement
import com.cobblemon.mod.common.pokemon.Pokemon
class EvolutionItemDropEntry : ItemDropEntry() {
val requirements: MutableSet<Requirement> = mutableSetOf()
val requirements: MutableSet<TransformationRequirement> = mutableSetOf()
override fun canDrop(pokemon: Pokemon?): Boolean = pokemon != null && requirements.all { it.check(pokemon) }
}
@@ -48,6 +48,10 @@ import com.cobblemon.mod.common.api.events.pokemon.evolution.EvolutionAcceptedEv
import com.cobblemon.mod.common.api.events.pokemon.evolution.EvolutionCompleteEvent
import com.cobblemon.mod.common.api.events.pokemon.evolution.EvolutionDisplayEvent
import com.cobblemon.mod.common.api.events.pokemon.evolution.EvolutionTestedEvent
import com.cobblemon.mod.common.api.events.pokemon.form.FormAcceptedEvent
import com.cobblemon.mod.common.api.events.pokemon.form.FormCompleteEvent
import com.cobblemon.mod.common.api.events.pokemon.form.FormDisplayEvent
import com.cobblemon.mod.common.api.events.pokemon.form.FormTestedEvent
import com.cobblemon.mod.common.api.events.pokemon.healing.PokemonHealedEvent
import com.cobblemon.mod.common.api.events.pokemon.interaction.ExperienceCandyUseEvent
import com.cobblemon.mod.common.api.events.pokemon.interaction.PokemonInteractionGUICreationEvent
@@ -103,6 +107,18 @@ object CobblemonEvents {
@JvmField
val EVOLUTION_COMPLETE = EventObservable<EvolutionCompleteEvent>()
@JvmField
val FORM_ACCEPTED = CancelableObservable<FormAcceptedEvent>()
@JvmField
val FORM_DISPLAY = EventObservable<FormDisplayEvent>()
@JvmField
val FORM_TESTED = EventObservable<FormTestedEvent>()
@JvmField
val FORM_COMPLETE = EventObservable<FormCompleteEvent>()
@JvmField
val POKEMON_NICKNAMED = CancelableObservable<PokemonNicknamedEvent>()
@@ -15,9 +15,7 @@ import com.cobblemon.mod.common.api.battles.model.actor.ActorType
import com.cobblemon.mod.common.api.battles.model.actor.BattleActor
import com.cobblemon.mod.common.api.battles.model.actor.EntityBackedBattleActor
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMostSpecificMoLangValue
import com.cobblemon.mod.common.battles.actor.PlayerBattleActor
import com.cobblemon.mod.common.entity.MoLangScriptingEntity
import com.cobblemon.mod.common.entity.npc.NPCBattleActor
import com.cobblemon.mod.common.util.asArrayValue
import net.minecraft.world.entity.LivingEntity
@@ -12,7 +12,6 @@ import com.bedrockk.molang.runtime.value.DoubleValue
import com.cobblemon.mod.common.api.events.Cancelable
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMoLangValue
import com.cobblemon.mod.common.api.molang.MoLangFunctions.moLangFunctionMap
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
import com.cobblemon.mod.common.pokemon.Pokemon
import com.cobblemon.mod.common.trade.TradeParticipant
import com.cobblemon.mod.common.util.getPlayer
@@ -12,8 +12,8 @@ import com.bedrockk.molang.runtime.value.MoValue
import com.cobblemon.mod.common.api.events.Cancelable
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMoLangValue
import com.cobblemon.mod.common.api.molang.MoLangFunctions.moLangFunctionMap
import com.cobblemon.mod.common.api.pokemon.evolution.Evolution
import com.cobblemon.mod.common.pokemon.Pokemon
import com.cobblemon.mod.common.pokemon.transformation.evolution.Evolution
/**
* Fired when an evolution is accepted.
@@ -10,8 +10,8 @@ package com.cobblemon.mod.common.api.events.pokemon.evolution
import com.bedrockk.molang.runtime.value.MoValue
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMoLangValue
import com.cobblemon.mod.common.api.pokemon.evolution.Evolution
import com.cobblemon.mod.common.pokemon.Pokemon
import com.cobblemon.mod.common.pokemon.transformation.evolution.Evolution
/**
* Fired after an evolution finishes.
@@ -8,9 +8,9 @@
package com.cobblemon.mod.common.api.events.pokemon.evolution
import com.cobblemon.mod.common.api.pokemon.evolution.Evolution
import com.cobblemon.mod.common.api.pokemon.evolution.EvolutionDisplay
import com.cobblemon.mod.common.pokemon.transformation.evolution.Evolution
import com.cobblemon.mod.common.pokemon.Pokemon
import com.cobblemon.mod.common.pokemon.transformation.evolution.EvolutionDisplay
/**
* Fired before an evolution is sent to clients.
@@ -8,7 +8,7 @@
package com.cobblemon.mod.common.api.events.pokemon.evolution
import com.cobblemon.mod.common.api.pokemon.evolution.Evolution
import com.cobblemon.mod.common.pokemon.transformation.evolution.Evolution
import com.cobblemon.mod.common.pokemon.Pokemon
/**
@@ -12,8 +12,8 @@ import com.bedrockk.molang.runtime.value.DoubleValue
import com.bedrockk.molang.runtime.value.MoValue
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMoLangValue
import com.cobblemon.mod.common.api.molang.MoLangFunctions.moLangFunctionMap
import com.cobblemon.mod.common.api.pokemon.evolution.Evolution
import com.cobblemon.mod.common.pokemon.Pokemon
import com.cobblemon.mod.common.pokemon.transformation.evolution.Evolution
import com.cobblemon.mod.common.util.getBoolean
/**
@@ -0,0 +1,37 @@
/*
* 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.events.pokemon.form
import com.bedrockk.molang.runtime.value.StringValue
import com.cobblemon.mod.common.api.events.Cancelable
import com.cobblemon.mod.common.api.molang.MoLangFunctions.moLangFunctionMap
import com.cobblemon.mod.common.pokemon.Pokemon
import com.cobblemon.mod.common.pokemon.transformation.form.TemporaryForm
/**
* Fired when a temporary form change is accepted.
* Cancelling will not notify users nor remove the form from the pending list.
*
* @param pokemon The [Pokemon] about to change form.
* @param form The [TemporaryForm] being used.
*
* @author Hiroku
* @since June 3rd, 2026
*/
data class FormAcceptedEvent(
override val pokemon: Pokemon,
override val form: TemporaryForm
) : Cancelable(), FormEvent {
val context = mutableMapOf(
"pokemon" to pokemon.struct,
"form" to StringValue(form.formOnlyShowdownId())
)
val functions = moLangFunctionMap(cancelFunc)
}
@@ -0,0 +1,34 @@
/*
* 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.events.pokemon.form
import com.bedrockk.molang.runtime.value.StringValue
import com.cobblemon.mod.common.pokemon.Pokemon
import com.cobblemon.mod.common.pokemon.transformation.form.TemporaryForm
/**
* Fired after a temporary form change finishes.
*
* @param pokemon The [Pokemon] resulting from the form change.
* @param form The [TemporaryForm] that was used.
*
* @author Hiroku
* @since June 3rd, 2026
*/
data class FormCompleteEvent(
/** The [Pokemon] that did the form change. */
override val pokemon: Pokemon,
/** The [TemporaryForm] that was used. */
override val form: TemporaryForm
) : FormEvent {
val context = mutableMapOf(
"pokemon" to pokemon.struct,
"form" to StringValue(form.formOnlyShowdownId())
)
}
@@ -0,0 +1,37 @@
/*
* 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.events.pokemon.form
import com.bedrockk.molang.runtime.value.StringValue
import com.cobblemon.mod.common.pokemon.Pokemon
import com.cobblemon.mod.common.pokemon.transformation.form.FormDisplay
import com.cobblemon.mod.common.pokemon.transformation.form.TemporaryForm
/**
* Fired before a form is sent to clients. For modifications on the actual output when they accept it modify
* the [display] directly.
*
* @param pokemon The [Pokemon] that will change form if this proposition is accepted.
* @param display The current [FormDisplay] the client will see.
* @param form The [TemporaryForm] being used.
*
* @author Hiroku
* @since June 3rd, 2026
*/
data class FormDisplayEvent(
override val pokemon: Pokemon,
var display: FormDisplay,
override val form: TemporaryForm
) : FormEvent {
val context = mutableMapOf(
"pokemon" to pokemon.struct,
"display" to display.struct,
"form" to StringValue(form.formOnlyShowdownId())
)
}
@@ -0,0 +1,22 @@
/*
* 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.events.pokemon.form
import com.cobblemon.mod.common.pokemon.Pokemon
import com.cobblemon.mod.common.pokemon.transformation.form.TemporaryForm
/**
* The root of the various [TemporaryForm]-related events.
*/
interface FormEvent {
/** The Pokémon impacted in this event.*/
val pokemon: Pokemon
/*** The form triggering this event.*/
val form: TemporaryForm
}
@@ -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.api.events.pokemon.form
import com.bedrockk.molang.runtime.value.DoubleValue
import com.bedrockk.molang.runtime.value.StringValue
import com.cobblemon.mod.common.api.molang.MoLangFunctions.moLangFunctionMap
import com.cobblemon.mod.common.pokemon.Pokemon
import com.cobblemon.mod.common.pokemon.transformation.form.TemporaryForm
import com.cobblemon.mod.common.util.getBoolean
/**
* An event fired when [TemporaryForm.test] has been performed.
* The final state [result] will be the return value of the test function.
*
* @property pokemon The [Pokemon] being tested against.
* @property form The [TemporaryForm] instance performing the test.
* @property originalResult The base result from the Cobblemon implementation.
* @property result The final value returned by [TemporaryForm.test].
*/
data class FormTestedEvent(
override val pokemon: Pokemon,
override val form: TemporaryForm,
val originalResult: Boolean,
) : FormEvent {
var result: Boolean = originalResult
val context = mutableMapOf(
"pokemon" to pokemon.struct,
"form" to StringValue(form.formOnlyShowdownId()),
"original_result" to DoubleValue(originalResult),
)
val functions = moLangFunctionMap(
"result" to { DoubleValue(result) },
"set_result" to {
result = it.getBoolean(0)
DoubleValue.ONE
}
)
}
@@ -15,7 +15,6 @@ import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMoLangValue
import com.cobblemon.mod.common.api.molang.MoLangFunctions.moLangFunctionMap
import com.cobblemon.mod.common.api.pokemon.PokemonProperties
import com.cobblemon.mod.common.pokemon.Pokemon
import com.cobblemon.mod.common.util.getPlayer
import net.minecraft.server.level.ServerPlayer
/**
@@ -8,7 +8,6 @@
package com.cobblemon.mod.common.api.events.storage
import com.bedrockk.molang.runtime.value.DoubleValue
import com.bedrockk.molang.runtime.value.StringValue
import com.cobblemon.mod.common.api.events.Cancelable
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMoLangValue
@@ -16,9 +16,7 @@ import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMoLangValue
import com.cobblemon.mod.common.api.molang.MoLangFunctions.moLangFunctionMap
import com.cobblemon.mod.common.api.storage.PokemonStore
import com.cobblemon.mod.common.pokemon.Pokemon
import com.cobblemon.mod.common.util.getPlayer
import net.minecraft.server.level.ServerPlayer
import java.util.UUID
/**
* The base of the events around the release of Pokémon from pc or party.
@@ -14,7 +14,7 @@ import com.cobblemon.mod.common.api.data.JsonDataRegistry
import com.cobblemon.mod.common.api.pokemon.PokemonProperties
import com.cobblemon.mod.common.api.reactive.SimpleObservable
import com.cobblemon.mod.common.net.messages.client.data.FossilRegistrySyncPacket
import com.cobblemon.mod.common.pokemon.evolution.adapters.LegacyItemConditionWrapperAdapter
import com.cobblemon.mod.common.pokemon.transformation.adapters.LegacyItemConditionWrapperAdapter
import com.cobblemon.mod.common.util.adapters.IdentifierAdapter
import com.cobblemon.mod.common.util.adapters.ItemLikeConditionAdapter
import com.cobblemon.mod.common.util.adapters.pokemonPropertiesShortAdapter
@@ -13,13 +13,13 @@ import com.cobblemon.mod.common.api.conditional.RegistryLikeCondition
import com.cobblemon.mod.common.api.data.JsonDataRegistry
import com.cobblemon.mod.common.api.molang.ExpressionLike
import com.cobblemon.mod.common.api.pokemon.PokemonProperties
import com.cobblemon.mod.common.api.pokemon.requirement.Requirement
import com.cobblemon.mod.common.api.pokemon.transformation.requirement.TransformationRequirement
import com.cobblemon.mod.common.api.reactive.SimpleObservable
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
import com.cobblemon.mod.common.net.messages.client.data.PokemonInteractionsSyncPacket
import com.cobblemon.mod.common.pokemon.adapters.CobblemonRequirementAdapter
import com.cobblemon.mod.common.pokemon.evolution.adapters.LegacyItemConditionWrapperAdapter
import com.cobblemon.mod.common.pokemon.requirements.PokemonPropertiesRequirement
import com.cobblemon.mod.common.pokemon.transformation.adapters.CobblemonRequirementAdapter
import com.cobblemon.mod.common.pokemon.transformation.adapters.LegacyItemConditionWrapperAdapter
import com.cobblemon.mod.common.pokemon.transformation.requirements.PokemonPropertiesRequirement
import com.cobblemon.mod.common.util.adapters.*
import com.cobblemon.mod.common.util.cobblemonResource
import com.google.gson.Gson
@@ -46,7 +46,7 @@ object PokemonInteractions : JsonDataRegistry<PokemonInteractionSet> {
.registerTypeAdapter(ResourceLocation::class.java, IdentifierAdapter)
.registerTypeAdapter(PokemonProperties::class.java, pokemonPropertiesShortAdapter)
.registerTypeAdapter(ItemPredicate::class.java, LegacyItemConditionWrapperAdapter)
.registerTypeAdapter(Requirement::class.java, CobblemonRequirementAdapter)
.registerTypeAdapter(TransformationRequirement::class.java, CobblemonRequirementAdapter)
.registerTypeAdapter(InteractionEffect::class.java, InteractionEffectAdapter)
.registerTypeAdapter(ExpressionLike::class.java, ExpressionLikeAdapter)
.registerTypeAdapter(TypeToken.getParameterized(RegistryLikeCondition::class.java, Biome::class.java).type, BiomeLikeConditionAdapter)
@@ -12,11 +12,16 @@ import com.bedrockk.molang.runtime.MoLangRuntime
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.setup
import com.cobblemon.mod.common.api.pokemon.requirement.Requirement
import com.cobblemon.mod.common.api.pokemon.transformation.requirement.TransformationRequirement
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
import com.cobblemon.mod.common.net.messages.client.sound.UnvalidatedPlaySoundS2CPacket
import com.cobblemon.mod.common.pokemon.adapters.CobblemonRequirementAdapter
import com.cobblemon.mod.common.util.*
import com.cobblemon.mod.common.pokemon.transformation.adapters.CobblemonRequirementAdapter
import com.cobblemon.mod.common.util.asExpressionLike
import com.cobblemon.mod.common.util.giveOrDropItemStack
import com.cobblemon.mod.common.util.readExpressionLike
import com.cobblemon.mod.common.util.withPlayerValue
import com.cobblemon.mod.common.util.withQueryValue
import com.cobblemon.mod.common.util.writeExpressionLike
import com.google.gson.annotations.SerializedName
import net.minecraft.core.registries.Registries
import net.minecraft.network.FriendlyByteBuf
@@ -29,7 +34,7 @@ import net.minecraft.world.entity.item.ItemEntity
import net.minecraft.world.item.ItemStack
data class PokemonInteractionSet(
val requirements: List<Requirement> = listOf(),
val requirements: List<TransformationRequirement> = listOf(),
val interactions: List<PokemonInteraction> = listOf(),
) {
fun encode(buffer: FriendlyByteBuf) {
@@ -51,7 +56,7 @@ data class PokemonInteractionSet(
}
data class PokemonInteraction(
val requirements: List<Requirement> = listOf(),
val requirements: List<TransformationRequirement> = listOf(),
val effects: List<InteractionEffect> = listOf(),
val cooldown: ExpressionLike = "0".asExpressionLike()
) {
@@ -74,7 +74,7 @@ abstract class RequestManager<T : ServerPlayerActionRequest> {
?: this.getInboundRequest(receiver.uuid, requestID)
/** Determines whether [player] can receive a [T]. */
open fun isBusy(player: ServerPlayer): Boolean = player.isInBattle() || player.isTrading() || player.party().find { it.entity?.isBusy == true } != null
open fun isBusy(player: ServerPlayer): Boolean = player.isBusy() || player.isPartyBusy()
/** Determines if the [target] is a valid interaction request target. */
abstract fun isValidInteraction(player: ServerPlayer, target: ServerPlayer): Boolean
@@ -21,34 +21,9 @@ import com.cobblemon.mod.common.api.battles.interpreter.BattleMessage
import com.cobblemon.mod.common.api.battles.model.PokemonBattle
import com.cobblemon.mod.common.api.battles.model.actor.BattleActor
import com.cobblemon.mod.common.api.drop.DropEntry
import com.cobblemon.mod.common.api.molang.function.BattleActorMoLangFunctions
import com.cobblemon.mod.common.api.molang.function.BattleMessageMoLangFunctions
import com.cobblemon.mod.common.api.molang.function.BattleMoLangFunctions
import com.cobblemon.mod.common.api.molang.function.BiomeMoLangFunctions
import com.cobblemon.mod.common.api.molang.function.BlockMoLangFunctions
import com.cobblemon.mod.common.api.molang.function.DimensionTypeMoLangFunctions
import com.cobblemon.mod.common.api.molang.function.DropEntryMoLangFunctions
import com.cobblemon.mod.common.api.molang.function.EntityMoLangFunctions
import com.cobblemon.mod.common.api.molang.function.EvolutionMoLangFunctions
import com.cobblemon.mod.common.api.molang.function.GeneralMoLangFunctions
import com.cobblemon.mod.common.api.molang.function.ItemStackMoLangFunctions
import com.cobblemon.mod.common.api.molang.function.LivingEntityMoLangFunctions
import com.cobblemon.mod.common.api.molang.function.NPCMoLangFunctions
import com.cobblemon.mod.common.api.molang.function.PCMoLangFunctions
import com.cobblemon.mod.common.api.molang.function.PartyMoLangFunctions
import com.cobblemon.mod.common.api.molang.function.PlayerMoLangFunctions
import com.cobblemon.mod.common.api.molang.function.PokedexMoLangFunctions
import com.cobblemon.mod.common.api.molang.function.PokemonEntityMoLangFunctions
import com.cobblemon.mod.common.api.molang.function.PokemonMoLangFunctions
import com.cobblemon.mod.common.api.molang.function.PokemonPropertiesMoLangFunctions
import com.cobblemon.mod.common.api.molang.function.PokemonStoreMoLangFunctions
import com.cobblemon.mod.common.api.molang.function.ServerMoLangFunctions
import com.cobblemon.mod.common.api.molang.function.SpawnablePositionMoLangFunctions
import com.cobblemon.mod.common.api.molang.function.SpeciesMoLangFunctions
import com.cobblemon.mod.common.api.molang.function.WorldMoLangFunctions
import com.cobblemon.mod.common.api.molang.function.*
import com.cobblemon.mod.common.api.pokedex.AbstractPokedexManager
import com.cobblemon.mod.common.api.pokemon.PokemonProperties
import com.cobblemon.mod.common.api.pokemon.evolution.Evolution
import com.cobblemon.mod.common.api.scripting.CobblemonScripts
import com.cobblemon.mod.common.api.spawning.position.SpawnablePosition
import com.cobblemon.mod.common.api.storage.PokemonStore
@@ -58,8 +33,10 @@ import com.cobblemon.mod.common.entity.npc.NPCEntity
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
import com.cobblemon.mod.common.pokemon.Pokemon
import com.cobblemon.mod.common.pokemon.Species
import com.cobblemon.mod.common.pokemon.transformation.evolution.Evolution
import com.cobblemon.mod.common.util.effectiveName
import com.mojang.datafixers.util.Either
import java.util.function.Function
import net.minecraft.core.Holder
import net.minecraft.core.Registry
import net.minecraft.core.RegistryAccess
@@ -84,7 +61,6 @@ import net.minecraft.world.level.biome.Biome
import net.minecraft.world.level.block.Block
import net.minecraft.world.level.dimension.DimensionType
import net.minecraft.world.phys.Vec3
import java.util.function.Function
/**
* Holds a bunch of useful MoLang trickery that can be used or extended in API
@@ -13,7 +13,7 @@ import com.bedrockk.molang.runtime.value.DoubleValue
import com.bedrockk.molang.runtime.value.StringValue
import com.cobblemon.mod.common.api.battles.model.PokemonBattle
import com.cobblemon.mod.common.util.asArrayValue
import java.util.*
import java.util.UUID
object BattleMoLangFunctions : AbstractMoLangFunctionHolder<PokemonBattle>() {
override fun PokemonBattle.moLangFunctions(): MutableMap<String, (MoParams) -> Any> {
@@ -11,31 +11,34 @@ package com.cobblemon.mod.common.api.molang.function
import com.bedrockk.molang.runtime.MoParams
import com.bedrockk.molang.runtime.value.DoubleValue
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMoLangValue
import com.cobblemon.mod.common.api.pokemon.evolution.Evolution
import com.cobblemon.mod.common.pokemon.evolution.variants.ItemInteractionEvolution
import com.cobblemon.mod.common.pokemon.evolution.variants.LevelUpEvolution
import com.cobblemon.mod.common.pokemon.evolution.variants.TradeEvolution
import com.cobblemon.mod.common.api.pokemon.transformation.Transformation
import com.cobblemon.mod.common.pokemon.transformation.evolution.Evolution
import com.cobblemon.mod.common.pokemon.transformation.triggers.ItemInteractionTrigger
import com.cobblemon.mod.common.pokemon.transformation.triggers.LevelUpTrigger
import com.cobblemon.mod.common.pokemon.transformation.triggers.TradeTrigger
object EvolutionMoLangFunctions : AbstractMoLangFunctionHolder<Evolution>() {
override fun Evolution.moLangFunctions(): MutableMap<String, (MoParams) -> Any> {
object EvolutionMoLangFunctions : AbstractMoLangFunctionHolder<Transformation>() {
override fun Transformation.moLangFunctions(): MutableMap<String, (MoParams) -> Any> {
val evolution = this
val functions = hashMapOf<String, (MoParams) -> Any>()
functions["result"] = { evolution.result.asMoLangValue() }
functions["is_optional"] = { DoubleValue(evolution.optional) }
functions["consumes_held_item"] = { DoubleValue(evolution.consumeHeldItem) }
functions["reevaluate"] = { DoubleValue(evolution.reevaluate) }
when (evolution) {
is LevelUpEvolution -> {
functions["is_level_up"] = { DoubleValue.ONE }
}
if (evolution is Evolution) {
functions["result"] = { evolution.result.asMoLangValue() }
when (evolution.trigger) {
is LevelUpTrigger -> {
functions["is_level_up"] = { DoubleValue.ONE }
}
is TradeEvolution -> {
functions["is_trade"] = { DoubleValue.ONE }
}
is TradeTrigger -> {
functions["is_trade"] = { DoubleValue.ONE }
}
is ItemInteractionEvolution -> {
functions["is_item"] = { DoubleValue.ONE }
is ItemInteractionTrigger -> {
functions["is_item"] = { DoubleValue.ONE }
}
}
}
@@ -55,6 +55,11 @@ object GeneralMoLangFunctions {
struct.map.remove(variable)
DoubleValue.ONE
}
functions["delete_variables"] = { params ->
val struct = params.get<VariableStruct>(0)
struct.map.clear()
DoubleValue.ONE
}
functions["get_variable"] = { params ->
val struct = params.get<VariableStruct>(0)
val variable = params.getString(1)
@@ -445,7 +445,7 @@ object PokemonMoLangFunctions : AbstractMoLangFunctionHolder<Pokemon>() {
val idx = params.getInt(0)
val evolution =
if (idx >= 0) pokemon.evolutions.elementAtOrNull(idx) else return@forceEvolve DoubleValue.ZERO
evolution?.forceEvolve(pokemon)
evolution?.perform(pokemon)
StringValue(evolution.toString())
}
@@ -12,6 +12,8 @@ import com.bedrockk.molang.runtime.struct.MoStruct
import com.bedrockk.molang.runtime.struct.QueryStruct
import com.bedrockk.molang.runtime.value.DoubleValue
import com.bedrockk.molang.runtime.value.StringValue
import com.cobblemon.mod.common.api.data.ShowdownIdentifiable
import com.cobblemon.mod.common.api.moves.animations.ActionEffectTimeline
import com.cobblemon.mod.common.api.moves.categories.DamageCategories
import com.cobblemon.mod.common.api.moves.categories.DamageCategory
import com.cobblemon.mod.common.api.types.ElementalType
@@ -55,7 +57,7 @@ open class MoveTemplate(
val critRatio: Double,
val effectChances: Array<Double>,
val weight: Float
) {
) : ShowdownIdentifiable {
val struct: MoStruct by lazy {
QueryStruct(hashMapOf())
.addFunction("name") { StringValue(name) }
@@ -163,6 +165,8 @@ open class MoveTemplate(
return this.elementalType
}
override fun showdownId() = ShowdownIdentifiable.REGEX.replace(this.name.lowercase(), "")
fun getSelectionWeight(form: FormData): Float {
return if (this in form.signatureMoves) {
weight * MovesetBuilder.signatureMoveWeightMultiplier
@@ -10,13 +10,17 @@ package com.cobblemon.mod.common.api.moves.animations
import com.bedrockk.molang.runtime.MoLangRuntime
import com.cobblemon.mod.common.api.molang.ExpressionLike
import com.cobblemon.mod.common.api.molang.MoLangFunctions.addStandardFunctions
import com.cobblemon.mod.common.api.moves.animations.keyframes.ActionEffectKeyframe
import com.cobblemon.mod.common.api.scheduling.Schedulable
import com.cobblemon.mod.common.api.scheduling.ServerTaskTracker
import com.cobblemon.mod.common.entity.npc.NPCEntity
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
import com.cobblemon.mod.common.util.asExpressionLike
import com.cobblemon.mod.common.util.resolveBoolean
import java.util.concurrent.CompletableFuture
import net.minecraft.world.entity.Entity
import net.minecraft.world.level.Level
import java.util.concurrent.CompletableFuture
/**
* An action effect will run and execute a series of 'keyframes', with each running once
@@ -36,7 +40,7 @@ class ActionEffectTimeline(
}
fun run(context: ActionEffectContext): CompletableFuture<Unit> {
return if (timeline.isEmpty() || !context.runtime.resolveBoolean(condition)) {
val future = if (timeline.isEmpty() || !context.runtime.resolveBoolean(condition)) {
CompletableFuture.completedFuture(Unit)
} else {
val finalFuture = CompletableFuture<Unit>()
@@ -47,6 +51,10 @@ class ActionEffectTimeline(
it.printStackTrace()
CompletableFuture.completedFuture(Unit)
}
context.future = future
future.thenRun { context.getHolds().forEach(context::removeHold) }
return future
}
fun chainKeyframes(context: ActionEffectContext, iterator: Iterator<ActionEffectKeyframe>, finalFuture: CompletableFuture<Unit>) {
@@ -65,15 +73,45 @@ class ActionEffectTimeline(
class ActionEffectContext(
val actionEffect: ActionEffectTimeline,
val holds: MutableSet<String> = mutableSetOf(),
private val holds: MutableSet<String> = mutableSetOf(),
val providers: MutableList<Any> = mutableListOf(),
val runtime: MoLangRuntime,
var canBeInterrupted: Boolean = false,
var interrupted: Boolean = false,
var currentKeyframes: MutableList<ActionEffectKeyframe> = mutableListOf(),
var level: Level? = null
var level: Level? = null,
var holdRemovalCallbacks: MutableMap<String, () -> Unit> = mutableMapOf(),
var tracker: Schedulable = ServerTaskTracker
) {
companion object {
fun fromPokemonEntity(
actionEffect: ActionEffectTimeline,
pokemonEntity: PokemonEntity,
runtime: MoLangRuntime = MoLangRuntime().also { it.environment.query.addStandardFunctions() },
holds: Collection<String> = emptySet(),
holdRemovalCallbacks: Map<String, () -> Unit> = emptyMap()
): ActionEffectContext {
return ActionEffectContext(
actionEffect = actionEffect,
providers = mutableListOf(UsersProvider(listOf(pokemonEntity))),
holdRemovalCallbacks = holdRemovalCallbacks.toMutableMap(),
holds = holds.toMutableSet(),
runtime = runtime,
level = pokemonEntity.level()
)
}
}
lateinit var future: CompletableFuture<Unit>
inline fun <reified T> findOneProvider() = providers.filterIsInstance<T>().firstOrNull()
/** Returns a reference to the internal holds set so you can keep an eye on it. */
fun getHolds(): Set<String> = holds
fun addHold(hold: String) = holds.add(hold)
fun removeHold(hold: String) {
holds.remove(hold)
holdRemovalCallbacks.remove(hold)?.invoke()
}
}
class UsersProvider(users: List<Entity>): EntityProvider {
@@ -21,7 +21,7 @@ import java.util.concurrent.CompletableFuture
class AddHoldsActionEffectKeyframe : ActionEffectKeyframe {
val holds = mutableSetOf<String>()
override fun play(context: ActionEffectContext): CompletableFuture<Unit> {
context.holds.addAll(holds)
holds.forEach(context::addHold)
return CompletableFuture.completedFuture(Unit)
}
}
@@ -49,6 +49,6 @@ class AnimationActionEffectKeyframe : ConditionalActionEffectKeyframe(), EntityC
players.forEach { it.sendPacket(pkt) }
}
return delayedFuture(seconds = delay.resolveFloat(context.runtime))
return delayedFuture(seconds = delay.resolveFloat(context.runtime), tracker = context.tracker)
}
}
@@ -46,6 +46,6 @@ class EntityMoLangActionEffectKeyframe : ConditionalActionEffectKeyframe(), Enti
players.forEach { it.sendPacket(pkt) }
}
return delayedFuture(seconds = delay.resolveFloat(context.runtime))
return delayedFuture(seconds = delay.resolveFloat(context.runtime), context.tracker)
}
}
@@ -18,7 +18,6 @@ import com.cobblemon.mod.common.entity.PosableEntity
import com.cobblemon.mod.common.net.messages.client.effect.SpawnSnowstormEntityParticlePacket
import com.cobblemon.mod.common.util.asExpressionLike
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
@@ -79,6 +78,6 @@ class EntityParticlesActionEffectKeyframe : ConditionalActionEffectKeyframe(), E
}
}
return delayedFuture(seconds = delay.resolveFloat(context.runtime))
return delayedFuture(seconds = delay.resolveFloat(context.runtime), context.tracker)
}
}
@@ -15,8 +15,8 @@ import com.cobblemon.mod.common.api.moves.animations.UsersProvider
import com.cobblemon.mod.common.api.scheduling.delayedFuture
import com.cobblemon.mod.common.util.asExpressionLike
import com.cobblemon.mod.common.util.asIdentifierDefaultingNamespace
import net.minecraft.core.registries.Registries
import java.util.concurrent.CompletableFuture
import net.minecraft.core.registries.Registries
/**
* An action effect keyframe that plays a positioned sound for all matching entities.
@@ -45,6 +45,6 @@ class EntitySoundActionEffectKeyframe : ConditionalActionEffectKeyframe(), Entit
entity.playSound(soundEvent, 1f, 1f)
}
return delayedFuture(seconds = delay.resolveFloat(context.runtime))
return delayedFuture(seconds = delay.resolveFloat(context.runtime), context.tracker)
}
}
@@ -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
@@ -27,6 +25,6 @@ class MoLangActionEffectKeyframe : ActionEffectKeyframe {
val delay: ExpressionLike = "0".asExpressionLike()
override fun play(context: ActionEffectContext): CompletableFuture<Unit> {
expressions.resolve(context.runtime)
return delayedFuture(seconds = delay.resolveFloat(context.runtime))
return delayedFuture(seconds = delay.resolveFloat(context.runtime), context.tracker)
}
}
@@ -13,7 +13,6 @@ 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.scheduling.afterOnServer
import com.cobblemon.mod.common.entity.ai.OmniPathNavigation.NavigationContext
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
import com.cobblemon.mod.common.util.asExpressionLike
@@ -61,7 +60,7 @@ class MoveToTargetActionEffectKeyframe : ActionEffectKeyframe {
}
)
afterOnServer(seconds = timeout.resolveFloat(context.runtime)) {
context.tracker.after(seconds = timeout.resolveFloat(context.runtime)) {
if (!future.isDone && !timedOut) {
timedOut = true
timeoutEffect.run(context).thenApply { future.complete(Unit) }
@@ -14,5 +14,5 @@ import com.cobblemon.mod.common.util.asExpressionLike
class PauseActionEffectKeyframe : ConditionalActionEffectKeyframe() {
val pause = "1".asExpressionLike()
override fun playWhenTrue(context: ActionEffectContext) = delayedFuture(seconds = pause.resolveFloat(context.runtime))
override fun playWhenTrue(context: ActionEffectContext) = delayedFuture(seconds = pause.resolveFloat(context.runtime), context.tracker)
}
@@ -25,11 +25,8 @@ class RemoveHoldsActionEffectKeyframe : ActionEffectKeyframe {
val holds = mutableSetOf<String>()
override fun play(context: ActionEffectContext): CompletableFuture<Unit> {
return delayedFuture(seconds = delay).thenApply {
if (holds.isEmpty()) {
context.holds.clear()
} else {
context.holds.removeAll(holds)
}
val holdsToRemove = if (holds.isEmpty()) context.getHolds() else holds
holdsToRemove.forEach(context::removeHold)
}
}
}
@@ -13,13 +13,12 @@ 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.UsersProvider
import com.cobblemon.mod.common.api.scheduling.after
import com.cobblemon.mod.common.entity.ai.OmniPathNavigation.NavigationContext
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
import com.cobblemon.mod.common.util.asExpressionLike
import java.util.concurrent.CompletableFuture
import net.minecraft.resources.ResourceLocation
import net.minecraft.world.phys.Vec3
import java.util.concurrent.CompletableFuture
class ReturnToPositionActionEffectKeyframe : ActionEffectKeyframe {
val speed = 1F
@@ -56,7 +55,7 @@ class ReturnToPositionActionEffectKeyframe : ActionEffectKeyframe {
}
)
after(seconds = timeout.resolveFloat(context.runtime)) {
context.tracker.after(seconds = timeout.resolveFloat(context.runtime)) {
if (!future.isDone && !timedOut) {
timedOut = true
timeoutEffect.run(context).thenApply { future.complete(Unit) }
@@ -29,7 +29,6 @@ import com.cobblemon.mod.common.util.withQueryValue
import com.google.gson.JsonElement
import com.google.gson.JsonObject
import kotlin.random.Random
import kotlin.ranges.random
import net.minecraft.server.level.ServerPlayer
/**
@@ -17,21 +17,18 @@ import com.cobblemon.mod.common.api.npc.NPCPartyProvider
import com.cobblemon.mod.common.api.pokemon.PokemonProperties
import com.cobblemon.mod.common.api.storage.party.NPCPartyStore
import com.cobblemon.mod.common.entity.npc.NPCEntity
import com.cobblemon.mod.common.util.*
import com.cobblemon.mod.common.util.asArrayValue
import com.cobblemon.mod.common.util.asExpression
import com.cobblemon.mod.common.util.cobblemonResource
import com.cobblemon.mod.common.util.resolveFloat
import com.cobblemon.mod.common.util.resolveInt
import com.cobblemon.mod.common.util.weightedSelection
import com.cobblemon.mod.common.util.withQueryValue
import com.google.gson.JsonElement
import com.google.gson.JsonObject
import com.google.gson.JsonPrimitive
import net.minecraft.server.level.ServerPlayer
import kotlin.collections.List
import kotlin.collections.any
import kotlin.collections.filter
import kotlin.collections.first
import kotlin.collections.mutableListOf
import kotlin.collections.mutableMapOf
import kotlin.collections.randomOrNull
import kotlin.collections.set
import kotlin.collections.toMutableList
import kotlin.random.Random
import net.minecraft.server.level.ServerPlayer
/**
* A provider of a party for battling the NPC. It generates a party using a more complex process
@@ -12,10 +12,10 @@ import com.cobblemon.mod.common.api.pokedex.AbstractPokedexManager
import com.cobblemon.mod.common.api.pokedex.PokedexEntryProgress
import com.cobblemon.mod.common.api.pokedex.entry.PokedexEntry
import com.cobblemon.mod.common.api.pokemon.PokemonSpecies
import com.cobblemon.mod.common.api.pokemon.evolution.Evolution
import com.cobblemon.mod.common.api.tms.TechnicalMachines
import com.cobblemon.mod.common.client.CobblemonClient
import com.cobblemon.mod.common.pokemon.FormData
import com.cobblemon.mod.common.pokemon.transformation.evolution.Evolution
import com.cobblemon.mod.common.util.asIdentifierDefaultingNamespace
enum class PokedexCategoryFilterType {
@@ -14,11 +14,11 @@ import com.cobblemon.mod.common.api.pokedex.AbstractPokedexManager
import com.cobblemon.mod.common.api.pokedex.PokedexEntryProgress
import com.cobblemon.mod.common.api.pokedex.entry.PokedexEntry
import com.cobblemon.mod.common.api.pokemon.PokemonSpecies
import com.cobblemon.mod.common.api.pokemon.evolution.Evolution
import com.cobblemon.mod.common.api.tms.TechnicalMachines
import com.cobblemon.mod.common.client.CobblemonClient
import com.cobblemon.mod.common.pokemon.abilities.HiddenAbility
import com.cobblemon.mod.common.pokemon.FormData
import com.cobblemon.mod.common.pokemon.abilities.HiddenAbility
import com.cobblemon.mod.common.pokemon.transformation.evolution.Evolution
import com.cobblemon.mod.common.util.asIdentifierDefaultingNamespace
import com.cobblemon.mod.common.util.asTranslated
import com.cobblemon.mod.common.util.itemRegistry
@@ -49,6 +49,7 @@ import com.mojang.brigadier.StringReader
import com.mojang.serialization.Codec
import com.mojang.serialization.JsonOps
import java.util.UUID
import kotlin.jvm.optionals.getOrNull
import kotlin.math.min
import kotlin.random.Random
import net.minecraft.ResourceLocationException
@@ -65,7 +66,6 @@ import net.minecraft.resources.ResourceLocation
import net.minecraft.server.level.ServerPlayer
import net.minecraft.world.item.ItemStack
import net.minecraft.world.level.Level
import kotlin.jvm.optionals.getOrNull
/**
* A grouping of typical, selectable properties for a Pokémon. This is serializable
@@ -168,8 +168,8 @@ open class PokemonProperties {
parseIntProperty(keyPairs, listOf("${statName}_iv"))?.coerceIn(0, IVs.MAX_VALUE)?.let { maybeIVs[stat] = it }
parseIntProperty(keyPairs, listOf("${statName}_ev"))?.coerceIn(0, EVs.MAX_STAT_VALUE)?.let { maybeEVs[stat] = it }
}
props.ivs = maybeIVs
props.evs = maybeEVs
props.evs = maybeEVs.takeIf { it.total() > 0 }
props.ivs = maybeIVs.takeIf { it.total() > 0 }
props.updateAspects()
return props
@@ -519,29 +519,18 @@ open class PokemonProperties {
}
fun matches(properties: PokemonProperties): Boolean {
return properties.asString() == this.asString()
// Custom properties check could be duplicated but can't assume 3rd party hasn't done anything type specific
return this.commonMatches(properties) && this.customProperties.containsAll(properties.customProperties)
}
// Undefined properties will match whatever they're compared with
private fun commonMatches(pokemon: Pokemon): Boolean {
level?.takeIf { it != pokemon.level }?.let { return false }
shiny?.takeIf { it != pokemon.shiny }?.let { return false }
gender?.takeIf { it != pokemon.gender }?.let { return false }
species?.run {
try {
val species = if (this == "random") {
PokemonSpecies.species.random()
} else {
PokemonSpecies.getByIdentifier(this.asIdentifierDefaultingNamespace()) ?: return@run
}
if (pokemon.species != species) {
return false
}
} catch (e: ResourceLocationException) {
return false
}
}
species?.takeIf { it.asSpecies() != pokemon.species }?.let { return false }
nickname?.takeIf { it.string != pokemon.nickname?.string }?.let { return false }
form?.takeIf { !it.equals(pokemon.form.name, true) }?.let { return false }
form?.takeIf { !it.equals(pokemon.form.formOnlyShowdownId(), true) }?.let { return false }
friendship?.takeIf { it != pokemon.friendship }?.let { return false }
fullness?.takeIf { it != pokemon.currentFullness }?.let { return false }
pokeball?.takeIf { it != pokemon.caughtBall.name.toString() }?.let { return false }
@@ -584,6 +573,36 @@ open class PokemonProperties {
return true
}
// Undefined properties will match whatever they're compared with
private fun commonMatches(properties: PokemonProperties): Boolean {
level?.takeIf { it != properties.level }?.let { return false }
shiny?.takeIf { it != properties.shiny }?.let { return false }
gender?.takeIf { it != properties.gender }?.let { return false }
species?.takeIf { it.asSpecies() != properties.species?.asSpecies() }?.let { return false }
nickname?.takeIf { it.string != properties.nickname?.string }?.let { return false }
form?.takeIf { it != properties.form }?.let { return false }
friendship?.takeIf { it != properties.friendship }?.let { return false }
pokeball?.takeIf { it != properties.pokeball }?.let { return false }
nature?.takeIf { it != properties.nature }?.let { return false }
ability?.takeIf { it != properties.ability }?.let { return false }
status?.takeIf { it != properties.status }?.let { return false }
ivs?.forEach{ stat ->
if (stat.value != properties.ivs?.get(stat.key)) { return false }
}
evs?.forEach{ stat ->
if (stat.value != properties.evs?.get(stat.key)) { return false }
}
type?.takeIf { it != properties.type }?.let { return false }
teraType?.takeIf { it != properties.teraType }?.let { return false }
dmaxLevel?.takeIf { it != properties.dmaxLevel }?.let { return false }
gmaxFactor?.takeIf { it != properties.gmaxFactor }?.let { return false }
tradeable?.takeIf { it != properties.tradeable }?.let { return false }
originalTrainer?.takeIf { it != properties.originalTrainer }?.let{ return false }
originalTrainerType?.takeIf { it != properties.originalTrainerType }?.let{ return false }
moves?.takeIf { it.any { move -> properties.moves?.none { it == move } == true } }?.let { return false }
return true
}
// TODO Review the need for this, usage for us is in commands that deviate from the behavior established by multiple Pokémon query equivalent
fun isSubSetOf(properties: PokemonProperties): Boolean {
level?.takeIf { it != properties.level }?.let { return false }
@@ -904,4 +923,15 @@ open class PokemonProperties {
}
fun hasSpecies() = species?.let { PokemonSpecies.getByIdentifier(it.asIdentifierDefaultingNamespace()) } != null
private fun String.asSpecies() =
try {
if (this == "random") {
PokemonSpecies.species.random()
} else {
PokemonSpecies.getByIdentifier(this.asIdentifierDefaultingNamespace())
}
}
catch (e: ResourceLocationException) {
null
}
}
@@ -12,6 +12,8 @@ import com.bedrockk.molang.Expression
import com.cobblemon.mod.common.Cobblemon
import com.cobblemon.mod.common.api.abilities.AbilityPool
import com.cobblemon.mod.common.api.abilities.AbilityTemplate
import com.cobblemon.mod.common.api.abilities.CommonAbility
import com.cobblemon.mod.common.api.abilities.PotentialAbility
import com.cobblemon.mod.common.api.ai.SleepDepth
import com.cobblemon.mod.common.api.ai.config.BehaviourConfig
import com.cobblemon.mod.common.api.ai.config.task.TaskConfig
@@ -30,14 +32,14 @@ import com.cobblemon.mod.common.api.pokemon.PokemonSpecies.getByIdentifier
import com.cobblemon.mod.common.api.pokemon.effect.ShoulderEffect
import com.cobblemon.mod.common.api.pokemon.effect.adapter.ShoulderEffectAdapter
import com.cobblemon.mod.common.api.pokemon.egg.EggGroup
import com.cobblemon.mod.common.api.pokemon.evolution.Evolution
import com.cobblemon.mod.common.api.pokemon.evolution.PreEvolution
import com.cobblemon.mod.common.api.pokemon.experience.ExperienceGroup
import com.cobblemon.mod.common.api.pokemon.experience.ExperienceGroupAdapter
import com.cobblemon.mod.common.api.pokemon.moves.Learnset
import com.cobblemon.mod.common.api.pokemon.requirement.Requirement
import com.cobblemon.mod.common.api.pokemon.stats.Stat
import com.cobblemon.mod.common.api.pokemon.stats.Stats
import com.cobblemon.mod.common.api.pokemon.transformation.evolution.PreEvolution
import com.cobblemon.mod.common.api.pokemon.transformation.requirement.TransformationRequirement
import com.cobblemon.mod.common.api.pokemon.transformation.trigger.TransformationTrigger
import com.cobblemon.mod.common.api.reactive.SimpleObservable
import com.cobblemon.mod.common.api.riding.behaviour.RidingBehaviourSettings
import com.cobblemon.mod.common.api.riding.sound.RideSoundSettingsList
@@ -48,12 +50,21 @@ import com.cobblemon.mod.common.net.messages.client.data.SpeciesRegistrySyncPack
import com.cobblemon.mod.common.pokemon.FormData
import com.cobblemon.mod.common.pokemon.Species
import com.cobblemon.mod.common.pokemon.SpeciesAdditions
import com.cobblemon.mod.common.pokemon.adapters.CobblemonRequirementAdapter
import com.cobblemon.mod.common.pokemon.abilities.HiddenAbility
import com.cobblemon.mod.common.pokemon.abilities.SpecialAbility
import com.cobblemon.mod.common.pokemon.ai.ObtainableItemCondition
import com.cobblemon.mod.common.pokemon.ai.ObtainableItemConditionAdapter
import com.cobblemon.mod.common.pokemon.evolution.adapters.CobblemonEvolutionAdapter
import com.cobblemon.mod.common.pokemon.evolution.adapters.CobblemonPreEvolutionAdapter
import com.cobblemon.mod.common.pokemon.evolution.adapters.LegacyItemConditionWrapperAdapter
import com.cobblemon.mod.common.pokemon.transformation.adapters.CobblemonPreEvolutionAdapter
import com.cobblemon.mod.common.pokemon.transformation.adapters.CobblemonRequirementAdapter
import com.cobblemon.mod.common.pokemon.transformation.adapters.CobblemonTriggerAdapter
import com.cobblemon.mod.common.pokemon.transformation.adapters.LegacyItemConditionWrapperAdapter
import com.cobblemon.mod.common.pokemon.transformation.evolution.Evolution
import com.cobblemon.mod.common.pokemon.transformation.form.GigantamaxForm
import com.cobblemon.mod.common.pokemon.transformation.form.PermanentForm
import com.cobblemon.mod.common.pokemon.transformation.form.StandardForm
import com.cobblemon.mod.common.pokemon.transformation.form.TemporaryForm
import com.cobblemon.mod.common.pokemon.transformation.requirements.HeldItemRequirement
import com.cobblemon.mod.common.pokemon.transformation.requirements.MoveSetRequirement
import com.cobblemon.mod.common.util.adapters.*
import com.cobblemon.mod.common.util.cobblemonResource
import com.google.common.collect.HashBasedTable
@@ -104,10 +115,8 @@ object PokemonSpecies : JsonDataRegistry<Species> {
.registerTypeAdapter(ExperienceGroup::class.java, ExperienceGroupAdapter)
.registerTypeAdapter(EntityDimensions::class.java, EntityDimensionsAdapter)
.registerTypeAdapter(Learnset::class.java, LearnsetAdapter)
.registerTypeAdapter(Evolution::class.java, CobblemonEvolutionAdapter)
.registerTypeAdapter(AABB::class.java, BoxAdapter)
.registerTypeAdapter(AbilityPool::class.java, AbilityPoolAdapter)
.registerTypeAdapter(Requirement::class.java, CobblemonRequirementAdapter)
.registerTypeAdapter(PreEvolution::class.java, CobblemonPreEvolutionAdapter)
.registerTypeAdapter(TypeToken.getParameterized(Set::class.java, Evolution::class.java).type, LazySetAdapter(Evolution::class))
.registerTypeAdapter(IntRange::class.java, IntRangeAdapter)
@@ -128,7 +137,10 @@ object PokemonSpecies : JsonDataRegistry<Species> {
.registerTypeAdapter(TypeToken.getParameterized(RegistryLikeCondition::class.java, Fluid::class.java).type, FluidLikeConditionAdapter)
.registerTypeAdapter(EggGroup::class.java, EggGroupAdapter)
.registerTypeAdapter(MobEffect::class.java, RegistryElementAdapter<MobEffect>(BuiltInRegistries::MOB_EFFECT))
.registerTypeAdapter(TransformationTrigger::class.java, CobblemonTriggerAdapter)
.registerTypeAdapter(TransformationRequirement::class.java, CobblemonRequirementAdapter)
.registerTypeAdapter(ItemPredicate::class.java, LegacyItemConditionWrapperAdapter)
.registerTypeAdapter(FormData::class.java, FormAdapter)
.registerTypeAdapter(RidingBehaviourSettings::class.java, RidingBehaviourSettingsAdapter)
.registerTypeAdapter(RideSoundSettingsList::class.java, RideSoundSettingsListAdapter)
.registerTypeAdapter(ObtainableItemCondition::class.java, ObtainableItemConditionAdapter)
@@ -152,6 +164,9 @@ object PokemonSpecies : JsonDataRegistry<Species> {
val implemented: List<Species>
get() = this.species.filter { it.implemented }
val forms: Collection<FormData>
get() = this.species.flatMap { it.allForms }
init {
SpeciesAdditions.observable.subscribe {
this.species.forEach(Species::initialize)
@@ -246,34 +261,18 @@ object PokemonSpecies : JsonDataRegistry<Species> {
}
/**
* The representation of a [Species] and/or [FormData] in the context of showdown.
* The representation of [FormData] in the context of Showdown.
* This is intended as a sort of DTO that can be easily converted between JSON and Java/JS objects.
*
* @param species The [Species] being converted or the base species if the form is not null.
* @param form The [FormData] being converted int o species (Showdown considers them species) will be null when dealing with the base form.
* @param form The [FormData] being converted into a species (Showdown considers them species).
*/
@Suppress("unused")
internal class ShowdownSpecies(species: Species, form: FormData?) {
val num = species.nationalPokedexNumber
val name = if (form != null) "${createShowdownName(species)}-${form.name}" else createShowdownName(species)
val baseSpecies = if (form != null) createShowdownName(species) else this.name
val forme = form?.name
// ToDo baseForme
val otherFormes = if (form == null && species.forms.isNotEmpty()) species.forms.map { "${this.name}-${it.name}" } else emptyList()
val formeOrder = if (form == null && this.otherFormes.isNotEmpty()) arrayListOf(this.name, *this.otherFormes.toTypedArray()) else emptyList()
val abilities: Map<String, String> = mapOf(
"0" to "No Ability",
"1" to "No Ability",
"H" to "No Ability",
"S" to "No Ability"
)
val types = (form?.types ?: species.types).map { it.name }
val preevo: String? = (form?.preEvolution ?: species.preEvolution)?.let { if (it.form == it.species.standardForm) createShowdownName(it.species) else "${createShowdownName(it.species)}-${it.form.name}" }
// For the context of battles the content here doesn't matter whatsoever and due to how PokemonProperties work we can't guarantee an actual specific species is defined.
val evos = if ((form?.evolutions ?: species.evolutions).isEmpty()) emptyList() else arrayListOf("")
val nfe = this.evos.isNotEmpty()
val eggGroups = (form?.eggGroups ?: species.eggGroups).map { it.showdownID }
val gender: String? = when (form?.maleRatio ?: species.maleRatio) {
internal open class ShowdownSpecies(form: FormData) {
val num = form.species.nationalPokedexNumber
val name = form.showdownName()
val types = form.types.map { it.name }
val eggGroups = form.eggGroups.map { it.showdownID }
val gender: String? = when (form.maleRatio) {
0F -> "F"
1F -> "M"
-1F, 1.125F -> "N"
@@ -281,47 +280,145 @@ object PokemonSpecies : JsonDataRegistry<Species> {
}
val genderRatio = if (this.gender == null)
mapOf(
"maleRatio" to (form?.maleRatio ?: species.maleRatio),
"femaleRation" to (1F - (form?.maleRatio ?: species.maleRatio))
"M" to (form.maleRatio),
"F" to (1F - (form.maleRatio))
) else null
val baseStats = mapOf(
"hp" to (form?.baseStats?.get(Stats.HP) ?: species.baseStats[Stats.HP] ?: 1),
"atk" to (form?.baseStats?.get(Stats.ATTACK) ?: species.baseStats[Stats.ATTACK] ?: 1),
"def" to (form?.baseStats?.get(Stats.DEFENCE) ?: species.baseStats[Stats.DEFENCE] ?: 1),
"spa" to (form?.baseStats?.get(Stats.SPECIAL_ATTACK) ?: species.baseStats[Stats.SPECIAL_ATTACK] ?: 1),
"spd" to (form?.baseStats?.get(Stats.SPECIAL_DEFENCE) ?: species.baseStats[Stats.SPECIAL_DEFENCE] ?: 1),
"spe" to (form?.baseStats?.get(Stats.SPEED) ?: species.baseStats[Stats.SPEED] ?: 1)
)
val heightm = (form?.height ?: species.height) / 10
val weightkg = (form?.weight ?: species.weight) / 10
val baseStats = Stats.PERMANENT.associateBy({ it.showdownId }, { form.baseStats[it] ?: 1 })
val heightm = form.height / 10
val weightkg = form.weight / 10
// This is ugly, but we already have it hardcoded in the mod anyway
val maxHP = if (species.showdownId() == "shedinja") 1 else null
val canGigantamax: String? = if (form?.gigantamaxMove != null) form.gigantamaxMove.name else null
val cannotDynamax = form?.dynamaxBlocked ?: species.dynamaxBlocked
// ToDo battleOnly
// ToDo changesFrom
val requiredMove = form?.requiredMove
val requiredItem = form?.requiredItem
val requiredItems = form?.requiredItems
val maxHP = if (this.num == 292) 1 else null
val cannotDynamax = form.dynamaxBlocked
val abilities = form.showdownAbilityMapping()
// Common fields exempt from standard forms
val baseSpecies = if (form !is StandardForm) form.species.standardForm.showdownName() else null
val forme = if (form !is StandardForm) form.name else null
/**
* The following fields are optional and currently omitted
*
* cosmeticFormes (not needed, we have species features)
* addedType (tertiary type [by name or showdownid] added by moves or abilities)
* tier (smogon tryhard bs)
* doublesTier (smogon tryhard bs)
* natDexTier (smogon tryhard bs)
* evoType (the evolution method used to evolve from 'prevo'; trade', 'useItem', 'levelMove', 'levelExtra', 'levelFriendship', 'levelHold', 'other')
* evoMove (the move [by name or showdownid] used to evolve from 'prevo')
* evoLevel (the minimum level required to evolve from 'prevo')
* canHatch (flag for baby pokemon)
* color (color, value is arbitrary)
* tags (flags for filtering pokemon; 'Mega', 'Mythical', 'Sub-Legendary', 'Restricted Legendary', 'Paradox')
* unreleasedHidden (whether this pokemon has an unreleased hidden ability)
* maleOnlyHidden (whether it is only possible to get the hidden ability on a male pokemon)
* gmaxUnreleased (whether this pokemon has an unreleased gmax form)
* pokemonGoData (no one cares)
*/
}
private fun createShowdownName(species: Species): String {
if (species.resourceIdentifier.namespace == Cobblemon.MODID) {
return species.name
/**
* The representation of a [PermanentForm] in the context of Showdown.
*
* @param form The [PermanentForm] being converted into a species.
*/
internal open class ShowdownPermanentForm(form: PermanentForm) : ShowdownSpecies(form) {
// species this form evolves from
val prevo = form.preEvolution?.form?.showdownName()
// For the context of battles the content here doesn't matter whatsoever and due to how PokemonProperties work we can't guarantee an actual specific species is defined.
val evos = form.evolutions.map { "" }
// not fully evolved
val nfe = this.evos.isNotEmpty()
// whether there is a gmax form to change to
val canGigantamax: String? = form.changeableForms.filterIsInstance<GigantamaxForm>().firstOrNull()?.name // TODO id better
}
/**
* The representation of a [StandardForm] in the context of Showdown.
*
* @param form The [StandardForm] being converted into a species.
*/
internal class ShowdownStandardForm(form: StandardForm) : ShowdownPermanentForm(form) {
// list of all forms descending from this base species
val otherFormes = form.flattenForms().map { it.showdownName() }
// list of forms [by name or showdownid] in the order they appear in game [union of baseSpecies, otherFormes, and cosmeticFormes] with the exception of ending with 'Gmax' forms
val formeOrder = if (this.otherFormes.isNotEmpty()) arrayListOf(this.name, *this.otherFormes.toTypedArray()) else null
// TODO we don't enforce any form order with our Species registration - right now this looks like only a problem with Mega Rayquaza, but investigate changes needed on Showdown's end to enable these lists to be more dynamic
}
/**
* The representation of a [TemporaryForm] in the context of Showdown.
*
* @param form The [TemporaryForm] being converted into a species.
*/
internal class ShowdownTemporaryForm(form: TemporaryForm) : ShowdownSpecies(form) {
// form change can occur during a battle
val battleOnly = if (form.battleOnly) form.parentForm.showdownName() else null
// form change can occur outside of battle (mutually exclusive with battleOnly)
val changesFrom = if (!form.battleOnly) form.parentForm.showdownName() else null
// pokemon must know this move to be in this form
val requiredMove = form.requirements.filterIsInstance<MoveSetRequirement>().firstOrNull()?.move?.showdownId() // TODO update showdown to support 'requiredMoves'
// pokemon must hold one of these item(s) to be in this form
val requiredItems = form.requirements.filterIsInstance<HeldItemRequirement>().firstOrNull()?.let { requirement ->
try {
requirement.itemCondition.items.get().map { BuiltInRegistries.ITEM.getKey(it.value()).path } // TODO held items on showdown are ignorant of namespace
}
catch (e: NoSuchElementException)
{
Cobblemon.LOGGER.error("Failed to resolve required held item for ${form.showdownId()}}") // TODO this needs to be done after tags are loaded...
null
}
}
return "${species.resourceIdentifier.namespace}:${species.name}"
}
/** Accommodate for Showdown bullshit. */
/*
private fun TemporaryForm.showdownParentForm(): Any {
if (this.parentOverrides.isNotEmpty())
return this.species.standardForm.flattenForms().filter {
parentOverrides.contains(it.showdownId())
}.map {
it.showdownName()
}
else
return parentForm.showdownName()
}
*/
/**
* Constructs a mapping of the [PotentialAbility]s belonging to a [FormData] in Showdown identifiable format.
*
* @return A map of type (numeric for [CommonAbility]s, H for [HiddenAbility], S for [SpecialAbility]) to showdownid.
*/
private fun FormData.showdownAbilityMapping(): Map<String, String>? {
// potential abilities
val commonAbilities = this.abilities.filterIsInstance<CommonAbility>()
val hiddenAbility = this.abilities.find { it is HiddenAbility }
val specialAbility = this.abilities.find { it is SpecialAbility }
// can have multiple common abilities
val abilities = mutableMapOf<String, String>()
val mapping: (String, PotentialAbility) -> Unit = { key, ability ->
abilities.put(key, ability.template.showdownId())
}
// can only have one hidden and one special ability
commonAbilities.forEachIndexed { index, ability -> mapping(index.toString(), ability) }
hiddenAbility?.let { ability -> mapping("H", ability) }
specialAbility?.let { ability -> mapping("S", ability) }
return if (abilities.isEmpty()) null else abilities
}
internal fun allShowdownSpecies(): Map<String, String> {
val result = mutableMapOf<String, String>()
this.species.forEach {species ->
val baseSpecies = ShowdownSpecies(species, null)
result[ShowdownIdentifiable.REGEX.replace(baseSpecies.name.lowercase(), "")] = this.gson.toJson(baseSpecies)
species.forms.forEach { form ->
if (form != species.standardForm) {
val formSpecies = ShowdownSpecies(species, form)
result[ShowdownIdentifiable.REGEX.replace(formSpecies.name.lowercase(), "")] = this.gson.toJson(formSpecies)
}
this.species.forEach { species ->
species.permanentForms.forEach { form ->
val formSpecies = ShowdownSpecies(form)
result[ShowdownIdentifiable.REGEX.replace(formSpecies.name.lowercase(), "")] = this.gson.toJson(formSpecies)
}
species.temporaryForms.forEach { form ->
val formSpecies = ShowdownSpecies(form)
result[ShowdownIdentifiable.REGEX.replace(formSpecies.name.lowercase(), "")] = this.gson.toJson(formSpecies)
}
}
return result
@@ -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.api.pokemon.adapters
import com.cobblemon.mod.common.api.pokemon.requirement.Requirement
import com.google.gson.JsonDeserializer
import com.google.gson.JsonSerializer
import kotlin.reflect.KClass
/**
* Saves and loads [Requirement]s with JSON.
* For the default implementation see [com.cobblemon.mod.common.pokemon.adapters.CobblemonRequirementAdapter].
*
* @author Licious
* @since March 21st, 2022
*/
interface RequirementAdapter : JsonDeserializer<Requirement>, JsonSerializer<Requirement> {
/**
* Registers the given type of [Requirement] to it's associated ID for deserialization.
*
* @param T The type of [Requirement].
* @param id The id of the evolution event.
* @param type The [KClass] of the type.
*/
fun <T : Requirement> registerType(id: String, type: KClass<T>)
}
@@ -0,0 +1,32 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.api.pokemon.aspect
import com.cobblemon.mod.common.api.pokemon.feature.SpeciesFeature
import com.cobblemon.mod.common.pokemon.Pokemon
/**
* A provider of aspects for a [SpeciesFeature].
*
* @author Segfault Guy
* @since Feb 12th, 2024
*/
interface FeatureAspectProvider: AspectProvider {
var default: String?
var isAspect: Boolean
/** Returns true if this [aspect] is provided by this provider. */
fun matches(aspect: String): Boolean
/** Creates a [SpeciesFeature] that provides the respective [aspect]. */
fun from(aspect: String): SpeciesFeature<*>?
/** Sets the [aspect] that's provided. */
fun set(pokemon: Pokemon, aspect: String)
}
@@ -24,11 +24,11 @@ interface SingleConditionalAspectProvider : AspectProvider {
fun getForFeature(name: String): SingleConditionalAspectProvider {
return object : SingleConditionalAspectProvider {
override val aspect: String = name
override fun meetsCondition(pokemon: Pokemon) = pokemon.getFeature<FlagSpeciesFeature>(name)?.enabled == true
override fun meetsCondition(pokemon: Pokemon) = pokemon.getFeature<FlagSpeciesFeature>(name)?.value == true
override fun meetsCondition(pokemonProperties: PokemonProperties) = pokemonProperties
.customProperties
.filterIsInstance<FlagSpeciesFeature>()
.any { it.name == name && it.enabled }
.any { it.name == name && it.value }
}
}
@@ -1,54 +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.api.pokemon.evolution
import com.cobblemon.mod.common.pokemon.Pokemon
import com.cobblemon.mod.common.pokemon.evolution.variants.ItemInteractionEvolution
import com.cobblemon.mod.common.pokemon.evolution.variants.TradeEvolution
/**
* Represents an evolution of a [Pokemon] that can only occur during specific actions and with added context.
* For the default implementations see [ItemInteractionEvolution] & [TradeEvolution].
*
* @param RC The context given at runtime when querying the [Evolution].
* @param TC The context that is serialized from JSON during species loading, this is what the [RC] is expected to match against.
* @author Licious
* @since March 19th, 2022
*/
interface ContextEvolution<RC, TC> : Evolution {
/**
* The target context for this [Evolution] to even be tested.
*/
val requiredContext: TC
/**
* Attempts to evolve the given [Pokemon] under the given context of type [RC].
*
* @param pokemon The [Pokemon] attempting to evolve.
* @param context The context of this query.
* @return If the evolution was successful.
*/
fun attemptEvolution(pokemon: Pokemon, context: RC): Boolean {
if (this.testContext(pokemon, context) && super.test(pokemon)) {
return super.evolve(pokemon)
}
return false
}
/**
* Checks if the given context is valid for the [requiredContext].
*
* @param pokemon The [Pokemon] attempting to evolve.
* @param context The context of this query.
* @return If the context matched the [requiredContext].
*/
fun testContext(pokemon: Pokemon, context: RC): Boolean
}
@@ -1,69 +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.api.pokemon.evolution
import com.cobblemon.mod.common.api.pokemon.evolution.progress.EvolutionProgress
import com.cobblemon.mod.common.pokemon.Pokemon
import com.cobblemon.mod.common.pokemon.evolution.controller.ClientEvolutionController
import com.cobblemon.mod.common.pokemon.evolution.controller.ServerEvolutionController
/**
* Responsible for holding all available [EvolutionLike]s in the [Pokemon].
* Also handles all the networking behind them.
* For the Cobblemon default implementations see [ClientEvolutionController] & [ServerEvolutionController].
*
* @author Licious
* @since April 28th, 2022
*/
interface EvolutionController<T : EvolutionLike, out I : PreProcessor> : MutableSet<T> {
/**
* Resolves the [Pokemon] attached to this controller.
*
* @return The [Pokemon] this controller is attached to.
*/
fun pokemon(): Pokemon
/**
* Starts the given evolution on this controller.
* All the necessary networking will be handled.
*
* @param evolution The [EvolutionLike] starting.
*/
fun start(evolution: T)
/**
* Returns an immutable collection of [EvolutionProgress]es attached to this controller.
*
* @return The currently tracked [EvolutionProgress]es.
*/
fun progress(): Collection<EvolutionProgress<*>>
/**
* Attaches a [EvolutionProgress] to this controller.
*
* @param P The type of [EvolutionProgress].
* @param progress The [EvolutionProgress] being attached for tracking.
* @return The instance being tracked.
*/
fun <P : EvolutionProgress<*>> trackProgress(progress: P): P
/**
* Attempts to find an [EvolutionProgress] in [progress] or creates and tracks using [trackProgress].
*
* @param P The type of [EvolutionProgress].
* @param predicate The lambda attempting to find specific progress. This needs to ensure the [EvolutionProgress] is of type [P] or the cast will fail.
* @param progressFactory The lambda creating a new instance of type [P] if [predicate] can't find an element.
* @return The found match in [progress] or the created and now tracked with [trackProgress].
*/
fun <P : EvolutionProgress<*>> progressFirstOrCreate(predicate: (progress: EvolutionProgress<*>) -> Boolean, progressFactory: () -> P): P
fun asIntermediate(): I
}
@@ -1,48 +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.api.pokemon.evolution
import com.cobblemon.mod.common.pokemon.Pokemon
import com.cobblemon.mod.common.pokemon.Species
import com.cobblemon.mod.common.pokemon.evolution.CobblemonEvolutionDisplay
import com.mojang.serialization.Codec
import com.mojang.serialization.codecs.RecordCodecBuilder
/**
* Represents an evolution of a [Pokemon], this is the client side counterpart of [Evolution].
* This has no attachments to any data regarding the evolution itself and only serves for display purposes and basic communication.
*
* @author Licious
* @since April 28th, 2022
*/
interface EvolutionDisplay : EvolutionLike {
/**
* The [Species] of the evolution result.
*/
val species: Species
/**
* The aspects of the evolution result.
* These are used by the client to resolve the entity it needs to display.
*/
val aspects: Set<String>
companion object {
@JvmStatic
val CODEC: Codec<EvolutionDisplay> = RecordCodecBuilder.create { instance ->
instance.group(
Codec.STRING.fieldOf("id").forGetter(EvolutionDisplay::id),
Species.BY_IDENTIFIER_CODEC.fieldOf("species").forGetter(EvolutionDisplay::species),
Codec.list(Codec.STRING).fieldOf("aspects").forGetter { it.aspects.toList() }
).apply(instance) { id, species, aspects -> CobblemonEvolutionDisplay(id, species, aspects.toSet()) }
}
}
}
@@ -1,59 +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.api.pokemon.evolution
/**
* Responsible for holding the different [EvolutionController] implementations based on the logical side.
* If you haven't already checked your side previously you can use [isClient].
*
* @param C The type of [EvolutionLike] on the client side.
* @param S The type of [EvolutionLike] on the server side.
* @param CI The type of [PreProcessor] on the client side.
* @param SI The type of [PreProcessor] on the server side.
*
* @author Licious
* @since June 18th, 2022
*/
interface EvolutionProxy<C : EvolutionLike, S : EvolutionLike, CI : PreProcessor, SI : PreProcessor> {
/**
* Checks if the current logical side is the client.
*
* @return True if the current logical side is the client.
*/
fun isClient(): Boolean
/**
* Returns the current [EvolutionController].
* Keep in mind this will have type erasure and as such most operations will not be possible.
* It's recommended to work with [client] or [server] when possible.
*
* @return The current [EvolutionController].
*/
fun current(): EvolutionController<out EvolutionLike, *>
/**
* The client side implementation of the [EvolutionController].
*
* @throws [ClassCastException] if called from the server side.
*
* @return The client side implementation of the [EvolutionController] if possible.
*/
fun client(): EvolutionController<C, CI>
/**
* The server side implementation of the [EvolutionController].
*
* @throws [ClassCastException] if called from the client side.
*
* @return The server side implementation of the [EvolutionController] if possible.
*/
fun server(): EvolutionController<S, SI>
}
@@ -1,43 +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.api.pokemon.evolution
import com.cobblemon.mod.common.pokemon.Pokemon
import com.cobblemon.mod.common.pokemon.evolution.variants.LevelUpEvolution
/**
* Represents an evolution of a [Pokemon] that can occur without any additional context or actions.
* For the default implementation see [LevelUpEvolution].
*
* @author Licious
* @since March 19th, 2022
*/
interface PassiveEvolution : Evolution {
/**
* Checks if the given [Pokemon] satisfies the requirements.
* If yes the evolution will attempt to start.
*
* @param pokemon The [Pokemon] being tested.
* @return If the [Pokemon] will evolve.
*/
fun attemptEvolution(pokemon: Pokemon): Boolean {
if (super.test(pokemon)) {
return super.evolve(pokemon)
}
return false
}
/**
* If the evolution will disappear once the conditions are no longer met.
*/
val permanent: Boolean
}
@@ -1,35 +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.api.pokemon.evolution.adapters
import com.cobblemon.mod.common.api.pokemon.evolution.Evolution
import com.cobblemon.mod.common.pokemon.evolution.adapters.CobblemonEvolutionAdapter
import com.google.gson.JsonDeserializer
import com.google.gson.JsonSerializer
import kotlin.reflect.KClass
/**
* Saves and loads [Evolution]s with JSON.
* For the default implementation see [CobblemonEvolutionAdapter].
*
* @author Licious
* @since March 20th, 2022
*/
interface EvolutionAdapter : JsonDeserializer<Evolution>, JsonSerializer<Evolution> {
/**
* Registers the given type of [Evolution] to it's associated ID for deserialization.
*
* @param T The type of [Evolution].
* @param id The id of the evolution event.
* @param type The [KClass] of the type.
*/
fun <T : Evolution> registerType(id: String, type: KClass<T>)
}
@@ -1,66 +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.api.pokemon.evolution.progress
import com.cobblemon.mod.common.pokemon.evolution.controller.ServerEvolutionController
import com.cobblemon.mod.common.pokemon.evolution.progress.*
import com.cobblemon.mod.common.util.cobblemonResource
import com.mojang.serialization.Codec
import com.mojang.serialization.Lifecycle
import net.minecraft.core.MappedRegistry
import net.minecraft.core.Registry
import net.minecraft.resources.ResourceKey
import net.minecraft.resources.ResourceLocation
import kotlin.jvm.Throws
object EvolutionProgressTypes {
private val REGISTRY: Registry<EvolutionProgressType<*>> = MappedRegistry(
ResourceKey.createRegistryKey(cobblemonResource("evolution_progress")), Lifecycle.stable()
)
@JvmStatic
val DAMAGE_TAKEN = this.registerType(DamageTakenEvolutionProgress.ID, EvolutionProgressType(DamageTakenEvolutionProgress.CODEC))
@JvmStatic
val DEFEAT = this.registerType(DefeatEvolutionProgress.ID, EvolutionProgressType(DefeatEvolutionProgress.CODEC))
@JvmStatic
val LAST_BATTLE_CRITICAL_HITS = this.registerType(LastBattleCriticalHitsEvolutionProgress.ID, EvolutionProgressType(LastBattleCriticalHitsEvolutionProgress.CODEC))
@JvmStatic
val RECOIL = this.registerType(RecoilEvolutionProgress.ID, EvolutionProgressType(RecoilEvolutionProgress.CODEC))
@JvmStatic
val USE_MOVE = this.registerType(UseMoveEvolutionProgress.ID, EvolutionProgressType(UseMoveEvolutionProgress.CODEC))
/**
* Registers an evolution progress.
*
* @param T The type of the [EvolutionProgress].
* @param id The [Identifier].
* @param type The [EvolutionProgressType] record.
* @return The registered [EvolutionProgressType] of type [T].
*
* @throws [IllegalStateException] if [Registry.register] fails.
*/
@Throws(IllegalStateException::class)
@JvmStatic
fun <T : EvolutionProgress<*>> registerType(id: ResourceLocation, type: EvolutionProgressType<T>): EvolutionProgressType<T> {
return Registry.register(REGISTRY, id, type)
}
/**
* Creates a codec instance of this registry.
*
* @return The generated [Codec] of [EvolutionProgress].
*/
fun codec(): Codec<EvolutionProgress<*>> = REGISTRY.byNameCodec().dispatch(
ServerEvolutionController.ID_KEY,
{ it.type() },
{ it.codec }
)
}
@@ -12,7 +12,7 @@ import com.cobblemon.mod.common.Cobblemon
import com.cobblemon.mod.common.api.tags.CobblemonItemTags
import com.cobblemon.mod.common.battles.pokemon.BattlePokemon
import com.cobblemon.mod.common.pokemon.OriginalTrainerType
import com.cobblemon.mod.common.pokemon.requirements.LevelRequirement
import com.cobblemon.mod.common.pokemon.transformation.requirements.LevelRequirement
import kotlin.math.pow
import kotlin.math.roundToInt
@@ -8,6 +8,7 @@
package com.cobblemon.mod.common.api.pokemon.feature
import com.cobblemon.mod.common.api.pokemon.PokemonProperties
import com.cobblemon.mod.common.pokemon.Pokemon
import com.cobblemon.mod.common.util.readString
import com.cobblemon.mod.common.util.substitute
@@ -80,4 +81,29 @@ class ChoiceSpeciesFeatureProvider : AbstractChoiceSpeciesFeatureProvider<List<S
}
return aspects
}
override fun provide(pokemon: Pokemon): Set<String> {
return if (isAspect) {
get(pokemon)?.let {
setOf(getAspect(it))
} ?: emptySet()
} else {
emptySet()
}
}
override fun get(pokemon: Pokemon) = pokemon.getFeature<StringSpeciesFeature>(keys.first())
override fun provide(properties: PokemonProperties): Set<String> {
return if (isAspect) {
val feature = properties.customProperties.filterIsInstance<StringSpeciesFeature>().find { it.name == keys.first() }
if (feature != null) {
setOf(getAspect(feature))
} else {
emptySet()
}
} else {
emptySet()
}
}
}
@@ -9,7 +9,7 @@
package com.cobblemon.mod.common.api.pokemon.feature
import com.cobblemon.mod.common.api.pokemon.PokemonProperties
import com.cobblemon.mod.common.api.pokemon.aspect.AspectProvider
import com.cobblemon.mod.common.api.pokemon.aspect.FeatureAspectProvider
import com.cobblemon.mod.common.api.properties.CustomPokemonProperty
import com.cobblemon.mod.common.api.properties.CustomPokemonPropertyType
import com.cobblemon.mod.common.client.gui.summary.featurerenderers.SummarySpeciesFeatureRenderer
@@ -17,9 +17,9 @@ import com.cobblemon.mod.common.pokemon.Pokemon
import com.cobblemon.mod.common.util.readString
import com.cobblemon.mod.common.util.writeString
import com.google.gson.JsonObject
import kotlin.random.Random
import net.minecraft.nbt.CompoundTag
import net.minecraft.network.RegistryFriendlyByteBuf
import kotlin.random.Random
/**
* A simple [SpeciesFeature] that is a true/false flag value. It implements [CustomPokemonProperty] for use in
@@ -30,65 +30,74 @@ import kotlin.random.Random
* @author Hiroku
* @since May 13th, 2022
*/
open class FlagSpeciesFeature(override val name: String) : SynchronizedSpeciesFeature, CustomPokemonProperty {
open class FlagSpeciesFeature(override val name: String) : SynchronizedSpeciesFeature<Boolean>, CustomPokemonProperty {
constructor(name: String, enabled: Boolean): this(name) {
this.enabled = enabled
this.value = enabled
}
var enabled = false
override var value: Boolean = false
override fun saveToNBT(pokemonNBT: CompoundTag): CompoundTag {
pokemonNBT.putBoolean(name, enabled)
pokemonNBT.putBoolean(name, value)
return pokemonNBT
}
override fun loadFromNBT(pokemonNBT: CompoundTag): SpeciesFeature {
enabled = if (pokemonNBT.contains(name)) pokemonNBT.getBoolean(name) else enabled
override fun loadFromNBT(pokemonNBT: CompoundTag): SpeciesFeature<Boolean> {
value = if (pokemonNBT.contains(name)) pokemonNBT.getBoolean(name) else value
return this
}
override fun saveToJSON(pokemonJSON: JsonObject): JsonObject {
pokemonJSON.addProperty(name, enabled)
pokemonJSON.addProperty(name, value)
return pokemonJSON
}
override fun loadFromJSON(pokemonJSON: JsonObject): SpeciesFeature {
override fun loadFromJSON(pokemonJSON: JsonObject): SpeciesFeature<Boolean> {
val isEnabled = pokemonJSON.get(name)?.asBoolean
enabled = isEnabled ?: this.enabled
value = isEnabled ?: this.value
return this
}
override fun saveToBuffer(buffer: RegistryFriendlyByteBuf, toClient: Boolean) {
buffer.writeBoolean(enabled)
buffer.writeBoolean(value)
}
override fun loadFromBuffer(buffer: RegistryFriendlyByteBuf) {
enabled = buffer.readBoolean()
value = buffer.readBoolean()
}
override fun asString() = "$name=$enabled"
override fun asString() = "$name=$value"
override fun apply(pokemon: Pokemon) {
val featureProvider = SpeciesFeatures.getFeature(name) ?: return
if (featureProvider in SpeciesFeatures.getFeaturesFor(pokemon.species)) {
val existingFeature = pokemon.getFeature<FlagSpeciesFeature>(name)
if (existingFeature != null) {
existingFeature.enabled = enabled
existingFeature.value = value
} else {
pokemon.features.add(FlagSpeciesFeature(name, enabled))
pokemon.features.add(FlagSpeciesFeature(name, value))
}
pokemon.updateAspects()
}
}
override fun matches(pokemon: Pokemon) = pokemon.getFeature<FlagSpeciesFeature>(name)?.enabled == enabled
override fun matches(pokemon: Pokemon) = pokemon.getFeature<FlagSpeciesFeature>(name)?.value == value
}
class FlagSpeciesFeatureProvider : SynchronizedSpeciesFeatureProvider<FlagSpeciesFeature>, CustomPokemonPropertyType<FlagSpeciesFeature>, AspectProvider {
class FlagSpeciesFeatureProvider : SynchronizedSpeciesFeatureProvider<FlagSpeciesFeature>, CustomPokemonPropertyType<FlagSpeciesFeature>, FeatureAspectProvider {
override var keys: List<String> = emptyList()
// Uses get() = true because that way there's no backing field. It MUST be true, this way no JSON trickery will overwrite it
override val needsKey get() = true
var default: String? = null
var isAspect = true
override var default: String? = null
override var isAspect = true
override fun matches(aspect: String): Boolean = this.isAspect && this.keys.first() == aspect
override fun from(aspect: String): SpeciesFeature<*>? = if (matches(aspect)) fromString(null) else null
override fun set(pokemon: Pokemon, aspect: String) {
this.get(pokemon)?.value = true
}
override var visible: Boolean = false
override fun invoke(buffer: RegistryFriendlyByteBuf, name: String): FlagSpeciesFeature? {
@@ -174,7 +183,7 @@ class FlagSpeciesFeatureProvider : SynchronizedSpeciesFeatureProvider<FlagSpecie
override fun provide(pokemon: Pokemon): Set<String> {
return if (isAspect) {
val feature = pokemon.features.filterIsInstance<FlagSpeciesFeature>().find { it.name in keys }
if (feature != null && feature.enabled) {
if (feature != null && feature.value) {
setOf(keys.first())
} else {
emptySet()
@@ -187,7 +196,7 @@ class FlagSpeciesFeatureProvider : SynchronizedSpeciesFeatureProvider<FlagSpecie
override fun provide(properties: PokemonProperties): Set<String> {
return if (isAspect) {
val feature = properties.customProperties.filterIsInstance<FlagSpeciesFeature>().find { it.name in keys }
if (feature != null && feature.enabled) {
if (feature != null && feature.value) {
setOf(keys.first())
} else {
emptySet()
@@ -90,7 +90,7 @@ object GlobalSpeciesFeatures : JsonDataRegistry<SpeciesFeatureProvider<*>> {
@JvmStatic
fun register(name: String, provider: SpeciesFeatureProvider<*>) = register(name, provider, isCoded = true)
@JvmStatic
fun <T : SpeciesFeature> register(name: String, providerLambda: () -> T) {
fun <T : SpeciesFeature<*>> register(name: String, providerLambda: () -> T) {
register(name, object : SpeciesFeatureProvider<T> {
override fun invoke(pokemon: Pokemon) = providerLambda()
override fun invoke(nbt: CompoundTag) = providerLambda().apply { loadFromNBT(nbt) }
@@ -26,8 +26,8 @@ import net.minecraft.world.phys.Vec3
* A species feature value that's just an integer. Complex stuff.
* @author Hiroku
*/
class IntSpeciesFeature(override var name: String) : SynchronizedSpeciesFeature, CustomPokemonProperty {
var value = 0
class IntSpeciesFeature(override var name: String) : SynchronizedSpeciesFeature<Int>, CustomPokemonProperty {
override var value = 0
constructor() : this("")
constructor(name: String, value: Int) : this(name) {
@@ -39,7 +39,7 @@ class IntSpeciesFeature(override var name: String) : SynchronizedSpeciesFeature,
return pokemonNBT
}
override fun loadFromNBT(pokemonNBT: CompoundTag): SynchronizedSpeciesFeature {
override fun loadFromNBT(pokemonNBT: CompoundTag): SynchronizedSpeciesFeature<Int> {
value = pokemonNBT.getInt(name)
return this
}
@@ -49,7 +49,7 @@ class IntSpeciesFeature(override var name: String) : SynchronizedSpeciesFeature,
return pokemonJSON
}
override fun loadFromJSON(pokemonJSON: JsonObject): SpeciesFeature {
override fun loadFromJSON(pokemonJSON: JsonObject): SpeciesFeature<Int> {
value = pokemonJSON.get(name).asInt
return this
}
@@ -24,10 +24,11 @@ import net.minecraft.nbt.CompoundTag
* @author Hiroku
* @since May 13th, 2022
*/
interface SpeciesFeature {
interface SpeciesFeature<T> {
val name: String
var value: T
fun saveToNBT(pokemonNBT: CompoundTag): CompoundTag
fun loadFromNBT(pokemonNBT: CompoundTag): SpeciesFeature
fun loadFromNBT(pokemonNBT: CompoundTag): SpeciesFeature<T>
fun saveToJSON(pokemonJSON: JsonObject): JsonObject
fun loadFromJSON(pokemonJSON: JsonObject): SpeciesFeature
fun loadFromJSON(pokemonJSON: JsonObject): SpeciesFeature<T>
}

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